World objects

From Wiki G1R-MP G1 Remake Multiplayer
Jump to navigation Jump to search

World objects

Client-side; since 0.1.4.

WorldObjects.request submits asynchronous commands for resource-owned static meshes. It is generic gameplay-resource API, not restricted to the map editor. There is no engine global named CreateModel or MapEditor.CreateObject; MapEditor helpers are Lua functions inside the editor resource only.

Function and events

requestIdOrFalse = WorldObjects.request(command)
-- Events on the calling resource:
-- onClientWorldObjectResult(requestId, ok, reason, json)
-- onClientWorldObjectsReset()

Supply a table. A numeric request ID means queued, not spawned/applied. false means immediate validation/readiness/capacity/IPC rejection. Match the ID in onClientWorldObjectResult before committing Lua state. The result's JSON argument is a string; decode it with fromJSON. Never expose native pointers to Lua.

Commands

op Required fields and effect
create id, mesh, x,y,z, pitch,yaw,roll, sx,sy,sz, hidden,collision,selected. Creates a new instance; an existing ID fails with id-already-exists.
update id, all nine transform numbers and all three booleans. Updates an existing instance. Full state, not a partial patch. Does not replace the mesh: delete/create to change the asset.
delete id. Removes the caller's instance; an absent ID also succeeds.
clear Only op. Removes all instances owned by the calling resource, never original world actors or another resource's objects.
pick op. Traces from the native player-controller view through the OS cursor, up to 1000 m. Requires usable game focus/viewport.
raycast x,y,z,tx,ty,tz, start and end in metres, length at most 1000 m.
lease Only op. Registers/renews ownership without creating a mesh; the host also renews ownership automatically.

Object IDs: 1-64 ASCII letters, digits, underscores or hyphens, scoped to the calling resource. Mesh must be a valid installed static-mesh object path like /Game/Directory/Asset.Asset, at most 512 characters, not an OBJ filename or filesystem path. The editor additionally restricts choices to its shipped catalog. A syntactically valid path can still fail to load.

Position: metres, each coordinate +/-100000. Rotation: pitch/yaw/roll in degrees, each +/-36000. Scale: sx/sy/sz in [0.01,100]. All numbers must be finite. The three booleans are required even when false. selected requests custom-depth selection presentation; it does not guarantee an outline without matching post-processing. Names and editor locks belong to the Lua document, not the native command schema.

Result contract

Successful mutations return JSON containing their id; clear/lease return an empty JSON object. Successful traces return {"hit":false} or a hit containing hit,x,y,z,nx,ny,nz,id. The coordinates are metres, normals unitless. A hit ID is populated only for a recognized object owned by the caller; it is empty for ordinary world surfaces or unrecognized/foreign instances. Do not access hit coordinates when hit=false. Traces depend on collision; use the editor hierarchy to select non-colliding objects.

Typical failure reasons include world-not-ready, native-dependencies-pending, mesh-load-or-spawn-failed, id-already-exists, owner-limit, object-invalid-or-transform-failed and raycast-unavailable. The former fixed-count object-limit failure is removed in BUILD124. An unanswered host request reports native-timeout after 10 seconds. A timeout does not prove a mutation was never applied: do not blindly retry it. Reconcile/reload the owned scene.

Example: complete create command

function requestMesh(meshPath, x, y, z)
    return WorldObjects.request({
        op="create", id="example_rock", mesh=meshPath,
        x=x, y=y, z=z, pitch=0, yaw=0, roll=0,
        sx=1, sy=1, sz=1,
        hidden=false, collision=true, selected=false
    })
end
-- Supply an actual installed mesh path and your desired coordinates.
-- Call after gameplay readiness; wait for onClientWorldObjectResult.
-- Reusing example_rock while it exists fails: assign unique IDs per instance.

Example: asynchronous deletion

local pending = {}
addEventHandler("onClientWorldObjectResult", resourceRoot,
    function(requestId, ok, reason, json)
        local id = pending[requestId]
        if not id then return end
        pending[requestId] = nil
        if ok then
            outputDebugString("Deleted owned object: " .. id)
        else
            outputDebugString("Delete not confirmed: " .. tostring(reason), 1)
        end
    end)

function deleteOwnedObject(id)
    local requestId = WorldObjects.request({op="delete", id=id})
    if not requestId then return false end
    pending[requestId] = id
    return true -- accepted only; completion is handled above
end

For full scene creation, use the supplied map_scene/client.lua loader and Map scene deployment. It includes startup readiness retries and reconstruction, which a one-shot on-start create call would miss.

Lifetime, limits and multiplayer

No fixed instance-count, pending-request-count or requests/second cap in this API since BUILD124 (0.1.4). The former 512 instances, 32 pending requests and 80 requests/second checks have been removed, not replaced with higher count caps. The editor and map_scene loader likewise no longer impose 500 objects.

Commands still encode to at most 4096 bytes and at most 16 owning resources are supported. Shared IPC transport queues remain bounded (256 frames per queue); a full queue can cause immediate request rejection even though the WorldObjects-specific pending-count ceiling is gone. Check false returns, pace submissions and await completion. Do not submit an entire huge scene in a tight loop: native mesh loading/creation runs on the game thread. The supplied loader continues to load sequentially. RAM/VRAM/CPU, asset complexity, Lua/resource memory and JSON document limits remain practical bounds, not a guarantee of unlimited performance.

The native ownership lease is 15 seconds and the host sends renewals every second. Stop/disconnect/world changes clear owned instances. Handle onClientWorldObjectsReset to discard stale IDs/pending state and reconstruct deliberately; the event has no arguments. Readiness, ownership, duplicate-ID checks, validation and timeout/cleanup safety have not been removed.

This API creates client-local static actors, not synchronized interactive doors, inventory items, server collision geometry or networked physics. Sending the same trusted static map resource to every player, as map_scene does, reconstructs the same layout for late joiners. Dynamic multiplayer edits require their own server-authorized state distribution.