Skip to content

Commit

Permalink
add reloadplugin command + update plugin api
Browse files Browse the repository at this point in the history
exposed more code and added more hooks
  • Loading branch information
wootguy committed Nov 3, 2024
1 parent 168f1ea commit f85e1fa
Show file tree
Hide file tree
Showing 17 changed files with 220 additions and 114 deletions.
8 changes: 6 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ include_directories(${CMAKE_SOURCE_DIR}/dlls/monster)
include_directories(${CMAKE_SOURCE_DIR}/dlls/item)
include_directories(${CMAKE_SOURCE_DIR}/dlls/path)
include_directories(${CMAKE_SOURCE_DIR}/dlls/weapon)
include_directories(${CMAKE_SOURCE_DIR}/dlls/net)
include_directories(${CMAKE_SOURCE_DIR}/dlls/)

project(sevenkewp)
Expand All @@ -45,8 +46,11 @@ if (BUILD_PLUGINS)
include(${CMAKE_SOURCE_DIR}/scripts/hlcoop_plugin.cmake)
set(PLUGIN_DIR "${CMAKE_CURRENT_LIST_DIR}/plugins")
file(GLOB ALL_ITEMS "${PLUGIN_DIR}/*")
message(STATUS "Note: Local plugin changes are discarded when built in BUILD_PLUGINS mode")


if (UPDATE_PLUGINS)
message(STATUS "Note: Local plugin changes are discarded when built in UPDATE_PLUGINS mode")
endif()

foreach(ITEM ${ALL_ITEMS})
if(IS_DIRECTORY ${ITEM})
get_filename_component(REPO_NAME ${ITEM} NAME)
Expand Down
13 changes: 12 additions & 1 deletion dlls/PluginHooks.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#pragma once
#include "weaponinfo.h"
#include "entity_state.h"

#define HLCOOP_API_VERSION 2

Expand Down Expand Up @@ -77,6 +79,9 @@ struct HLCOOP_PLUGIN_HOOKS {

// called when a sound is about to be played, after the mod has handled sound replacement
HOOK_RETURN_DATA (*pfnEmitSound)(edict_t* pEntity, int channel, const char* pszSample, float volume, float attenuation, int fFlags, int pitch);

// called when an ambient sound is about to be played, after the mod has handled sound replacement
HOOK_RETURN_DATA (*pfnEmitAmbientSound)(edict_t* pEntity, const float* vecPos, const char* pszSample, float vol, float attenuation, int fFlags, int pitch);

// called when the mod registers a custom user message
HOOK_RETURN_DATA (*pfnRegUserMsg)(const char* name, int size);
Expand Down Expand Up @@ -118,7 +123,13 @@ struct HLCOOP_PLUGIN_HOOKS {
HOOK_RETURN_DATA (*pfnPrecacheModelPost)(const char* model);

// called before an event is played
HOOK_RETURN_DATA(*pfnPlaybackEvent)(int flags, const edict_t* pInvoker, unsigned short eventindex, float delay, float* origin, float* angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2);
HOOK_RETURN_DATA (*pfnPlaybackEvent)(int flags, const edict_t* pInvoker, unsigned short eventindex, float delay, float* origin, float* angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2);

// called before weapon data is updated
HOOK_RETURN_DATA (*pfnGetWeaponData)(edict_t* player, weapon_data_t* info);

// called after client data is updated by the mod and before it is returned to the engine
HOOK_RETURN_DATA (*pfnUpdateClientDataPost)(const edict_t* ent, int sendweapons, clientdata_t* cd);
};

EXPORT void RegisterPlugin(void* plugin, HLCOOP_PLUGIN_HOOKS* hooks, const char* name);
Expand Down
46 changes: 42 additions & 4 deletions dlls/PluginManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ bool PluginManager::AddPlugin(const char* fpath, bool isMapPlugin) {
plugin.fpath = fpath;
plugin.id = g_plugin_id++;

if (LoadPlugin(plugin)) {
plugins.push_back(plugin);
return true;
}

return false;
}

bool PluginManager::LoadPlugin(Plugin& plugin) {
#ifdef _WIN32
plugin.h_module = LoadLibraryA(plugin.fpath.c_str());
#else
Expand All @@ -76,7 +85,7 @@ bool PluginManager::AddPlugin(const char* fpath, bool isMapPlugin) {

if (!plugin.h_module) {
ALERT(at_error, "Plugin load failed '%s' (" LOADLIB_FUNC_NAME " error code %d)\n",
fpath, GetLastError());
plugin.fpath.c_str(), GetLastError());
return false;
}

Expand All @@ -87,7 +96,8 @@ bool PluginManager::AddPlugin(const char* fpath, bool isMapPlugin) {
int apiVersion = HLCOOP_API_VERSION;
if (apiFunc(&plugin, apiVersion)) {
ALERT(at_console, "Loaded plugin '%s'\n", plugin.fpath.c_str());
} else {
}
else {
ALERT(at_error, "PluginInit call failed in plugin '%s'.\n", plugin.fpath.c_str());
FreeLibrary((HMODULE)plugin.h_module);
return false;
Expand All @@ -99,7 +109,6 @@ bool PluginManager::AddPlugin(const char* fpath, bool isMapPlugin) {
return false;
}

plugins.push_back(plugin);
return true;
}

Expand Down Expand Up @@ -155,6 +164,31 @@ void PluginManager::RemovePlugin(const char* name) {
}
}

void PluginManager::ReloadPlugin(const char* name) {
int bestIdx = -1;
int numFound = 0;

std::string lowerName = toLowerCase(name);

for (int i = 0; i < (int)plugins.size(); i++) {
if (toLowerCase(plugins[i].fpath).find(lowerName) != std::string::npos) {
bestIdx = i;
numFound++;
}
}

if (numFound == 1) {
UnloadPlugin(plugins[bestIdx]);
LoadPlugin(plugins[bestIdx]);
}
else if (numFound > 1) {
g_engfuncs.pfnServerPrint(UTIL_VarArgs("Multiple plugins contain '%s'. Be more specific.\n", name));
}
else {
g_engfuncs.pfnServerPrint(UTIL_VarArgs("No plugin found by name '%s'\n", name));
}
}

void PluginManager::RemovePlugins(bool mapPluginsOnly) {
std::vector<Plugin> newPluginList;

Expand Down Expand Up @@ -481,7 +515,11 @@ void RegisterPlugin(void* pluginptr, HLCOOP_PLUGIN_HOOKS* hooks, const char* nam
Plugin* plugin = (Plugin*)pluginptr;

plugin->name = name;
memcpy(&plugin->hooks, hooks, sizeof(HLCOOP_PLUGIN_HOOKS));

if (hooks)
memcpy(&plugin->hooks, hooks, sizeof(HLCOOP_PLUGIN_HOOKS));
else
memset(&plugin->hooks, 0, sizeof(HLCOOP_PLUGIN_HOOKS));
}

// custom entity loader called by the engine during map load
Expand Down
4 changes: 4 additions & 0 deletions dlls/PluginManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,16 @@ class PluginManager {
// set isMapPlugin to true if the plugin should only run on the current map
bool AddPlugin(const char* fpath, bool isMapPlugin);

bool LoadPlugin(Plugin& plugin);

void UnloadPlugin(const Plugin& plugin);

void RemovePlugin(const Plugin& plugin);

void RemovePlugin(const char* name);

void ReloadPlugin(const char* name);

void RemovePlugins(bool mapPluginsOnly);

// will conditionally load/unload plugins if the config has been updated since the last call, unless forceUpdate=true
Expand Down
2 changes: 1 addition & 1 deletion dlls/Scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class Scheduler {

void Think();

void RemoveTimer(ScheduledFunction schedule);
EXPORT void RemoveTimer(ScheduledFunction schedule);

void RemoveTimers(const char* owner);
};
Expand Down
4 changes: 4 additions & 0 deletions dlls/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,8 @@ void RegisterEncoders( void )

int GetWeaponData( struct edict_s *player, struct weapon_data_s *info )
{
CALL_HOOKS(int, pfnGetWeaponData, player, info);

#if defined( CLIENT_WEAPONS )
int i;
weapon_data_t *item;
Expand Down Expand Up @@ -1779,6 +1781,8 @@ void UpdateClientData ( const edict_t *ent, int sendweapons, struct clientdata_s
}
}
#endif

CALL_HOOKS_VOID(pfnUpdateClientDataPost, ent, sendweapons, cd);
}

/*
Expand Down
16 changes: 16 additions & 0 deletions dlls/eng_wrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,11 @@ int PRECACHE_EVENT(int id, const char* path) {
bool SET_MODEL(edict_t* edict, const char* model) {
if (model && model[0] == '*') {
// BSP model. No special handling.
CALL_HOOKS(bool, pfnSetModel, edict, model);
g_engfuncs.pfnSetModel(edict, model);
if (!g_serveractive)
g_precachedModels[model] = model; // engine precaches entity BSP models automatically
CALL_HOOKS(bool, pfnSetModelPost, edict, model);
return false;
}

Expand Down Expand Up @@ -537,6 +541,13 @@ int MODEL_INDEX(const char* model) {
return g_engfuncs.pfnModelIndex(model);
}

int SOUND_INDEX(const char* sound) {
std::string lowerPath = toLowerCase(sound);
sound = lowerPath.c_str();
return g_engfuncs.pfnPrecacheSound(sound);
}


void* GET_MODEL_PTR(edict_t* edict) {
studiohdr_t* header = (studiohdr_t*)g_engfuncs.pfnGetModelPtr(edict);

Expand Down Expand Up @@ -630,6 +641,11 @@ void EMIT_SOUND_DYN2(edict_t* pEntity, int channel, const char* pszSample, float
g_engfuncs.pfnEmitSound(pEntity, channel, pszSample, volume, attenuation, fFlags, pitch);
}

void EMIT_AMBIENT_SOUND(edict_t* pEntity, const float* vecPos, const char* pszSample, float vol, float attenuation, int fFlags, int pitch) {
CALL_HOOKS_VOID(pfnEmitAmbientSound, pEntity, vecPos, pszSample, vol, attenuation, fFlags, pitch);
g_engfuncs.pfnEmitAmbientSound(pEntity, vecPos, pszSample, vol, attenuation, fFlags, pitch);
}

void SetClientMaxspeed(const edict_t* pEntity, float maxspeed) {
CALL_HOOKS_VOID(pfnSetClientMaxspeed, pEntity, maxspeed);
g_engfuncs.pfnSetClientMaxspeed(pEntity, maxspeed);
Expand Down
23 changes: 13 additions & 10 deletions dlls/eng_wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@

class CBaseEntity;

extern Bsp g_bsp;
EXPORT extern Bsp g_bsp;

// resources that were successfully precached
extern std::unordered_map<std::string, std::string> g_precachedModels; // storing values so GET_MODEL can be used with MAKE_STRING
extern std::unordered_set<std::string> g_missingModels; // storing values so GET_MODEL can be used with MAKE_STRING
extern std::unordered_set<std::string> g_precachedSounds;
extern std::unordered_set<std::string> g_precachedGeneric;
extern std::unordered_map<std::string, int> g_precachedEvents;
EXPORT extern std::unordered_map<std::string, std::string> g_precachedModels; // storing values so GET_MODEL can be used with MAKE_STRING
EXPORT extern std::unordered_set<std::string> g_missingModels; // storing values so GET_MODEL can be used with MAKE_STRING
EXPORT extern std::unordered_set<std::string> g_precachedSounds;
EXPORT extern std::unordered_set<std::string> g_precachedGeneric;
EXPORT extern std::unordered_map<std::string, int> g_precachedEvents;

// resources that attempted to precache but may have been replaced with a failure model
extern std::unordered_set<std::string> g_tryPrecacheModels;
extern std::unordered_set<std::string> g_tryPrecacheSounds;
extern std::unordered_set<std::string> g_tryPrecacheGeneric;
extern std::unordered_set<std::string> g_tryPrecacheEvents;
EXPORT extern std::unordered_set<std::string> g_tryPrecacheModels;
EXPORT extern std::unordered_set<std::string> g_tryPrecacheSounds;
EXPORT extern std::unordered_set<std::string> g_tryPrecacheGeneric;
EXPORT extern std::unordered_set<std::string> g_tryPrecacheEvents;

#ifdef CLIENT_DLL
#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel)
Expand All @@ -42,6 +42,7 @@ inline void MESSAGE_BEGIN(int msg_dest, int msg_type, const float* pOrigin = NUL
#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr)
#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity)
#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound)
#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound)
#define CMD_ARGS (*g_engfuncs.pfnCmd_Args)
#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc)
#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv)
Expand All @@ -59,6 +60,7 @@ EXPORT bool SET_MODEL(edict_t* edict, const char* model); // returns true if the
EXPORT bool SET_MODEL_MERGED(edict_t* edict, const char* model, int mergeId); // will set the merged model and body if the given model was not replaced
EXPORT const char* GET_MODEL(const char* model); // return replacement model, if one exists, or the given model
EXPORT int MODEL_INDEX(const char* model);
EXPORT int SOUND_INDEX(const char* model);
EXPORT void* GET_MODEL_PTR(edict_t* edict);
EXPORT edict_t* CREATE_NAMED_ENTITY(string_t cname);
#define PRECACHE_SOUND(path) PRECACHE_SOUND_ENT(this, path)
Expand All @@ -80,6 +82,7 @@ EXPORT void WRITE_STRING(const char* sValue);
EXPORT void WRITE_ENTITY(int iValue);

EXPORT void EMIT_SOUND_DYN2(edict_t* pEntity, int channel, const char* pszSample, float volume, float attenuation, int fFlags, int pitch);
EXPORT void EMIT_AMBIENT_SOUND(edict_t* pEntity, const float* vecPos, const char* pszSample, float vol, float attenuation, int fFlags, int pitch);
EXPORT void SetClientMaxspeed(const edict_t* pEntity, float maxspeed);
EXPORT void SetClientKeyValue(int clientIndex, char* pszInfoBuffer, const char* pszKey, const char* pszValue);

Expand Down
1 change: 0 additions & 1 deletion dlls/enginecallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ inline void *GET_PRIVATE( const edict_t *pent )
#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum)
#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere)
#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS) // Doesn't work as expected in multiplayer.
#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound)
#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition)
#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName)
#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction)
Expand Down
6 changes: 3 additions & 3 deletions dlls/env/CAmbientGeneric.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ typedef struct dynpitchvol

// presets for runtime pitch and vol modulation of ambient sounds

class CAmbientGeneric : public CBaseEntity
class EXPORT CAmbientGeneric : public CBaseEntity
{
public:
virtual int GetEntindexPriority() { return ENTIDX_PRIORITY_HIGH; }
void KeyValue(KeyValueData* pkvd);
void Spawn(void);
void Precache(void);
void EXPORT ToggleUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
void EXPORT RampThink(void);
void ToggleUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
void RampThink(void);
void InitModulationParms(void);
void InitSoundForNewJoiner(edict_t* target);

Expand Down
16 changes: 8 additions & 8 deletions dlls/func/CBaseButton.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ void DoSpark(entvars_t* pev, const Vector& location);
//
// Generic Button
//
class CBaseButton : public CBaseToggle
class EXPORT CBaseButton : public CBaseToggle
{
public:
void Spawn(void);
Expand All @@ -25,13 +25,13 @@ class CBaseButton : public CBaseToggle
void ButtonActivate();
void SparkSoundCache(void);

void EXPORT ButtonShot(void);
void EXPORT ButtonTouch(CBaseEntity* pOther);
void EXPORT ButtonSpark(void);
void EXPORT TriggerAndWait(void);
void EXPORT ButtonReturn(void);
void EXPORT ButtonBackHome(void);
void EXPORT ButtonUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
void ButtonShot(void);
void ButtonTouch(CBaseEntity* pOther);
void ButtonSpark(void);
void TriggerAndWait(void);
void ButtonReturn(void);
void ButtonBackHome(void);
void ButtonUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
virtual int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
virtual int Save(CSave& save);
virtual int Restore(CRestore& restore);
Expand Down
9 changes: 9 additions & 0 deletions dlls/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ void remove_plugin() {
g_pluginManager.RemovePlugin(CMD_ARGV(1));
}

void reload_plugin() {
if (CMD_ARGC() < 2) {
return;
}

g_pluginManager.ReloadPlugin(CMD_ARGV(1));
}

void test_command() {
}

Expand All @@ -239,6 +247,7 @@ void GameDLLInit( void )
g_engfuncs.pfnAddServerCommand("reloadplugins", reload_plugins);
g_engfuncs.pfnAddServerCommand("listplugins", list_plugins);
g_engfuncs.pfnAddServerCommand("removeplugin", remove_plugin);
g_engfuncs.pfnAddServerCommand("reloadplugin", reload_plugin);
// Register cvars here:

g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
Expand Down
Loading

0 comments on commit f85e1fa

Please sign in to comment.