Перейти к содержанию

Рекомендуемые сообщения

  • Администратор

Расширение предоставляет собой встроенные средства для перехвата обработчиков событий действий и создания пользовательских действий.

  • Если два разных плагина попытаются вернуть разные действия для одного и того же обработчика событий, будет выбран последний.
  • Расширение не поддерживает позднюю загрузку, поэтому после перезагрузки вы должны заново создать nextbots
  • Все действия кэшируются их родительскими обработчиками событий действий.

Команды и ConVars:

/* Комманды */
ext_actions_dump - Записывает действия сущностей
ext_actions_offsets - Печатает оффсеты каждой перехваченной функции
ext_actions_listeners - Записывает прослушиватели действий
ext_actions_list - Записывает каждое действие, которое менеджер в настоящее время проводит

/* ConVars */
ext_actions_debug - Отладка (1 - Включить, 0 - Выключить)
ext_actions_debug_processors - Логирование (-2 - Выключить, -1 - Записывать все, N - Записывать только индекс функции) 

Шаблоны:

Блокировка действий:

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>

#include <actions>

public void OnActionCreated( BehaviorAction action, int actor, const char[] name )
{
    if ( strcmp(name, "WitchAttack") == 0 )
    {
        /* Hook OnStart handler */
        action.OnStart = OnStart;
    }
}

public Action OnStart( BehaviorAction action, int actor, BehaviorAction priorAction, ActionResult result )
{
    /* When WitchAttack actions starts force it to end */
    result.type = DONE;
    return Plugin_Changed;
} 

Пользовательские действия:

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>

#include <actions>

public void OnActionCreated( BehaviorAction action, int actor, const char[] name )
{
    if ( strcmp(name, "SurvivorAttack") == 0 )    
        action.OnStart = OnStart;
}

public Action OnStart( BehaviorAction action, int actor, BehaviorAction priorAction, ActionResult result )
{
    /* We suspend WitchAttack action for our action */
    /* That means WitchAttack will be like in frozen state */
    /* It's will not be updated until our action is done */
    
    return action.SuspendFor(MyCustomAction(), "Suspend example");
}

BehaviorAction MyCustomAction()
{
    /* Creating action */
    BehaviorAction action = ActionsManager.Create("MyCustomAction");
    
    /* Setup event handlers */
    action.OnStart = OnMyActionStart;
    action.OnUpdate = OnMyActionUpdate;
    
    return action;
}

public Action OnMyActionStart( BehaviorAction action, int actor, BehaviorAction priorAction, ActionResult result )
{
    PrintToServer("We are started!");
    return Plugin_Continue;
}

public Action OnMyActionUpdate( BehaviorAction action, int actor, float interval, ActionResult result )
{
    PrintToServer("MyCustomAction is updating...");
    
    if (GetRandomFloat() >= 0.5)
    {
        return action.Done("We are done");
    }

    return Plugin_Continue;
} 

Изменение исходного результата:

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>

#include <actions>

public void OnActionCreated( BehaviorAction action, int actor, int actor, const char[] name )
{
    if ( strcmp(name, "WitchIdle") == 0 || strcmp(name, "WitchAngry") == 0 )    
    {
        /* We set post hook otherwise ActionDesiredResult will contain default values */
        action.OnShovedPost = OnShovedPost;
    }
}

public Action OnShovedPost( BehaviorAction action, int actor, int shover, ActionDesiredResult result )
{
    if ( result.type == SUSPEND_FOR )
    {
        result.type = CONTINUE;
        return Plugin_Changed;
    }
    
    return Plugin_Continue;
} 

Заставить ботов лечить только вас или себя, только в состоянии ЧБ:

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>

#include <actions>

stock int m_bIsOnThirdStrike;

public void OnPluginStart()
{
    m_bIsOnThirdStrike = FindSendPropInfo("CTerrorPlayer", "m_bIsOnThirdStrike");
}

public void OnActionCreated( BehaviorAction action, int actor, const char[] name )
{
    /* Hooking self healing action (when bot wants to heal self) */
    if (  strcmp(name, "SurvivorHealSelf") == 0 )    
        action.OnStart = OnSelfAction;
        
    /* Hooking friend healing action (when bot wants to heal someone) */
    if ( strcmp(name, "SurvivorHealFriend") == 0 )    
        action.OnStartPost = OnFriendAction;
    
    /* Hooking take pills action (when bot wants to take pills) */
    if ( strcmp(name, "SurvivorTakePills") == 0 )    
        action.OnStart = OnSelfAction;
    
    /* Hooking give pills action (when bot wants to give pills) */
    if ( strcmp(name, "SurvivorGivePillsToFriend") == 0 )    
        action.OnStartPost = OnFriendAction;
}

public Action OnSelfAction( BehaviorAction action, int actor, BehaviorAction priorAction, ActionResult result )
{
    /* When bot will be about to start healing/taking pills we chech if he's black & white */
    /* if he is then we allow to heal otherwise no */
    result.type = GetEntData(action.Actor, m_bIsOnThirdStrike, 1) ? CONTINUE : DONE;
    return Plugin_Handled;
}

public Action OnFriendAction( BehaviorAction action, int actor, BehaviorAction priorAction, ActionResult result )
{
    /* When bot will be about to start healing/giving pills to someone, we chech if friend is black & white */
    /* if friend is then we allow to give heal otherwise no */
    int target = action.Get(0x34) & 0xFFF;
    result.type = GetEntData(target, m_bIsOnThirdStrike, 1) ? CONTINUE : DONE;
    return Plugin_Handled;
} 

Источник: https://forums.alliedmods.net/showthread.php?p=2771520#post2771520

actions.ext.l4d2.zip

Ссылка на комментарий
Поделиться на другие сайты

Спасибо за то что выложил это расширение=.
Я пытался портировать версию расширения TF2 для Insurgency. Я предполагаю, что их NextBots основаны на версии TF2, потому что у них есть все те же функции и оффсеты, что и у TF2, но есть также некоторые специфические действия INS. Однако у меня происходит сбой сервера из-за зацикливания функции OnIntentionReset.

actions.ext.2.insurgency.dll!OnIntentionReset()Line 27	C++
actions.ext.2.insurgency.dll!fastdelegate::FastDelegate<void>::InvokeStaticFunction()Line 968	C++
actions.ext.2.insurgency.dll!fastdelegate::FastDelegate<void>::operator()()Line 928	C++
actions.ext.2.insurgency.dll!__SourceHook_MFHCls_OnIntentionReset::CMyDelegateImpl::Call()Line 7	C++
actions.ext.2.insurgency.dll!__SourceHook_MFHCls_OnIntentionReset::Func()Line 7	C++

Есть идеи, в чем причина?Вот игровые данные. Адрес и подписи основаны на том, что я видел в игровых данных TF2.

"Games"
{
	"#default"
	{
		"Offsets"
		{
			"Destructor"
			{
				"linux" "1"
				"windows" "0"
			}
		}
	}
	
	"insurgency"
	{
		"Offsets"
		{
			"IIntention::Reset"
			{
				"linux" "46"
				"windows" "45"
			}
			
			// IIntention offsets?
			"ShouldPickUp"
			{
				"linux" "2"
				"windows" "1"
			}
			"ShouldHurry"
			{
				"linux" "3"
				"windows" "2"
			}
			"ShouldRetreat"
			{
				"linux" "4"
				"windows" "3"				
			}
			"ShouldAttack"
			{
				"linux" "5"
				"windows" "4"				
			}			
			"IsHindrance"
			{
				"linux" "6"
				"windows" "5"
			}
			"SelectTargetPoint"
			{
				"linux" "7"
				"windows" "6"
			}
			"IsPositionAllowed"
			{
				"linux" "8"
				"windows" "7"
			}
			"SelectMoreDangerousThreat"
			{
				"linux" "9"
				"windows" "8"
			}
			"ShouldWalk"
			{
				"linux" "10"
				"windows" "9"
			}
			"ShouldIronsight"
			{
				"linux" "11"
				"windows" "10"
			}
			"ShouldProne"
			{
				"linux" "12"
				"windows" "11"
			}
			"ShouldPursue"
			{
				"linux" "13"
				"windows" "12"
			}

			// MainAction offsets
			"OnStart"
			{
				"linux" "49"
				"windows" "48"
			}
			"Update"
			{
				"linux" "50"
				"windows" "49"
			}
			"OnEnd"
			{
				"linux" "51"
				"windows" "50"
			}
			"OnSuspend"
			{
				"linux" "52"
				"windows" "51"
			}
			"OnResume"
			{
				"linux" "53"
				"windows" "52"
			}
			"InitialContainedAction"
			{
				"linux" "54"
				"windows" "53"
			}
			"OnLeaveGround"
			{
				"linux" "55"
				"windows" "54"
			}
			"OnLandOnGround"
			{
				"linux" "56"
				"windows" "55"
			}
			"OnContact"
			{
				"linux" "57"
				"windows" "56"
			}
			"OnMoveToSuccess"
			{
				"linux" "58"
				"windows" "57"
			}
			"OnMoveToFailure"
			{
				"linux" "59"
				"windows" "58"
			}
			"OnStuck"
			{
				"linux" "60"
				"windows" "59"
			}
			"OnUnStuck"
			{
				"linux" "61"
				"windows" "60"
			}
			"OnPostureChanged"
			{
				"linux" "62"
				"windows" "61"
			}
			"OnAnimationActivityComplete"
			{
				"linux" "63"
				"windows" "62"
			}
			"OnAnimationActivityInterrupted"
			{
				"linux" "64"
				"windows" "63"
			}
			"OnAnimationEvent"
			{
				"linux" "65"
				"windows" "64"
			}
			"OnIgnite"
			{
				"linux" "66"
				"windows" "65"
			}
			"OnInjured"
			{
				"linux" "67"
				"windows" "66"
			}
			"OnKilled"
			{
				"linux" "68"
				"windows" "67"
			}
			"OnOtherKilled"
			{
				"linux" "69"
				"windows" "68"
			}
			"OnSight"
			{
				"linux" "70"
				"windows" "69"
			}
			"OnLostSight"
			{
				"linux" "71"
				"windows" "70"
			}
			"OnSound"
			{
				"linux" "72"
				"windows" "71"
			}
			"OnSpokeConcept"
			{
				"linux" "73"
				"windows" "72"
			}
			"OnWeaponFired"
			{
				"linux" "74"
				"windows" "73"
			}			
			"OnNavAreaChanged"
			{
				"linux" "75"
				"windows" "64"
			}
			"OnModelChanged"
			{
				"linux" "76"
				"windows" "75"
			}
			"OnPickUp"
			{
				"linux" "77"
				"windows" "76"
			}
			"OnDrop"
			{
				"linux" "78"
				"windows" "77"
			}
			"OnActorEmoted"
			{
				"linux" "79"
				"windows" "78"
			}			
			"OnShoved"
			{
				"linux" "87"
				"windows" "86"
			}
			"OnBlinded"
			{
				"linux" "88"
				"windows" "87"
			}
			"OnCommandAttack"
			{
				"linux" "80"
				"windows" "79"
			}
			"OnCommandApproachVector"
			{
				"linux" "81"
				"windows" "81"
			}
			"OnCommandApproachEntity"
			{
				"linux" "82"
				"windows" "80"
			}
			"OnCommandRetreat"
			{
				"linux" "83"
				"windows" "82"
			}
			"OnCommandPause"
			{
				"linux" "84"
				"windows" "83"
			}
			"OnCommandResume"
			{
				"linux" "85"
				"windows" "84"
			}
			"OnCommandString"
			{
				"linux" "86"
				"windows" "85"
			}
			"IsAbleToBlockMovementOf"
			{
				"linux" "97"
				"windows" "96"
			}
			"OnTerritoryContested"
			{
				"linux" "89"
				"windows" "88"
			}
			"OnTerritoryCaptured"
			{
				"linux" "90"
				"windows" "89"
			}
			"OnTerritoryLost"
			{
				"linux" "91"
				"windows" "90"				
			}
			"OnWin"
			{
				"linux" "92"
				"windows" "91"				
			}
			"OnLose"
			{
				"linux" "93"
				"windows" "92"				
			}
			"OnHeardFootsteps"
			{
				"linux" "94"
				"windows" "93"				
			}
			"OnSeeSomethingSuspicious"
			{
				"linux" "95"
				"windows" "94"				
			}
			"OnOrderReceived"
			{
				"linux" "96"
				"windows" "95"				
			}	
		}
		"Addresses"
		{
			"CINSNextBot::CINSNextBotIntention::Reset"
			{	
				"signature" "CINSNextBot::CINSNextBotIntention::Reset"
				"linux"
				{
					"offset" "8"
				}
				"windows"
				{
					"read" "4"
				}
			}
		}
		"Signatures"
		{
			"CINSNextBot::CINSNextBotIntention::Reset"
			{
				// first xref to "const CINSNextBot::CINSNextBotIntention::`vftable'"
				// push 	50h
				// mov 		dword ptr [esi], offset ??_7CINSNextBotIntention@CINSNextBot@@6B@
				// 6A 50 C7 06 F8 F3 54 10 C7 46
				"windows" "\x6A\x50\xC7\x06\xF8\xF3\x2A\x2A\xC7\x46"
				"linux" "@_ZN11CINSNextBot20CINSNextBotIntentionC2EPS_"
			}
		}
	}
}

 

Ссылка на комментарий
Поделиться на другие сайты
  • Администратор
В 26.08.2022 в 08:03, randomrb сказал:

Спасибо за то что выложил это расширение=.
Я пытался портировать версию расширения TF2 для Insurgency. Я предполагаю, что их NextBots основаны на версии TF2, потому что у них есть все те же функции и оффсеты, что и у TF2, но есть также некоторые специфические действия INS. Однако у меня происходит сбой сервера из-за зацикливания функции OnIntentionReset.

actions.ext.2.insurgency.dll!OnIntentionReset()Line 27	C++
actions.ext.2.insurgency.dll!fastdelegate::FastDelegate<void>::InvokeStaticFunction()Line 968	C++
actions.ext.2.insurgency.dll!fastdelegate::FastDelegate<void>::operator()()Line 928	C++
actions.ext.2.insurgency.dll!__SourceHook_MFHCls_OnIntentionReset::CMyDelegateImpl::Call()Line 7	C++
actions.ext.2.insurgency.dll!__SourceHook_MFHCls_OnIntentionReset::Func()Line 7	C++

Есть идеи, в чем причина?Вот игровые данные. Адрес и подписи основаны на том, что я видел в игровых данных TF2.

"Games"
{
	"#default"
	{
		"Offsets"
		{
			"Destructor"
			{
				"linux" "1"
				"windows" "0"
			}
		}
	}
	
	"insurgency"
	{
		"Offsets"
		{
			"IIntention::Reset"
			{
				"linux" "46"
				"windows" "45"
			}
			
			// IIntention offsets?
			"ShouldPickUp"
			{
				"linux" "2"
				"windows" "1"
			}
			"ShouldHurry"
			{
				"linux" "3"
				"windows" "2"
			}
			"ShouldRetreat"
			{
				"linux" "4"
				"windows" "3"				
			}
			"ShouldAttack"
			{
				"linux" "5"
				"windows" "4"				
			}			
			"IsHindrance"
			{
				"linux" "6"
				"windows" "5"
			}
			"SelectTargetPoint"
			{
				"linux" "7"
				"windows" "6"
			}
			"IsPositionAllowed"
			{
				"linux" "8"
				"windows" "7"
			}
			"SelectMoreDangerousThreat"
			{
				"linux" "9"
				"windows" "8"
			}
			"ShouldWalk"
			{
				"linux" "10"
				"windows" "9"
			}
			"ShouldIronsight"
			{
				"linux" "11"
				"windows" "10"
			}
			"ShouldProne"
			{
				"linux" "12"
				"windows" "11"
			}
			"ShouldPursue"
			{
				"linux" "13"
				"windows" "12"
			}

			// MainAction offsets
			"OnStart"
			{
				"linux" "49"
				"windows" "48"
			}
			"Update"
			{
				"linux" "50"
				"windows" "49"
			}
			"OnEnd"
			{
				"linux" "51"
				"windows" "50"
			}
			"OnSuspend"
			{
				"linux" "52"
				"windows" "51"
			}
			"OnResume"
			{
				"linux" "53"
				"windows" "52"
			}
			"InitialContainedAction"
			{
				"linux" "54"
				"windows" "53"
			}
			"OnLeaveGround"
			{
				"linux" "55"
				"windows" "54"
			}
			"OnLandOnGround"
			{
				"linux" "56"
				"windows" "55"
			}
			"OnContact"
			{
				"linux" "57"
				"windows" "56"
			}
			"OnMoveToSuccess"
			{
				"linux" "58"
				"windows" "57"
			}
			"OnMoveToFailure"
			{
				"linux" "59"
				"windows" "58"
			}
			"OnStuck"
			{
				"linux" "60"
				"windows" "59"
			}
			"OnUnStuck"
			{
				"linux" "61"
				"windows" "60"
			}
			"OnPostureChanged"
			{
				"linux" "62"
				"windows" "61"
			}
			"OnAnimationActivityComplete"
			{
				"linux" "63"
				"windows" "62"
			}
			"OnAnimationActivityInterrupted"
			{
				"linux" "64"
				"windows" "63"
			}
			"OnAnimationEvent"
			{
				"linux" "65"
				"windows" "64"
			}
			"OnIgnite"
			{
				"linux" "66"
				"windows" "65"
			}
			"OnInjured"
			{
				"linux" "67"
				"windows" "66"
			}
			"OnKilled"
			{
				"linux" "68"
				"windows" "67"
			}
			"OnOtherKilled"
			{
				"linux" "69"
				"windows" "68"
			}
			"OnSight"
			{
				"linux" "70"
				"windows" "69"
			}
			"OnLostSight"
			{
				"linux" "71"
				"windows" "70"
			}
			"OnSound"
			{
				"linux" "72"
				"windows" "71"
			}
			"OnSpokeConcept"
			{
				"linux" "73"
				"windows" "72"
			}
			"OnWeaponFired"
			{
				"linux" "74"
				"windows" "73"
			}			
			"OnNavAreaChanged"
			{
				"linux" "75"
				"windows" "64"
			}
			"OnModelChanged"
			{
				"linux" "76"
				"windows" "75"
			}
			"OnPickUp"
			{
				"linux" "77"
				"windows" "76"
			}
			"OnDrop"
			{
				"linux" "78"
				"windows" "77"
			}
			"OnActorEmoted"
			{
				"linux" "79"
				"windows" "78"
			}			
			"OnShoved"
			{
				"linux" "87"
				"windows" "86"
			}
			"OnBlinded"
			{
				"linux" "88"
				"windows" "87"
			}
			"OnCommandAttack"
			{
				"linux" "80"
				"windows" "79"
			}
			"OnCommandApproachVector"
			{
				"linux" "81"
				"windows" "81"
			}
			"OnCommandApproachEntity"
			{
				"linux" "82"
				"windows" "80"
			}
			"OnCommandRetreat"
			{
				"linux" "83"
				"windows" "82"
			}
			"OnCommandPause"
			{
				"linux" "84"
				"windows" "83"
			}
			"OnCommandResume"
			{
				"linux" "85"
				"windows" "84"
			}
			"OnCommandString"
			{
				"linux" "86"
				"windows" "85"
			}
			"IsAbleToBlockMovementOf"
			{
				"linux" "97"
				"windows" "96"
			}
			"OnTerritoryContested"
			{
				"linux" "89"
				"windows" "88"
			}
			"OnTerritoryCaptured"
			{
				"linux" "90"
				"windows" "89"
			}
			"OnTerritoryLost"
			{
				"linux" "91"
				"windows" "90"				
			}
			"OnWin"
			{
				"linux" "92"
				"windows" "91"				
			}
			"OnLose"
			{
				"linux" "93"
				"windows" "92"				
			}
			"OnHeardFootsteps"
			{
				"linux" "94"
				"windows" "93"				
			}
			"OnSeeSomethingSuspicious"
			{
				"linux" "95"
				"windows" "94"				
			}
			"OnOrderReceived"
			{
				"linux" "96"
				"windows" "95"				
			}	
		}
		"Addresses"
		{
			"CINSNextBot::CINSNextBotIntention::Reset"
			{	
				"signature" "CINSNextBot::CINSNextBotIntention::Reset"
				"linux"
				{
					"offset" "8"
				}
				"windows"
				{
					"read" "4"
				}
			}
		}
		"Signatures"
		{
			"CINSNextBot::CINSNextBotIntention::Reset"
			{
				// first xref to "const CINSNextBot::CINSNextBotIntention::`vftable'"
				// push 	50h
				// mov 		dword ptr [esi], offset ??_7CINSNextBotIntention@CINSNextBot@@6B@
				// 6A 50 C7 06 F8 F3 54 10 C7 46
				"windows" "\x6A\x50\xC7\x06\xF8\xF3\x2A\x2A\xC7\x46"
				"linux" "@_ZN11CINSNextBot20CINSNextBotIntentionC2EPS_"
			}
		}
	}
}

 

Пока, насколько я знаю, даже не планируется никакой поддержки для INS. Что касается сбоев сервера, то это может быть что угодно. Вообще в таких случаях рекомендуют отладить интерфейс Intention, чтобы убедиться, что вы подключаете правильную функцию.

Ссылка на комментарий
Поделиться на другие сайты
  • 3 недели спустя...
  • Администратор

Недавнее обновление сломало это расширение на серверах. Автор пообещал исправить его позже.

Если вы размещаете выделенный сервер, попробуйте пример ниже. Пример, приведенный в первом посте, имеет плохой метод обнаружения черно-белого изображения.

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>

#include <actions>

ConVar survivor_max_incapacitated_count;

public void OnPluginStart()
{
    survivor_max_incapacitated_count = FindConVar("survivor_max_incapacitated_count");
}

public void OnActionCreated( BehaviorAction action, int actor, const char[] name )
{
    /* Hooking self healing action (when bot wants to heal self) */
    if (  strcmp(name, "SurvivorHealSelf") == 0 )    
        action.OnStart = OnSelfAction;
        
    /* Hooking friend healing action (when bot wants to heal someone) */
    if ( strcmp(name, "SurvivorHealFriend") == 0 )    
        action.OnStartPost = OnFriendAction;
    
    /* Hooking take pills action (when bot wants to take pills) */
    if ( strcmp(name, "SurvivorTakePills") == 0 )    
        action.OnStart = OnSelfAction;
    
    /* Hooking give pills action (when bot wants to give pills) */
    if ( strcmp(name, "SurvivorGivePillsToFriend") == 0 )    
        action.OnStartPost = OnFriendAction;
}

public Action OnSelfAction( BehaviorAction action, int actor, BehaviorAction priorAction, ActionResult result )
{
    /* When bot will be about to start healing/taking pills we chech if he's black & white */
    /* if he is then we allow to heal otherwise no */
    if (IsGoingToDie(actor))
        return Plugin_Continue;

    action.Done("I am not black and white");
    return Plugin_Handled;
}

public Action OnFriendAction( BehaviorAction action, int actor, BehaviorAction priorAction, ActionResult result )
{
    /* When bot will be about to start healing/giving pills to someone, we chech if friend is black & white */
    /* if friend is then we allow to give heal otherwise no */
    int target = action.Get(0x34) & 0xFFF;

    if (!IsGoingToDie(target))
    {
        action.Done("My friend isn't black and white");
        return Plugin_Handled;
    }

    return Plugin_Continue;
}

bool IsGoingToDie(int client)
{
    return GetEntProp(client, Prop_Send, "m_currentReviveCount") >= survivor_max_incapacitated_count.IntValue;
} 

 

Ссылка на комментарий
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
×
×
  • Создать...