mirror of
https://github.com/TemujinCalidius/SurvivorCore.git
synced 2026-08-14 00:58:01 +00:00
A Studio dock widget that lets the experience owner tune the survival stats through a validated form instead of hand-editing Attributes on the SurvivalStatsConfig instance — the first slice of the Builder/Admin plugin (#11). The point is compatibility: edits are LOCKED against engine updates. StatAdmin (the pure, headlessly-testable logic layer) writes deltas only — it sets an attribute solely when the owner changes a field from the live engine default, and removes it on reset / edit-back-to-default. So unset fields keep following the (improvable) engine defaults across a SurvivorCore release, while explicit overrides live on the owner's instance, which the engine only ever seeds and never overwrites. Nothing tuned is lost; nothing left alone is frozen. Hard guardrail: the plugin can read/write only the seven owner-tunable fields (STUDIO_ATTR_MAP). A write() assert makes it impossible to ever set the engine-owned semantics Invert / DangerHigh — re-freezing the affliction fill-direction bug is structurally unreachable. Runtime-verified in Studio: every write path exercised (including rejected Invert/DangerHigh attempts) left zero banned attributes on the instance. - plugin/StatAdmin.luau — logic: roster, effective values, deltas-only writes - plugin/StatAdminUi.luau — the dock-widget form (per-field reset, override dots) - plugin/init.server.luau — toolbar/widget wiring + ChangeHistory undo steps - plugin.project.json — separate Rojo tree; build with --plugin to install - CI: stylua + a plugin-sourcemap luau-lsp pass + a plugin build - docs/admin-plugin.md + cross-links; fix stale Invert row in the no-code table Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
78 lines
2.8 KiB
Luau
78 lines
2.8 KiB
Luau
--!nonstrict
|
|
--[[
|
|
SurvivorCore — Survival Stats admin plugin (main).
|
|
|
|
A toolbar button toggles a dock widget that edits the survival-stats `SurvivalStatsConfig`
|
|
instance through StatAdmin — the deltas-only, LOCKED model: it writes only fields the owner
|
|
changes from the engine default, removes them on reset, and can NEVER write the engine-owned
|
|
semantics (Invert / DangerHigh). Edits are wrapped in ChangeHistoryService recordings so each
|
|
is a single undo step. All real logic lives in StatAdmin (testable); the form in StatAdminUi.
|
|
|
|
First slice of the Builder / Admin plugin (issue #11).
|
|
]]
|
|
|
|
local ChangeHistoryService = game:GetService("ChangeHistoryService")
|
|
|
|
local StatAdmin = require(script.StatAdmin)
|
|
local StatAdminUi = require(script.StatAdminUi)
|
|
|
|
local toolbar = plugin:CreateToolbar("SurvivorCore")
|
|
local button = toolbar:CreateButton("Survival Stats", "Tune survival-stat rates, thresholds and HUD options", "")
|
|
button.ClickableWhenViewportHidden = true
|
|
|
|
-- CreateDockWidgetPluginGui is flagged deprecated by the tooling, but it is still the only
|
|
-- API for a dockable plugin widget (there is no replacement) — so allow it here.
|
|
-- selene: allow(deprecated)
|
|
local widget = plugin:CreateDockWidgetPluginGui(
|
|
"SurvivorCoreStatAdmin",
|
|
DockWidgetPluginGuiInfo.new(Enum.InitialDockState.Right, false, false, 320, 520, 280, 360)
|
|
)
|
|
widget.Title = "Survival Stats"
|
|
widget.Name = "SurvivorCoreStatAdmin"
|
|
|
|
local container = Instance.new("Frame")
|
|
container.Size = UDim2.fromScale(1, 1)
|
|
container.BackgroundColor3 = Color3.fromRGB(18, 21, 28)
|
|
container.BorderSizePixel = 0
|
|
container.Parent = widget
|
|
|
|
local ui: { refresh: () -> () }? = nil
|
|
|
|
-- Wrap a single StatAdmin mutation in one ChangeHistory recording (so it's one undo step),
|
|
-- then refresh the form so the override indicators reflect the new state.
|
|
local function record(name: string, mutate: () -> any): any
|
|
local recording = ChangeHistoryService:TryBeginRecording(name)
|
|
local result = mutate()
|
|
if recording then
|
|
ChangeHistoryService:FinishRecording(recording, Enum.FinishRecordingOperation.Commit)
|
|
end
|
|
if ui then
|
|
ui.refresh()
|
|
end
|
|
return result
|
|
end
|
|
|
|
local function applyEdit(statName: string, attr: string, raw: any, default: any): any
|
|
return record(`Survival Stats: {statName}.{attr}`, function()
|
|
return StatAdmin.setOverride(statName, attr, raw, default)
|
|
end)
|
|
end
|
|
|
|
local function applyReset(statName: string, attr: string): any
|
|
return record(`Survival Stats: reset {statName}.{attr}`, function()
|
|
return StatAdmin.resetOverride(statName, attr)
|
|
end)
|
|
end
|
|
|
|
ui = StatAdminUi.mount(container, StatAdmin, applyEdit, applyReset)
|
|
|
|
button.Click:Connect(function()
|
|
widget.Enabled = not widget.Enabled
|
|
if widget.Enabled and ui then
|
|
ui.refresh()
|
|
end
|
|
end)
|
|
widget:GetPropertyChangedSignal("Enabled"):Connect(function()
|
|
button:SetActive(widget.Enabled)
|
|
end)
|