138 Commits
Author SHA1 Message Date
Samuel Lison a0133473e3 Merge pull request #100 from TemujinCalidius/dev
release: v0.10.0 → main
v0.10.0
2026-08-01 19:31:14 +10:00
Samuel Lison cf28cec277 Merge pull request #99 from TemujinCalidius/release/v0.10.0
chore(release): v0.10.0
2026-08-01 19:30:26 +10:00
Samuel LisonandClaude Opus 4.8 3a0206e566 chore(release): v0.10.0
Promote CHANGELOG Unreleased → 0.10.0 (the schema-driven Build page for world
objects, #11) and bump wally.toml + SurvivorCore.VERSION.

Demo: new demo/server/Stage.luau — one switch for what the demo places in the
world (gather field + quest post, mobs, starting inventory, hand-test props).
The test-station prop rows now default OFF: they're scaffolding for working ON
the engine and crowded the spawn area for everyone else.

Collateral: the Build demo video on the docs Demos line and as an 8th site
video tile; the landing page's Studio card now tells the Build story; version
surfaces bumped across site, README and getting-started.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-01 19:29:49 +10:00
Samuel Lison f1825c3512 Merge pull request #98 from TemujinCalidius/fix/build-firstrun-hint
fix(builder): point first-time creators at Content when a picker is empty
2026-07-30 18:13:12 +10:00
Samuel LisonandClaude Opus 4.8 d15b47e7d8 fix(builder): point first-time creators at Content when a picker is empty
Found in real use: with no gatherables authored yet, the Build form's Resource
field has no ⌄ picker (there's nothing to cycle) and nothing explains where
entries come from — so the very first no-code run dead-ends at the moment the
flow should feel best.

A field that references authored content now shows "No Gatherables yet —
create one →" when that category is empty, which jumps straight to the right
Content page. Not a mutation, so it isn't wrapped in a ChangeHistory recording.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 18:12:28 +10:00
Samuel Lison e640fd6a79 Merge pull request #97 from TemujinCalidius/fix/build-page-review
fix(builder): chooser cards were unclickable and misrouted picks
2026-07-30 17:59:50 +10:00
Samuel Lison f7a751264a chore: re-trigger CI 2026-07-30 17:57:25 +10:00
Samuel LisonandClaude Opus 4.8 bbfefbec38 fix(builder): chooser cards were unclickable and misrouted picks
Found by an adversarial review of the Build page before it was ever run — all
three reviewers independently flagged the first one.

1. The "what is this object?" cards were dead. chooserCard parented a
   Size=fromScale(1,1) TextButton into Theme.panel() intending an overlay, but
   Theme.panel() contains a UIListLayout, which lays out EVERY GuiObject child —
   there is no opt-out, and ZIndex does not affect layout. So the button became
   another list row: clicking a card's title/summary did nothing, and the
   oversized button spilled past the card and took the click for the card BELOW,
   applying the WRONG component (which also strips the previous component's
   attributes). This was the page's primary interaction.
   Fixed with Theme.panelButton() — the card itself is the button, matching the
   pattern OverviewPage already uses.

2. Clear did nothing on an object whose only tag was unknown to this engine,
   yet reported success. The page renders exactly that branch with a Clear
   button. BuildAdmin.clear now takes the tags to remove explicitly, and the page
   passes the unknown tags it just displayed — never removing an unlisted tag
   speculatively, since it may belong to another plugin. It also reports
   "nothing to clear" instead of a false success.

3. FieldRow's help text set Position inside a UIListLayout parent, so its indent
   was silently dropped and every help line rendered flush left. Uses padding now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 17:54:21 +10:00
Samuel Lison 4b6eada1ca Merge pull request #96 from TemujinCalidius/feat/build-page
feat(builder): schema-driven Build page for world objects (#11)
2026-07-30 17:15:52 +10:00
Samuel LisonandClaude Opus 4.8 29bd20a93f feat(builder): schema-driven Build page for world objects (#11)
Select a Part or Model in Studio, answer "what is this object?", fill a form —
it becomes a gatherable node, a mob or a quest giver. Closes the gap between
authoring a def and setting up a world object, which until now meant knowing to
tag a part and hand-typing PascalCase attributes in the property panel.

Engine — components can declare an attribute SCHEMA:
- src/components/Schema.luau (new): AttributeSpec/Display/ComponentSchema types,
  normalize/defaults/get/list, and the schemas for Gatherable, Mob, QuestGiver.
  Dependency-free ON PURPOSE: the plugin requires it live at edit time, and the
  component modules themselves can't be required there (Harvesting asserts
  IsServer; Remotes creates instances in ReplicatedStorage).
- Components.define now accepts EITHER the legacy `attr = default` map or a
  schema array, normalizing both to one ordered spec list; bind() reads the
  derived default map, so binding is byte-identical. Legacy maps are sorted, as
  `pairs` order is arbitrary and would make a UI jitter. New getSchema/
  listSchemas. The three shipped components pull name/tag/display/attributes
  from the schema; their onSetup bodies are untouched (defaults verified
  identical, all 23 attributes).

Plugin — the Build page:
- Field.luau (new): coerce/format/equalsDefault, lifted from ConfigAdmin (which
  now delegates), shared by every schema-driven editor.
- FieldRow.luau (new): the shared [○/●] label … control + help row, including a
  ⌄ picker that cycles authored ids for fields declaring `ref`.
- BuildAdmin.luau (new): live schema read with three distinct empty states,
  selection/eligibility/identify, deltas-only attribute writes, applyType
  (tag + clear any other component) and clear.
- BuildAdminUi.luau (new): chooser cards, grouped form, multi-select apply,
  stale-bind-marker warning, SelectionChanged-driven refresh.
- init.server.luau: record()-wrapped buildActions + the page.

Docs: docs/admin-plugin.md Build section + a 60-second walkthrough,
docs/extending.md schema guide, a CONTRIBUTING rule that new creator components
declare one, CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 17:14:52 +10:00
Samuel Lison a4ee3cabc5 Merge pull request #94 from TemujinCalidius/dev
release: v0.9.0 → main
v0.9.0
2026-07-30 17:02:33 +10:00
Samuel Lison 7346c5ccf4 Merge pull request #93 from TemujinCalidius/release/v0.9.0
chore(release): v0.9.0
2026-07-30 17:01:36 +10:00
Samuel LisonandClaude Opus 4.8 f4fad6fc83 chore(release): v0.9.0
Promote CHANGELOG Unreleased → 0.9.0 (player trading #15, the player interact
window, and the bow rate-limit security fix). Bump wally.toml +
SurvivorCore.VERSION to 0.9.0.

Collateral: player-trading demo video as a 7th site video tile and a Demo line
in docs/trading.md + docs/interact.md; a full-width "Player trading" feature
card on the landing page; trading.md + interact.md added to the README doc
index; version surfaces bumped across site, README and getting-started.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 17:00:36 +10:00
Samuel Lison 0ab3e7d062 Merge pull request #92 from TemujinCalidius/fix/bow-rate-limit
fix(combat): rate-limit bow shots + validate bow inputs
2026-07-30 16:57:53 +10:00
Samuel LisonandClaude Opus 4.8 7a5aaac0df fix(combat): rate-limit bow shots + validate bow inputs
The bow release handler enforced no cooldown — the only client-driven action
in the engine without one (melee, harvesting and item use all rate-limit). Each
release also costs up to MaxRange/StepSize server raycasts to simulate the arc,
so the gate now runs BEFORE the arrow is spent and before the simulation.

- Combat.Bow.Cooldown (0.35s) added to CombatConfig + the EngineConfig schema,
  so it's tunable no-code in SurvivorCore Studio.
- onBowRelease honours def.weaponCooldown first, falling back to Bow.Cooldown.
  weaponCooldown was previously read only by the melee path, even though the
  authoring form offers it for every weapon — a bow cooldown was silently
  ignored. Its plugin label is now "Cooldown (s)" noting it covers both.
- A release with no matching draw is rejected (a real client fires BowDraw on
  press, BowRelease on release).
- BowDraw validates the sender is alive and holding a bow; it previously
  accepted anything from anyone.
- Aim points are checked for finiteness: a non-finite Vector3 defeats magnitude
  comparisons and would reach the raycast after the arrow was already spent.
- lastShot is cleared in PlayerRemoving alongside lastSwing/drawStart.

Affects v0.8.0 and earlier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 16:56:54 +10:00
Samuel Lison 5e42556e5f Merge pull request #91 from TemujinCalidius/fix/trade-window-ux
fix: self-contained + draggable trade window
2026-07-30 15:04:20 +10:00
Samuel LisonandClaude Opus 4.8 96bafb8345 fix(trade): self-contained + draggable trade window
Two UX bugs found while recording:

1. The trade window relied on the SEPARATE inventory menu for staging, and
   clicking the menu's backdrop closed it with no obvious way to reopen —
   leaving the trade unusable. The window now lists your carried stacks
   INSIDE it (read from the replicated inventory attributes): click a row to
   offer one, "All" for the whole stack. Dragging from the inventory grid
   still works when that menu happens to be open. Removed the auto-open of
   the inventory panel that created the trap.

2. The window couldn't be moved. Its header is now a drag handle (mouse +
   touch), so it can be pulled out of the way.

Also: the in-window backpack live-refreshes on inventory attribute changes
(coalesced per frame) so a mid-trade pickup can't leave it stale. Panel grown
to 420x476 for the added section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 15:03:24 +10:00
Samuel Lison 2f1fbf287c Merge pull request #90 from TemujinCalidius/feat/player-interact-window
feat: walk-up player interact window + self-prompt fix (#15)
2026-07-16 20:57:04 +10:00
Samuel LisonandClaude Opus 4.8 10891b1fcd feat(interact): walk-up player interact window; fix self-prompt (#15)
Replaces the buggy per-character Trade ProximityPrompt — which rendered over
your OWN head (no per-viewer exclusion) — with a TCE-ported interact window.

Walk up to another player → an "[E] Interact" badge floats over THEIR head →
press E / tap → a window shows their name + survival stats and an action list.
Targeting is a client-side nearest-OTHER-player scan (self skipped in the loop,
with hysteresis to stop flicker), so the affordance can never point at you —
the reported bug is fixed by construction.

Extensible: SurvivorCore.Interact.addAction{ id, label, order?, enabled?,
onActivate } — Trade is registered as the first built-in action and just fires
the existing (server-validated) TradeRequest remote, so the invite/Accept flow
is unchanged. Cursor is freed while the window is open; the window auto-closes
on walk-away / target-leaves / death / trade-start.

- src/client/PlayerInteract.luau (new): scan + billboard + window + action registry
- src/systems/Trade.luau: delete the per-character prompt block (keep Died abort)
- src/init.luau: boot PlayerInteract, expose SurvivorCore.Interact
- src/shared/UiConfig.luau: UI.Keybinds.Interact = "E"
- docs/interact.md (new), docs/trading.md, CHANGELOG (Unreleased)

Ported from The Counter Earth's PlayerInspectService/InspectController.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:56:10 +10:00
Samuel Lison f93504ec1a Merge pull request #89 from TemujinCalidius/feat/player-trading
feat: player trading (#15)
2026-07-16 20:20:25 +10:00
Samuel LisonandClaude Opus 4.8 177a4118fe feat(trade): secure player-to-player trading (#15)
A new server-authoritative, dupe-proof trade system. Walk up to another player,
trigger the "Trade" prompt; they Accept/Decline; both stage loose backpack
stacks (drag from the inventory grid, with −/+ qty steppers) and must Confirm
before anything moves.

Anti-dupe by construction: staging is by-reference (items never leave the owner
until commit), and the commit is one synchronous, no-yield critical section —
re-validate holds → pre-flight both receivers have room (new Inventory.canAccept)
→ remove both → grant with addUpTo → refund any residue. Item count is conserved
on every branch (verified: 200k-iteration conservation + fit-oracle fuzz).

Auto-cancels on death / leave / out-of-range (MaxDistance) / request timeout; a
staging change resets both confirms. New Trade server system + TradeUi client
window, the "Trading" Config section (tunable in SurvivorCore Studio), hooks
trade:started / trade:completed, and a trades_total progression counter. v1 is
backpack stacks only (worn gear reserved behind AllowEquippedItems).

- src/systems/Trade.luau, src/client/TradeUi.luau, src/shared/TradingConfig.luau (new)
- src/systems/Inventory.luau: exported canAccept (weight+slot fit oracle)
- src/shared/EngineConfig.luau: Trading section; src/init.luau boot wiring
- docs/trading.md, README, CHANGELOG (Unreleased), Hooks catalogue, extending.md
- demo/server/TradeTestStation.server.luau: /tradetest 2-player conservation harness

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:19:06 +10:00
Samuel Lison 7f1331c4a6 Merge pull request #87 from TemujinCalidius/dev
release: v0.8.0 → main
v0.8.0
2026-07-16 19:57:54 +10:00
Samuel Lison 91bc1bb756 Merge pull request #86 from TemujinCalidius/release/v0.8.0
chore(release): v0.8.0
2026-07-16 19:56:48 +10:00
Samuel LisonandClaude Opus 4.8 b15005c09a chore(release): v0.8.0
Promote CHANGELOG Unreleased → 0.8.0 (SurvivorCore Studio, Engine Config #21,
content overrides #40). Bump wally.toml + SurvivorCore.VERSION to 0.8.0.

Collateral: admin-panel demo video tile on the landing site + docs/admin-plugin
Demos line; refresh the admin feature card + value-prop to name SurvivorCore
Studio / Engine Config / content overrides; bump version surfaces across
site, README and getting-started.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 19:55:56 +10:00
Samuel Lison 5dd316afad Merge pull request #85 from TemujinCalidius/feat/admin-studio
feat: SurvivorCore Studio — Engine Config editor, content overrides, window/sidebar rework
2026-07-07 12:41:01 +10:00
Samuel LisonandClaude Opus 4.8 3349738779 fix: address adversarial-review findings across engine + plugin
Engine: quest overrides with objective*/reward* fields on nested code quests
now WARN at boot (they merge nothing — QuestData prefers nested tables);
EngineConfig + ConfigAdmin reject non-finite numbers (inf/nan).

Plugin: Config group panels auto-size (fixed-height math clipped the last row
of big groups — Theme group lost its Bold font row); Stats panels get the gap
math right; the Engine Config explainer page now REBUILDS the window when the
engine appears (the old hint was impossible — pages were assembled once at
plugin load); create() refuses ids that already have an override (mirror
guard); failed Create/Override reasons render under the create row; rejected
config edits report in the footer; explicit navigation cancels a pending
debounced search jump; the mount-time page restore no longer clobbers the
saved last-page setting during an engine-less session; undo/redo refresh
skips while typing in one of the plugin's own text boxes; search results past
the 50-cap no longer render empty category headers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:39:56 +10:00
Samuel LisonandClaude Opus 4.8 40bf167318 docs: SurvivorCore Studio + Engine Config + overrides docs, CHANGELOG Unreleased
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:16:11 +10:00
Samuel LisonandClaude Opus 4.8 91c7a87f89 feat(plugin): SurvivorCore Studio — floating window, sidebar nav, search, Engine Config editor, roster overrides (#11, #21, #40)
New shell: Theme (shared visual system), Nav (rail + lazy router + badges),
OverviewPage, SearchPage (global editable results), SpawnHelpers; init.server
restructured around data-driven pages with last-page persistence and
undo/redo-aware refresh. Widget: floating 660×580 (min 480×380), new ID
SurvivorCoreStudio. ConfigAdmin/-Ui: deltas-only editor pages for all 11
engine Config sections incl. Theme colors (R,G,B + swatch) and fonts.
ContentAdmin/-Ui: per-category pages over the merged roster; + Override
entries (blank = inherit) tuning code-registered defs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:07:48 +10:00
Samuel LisonandClaude Opus 4.8 c661832485 feat(engine): SurvivorCoreEngineConfig no-code tuning layer + Registry.applyOverrides (#21, #40)
EngineConfig: schema for all 11 Config sections (~94 typed fields incl. color3/font),
deltas-only persisted instance applied at start()/startClient() before systems boot.
Registry.applyOverrides + SurvivorCoreContent/Overrides loading: field-merge deltas onto
already-registered (incl. code-registered) defs, pre-scan/pre-publish.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 11:57:59 +10:00
Samuel Lison 5cd6b263d1 Merge pull request #84 from TemujinCalidius/main
sync: v0.7.0 video docs → dev
2026-07-07 11:53:46 +10:00
Samuel Lison e4486426ca Merge pull request #83 from TemujinCalidius/docs/v0.7.0-video
docs: v0.7.0 hunting/loot-bags demo video
2026-07-07 11:53:04 +10:00
Samuel LisonandClaude Opus 4.8 8bd929a1d4 docs: add v0.7.0 hunting/loot-bags demo video + site video grid tile
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 11:52:19 +10:00
Samuel Lison 8ddb7f8a24 Merge pull request #81 from TemujinCalidius/main
sync: v0.7.4 → dev
2026-07-06 15:41:40 +10:00
Samuel Lison 7877e88f3a Merge pull request #80 from TemujinCalidius/dev
release: v0.7.4 → main
v0.7.4
2026-07-06 15:40:56 +10:00
Samuel Lison ea9baf62e8 Merge pull request #79 from TemujinCalidius/release/v0.7.4
chore(release): v0.7.4
2026-07-06 15:40:05 +10:00
Samuel LisonandClaude Opus 4.8 51426d6e3a chore(release): v0.7.4
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 15:39:19 +10:00
Samuel Lison f5d8cdf968 Merge pull request #78 from TemujinCalidius/fix/beacon-latest-bag
fix: beacon follows the owner's newest bag
2026-07-06 15:39:15 +10:00
Samuel LisonandClaude Opus 4.8 44c0f8e25c fix: beacon follows the owner's newest bag; older bags never clear it
Dying again mid corpse-run drops a second bag (old + new coexist in the world,
each on its own 5-minute timer) and re-points the owner's beacon at the new
one. Previously the OLDER bag's later despawn/looting fired the unscoped
beacon-clear and wiped the beam pointing at the newer bag. LootBags now tracks
each owner's latest bag and only its destruction clears the beacon.

docs/loot-bags.md: documented the multi-bag + beacon-follows-newest behavior.

Live-verified: two coexisting bags, beacon on the newest; looting the OLD bag
left the beacon untouched; looting the NEW bag cleared it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 15:38:26 +10:00
Samuel Lison f6a26ddd30 Merge pull request #76 from TemujinCalidius/main
sync: v0.7.3 → dev
2026-07-06 15:34:14 +10:00
Samuel Lison aafa144a03 Merge pull request #75 from TemujinCalidius/dev
release: v0.7.3 → main
v0.7.3
2026-07-06 15:33:32 +10:00
Samuel Lison f6edd14214 Merge pull request #74 from TemujinCalidius/release/v0.7.3
chore(release): v0.7.3
2026-07-06 15:32:41 +10:00
Samuel LisonandClaude Opus 4.8 9ccd667e5b chore(release): v0.7.3
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 15:31:54 +10:00
Samuel Lison 771534a544 Merge pull request #73 from TemujinCalidius/fix/lootbag-streaming
fix: loot bag + beacon vanished on respawn (StreamingEnabled)
2026-07-06 15:31:50 +10:00
Samuel LisonandClaude Opus 4.8 ee77ca9816 fix: loot bag + beacon vanished on respawn under StreamingEnabled
Root cause: with StreamingEnabled (the new-place default), respawning away
from the death spot let Roblox evict the bag from the owner's client — the
bag looked deleted, and the local Destroying event fired, permanently killing
the beacon (server bag was fine all along).

- The bag is now a Model set PersistentPerPlayer for its owner
  (AddPersistentPlayer) — it never streams out of the owner's view.
- The beacon is position-driven plain data: no Instance in the remote, so no
  replication race (the 0.5s delay hack is gone) and no streaming fragility.
- The beam clears on an explicit server nil-fire when the bag is truly
  emptied/expired (plus a lifetime fallback), not on replica Destroying.

Live-verified (fresh bytecode confirmed via bag ClassName): beacon appears
instantly, survives respawn, bag stays visible to the owner, loot restores
everything, beam clears on empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 15:31:01 +10:00
Samuel Lison 1b3eea714a Merge pull request #71 from TemujinCalidius/main
sync: v0.7.2 → dev
2026-07-06 14:59:12 +10:00
Samuel Lison e6ae4f4800 Merge pull request #70 from TemujinCalidius/dev
release: v0.7.2 → main
v0.7.2
2026-07-06 14:58:29 +10:00
Samuel Lison 1e2c6a43ac Merge pull request #69 from TemujinCalidius/release/v0.7.2
chore(release): v0.7.2
2026-07-06 14:57:36 +10:00
Samuel LisonandClaude Opus 4.8 52d9aea26b chore(release): v0.7.2
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 14:56:50 +10:00
Samuel Lison 23e07ef6fb Merge pull request #68 from TemujinCalidius/fix/lootbag-beacon-dead-loot
fix: loot-bag owner beacon race + looting while dead
2026-07-06 14:56:47 +10:00
Samuel LisonandClaude Opus 4.8 78f99a0667 fix: loot-bag owner beacon race + looting while dead
- Beacon: LootBagDropped fired the same frame the bag was created, so the
  Instance reference arrived as nil on the client (not yet replicated) and the
  owner beacon silently never appeared. The fire is now delayed 0.5s.
- Dead looting: collect() never verified the collector was alive, so a corpse
  lying next to its own bag could scoop everything back before respawning.
  The server now rejects dead collectors (isAlive gate, Harvesting pattern).

Live verification note: the running Studio session executed stale bytecode
(old collect granted loot to a dead player even though the new source was
synced) — verified source-in-place; behavior verification needs a Studio
restart, which CI/release artifacts are unaffected by.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 14:55:55 +10:00