Keeping the server DLL handle alive fixes BugfixedAPI / WeaponMod conflict on Linux
Environment
- OS: Linux
- Game: Half-Life Deathmatch
- BugfixedHL-Rebased:
1.13.2+HEAD.3270cea
- AMX Mod X:
1.10.0.5479
- WeaponMod:
v0.1.0-dev.323+HEAD.ec67f02
- BugfixedAPI AMXX module:
v1.13.2+HEAD.3270cea
- WeaponMod repository: https://github.com/tmp64/weaponmod
Problem
When bugfixedapi_amxx_i386.so is loaded together with WeaponMod on Linux, custom WeaponMod weapons become partially broken after a map change.
Example with a custom SporeLauncher:
- custom weapon registration works;
- HUD weapon selection works;
- custom PrimaryAttack logic works;
- custom projectiles/effects work;
- dropped weapon has the correct custom world model;
- but after selecting the weapon, the first-person model becomes
v_crowbar.mdl.
In one test the correct SporeLauncher view model was visible for a brief moment immediately after selection, then it was replaced by the crowbar model.
This is relevant because WeaponMod uses weapon_crowbar as the reference weapon and hooks its virtual functions.
Reproduction with original BugfixedAPI
- Start HLDS with WeaponMod
v0.1.0-dev.323+HEAD.ec67f02 and BugfixedAPI v1.13.2+HEAD.3270cea.
- Obtain/select a custom WeaponMod weapon such as SporeLauncher.
- On the initial map it may work correctly.
- Change map.
- Select the custom weapon again.
Result:
Custom weapon mechanics: OK
Custom weapon firing: OK
Custom world model: OK
First-person model: WRONG (crowbar)
The issue was reproduced even with almost all third-party AMXX plugins disabled.
If bugfixedapi_amxx_i386.so is physically removed and the server is fully restarted, WeaponMod works correctly. Multiple subsequent map changes also work correctly.
If BugfixedAPI has already been loaded into the process and the broken state has occurred, unloading BugfixedAPI does not necessarily restore WeaponMod; a full server restart is required.
Suspicious code
In:
src/bugfixedapi_amxx/bhl_api.cpp
InitServerApi() currently does:
g_pServerModule = Sys_LoadModule(pszModule);
if (!g_pServerModule)
return E_ApiInitResult::ModuleNotFound;
// Decrease reference count - module should still be loaded by the engine
Sys_UnloadModule(g_pServerModule);
// Get factory
g_fnServerFactory = Sys_GetFactory(g_pServerModule);
On Linux Sys_UnloadModule() calls dlclose().
So the effective sequence is:
dlopen(server DLL)
dlclose(server DLL)
dlsym/use the same handle afterwards
Although the server DLL is also loaded by the engine and normally remains resident, this lifetime pattern appears to interact badly with WeaponMod's runtime virtual hooks.
Test patch
For testing, I modified BugfixedAPI so that the extra server DLL reference is kept alive for the whole lifetime of the AMXX module.
The immediate Sys_UnloadModule(g_pServerModule) call was removed from InitServerApi().
The reference is instead released in ShutdownServerApi():
void bhl::ShutdownServerApi()
{
g_pServerApi = nullptr;
g_iServerMajor = 0;
g_iServerMinor = 0;
g_fnServerFactory = nullptr;
if (g_pServerModule)
{
Sys_UnloadModule(g_pServerModule);
g_pServerModule = nullptr;
}
}
Failure paths after a successful Sys_LoadModule() were also adjusted to release the handle before returning.
No WeaponMod, AMXX, gamedata, offsets or GameDLL changes were made.
Test result
The modified module reports:
BugfixedAPI v1.13.2+HEAD.3270cea.m
Test 1 — BugfixedAPI auto-loaded later
[ 5] HL Weapon Mod RUN weaponmod_amxx_i386.so
v0.1.0-dev.323+HEAD.ec67f02
[11] BugfixedAPI RUN bugfixedapi_amxx_i386.so
v1.13.2+HEAD.3270cea.m
Multiple map changes: OK.
Custom weapon view models continue to work correctly.
Test 2 — BugfixedAPI explicitly loaded immediately after WeaponMod
modules.ini:
Result:
[ 5] HL Weapon Mod RUN weaponmod_amxx_i386.so
v0.1.0-dev.323+HEAD.ec67f02
[ 6] BugfixedAPI RUN bugfixedapi_amxx_i386.so
v1.13.2+HEAD.3270cea.m
Again, multiple map changes: OK.
The original bug could no longer be reproduced.
Expected behavior
Loading BugfixedAPI should not affect WeaponMod virtual hooks or custom weapon view models across map changes.
Actual behavior with the original module
After BugfixedAPI has been loaded, WeaponMod custom weapons can lose their custom first-person model after a map change and fall back to the reference weapon_crowbar model.
Conclusion
Keeping the Sys_LoadModule() reference alive until ShutdownServerApi() completely eliminates the issue in my tests, regardless of whether BugfixedAPI is loaded early from modules.ini or auto-loaded later by AMXX.
This strongly suggests that the current immediate Sys_UnloadModule() in InitServerApi() is involved in the conflict.
I can provide the exact patch or compiled test module if needed.
Keeping the server DLL handle alive fixes BugfixedAPI / WeaponMod conflict on Linux
Environment
1.13.2+HEAD.3270cea1.10.0.5479v0.1.0-dev.323+HEAD.ec67f02v1.13.2+HEAD.3270ceaProblem
When
bugfixedapi_amxx_i386.sois loaded together with WeaponMod on Linux, custom WeaponMod weapons become partially broken after a map change.Example with a custom SporeLauncher:
v_crowbar.mdl.In one test the correct SporeLauncher view model was visible for a brief moment immediately after selection, then it was replaced by the crowbar model.
This is relevant because WeaponMod uses
weapon_crowbaras the reference weapon and hooks its virtual functions.Reproduction with original BugfixedAPI
v0.1.0-dev.323+HEAD.ec67f02and BugfixedAPIv1.13.2+HEAD.3270cea.Result:
The issue was reproduced even with almost all third-party AMXX plugins disabled.
If
bugfixedapi_amxx_i386.sois physically removed and the server is fully restarted, WeaponMod works correctly. Multiple subsequent map changes also work correctly.If BugfixedAPI has already been loaded into the process and the broken state has occurred, unloading BugfixedAPI does not necessarily restore WeaponMod; a full server restart is required.
Suspicious code
In:
InitServerApi()currently does:On Linux
Sys_UnloadModule()callsdlclose().So the effective sequence is:
Although the server DLL is also loaded by the engine and normally remains resident, this lifetime pattern appears to interact badly with WeaponMod's runtime virtual hooks.
Test patch
For testing, I modified BugfixedAPI so that the extra server DLL reference is kept alive for the whole lifetime of the AMXX module.
The immediate
Sys_UnloadModule(g_pServerModule)call was removed fromInitServerApi().The reference is instead released in
ShutdownServerApi():Failure paths after a successful
Sys_LoadModule()were also adjusted to release the handle before returning.No WeaponMod, AMXX, gamedata, offsets or GameDLL changes were made.
Test result
The modified module reports:
Test 1 — BugfixedAPI auto-loaded later
Multiple map changes: OK.
Custom weapon view models continue to work correctly.
Test 2 — BugfixedAPI explicitly loaded immediately after WeaponMod
modules.ini:Result:
Again, multiple map changes: OK.
The original bug could no longer be reproduced.
Expected behavior
Loading BugfixedAPI should not affect WeaponMod virtual hooks or custom weapon view models across map changes.
Actual behavior with the original module
After BugfixedAPI has been loaded, WeaponMod custom weapons can lose their custom first-person model after a map change and fall back to the reference
weapon_crowbarmodel.Conclusion
Keeping the
Sys_LoadModule()reference alive untilShutdownServerApi()completely eliminates the issue in my tests, regardless of whether BugfixedAPI is loaded early frommodules.inior auto-loaded later by AMXX.This strongly suggests that the current immediate
Sys_UnloadModule()inInitServerApi()is involved in the conflict.I can provide the exact patch or compiled test module if needed.