S PreserveEnts: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Updated tf2 list with most recent version from 2018, by reverse-engineered binaries)
No edit summary
 
(54 intermediate revisions by 15 users not shown)
Line 1: Line 1:
{{DISPLAYTITLE:s_PreserveEnts}}
{{LanguageBar|title=s_PreserveEnts}}
In multiplayer Source games, when a round is reset in some way, all entities are deleted and then respawned to quickly reset the map. However, a list of entities to ''not'' reset exists. Usually these entities have special code to handle the resetting process. The {{ent|player}} entity for example, should not ever be erased unless the client disconnects from the server.


Some entities in this list however, do not have any code for handling round resets, so when the reset occurs, those entities will behave in unwanted ways as they have carried over all their properties (including position) from the last round.
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 mp_forcewin or mp_restartgame).}}
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"
|-
|-
! !{{pergame}}
! Games !! Has Whitelist !! Has Rounds !! Notes
|-
|{{css|2}} || {{style|color:green|Yes}} || Yes ||
|-
|{{hls|2}} || {{style|color:red|No}} || - ||
|-
|{{hldms|2}} || {{style|color:red|No}} || - ||
|-
|{{hl2|2}} || {{style|color:red|No}} || - ||
|-
|{{hl2dm|2}} || {{style|color:green|Yes}} || No || Round can be reset using mp_restartgame
|-
|{{dods|2}} || {{style|color:green|Yes}} || Yes ||
|-
|{{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 ||
|-
|-
|Affects:
||{{style|color:yellow|Unsure}}
||{{style|color:yellow|Unsure}}
||{{style|color:green|Yes}}
||{{style|color:green|Yes}}
||N/A
||{{style|color:green|Yes}}
||N/A
||N/A
||{{style|color:yellow|Unsure}}
||{{style|color:yellow|Unsure}}
||{{style|color:green|Yes}}
||{{style|color:yellow|Unsure}}
||{{style|color:green|Yes}}
|}
|}


=={{hl2}}hl2mp/hl2mp_gamerules.cpp==
== Behavior ==
<pre>
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 {{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">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
{
{
"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 40: 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 49: 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 58: Line 149:
"player",
"player",
"point_viewcontrol",
"point_viewcontrol",
"point_viewcontrol_multiplayer",
"scene_manager",
"scene_manager",
"shadow_control",
"shadow_control",
Line 67: 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
};
};
</pre>
</syntaxhighlight>
}}


=={{portal}}portal/portal_mp_gamerules.cpp==
===={{css|4}}====
<pre>
{{expand|title={{mono|cstrike/cs_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
{
{
"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 90: Line 195:
"func_buyzone",
"func_buyzone",
"func_illusionary",
"func_illusionary",
"func_hostage_rescue",
"func_bomb_target",
"infodecal",
"infodecal",
"info_projecteddecal",
"info_projecteddecal",
Line 95: 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 115: Line 221:
"", // END Marker
"", // END Marker
};
};
</pre>
</syntaxhighlight>
}}


=={{tf2}}tf/tf_gamerules.cpp==
===={{dods|4}}====
<pre>
{{expand|title={{mono|dod/dod_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
{
{
"tf_gamerules",
"player",
"tf_team_manager",
"viewmodel",
"tf_player_manager",
"worldspawn",
"tf_team",
"soundent",
"tf_objective_resource",
"ai_network",
"keyframe_rope",
"ai_hint",
"move_rope",
"dod_gamerules",
"tf_",
"dod_team_manager",
        "tf_logic_training",
"dod_player_manager",
"tf_logic_training_mode",
"dod_objective_resource",
        "tf_powerup_bottle",
"env_soundscape",
"tf_mann_vs_machine_stats",
"env_soundscape_proxy",
        "tf_wearable",
"env_soundscape_triggerable",
"tf_wearable_demoshield",
"env_sprite",
        "tf_wearable_robot_arm",
"env_sun",
"tf_wearable_vm",
"env_wind",
        "tf_logic_bonusround",
"env_fog_controller",
"vote_controller",
"func_brush",
        "monster_resource",
"func_wall",
"tf_logic_medieval",
"func_illusionary",
        "tf_logic_cp_timer",
"info_node",
"tf_logic_tower_defense",
"info_target",
        "func_upgradestation",
"info_node_hint",
"entity_rocket",
"info_player_allies",
        "entity_carrier",
"info_player_axis",
"entity_sign",
"point_viewcontrol",
        "entity_saucer",
"shadow_control",
        "tf_halloween_gift_pickup",
"sky_camera",
        "tf_logic_competitive",
"scene_manager",
        "tf_wearable_razorback",
"trigger_soundscape",
"info_dod_detect",
"dod_team_allies",
"dod_team_axis",
"point_commentary_node",
"dod_round_timer",
"func_precipitation",
"func_team_wall",
"", // END Marker
};
};
</pre>
</syntaxhighlight>
}}


=={{css}}cstrike/cs_gamerules.cpp==
===={{hl2dm|4}}====
<pre>
{{Expand|title={{mono|hl2mp/hl2mp_gamerules.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",
Line 173: Line 291:
"func_buyzone",
"func_buyzone",
"func_illusionary",
"func_illusionary",
"func_hostage_rescue",
"func_bomb_target",
"infodecal",
"infodecal",
"info_projecteddecal",
"info_projecteddecal",
Line 180: 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 199: Line 316:
"", // END Marker
"", // END Marker
};
};
</pre>
</syntaxhighlight>
}}
 
===={{portal2|4}}====
{{Expand|title={{mono|portal/portal_mp_gamerules.cpp}}|
<syntaxhighlight lang="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
};
</syntaxhighlight>
}}


=={{dods}}dod/dod_gamerules.cpp==
===={{tf2|4}}====
<pre>
{{Expand|title={{mono|teamplayroundbased_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
// Classnames of entities that are preserved across round restarts
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
{
{
Line 211: 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 222: Line 386:
"env_wind",
"env_wind",
"env_fog_controller",
"env_fog_controller",
"func_brush",
"func_wall",
"func_wall",
"func_illusionary",
"func_illusionary",
Line 228: 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
};</syntaxhighlight>}}
 
{{expand|title={{mono|tf/tf_gamerules.cpp}}|
<syntaxhighlight lang="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
"", // END Marker
};
};</syntaxhighlight>}}
</pre>
 
===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}}.
 
===={{l4d|4}}====
{{expand|
<syntaxhighlight lang="cpp">
; "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",
</syntaxhighlight>
}}
 
===={{l4d2|4}}====
{{expand|
<syntaxhighlight lang="cpp">
; "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",
</syntaxhighlight>
}}

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",