Changelog: KrausNet update
Porting your scripts
2.0.0 changes the scripting API. Existing resources need to be ported: see Porting to 2.0.0.
JC4MP now runs on KrausNet, a new networking and scripting core. Epic Games version is now fully supported. Players get smoother and more reliable sync. Server owners get a sturdier server, and script authors get a cleaner Lua API, which means existing scripts need a port. The script API changes section lists what to rename.
Why KrausNet
Performance
- Smaller packets:
- positions, rotations and velocities are bit-packed at a precision tuned per value (positions to 1 cm), instead of being sent as full numbers;
- packet buffers are pooled and reused instead of allocated for every packet.
- The right channel for each update: movement goes on its own fast, unordered channel, so a lost packet never holds the others back. Important state (health, spawns, ownership) is delivered reliably and in order.
- Only what you can see: your game only creates and receives the players and objects near you. That means less traffic, less memory and fewer game objects on screen.
- No waiting on the network: the server and client handle every queued packet each tick instead of one batch at a time, so updates don't pile up under load.
- Smooth movement: remote players and vehicles are interpolated between snapshots and predicted with your own ping.
- Faster scripts: scripts run on LuaJIT, a just-in-time compiler.
Reliability
- Server moves always win: a teleport or server-side move can't be undone by a late update from the player who controls the object. Outdated updates are recognised and dropped, without extra round trips.
- Safe object references: scripts and the engine refer to objects through handles, so a destroyed object can't be reached by mistake, and its ID isn't reused right away.
- Ownership: each object is simulated by the closest player, and it only changes hands when someone else is clearly closer, so objects don't flip between players.
- Clean disconnects: a player who leaves is removed from everything they were part of, and kicking is safe at any moment.
Security
- Validated data: every incoming packet is bounds-checked. Malformed data is rejected instead of crashing the server.
- Login first: players are authenticated before they receive any server resources.
- Script sandbox: client scripts can't load native code or read files, and recursion or runaway nesting can't crash the server.
- Script-safe dispatch: scripts can't break the engine by changing events, timers or resources while those are running. Such changes are refused or queued.
Scripting
- One consistent API: handles everywhere,
ok, errresults and the same naming on server and client. - Built-in SQL: an SQLite database API with queries, transactions and helpers.
- Player list: every client knows every connected player's name, ID and role.
- Diagnostics: network statistics are available to scripts (see the net-stats overlay).
New
- KrausNet core: new networking, world streaming and scripting, replacing JC4MP's own.
- LuaJIT: scripts run on LuaJIT instead of Lua 5.4, so they're much faster.
- Epic Games support: JC4MP works with the Epic Games Store version of Just Cause 4 as well as Steam.
- Download progress: resource downloads show a progress bar before the world loads, and files now download over TCP.
- Script handles: objects and players are handles (
PlayerHandle,VehicleHandle, ...), and==compares them correctly. - Server-side checks: script events with unreadable arguments are dropped with a warning instead of affecting the server, and the sender stays connected.
- New SQL helpers:
SQL.QueryRow,SQL.QueryValue,SQL.ExecuteScript,SQL.Transaction,SQL.TableExists,SQL.NullandSQL.Blob. Net.SendToPlayersVisibleTo: sends an event only to the players who can see an object.- Console
kickcommand:kick <steam_id> [reason]. Asset.IsLoaded: tells whether an asset is loaded in the game. Used to check if the location load of assets is loaded or not.- Rigid objects load their own assets:
World.SpawnRigidObjectloads the model (with its textures and meshes) and the collision from the game archives, so any model can be spawned, even one the current area hasn't loaded. - Weapons: a new
Weaponclass (no fields yet), andPlayerObjectHandle:GetWeapon()(client) returns a player's active weapon. - Water boxes (client):
World.SpawnWaterBox(position, size, style)spawns aWaterBox;WaterBoxStyleisClipToTerrain,NoCliporShrinkWrap.
- Force pulses (client):
World.SpawnForcePulse(position, tuning, radius, category, velocity, pressure)spawns aForcePulse, andForcePulse:Explode()triggers it;ForcePulseCategoryisHandgrenade,FuelBarrel,C4,Vehicle,FuelTruckorManual;ForcePulseTuningholds the game's full catalog of tunings (HandGrenade,GrenadeLauncher,CarMedium,Barreland more).
- Explosions (server):
World.SpawnExplosion(position, entity)sets off the force pulse of a game entity for every player, with its effects, sounds and damage, e.g. the hand grenade's"editor/entities/weapons/03_thrown/w301_grenade/w301_grenade.epe". - Player tethers: tethers players make with the grappling hook are seen by everyone, and they end for everyone when the player releases them, the tether breaks or the player leaves.
- NPC grenades:
npc:ThrowGrenade(position)(server) makes an NPC throw a hand grenade at a position. Every NPC carries one and never runs out, and every player sees the throw. - NPC melee:
npc:Melee(target)(server) makes an NPC swing at a player or another NPC. Civilians can melee too, and an NPC that's walking or running keeps moving while it swings. - Drones (server): a drone spawned with
World.SpawnVehicle(e.g."v254_helicopter_guarddrone_rebel") flies where scripts tell it, and every player sees the same:vehicle:DroneFlyTo(position)flies it to a position, where it hovers;vehicle:DroneFollow(target, offset)makes it follow a player or another object at an offset from it;vehicle:DroneAimAt(position)orvehicle:DroneAimAt(target, offset)turns it and its gun to the aim, andvehicle:DroneStopAiming()ends it;vehicle:DroneSetFiring(enable)fires its gun at the aim.- its shots hit the aim at any angle, with the minigun's impact effects (the game ships the guard drone's gun without any).
- Hoverboard (client):
Local.SetHoverboardEnabled(enable)lets the player open the Danger Rising hoverboard with its usual key, andLocal.IsHoverboardEnabled()reads it back. It's off by default and needs the Danger Rising DLC:- every player sees others ride, jump, brake and close their board, and switch from it to the wingsuit or parachute;
- others never see a rider walking, or a walking player riding, even when one of their inputs is missed.
GameObject:Destroy()(client): removes an object that a client script spawned.- Player animations:
- players can play the game's civilian animations, retargeted to the player's skeleton so the neck and limbs keep their length;
PlayerObjectHandle:PlayAnimation(path, loop)andStopAnimation()(server),Local.PlayAnimation(path, loop)andLocal.StopAnimation()(client), andGetAnimation()on both;- everyone sees the animation, including players who join while it plays.
- Custom sandstorms:
World.SpawnSandstorm(position, size, wind_speed, rotation)(server) spawns a sandstorm of any size anywhere, and every player sees it;- inside it, players get the sandstorm's weather, wind, sand and slowed movement;
- the rotation (optional) sets the wind's direction, and
SandstormHandle:GetSize()andGetWindSpeed()read it back.
- Navigation data (client): scripts can read where characters can walk and where vehicles can drive, straight from the game's AI data:
NavMesh.GetClosestPosition(position, maxDistance),NavMesh.GetVertices(position, radius)andNavMesh.GetPolygons(position, radius)read the walkable surface. The game only loads it around the camera, about 1.5 km across;RoadGraph.GetSamples(position, radius, types)returns points along the roads of the whole map, andRoadGraph.GetNodes,GetNode(id)andGetEdge(id)return its junctions and the roads between them;RoadGraphTypeisLand(car roads),Sea,Air,Pedestrian(the sidewalks civilians walk),RailwayorAny.
- navigation resource: a default script that shows the navigation data and uses it:
/navmeshdraws the walkable area, the car roads, the sidewalks and the road junctions around you;/peds [count]spawns civilians who walk the sidewalks around you without leaving the walkable area, and every player sees them.
- Custom game objects: an internal builder creates game objects with custom properties, which is what force pulses use.
- Players no longer drop their current weapon if they run out of ammo: Players were dropping the current weapon automatically when it runs out of ammo, now that's fixed so it can line up with the multiplayer base (inventory scripts that show that you have the weapon but not the ammo etc)
- Joining: your game joins only once it's ready (at the main menu), which avoids failed joins.
- Steam login: the ticket check no longer pauses the server while players log in.
Changed
- Positions: sent with 1 cm precision. Teleports and server moves always win over a player's own sync.
- Remote players and vehicles: movement is predicted with your own ping instead of a fixed guess, so fast vehicles no longer overshoot.
- Streaming distance: players and objects stream in within about 800–1200 m, down from about 2–3 km.
- Health: health is a value from 0 to 1 everywhere in scripts. There's no separate max health any more.
- Ping: only the server knows players' pings. Scripts that show pings send them to clients themselves; player-menu and dashboard already do.
- Resource actions:
Resources.Start/Stop/Restartcalled from an event, command or timer are queued and run right after it, so admin menus can control resources again. OnPlayerTeleport: fires only for real teleports and respawns.- Damage and kill events: they lost their always-zero "hit bone" argument, so they're now
(player, damager, damage, weapon, position). math.random: seeded per server start, so "random" picks differ between runs.- net-stats: the overlay is hidden until you type
/netstats. - Weather: the server remembers the current weather and sends it to players who join late.
Fixed
Sync and gameplay
- Server moves: the server's
SetPositionandSetRotationwork for vehicles and rigid objects, and moved vehicles no longer float in the air. - Rigid objects: rigid objects spawned by the server now show up. The game waits until their model and collision are loaded before spawning them.
- Vehicle health: a vehicle's health set by the server no longer reverts.
- World origin: vehicles no longer jump to the world's origin (0, 0, 0) when another player takes them over.
- Vehicle parts: door and trunk states set by the server are now remembered, so they close again and stop blocking entry.
- Parachutes: other players' parachutes now turn smoothly instead of snapping with every update.
- Mounted guns: they now turn with the player's aim, and other players see them turn.
- Slow movers: walking NPCs and other slow objects now sync their position.
- Ammo: the server's
SetWeaponAmmo/SetInventoryAmmonow apply to your own player. - Damage kicks: damage with broken (infinite) values no longer kicks players.
- Position stalls: brief freezes of up to 2 s right after joining are gone.
- Tethers:
World.SpawnTetherno longer crashes both games, and joining while a tether exists no longer crashes. - Weather values: float cloud values now arrive correctly, and fractional values no longer crash the server.
- Force pulse damage: explosions without a damager (script force pulses and explosions) now hurt and knock back players.
- Quick key presses: a key tapped for a single frame is no longer lost for other players.
Server
- Console
stop <name>: it stops only that resource instead of the whole server. - Web requests: the server no longer drops about 1 in 100 web requests (server info, mods).
- Connection errors: the "Unable to connect" popup shows the real reason again.
- Malformed data: a client can no longer crash the server with malformed script data.
- Tick rate: the server keeps its full tick rate.
Scripting
Physics.Raycast: it returns the real hit point.Timer.Kill: it works now. Before, it didn't stop timers at all.- Delta time:
GetUpdateDeltaTimeandGetRenderDeltaTimereturn correct values. - JSON: keeps decimals and large numbers exact.
FX.Spawn: it plays effects the current area hasn't loaded, loading them and everything they use first.- SQL:
last_insert_idis no longer set after an UPDATE, and query errors are reported instead of looking like an empty result. - Table keys: keys like
3.5, negative numbers or numbers above 65535 surviveNet.Send. require: a missing module raises an error instead of returning nil.- Server files: a resource whose name contains "client" no longer sends its server files to players.
- Self-stop errors: the two "a resource can't stop/restart itself" error messages are no longer swapped.
tostring: works on avec4.- Client sandbox: client scripts can no longer use
loadlib,dofileorloadfile.
Removed
- Lua 5.4 features: use
bit.*for bit operations andunpackinstead oftable.unpack.table.pack,math.typeand the integer subtype are gone. - Old API names:
Players.*,GetNick,GetSteamId,GetNetPlayer,Net.SendToTarget,GetAclLevel(see below). - Max health:
GetMaxHealth/SetMaxHealthare gone. - Client pings:
GetPingon clients is gone; it's server only now. - Timers inside timers:
Timer.Setinside a timer callback now raises an error. Set timers from load time or from event handlers.
Script API changes
| Old | New |
|---|---|
Players.GetJoined() | World.GetPlayers() |
Players.GetRandom() | World.GetRandomClient() |
Players.LocalPlayer() | World.LocalPlayer():AsPlayer() |
Players.LocalClient() | World.LocalClient() |
client:GetNick() | client:GetName() |
client:GetSteamId() | client:GetUserId() |
client:GetNetPlayer() | client:GetPlayer():AsPlayer() |
client:GetAclLevel() == AclLevel.Admin | client:HasAcl(AclLevel.Admin) |
AclLevel.Normal | AclLevel.Default |
Net.SendToTarget(client, ...) | Net.SendToPlayer(client, ...) |
Net.SendToTargets(list, ...) | Net.SendToPlayers(list, ...) |
local r = SQL.Execute(...); r.success, r.error | local r, err = SQL.Execute(...) |
obj:GetData(key, default) | obj:GetData(key) (nil when missing) |
OnPlayerKilled(p, d, loss, hitBone, weapon, pos) | OnPlayerKilled(p, d, loss, weapon, pos) |
Good to know when porting:
- Before join: a client starts its resources before it joins, so in
OnPlayerResourceActionthe player may have no object yet. Load player data inOnPlayerJoin. - Out of view: on a client, an object out of view is
nil, both fromWorld.GetObjectByNIDand when it arrives in aNetevent. - Warping into vehicles: a player can only be put into a vehicle their game can see. Spawn the vehicle near them, or teleport them next to it first.
- SQL errors in the log: every failed SQL statement is logged. Use
INSERT OR IGNOREinstead of "insert and ignore the error".
Default scripts
Every default script is ported to the new API except chat (coming later).
- cnr: rounds start when 2 players are in, the robber is put in their car, and the cop gets the attack helicopter.
- derby: players are seated in their cars, non-admins see why they can't start a round, quitting players no longer block the win, and there's no "No winner" after a win.
- deathmatch: players who load in early respawn correctly once they join.
- car-radio: songs now reach other players (they never did before).
- weather:
- only admins can control it;
- H spawns a sandstorm where you aim, its wind blowing toward you, and L removes the newest one.
- spawn-menu:
- vehicle colours are truly random;
- the weapon button arms only you.
- teleport-menu: a click outside the menu no longer teleports you.
- player-menu: shows pings and has its own Warp, so it no longer needs teleport-menu.
- admin-menu: start, stop and restart work again.
- dashboard:
- works without the async SQL calls;
- only sends pings while it's open.
- login-system: saves and restores players reliably on join.
- npc-shooter: press G and your NPC throws a grenade at your feet, press U and it runs at you and hits you.
- drones (new): command your own squad of up to 6 drones with the numpad:
- 1 spawns a guard, attack or rocket drone, in turn;
- 2 makes them follow you in a ring over your head, 3 holds them where they are, and 4 sends them to where you aim;
- hold 5 and they fire where you aim, press 6 and they hunt the closest other player;
.removes them. A panel on the right lists the keys and shows your squad, and 0 hides it.
- animation-menu (new): press Y to pick from 428 civilian animations in 10 categories (dancing, music, emotes, sitting and more). Select one and press Play, or Stop to end it.
Known limitations
- Altitude limit: above 4096 m, positions are capped. Only very high planes notice.
Input.SetValue: actions triggered from scripts with it aren't seen by other players.- Chat resource: while it runs, client commands (
/...) can't be typed. - One handler per event: each script can have only one handler per event.