Skip to content

Architecture

ESTONlA edited this page Sep 8, 2026 · 2 revisions

Architecture

Version 0.3.0 keeps the plugin bootstrap separate from runtime, game bridges, APIs and native UI. These are separate classes with clear ownership, not partial files for one large plugin class.

Area Responsibility
src/HowToLuaPlugin.cs BepInEx startup, Harmony installation, Update orchestration and teardown.
src/Runtime/LuaHost.cs Mod discovery/dependency loading, registrations, timer scheduling and event delivery.
src/Runtime/LuaMod.cs One mod's script state, persistent configuration and error isolation.
src/Runtime/LuaManifest.cs, LuaRegistrations.cs Manifest and callback/timer/action records.
src/LuaExecution.cs Restricted MoonSharp globals, instruction budget, manifest ID and entry-path validation.
src/Runtime/GameEventQueue.cs Bounded FIFO queue and deferred callback-generated events.
src/Runtime/LuaValues.cs Convert approved CLR primitives/records into independent Lua snapshots.
src/Runtime/ObservedRoutine.cs Preserve native coroutine yields and observe natural completion.
src/Runtime/WindowBudget.cs Shared spawn/save/travel rate windows; LuaHost retains the live spawned-item set across reloads.
src/Api/CoreApi.cs Existing commands, timers, buttons, chat, money and string-data bindings.
src/Api/GameApi.cs, PlayerApi.cs, WorldApi.cs, LuaArguments.cs Namespaced gameplay bindings and validated host actions.
src/Api/ItemApi.cs, CatalogApi.cs, InventoryApi.cs, CombatApi.cs Item definitions/instances, bounded spawning, inventories and equipment.
src/Api/BoatApi.cs, ServerApi.cs, ProgressionApi.cs, NpcApi.cs, BossApi.cs Boat, session rules, economy, island, quest and boss bindings.
src/Game/GameHooks.cs Host lifecycle, player roster, original catch/death/command hooks, guarded snapshot capture.
src/Game/PlayerHooks.cs, ItemHooks.cs, WorldHooks.cs Domain-specific Harmony patches.
src/Game/InventoryHooks.cs, BoatHooks.cs, EquipmentHooks.cs, ProgressionHooks.cs Additional server-branch notifications.
src/Game/GameAccess.cs, ItemSnapshots.cs Validated lookups, protection checks and detailed item/catalog records.
src/Game/GameSnapshots.cs, GameEventCatalog.cs Stable event records and allowed event names.
src/UI/LuaMenu.cs Existing game-styled Pause > Lua Mods panel and native buttons.

Adding a Hook

  1. Inspect the actual installed game method and its callers. A method/event name alone is not a contract; vanilla MoneyManager.OnItemSold also fires for unrelated balance changes.
  2. Add a narrow patch to the appropriate domain file. Use the server branch of synchronized-value callbacks to avoid duplicate host/client delivery.
  3. Capture only safe primitive records, inside GameHooks.Capture or Snapshot. Never put a Unity object in the event queue.
  4. Add the event to GameEventCatalog, document its exact arguments in Events, and provide an example where useful.
  5. Extend tests. HookContractTests reads the built plugin and installed game with Mono.Cecil, validates every Harmony target and injected parameter, and checks the expected patch-class count. Update that count when adding/removing a patch.

For pre-operation snapshots (such as item sales or boss removal), capture data in Prefix and publish it from Postfix. Notification hooks do not give Lua permission to suppress native code. If adding a cancellable policy API later, design that separately with explicit authority and timing rules.

Adding an API

Keep bindings in Api, use LuaArguments for validation, guard host-side actions, and return plain tables through LuaValues. Do not register raw Unity types as MoonSharp userdata. Read-only snapshots avoid destroyed-object handles and cross-mod table mutation. Document nil/false readiness results separately from argument errors.

Mark gameplay API/bridge classes with [LuaBridge]. The method coverage generator scans those classes and their nested callbacks for direct calls into Assembly-CSharp and scans Harmony targets separately. It does not count menu code, transitive native calls or raw fields. Generate the report with dotnet run --project tests/SmokeTests.csproj -c Release -- --coverage after changing bindings; packaging also does this. Review the inventory, not just its percentage.

New namespaces must be registered in GameApi.Register; extensions to players, world and economy run after the original tables are created. ApiContractTests checks 79 compiled callback registrations, module wiring and the four private fields used for native collection bounds/registries. Add contract and example tests when extending this surface. These checks do not execute Unity gameplay.

Build and Verify

dotnet build HowToLua.csproj -c Release
dotnet run --project tests/SmokeTests.csproj -c Release
./Build-Package.ps1

The smoke project links the actual pure runtime helpers. Its 405 checks cover sandbox limits, three examples with mocked APIs, snapshots, numeric/Steam/network ID validation, rate windows, queue overflow/deferral/reset, coroutine completion/cancellation, all 39 installed-game patch targets, field contracts, API wiring and documented functions/events. It does not emulate a running FishNet session or verify RPC delivery/UI behavior.

Keep MoonSharp.Reference.props: the classic net40-client binary avoids the missing System.Collections 4.0.10.0 error. Packaging also executes the staged interpreter in fresh Windows PowerShell under .NET Framework. Project references and contract-test paths currently target the local Steam installation; change them together when building elsewhere.

Update README and affected Wiki pages with API changes. The Wiki is its own Git repository. Publishing it does not publish the main source repository or create a GitHub release.

Clone this wiki locally