OpenJK
OpenJK copied to clipboard
Reintroduce QVM support
Prologue
The original jka release used native binaries, but the vanilla jamp and jampded engine binaries were still capable of loading QVM mods and both, the 2003 SDK and the 2013 release of the code could be used to compile QVMs for jampgame
, cgame
and ui
. It is unknown whether anyone tried to make use of that before 2013, but there seems to be no publicly known mods that made use of QVMs, thus OpenJK removed support for QVMs early on. However, the interest in QVM mods has increased over time for better mod-compatibility accross different platforms and there is currently at least one server running jampded with a QVM based mod. For those reasons this pull request readds QVM support by porting the QVM code from jk2mv (which ported parts of it from ioq3) and adjusting the module APIs to support QVMs.
Issues when using QVMs on vanilla jamp/jampded
- The string pointers written into the
glconfig_t
instances inside ofcgame
andui
would point to engine memory, making them invalid - The notetrack callback for the roff system would pass a pointer to engine memory into the module, making it invalid (this issue already existed in jk2, but vanilla jk2 modules didn't properly support roff, leading to a very low chance of anyone actually having encountered the bug on there)
- A few of the NAV VM_Calls would pass
vec3_t
(pointer to float) into the game module, possibly affecting NPC pathfinding
Pull Request
QVM related changes
- Ports
vm_arm.cpp
,vm_interpreted.cpp
,vm_local.h
andvm_x86.c
from mvdevs/jk2mv (which in turn got some of its code from ioq3 and multiple contributors) - Ports various QVM related functions from mvdevs/jk2mv
- Reintroduces the cvars
vm_game
,vm_cgame
andvm_ui
- Reintroduces the commands
vminfo
andvmprofile
- Maps G2 pointers to integer handles for the module APIs when using QVMs, because the types within the QVM are 32 bit, making 64 bit pointers incompatible
- Replaces
sharedEntity_t
in the engine withsharedEntityMapper_t
. As the QVM types are 32 bit thesharedEntity_t
struct doesn't match when running the engine as 64 bit build. To work around this the engine stores the correct addresses for the members ofsharedEntity_t
insharedEntityMapper_t
when the game module passes the shared entities intoSV_LocateGameData
. - Solves the vanilla jamp/jampded issues by allocating additional memory for the QVM on load. This additional memory is used to write data into and then pass a pointer to that data into the module, which is valid, because it's within the datamask for the module.
- Replaces the exceptions in
qcommon.cpp
withlongjmp
, because throwing exceptions within a VM_Call was unreliable
Other changes
- Fixes undefined behavior in
SV_ClipMoveToEntities
, which becmae obvious when replacingsharedEntity_t
withsharedEntityMapper_t
- The
vm_legacy
cvar is no longer limited to_DEBUG
builds to make potenital API tests with users easier, because it doesn't require extra builds - Adds
com_dedicatedForceErrorsToFatal
cvar to be able to disable theERR_DROP
toERR_FATAL
rewrite for Com_Error calls on dedicated servers - Blocks additional file extensions for write attempts from VMs (
dll
,exe
,bat
,cmd
,dylib
,so
,qvm
,pk3
). - Resolves filenames for the extension check to cover symlinks and potential bypasses of the checks
- Blocks a few characters in filenames specified by VMs (
<>:"|?*
)