S PreserveEnts: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Updated tf2's list; it has reliance on two separate files)
No edit summary
 
(43 intermediate revisions by 13 users not shown)
Line 1: Line 1:
{{stub}}
{{LanguageBar|title=s_PreserveEnts}}
{{DISPLAYTITLE:s_PreserveEnts}}
In multiplayer Source games, during a round reset, all entities are resetted to their defaults by being deleted then respawned, unless their current classnames matches an entry in the whitelist '''s_PreserveEnts'''. Whitelisted entities either has special code to handle the resetting process, and isn't ideal to be deleted.


Some whitelist entities however don't account round resets properly with their new behavior, so when a round reset occurs, their properties are carried over from the last round, like their [[origin]]s.
In multiplayer {{source|4}} games, all [[entity|entities]] are set back to their defaults during a round reset by removing and immediately respawning them, unless their ''current'' [[classname]]s match an entry in the {{mono|s_PreserveEnts}} whitelist. Whitelisted entities either have special code to handle the reset process or none at all, and the entity is therefore considered not ideal for removal.


{{todo|Attempt to finish this table. Some games might not have any way to reset the round (even through<code>mp_forcewin</code>or<code>mp_restartgame</code>commands).}}
Some whitelisted entities may not properly account for round resets and are likely to carry their previous properties over to the next round, such as their [[Coordinates|origins]].
 
{{note|
* Some games might not have any way to reset the round (even through {{mono|mp_forcewin}} or {{mono|mp_restartgame}} commands).
* [[Contexts]] aren't preserved between round restart even for preserved entities {{todotest|Left 4 Dead 2}}
}}
{| class="wikitable"
{| class="wikitable"
|-
|-
! Games
! Games !! Has Whitelist !! Has Rounds !! Notes
!{{as}}
|-
!{{csgo}}
|{{css|2}} || {{style|color:green|Yes}} || Yes ||
!{{css}}
|-
!{{dods}}
|{{hls|2}} || {{style|color:red|No}} || - ||
!{{hl2}}
|-
!{{hl2dm}}
|{{hldms|2}} || {{style|color:red|No}} || - ||
!{{ep1}}
|-
!{{ep2}}
|{{hl2|2}} || {{style|color:red|No}} || - ||
!{{l4d}}
|-
!{{l4d2}}
|{{hl2dm|2}} || {{style|color:green|Yes}} || No || Round can be reset using mp_restartgame
!{{portal}}
|-
!{{portal2}}
|{{dods|2}} || {{style|color:green|Yes}} || Yes ||
!{{tf2}}
|-
|{{hl2ep1|2}} || {{style|color:red|No}} || - ||
|-
|{{hl2ep2|2}} || {{style|color:red|No}} || - ||
|-
|{{portal|2}} || {{style|color:red|No}} || - || Whitelist exists, but is not included in the compiled DLLs.
|-
|{{tf2|2}} || {{style|color:green|Yes}} || Yes ||
|-
|{{l4d|2}} || {{style|color:green|Yes}} || Yes ||
|-
|{{l4d2|2}} ||  {{style|color:green|Yes}} || Yes ||
|-
|{{as|2}}{{asrd|2}} || {{style|color:green|Yes}} || No || <code>asw_instant_restart 1</code> should allow for round reset without full map reload but seems to always crash the game instead in {{as}}. It's the default behavior in {{asrd}} and works properly.<br>Uses {{mono|m_MapResetFilter.AddKeepEntity()}} function instead of {{mono|s_PreserveEnts[]}} array.
|-
|{{portal2|2}} || {{style|color:green|Yes}} || No || Can round be reset in coop?{{confirm}}
|-
|{{csgo|2}} || {{style|color:green|Yes}} || Yes ||
|-
|-
|'''Has Whitelist'''
||{{style|color:green|Yes}}
||{{style|color:green|Yes}}
||{{style|color:green|Yes}}
||{{style|color:green|Yes}}
||{{style|color:yellowgreen|No}}
||{{style|color:green|Yes}}
||{{style|color:yellowgreen|No}}
||{{style|color:yellowgreen|No}}
||{{style|color:orange|From code dump}}
||{{style|color:orange|From code dump}}
||{{style|color:green|Yes}}
||{{style|color:yellow|Unsure}}
||{{style|color:green|Yes}}
|}
|}


== Source Code ==
== Behavior ==
==={{hl2}}hl2mp/hl2mp_gamerules.cpp===
If the game has round restart mechanics, a preserved entity may not behave as expected:
{{ExpandBox|
* On a new round entities with this classname will '''intentionally not reset'''. You can use {{ent|logic_auto}} to emulate resetting it.
* [[Kill]]ing it removes it forever, as '''it is not respawned''' on a new round.
* It cannot be spawned with a {{ent|point_template}}.
* Parenting this with non-preserved entities may have [[Counter-Strike Source Entity Overview#Counter-Strike Round Restarts|undesirable effects]].
 
== Lists ==
{{note|Some entities don't exist in the given games despite being in s_preservedEnts list. (for example info_node* entities in {{l4ds}})}}
===Source Code===
 
 
===={{as|4}}====
{{expand|title={{mono|swarm/asw_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
CAlienSwarm::CAlienSwarm()
{
// set which entities should stay around when we restart the mission
m_MapResetFilter.AddKeepEntity("worldspawn");
m_MapResetFilter.AddKeepEntity("soundent");
m_MapResetFilter.AddKeepEntity("asw_gamerules");
m_MapResetFilter.AddKeepEntity("player");
m_MapResetFilter.AddKeepEntity("asw_player");
m_MapResetFilter.AddKeepEntity("player_manager");
m_MapResetFilter.AddKeepEntity("predicted_viewmodel");
m_MapResetFilter.AddKeepEntity("sdk_team_manager");
m_MapResetFilter.AddKeepEntity("scene_manager");
m_MapResetFilter.AddKeepEntity("event_queue_saveload_proxy");
m_MapResetFilter.AddKeepEntity("ai_network");
}
</syntaxhighlight>
}}
 
==== {{asrd|4}} ====
{{expand|title={{mono|swarm/asw_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
// set which entities should stay around when we restart the mission
m_MapResetFilter.AddKeepEntity( "worldspawn" );
m_MapResetFilter.AddKeepEntity( "soundent" );
m_MapResetFilter.AddKeepEntity( "asw_gamerules" );
m_MapResetFilter.AddKeepEntity( "player" );
m_MapResetFilter.AddKeepEntity( "asw_player" );
m_MapResetFilter.AddKeepEntity( "player_manager" );
m_MapResetFilter.AddKeepEntity( "predicted_viewmodel" );
m_MapResetFilter.AddKeepEntity( "sdk_team_manager" );
m_MapResetFilter.AddKeepEntity( "scene_manager" );
m_MapResetFilter.AddKeepEntity( "event_queue_saveload_proxy" );
m_MapResetFilter.AddKeepEntity( "ai_network" );
m_MapResetFilter.AddKeepEntity( "ai_hint" );
m_MapResetFilter.AddKeepEntity( "info_node" );
m_MapResetFilter.AddKeepEntity( "info_hint" );
m_MapResetFilter.AddKeepEntity( "info_node_hint" );
m_MapResetFilter.AddKeepEntity( "info_node_air" );
m_MapResetFilter.AddKeepEntity( "info_node_air_hint" );
m_MapResetFilter.AddKeepEntity( "info_node_climb" );
m_MapResetFilter.AddKeepEntity( "info_marine_hint" );
m_MapResetFilter.AddKeepEntity( "info_node_marine_hint" );
m_MapResetFilter.AddKeepEntity( "infodecal" );
 
// riflemod: keep health regen entity all the time
m_MapResetFilter.AddKeepEntity( "asw_health_regen" );
</syntaxhighlight>}}
 
===={{csgo|4}}====
{{expand|title={{mono|cstrike15/cs_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 47: Line 115:
"ai_network",
"ai_network",
"ai_hint",
"ai_hint",
"hl2mp_gamerules",
"cs_gamerules",
"team_manager",
"cs_team_manager",
"player_manager",
"cs_player_manager",
"env_soundscape",
"env_soundscape",
"env_soundscape_proxy",
"env_soundscape_proxy",
Line 56: Line 124:
"env_wind",
"env_wind",
"env_fog_controller",
"env_fog_controller",
"env_tonemap_controller",
"env_cascade_light",
"func_brush",
"func_brush",
"func_wall",
"func_wall",
"func_buyzone",
"func_buyzone",
"func_illusionary",
"func_illusionary",
"func_hostage_rescue",
"func_bomb_target",
"infodecal",
"infodecal",
"info_projecteddecal",
"info_projecteddecal",
Line 65: Line 137:
"info_target",
"info_target",
"info_node_hint",
"info_node_hint",
"info_player_deathmatch",
"info_player_counterterrorist",
"info_player_combine",
"info_player_terrorist",
"info_player_rebel",
"info_enemy_terrorist_spawn",
"info_deathmatch_spawn",
"info_armsrace_counterterrorist",
"info_armsrace_terrorist",
"info_map_parameters",
"info_map_parameters",
"keyframe_rope",
"keyframe_rope",
Line 74: Line 149:
"player",
"player",
"point_viewcontrol",
"point_viewcontrol",
"point_viewcontrol_multiplayer",
"scene_manager",
"scene_manager",
"shadow_control",
"shadow_control",
Line 83: Line 159:
"worldspawn",
"worldspawn",
"point_devshot_camera",
"point_devshot_camera",
"logic_choreographed_scene",
"cfe_player_decal",
"info_bomb_target_hint_A",
"info_bomb_target_hint_B",
"info_hostage_rescue_zone_hint",
"generic_actor",
"vote_controller",
"wearable_item",
"point_hiding_spot",
"game_coopmission_manager",
"chicken",
"", // END Marker
"", // END Marker
};
};
Line 88: Line 175:
}}
}}


==={{portal}}portal/portal_mp_gamerules.cpp===
===={{css|4}}====
{{ExpandBox|
{{expand|title={{mono|cstrike/cs_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 95: Line 182:
"ai_network",
"ai_network",
"ai_hint",
"ai_hint",
"hl2mp_gamerules",
"cs_gamerules",
"team_manager",
"cs_team_manager",
"player_manager",
"cs_player_manager",
"env_soundscape",
"env_soundscape",
"env_soundscape_proxy",
"env_soundscape_proxy",
Line 108: Line 195:
"func_buyzone",
"func_buyzone",
"func_illusionary",
"func_illusionary",
"func_hostage_rescue",
"func_bomb_target",
"infodecal",
"infodecal",
"info_projecteddecal",
"info_projecteddecal",
Line 113: Line 202:
"info_target",
"info_target",
"info_node_hint",
"info_node_hint",
"info_player_deathmatch",
"info_player_counterterrorist",
"info_player_combine",
"info_player_terrorist",
"info_player_rebel",
"info_map_parameters",
"info_map_parameters",
"keyframe_rope",
"keyframe_rope",
Line 136: Line 224:
}}
}}


==={{tf2}}(Multiple Files)===
===={{dods|4}}====
{| width=100%
{{expand|title={{mono|dod/dod_gamerules.cpp}}|
|- style="vertical-align:top;"
<syntaxhighlight lang="cpp">
| {{ExpandBox|noendlinebreak=1|<syntaxhighlight lang="cpp">
// Classnames of entities that are preserved across round restarts
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
{
{
Line 149: Line 235:
"ai_network",
"ai_network",
"ai_hint",
"ai_hint",
"dod_gamerules",
"dod_team_manager",
"dod_player_manager",
"dod_objective_resource",
"env_soundscape",
"env_soundscape",
"env_soundscape_proxy",
"env_soundscape_proxy",
Line 156: Line 246:
"env_wind",
"env_wind",
"env_fog_controller",
"env_fog_controller",
"func_brush",
"func_wall",
"func_wall",
"func_illusionary",
"func_illusionary",
Line 161: Line 252:
"info_target",
"info_target",
"info_node_hint",
"info_node_hint",
"point_commentary_node",
"info_player_allies",
"info_player_axis",
"point_viewcontrol",
"point_viewcontrol",
"func_precipitation",
"func_team_wall",
"shadow_control",
"shadow_control",
"sky_camera",
"sky_camera",
"scene_manager",
"scene_manager",
"trigger_soundscape",
"trigger_soundscape",
"commentary_auto",
"info_dod_detect",
"dod_team_allies",
"dod_team_axis",
"point_commentary_node",
"point_commentary_node",
"point_commentary_viewpoint",
"dod_round_timer",
"bot_roster",
"func_precipitation",
"info_populator",
"func_team_wall",
"", // END Marker
"", // END Marker
};</syntaxhighlight>| teamplayroundbased_gamerules.cpp }}
};
| {{ExpandBox|noendlinebreak=1|<syntaxhighlight lang="cpp">
</syntaxhighlight>
// Classnames of entities that are preserved across round restarts
}}
static const char *s_PreserveEnts[] =
{
"tf_gamerules",
"tf_team_manager",
"tf_player_manager",
"tf_team",
"tf_objective_resource",
"keyframe_rope",
"move_rope",
"tf_viewmodel",
"tf_logic_training",
"tf_logic_training_mode",
#ifdef TF_RAID_MODE
"tf_logic_raid",
#endif // TF_RAID_MODE
"tf_powerup_bottle",
"tf_mann_vs_machine_stats",
"tf_wearable",
"tf_wearable_demoshield",
"tf_wearable_robot_arm",
"tf_wearable_vm",
"tf_logic_bonusround",
"vote_controller",
"monster_resource",
"tf_logic_medieval",
"tf_logic_cp_timer",
"tf_logic_tower_defense", // legacy
"tf_logic_mann_vs_machine",
"func_upgradestation",
"entity_rocket",
"entity_carrier",
"entity_sign",
"entity_saucer",
"tf_halloween_gift_pickup",
"tf_logic_competitive",
"", // END Marker
};</syntaxhighlight>| tf/tf_gamerules.cpp }}
|}


==={{css}}cstrike/cs_gamerules.cpp===
===={{hl2dm|4}}====
{{ExpandBox|
{{Expand|title={{mono|hl2mp/hl2mp_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 224: Line 278:
"ai_network",
"ai_network",
"ai_hint",
"ai_hint",
"cs_gamerules",
"hl2mp_gamerules",
"cs_team_manager",
"team_manager",
"cs_player_manager",
"player_manager",
"env_soundscape",
"env_soundscape",
"env_soundscape_proxy",
"env_soundscape_proxy",
Line 237: Line 291:
"func_buyzone",
"func_buyzone",
"func_illusionary",
"func_illusionary",
"func_hostage_rescue",
"func_bomb_target",
"infodecal",
"infodecal",
"info_projecteddecal",
"info_projecteddecal",
Line 244: Line 296:
"info_target",
"info_target",
"info_node_hint",
"info_node_hint",
"info_player_counterterrorist",
"info_player_deathmatch",
"info_player_terrorist",
"info_player_combine",
"info_player_rebel",
"info_map_parameters",
"info_map_parameters",
"keyframe_rope",
"keyframe_rope",
Line 266: Line 319:
}}
}}


==={{csgo}}cstrike15/cs_gamerules.cpp===
===={{portal2|4}}====
{{ExpandBox|
{{Expand|title={{mono|portal/portal_mp_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
{
{
"ai_network",
"ai_network",
"ai_hint",
"ai_hint",
"cs_gamerules",
"hl2mp_gamerules",
"cs_team_manager",
"team_manager",
"cs_player_manager",
"player_manager",
"env_soundscape",
"env_soundscape",
"env_soundscape_proxy",
"env_soundscape_proxy",
"env_soundscape_triggerable",
"env_soundscape_triggerable",
"env_sun",
"env_sun",
"env_wind",
"env_wind",
"env_fog_controller",
"env_fog_controller",
"env_tonemap_controller",
"func_brush",
"env_cascade_light",
"func_wall",
"func_brush",
"func_buyzone",
"func_wall",
"func_illusionary",
"func_buyzone",
"infodecal",
"func_illusionary",
"info_projecteddecal",
"func_hostage_rescue",
"info_node",
"func_bomb_target",
"info_target",
"infodecal",
"info_node_hint",
"info_projecteddecal",
"info_player_deathmatch",
"info_node",
"info_player_combine",
"info_target",
"info_player_rebel",
"info_node_hint",
"info_map_parameters",
"info_player_counterterrorist",
"keyframe_rope",
"info_player_terrorist",
"move_rope",
"info_enemy_terrorist_spawn",
"info_ladder",
"info_deathmatch_spawn",
"player",
"info_armsrace_counterterrorist",
"point_viewcontrol",
"info_armsrace_terrorist",
"scene_manager",
"info_map_parameters",
"shadow_control",
"keyframe_rope",
"sky_camera",
"move_rope",
"soundent",
"info_ladder",
"trigger_soundscape",
"player",
"viewmodel",
"point_viewcontrol",
"predicted_viewmodel",
"point_viewcontrol_multiplayer",
"worldspawn",
"scene_manager",
"point_devshot_camera",
"shadow_control",
"", // END Marker
"sky_camera",
"soundent",
"trigger_soundscape",
"viewmodel",
"predicted_viewmodel",
"worldspawn",
"point_devshot_camera",
"logic_choreographed_scene",
"cfe_player_decal",
"info_bomb_target_hint_A",
"info_bomb_target_hint_B",
"info_hostage_rescue_zone_hint",
"generic_actor",
"vote_controller",
"wearable_item",
"point_hiding_spot",
"game_coopmission_manager",
"chicken",
"", // END Marker
};
};
</syntaxhighlight>
</syntaxhighlight>
}}
}}


==={{dods}}dod/dod_gamerules.cpp===
===={{tf2|4}}====
{{ExpandBox|
{{Expand|title={{mono|teamplayroundbased_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
// Classnames of entities that are preserved across round restarts
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
{
{
Line 344: Line 379:
"ai_network",
"ai_network",
"ai_hint",
"ai_hint",
"dod_gamerules",
"dod_team_manager",
"dod_player_manager",
"dod_objective_resource",
"env_soundscape",
"env_soundscape",
"env_soundscape_proxy",
"env_soundscape_proxy",
Line 355: Line 386:
"env_wind",
"env_wind",
"env_fog_controller",
"env_fog_controller",
"func_brush",
"func_wall",
"func_wall",
"func_illusionary",
"func_illusionary",
Line 361: Line 391:
"info_target",
"info_target",
"info_node_hint",
"info_node_hint",
"info_player_allies",
"point_commentary_node",
"info_player_axis",
"point_viewcontrol",
"point_viewcontrol",
"func_precipitation",
"func_team_wall",
"shadow_control",
"shadow_control",
"sky_camera",
"sky_camera",
"scene_manager",
"scene_manager",
"trigger_soundscape",
"trigger_soundscape",
"info_dod_detect",
"commentary_auto",
"dod_team_allies",
"dod_team_axis",
"point_commentary_node",
"point_commentary_node",
"dod_round_timer",
"point_commentary_viewpoint",
"func_precipitation",
"bot_roster",
"func_team_wall",
"info_populator",
"", // END Marker
"", // END Marker
};
};</syntaxhighlight>}}
</syntaxhighlight>
}}


==={{as}}swarm/asw_gamerules.cpp===
{{expand|title={{mono|tf/tf_gamerules.cpp}}|
{{ExpandBox|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
CAlienSwarm::CAlienSwarm()
// Classnames of entities that are preserved across round restarts
static const char *s_PreserveEnts[] =
{
{
// set which entities should stay around when we restart the mission
"tf_gamerules",
m_MapResetFilter.AddKeepEntity("worldspawn");
"tf_team_manager",
m_MapResetFilter.AddKeepEntity("soundent");
"tf_player_manager",
m_MapResetFilter.AddKeepEntity("asw_gamerules");
"tf_team",
m_MapResetFilter.AddKeepEntity("player");
"tf_objective_resource",
m_MapResetFilter.AddKeepEntity("asw_player");
"keyframe_rope",
m_MapResetFilter.AddKeepEntity("player_manager");
"move_rope",
m_MapResetFilter.AddKeepEntity("predicted_viewmodel");
"tf_viewmodel",
m_MapResetFilter.AddKeepEntity("sdk_team_manager");
"tf_logic_training",
m_MapResetFilter.AddKeepEntity("scene_manager");
"tf_logic_training_mode",
m_MapResetFilter.AddKeepEntity("event_queue_saveload_proxy");
"tf_powerup_bottle",
m_MapResetFilter.AddKeepEntity("ai_network");
"tf_mann_vs_machine_stats",
}
"tf_wearable",
</syntaxhighlight>
"tf_wearable_demoshield",
}}
"tf_wearable_robot_arm",
"tf_wearable_vm",
"tf_logic_bonusround",
"vote_controller",
"monster_resource",
"tf_logic_medieval",
"tf_logic_cp_timer",
"tf_logic_tower_defense", // legacy
"tf_logic_mann_vs_machine",
"func_upgradestation",
"entity_rocket",
"entity_carrier",
"entity_sign",
"entity_saucer",
"tf_halloween_gift_pickup",
"tf_logic_competitive",
"tf_wearable_razorback",
"entity_soldier_statue",
"", // END Marker
};</syntaxhighlight>}}
 
===Code Dumps===
To find the {{mono|S_PreserveEnts}} whitelist in the Left 4 Dead games in IDA:
# Search for the {{ent|ai_network}} string reference.
# Bring up all applicable XREFs.
# Search for the list that includes {{ent|survivor_bot}} and {{ent|logic_versus_random}}.


== Code Dumps ==
===={{l4d|4}}====
=== {{l4d}} Left 4 Dead ===
{{expand|
22/07/2021 - Steps: [IDA]<br>
1. Search for the<code>ai_network</code>string reference.<br>
2. Bring up the XREFs of the reference.<br>
3. Find the list that has both<code>survivor_bot</code>and<code>logic_versus_random</code>in it.
{{ExpandBox|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
; "ai_network",
; "ai_network",
Line 457: Line 504:
}}
}}


=== {{l4d2}} Left 4 Dead 2 ===
===={{l4d2|4}}====
22/07/2021 - Steps: [IDA]<br>
{{expand|
1. Search for the<code>ai_network</code>string reference.<br>
2. Bring up the XREFs of the reference.<br>
3. Find the list that has both<code>survivor_bot</code>and<code>logic_versus_random</code>in it.
{{ExpandBox|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
; "ai_network",
; "ai_network",

Latest revision as of 08:57, 8 May 2025

English (en)中文 (zh)Translate (Translate)

In multiplayer Source Source games, all entities are set back to their defaults during a round reset by removing and immediately respawning them, unless their current classnames match an entry in the s_PreserveEnts whitelist. Whitelisted entities either have special code to handle the reset process or none at all, and the entity is therefore considered not ideal for removal.

Some whitelisted entities may not properly account for round resets and are likely to carry their previous properties over to the next round, such as their origins.

Note.pngNote:
  • Some games might not have any way to reset the round (even through mp_forcewin or mp_restartgame commands).
  • Contexts aren't preserved between round restart even for preserved entities  (tested in: Left 4 Dead 2)
Games Has Whitelist Has Rounds Notes
Counter-Strike: Source Counter-Strike: Source Yes Yes
Half-Life: Source Half-Life: Source No -
Half-Life Deathmatch: Source Half-Life Deathmatch: Source No -
Half-Life 2 Half-Life 2 No -
Half-Life 2: Deathmatch Half-Life 2: Deathmatch Yes No Round can be reset using mp_restartgame
Day of Defeat: Source Day of Defeat: Source Yes Yes
Half-Life 2: Episode One Half-Life 2: Episode One No -
Half-Life 2: Episode Two Half-Life 2: Episode Two No -
Portal Portal No - Whitelist exists, but is not included in the compiled DLLs.
Team Fortress 2 Team Fortress 2 Yes Yes
Left 4 Dead Left 4 Dead Yes Yes
Left 4 Dead 2 Left 4 Dead 2 Yes Yes
Alien Swarm Alien SwarmAlien Swarm: Reactive Drop Alien Swarm: Reactive Drop Yes No asw_instant_restart 1 should allow for round reset without full map reload but seems to always crash the game instead in Alien Swarm. It's the default behavior in Alien Swarm: Reactive Drop and works properly.
Uses m_MapResetFilter.AddKeepEntity() function instead of s_PreserveEnts[] array.
Portal 2 Portal 2 Yes No Can round be reset in coop?[confirm]
Counter-Strike: Global Offensive Counter-Strike: Global Offensive Yes Yes

Behavior

If the game has round restart mechanics, a preserved entity may not behave as expected:

  • On a new round entities with this classname will intentionally not reset. You can use logic_auto to emulate resetting it.
  • Killing it removes it forever, as it is not respawned on a new round.
  • It cannot be spawned with a point_template.
  • Parenting this with non-preserved entities may have undesirable effects.

Lists

Note.pngNote:Some entities don't exist in the given games despite being in s_preservedEnts list. (for example info_node* entities in Left 4 Dead seriesLeft 4 Dead series)

Source Code

Alien Swarm Alien Swarm

swarm/asw_gamerules.cpp
CAlienSwarm::CAlienSwarm()
{
	// set which entities should stay around when we restart the mission
	m_MapResetFilter.AddKeepEntity("worldspawn");
	m_MapResetFilter.AddKeepEntity("soundent");
	m_MapResetFilter.AddKeepEntity("asw_gamerules");
	m_MapResetFilter.AddKeepEntity("player");
	m_MapResetFilter.AddKeepEntity("asw_player");
	m_MapResetFilter.AddKeepEntity("player_manager");	
	m_MapResetFilter.AddKeepEntity("predicted_viewmodel");
	m_MapResetFilter.AddKeepEntity("sdk_team_manager");
	m_MapResetFilter.AddKeepEntity("scene_manager");
	m_MapResetFilter.AddKeepEntity("event_queue_saveload_proxy");
	m_MapResetFilter.AddKeepEntity("ai_network");
}

Alien Swarm: Reactive Drop Alien Swarm: Reactive Drop

swarm/asw_gamerules.cpp
	// set which entities should stay around when we restart the mission
	m_MapResetFilter.AddKeepEntity( "worldspawn" );
	m_MapResetFilter.AddKeepEntity( "soundent" );
	m_MapResetFilter.AddKeepEntity( "asw_gamerules" );
	m_MapResetFilter.AddKeepEntity( "player" );
	m_MapResetFilter.AddKeepEntity( "asw_player" );
	m_MapResetFilter.AddKeepEntity( "player_manager" );
	m_MapResetFilter.AddKeepEntity( "predicted_viewmodel" );
	m_MapResetFilter.AddKeepEntity( "sdk_team_manager" );
	m_MapResetFilter.AddKeepEntity( "scene_manager" );
	m_MapResetFilter.AddKeepEntity( "event_queue_saveload_proxy" );
	m_MapResetFilter.AddKeepEntity( "ai_network" );
	m_MapResetFilter.AddKeepEntity( "ai_hint" );
	m_MapResetFilter.AddKeepEntity( "info_node" );
	m_MapResetFilter.AddKeepEntity( "info_hint" );
	m_MapResetFilter.AddKeepEntity( "info_node_hint" );
	m_MapResetFilter.AddKeepEntity( "info_node_air" );
	m_MapResetFilter.AddKeepEntity( "info_node_air_hint" );
	m_MapResetFilter.AddKeepEntity( "info_node_climb" );
	m_MapResetFilter.AddKeepEntity( "info_marine_hint" );
	m_MapResetFilter.AddKeepEntity( "info_node_marine_hint" );
	m_MapResetFilter.AddKeepEntity( "infodecal" );

	// riflemod: keep health regen entity all the time
	m_MapResetFilter.AddKeepEntity( "asw_health_regen" );

Counter-Strike: Global Offensive Counter-Strike: Global Offensive

cstrike15/cs_gamerules.cpp
static const char *s_PreserveEnts[] =
{
	"ai_network",
	"ai_hint",
	"cs_gamerules",
	"cs_team_manager",
	"cs_player_manager",
	"env_soundscape",
	"env_soundscape_proxy",
	"env_soundscape_triggerable",
	"env_sun",
	"env_wind",
	"env_fog_controller",
	"env_tonemap_controller",
	"env_cascade_light",
	"func_brush",
	"func_wall",
	"func_buyzone",
	"func_illusionary",
	"func_hostage_rescue",
	"func_bomb_target",
	"infodecal",
	"info_projecteddecal",
	"info_node",
	"info_target",
	"info_node_hint",
	"info_player_counterterrorist",
	"info_player_terrorist",
	"info_enemy_terrorist_spawn",
	"info_deathmatch_spawn",
	"info_armsrace_counterterrorist",
	"info_armsrace_terrorist",
	"info_map_parameters",
	"keyframe_rope",
	"move_rope",
	"info_ladder",
	"player",
	"point_viewcontrol",
	"point_viewcontrol_multiplayer",
	"scene_manager",
	"shadow_control",
	"sky_camera",
	"soundent",
	"trigger_soundscape",
	"viewmodel",
	"predicted_viewmodel",
	"worldspawn",
	"point_devshot_camera",
	"logic_choreographed_scene",
	"cfe_player_decal",
	"info_bomb_target_hint_A",
	"info_bomb_target_hint_B",
	"info_hostage_rescue_zone_hint",
	"generic_actor",
	"vote_controller",
	"wearable_item",
	"point_hiding_spot",
	"game_coopmission_manager",
	"chicken",
	"", // END Marker
};

Counter-Strike: Source Counter-Strike: Source

cstrike/cs_gamerules.cpp
static const char *s_PreserveEnts[] =
{
	"ai_network",
	"ai_hint",
	"cs_gamerules",
	"cs_team_manager",
	"cs_player_manager",
	"env_soundscape",
	"env_soundscape_proxy",
	"env_soundscape_triggerable",
	"env_sun",
	"env_wind",
	"env_fog_controller",
	"func_brush",
	"func_wall",
	"func_buyzone",
	"func_illusionary",
	"func_hostage_rescue",
	"func_bomb_target",
	"infodecal",
	"info_projecteddecal",
	"info_node",
	"info_target",
	"info_node_hint",
	"info_player_counterterrorist",
	"info_player_terrorist",
	"info_map_parameters",
	"keyframe_rope",
	"move_rope",
	"info_ladder",
	"player",
	"point_viewcontrol",
	"scene_manager",
	"shadow_control",
	"sky_camera",
	"soundent",
	"trigger_soundscape",
	"viewmodel",
	"predicted_viewmodel",
	"worldspawn",
	"point_devshot_camera",
	"", // END Marker
};

Day of Defeat: Source Day of Defeat: Source

dod/dod_gamerules.cpp
static const char *s_PreserveEnts[] =
{
	"player",
	"viewmodel",
	"worldspawn",
	"soundent",
	"ai_network",
	"ai_hint",
	"dod_gamerules",
	"dod_team_manager",
	"dod_player_manager",
	"dod_objective_resource",
	"env_soundscape",
	"env_soundscape_proxy",
	"env_soundscape_triggerable",
	"env_sprite",
	"env_sun",
	"env_wind",
	"env_fog_controller",
	"func_brush",
	"func_wall",
	"func_illusionary",
	"info_node",
	"info_target",
	"info_node_hint",
	"info_player_allies",
	"info_player_axis",
	"point_viewcontrol",
	"shadow_control",
	"sky_camera",
	"scene_manager",
	"trigger_soundscape",
	"info_dod_detect",
	"dod_team_allies",
	"dod_team_axis",
	"point_commentary_node",
	"dod_round_timer",
	"func_precipitation",
	"func_team_wall",
	"", // END Marker
};

Half-Life 2: Deathmatch Half-Life 2: Deathmatch

hl2mp/hl2mp_gamerules.cpp
static const char *s_PreserveEnts[] =
{
	"ai_network",
	"ai_hint",
	"hl2mp_gamerules",
	"team_manager",
	"player_manager",
	"env_soundscape",
	"env_soundscape_proxy",
	"env_soundscape_triggerable",
	"env_sun",
	"env_wind",
	"env_fog_controller",
	"func_brush",
	"func_wall",
	"func_buyzone",
	"func_illusionary",
	"infodecal",
	"info_projecteddecal",
	"info_node",
	"info_target",
	"info_node_hint",
	"info_player_deathmatch",
	"info_player_combine",
	"info_player_rebel",
	"info_map_parameters",
	"keyframe_rope",
	"move_rope",
	"info_ladder",
	"player",
	"point_viewcontrol",
	"scene_manager",
	"shadow_control",
	"sky_camera",
	"soundent",
	"trigger_soundscape",
	"viewmodel",
	"predicted_viewmodel",
	"worldspawn",
	"point_devshot_camera",
	"", // END Marker
};

Portal 2 Portal 2

portal/portal_mp_gamerules.cpp
static const char *s_PreserveEnts[] =
{
	"ai_network",
		"ai_hint",
		"hl2mp_gamerules",
		"team_manager",
		"player_manager",
		"env_soundscape",
		"env_soundscape_proxy",
		"env_soundscape_triggerable",
		"env_sun",
		"env_wind",
		"env_fog_controller",
		"func_brush",
		"func_wall",
		"func_buyzone",
		"func_illusionary",
		"infodecal",
		"info_projecteddecal",
		"info_node",
		"info_target",
		"info_node_hint",
		"info_player_deathmatch",
		"info_player_combine",
		"info_player_rebel",
		"info_map_parameters",
		"keyframe_rope",
		"move_rope",
		"info_ladder",
		"player",
		"point_viewcontrol",
		"scene_manager",
		"shadow_control",
		"sky_camera",
		"soundent",
		"trigger_soundscape",
		"viewmodel",
		"predicted_viewmodel",
		"worldspawn",
		"point_devshot_camera",
		"", // END Marker
};

Team Fortress 2 Team Fortress 2

teamplayroundbased_gamerules.cpp
// Classnames of entities that are preserved across round restarts
static const char *s_PreserveEnts[] =
{
	"player",
	"viewmodel",
	"worldspawn",
	"soundent",
	"ai_network",
	"ai_hint",
	"env_soundscape",
	"env_soundscape_proxy",
	"env_soundscape_triggerable",
	"env_sprite",
	"env_sun",
	"env_wind",
	"env_fog_controller",
	"func_wall",
	"func_illusionary",
	"info_node",
	"info_target",
	"info_node_hint",
	"point_commentary_node",
	"point_viewcontrol",
	"func_precipitation",
	"func_team_wall",
	"shadow_control",
	"sky_camera",
	"scene_manager",
	"trigger_soundscape",
	"commentary_auto",
	"point_commentary_node",
	"point_commentary_viewpoint",
	"bot_roster",
	"info_populator",
	"", // END Marker
};
tf/tf_gamerules.cpp
// Classnames of entities that are preserved across round restarts
static const char *s_PreserveEnts[] =
{
	"tf_gamerules",
	"tf_team_manager",
	"tf_player_manager",
	"tf_team",
	"tf_objective_resource",
	"keyframe_rope",
	"move_rope",
	"tf_viewmodel",
	"tf_logic_training",
	"tf_logic_training_mode",
	"tf_powerup_bottle",
	"tf_mann_vs_machine_stats",
	"tf_wearable",
	"tf_wearable_demoshield",
	"tf_wearable_robot_arm",
	"tf_wearable_vm",
	"tf_logic_bonusround",
	"vote_controller",
	"monster_resource",
	"tf_logic_medieval",
	"tf_logic_cp_timer",
	"tf_logic_tower_defense",	// legacy
	"tf_logic_mann_vs_machine",
	"func_upgradestation",
	"entity_rocket",
	"entity_carrier",
	"entity_sign",
	"entity_saucer",
	"tf_halloween_gift_pickup",
	"tf_logic_competitive",
	"tf_wearable_razorback",
	"entity_soldier_statue",
	"", // END Marker
};

Code Dumps

To find the S_PreserveEnts whitelist in the Left 4 Dead games in IDA:

  1. Search for the ai_network string reference.
  2. Bring up all applicable XREFs.
  3. Search for the list that includes survivor_bot and logic_versus_random.

Left 4 Dead Left 4 Dead

; "ai_network",
; "ai_hint",
; "cs_team_manager",
; "terror_gamerules",
; "terror_player_manager",
; "survivor_bot",
; "env_tonemap_controller",
; "env_tonemap_controller_infected",
; "env_tonemap_controller_ghost",
; "vote_controller",
; "env_soundscape",
; "env_soundscape_proxy",
; "env_soundscape_triggerable",
; "env_sun",
; "env_wind",
; "env_fog_controller",
; "func_wall",
; "func_buyzone",
; "func_illusionary",
; "func_hostage_rescue",
; "func_bomb_target",
; "infodecal",
; "info_projecteddecal",
; "info_node",
; "info_target",
; "info_node_hint",
; "info_player_counterterrorist",
; "info_player_terrorist",
; "info_map_parameters",
; "info_map_parameters_versus",
; "info_ladder",
; "func_simpleladder",
; "player",
; "point_viewcontrol",
; "scene_manager",
; "shadow_control",
; "sky_camera",
; "soundent",
; "trigger_soundscape",
; "viewmodel",
; "predicted_viewmodel",
; "worldspawn",
; "point_devshot_camera",
; "info_survivor_position",
; "logic_versus_random",

Left 4 Dead 2 Left 4 Dead 2

; "ai_network",
; "ai_hint",
; "cs_team_manager",
; "terror_gamerules",
; "terror_player_manager",
; "survivor_bot",
; "env_tonemap_controller",
; "env_tonemap_controller_infected",
; "env_tonemap_controller_ghost",
; "vote_controller",
; "env_soundscape",
; "env_soundscape_proxy",
; "env_soundscape_triggerable",
; "env_sun",
; "env_wind",
; "env_fog_controller",
; "func_wall",
; "infodecal",
; "info_projecteddecal",
; "info_node",
; "info_node_hint",
; "info_map_parameters",
; "info_map_parameters_versus",
; "info_ladder",
; "func_simpleladder",
; "player",
; "point_viewcontrol",
; "scene_manager",
; "shadow_control",
; "sky_camera",
; "soundent",
; "trigger_soundscape",
; "viewmodel",
; "predicted_viewmodel",
; "worldspawn",
; "point_devshot_camera",
; "weapon_scavenge_item_spawn",
; "logic_versus_random",