dayz-physics-engine
Skill20 starsChanged 41 days agoMITView on GitHub
Use when: física DayZ, dBody, collision layers, player walks through my object, action/cursor does not appear, EOnContact, TransportHit, thrown/rolling objects, ragdoll, .ragdoll, fall damage, PhysicsSetSimpleDeath, offload physics / reduce server load. Not vehicle authoring: dayz-vehicles; not flight: dayz-aviation.
In this repository47 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- 3d-generation-harnessSkill
- ai-3d-to-dayzSkill
- ardy-motion-generationSkill
- blender-animationSkill
- blender-assemblySkill
- blender-visual-reviewSkill
- dayz-3d-viewerSkill
- dayz-ai-patternsSkill
- dayz-animation-pipelineSkill
- dayz-aviationSkill
- dayz-basebuildingSkill
- dayz-charactersSkill
- dayz-clothingSkill
- dayz-doorsSkill
- dayz-environment-hazardsSkill
- dayz-feature-specSkill
- dayz-mcp-verifySkill
- dayz-model-pipelineSkill
- dayz-mod-workflowSkill
- dayz-motorbikesSkill
- dayz-p3d-auditSkill
- dayz-p3d-inspectorSkill
- dayz-particlesSkill
- dayz-pbo-buildSkill
- dayz-pbo-reverse-engineeringSkill
- dayz-persistenceSkill
- dayz-preflightSkill
- dayz-proxy-alignSkill
- dayz-realistic-animation-directorSkill
- dayz-sound-systemSkill
- dayz-test-ingameSkill
- dayz-texture-pipelineSkill
- dayz-ui-developmentSkill
- dayz-undergroundSkill
- dayz-vehiclesSkill
- dayz-weaponsSkill
- enforce-script-referenceSkill
- mixamo-retargetSkill
- ovh-cloudSkill
- rigorous-data-auditSkill
- rip-vehicle-importSkill
- systematic-debuggingSkill
- task-observerSkill
- uv-clean-atlasSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 85
Not measured: a jump while the platform rises, a vehicle with a driver aboard, the latency of a second client on another machine.
- Very specific: line 154
Use the same query to log whether CHARACTER × DYNAMICITEM is active when debugging "walks through".
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
DayZ Engine Physics (Enforce Script)
Engine-truth reference for rigid-body work in DayZ mods. Every API claim below was verified against
the decompiled vanilla v1.24 scripts; citations are path:line relative to the script root (treat
line numbers as ±3 — minor drift between builds). When something common-sounding is missing here,
check section "What does NOT exist" before assuming it exists.
How to use this skill
The body covers the 90% working set. Three bundled references hold the full deep-dives — load them only when the task needs that depth:
| Reference | Read it when |
references/fisica-engine-deep-dive.md | full dBody/dGeom/dJoint signatures, raycast family tables, surfaces, drop-physics lifecycle details |
references/transport-netsync-vehiculos.md | anything about why/how vehicles replicate, CarScript damage-by-momentum, Pawn/TransportOwnerState, push-action pattern |
references/dano-transporthit.md | damage pipeline (MDF), EEHitBy chain, the complete TransportHit flow line-by-line, hitzones, armor reality |
references/dayz-1-30-ragdoll-and-fall.md | 1.30 Exp: .ragdoll / RagdollDef, PhysicsSetSimpleDeath, unconscious wake-while-falling, fall-damage CurveExp |
The 11 engine truths (prevent the classic bugs)
- A body only collides where it exists. The player capsule (CCT) is simulated client-side
(hasta 1.29:
3_game/human.c:1397-1418; desde 1.30 Exp:exp/scripts/scripts/3_Game/human.c:1426-1452). A rigid body created only on the server can never block a player — the client's CCT has nothing to collide with. This is architectural; no layer mask fixes it. - The action cursor sees View Geometry, not physics. Action targeting uses
RaycastRVProxywith defaultObjIntersectView(hasta 1.29:4_world/classes/useractionscomponent/actiontargets.c:214-219; desde 1.30 Exp:exp/scripts/scripts/4_World/Classes/UserActionsComponent/ActionTargets.c:255; default still3_game/global/dayzphysics.c:88). No View Geometry LOD in the .p3d → no action, no admin-tool selection, regardless of any physics body. Truth #2 still holds in 1.30. (desde 1.30 Exp: liquid surfaces with no object are also scored action targets at utility 0.01 —exp/scripts/scripts/4_World/Classes/UserActionsComponent/ActionTargets.c:532-534;ActionTargetctor takessurfaceNameat:125-138.) (Qualified 2026-10-03, read in the 1.29 source, not measured; 1.30 not checked: at a camera pitch of −45° or lower, targeting also takes the objects of a 30°, 3 m cone and scores them by their distance to the cursor ray, with no hit on them needed (4_world/classes/useractionscomponent/actiontargets.c:286-287,:444-445,:730-735), so an item on the ground can become a target without any View Geometry hit. Seedayz-mcp-verify, "Picking an item up proves nothing about its collision".) dSetInteractionLayeris GLOBAL. It edits the world's layer↔layer interaction matrix (1_core/physics/physicsworld.c:14-21); the first parameter only resolves the world. To stop two specific entities from colliding use the surgical pair-block instead:dBlock b = dBodyCollisionBlock(entA, entB); ... dBodyRemoveBlock(world, b);(1_core/proto/enphysics.c:116-117).- Friction/restitution are material strings, not setters. They come from the physics material
assigned per-geometry (
PhysicsGeomDef.MaterialName, e.g."material/default"—1_core/physics/physicsgeomdef.c:18-24) and surface definitions (.bisurf / CfgSurfaces). There is nodBodySetFriction-style API (0 matches in all of scripts/). Measured (BenchRE 2026-08-26): .bisurfrestitutiondoes not translate into bounce on the native item path — SmallStone dropped from 5 m onto open-field terrain rebounds 0.02-10 mm (apparent e = 0.009-0.046, n=6). - Transport replicates because it is a Pawn.
Transport extends Pawnwith continuousTransportOwnerState(world transform + linear + angular velocity) streamed to all proxies (3_game/vehicles/transport.c:13-30,52-53;3_game/entities/pawn.c:20-24).ItemBaseis not a Pawn: clients get only occasional entity snapshots — never velocities. A free dynamic body on an ItemBase looks "synced" only at low latency/local tests. - The native throw path runs on server AND owner client.
HandActionThrowguards withGetInstanceType() != INSTANCETYPE_REMOTEbeforeitem.ThrowPhysically(player, force)(3_game/systems/inventory/hand_actions.c:77-81). That is why thrown items collide for the thrower. Whether REMOTE clients get a local body is not visible in scripts — treat third-party collision as unverified until tested in-game. - Drop/throw physics is temporary by design. It is governed by a lifetime:
StopItemDynamicPhysics()kills it viaSetDynamicPhysicsLifeTime(0.01)(4_world/entities/itembase.c:4530-4534). A long-rolling object must renew/extend the lifetime or avoid depending on the drop path. Measured (BenchRE 2026-08-26): the default lifetime is exactly 15 s (n=2,dBodyIsDynamicpolled at 4 Hz flips at t=15.00);SetDynamicPhysicsLifeTime(3600)is honored (still dynamic past a 300 s watchdog). - A player's EOnContact only reacts to Transport.
DayZPlayerImplement.EOnContactcastsTransport.Cast(other)and ignores everything else (hasta 1.29:4_world/entities/dayzplayerimplement.c:3814-3829; 1.29 realEOnContactisstable-1.29/scripts/scripts/4_World/Entities/DayZPlayerImplement.c:3822-3836; desde 1.30 Exp:exp/scripts/scripts/4_World/Entities/DayZPlayerImplement.c:3958-3973). A custom ItemBase that should hurt players must detect the contact itself and calltarget.ProcessDirectDamage(...)from its ownEOnContact. - Script impulses push corpses, not living players. Vanilla applies
dBodyApplyImpulseto the victim only whenIsDamageDestroyed()(ragdoll) —3_game/entities/entityai.c:4111-4115. Living players are displaced by the contact solver itself (both bodies present + interacting layers), not by script. - Config-driven animated geometry on a building is NOT a mover (measured in game, DayZDiag 1.29.163709) [EXACT]: a standing player stays suspended while the piece descends; a moving player rides up but does not ride down — they stay up, can walk a few metres on "nothing", then fall; a parked car is clipped through by the rising piece; a running car rises a bit and drops. Any elevator or lift platform needs a script layer that carries the rider. (On the way down the client seems to keep the old collision for a while — hypothesis, not measured.)
- A platform that is a SEPARATE entity does carry riders (measured in game, DayZDiag 1.29.163709, one client on localhost; SP-450) [EXACT]: a
Housewhose config inheritsHouseNoDestructwithanimPhysDetachSpeed=100, moved withSetPositionevery frame on the server AND on each client from the same clock (the server re-syncs the time every 0.25 s, the client extrapolates), lifted a standing player 8.9 m in 15 s (peak 0.93 m/s) without touching the player's position: within 5 cm on the server and 7.9 cm on the client, the client error being one frame of lag (correlation 0.89 with speed × frame time). The player must be linked (PhysicsGetLinkedEntity() == platform,3_game/human.c:1403); after a teleport they need one native step before they link.- Walking and jumping on it (SP-452; the same platform, build and setup, four 8.9 m trips played by hand, run
8e032fd9, the player's position logged at 20 Hz while the platform moved and 2 Hz while it stood: 1,448 samples on the server, 1,369 on the client) [EXACT][CLAIM-PHYS-PLATFORM-WALK-INGAME]:- Walking during the travel keeps the link.
link=1in every sample until the player stepped off onto the deck at the end, and no slide in any sample; on each of the three trips walked, 96.0-97.8 % of the server samples and 98.4-99.6 % of the client samples stayed within 8 cm of the face (the descent counted without its two jumps). - A jump keeps the link and is relative to the platform. The two jumps, both on the way down, spent 0.42-0.47 s in the air with a peak 0.30-0.32 m above the face,
link=1throughout, and landed on the platform. That is close to the vanilla jump on still ground:StartCommand_Fall(2.6)(4_world/entities/dayzplayerimplementjumpclimb.c:97) starts the fall at 2.6 m/s up (StartCommand_Fall(float pYVelocity),3_game/human.c:1467), a 0.345 m, 0.53 s arc by ballistics. The run does not tell whether the link carries the player in the air or the take-off inherits the platform's velocity: on these two jumps the two differ by about 2 cm at most, below what the trace resolves. It does rule out a jump that leaves the player at 2.6 m/s up in the world, neither carried nor inheriting: by the same ballistics its peak would be about 0.5-0.6 m above the face, which was descending at 0.60-0.83 m/s. No jump was made going up. - Walking aboard links on its own. A player who walked onto the stopped platform was linked with no preparatory step, about 8 s before it started: that step is only needed after a teleport. No sample read a fall when the player stepped off at the bottom (0.35 m down to the floor, logged at 2 Hz, so a drop that short can fall between two samples) or onto the deck at the top in about the last half second of the travel, with the platform within 3 cm of it (logged at 20 Hz).
- Short spikes. The player read up to 22 cm off the face on the server and 12.6 cm on the client, for one sample (up to three in a row on the server), and was back within 5 cm at the next. The offset trails the travel (above the face going down, below it going up) except in one client sample. On the client the spikes follow long frames (correlation about 0.7 with speed × frame time; 53 ms frames at the spikes, 8 ms elsewhere); on the server the correlation is 0.31 and the cause is open.
- Not measured: a jump while the platform rises, a vehicle with a driver aboard, the latency of a second client on another machine.
- Walking during the travel keeps the link.
- Vehicles on that platform. Asleep (
dBodyActiveINACTIVE) +SetPosition+Transport.Synchronize(): the server carries them but the client receives nothing until they wake — do not use. Awake only (ALWAYS_ACTIVE): a sedan rides well, but aCarScripthelicopter with its own flight model bounces up to 24 cm and slides 31 cm. Awake withSetVelocity= platform velocity + 4 × position error, every frame: the sedan (with and without wheels) and the helicopter ride within 4.6 cm on the server and 11.5 cm on the client, and stop exactly when released. - The frame hook.
EOnFramenever reaches aHouseinstance, even withSetEventMask(EntityEvent.FRAME)(measuredfe=0); theGetGame().GetUpdateQueue(CALL_CATEGORY_GAMEPLAY)invoker runs every frame on server and client (3_game/dayzgame.c:3035-3038). - A script can walk a client-controlled player only with the overrides on both sides, every move. In 1.29 multiplayer with reconciliation,
OverrideMovementSpeed/OverrideMovementAngle(3_game/human.c:234-237in 1.29,:253and:256in 1.30) moved the player 0.24-0.40 m in 1.5 s when set on the client only, and 0.00 m when also set once on the server by RPC. What walks it (DayZDiag 1.29, one client on localhost, spike run 0db321a8; dayz-mcpplayer_move, #191, merged 2026-10-01): the owner sets both overridesENABLEDon every command tick and sends aScriptInputUserDatarequest; the server applies the same two overridesENABLEDin everyConsumeMoveaftersuperand in itsCommandHandler, thenDISABLEDat the end. Owner and server walked 0.76 m per 0.5 s (about 1.52 m/s) and stopped at the same position. Script fields added toPlayerBaseMovenever reached the server. Reference implementation: dayz-mcpaddon/scripts/4_World/MCP_PlayerMove.c. - A Roadway face of another model across the travel stops the ride down (SecretRock elevator, measured in game, DayZDiag 1.29.163709, 2026-10-02/03) [EXACT][CLAIM-PHYS-ROADWAY-ACROSS-TRAVEL]: an elevator cabin of this kind (a
HouseNoDestructmoved withSetPositionon the update queue) carried a player up through its stops but not down: going down, it left them standing at the stop's floor height, 18.59 or 12.78 m, and went on without them.player_traceread the building's interior model as the floor, no linked entity and no fall. That model's collision slabs had the shaft cut out, but its Roadway LOD did not: the project counted 26 Roadway triangles at 12.78 and 16 at 18.59 inside the shaft's footprint, the faces the rising cabin had carried the player through. With the shaft cut out of that Roadway too (per the project, the build changed only that model, and in it only those Roadway polygons), the player rode down 2 → 1 → 0, and on a later build a 2 → 0 ride stayed linked to the cabin in all 1,033 samples, none falling. So a character stands on a Roadway face where no Geometry is, and noRaycastRVprobe can target it:ObjIntersectoffers Fire, View, Geom, IFire and None, not Roadway (3_game/constants.c:31-38). Before shipping a lift, cabin or sliding piece, check offline that no Roadway face of any other model lies in the volume its collision sweeps (the piece's own Roadway moves with it: the cabin has one, and the project's gate leaves the cabin out). The project's gate swept the cabin's Geometry, shrunk 1 cm, from stop 0 to stop 2: it failed the old models on 25 faces and passed the fixed ones with 0. Not measured: aRayCastBulletwithPhxInteractionLayers.ROADWAYagainst a model's Roadway LOD; one cabin in one building.
- Walking and jumping on it (SP-452; the same platform, build and setup, four 8.9 m trips played by hand, run
API quick map (verified signatures)
Create / destroy (1_core/proto/enphysics.c)
proto bool dBodyCreateStaticEx (notnull IEntity ent, PhysicsGeomDef geoms[]); // :38
proto bool dBodyCreateGhostEx (notnull IEntity ent, PhysicsGeomDef geoms[]); // :39
proto bool dBodyCreateDynamicEx(notnull IEntity ent, vector centerOfMass, float mass, PhysicsGeomDef geoms[]); // :51
proto native void dBodyDestroy(notnull IEntity ent); // :54
proto native bool dBodyIsSet(notnull IEntity ent); // :57PhysicsGeomDef(string name, dGeom geom, string materialName, int layerMask)+ publicFrame[4],ParentNode(1_core/physics/physicsgeomdef.c:9-26).- Geoms:
dGeomCreateBox(size):186,dGeomCreateSphere(radius):189,dGeomCreateCapsule:192,dGeomCreateCylinder:195,dGeomDestroy:198. dBodyCreateDynamic/Static(noEx) exist only under#ifdef GAME_TEMPLATE(2_gamelib/entities/scriptmodel.c:31,35) — they do not compile in DayZ. The wrapperPhysics.CreateDynamic(ent, mass, layerMask)builds geometry from the entity's .p3d (1_core/physics/physics.c:189).- Recreate pattern: always
if (dBodyIsSet(this)) dBodyDestroy(this);before re-creating.
State, damping, sleep, CCD
dBodySetInteractionLayer(ent, mask) // :59 (per body) dBodyGetInteractionLayer :60
dBodyActive(ent, ActiveState.X) // :64 INACTIVE | ACTIVE | ALWAYS_ACTIVE (activestate.c:9-17)
dBodyDynamic(ent, bool) // :65
dBodyEnableGravity(ent, bool) // :69 bool only — no vector
dBodySetDamping(ent, linear, angular) // :70
dBodySetSleepingTreshold(body, lin, ang) // :71
dBodyEnableCCD(body, maxMotion, castRadius) // :83 (-1 disables) anti-tunneling
dBodySetLinearFactor(body, vector) // :87 zero an axis => 2D physics
dBodyGetMass / dBodySetMass // :122-123Impulses, forces, velocities
dBodyApplyImpulse(body, impulse) // :141
dBodyApplyImpulseAt(body, impulse, worldPos) // :136 off-center => natural torque/roll
dBodyApplyForce / dBodyApplyForceAt // :146 / :151
dBodyApplyTorque / dBodyApplyTorqueImpulse // :153 / :125
GetVelocity(ent) / SetVelocity(ent, v) // :104 / :111 global functions (work on Man too)
dBodyGetAngularVelocity / dBodySetAngularVelocity // :158 / :165 rad/s per axis, NOT yaw/pitch/roll
dBodyGetVelocityAt(body, worldPos) // :177
dBodySetTargetMatrix(body, matrix, timeslice) // :170 kinematic move
dBodyGetKineticEnergy(body) // :175Wrapper-only extras: Physics.ClearForces/GetTotalForce/GetTotalTorque/SetResponseIndex
(physics.c:106-115); constants Physics.STANDARD_GRAVITY(9.81)/VGravity/KMH2MS (physics.c:18-21).
Interaction layers (3_game/global/dayzphysics.c:1-43)
PhxInteractionLayers (bit order): NOCOLLISION, DEFAULT, BUILDING, CHARACTER, VEHICLE, DYNAMICITEM,
DYNAMICITEM_NOCHAR, ROADWAY, VEHICLE_NOTERRAIN, CHARACTER_NO_GRAVITY, RAGDOLL_NO_CHARACTER/FIREGEOM,
DOOR, RAGDOLL, WATERLAYER, TERRAIN, GHOST, WORLDBOUNDS, FENCE, AI, AI_NO_COLLISION, AI_COMPLEX,
TINYCAPSULE, TRIGGER, TRIGGER_NOTERRAIN, ITEM_SMALL, ITEM_LARGE, CAMERA, TEMP.
Runtime query pattern (vanilla, 3_game/vehicles/transport.c:556-557):
int layer = dBodyGetInteractionLayer(obj);
bool blocksPlayer = dGetInteractionLayer(this, PhxInteractionLayers.CHARACTER, layer);Use the same query to log whether CHARACTER × DYNAMICITEM is active when debugging "walks through".
Raycast / overlap families (3_game/global/dayzphysics.c:123-230)
Two separate worlds — pick the right one:
| Family | Sees | Use for |
RaycastRV :199 / RaycastRVProxy :208 | RV geometries via ObjIntersect*: Fire(0), View(1), Geom(2), IFire(3), None(4) (:66-71) | cursor/action targeting, hit surfaces, melee aim |
RayCastBullet :211, SphereCastBullet :213, *OverlapBullet :216-228 | Bullet physics world, filtered by PhxInteractionLayers | physical LOS, ground probes, area queries on bodies |
CollisionFlags (FIRSTCONTACT, NEARESTCONTACT, ONLYSTATIC, ONLYDYNAMIC, ONLYWATER, ALLOBJECTS) —
1_core/proto/endebug.c:140-148. Overlap callback: CollisionOverlapCallback.OnContact(IEntity, Contact)
(dayzphysics.c:115-121). Action-cursor ground fallback uses RayCastBullet with
ROADWAY|TERRAIN|WATERLAYER (up to 1.29: actiontargets.c:329-331; from 1.30 Exp: exp/scripts/scripts/4_World/Classes/UserActionsComponent/ActionTargets.c:383-384).
Contacts
sealed class Contact (1_core/physics/contact.c:9-50): Impulse (:21), Normal, Position,
PenetrationDepth, RelativeVelocityBefore/After, GetNormalImpulse() (:47). Receive it via
SetEventMask(EntityEvent.CONTACT) → override void EOnContact(IEntity other, Contact extra)
(1_core/proto/enentity.c:213). Vanilla measures impact magnitude with
extra.RelativeVelocityBefore.Length() (3_game/entities/inventoryitem.c:200, threshold 0.3,
throttled 0.33 s) — not with Impulse. Transport.OnContact warns "Can be called very frequently in
one frame" (4_world/entities/vehicles/carscript.c:1453): buffer contacts, process once per tick
(vanilla caches and consumes in EOnPostSimulate).
Native dynamic-item path (drop/throw)
// 3_game/entities/inventoryitem.c
proto native void EnableCollisionsWithCharacter(bool state); // :21
proto native void ThrowPhysically(DayZPlayer player, vector force, bool collideWithCharacters = true); // :26
// 3_game/entities/object.c
proto native void CreateDynamicPhysics(int interactionLayers); // up to 1.29: :462; from 1.30 Exp: exp/scripts/scripts/3_Game/Entities/Object.c:456 (never called by vanilla script)
proto native void EnableDynamicCCD(bool state); // up to 1.29: :463; from 1.30 Exp: :457
proto native void SetDynamicPhysicsLifeTime(float lifeTime); // up to 1.29: :464; from 1.30 Exp: :458Lifecycle: throw (hand_actions.c:62-88, server+owner) · inventory dump uses
ThrowPhysically(null, force, false) (4_world/static/miscgameplayfunctions.c:1164-1220) · admin
spawn-with-gravity uses item.ThrowPhysically(null, "0 0 0") server-side
(4_world/plugins/pluginbase/plugindeveloper.c:381,504) · re-config hook
override void OnCreatePhysics() (itembase.c:1222-1227; real overrides in tentbase.c, fireplace.c,
batterycharger.c). The DYNAMICITEM / DYNAMICITEM_NOCHAR pair maps to collideWithCharacters
by naming (inference — internal assignment not script-visible).
Player CCT (3_game/human.c)
PhysicsIsFalling (up to 1.29: :1397; from 1.30 Exp: exp/scripts/scripts/3_Game/human.c:1428, comment :1426-1427 "returns true if the ragdoll is moving greater than 1m/s"), PhysicsGetFloorEntity (up to 1.29: :1400; from 1.30 Exp: :1431), PhysicsGetLinkedEntity :1403,
PhysicsGetVelocity :1410, PhysicsEnableGravity :1412, PhysicsSetSolid :1414-1415,
PhysicsSetRagdoll (up to 1.29: :1418 comment at stable-1.29/scripts/scripts/3_Game/human.c:1417-1418; from 1.30 Exp: :1451, catalogued as old death-state system),
PhysicsSetSimpleDeath (from 1.30 Exp: :1449), PhysicsIsRagdoll (from 1.30 Exp: :1452; also HumanCommandUnconscious.IsRagdoll at :647),
CheckFreeSpace :1354, CollisionMoveTest :1357, LinkToLocalSpaceOf :1361.
Lifting the player from a HumanCommandScript needs the controller's gravity off (measured in game, DayZDiag 1.30.164014 Exp, LFSkateboard test R1c, 2026-10-06, server and one client on one machine) [EXACT][CLAIM-PHYS-SCRIPTCMD-GRAVITY-130]. A skateboard ride command integrated its own ollie (dy = vy·dt − ½g·dt² each tick, vy 2.69 m/s at take-off) and passed dy as the y of PrePhys_SetTranslation, which is local space (exp/scripts/scripts/3_Game/human.c:1313). In PostPhysUpdate it compared PostPhys_GetPosition with the integrated height and, past 3 cm, pinned the height with PostPhys_SetPosition on every air tick (world space, human.c:1325-1327).
- Gravity on, the default: the body did not rise. The first air tick ended 0.088 m under the integrated height on the server and on the owner client, which is that tick's whole 0.084 m step lost. 0.2 s into the flight, with the pin already on, the server read the body 1 cm under its take-off height, where the integration asked for about +0.34 m.
Human.PhysicsEnableGravity(false)from take-off to landing (human.c:1443), the only script change in the next build: the body followed the translation. The server never needed the pin (every air tick within 3 cm). On the owner client the root peaked at 0.996 and 1.001 × vy²/2g in the two landed flights, sampled at about 10 Hz; in the second one the client had switched to the pin after reading the body 0.079 m above the integration on its second air tick.PhysicsEnableGravity(true)at the landing, and inOnDeactivatefor a ride that ends in the air: after the first landing the rider rolled down a slope again, 2.6 m of descent over the next 11 s.
Vanilla calls PhysicsEnableGravity once, with true, when a vehicle death's simulation ends (exp/scripts/scripts/4_World/Entities/DayZPlayerImplement.c:32), so a command that switches the gravity off owns switching it back on every exit path. Not measured: a remote observer, flights longer than the 0.6 s these lasted, and fall damage after a flight with the gravity off.
PhysicsIsFalling(true) is not a pure read (measured in game, DayZDiag 1.30.164014 Exp, LFSkateboard test R1d, 2026-10-06) [EXACT][CLAIM-PHYS-ISFALLING-VALIDATE-130]. R1d's command switches the gravity off at the pop, 0.1 s before the take-off, and then lifts the body with PrePhys_SetTranslation(Vector(0, dy, z)). Up to R1c an airborne guard called PhysicsIsFalling(true) on every tick of the pop; R1d skipped that call during the pop, and every take-off lost its first air tick: PostPhys_GetPosition read exactly that tick's dy under the integrated height (errors of −0.11 to −0.15 m), the body barely rose for about 0.1 s, and the apex reached 0.44 to 0.61 of vy²/2g, on a climb and on a downhill alike. Calling it again on the ticks of the pop, its result ignored, was the only take-off change between the build of run 1 and the build of runs 2 and 3 (the other suspect, an extra PostPhys_GetPosition read on every tick, was in both): in runs 2 and 3 the apex came to 1.00 of vy²/2g (0.70 m for 0.698 expected), with no correction. What pValidate does is not documented (exp/scripts/scripts/3_Game/human.c:1428). A command that lifts the body with the gravity off keeps calling PhysicsIsFalling(true) on the ticks before the lift, or measures its first air tick.
Joints
dJointCreateHinge/Hinge2/Slider/BallSocket/Fixed/ConeTwist/6DOF/6DOFSpring(..., bool block, float breakThreshold)
- per-type setters (
enphysics.c:212-270); break eventEOnJointBreak(1_core/proto/enentity.c:207).
Surfaces
SurfaceInfo (3_game/surfaceinfo.c:8-51): GetByName/GetByFile, roughness/dustness/penetrability,
IsLiquid/IsSolid, step/wheel particle ids. Detection: CGame.GetSurface/SurfaceY/SurfaceGetType/
SurfaceUnderObject/SurfaceGetNormal (3_game/global/game.c:1160-1187). Impact surface:
DayZPhysics.GetHitSurfaceAndLiquid (dayzphysics.c:206; used inventoryitem.c:168-176). No
friction getters — see truth #4. Water over water objects (river and stream pieces, a roadway
water_ext face): knowledge/vault-notes/dayz-engine-water.md.
Recipes
A. Custom dynamic sphere body (server-side baseline)
PhysicsGeomDef geoms[] = {PhysicsGeomDef("", dGeomCreateSphere(0.5), "material/default",
PhxInteractionLayers.DYNAMICITEM)};
dBodyCreateDynamicEx(this, GetCenterOfMassOffset(), 80.0, geoms);
dBodySetInteractionLayer(this, PhxInteractionLayers.DYNAMICITEM);
dBodyActive(this, ActiveState.ALWAYS_ACTIVE); // no mid-slope sleep
dBodySetDamping(this, 0.05, 0.2);
dBodyEnableCCD(this, 0.4, 0.45); // ~diameter*0.8, inner radiusRemember truth #1: created only server-side, players walk through it.
B. Native path (recommended for items that must block/hit players)
// run on server AND owner client (replicate the hand_actions.c:77 guard):
item.ThrowPhysically(null, impulse, true); // true => collides with CHARACTER
item.EnableDynamicCCD(true);
item.SetDynamicPhysicsLifeTime(3600); // renew for long rolling [validate in-game]Model requirements: Geometry LOD (collision), View Geometry (cursor — truth #2), FireGeometry (bullets).
C. Contact damage to players (vehicle-parity, from the stone side)
void MyItem() { SetEventMask(EntityEvent.CONTACT); }
override void EOnContact(IEntity other, Contact extra)
{
if (!g_Game.IsServer()) return;
EntityAI target = EntityAI.Cast(other);
if (target && target.IsAlive())
{
float speed = GetVelocity(this).Length(); // m/s
if (speed > 0.5 && m_CanHit) // guard vs multi-contact per tick
{
m_CanHit = false; // reset via timer or target EEHitBy
target.ProcessDirectDamage(DT_CUSTOM, this, "", "TransportHit", "0 0 0", speed);
}
}
}damageCoef IS the velocity: real damage = base damage of ammo "TransportHit" × coef
(entityai.c:4086-4116; desde 1.30 Exp: RegisterTransportHit at exp/scripts/scripts/3_Game/Entities/EntityAI.c:4111, Motorbike branch :4143-4160). The ammo lives in binary game data, not scripts. Vanilla resets its
one-hit guard in the victim's EEHitBy (dayzplayerimplement.c:1551; desde 1.30 Exp: exp/scripts/scripts/4_World/Entities/DayZPlayerImplement.c:1567). Corpse launch only:
impulse = 40 * velocity; impulse[1] = 60; dBodyApplyImpulse(victim, impulse); gated by
IsDamageDestroyed() (truth #9). Full pipeline: references/dano-transporthit.md.
D. Push action (vanilla parity)
ActionPushCar applies dBodyApplyImpulseAt(car, impulse, car.ModelToWorld(car.GetEnginePos()))
(4_world/classes/useractionscomponent/actions/continuous/actionpushcar.c:52). Off-center
application point gives natural roll. Stamina cost is one line: EStaminaModifiers.PUSH_CAR already
exists (3_game/enums/estaminamodifiers.c:13).
E. Wake a sleeping body before impulses
dBodyActive(ent, ActiveState.ACTIVE); dBodyDynamic(ent, true); then apply the impulse — impulses
on sleeping bodies are lost.
Debugging physics
- Visual overlay works in retail builds:
Shape.CreateSphere(0x88FF0000, ShapeFlags.TRANSP|ShapeFlags.NOZBUFFER, pos, r)andShape.CreateLines(...)withShapeFlags.ONCEfor per-frame draws (1_core/proto/endebug.c:114-230; never keep a pointer to a ONCE shape). - Log the layer matrix at runtime with the
dGetInteractionLayerquery pattern above. - Count world bodies:
dGetNumDynamicBodies(world)/dGetDynamicBody(world, i)(enphysics.c:9-10). - Fast iteration: DayZDiag_x64 +
-filePatchingreloads scripts without PBO rebuild (no BattlEye, no signature checks); see the dayz-mod-workflow skill §6 for the full loop.
What does NOT exist (verified: 0 matches in scripts/)
| Plausible-sounding API | Reality |
dBodySetFriction / SetRestitution / SetBounciness | physics material string per geometry + .bisurf only |
per-body gravity vector (dBodySetGravity) | only dBodyEnableGravity(ent, bool) and global dSetGravity(world, g) (enphysics.c:17) |
dBodySetVelocity / dBodyGetVelocity | global SetVelocity/GetVelocity (enphysics.c:104,111) |
dBodyApplyAngularImpulse | dBodyApplyTorqueImpulse (enphysics.c:125) |
AddForce (Unity-style) | dBodyApplyForce* |
SetMaxLinearVelocity clamp | clamp manually per tick |
PhxRaycast* | the physics-world casts are the *Bullet family in DayZPhysics |
EOnSimulate on CarScript | car physics is 100% native; script only calls Set* controls |
vanilla script call to CreateDynamicPhysics | declared but never called from script — no vanilla usage pattern |
Synchronize() on EntityAI/ItemBase | Transport-only (transport.c:108-109) |
Sleep/active enum
enum ActiveState { INACTIVE, ACTIVE, ALWAYS_ACTIVE } (1_core/physics/activestate.c:9-17).
ALWAYS_ACTIVE prevents mid-slope sleep for objects that must keep simulating.
Offloading physics from the server (checked 2026-09-26)
Gameplay physics cannot leave the authority; only cosmetic physics can.
- No out-of-process channel for per-tick work. Vanilla scripts expose no native-extension call
(0 matches for
callExtension,LoadLibrary,DllImportin the 1.29 and 1.30 Exp trees). The only network exit isRestApi: asynchronous with a callback (3_game/http/restapi.c:103,123) or thread-blockingGET_now/POST_now(:106-108,:126-128). Fine for slow, latency-tolerant work; never for a physics step. - Owner prediction does not remove server work. The authority consumes and replays the owner's move
(
3_game/entities/pawn.c:80-81,ConsumeMove:270-274), and a native comparison runs as well, with the more severe result winning (:261-265). A scriptCompareMovethat always returnsAPPROVEtherefore cannot suppress corrections. Vanilla cars follow this underNetworkMoveStrategy.PHYSICS(4_world/entities/vehicles/carscript.c:3220-3230). - Cosmetic physics can run per client at no server cost.
ECE_LOCALcreates a machine-local object (3_game/ce/centraleconomy.c:24); vanilla gives local objects collision withECE_LOCAL|ECE_CREATEPHYSICS(5_mission/gui/scriptconsoleitemstab.c:695). Whether a local object accepts a dynamic body is unverified. - Measure before optimizing.
EnProfilerprofiles script only (1_core/proto/enprofiler.c:62-63,-profile). For native cost, compare server CPU with and without the load on a capped server (dayz-test-ingame/references/dayz-1-30-test-ingame.md§ Measuring server load). On 1.30 Exp, 50 server-side dummy players sprinting did not show at 60 FPS and 100 did (dayz-mcp-verify/references/dayz-1-30-mcp-verify.md).
Cross-skill pointers
enforce-script-reference— language rules, RPC/SyncVars, config.cpp, action system basics.dayz-p3d-audit/dayz-model-pipeline— building the Geometry/ViewGeo/FireGeo LODs that physics and the cursor require.dayz-mod-workflow— implementation protocol + DayZDiag/filePatching fast loop.dayz-sound-system— impact/rolling audio driven from contact events (client-only rules).
PhysicsSetRagdoll on a LIVE player — empirical evidence (added 2026-06-11)
Origin: LFSlidingFloor spike B, in-game test 2026-06-10 (script logs with complete telemetry). Updates previous expectation "no public usage on live players / probably does not simulate":
(desde 1.30 Exp: ragdoll is no longer a fully opaque native blob — vanilla ships RagdollDef in exp/characters_bodies/DZ/characters/bodies/human.ragdoll. The live-player empirical notes below still apply; the new data format, Workbench editor, and PhysicsSetSimpleDeath are in references/dayz-1-30-ragdoll-and-fall.md.)
- SERVER-SIDE DOES SIMULATE: with (1) DisableSimulation(false) before toggle (parity with death flow, dayzplayerimplement.c:726), (2) pre-wake
dBodyActive(p, ActiveState.ACTIVE)+dBodyDynamic(p, true), (3)dBodyApplyImpulse(p, V*masa)— dBodyGetMass returned actual player mass (87.5 kg) and impulse caught on first try (without need for SetVelocity). Body slid 77.6 m at 4-6.7 m/s following terrain (including uphills — extremely low effective friction). - OWNER CLIENT DOES NOT: local avatar never ragdolls — remains standing and controllable (client-authoritative movement). Total server-owner desync. Live-ragdoll is only viable end-to-end with custom position sync (see LL-138).
- Toggle
PhysicsSetRagdoll(false)does NOT rubber-band: entity stays exactly where body ended up (pos pre == post, verified). - DANGER get-up:
StartCommand_Unconscious(0)+WakeUpat 0.5 s left player server-side 40 m UNDER terrain, with void fall, real uncon and death. Vanilla anti-wake-early protection is 2 s (up to 1.29: playerbase.c:3169-3172; 1.29 real:stable-1.29/scripts/scripts/4_World/Entities/ManBase/PlayerBase.c:3184m_UnconsciousTime > 2). (from 1.30 Exp: the 2 s guard remains atexp/scripts/scripts/4_World/Entities/ManBase/PlayerBase.c:3420AND vanilla additionally refuses wake-up while falling:if (false == PhysicsIsFalling(false))beforehcu.WakeUp()at:3423-3431. Custom 0.5 s wake paths that skip this still risk burying the body.)
Script bodies on vanilla items — BenchRE empirical evidence (added 2026-08-26)
DayZDiag 1.29 server+client run, BenchRE mod build 0004. Evidence:
C:\Users\<you>\dayz_re_scratch\bench_results\ (CSVs + raw logs); synthesis with 7
matrix questions in C:\Users\<you>\dayz_re_scratch\physics_matrix.md §6.
Physics.CreateDynamic/CreateDynamicEx/CreateStaticExreturn falsy on vanilla InventoryItem (SmallStone/WoodenStick spawned withCreateObjectEx): 7/7 attempts server-side. The NATIVE path on the same items works (ThrowPhysically+SetDynamicPhysicsLifeTime+dBodyIsDynamicread 2402 ticks). Items already possess a native body and theCreate*Exfamily does not adhere to them — coincides with its 0 gameplay uses in vanilla. A viable host for script bodies must lack own physics (unvalidated yet: custom entity stylescriptmodel.c).DayZPhysics.GetHitSurfaceAndLiquiddoes not name TERRAIN surfaces:RayCastBulletover open field returns valid hit_pos, but the path requires an Object and terrain is not one (6/6 nameless probes). For terrain:CGame.SurfaceGetType(x, z, out type)(3_game/global/game.c:1166) /SurfaceGetType3D(game.c:1168).- MP client:
CreateObjectExwithoutECE_LOCALreturns null (n=2). For client test local geometry addECE_LOCAL(3_game/ce/centraleconomy.c:24; client pattern:3_game/particles/particle.c:119).
Rules promoted from the lessons corpus (added 2026-07-27)
Promoted from AI/20_Knowledge/lessons-learned.md so that they arrive via trigger instead
of relying on someone remembering to look them up. Each rule cites its source LL-NNN;
the full entry lives there. Do not remove the citation: the index detects promotion by it.
- LL-014 — For rolling bodies, use very low but non-zero linear and angular damping and adjust sleeping threshold. Do not minimize contact friction: lives in
.bisurf; if it slides without rotating, raise it, and if it vibrates or does not stop, raise damping.
DayZ 1.30 Exp (build 1.30.164014)
What changes:
- Ragdoll is data-driven. Vanilla ships
RagdollDefwith 11 bones, capsules/sphere,flesh.bisurf, joints (exp/characters_bodies/DZ/characters/bodies/human.ragdoll:1-202). Workbench adds a ragdoll editor. [CHANGELOG]work/changelog-1.30-exp-modding.md:47. - Death-state handling: (hasta 1.29:
DayZPlayerImplementcalledPhysicsSetRagdoll(true)atstable-1.29/scripts/scripts/4_World/Entities/DayZPlayerImplement.c:736) (desde 1.30 Exp: the non-command death branch callsPhysicsSetSimpleDeath(true)atexp/scripts/scripts/4_World/Entities/DayZPlayerImplement.c:745).PhysicsSetRagdoll/PhysicsIsRagdollremain (exp/scripts/scripts/3_Game/human.c:1451-1452). - Unconscious ragdoll unhooks vehicle re-attach:
if (hcu && hcu.IsRagdoll()) m_TransportCache = null(exp/scripts/scripts/4_World/Entities/ManBase/PlayerBase.c:3346-3350). - Fall damage is exponential
CurveExpwith much lower height gates (health from 2 m, shock from 0 m, broken legs from 3 m).Randomizeno longer rolls a lethal 1.0 coef back down. Detail inreferences/dano-transporthit.mdandreferences/dayz-1-30-ragdoll-and-fall.md. - Action cursor still uses View Geometry (
RaycastRVProxy+ObjIntersectView). Liquid surfaces without an object are now targets (utility 0.01). - [CHANGELOG] hiding physics components of static meshes no longer leaves a residual collision at the origin (
work/changelog-1.30-exp-modding.md:35). No script counterpart.
What breaks:
modded DayZPlayerImplementFallDamagethat copies 1.29Math.InverseLerpthresholds: 2.5–4 m falls now cause shock and can break legs.- Custom uncon wake that calls
hcu.WakeUp()whilePhysicsIsFalling(false)is true: vanilla now refuses; skipping the guard can still bury the body (1.29 empirical). - Assuming player ragdoll collision/mass is 100% native and uneditable: you can now author
.ragdoll(bind path is adayz-charactersconcern). - Assuming infected can ragdoll:
ragdoll =in an infected'senfanimsysplus player death clips with theRagdollevent did nothing in an in-game test reported in #135 (1.30.164078). The ragdoll API isHuman-only. The reference proposes a corpse swap instead, a design that has not been tested; seereferences/dayz-1-30-ragdoll-and-fall.md§1.
Migration checklist:
- If you override fall damage: port
CurveExp+ 1.30 height constants; keepif (pValue == 1) return pValue;inRandomize. - Custom humanoids: ship a
.ragdollnext to the body; do not assumeLoadRagdollFileexists in script ([UNVERIFIED] — no such call in extracted scripts). - Custom uncon wake: keep
m_UnconsciousTime > 2ANDPhysicsIsFalling(false) == false. - Action targeting over water: expect a surface target even with no object (
ActionTarget.GetSurfaceLiquidType). - Death path:
PhysicsSetSimpleDeath(true)is the script-visible non-ragdoll death branch.
Detail: references/dayz-1-30-ragdoll-and-fall.md. Action-cursor line drift also patched in references/fisica-engine-deep-dive.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

