Tags · Sure-Development/sure_lib · GitHub
Skip to content

Tags: Sure-Development/sure_lib

Tags

v2.12.2

Toggle v2.12.2's commit message
fix(spawn): drive streaming spawn/despawn from onEnter/onExit transit…

…ions

The nearby-based spawn loop introduced two real bugs:

  - spawnEntityInternal yields on awaitModel (CreateThread + Citizen.Await).
    The nearby tick keeps firing every 300ms while that coroutine is
    suspended; each tick sees entry.spawned still false and dispatched
    another CreatePed, so peds stacked every time the model finished
    loading.

  - The watchDistance widening pushed point.distance well past
    despawnRadius. ox_lib's onExit only fires when the point falls out
    of the watch window or the player crosses a grid cell, so peds
    routinely stayed in the world after the player left range.

Match grand_ped-manager's simpler shape and add an idempotency guard:

  - point.distance = despawnRadius or radius (single radius, no watch
    hysteresis).
  - onEnter -> spawn via a guarded helper that returns immediately if
    entry.spawned or entry.pending is true. The pending flag is set
    before spawnEntityInternal and cleared after it returns, so
    concurrent onEnter / nearby ticks during model loading no-op.
  - onExit -> despawn helper that no-ops when nothing is spawned.
  - spawnOnNear.onNear is wired through point.nearby only when
    provided, so the polling callback stays opt-in and never drives
    state transitions.

Bump version 2.12.1 -> 2.12.2.

v2.12.1

Toggle v2.12.1's commit message
fix(spawn): despawn from nearby tick instead of relying on onExit alone

ox_lib's points only fires onExit reliably when the player crosses a
grid cell boundary or when the point falls out of the grid query. A
player drifting in/out of despawn range inside the same cell could
leave the entity spawned indefinitely, and the user reported seeing
peds accumulate every time they walked back into range.

Widen the lib.points distance to max(despawnRadius * 1.5, radius * 2)
so the nearby tick keeps firing through the entire spawn-despawn
transition, then do the radius check ourselves on every tick:
  - currentDistance <= radius and not spawned -> spawn
  - currentDistance > despawnRadius and spawned -> despawn
onExit becomes the belt-and-suspenders for the case where the point
truly leaves the watch window or the entire grid query.

Bump version 2.12.0 -> 2.12.1.

v2.12.0

Toggle v2.12.0's commit message
feat(spawn): streamRadius / despawnRadius shortcut on spawn:ped|object

Move the streamRadius / despawnRadius option from slice:interact down
into sure.spawn so any caller (with or without slice) can opt into the
proximity streaming behavior without hand-rolling the spawnOnNear
table:

  spawn:object('prop_rock_3_g', vector3(x, y, z), {
    freeze = true,
    placeOnGround = true,
    streamRadius = 50,
    despawnRadius = 60,
    onNear = function(state) ... end,
  })

spawn now derives spawnOnNear.coords from the spawn coords argument so
the proximity check defaults to the entity's location. spawnOnNear is
still accepted directly for the advanced case where the proximity
point differs from the entity coords.

slice:interact stops building spawnOnNear itself and just forwards
streamRadius / despawnRadius / its own onNear into the spawn options;
sure.spawn handles the wiring. ctx.stream / ctx.entity behavior is
unchanged.

Bump version 2.11.0 -> 2.12.0.

v2.11.0

Toggle v2.11.0's commit message
feat(spawn,slice): streaming spawn radius for slice:interact

Wire sure.spawn's existing spawnOnNear proximity streaming through
slice:interact so entities are only created when the player gets
within range and torn down when they leave it. Targets the typical
farming/heist pattern where a single resource can hold hundreds of
world entities without keeping them all spawned at once.

- spawn module now attaches entry:dispose() to the table returned by
  registerStreamEntry so callers can tear down a single streaming
  entry without reaching into module-private helpers.

- slice:interact spawn block accepts streamRadius and despawnRadius:
    spawn = {
      type = 'object',
      streamRadius = 50,
      despawnRadius = 60,
      options = { freeze = true, placeOnGround = true },
    }
  When streamRadius is set the helper:
  - shallow-clones options, fills spawnOnNear from item coords +
    streamRadius/despawnRadius, and attaches an onNear that pushes
    the live spawn handle into ctx.entity.
  - records the stream entry on ctx.stream instead of treating the
    return value as a handle.
  - calls ctx.stream:dispose() on unmount, otherwise falls back to
    the existing safe DeleteEntity path.

LLS stubs gain ctx.stream plus streamRadius / despawnRadius on
SureSliceInteractSpawn so authors get autocomplete and warnings.

Bump version 2.10.3 -> 2.11.0.

v2.10.3

Toggle v2.10.3's commit message
fix(slice): widen interact action trigger to any truthy nearby result

IsControlJustReleased and other FiveM bool natives can return 1
instead of the literal true depending on the lua binding. The strict
`triggered == true` gate kept action silent because `1 == true` is
false in Lua. Switch to a truthy check so any truthy nearby result
fires action.

Bump version 2.10.2 -> 2.10.3.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

v2.10.2

Toggle v2.10.2's commit message
fix(slice): guard interact.spawn against non-vector3 coords / non-str…

…ing model

Type-check item[modelKey] and item[coordsFrom] before forwarding to
sure.spawn so a stale ox_lib cache.coords value (returns false until
ox_lib:cache:coords fires the first time) or a missing model field
errors at the slice boundary with a useful message instead of
exploding inside sure.spawn with "attempt to index a boolean value".

  [sure_lib][slice] interact(entities): item.coords must be a
  vector3 or table with x/y/z, got boolean (value: false)

Bump version 2.10.1 -> 2.10.2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

v2.10.1

Toggle v2.10.1's commit message
fix(slice): call slice.log via colon so message is not eaten

slice was calling slice.log.error/warn with dot syntax against a
logger whose methods are defined as colon methods (function
logger:error(message)). That made the formatted error string become
self and left message as nil, so every internal slice error printed
as `[farming] [error] nil` and ate the actual failure.

Switch every internal slice.log.error / slice.log.warn call to
slice.log:error / slice.log:warn so the formatted message reaches
the logger, matching log_test.lua's expectation and the SureLogger
LLS stub.

Bump version 2.10.0 -> 2.10.1. 165/165 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

v2.10.0

Toggle v2.10.0's commit message
feat(slice): split interact into nearby predicate + action effect

Interact now separates the gate from the work. nearby returns a
boolean - the predicate that decides whether the interaction is
ready to fire this frame. action is a new optional callback that
runs the same frame nearby returns true, receiving the same
(slice, item, ctx) triple.

  s:interact('entities', {
    spawn = { type = 'object' },
    nearby = function() return IsControlJustReleased(0, 38) end,
    action = function(s, item)
      -- play anim, wait, then s:unmount('entities', item.key)
    end,
  })

- nearby's old "do effects inline" pattern still works for users who
  ignore action - the library only invokes action when nearby returns
  true AND action is set.
- Defining action without nearby errors - action has no trigger
  without a predicate.
- Debounce is on the user; ctx is per-item so a ctx.busy flag is the
  natural place for "interaction in progress".

Bump version 2.9.1 -> 2.10.0. 165/165 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

v2.9.1

Toggle v2.9.1's commit message
fix(library): move transaction/scope back onto SureSliceInstance

The transaction and scope @field lines were trailing
SureSliceInteractSpec instead of SureSliceInstance, so LuaLS treated
them as required members of the interact spec. Any call to
s:interact(stateKey, {...}) reported "Missing required fields in
type SureSliceInteractSpec: transaction, scope".

Also switch every optional field on SureSliceSpec,
SureSliceNetSyncConfig, SureSliceInteractContext,
SureSliceInteractSpawn, and SureSliceInteractSpec from
`field type?` to `field? type` so LuaLS marks the field as optional
rather than only the type as nullable.

Bump version 2.9.0 -> 2.9.1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

v2.9.0

Toggle v2.9.0's commit message
feat(slice): interact helper that wires spawn + point + lifecycle

slice:interact(stateKey, spec) (client only) wraps slice:ref with
sure.spawn and lib.points.new so a feature can describe an entity +
interaction in one place instead of hand-wiring the four moving
parts (ref handler, sure.spawn call, lib.points.new, cleanup).

  s:interact('entities', {
    spawn = {
      type = 'object',
      modelFrom = 'model',
      coordsFrom = 'coords',
      options = { freeze = true, placeOnGround = true },
    },
    distanceFrom = 'range',
    onEnter = function(s, item, ctx) lib.showTextUI('press E') end,
    onExit = function(s, item, ctx) lib.hideTextUI() end,
    nearby = function(s, item, ctx)
      if IsControlJustReleased(0, 38) then return true end
    end,
  })

- spawn block resolves model/coords/heading by field name on the item
  and forwards options to sure.spawn:ped / sure.spawn:object.
- point is created from lib.points.new with coords from coordsFrom
  and distance from item[distanceFrom] (fallback 2.0).
- onEnter / onExit / nearby receive (slice, item, ctx). ctx.entity is
  the spawned handle, ctx.point is the lib.points instance.
- nearby's return value is intentionally not interpreted - users use
  return true as an internal signal and decide what to do themselves.
- cleanup on ref unmount removes the point first, then claims and
  deletes the entity.
- errors on server side and when neither spawn nor a handler is set.

Prompts and UI stay outside the helper so each resource can keep its
own text-UI / target / NUI stack.

Bump version 2.8.0 -> 2.9.0. 162/162 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>