Progress on Half-Life Unified SDK
A fair amount of work has been done in recent weeks. These are the highlights:- Simplified the logging system to remove the need to create loggers in PostInitialize in some game systems
- Added file logging with configuration support in logging.json
- Added IGameSystem interface to help simplify how various systems are initialized and shut down
- Bunch of code cleanup including removal of redundant forward declarations and extern keyword, removing duplicated code and more
- Added
IMPLEMENT_CUSTOM_SCHEDULES
andDECLARE_COMMAND
macros to Visual Studio hint file so Intellisense stops showing green squiggles under usages - Reworked how client commands are handled on the server side to use a map of commands. Commands can be registered and unregistered at any time, this is done for gamemode-specific commands to simplify command handling
- Changed how weapon selection is handled to use a proper named client command (previously any
weapon_*
command was interpreted as a weapon selection command) - Added virtual destructor to
CGameRules
so the destructor runs properly - Re-implemented the
spectator
client command to function outside of the CTF gamemode. This command was made unavailable due to Opposing Force using an older version of the SDK as a base which didn't support spectator mode in all game modes. Opposing Force Updated does this for consistency with the original game, the Unified SDK allows the use of this mode in all game modes just like the Half-Life SDK does (even in singleplayer) - The hud color is now saved and restored, allowing it to persist between levels
- Fixed some Opposing Force code sending
ScoreInfo
messages with incorrect contents causing a fatal error (Opposing Force doesn't send the player class and team index values because it uses a different method of team-based gameplay) - Reworked how the health and model values are set to allow mappers to set custom values for both. Entities now initialize these in
OnCreate
, if a mapper-provided value exists it will be overridden inDispatchKeyValue
. All code usespev->model
now to support custom models, although some edge cases may exist - Removed NPC voice pitch restore hack (initial pitch value is set in
OnCreate
now) - Added global model replacement support. This feature lets you globally change references to a model to use another model instead. This does not apply to models used by the engine since those references cannot be changed
- The
PRECACHE_SOUND
macro has been removed, eitherCBaseEntity::PrecacheSound
(for entities) orUTIL_PrecacheSound
(for global precaching) should be used instead, org_engfuncs.PfnPrecacheSound
if you need to precache a sound unaffected by global model replacement - The
SET_MODEL
macro has been removed,CBaseEntity::SetModel
should be used instead - Weapons store off the world, view and player models they use to properly precache and restore these models as well as to adjust the active weapon model when changing levels (not intended for use outside of these use cases, but can be made more robust if necessary)
- Fixed
weapon_eagle
saving and restoring booleans as integers - The player's hud color and suit light type (flashlight or nightvision) can be configured from a configuration file now as well as through an entity and the console
- Simplified how game configurations are loaded by merging the data apply step into the parse step (more efficient, easier to use, less confusing)
I've recorded a short video that shows the Half-Life => Opposing Force => Blue Shift transition when changing maps: The first map has this configuration file:
{
"Sections": [
{
"Name": "HudColor",
"Color": "255 160 0"
},
{
"Name": "SuitLightType",
"Type": "flashlight"
}
]
}
These are the default values as well.The second map has this:
{
"Sections": [
{
"Name": "HudColor",
"Color": "0 160 0"
},
{
"Name": "SuitLightType",
"Type": "nightvision"
},
{
"Name": "GlobalModelReplacement",
"FileName": "cfg/maps/Op4ModelReplacement.json"
}
]
}
This configures the HUD color to Opposing Force green, the suit light type to night vision and it uses the Opposing Force model replacement file, which looks like this:
{
"models/v_9mmar.mdl": "models/op4/v_9mmar.mdl",
"models/v_9mmhandgun.mdl": "models/op4/v_9mmhandgun.mdl",
"models/v_357.mdl": "models/op4/v_357.mdl",
"models/v_chub.mdl": "models/op4/v_chub.mdl",
"models/v_crossbow.mdl": "models/op4/v_crossbow.mdl",
"models/v_crowbar.mdl": "models/op4/v_crowbar.mdl",
"models/v_desert_eagle.mdl": "models/op4/v_desert_eagle.mdl",
"models/v_displacer.mdl": "models/op4/v_displacer.mdl",
"models/v_egon.mdl": "models/op4/v_egon.mdl",
"models/v_gauss.mdl": "models/op4/v_gauss.mdl",
"models/v_grenade.mdl": "models/op4/v_grenade.mdl",
"models/v_hgun.mdl": "models/op4/v_hgun.mdl",
"models/v_knife.mdl": "models/op4/v_knife.mdl",
"models/v_m40a1.mdl": "models/op4/v_m40a1.mdl",
"models/v_penguin.mdl": "models/op4/v_penguin.mdl",
"models/v_pipe_wrench.mdl": "models/op4/v_pipe_wrench.mdl",
"models/v_rpg.mdl": "models/op4/v_rpg.mdl",
"models/v_satchel.mdl": "models/op4/v_satchel.mdl",
"models/v_satchel_radio.mdl": "models/op4/v_satchel_radio.mdl",
"models/v_saw.mdl": "models/op4/v_saw.mdl",
"models/v_shock.mdl": "models/op4/v_shock.mdl",
"models/v_shotgun.mdl": "models/op4/v_shotgun.mdl",
"models/v_spore_launcher.mdl": "models/op4/v_spore_launcher.mdl",
"models/v_squeak.mdl": "models/op4/v_squeak.mdl",
"models/v_tripmine.mdl": "models/op4/v_tripmine.mdl"
}
The third map uses this:
{
"Sections": [
{
"Name": "HudColor",
"Color": "95 95 255"
},
{
"Name": "SuitLightType",
"Type": "flashlight"
},
{
"Name": "GlobalModelReplacement",
"FileName": "cfg/maps/BlueShiftModelReplacement.json"
}
]
}
Same thing as Opposing Force.Config files can be included in other config files so a single file can be used to configure entire map packs pretty easily. The server config file can also do all of this so you can use that to configure a mod's default values.
The CTF game mode is the big exception since that still uses hard-coded values. Ideally those will also be configurable at some point.