OpenJK icon indicating copy to clipboard operation
OpenJK copied to clipboard

Reintroduce QVM support

Open Daggolin opened this issue 8 months ago • 0 comments

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 of cgame and ui 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 and vm_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 and vm_ui
  • Reintroduces the commands vminfo and vmprofile
  • 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 with sharedEntityMapper_t. As the QVM types are 32 bit the sharedEntity_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 of sharedEntity_t in sharedEntityMapper_t when the game module passes the shared entities into SV_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 with longjmp, because throwing exceptions within a VM_Call was unreliable

Other changes

  • Fixes undefined behavior in SV_ClipMoveToEntities, which becmae obvious when replacing sharedEntity_t with sharedEntityMapper_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 the ERR_DROP to ERR_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 (<>:"|?*)

Daggolin avatar Nov 02 '23 22:11 Daggolin