Repository navigation
Code Style
Ink230 edited this page Sep 10, 2026
·
5 revisions
Irongoon uses a shallow, leaf-based dependency tree:
Severed Chains event bus
-> Irongoon event adapter
-> Randomizer strategy coordinator
-> focused service or randomizer leaf
-> parser, data, or configuration leaf
Parents select and invoke behavior. Leaves perform one bounded operation and do not route back through a parent or depend on unrelated sibling features.
-
Irongoonowns lifecycle and Severed Chains event adaptation -
Randomizerselects configured strategies and applies leaf results -
services.randomizerowns terminal randomization algorithms -
servicesowns stateful domain services such as Additions, Dragoon spells, and canonical data tables -
services.dataowns data-source selection and loading -
parse.externalowns file syntax parsing -
parse.gameowns table-to-game conversion -
parse.schemaowns table validation -
IrongoonConfigapplies the current campaign configuration snapshot; profiles and their persisted snapshots are owned by the configuration profile and campaign leaves -
dataowns closed option enums and serialized identifiers -
modelsowns domain and transport values
Put new behavior in the narrowest existing owner. Do not accumulate algorithms in Irongoon, parsing in Randomizer, or source-selection policy in parsers.
Stateful services, parsers, data sources, and randomizer leaves use eager process-wide singletons:
public final class ExampleService {
private static final ExampleService INSTANCE = new ExampleService();
public static ExampleService getInstance() {
return INSTANCE;
}
private ExampleService() {
}
}Obtain collaborators through Type.getInstance(). Do not add public constructors, dependency-injection infrastructure, service locators, or mutable test setters solely for convenience.
Use ordinary records, models, enums, and event values when process-wide identity is not required.
- Use package root
lod.irongoon - Keep one top-level production type per file
- Use four-space indentation and opening braces on declaration lines
- Allow brace-free single-line guards such as
if (characterId < 0) return; - Use braces for multiline conditionals and loops
- Use
finalfor parameters and locals that are not reassigned - Use
varwhen the initializer makes the concrete type obvious - Use
this.where it clarifies instance ownership - Use exhaustive switch expressions for closed configuration modes
- Keep stock or passthrough behavior explicit
- Use records for small immutable transports and enums for closed policies
- Implement
Data<T>when an enum exposes a serialized scalar - Preserve Severed Chains terminology at the integration boundary
- Campaign and fixed modes must derive reproducible values from
IrongoonConfig.seed - Add stable domain modifiers such as character, monster, shop, level, encounter, or submap IDs
- Keep shared bounded, distribution, and percentage calculations in
StatsRandomizer - Use unseeded randomness only for modes explicitly documented to reroll per battle, transformation, spawn, or use
- Treat changes to seed salts or modifier composition as compatibility changes for existing seeds
- Keep configuration state in
IrongoonConfig - Validate explicit bounds and closed policies during configuration loading
- Validate external tables at the source boundary with dataset, source, row, and field context
- Do not silently fall through to another source after an explicitly selected source fails validation
- Treat
DataTablesas the owner of canonical loaded tables and copy mutable collections across ownership boundaries - Clear and rebuild service caches during initialization so save reloads cannot retain stale state
- Throw
IllegalStateExceptionwhen initialized runtime data is missing, invalid, inconsistent, or used too early - Add domain context when translating lower-level failures
- Use
LogManager.getFormatterLogger(Type.class)and formatter-style placeholders - Do not use
System.out.println, swallowed exceptions, or context-free generic errors
- Prefer the smallest coherent change and avoid unrelated formatting cleanup
- Preserve bundled CSV compatibility data and patch assets unless the task requires changing them
- Use the Gradle wrapper for compilation and packaging
- Run
gradlew.bat compileJavafor production Java changes - Run
gradlew.bat assemblefor dependency, registry, resource, patch, or packaging changes - Treat builds as integration checks, not proof of combat, graphics, audio, save, or other runtime behavior
- Inspect
git diff, rungit diff --check, and preserve unrelated worktree changes before committing