Fixing AI in multiplayer: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
(Rewrite Template:Lang to Template:LanguageBar. This action was performed by a bot.)
 
(78 intermediate revisions by 25 users not shown)
Line 1: Line 1:
{{wip}}
{{LanguageBar|Fixing_AI_in_multiplayer}}


This is an updated article about how to fix NPCs in multiplayer. HL2 has no support for NPCs in multiplayer and HL2DM has certainly broken more of the AI.
This article describes the changes that need to be made to get NPCs to work in the multiplayer SDK, as there are several key features that need to be re-implemented in a multiplayer context. While it covers the use of the {{hl2dm|4.1}} SDK, it should be readily convertible to work with any SDK, by referring to the correct GameRules.
 
Note that a patch is available for the Orange Box HL2DM source that implements all changes described here, it is listed near the end of the article.
 
Note that a [https://github.com/lun4rD35p4ir/SDK-2013-Multiplayer-AI-Fixes Fork] of the {{src13|4.1}} codeline on GitHub exists in which these changes have been applied.  Cloning this fork might be a good way to get these changes into your project.


== Relationships ==
== Relationships ==
There are no relationships-table set in HL2DM. With this table NPCs don't know which entities to hate/like. And if a Combine Soldiers likes players, he won't shoot them.
There is no relationship table set in {{hl2dm|3.1}}. Without this table, NPCs won't know which entities to hate/like, and if Combine Soldiers like players, they won't attack them.
 
This is simple to fix. First go to {{file|hl2mp_gamerules|h}}, under <code>void RestartGame();</code> add this:
 
<source lang=cpp>
#ifndef CLIENT_DLL
void InitDefaultAIRelationships( void );
#endif
</source>
 
Next go to {{file|hl2_gamerules|cpp}} and copy the entire <code>InitDefaultAIRelationships()</code> function. Paste it in {{file|hl2mp_gamerules|cpp}}.
 
Don't forget to put the copied functions from hl2_gamerules.cpp between <code>#ifndef CLIENT_DLL</code> and <code>#endif</code>.


And change {{Code|highlight=cpp|void CHalfLife2::InitDefaultAIRelationships( void )}} to {{Code|highlight=cpp|void CHL2MPRules::InitDefaultAIRelationships( void )}}
in hl2mp_gamerules.cpp .


This is simpel to fix. Go to <code>hl2_gamerules.cpp</code> and copy the entire <code>InitDefaultAIRelationships</code> function. Past it in <code>hl2mp_gamerules.cpp</code> and add a call to the new function in the constructor of the HL2DM gamerules.
And Voula now you should have working relationships with npcs


== Weapons ==
== Weapons ==
=== Activities & animation events ===
=== Activities & animation events ===
The weapons have custom activities and animation events in HL2DM. In the HL2DM-versions of the weapons, this is removed.


Open the weapon_hl2mpbase.h file and add the following code after the includes:
The weapons have custom activities and animation events used for the AI in HL2. In the HL2DM-versions of the weapons this is removed.
<pre>#ifndef CLIENT_DLL
 
Open the {{file|weapon_hl2mpbase|h}} file and add the following code after the includes:
 
<source lang=cpp>
#ifndef CLIENT_DLL
#include "AI_BaseNPC.h"
#include "AI_BaseNPC.h"
#endif</pre>
#endif
</source>


Now open the HL2SP files of the BaseHLBludgeonWeapon, AR2, shotgun, SMG1, crowbar, pistol, stunstick and frag grenade (found in <code>dlls/hl2_dll/</code>). The NPCs in HL2 don't use any other weapons. Each weapon has a <code>Operator_HandleAnimEvent</code> and/or <code>CapabilitiesGet</code> function, which the NPCs use to fire their weapons. Copy these functions and any other functions that are called in <code>Operator_HandleAnimEvent</code> to the HL2DM weaponfiles (found in <code>game_shared/hl2mp/</code>).


Now open the HL2SP files of the AR2, shotgun, SMG1, crowbar, pistol and stunstick (found in <code>dlls/hl2_dll/</code>). The NPCs in HL2 don't use any other weapons. Each weapon has a <code>Operator_HandleAnimEvent</code> function, which the NPCs use to fire their weapons. Copy this function and any other functions that are called in this function to the HL2DM weaponfiles (found in <code>game_shared/hl2mp/</code>). Don't forget the headers and to put all copied functions between:
Don't forget the headers and put all copied functions between <code>#ifndef CLIENT_DLL</code> and <code>#endif</code>.
<pre>#ifndef CLIENT_DLL
...
#endif</code>


Also, you need to copy the activities. Look for <code<m_acttable[]</code> in the HL2SP-variants and copy them to the HL2DM-variants.
Also, you need to copy the activities. Look for <code>m_acttable[]</code> in the HL2SP-variants and copy them to the HL2DM-variants.


=== SetActivity() ===
=== SetActivity() ===
Open <code>basecombatweapon_shared.cpp</code> and look for the function <code>SetActivity</code>.
 
Open {{file|basecombatweapon_shared|cpp}} and look for the function <code>SetActivity</code>.
Look for the following code:
Look for the following code:


<pre>//Adrian: Oh man...
<source lang=cpp>
//Adrian: Oh man...
#if !defined( CLIENT_DLL ) && defined( HL2MP )
#if !defined( CLIENT_DLL ) && defined( HL2MP )
SetModel( GetWorldModel() );
SetModel( GetWorldModel() );
Line 44: Line 67:
#if !defined( CLIENT_DLL ) && defined( HL2MP )
#if !defined( CLIENT_DLL ) && defined( HL2MP )
SetModel( GetViewModel() );
SetModel( GetViewModel() );
#endif</pre>
#endif
</source>


The activities can only be retrieved from weapon world models. However the weapons of players are viewmodels. So with this little hack the models are changed to worldmodel, activies are retrieved and changed back to viewmodel. However considering NPCs don't have to see or work with their viewmodels, this is going to be changed:
The activities can only be retrieved from weapon world models. However, the weapons of players are viewmodels. So with this little hack, the models are changed to worldmodel, and activities are retrieved and changed back to viewmodel. However considering NPCs don't have to see or work with their viewmodels, this is going to be changed:


<pre> //Adrian: Oh man...
<source lang=cpp>
//Adrian: Oh man...
if ( GetOwner()->IsPlayer() )
if ( GetOwner()->IsPlayer() )
SetModel( GetWorldModel() );
SetModel( GetWorldModel() );
Line 60: Line 85:
//Adrian: Oh man again...
//Adrian: Oh man again...
if ( GetOwner()->IsPlayer() )
if ( GetOwner()->IsPlayer() )
SetModel( GetViewModel() );</pre>
SetModel( GetViewModel() );
</source>


== Ammotypes ==
== Ammotypes ==
The damage of the weapons need to use the data from <code>skill.cfg</code>. Don't forget the copy HL2's <code>skill.cfg</code> to your mod's <code>cfg</code> directory.


Also, the code needs to be told to use this values. Open <code>hl2_gamerules.cpp</code> again and copy the entire <code>GetAmmoDef</code> function. Replace the same function in <code>hl2_gamerules.cpp</code> with the copied code but add the following line:
The damage of the weapons need to use the data from {{file|skill|cfg}}. Don't forget to copy {{hl2|4.1}}'s {{file|skill|cfg}}</code> to your mod's <code>cfg</code> directory.
<pre>def.AddAmmoType("slam", DMG_BURN, TRACER_NONE, 0, 0, 5, 0, 0 );</pre>


HL2 doesn't have the SLAM and without that line the SLAM won't work anymore.
Also, the code needs to be told to use these values. Open {{file|hl2_gamerules|cpp}} again and copy the entire <code>GetAmmoDef</code> function. Replace the same function in <code>hl2mp_gamerules.cpp</code> with the copied code but add the following line:
<pre>def.AddAmmoType("slam", DMG_BURN, TRACER_NONE, 0, 0, 5, 0, 0);</pre>
 
{{note|HL2 doesn't have the SLAM and without that line the SLAM won't work anymore.}}
 
You need to include {{file|hl2_shareddefs|h}} in {{file|hl2mp_gamerules|cpp}} too.
Otherwise, you will get two compiler errors C2065: 'DMG_SNIPER': undeclared identifier.


== Model animations ==
== Model animations ==
If you are using HL2DM as base (320 as SteamAppID in <code>gameinfo.txt</code>) then you are using the models of HL2DM. HL2DM has new models for the metropolice, combine soldiers and rebels. These HL2DM models don't have the animations of the HL2-variants and the AI doesn't like that. For that to work, you need to copy the models over from HL2. Also, new player models are needed, considering the ones from HL2DM won't work anymore.
 
Source's humanoid NPC models and deathmatch player models were not designed to be compatible with each other. The player and NPC versions both require different animations, and so depending on the order you mount your game content in (HL2DM before HL2, or vice versa) either humanoid NPCs or player animations will be completely missing, unless you use custom models.
 
Assuming you don't have new models, then two approaches are open to you.
 
# The first involves duplicating either the NPC or player models, and using a hex editor to direct the model to use a different animation file (eg create a renamed copy of the npc animations, and change NPC models to use that instead)
# Alternatively, you can try to "remap" the NPC animation names into player names in the code. A brief discussion of this method can be seen here: http://forums.steampowered.com/forums/showthread.php?t=752399


== Function calls ==
== Function calls ==
Still, most part of the AI is still not suited to use in multiplayer. All calls to the functions <code>AI_GetSinglePlayer</code>, <code>AI_IsSingleplayer</code> and <code>UTIL_GetLocalPlayer</code> would need fixing. Also pieces of code like <code>if ( gpGlobals->maxClients == 1) </code>. There are over 100 calls and it's lots of work to fix this.
 
Still, much of the AI code is still not designed to be used in multiplayer. All calls to the functions <code>AI_GetSinglePlayer</code>, <code>AI_IsSingleplayer</code> and <code>UTIL_GetLocalPlayer</code> would need fixing. Also pieces of code like <code>if ( gpGlobals->maxClients == 1)</code> and <code>UTIL_PlayerByIndex( 1 )</code>. There are hundreds of these calls, and it's lots of work to fix them all.
 
{{note|Take a look at [[GetLocalPlayer|this article]] if you need help fixing these function calls.}}
 
== Lag compensation ==
 
Without lag compensation, when you shoot at a target, you have to take your ping time into account, and aim ahead of it accordingly.
So if your ping is 100ms, you have to aim for where the target's head will be in 100ms, rather than where you see it right now.
 
Clearly, this is less than ideal, and so HL2DM incorporates lag compensation, which when calculating whether a bullet hits or not, briefly adjusts the position of all players back by the shooter's ping, so that it calculates the bullet collision based upon exactly what the shooter saw when they fired. This effect is missing for NPCs but can be duplicated from the player lag compensation code without too much trouble.
 
The NPC lag compensation article proved too long to include in this tutorial, it is instead located [[NPC_Lag_Compensation|here]].
 
== Jerky animations ==
 
When ping times are large enough, NPC animation becomes extremely slow and jerky. There's a built-in mechanism to correct for this, [[Lag_Compensation#Display_of_Targets|interpolation]]. Essentially, it shows all NPCs etc slightly "back in time" by a few hundred milliseconds, essentially giving more buffer time for clients. It's controlled by a ConVar, and it would be best to have a slightly higher value by default, so open c_baseentity.cpp, and find
 
<source lang=cpp>static ConVar  cl_interp_npcs( "cl_interp_npcs", "0.0", FCVAR_USERINFO, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)" );</source>
 
Change the second parameter (default value) to 0.25, and now an unusually high ping will be required to distort animations.
 
<source lang=cpp>static ConVar  cl_interp_npcs( "cl_interp_npcs", "0.25", FCVAR_USERINFO, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)" );</source>
 
 
That's 250 milliseconds. Experiment with the {{command|net_fakelag}} console command to determine an optimal value, the higher value you provide, the higher latency users can have and still observe smooth animation. For 250 ms cl_interp_npcs, a net_fakelag of 150 ms still results in smooth animation. The higher the value you provide, however, the further NPCs will operate "in the past" - this only really presents a problem with fast zombies and headcrabs, as the user will appear to take damage while the NPC is still jumping towards them. If you are making a multiplayer zombie mod, it is recommended that you only set the ConVar to around 150, as it would decrease the effect of taking damage before being hit.
 
Instead of relying on interpolation, <code>UseClientSideAnimation();</code> could be added to the <code>CAI_BaseNPC</code> constructor (in ai_basenpc.cpp) - however, this significantly dampens NPCs animations, and so is not recommended.


== Blood ==
== Blood ==
Thanks to the prediction, the blood of NPCs is suppressed. This is because in HL2DM the blood of players is done client-side. This is not the case with NPCs and the prediction needs to "break":
Thanks to the prediction, the blood of NPCs is suppressed. This is because in HL2DM the blood of players is done client-side. This is not the case with NPCs and the prediction needs to "break":


Open <code>util_shared.cpp</code> and look for the function <code>UTIL_BloodDrips</code>. Add to the top of the function: <pre>IPredictionSystem::SuppressHostEvents( NULL );</pre>
Open {{file|util_shared|cpp}} and look for the function <code>UTIL_BloodDrips</code>. Add to the top of the function: <pre>IPredictionSystem::SuppressHostEvents( NULL );</pre>
 
== Zombies ==
 
In {{file|BaseCombatCharacter|cpp}} (Or ai_basenpc.cpp?) find <code>CAI_BaseNPC::Ignite</code> and remove/comment out the <code>#ifdef HL2_EPISODIC</code> section. In <code>npc_BaseZombie.cpp</code> find <code>CNPC_BaseZombie::MakeAISpookySound</code> and remove/comment out its contents.
 
== Patch ==
 
Including the 'function calls,' there are an awful lot of changes required to implement AI in a multiplayer mod. [http://www.megaupload.com/?d=FTB8OOOH This patch file] implements all the changes described here, (crucially) including correcting all the function calls and lag compensation code - so it should save you a good deal of dull coding work! See the readme for details of how it replaces calls to functions such as <code>UTIL_GetLocalPlayer()</code> & <code>AI_GetSingleplayer()</code>. Users requiring assistance in applying a patch file are directed [[Setting up Tortoise SVN to apply a Patch|here]].
 
Due to Megaupload being closed,
it has been uploaded using mirrorcreator.com which uploads to 8 various file hosting websites
[http://www.mirrorcreator.com/files/97C73SFU/hl2mp_ob_ai_fix.zip_links Download Here]
 
Another direct link is [http://www.4shared.com/zip/3XPXCGf2/hl2mp_ob_ai_fix.html Here]
 
=== 15th June 2009 HL2MP Patch ===
 
{{note|This version of the HL2MP patch file has been superseded by the [[Co-Operative Base (Mod)|OrangeBox CoOperative Base Modification]] which contains numerous fixes (alongside other game enhancements which can be removed/disabled). You will notice that this patch is a very early alpha version of OBCO (then called ShadowSource). If you feel up to the challenge you can also 'patch' your hl2mp modification manually by using the following tutorial ('''Please note that I no longer guarantee that this AI patch contains all the AI fixes included in the latest OBCO version!'''):
 
http://www.moddb.com/company/the-development-team/downloads/hl2mp-sdk-adding-hl2-ai-into-the-hl2mp-sourcesdk
 
If you don't wish to use OBCO or the manual tutorial, then here is the old patch.}}
 
The patch (which was made using the original Winston patch via copy & paste) can be downloaded from [http://www.megaupload.com/?d=VMHM1W16 MegaUpload]. Please note that this is the basic AI patch added to the new SDK, it behaves like the old patch.
 
There is a small bug that crept in on each weapon_*.cpp file. That is the ACT_ items are in #ifndef client_dll sections. This is incorrect, they (and the IMPLEMENT_ACTTABLE) should be outside these. If you don't fix these, then even if you get custom player animations to work, their activities won't be called so they'll continue to be t-posed with no animations.
 
For example in the weapon_ar2:
 
<source lang=cpp>
ifndef CLIENT_DLL
acttable_t CWeaponAR2::m_acttable[] =
{
{ ACT_MP_STAND_IDLE, ACT_HL2MP_IDLE_AR2, false },</source>
 
'''Should be:'''
 
<source lang=cpp>
acttable_t CWeaponAR2::m_acttable[] =
{
{ ACT_MP_STAND_IDLE, ACT_HL2MP_IDLE_AR2, false },</source>
 
 
{{note|Everything which was modified by the original AI patch is commented with either "<code>//AI Patch</code>" or "<code>// AI Patch</code>".}}
 
{{warning|Because this comes from code I'd been modifying for my own requirements, there are additional changes. To remove my edits just search for <code>//Modification</code>
 
The files with modifications are:
 
* client/episodic/c_prop_scalable.cpp
* client/in_joystick.cpp
* server/episodic/ep2_gamestats.cpp
* server/player.cpp
* shared/gamemovement.cpp
* shared/gamemovement.h
 
Finally, additional GCF mounts are in {{file|client/cdll_client_int|cpp}} and {{file|server/gameinterface|cpp}}, which are commented as <code>// MOUNTING ADDITIONAL GAMES LINES</code>.
}}
 
{{note|If sdk_gamerules.cpp gives errors during compilation after applying this patch, you may have to do the [http://developer.valvesoftware.com/wiki/Fixing_AI_in_multiplayer#Relationships Relationships step] manually.}}
 
== Conclusion ==
 
While a lot of work is involved, particularly if the patch file is not used, the changes described here should fix most of the AI to a reasonable standard for use in multiplayer. Further changes that will be required, and there is probably room for optimisation in the "function call" fixes, but most NPCs should work well.


[[Category:Programming]]
[[Category:Networking]]
[[Category:AI_Programming]]
[[Category:AI Programming]]
[[Category:Multiplayer]]

Latest revision as of 17:52, 18 July 2025

English (en)Français (fr)Translate (Translate)

This article describes the changes that need to be made to get NPCs to work in the multiplayer SDK, as there are several key features that need to be re-implemented in a multiplayer context. While it covers the use of the Half-Life 2: Deathmatch Half-Life 2: Deathmatch SDK, it should be readily convertible to work with any SDK, by referring to the correct GameRules.

Note that a patch is available for the Orange Box HL2DM source that implements all changes described here, it is listed near the end of the article.

Note that a Fork of the Source 2013 Source 2013 codeline on GitHub exists in which these changes have been applied. Cloning this fork might be a good way to get these changes into your project.

Relationships

There is no relationship table set in Half-Life 2: Deathmatch. Without this table, NPCs won't know which entities to hate/like, and if Combine Soldiers like players, they won't attack them.

This is simple to fix. First go to 🖿hl2mp_gamerules.h, under void RestartGame(); add this:

 #ifndef CLIENT_DLL 
 void InitDefaultAIRelationships( void );
 #endif

Next go to 🖿hl2_gamerules.cpp and copy the entire InitDefaultAIRelationships() function. Paste it in 🖿hl2mp_gamerules.cpp.

Don't forget to put the copied functions from hl2_gamerules.cpp between #ifndef CLIENT_DLL and #endif.

And change void CHalfLife2::InitDefaultAIRelationships( void ) to void CHL2MPRules::InitDefaultAIRelationships( void ) in hl2mp_gamerules.cpp .

And Voula now you should have working relationships with npcs

Weapons

Activities & animation events

The weapons have custom activities and animation events used for the AI in HL2. In the HL2DM-versions of the weapons this is removed.

Open the 🖿weapon_hl2mpbase.h file and add the following code after the includes:

#ifndef CLIENT_DLL
	#include "AI_BaseNPC.h"
#endif

Now open the HL2SP files of the BaseHLBludgeonWeapon, AR2, shotgun, SMG1, crowbar, pistol, stunstick and frag grenade (found in dlls/hl2_dll/). The NPCs in HL2 don't use any other weapons. Each weapon has a Operator_HandleAnimEvent and/or CapabilitiesGet function, which the NPCs use to fire their weapons. Copy these functions and any other functions that are called in Operator_HandleAnimEvent to the HL2DM weaponfiles (found in game_shared/hl2mp/).

Don't forget the headers and put all copied functions between #ifndef CLIENT_DLL and #endif.

Also, you need to copy the activities. Look for m_acttable[] in the HL2SP-variants and copy them to the HL2DM-variants.

SetActivity()

Open 🖿basecombatweapon_shared.cpp and look for the function SetActivity. Look for the following code:

//Adrian: Oh man...
#if !defined( CLIENT_DLL ) && defined( HL2MP )
	SetModel( GetWorldModel() );
#endif

int sequence = SelectWeightedSequence( act ); 
	
	// FORCE IDLE on sequences we don't have (which should be many)
	if ( sequence == ACTIVITY_NOT_AVAILABLE )
		sequence = SelectWeightedSequence( ACT_VM_IDLE );

//Adrian: Oh man again...
#if !defined( CLIENT_DLL ) && defined( HL2MP )
	SetModel( GetViewModel() );
#endif

The activities can only be retrieved from weapon world models. However, the weapons of players are viewmodels. So with this little hack, the models are changed to worldmodel, and activities are retrieved and changed back to viewmodel. However considering NPCs don't have to see or work with their viewmodels, this is going to be changed:

	//Adrian: Oh man...
	if ( GetOwner()->IsPlayer() )
		SetModel( GetWorldModel() );
	
	int sequence = SelectWeightedSequence( act ); 
	
	// FORCE IDLE on sequences we don't have (which should be many)
	if ( sequence == ACTIVITY_NOT_AVAILABLE )
		sequence = SelectWeightedSequence( ACT_VM_IDLE );

	//Adrian: Oh man again...
	if ( GetOwner()->IsPlayer() )
		SetModel( GetViewModel() );

Ammotypes

The damage of the weapons need to use the data from 🖿skill.cfg. Don't forget to copy Half-Life 2 Half-Life 2's 🖿skill.cfg to your mod's cfg directory.

Also, the code needs to be told to use these values. Open 🖿hl2_gamerules.cpp again and copy the entire GetAmmoDef function. Replace the same function in hl2mp_gamerules.cpp with the copied code but add the following line:

def.AddAmmoType("slam", DMG_BURN, TRACER_NONE, 0, 0, 5, 0, 0);
Note.pngNote:HL2 doesn't have the SLAM and without that line the SLAM won't work anymore.

You need to include 🖿hl2_shareddefs.h in 🖿hl2mp_gamerules.cpp too. Otherwise, you will get two compiler errors C2065: 'DMG_SNIPER': undeclared identifier.

Model animations

Source's humanoid NPC models and deathmatch player models were not designed to be compatible with each other. The player and NPC versions both require different animations, and so depending on the order you mount your game content in (HL2DM before HL2, or vice versa) either humanoid NPCs or player animations will be completely missing, unless you use custom models.

Assuming you don't have new models, then two approaches are open to you.

  1. The first involves duplicating either the NPC or player models, and using a hex editor to direct the model to use a different animation file (eg create a renamed copy of the npc animations, and change NPC models to use that instead)
  2. Alternatively, you can try to "remap" the NPC animation names into player names in the code. A brief discussion of this method can be seen here: http://forums.steampowered.com/forums/showthread.php?t=752399

Function calls

Still, much of the AI code is still not designed to be used in multiplayer. All calls to the functions AI_GetSinglePlayer, AI_IsSingleplayer and UTIL_GetLocalPlayer would need fixing. Also pieces of code like if ( gpGlobals->maxClients == 1) and UTIL_PlayerByIndex( 1 ). There are hundreds of these calls, and it's lots of work to fix them all.

Note.pngNote:Take a look at this article if you need help fixing these function calls.

Lag compensation

Without lag compensation, when you shoot at a target, you have to take your ping time into account, and aim ahead of it accordingly. So if your ping is 100ms, you have to aim for where the target's head will be in 100ms, rather than where you see it right now.

Clearly, this is less than ideal, and so HL2DM incorporates lag compensation, which when calculating whether a bullet hits or not, briefly adjusts the position of all players back by the shooter's ping, so that it calculates the bullet collision based upon exactly what the shooter saw when they fired. This effect is missing for NPCs but can be duplicated from the player lag compensation code without too much trouble.

The NPC lag compensation article proved too long to include in this tutorial, it is instead located here.

Jerky animations

When ping times are large enough, NPC animation becomes extremely slow and jerky. There's a built-in mechanism to correct for this, interpolation. Essentially, it shows all NPCs etc slightly "back in time" by a few hundred milliseconds, essentially giving more buffer time for clients. It's controlled by a ConVar, and it would be best to have a slightly higher value by default, so open c_baseentity.cpp, and find

static ConVar  cl_interp_npcs( "cl_interp_npcs", "0.0", FCVAR_USERINFO, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)" );

Change the second parameter (default value) to 0.25, and now an unusually high ping will be required to distort animations.

static ConVar  cl_interp_npcs( "cl_interp_npcs", "0.25", FCVAR_USERINFO, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)" );


That's 250 milliseconds. Experiment with the net_fakelag console command to determine an optimal value, the higher value you provide, the higher latency users can have and still observe smooth animation. For 250 ms cl_interp_npcs, a net_fakelag of 150 ms still results in smooth animation. The higher the value you provide, however, the further NPCs will operate "in the past" - this only really presents a problem with fast zombies and headcrabs, as the user will appear to take damage while the NPC is still jumping towards them. If you are making a multiplayer zombie mod, it is recommended that you only set the ConVar to around 150, as it would decrease the effect of taking damage before being hit.

Instead of relying on interpolation, UseClientSideAnimation(); could be added to the CAI_BaseNPC constructor (in ai_basenpc.cpp) - however, this significantly dampens NPCs animations, and so is not recommended.

Blood

Thanks to the prediction, the blood of NPCs is suppressed. This is because in HL2DM the blood of players is done client-side. This is not the case with NPCs and the prediction needs to "break":

Open 🖿util_shared.cpp and look for the function UTIL_BloodDrips. Add to the top of the function:

IPredictionSystem::SuppressHostEvents( NULL );

Zombies

In 🖿BaseCombatCharacter.cpp (Or ai_basenpc.cpp?) find CAI_BaseNPC::Ignite and remove/comment out the #ifdef HL2_EPISODIC section. In npc_BaseZombie.cpp find CNPC_BaseZombie::MakeAISpookySound and remove/comment out its contents.

Patch

Including the 'function calls,' there are an awful lot of changes required to implement AI in a multiplayer mod. This patch file implements all the changes described here, (crucially) including correcting all the function calls and lag compensation code - so it should save you a good deal of dull coding work! See the readme for details of how it replaces calls to functions such as UTIL_GetLocalPlayer() & AI_GetSingleplayer(). Users requiring assistance in applying a patch file are directed here.

Due to Megaupload being closed, it has been uploaded using mirrorcreator.com which uploads to 8 various file hosting websites Download Here

Another direct link is Here

15th June 2009 HL2MP Patch

Note.pngNote:This version of the HL2MP patch file has been superseded by the OrangeBox CoOperative Base Modification which contains numerous fixes (alongside other game enhancements which can be removed/disabled). You will notice that this patch is a very early alpha version of OBCO (then called ShadowSource). If you feel up to the challenge you can also 'patch' your hl2mp modification manually by using the following tutorial (Please note that I no longer guarantee that this AI patch contains all the AI fixes included in the latest OBCO version!):

http://www.moddb.com/company/the-development-team/downloads/hl2mp-sdk-adding-hl2-ai-into-the-hl2mp-sourcesdk

If you don't wish to use OBCO or the manual tutorial, then here is the old patch.

The patch (which was made using the original Winston patch via copy & paste) can be downloaded from MegaUpload. Please note that this is the basic AI patch added to the new SDK, it behaves like the old patch.

There is a small bug that crept in on each weapon_*.cpp file. That is the ACT_ items are in #ifndef client_dll sections. This is incorrect, they (and the IMPLEMENT_ACTTABLE) should be outside these. If you don't fix these, then even if you get custom player animations to work, their activities won't be called so they'll continue to be t-posed with no animations.

For example in the weapon_ar2:

ifndef CLIENT_DLL
acttable_t	CWeaponAR2::m_acttable[] = 
{
	{ ACT_MP_STAND_IDLE,				ACT_HL2MP_IDLE_AR2,					false },

Should be:

acttable_t	CWeaponAR2::m_acttable[] = 
{
	{ ACT_MP_STAND_IDLE,				ACT_HL2MP_IDLE_AR2,					false },


Note.pngNote:Everything which was modified by the original AI patch is commented with either "//AI Patch" or "// AI Patch".
Warning.pngWarning:Because this comes from code I'd been modifying for my own requirements, there are additional changes. To remove my edits just search for //Modification

The files with modifications are:

  • client/episodic/c_prop_scalable.cpp
  • client/in_joystick.cpp
  • server/episodic/ep2_gamestats.cpp
  • server/player.cpp
  • shared/gamemovement.cpp
  • shared/gamemovement.h

Finally, additional GCF mounts are in 🖿client/cdll_client_int.cpp and 🖿server/gameinterface.cpp, which are commented as // MOUNTING ADDITIONAL GAMES LINES.

Note.pngNote:If sdk_gamerules.cpp gives errors during compilation after applying this patch, you may have to do the Relationships step manually.

Conclusion

While a lot of work is involved, particularly if the patch file is not used, the changes described here should fix most of the AI to a reasonable standard for use in multiplayer. Further changes that will be required, and there is probably room for optimisation in the "function call" fixes, but most NPCs should work well.