Player guide
Mod compatibility
Two things decide how TaystJK behaves with a mod: which client modules get loaded, and which server features the client turns on once they are. This page covers both, and why a feature can silently do nothing.
Loading another mod’s client modules
The TaystJK executable is the engine. The game, client-game and UI modules are separate native libraries:
| Module | Windows example | Linux example | Purpose |
|---|---|---|---|
| Game | jampgamex86_64.dll |
jampgamex86_64.so |
Server-side game rules; also used by a locally hosted game. |
| Client game | cgamex86_64.dll |
cgamex86_64.so |
Client-side prediction, HUD, and world presentation. |
| UI | uix86_64.dll |
uix86_64.so |
Menus and other UI behaviour. |
macOS uses the equivalent .dylib files. TaystJK does not run QVM bytecode; both its current
module API and the older dllEntry/vmMain API load native libraries. A module must match
the operating system and CPU architecture of the TaystJK executable.
For each module, the client asks only for the file name that matches its own architecture,
and looks in the server’s mod directory first, then taystjk, then base
(sys_main.cpp).
So a 64-bit client on a JA+ server never tries the mod’s cgamex86.dll; it loads TaystJK’s
own cgame and you keep TaystJK’s HUD. That is what you want almost every time.
Mods that package native libraries inside a PK3
Many older mods put cgame, ui, or jampgame native libraries inside a PK3. TaystJK
still mounts the PK3 and reads its assets, but it does not unpack and run those libraries
by default: com_unpackLibraries
defaults to 0, and both module loaders only try PK3 unpacking when it is on
(registration,
legacy loader,
OpenJK-style loader).
The result is a mod whose assets appear while its custom HUD, menus or game code does not
load.
The fix is to extract the native libraries from the mod’s PK3 and put them beside that PK3 in the mod directory. Keep the PK3, because the mod still needs its maps, menus, shaders and other assets. For a 32-bit Windows mod, the result usually looks like this:
japlus/
├── mod-assets.pk3
├── cgamex86.dll
├── uix86.dll
└── jampgamex86.dll
Only extract files from a mod you trust: native modules are programs, not data. The names
and architecture must match your TaystJK build, so an x86.dll from an old mod cannot be
loaded by the 64-bit client. Use the 32-bit Windows build for a mod that only has 32-bit
Windows modules, or get modules built for your platform.
On Windows, you can instead turn the old unpacking behaviour back on for a trusted mod at startup:
taystjk.x86.exe +set fs_game japlus +set fs_forcegame japlus +set com_unpackLibraries 1
com_unpackLibraries is read once at startup, so put it on the command line. Only Windows
has this fallback. Linux and macOS never extract .so or .dylib modules from a PK3, so
install those as loose files
(Windows unpacker,
Unix behaviour).
When to use vm_legacy
You should not need it. For each native module, TaystJK looks for the newer OpenJK-style
GetModuleAPI entry point and, when the library does not export one, loads it through the
older dllEntry/vmMain interface instead
(sys_main.cpp,
cl_uiapi.cpp).
Older mods such as JA+ load this way with no setting.
vm_legacy forces the older interface on a library that exports both. That matters in one
case: the library’s GetModuleAPI rejects the engine’s API version, and the client stops
with GetGameAPI failed on followed by the library name
(cl_uiapi.cpp).
It still loads a native library; it does not enable QVMs.
vm_legacy is a bitmask:
| Bit | Value | Module |
|---|---|---|
| 0 | 1 |
Game (jampgame), for a local or dedicated server. |
| 1 | 2 |
Client game (cgame). |
| 2 | 4 |
UI (ui). |
Add the values to force more than one, so 6 forces both cgame and UI. Put it on the
command line, for example +set vm_legacy 4 for the UI: it is read when a module loads, and
changing it later does not affect a module that is already running.
If the console then reports VM_CreateLegacy: ... succeeded, the older interface loaded. If
it reports failed, the library has no older interface; remove the setting and check that
the mod build matches your platform.
Where TaystJK reads and writes files
Three cvars decide which directories the client reads files from and which one it writes to. All three can only be set at startup, on the command line or in a launch script.
The search order
The client searches these directories, lowest priority first, and a file in a later one
replaces the same file in an earlier one
(files.cpp):
| Order | Directory | Holds |
|---|---|---|
| 1 | base |
The retail game files. |
| 2 | fs_basegame |
A mod other mods build on. On TaystJK this is taystjk, with japro-assets.pk3. |
| 3 | fs_game |
The mod the server runs, or the one you chose at startup. |
Each directory is looked for under fs_cdpath, fs_basepath and fs_homepath in turn. Run
path in the console to see the result.
On TaystJK, fs_basegame defaults to fs_forcegame
(files.cpp): it is taystjk on a normal client, and empty when you clear
fs_forcegame. Set it yourself on the command line to choose a different one
(files.cpp). Running TaystJK for one mod shows
what that is for. Builds from before 24 October 2026 ignore a +set fs_basegame and always copy
fs_forcegame.
fs_forcegame also decides where the client writes: configs, screenshots, demos and
downloads go to the fs_forcegame directory when it is set
(files.cpp), and to the fs_game directory, or base, when it is empty.
Client modules are found separately. The client tries the fs_game directory first, then
taystjk, then base, whatever these cvars say
(sys_main.cpp).
What fs_forcegame does
fs_forcegame defaults to taystjk on the client and to nothing on a dedicated server
(files.cpp). A server cannot change it. The three ways to set it behave
differently:
fs_forcegame |
Searched | Written to | When you join a server with another mod |
|---|---|---|---|
taystjk, the default |
base, taystjk, then the server’s mod |
taystjk/ |
The mod’s files override TaystJK’s. Your settings stay in one taystjk/taystjk.cfg on every server. |
A mod, such as japlus, with fs_game set to the same |
base, then that mod, then the server’s mod if it is a different one. taystjk/ is not searched, so TaystJK’s own assets are not loaded. |
that mod’s directory | Your settings stay in that mod’s directory on every server, and its files stay in the search order under the server’s. |
Empty: +set fs_forcegame "" |
base, then the server’s mod. Add +set fs_basegame taystjk to keep taystjk between them. |
the server’s mod directory, or base/ |
The client switches to that mod’s directory and loads the taystjk.cfg in it (files.cpp), so each mod keeps its own settings. A mod you have never played starts a new directory and config. |
Leave it at the default to keep TaystJK’s own client files and one set of settings on JA+,
JA++, jaPRO and other modded servers. Do not add fs_game just to join a server; the server
sends its own game directory when you connect. The Mods menu only changes fs_game, so it
does not change where your files are written
(ui_main.c).
To use another mod’s client libraries and assets everywhere, install them in that mod’s
directory and set both at startup. JA++, for example, uses japlus/ to stay compatible with
JA+:
taystjk.x86_64.exe +set fs_game japlus +set fs_forcegame japlus
To go back to the normal setup, remove fs_game japlus and either remove fs_forcegame or
set it back to taystjk.
Running TaystJK for one mod
A mod with its own client files, such as a roleplay mod with its own models, HUD and settings, has two separate choices to make about TaystJK: what happens to TaystJK’s assets, and where its players’ settings are saved.
Overriding TaystJK’s assets needs nothing special. The mod’s directory is searched after
taystjk/, so any file the mod ships under the same name, such as a HUD graphic, replaces
TaystJK’s on that mod’s servers. TaystJK’s other assets still load.
Bypassing TaystJK’s assets, so that none of them load, means keeping taystjk/ out of the
search order. Only a launch option can do that: fs_basegame has to be empty, so fs_forcegame
has to be cleared without setting fs_basegame, or set to the mod itself.
Settings go wherever fs_forcegame points. By default that is one taystjk/taystjk.cfg
used on every server. Clearing it gives each mod its own taystjk.cfg in its own directory.
| TaystJK’s assets | Settings | Launch with |
|---|---|---|
| Overridden by the mod | taystjk/taystjk.cfg, shared with every server |
nothing extra |
| Overridden by the mod | mymod/taystjk.cfg, separate per mod |
+set fs_forcegame "" +set fs_basegame taystjk +set fs_game mymod |
| Not loaded | mymod/taystjk.cfg, separate per mod |
+set fs_forcegame "" +set fs_game mymod |
| Not loaded | mymod/taystjk.cfg, used on every server |
+set fs_forcegame mymod +set fs_game mymod |
In the first row the player needs no script, but if the mod has its own ui module, starting
with +set fs_game mymod loads its menus before the player connects.
With separate settings per mod, joining a server that runs a different mod switches the client
to that mod’s directory and its taystjk.cfg, which is the point of clearing fs_forcegame.
With the last row nothing switches: the mod’s settings and files follow the player to servers
that were not made for them.
For every row except the first, the launch script is the only signal. A player who starts TaystJK normally gets the default setup, so tell players to start the game from a shortcut to your script.
What the client decides
On connecting, the client reads the server’s gamename and sorts the server into one of six
kinds
(cg_servercmds.c):
gamename |
Treated as |
|---|---|
starts with JA+, ^4U^3A^5Galaxy or AbyssMod |
JA+ |
starts with japro |
jaPRO |
starts with smU |
OpenJK-alt |
starts with base_enhanced or base_entranced |
Base Enhanced |
starts with basejk |
Base JKA |
is exactly Lugormod or ^5L^7ugormod ^5v3 |
Lugormod |
None of these care about case. Anything else is treated as base JKA, and so is any server on
a pre-1.01 protocol whatever its name. Because most of these match only the start of the
name, a server that renames itself loses the classification and the features that depend on
it; a Lugormod server has to use one of its two names exactly
(cg_servercmds.c).
Why that ordering matters
The six kinds are an ordered enum, not a set
(cg_local.h):
basejka < base_enhanced < ojkalt < lugormod < ja+ < japro
Most feature checks are written as at least JA+ instead of as a list of names. A feature checked that way is on for JA+ and jaPRO and off for everything to their left, including Lugormod. So the practical answer to “does my client do X here” is usually “are you on a JA+ or jaPRO server”.
What is actually gated
Not everything. The client’s own display settings, including the HUD tools, the cosmetics you see locally and console behaviour, work whatever the server runs. What is gated is behaviour the server has to agree with, because the client is predicting movement or drawing something the server also has a say in.
| Feature | Needs |
|---|---|
| RGB sabers | JA+ or jaPRO, or the server advertising it (cg_players.c) |
| Black sabers | the same, and not disabled by plugin settings (cg_players.c) |
| Flipkick | the server advertising it (bg_pmove.c) |
| JA+-style grapple | JA+, or jaPRO with its JA+ grapple option on, or the server advertising it (bg_pmove.c) |
| Roll fixes 1–3 | JA+ or jaPRO with the matching option, or the server advertising it (bg_pmove.c) |
The plugin command |
JA+ or above; it returns silently otherwise (cg_consolecmds.c) |
| Force column on the team overlay | jaPRO, which is what supplies the data |
Lugormod is a special case throughout: it is recognised on its own and several movement paths branch for it, because it moves players in ways the stock prediction gets wrong.
Base Enhanced and Base Entranced: use NewJK
If you play on base_enhanced or base_entranced servers, use NewJK/NewMod instead of this client.
Those server mods and NewMod share an author, and NewMod is built for them. It supports their features fully, where TaystJK only recognises base_enhanced well enough not to break on it.
taystJKinfo: how a server turns these on
A server does not have to be JA+ or jaPRO. Any game module can advertise the individual
features it supports by putting a bitmask in the taystJKinfo serverinfo key, which the
client reads on connect and whenever the serverinfo changes
(cg_servercmds.c).
The mask covers RGB and black sabers, flipkick, grapple, the three roll fixes, and
server-supplied scoreboard deaths. The bits are listed in
the feature flags spec. Scoreboard deaths
also depends on the client advertising support in its taystJKcgflags userinfo, so the
server only sends the extended scoreboard to clients that can read it.
The flag does not bypass the plugin command’s JA+/jaPRO check
(cg_consolecmds.c),
or turn on the team overlay’s force column on other mods: that still requires jaPRO
(cg_draw.c).
If you run a server on something other than JA+ or jaPRO and players report that RGB sabers or flipkick do nothing, this key is the answer.
Telling which you are on
Run configstrings in the console while connected
(cl_main.cpp).
The first entry is the server’s serverinfo, which includes gamename and, if the server
sets it, taystJKinfo. That is the quickest way to tell whether a feature is missing
because of your client or because of the server. serverinfo only works on the machine
running the server; on a client it prints “Server is not running.”
A feature that behaves differently on two servers is usually down to the servers, not the client. See where to report.
Last changed History Edit this page on GitHub