Repository navigation
Creator surface: the reads, runtime items, use handlers, a judged bar, benches, eye rows - #89
Merged
Merged
Conversation
…, benches, eye rows What a separate resource could not do and every framework it comes from can: Server exports - GetPlayers(filter?), GetJobs(), GetGangs(): the roster and the configured groups - GetItem, GetItems, GetInventory, CanCarryItem: the catalogue and a whole bag - RegisterItem(name, def): an item added on both halves at runtime, validated by the one Catalog.Register both halves run, sent to late joiners on hello; never a weapon, never a taken name, capped per caller (SERVER.EXPORTS.ITEMS) - RegisterUsableItem / UnregisterUsableItem: the caller's export decides a use - OpenStash: configured or the caller's own namespace only, under the create cap - GetVehicle, GetOwnedVehicles, AddVehicle, HasKeys, GiveKeys - Notify; StartProgress / StopProgress: a bar the server starts and judges by its own clock (modules/progress/server/main.lua), rejected when finished early - RegisterCraftingBench / UnregisterCraftingBench, with a job-list gate - GetMetadata / SetMetadata take a citizen id: one row key under the ledger - everything a caller handed over goes when it stops Client exports - AddTarget / UpdateTarget / RemoveTarget / ClearTargets: eye rows owned by the caller, callbacks held to its own exports - ShowPrompt / UpdatePrompt / HidePrompt / HideAllPrompts - OpenPanel / UpdatePanel / AppendPanel / ClosePanel (opx:on:panel:action) - OpenCraftingBench; GetPlayerData, GetItemCount, HasItem, GetItem, IsDown, GetNeeds - a caller named like a module is refused the eye and the strip Public events - opx:on:inventory:items (what a bag gained and lost, by item name) - opx:on:character:created / deleted, opx:on:vehicles:registered / state, opx:on:crafting:ordered / collected, opx:on:progress:finished Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every client re-validates a runtime item with Catalog.Register inside the resume that received the `opx:net:inventory:catalog` event, and the platform kills a resume that spends more than ~10,000 instructions. Two things let a valid RegisterItem call overrun it, silently leaving the item on the server and missing on that client (and on every late joiner, whose hello resends the same parts): - `use.status` was unbounded, and is walked twice per item on the client; a part of items with a few hundred needs measured 82,000 instructions. It is now held to 8 needs, refused `bad_definition:use.status` past that. - eight items per event was too many even inside the bounds: eight items at every bound the validator allows measured 12,600. The server now sends four per event and the client refuses a longer part whole (it was 16). Tests measure a refused heavy part and a full part at the bounds with the exact callCost helper, and check a late joiner is sent every item in parts of at most four. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A stash's size is written into its row when it is created and read back from the row for ever after. The new OpenStash export admits a configured stash (config/inventory STASHES) for any writer, but OpenStash sized it from the caller's options or the 50-slot / 100 kg default -- so a creator opening `ncpd_lockers` before anybody walked to its marker created it at its own size and replaced the operator's for good. `withStash` (AddToStash) and the stash marker already use the configured size; OpenStash now does too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new cleanup on `onResourceStop` drops every use handler, crafting bench and server bar a caller registered, by name. Another resource's stop reaches this VM queued, on a later tick, and the devkit says outright that a stop/start can occur before then (server-api, "Resource lifecycle events": check GetResourceState). On `restart my_shop` the new instance can register its handlers and benches before the old instance's stop is drained here, and the late cleanup then wiped the new registrations: every use of its items refused, its benches gone, until the next restart. The server bus is also host-wide, so any resource could raise `onResourceStop` naming a running caller and wipe it the same way. The handler now leaves a caller GetResourceState reports running or starting; its own re-registrations replace the old ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Owner's ask: make sure the APIs give creators their full power, and add what is logically missing. This compares the creator surface with ESX / QBCore / ox_core / ox_inventory / ox_lib / ox_target and fills the gaps that can be filled safely.
Server exports (all behind the READ / WRITERS allowlists, writes audited
event=export.<Name>)GetPlayers(filter?),GetJobs(),GetGangs(): the roster and the configured groups (grades as a list)GetItem,GetItems,GetInventory(target),CanCarryItem(target, item, count?, meta?)RegisterItem(name, def): an item added on both halves at runtime. Validated by the oneCatalog.Registerboth halves run, sent to late joiners on hello, never a weapon, never a taken name, capped per caller (SERVER.EXPORTS.ITEMS.MAX_PER_CALLER), sent eight per event so the client takes them inside one resumeRegisterUsableItem(name, export)/UnregisterUsableItem: the caller's export decides a use ({ ok, consume? }), never taken from another ownerOpenStash(src, name, options?): configured stashes or the caller's own namespace only, under the create cap (rule also enforced in the contract)GetVehicle,GetOwnedVehicles,AddVehicle,HasKeys,GiveKeysNotify(src, msg, kind?, ms?)StartProgress(src, spec)/StopProgress(src, id?): a bar the server starts and judges by its own clock (modules/progress/server/main.lua): finished early isrejected+ security journal, no report isno_answer, leaving isleft; verdict onopx:on:progress:finishedRegisterCraftingBench(key, def)/UnregisterCraftingBench(key): stored as<caller>:<key>, gate as a job listGetMetadata/SetMetadatatake a citizen id: one row key (JSON_SET/JSON_REMOVEon a quoted path) under the offline ledger, bounds checked at the writeClient exports
AddTarget/UpdateTarget/RemoveTarget/ClearTargets: rows owned by the caller's resource name, callbacks held to its own exports, swept on stop/reload by the eyeShowPrompt/UpdatePrompt/HidePrompt/HideAllPromptsOpenPanel/UpdatePanel/AppendPanel/ClosePanel(opx:on:panel:action)OpenCraftingBench(key); readsGetPlayerData,GetItemCount,HasItem,GetItem,IsDown,GetNeedsexport.ownerTaken): it would share that module's rowsPublic events
opx:on:inventory:items(bag deltas by item name, from a per-bag tally),opx:on:character:created/deleted,opx:on:vehicles:registered/state(impound),opx:on:crafting:ordered/collected,opx:on:progress:finished.Skipped, and why
shopsis the clothing shop; gunsmith is a crafting consumer, covered by creator benchesLib.Callbackin opx_lib overOpen77.netChecks
OPX_LIB_PATH=../opx_lib lua tests/run.lua: 4546 checks, 0 failed (≈170 new: allowlist refusal, validation, audit, events firing, caller-stop cleanup, client budget for target rows and runtime-item parts)luac -pon every changed file, manifest paths ≤ 47,python tools/check-sandbox-globals.pyok; no UI changeorigin/mainDocs: opx77-framework/opx77_doc#10
🤖 Generated with Claude Code