S PreserveEnts: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Add HLS and HLDMS to list of whether there's a whitelist (they don't preserve))
No edit summary
Line 1: Line 1:
{{LanguageBar|title=s_PreserveEnts}}
{{LanguageBar|title=s_PreserveEnts}}


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'' classnames matches an entry in the <code>s_PreserveEnts</code> 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.
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'' classnames matches 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.


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]].
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 <code>mp_forcewin</code> or <code>mp_restartgame</code> commands).}}
{{note|Some games might not have any way to reset the round (even through {{mono|mp_forcewin}} or {{mono|mp_restartgame}} commands).}}
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 44: Line 44:
==Source Code==
==Source Code==
==={{hl2dm|4}}===
==={{hl2dm|4}}===
{{Expand|title=<code>hl2mp/hl2mp_gamerules.cpp</code>|
{{Expand|title={{mono|hl2mp/hl2mp_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 92: Line 92:


==={{portal|4}}===
==={{portal|4}}===
{{Expand|title=<code>portal/portal_mp_gamerules.cpp</code>|
{{Expand|title={{mono|portal/portal_mp_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 140: Line 140:


==={{portal2|4}}===
==={{portal2|4}}===
{{Expand|title=<code>portal/portal_mp_gamerules.cpp</code>|
{{Expand|title={{mono|portal/portal_mp_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 188: Line 188:


==={{tf2|4}}===
==={{tf2|4}}===
{{Expand|title=<code>teamplayroundbased_gamerules.cpp</code>|
{{Expand|title={{mono|teamplayroundbased_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
// Classnames of entities that are preserved across round restarts
// Classnames of entities that are preserved across round restarts
Line 227: Line 227:
};</syntaxhighlight>}}
};</syntaxhighlight>}}


{{expand|title=<code>tf/tf_gamerules.cpp</code>|
{{expand|title={{mono|tf/tf_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
// Classnames of entities that are preserved across round restarts
// Classnames of entities that are preserved across round restarts
Line 268: Line 268:


==={{css|4}}===
==={{css|4}}===
{{expand|title=<code>cstrike/cs_gamerules.cpp</code>|
{{expand|title={{mono|cstrike/cs_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 317: Line 317:


==={{csgo|4}}===
==={{csgo|4}}===
{{expand|title=<code>cstrike15/cs_gamerules.cpp</code>|
{{expand|title={{mono|cstrike15/cs_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 384: Line 384:


==={{dods|4}}===
==={{dods|4}}===
{{expand|title=<code>dod/dod_gamerules.cpp</code>|
{{expand|title={{mono|dod/dod_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
static const char *s_PreserveEnts[] =
static const char *s_PreserveEnts[] =
Line 431: Line 431:


==={{as|4}}===
==={{as|4}}===
{{expand|title=<code>swarm/asw_gamerules.cpp</code>|
{{expand|title={{mono|swarm/asw_gamerules.cpp}}|
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
CAlienSwarm::CAlienSwarm()
CAlienSwarm::CAlienSwarm()
Line 452: Line 452:


==Code Dumps==
==Code Dumps==
To find the <code>S_PreserveEnts</code> whitelist in the Left 4 Dead games in IDA:
To find the {{mono|S_PreserveEnts}} whitelist in the Left 4 Dead games in IDA:
# Search for the {{ent|ai_network}} string reference.
# Search for the {{ent|ai_network}} string reference.
# Bring up all applicable XREFs.
# Bring up all applicable XREFs.

Revision as of 13:00, 4 December 2024

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 matches 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).
Games Counter-Strike: Source Half-Life: Source Half-Life Deathmatch: Source Half-Life 2 Half-Life 2: Deathmatch Day of Defeat: Source Half-Life 2: Episode One Half-Life 2: Episode Two Portal Team Fortress 2 Left 4 Dead Left 4 Dead 2 Alien Swarm Portal 2 Counter-Strike: Global Offensive
Has Whitelist Yes No No No Yes Yes No No Yes Yes Yes (Disassembly) Yes Yes Yes

Source Code

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 Portal

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
};

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
};

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
};

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
};

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
};

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");
}

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