Porting to Orange Box
Porting Valve Server Plugins or Metamod:Source plugins to Orange Box is not very difficult. This article explores some of the changes and how to simplify them.
Users of Metamod:Source will need to upgrade to Metamod:Source 1.6.0. To do so, see Upgrading Plugins to Metamod:Source 1.6.0. The Orange Box SDK is also available from the Metamod:Source SVN.
This document will assume a single preprocessor macro, ORANGEBOX_BUILD, determines that an Orange Box build is being made.
Command Callbacks
In the original Half-Life 2 engine, all commands used IVEngineServer::Cmd_Arg* in order to receive information about the current command's tokenization. However, these functions have been completely removed, and a new re-entrant version is in place.
Each of the following callbacks:
void IServerGameClients::ClientCommand(edict_t *pEdict); typedef void (*FnCommandCallback)(void);
Is now:
void IServerGameClients::ClientCommand(edict_t *pEdict, const CCommand &args); typedef void (*FnCommandCallback)(const CCommand &args);
Definitions for CCommand can be found in convar.h. A simple way to work around this change is to use wrapper functions. For example:
#if defined ORANGEBOX_BUILD SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *, const CCommand &); #else SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *); #endif #if !defined ORANGEBOX_BUILD class CCommand { public: const char *ArgS() { return engine->Cmd_Args(); } int ArgC() { return engine->Cmd_Argc(); } const char *Arg(int index) { return engine->Cmd_Argv(index); } }; #endif #if defined ORANGEBOX_BUILD void Hook_ClientCommand(edict_t *pEntity, const CCommand &args) #else void Hook_ClientCommand(edict_t *pEntity) #endif { #if !defined ORANGEBOX_BUILD CCommand args; #endif const char *cmd = args.Arg(0); /* ... stuff ... */ }
ConCommandBaseMgr Removed
ConCommandBaseMgr has been removed. That means the normal call, ConCommandBaseMgr::OneTimeInit(), is no longer applicable. There are two other solutions to registering your ConVars and ConCommands:
- Use ConVar_Register instead.
- Use META_REGCVAR on each pointer (it will work on any ConCommandBase *) pointer, or META_REGCMD on each individual command name.
It is highly recommended that Metamod:Source plugins go through Metamod:Source's ConCommandBase registration process. This will make your plugin more compatible across engines and other plugins. Example:
class BaseAccessor : public IConCommandBaseAccessor { public: bool RegisterConCommandBase(ConCommandBase *pVar) { META_REGCVAR(pVar); } } s_BaseAccessor; void SetupEverything() { #if defined ORANGEBOX_BUILD ConVar_Register(0, &s_BaseAccessor); #else ConCommandBaseMgr::OneTimeInit(&s_BaseAccessor); #endif }