diff --git a/.AGENTS/BUILD_SYSTEM.md b/.AGENTS/BUILD_SYSTEM.md new file mode 100644 index 000000000..466be3ad8 --- /dev/null +++ b/.AGENTS/BUILD_SYSTEM.md @@ -0,0 +1,82 @@ +# BUILD_SYSTEM.md — Gradle Build Architecture + +## Module Graph + +``` +Dependency flow: platform-api ←(api)── core ←(impl)── root (mc1710) + gradle-plugins/ → composite build (dts.typescript-generator) +``` + +- **platform-api**: Zero deps. Interfaces (`PlatformService`, `INBTCompound`). Java 8. +- **core**: Depends on platform-api (transitive). MC-free game logic. Java 8. +- **root**: Depends on core. Full MC 1.7.10/Forge via GTNH convention plugin. +- **gradle-plugins**: Isolated composite build for `dts.typescript-generator` plugin. + +## Build Flow + +``` +updateAPI (submodule init) → decompileMc (RetroFuturaGradle) → compileJava + → generateTypeScriptDefinitions → processResources (bundles .d.ts) + → shadowJar (Mixin + JaninoLoader unless -Pnomixin) → build +``` + +## Config Files + +| File | Purpose | +|---|---| +| `build.gradle` | Plugins, version, custom tasks, TS gen config, javadoc | +| `settings.gradle` | Module includes, composite build, GTNH convention | +| `gradle.properties` | MC/Forge version, modId, mixin/shadow/spotless flags | +| `dependencies.gradle` | Runtime deps, shadow deps, core module reference | +| `repositories.gradle` | Sponge maven (Mixin), flatDir `lib/` | + +## Custom Tasks (group: `CustomNPC+`) + +| Task | Purpose | +|---|---| +| `updateAPI` | `git submodule update --init --recursive` — required first time | +| `buildNoMixin` | `build -Pnomixin` — jar without embedded Mixin | +| `runClientNoNashorn` / `runServerNoNashorn` | Launch without Nashorn scripting engine | +| `generateTypeScriptDefinitions` | Java API → `.d.ts` (see gradle-plugins/AGENTS.md) | + +## TypeScript Generation Config + +``` +sourceDirectories: src/api/java, src/main/java +outputDirectory: src/main/resources/assets/customnpcs/api +apiPackages: noppes.npcs.api, net.minecraft +implementationPackages: noppes.npcs.scripted, noppes.npcs.controllers.data, + noppes.npcs.entity.data, noppes.npcs.quests, kamkeel.npcs.controllers.data +patchesDirectory: dts-patches/ +``` + +## Dependencies (dependencies.gradle) + +| Configuration | Used For | +|---|---| +| `implementation project(':core')` | Core game logic (transitively includes platform-api) | +| `shadowImplementation` | Embedded: Mixin (unless `-Pnomixin`), JaninoLoader | +| `runtimeOnlyNonPublishable` | Dev-only: NEI, Nashorn (unless `-PnoNashorn`) | + +## Key gradle.properties + +| Property | Value | Effect | +|---|---|---| +| `modId` | `customnpcs` | Mixin JSON, resource paths, TS output | +| `usesMixins` | `true` | Mixin AP + embed. Plugin: `mixin.CustomNPCsMixinPlugin` | +| `usesShadowedDependencies` | `true` | Enables `shadowImplementation` | +| `minimizeShadowedDependencies` | `false` | Keep all shadowed classes (reflection) | +| `disableSpotless` | `true` | No auto-formatting | +| `enableModernJavaSyntax` | `false` | Strict Java 8 (no Jabel) | +| `accessTransformersFile` | `customnpcs_at.cfg` | Forge access transformer | + +## Quick Reference + +```bash +./gradlew updateAPI # Init API submodule (first time) +./gradlew build # Full build with mixin embedding +./gradlew buildNoMixin # Without embedded Mixin +./gradlew runClient / runServer # Launch game +./gradlew generateTypeScriptDefinitions # Regen .d.ts only +./gradlew genIntellijRuns # IDE setup (add Mixin tweaker args) +``` diff --git a/.AGENTS/CORE_ABSTRACTION.md b/.AGENTS/CORE_ABSTRACTION.md new file mode 100644 index 000000000..541c340a3 --- /dev/null +++ b/.AGENTS/CORE_ABSTRACTION.md @@ -0,0 +1,56 @@ +# Core Abstraction Reference + +Quick-reference for platform abstraction architecture and migration status. +For full details: `CORE_PLAN.md` (architecture), `CORE_MIGRATION_STATUS.md` (per-file blockers). + +## Module Layout + +``` +platform-api/ → Interfaces only (43 files). No MC imports. + ^ + core/ → Game logic (140 files). Imports platform-api only. + ^ +src/main/java/ → MC 1.7.10 implementations, wrappers, GUI, packets (~1,627 files) +``` + +## Migration Status: 183 / ~1,810 files abstracted + +### Fully Abstracted (in core/) +- **Controllers**: GlobalData, ServerTagMap, Transport, Faction, Magic, Tag, CategoryManager, APIRegistry +- **Data clusters**: Transport, Faction, Magic/MagicCycle/MagicEntry, Tag/TagMap, Frame/FramePart +- **Player data fragments**: PlayerDialogData, PlayerTransportData, PlayerEffect, AbilityHotbarData +- **Display data**: DialogImage, DialogColorData, Lines/Line, SkinOverlay, HitboxData, TintData +- **Infrastructure**: NBTTags, NBT factory, CustomNPCsThreader, network enums, developer registry +- **Constants**: 40+ enums (EnumRoleType, EnumQuestType, EnumAnimation, etc.) +- **Utilities**: ValueUtil, LRUHashMap, CacheHashMap, TextSplitter, FileNameHelper + +### Tier 1 — Blocked by IStack/Inventory Abstraction +Bank, BankController, AuctionClaim, AuctionListing, AuctionBlacklist, LinkedItem, RecipeAnvil, PlayerItemGiverData + +### Tier 2 — Blocked by IUser (EntityPlayer) Abstraction +Availability, FactionOptions, Dialog/DialogOption/DialogCategory, Quest/QuestCategory/QuestData, +CustomEffect, Party, PlayerData, PlayerFactionData, all remaining Player*Data classes + +### Tier 3 — Blocked by Entity/World Abstraction (IMob, IGameWorld) +SpawnData, SpawnController, Animation, AnimationData, DataTransform, MarkData, TelegraphInstance + +### Tier 4 — Script System (DO NOT TOUCH) +All I*Script* interfaces, ScriptHandler, ScriptContainer, AbilityScript, EffectScript, Action framework + +### Tier 5 — Heavy MC Coupling (Long-term) +RecipeCarpentry, RecipeController, Ability.java + all ability types, ChunkController, ProfileController, SyncController + +## Key Rules + +- **Interfaces**: Short `I` prefix (`IMob`, `IUser`, `IStack`). No `Platform` prefix. Access: `PlatformServiceHolder.get()` +- **Core imports**: Only `java.*`, platform-api interfaces, other core classes — never MC +- **NBT**: `NBT.compound()` / `NBT.list()`. File I/O via `PlatformServiceHolder` +- **Shadow pattern**: Core + mc1710 share packages. mc1710 adds `implements IFaction`, SyncController calls, MC-type methods + +## Recommended Migration Order + +1. mc1710 shadow files for already-migrated controllers +2. `IUser` implementation (unblocks Tier 2: ~15 files) +3. `IStack` / inventory abstraction (unblocks Tier 1: ~8 files) +4. Dialog cluster → Quest cluster → Player data classes +5. `NBTJsonUtil` to core (unblocks Dialog/Quest controllers) diff --git a/.AGENTS/FORBIDDEN_PRACTICES.md b/.AGENTS/FORBIDDEN_PRACTICES.md new file mode 100644 index 000000000..1d6d36f01 --- /dev/null +++ b/.AGENTS/FORBIDDEN_PRACTICES.md @@ -0,0 +1,86 @@ +# Forbidden Practices — CustomNPC-Plus + +Quick-reference guardrails. Prevents regressions, guides contributors. +See also: `AGENTS.md` (architecture), `CORE_PLAN.md` (roadmap), `CORE_MIGRATION_STATUS.md` (blockers). + +--- + +## 1. NEVER Rules + +### Thread Safety +- **NEVER use mutable static fields for shared state.** Known violation: `RandomPositionGeneratorAlt.staticVector` — a mutable `Vec3` reused across calls. Do not replicate this pattern. + +### Core / Platform-API Isolation +- **NEVER import MC classes in `core/` or `platform-api/`.** Use platform interfaces only (`INBTCompound`, `IUser`, `IStack`, `IGameWorld`). +- **NEVER import wrapper classes in `core/`.** Only interfaces from `platform-api/`. +- **NEVER call `getMCNBT()` / `getMCTagList()` from `core/` code.** These are escape hatches on `INbt`/`INbtList` for mc1710 code only. +- **NEVER use `new NBTTagCompound()` in `core/`.** Use `NBT.compound()` / `NBT.list()`. +- **NEVER use `CompressedStreamTools` in `core/`.** Use `PlatformServiceHolder.get().readCompressedNBT()`. +- **NEVER use `LogWriter` in `core/`.** Use `PlatformServiceHolder.get().logError()`. + +### Split-Package Contract +- **NEVER break the split-package shadow.** When a class exists in both `core/` and `src/main/java/` with the same package, mc1710 shadows core at compile time. The mc1710 version adds `implements IFaction`, SyncController calls, MC-specific methods. Core version must remain MC-free. + +### Naming +- **Platform interfaces:** Short `I` prefix, no `Platform` in name. `IUser` not `IPlatformUser`. +- **MC1710 wrappers:** `[Thing]Wrapper`. No `MC1710` prefix. `PlayerWrapper` not `MC1710PlayerWrapper`. +- **Scripting API** (`IPlayer`, `IEntity`, `ICustomNpc`) is a separate concern from platform interfaces. Different package, different purpose. Do not conflate. + +--- + +## 2. Deprecated Components + +| Component | Status | Replacement | +|---|---|---| +| `CommandNoppes` (`foxz.command`) | Deprecated | Use `/kam` command hierarchy (`kamkeel.npcs.command.CommandKamkeel`) | +| `GuiScriptInterface.saveText()` | Deprecated | Use current script save mechanism | +| `NBTTags.GetScript` / `GetScriptOld` / `NBTScript` | mc1710-only | Not migrated to core; uses `IScriptHandler` directly | +| `NBTTags.getItemStackList/Array` | mc1710-only | Uses `NoppesUtilServer.readItem()` + `ItemStack`; no core equivalent yet | + +--- + +## 3. Forbidden Subsystem Areas (for Core Migration) + +Do NOT attempt to migrate these to `core/`. See `CORE_PLAN.md` §DO NOT TOUCH. + +| Subsystem | Reason | Tier | +|---|---|---| +| **Script system** — `ScriptHandler`, `ScriptContainer`, `I*Script*`, Action framework | Deeply coupled, not yet planned | 4 | +| **Ability.java** + ability type classes | 30+ MC imports (Block, Entity, DamageSource, Vec3, World) | 5 | +| **Entity classes** — `EntityNPCInterface`, `EntityCustomNpc`, all `EntityAbility*` | Extend MC `Entity` directly | 5 | +| **Recipe system** — `RecipeCarpentry`, `RecipeController` | Extends `ShapedRecipes`, uses `CraftingManager` | 5 | +| **Chunk system** — `ChunkController` | `ForgeChunkManager` dependency | 5 | +| **SyncController** | ByteBuf, packets, Minecraft server | 5 | +| **Profile system** — `ProfileController` | EntityPlayer lifecycle, Mojang API | 5 | + +--- + +## 4. Architectural Guardrails + +### Dependency Flow +``` +platform-api/ (interfaces only, zero MC deps) + ^ + core/ (game logic, MC-free) + ^ +src/main/java/ (mc1710: wrappers, entities, GUI, packets) +``` +Violations = build failures. Core depends on platform-api only. + +### mc1710 Shadow Responsibilities +When a controller is migrated to `core/`, the mc1710 shadow file MUST: +1. Add `implements IFactionHandler` (or equivalent scripting API interface) +2. Re-add `SyncController` calls in save/delete methods +3. Re-add `EntityPlayer`/`IPlayer` overload methods +4. Override MC-dependent factory methods (e.g., `createDefaults()` for ItemStack) + +### NBT Serialization +- Core: `readNBT(INBTCompound)` / `writeNBT(INBTCompound)` — interfaces only +- mc1710: can use `NBTTagCompound` directly, cast via `getMCNBT()` at boundary + +### File I/O in Core +- `CustomNpcs.getWorldSaveDirectory()` → `PlatformServiceHolder.get().getWorldSaveDirectory()` +- Async saves use `CustomNPCsThreader` thread pool (already in core) + +### What Stays mc1710-Only (permanently) +GUI/rendering (`@SideOnly`), packets/network (ByteBuf), `FieldDef`/ability GUI, `GameRegistry`, `ForgeChunkManager`, `WeightedRandom`, scripting API interface implementations. diff --git a/.AGENTS/MC_COUPLING_ANALYSIS.md b/.AGENTS/MC_COUPLING_ANALYSIS.md new file mode 100644 index 000000000..884a001e0 --- /dev/null +++ b/.AGENTS/MC_COUPLING_ANALYSIS.md @@ -0,0 +1,154 @@ +# MC Coupling Analysis — CustomNPC-Plus + +> Codebase analysis of Minecraft API coupling across `src/main/java/`. +> Generated from verified grep/search results on the repository. + +--- + +## 1. MC-Dependent Code Overview + +| Metric | Count | Context | +|---|---|---| +| Total files in `src/main/java/` | ~2,170 | All Java source files | +| Files importing `net.minecraft.*` | 1,424 | 66.5% of all source files | +| Files importing `cpw.mods.fml.*` | 507 | 35.5% of MC-importing files | +| Files importing `net.minecraftforge.*` | 398 | 27.9% of MC-importing files | +| `@SideOnly` annotations | 488 | Across 398 files | +| Platform abstraction adoption | <0.2% | Almost no MC code uses `platform-api` interfaces yet | + +**Key takeaway:** Two-thirds of the codebase directly imports Minecraft classes. FML and Forge imports are concentrated in registration, event handling, and networking code. The platform abstraction layer (`platform-api/`, `core/`) exists but has near-zero adoption in `src/main/java/` — the vast majority of code still calls MC APIs directly. + +--- + +## 2. Top MC-Coupled Hotspots (by directory) + +Directories ranked by number of files importing `net.minecraft.*`: + +| Rank | Directory | Files | Notes | +|---|---|---|---| +| 1 | `noppes/npcs/client/gui` | 66 | GUI screens — version-locked | +| 2 | `noppes/npcs/controllers/data` | 52 | Data classes — mostly NBT boundaries | +| 3 | `noppes/npcs/client/gui/util` | 44 | GUI utilities — version-locked | +| 4 | `noppes/npcs/containers` | 42 | Inventory containers — IInventory-dependent | +| 5 | `noppes/npcs/items` | 41 | Items — registration changes, logic stable | +| 6 | `noppes/npcs/blocks` | 34 | Blocks — metadata, BlockState, registration | +| 7 | `noppes/npcs` (root) | 34 | Core mod classes, utilities | +| 8 | `noppes/npcs/controllers` | 29 | Singleton controllers — mostly light coupling | +| 9 | `noppes/npcs/ai` | 29 | AI tasks — EntityAI API throughout | +| 10 | `kamkeel/npcs/network/packets/data` | 19 | Network data packets | + +**Observation:** The top 3 hotspots account for 162 files. GUI code (#1, #3) is inherently version-locked and should not be abstracted — it must be rewritten per MC version. Controllers/data (#2, #8) are the best migration candidates due to light MC coupling at boundaries only. + +--- + +## 3. Flattening-Sensitive Code (Pre-1.13 Patterns) + +The Flattening (1.13) eliminates block metadata, changes registration, and restructures BlockStates. These patterns will **break**: + +### Block Metadata +- **Pattern:** `getMetadata()`, `damageDropped()`, `getStateFromMeta()` +- **Matches:** 29 across 27 files +- **Impact:** Every block using metadata subsets must be converted to individual block instances or BlockState properties + +### GameRegistry Registration +- **Pattern:** `GameRegistry.register*` +- **Matches:** 82 across 18 files +- **Concentration:** `CustomItems.java` alone has **62** calls +- **Impact:** Registration moves to `DeferredRegister` / event-driven registration in 1.13+ + +### IInventory Implementations +- **Files:** 40+ in `containers/` +- **Impact:** `IInventory` replaced by capability-based `IItemHandler` pattern + +### Block Renderers Using Metadata +- **Files:** 25+ renderer files +- **Impact:** Metadata-driven rendering replaced by BlockState model system + +### OreDictionary +- **Files:** `NoppesUtilPlayer.java`, `CustomItems.java` +- **Impact:** Replaced by Tags system in 1.13+ + +### Numerical Item IDs +- **Pattern:** `getIdFromItem()` +- **Files:** `RoleCompanion.java`, `EntityProjectile.java` (2 files) +- **Impact:** Must convert to `ResourceLocation`-based identification + +--- + +## 4. GUI/Rendering Layer + +| Pattern | Matches | Files | +|---|---|---| +| `extends GuiScreen/GuiContainer/GuiButton` | 37 | 35 | +| Total client rendering files | 212 | — | + +**Assessment:** The GUI and rendering layer is **completely different per MC version**: +- 1.7.10: `GuiScreen`, `GuiButton`, `Tessellator` with fixed pipeline +- 1.12.2: `GuiScreen`, `GuiButton` (similar but shifted APIs) +- 1.16.5+: `Screen`, `Button`, `MatrixStack`-based rendering +- 1.20+: `GuiGraphics` wrapper, component-based text + +**Recommendation:** Do **NOT** abstract the GUI layer. Rewrite per version. For multi-version support, start with admin essentials only (NPC editor, quest editor, dialog editor) and defer cosmetic GUIs. + +--- + +## 5. Registration Centralization + +| Registration Type | Location | Calls/Files | +|---|---|---| +| Block/Item registration | `CustomItems.java` | 62 `GameRegistry` calls | +| Entity registration | `CustomNpcs.java` | Centralized | +| Event handler registration | 16+ files | `EVENT_BUS.register()` | + +**Assessment:** Registration is already well-centralized. This is **good for porting** — only `CustomItems.java`, `CustomNpcs.java`, and a handful of event handler files need version-specific registration code. The majority of block/item/entity *logic* is separate from registration. + +--- + +## 6. Subsystem Coupling Categories + +Classification key: +- **CORE-READY** — Could move to `core/` today with interface swaps +- **LIGHT-MC** — Uses MC types at boundaries only (EntityPlayer params, NBT) +- **HEAVY-MC** — Deep MC API usage throughout +- **VERSION-LOCKED** — Uses APIs that change fundamentally between versions + +| Subsystem | Files | Coupling | Notes | +|---|---|---|---| +| Controllers/Data | 81 | LIGHT-MC | Mostly NBT + EntityPlayer params at method signatures | +| Networking | 100+ | HEAVY-MC | Packet framework changes every version (SimpleNetworkWrapper → custom channels) | +| Blocks | 97 | VERSION-LOCKED | Metadata, BlockState, registration, rendering all change | +| Items | 41 | LIGHT-MC | Registration changes, but item logic is stable across versions | +| AI | 29 | HEAVY-MC | EntityAI API changes significantly (Goal system in 1.16+) | +| Commands | 22 | VERSION-LOCKED | Custom system in 1.7.10, Brigadier command tree in 1.13+ | +| Roles/Jobs | 19 | LIGHT-MC | Mostly game logic with entity params at boundaries | +| Config | 9 | LIGHT-MC | Forge config API changes but configuration logic is the same | +| GUI/Client | 212 | VERSION-LOCKED | Completely different rendering/widget APIs per version | + +**Summary:** 41% of subsystem files (Controllers/Data + Roles/Jobs + Items + Config = 150 files) are LIGHT-MC and viable migration candidates. The remaining 59% requires version-specific implementations or deep abstraction work. + +--- + +## 7. Migration Priority Recommendations + +Ordered by ROI (code sharing potential vs. effort required): + +| Priority | Subsystem | Files | Coupling | Rationale | +|---|---|---|---|---| +| **1st** | Controllers/Data | 81 | LIGHT-MC | Highest ROI. Most code can be shared across versions. MC types appear only at method boundaries (EntityPlayer params, NBT serialization). 52 data files + 29 controller files. | +| **2nd** | Roles/Jobs | 19 | LIGHT-MC | Small surface area, high value. Game logic is version-independent. Entity interactions are at boundaries only. | +| **3rd** | Items | 41 | LIGHT-MC | Registration is centralized in `CustomItems.java`. Item behavior logic is stable across versions — only registration mechanism changes. | +| **4th** | Networking Packets | 100+ | HEAVY-MC | Needs packet DTO abstraction. Separate serializable data from transport. High file count but patterns are repetitive — a good abstraction pays off across all packets. | +| **5th** | AI | 29 | HEAVY-MC | Needs `EntityAI` → `Goal` abstraction layer. AI *logic* (targeting, combat, pathing decisions) is version-independent but the API surface changes significantly. | +| **6th** | Commands | 22 | VERSION-LOCKED | Needs Brigadier adapter for 1.13+. Custom command hierarchy in 1.7.10 maps conceptually to Brigadier's command tree. | +| **7th** | Blocks | 97 | VERSION-LOCKED | Needs BlockState abstraction. Metadata elimination, registration changes, and rendering differences make this high-effort. | +| **Last** | GUI/Client | 212 | VERSION-LOCKED | Rewrite per version, do not abstract. Start with admin essentials (NPC editor, quest editor, dialog editor). Defer cosmetic GUIs. | + +--- + +## Appendix: Current Core Migration Status + +As of this analysis, **183 files** have been abstracted to `core/` + `platform-api/` out of ~2,170 total source files. Migrated subsystems include: +- Faction, Magic, Transport, Tag, GlobalData controllers +- 60+ data classes + +See `CORE_MIGRATION_STATUS.md` for per-file blocker analysis and `CORE_PLAN.md` for the migration roadmap. diff --git a/.AGENTS/MULTI_VERSION_RESEARCH.md b/.AGENTS/MULTI_VERSION_RESEARCH.md new file mode 100644 index 000000000..724ad1518 --- /dev/null +++ b/.AGENTS/MULTI_VERSION_RESEARCH.md @@ -0,0 +1,136 @@ +# Multi-Version Mod Architecture Research + +> Permanent reference document. Findings marked **VERIFIED** come from real repositories; **THEORETICAL** findings need validation. + +--- + +## 1. Real-World Multi-Version Mod Architectures + +### Essential Mod (Gold Standard) — VERIFIED + +- **Repo:** SparkUniverse/Essential-Mod (formerly EssentialGG) +- **Toolkit:** [Essential Gradle Toolkit](https://github.com/EssentialGG/essential-gradle-toolkit) +- Uses **ReplayMod Preprocessor** at scale +- **Structure:** `versions/` folder with sub-projects per MC version +- Single modern Gradle wrapper (8.x) with **Java toolchains** for Java 8/17/21 +- Does **NOT** use separate `gradlew` files — uses one unified build + +### ReplayMod Preprocessor — VERIFIED + +- **Repo:** [github.com/ReplayMod/preprocessor](https://github.com/ReplayMod/preprocessor) +- **Structure:** + - `common/src/main/java` — shared code with `#if` directives + - `versions/` — subprojects per MC version +- Each version subproject applies its own Gradle plugin (ForgeGradle / RFG / Loom) +- `settings.json` defines version variables +- Root `build.gradle` wires common to version nodes via `preprocess {}` DSL +- **Real example:** Fallen-Breath/fast-ip-ping + +### Essential Gradle Toolkit — VERIFIED + +- **Plugin IDs:** `gg.essential.multi-version.root` / `gg.essential.multi-version` +- Wraps ReplayMod Preprocessor with cleaner DSL +- Supports version branching with `version(10710)`, `version(12001)`, etc. + +### ModStitch Plugin — VERIFIED + +- **Repo:** [github.com/isXander/modstitch](https://github.com/isXander/modstitch) +- Designed to unify Official Tooling (NeoGradle / ForgeGradle) with RetroFuturaGradle +- Enables single build system spanning 1.7.10 to 1.20.1 +- Used by Archipelago CoreClient (bridging 1.7.10 RFG and 1.20.1 NeoGradle) + +--- + +## 2. Build System Findings + +| Finding | Status | +|---|---| +| Architectury Loom CAN consume plain Java libraries (`core/`, `platform-api/`) as standard project dependencies — no remapping needed since they have no MC imports | **VERIFIED** | +| Modern Gradle 8.x CAN compile Java 8 code using Java Toolchains — no need for separate Gradle wrappers | **VERIFIED** | +| RetroFuturaGradle and ForgeGradle CAN potentially coexist in one build via modstitch | **THEORETICAL** — modstitch repo confirms design intent; needs validation with CustomNPC-Plus specifically | +| Single unified Gradle wrapper is the recommended approach (Essential mod proves this at scale) | **VERIFIED** | + +--- + +## 3. Preprocessor Syntax + +The ReplayMod Preprocessor uses comment-based directives that are valid Java (comments), so code compiles without the preprocessor too. Inactive branches are prefixed with `//$$ ` to comment them out. + +```java +//#if MC>=11600 +import net.minecraft.client.util.math.MatrixStack; +//#else +//$$ import net.minecraft.client.renderer.GlStateManager; +//#endif +``` + +Key syntax elements: +- `//#if MC>=11600` — conditional on version variable +- `//#else` — else branch +- `//#endif` — end conditional +- `//$$ ` — prefix for inactive code (commented out by preprocessor) + +--- + +## 4. Key Insight: Oracle Was Wrong About Separate Gradle Wrappers + +Oracle recommended separate Gradle wrappers per version leaf. Real-world evidence shows: + +- **Essential Mod** uses **ONE** Gradle wrapper for **ALL** versions +- **Java Toolchains** handle JDK version differences (Java 8 for 1.7.10, Java 17 for 1.18+, Java 21 for 1.20.5+) +- **modstitch** plugin unifies RFG + ForgeGradle in one build +- Separate wrappers add unnecessary complexity and maintenance burden + +--- + +## 5. Project Structure Template (Based on Real Implementations) + +``` +CustomNPC-Plus/ + platform-api/ → Plain Java 8 library (interfaces) + core/ → Plain Java 8 library (game logic) + common/ → Shared MC-aware code with preprocessor directives + versions/ + 1.7.10/ → RetroFuturaGradle + 1.12.2/ → ForgeGradle or RFG + 1.16.5/ → ForgeGradle 5/6 or Architectury Loom + 1.20.1/ → NeoGradle or Architectury Loom + gradle-plugins/ → TypeScript .d.ts generator + settings.json → Preprocessor version definitions + build.gradle → Root wiring +``` + +- `platform-api/` and `core/` are consumed as plain `implementation project(":core")` dependencies by all version leaves +- `common/` contains MC-aware code that uses `#if` directives for version differences +- Each `versions//` subproject applies the appropriate Gradle plugin for that MC version +- One `gradlew` at root, one `settings.gradle`, one unified build + +--- + +## 6. Corrected Architecture (vs Oracle's 6-Layer Recommendation) + +**Oracle recommended:** +``` +platform-api → core → legacy-common → modern-common → version leaves +``` + +**Evidence suggests:** +``` +platform-api → core → common (with preprocessor) → version leaves +``` + +### Why the preprocessor replaces separate common modules: + +- The preprocessor **REPLACES** the need for separate `legacy-common` / `modern-common` modules +- Syntactic differences (import paths, method signatures, rendering APIs) are handled by `#if` directives in a single `common/` module +- Only truly version-specific code (entity registration, rendering pipelines, network handlers) goes in version leaves +- This is proven at scale by Essential Mod, which supports 10+ MC versions with a single `common/` source set + +### What goes where: + +| Layer | Contents | MC Dependencies | +|---|---|---| +| `platform-api/` | Interfaces only (`IUser`, `INBTCompound`, `PlatformService`) | None | +| `core/` | MC-free game logic (controllers, data classes, enums, utils) | None | +| `common/` | Shared MC-aware code with `#if` preprocessor directives | Yes (version-gated) | +| `versions//` | Entity registration, rendering, version-specific implementations | Full MC + Forge/NeoForge | diff --git a/.AGENTS/SCRIPTING_TOOLCHAIN.md b/.AGENTS/SCRIPTING_TOOLCHAIN.md new file mode 100644 index 000000000..44147795a --- /dev/null +++ b/.AGENTS/SCRIPTING_TOOLCHAIN.md @@ -0,0 +1,77 @@ +# Scripting Toolchain — Java → TypeScript → Editor + +## Overview +Pipeline that turns Java API interfaces into `.d.ts` TypeScript definitions, loaded at runtime +by the in-game script editor for autocomplete, hover info, and error detection. +Addons can ship their own `.d.ts` files for full editor integration. + +## Pipeline Flow +``` +Java API interfaces (src/api/java) + ▼ +dts.typescript-generator (Gradle plugin) + 1. JavaToTypeScriptConverter → .d.ts per file + 2. ImplementationFieldEnricher → inject impl fields + 3. hooks.d.ts → event hooks with param types + 4. dts-patches/ → ECMAScript built-in overrides + ▼ +src/main/resources/assets/customnpcs/api/**/*.d.ts (in mod JAR) + ▼ +Runtime: JSTypeRegistry (client-side) + 1. DtsModScanner → scan ALL loaded mods for assets//api/ + 2. TypeScriptDefinitionParser → parse .d.ts into JSTypeInfo + 3. DtsJavaBridge → map .d.ts types to Java reflection + ▼ +Script editor: autocomplete, hover, error detection +``` + +## Gradle Plugin (`gradle-plugins/`) +| File | Role | +|------|------| +| `TypeScriptGeneratorPlugin.groovy` | Plugin entry — registers `generateTypeScriptDefinitions` task | +| `GenerateTypeScriptTask.groovy` | Task orchestration — generation, patches, enrichment | +| `JavaToTypeScriptConverter.groovy` | Core converter — Java source → `.d.ts` with Javadoc, generics, nested types, `hooks.d.ts` | +| `ImplementationFieldEnricher.groovy` | Injects public impl fields into API interface `.d.ts` | + +### Configuration (root `build.gradle`) +| Option | Purpose | +|--------|---------| +| `apiPackages` | Packages to generate `.d.ts` for (`noppes.npcs.api`, `net.minecraft`) | +| `implementationPackages` | Impl classes scanned for field enrichment (`noppes.npcs.scripted`, `noppes.npcs.controllers.data`, etc.) | +| `patchesDirectory` | Hand-written `.d.ts` overrides copied to `assets//api/patches` | +| `cleanOutputFirst` | Deletes old generated `.d.ts` before regenerating | +| `mapJavaPrimitivesToJS` | `false` = preserve `int`/`float`/`double`; `true` = map all to `number` | + +`processResources.dependsOn generateTypeScriptDefinitions` — runs automatically during build. + +### Implementation Enrichment +Scripts access `event.npc`, `event.player` — public fields on impl classes, not API interfaces. +The enricher scans impl packages, and if exactly one implementer exists for an API interface, +injects its public instance fields. `final` → `readonly`. Multiple implementers → skipped. + +## dts-patches Directory +Hand-written ECMAScript 5.1 built-in `.d.ts` files: `Array`, `Boolean`, `Date`, `Error`, +`GlobalFunctions`, `JSON`, `Math`, `Number`, `Object`, `RegExp`, `String`. +Provides autocomplete for standard JS globals in the Nashorn environment. + +## Addon API Support +1. Place `.d.ts` files at `assets//api/**/*.d.ts` in your mod JAR +2. `DtsModScanner` discovers them automatically (priority: `customnpcs` > `npcdbc` > others) +3. Register hooks via `IScriptHookHandler.registerHookDefinition()` for sidebar + stub generation + +## Generated Output Structure +``` +assets/customnpcs/api/ +├── hooks.d.ts # Hook signatures organized by context +├── entity/ # IPlayer.d.ts, ICustomNpc.d.ts, IEntity.d.ts +├── event/ # INpcEvent.d.ts, IPlayerEvent.d.ts (with @hookName) +├── handler/data/ # IQuest.d.ts, IDialog.d.ts, IFaction.d.ts +├── patches/ecmascript/ # Math.d.ts, JSON.d.ts, etc. +└── index.d.ts # Re-exports all generated types +``` + +## Running +```bash +./gradlew generateTypeScriptDefinitions # Generate only +./gradlew build # Generates as part of build +``` diff --git a/.AGENTS/SESSION_MEMORY.md b/.AGENTS/SESSION_MEMORY.md new file mode 100644 index 000000000..fa2237e54 --- /dev/null +++ b/.AGENTS/SESSION_MEMORY.md @@ -0,0 +1,268 @@ + +# SESSION_MEMORY.md — Multi-Version Porting Strategy + +**Created:** 2026-03-15 +**Last updated:** 2026-03-15 +**Purpose:** Persistent memory of critical decisions, research, and roadmap for porting CustomNPC-Plus to multiple Minecraft versions simultaneously. + + +**Related documents:** +- `MULTI_VERSION_RESEARCH.md` — Detailed external research (tools, repos, real implementations) +- `MC_COUPLING_ANALYSIS.md` — Quantified MC-dependency breakdown by subsystem +- `CORE_MIGRATION_STATUS.md` — Per-file blocker analysis for core abstraction +- `CORE_PLAN.md` — Platform abstraction roadmap and naming conventions + +--- + + +## Owner's Vision + +**Goal:** Port CustomNPC-Plus from 1.7.10 to **1.12.2, 1.16.5, and 1.20.1 simultaneously**. + +**Key Constraints (from owner):** +- **NOT sequential** — refuses to spend 2-3 months per version one at a time +- Must tackle all versions at once, to the highest possible degree +- 1.7.10 remains the primary/active build during porting +- Time and budget are limited — efficiency is paramount + +--- + +## Current State Assessment + +### Abstraction Progress +- **183 / ~1,810 files abstracted** (~10%) into `core/` + `platform-api/` +- `platform-api/`: 48 interface files (NBT, entity wrapping, file I/O, logging, scheduling) +- `core/`: 140 files (8 controllers, 60+ data classes, enums, utils) +- `PlatformService` exists but is used in <0.2% of MC-dependent code + +### MC-Dependent Code Distribution (~1,424 files import net.minecraft.*) + +| Subsystem | File Count | Coupling Level | Porting Difficulty | +|---|---|---|---| +| **GUI/Client/Rendering** | 212 | VERSION-LOCKED | Extreme — rewrite per version | +| **Networking/Packets** | 100+ | HEAVY-MC | High — framework changes every version | +| **Blocks + Tiles** | 97 | VERSION-LOCKED | High — Flattening breaks everything | +| **Controllers/Data** | 81 | LIGHT-MC | Medium — mostly NBT + EntityPlayer params | +| **Scripting Wrappers** | 50+ | HEAVY-MC | Medium — API surface stable-ish | +| **Abilities** | 44 | HEAVY-MC | High — DO NOT TOUCH yet | +| **Items** | 41 | LIGHT-MC | Medium — registration centralized in CustomItems.java | +| **AI** | 29 | HEAVY-MC | Medium — EntityAI API changes significantly | +| **Commands** | 22 | VERSION-LOCKED | Medium — Brigadier in 1.13+ | +| **Roles/Jobs** | 19 | LIGHT-MC | Low — mostly game logic with entity params | +| **Config** | 9 | LIGHT-MC | Low — Forge config API changes but logic same | + +### 1.7.10 → 1.12.2 API Differences (Verified Against This Codebase) + +| Pattern | Change Level | Files Affected | Details | +|---|---|---|---| +| FML package (cpw.mods.fml → net.minecraftforge.fml) | MINOR_CHANGE | 524 files | Mass rename, mechanical | +| Entity registration | MINOR_CHANGE | 1 file (CustomNpcs.java) | Package rename | +| Block/Item registration (GameRegistry) | IDENTICAL | 18 files (62 calls in CustomItems.java) | Same API | +| Event system (@SubscribeEvent, EVENT_BUS) | IDENTICAL | 16+ files | Same API | +| GUI handler (NetworkRegistry) | IDENTICAL | 1 file | Same API | +| NBT (NBTTagCompound) | IDENTICAL | Hundreds | Same API | +| World save data (WorldSavedData) | IDENTICAL | Several | Same API | +| @Mod, @EventHandler, @SidedProxy | MINOR_CHANGE | ~5 files | Package rename | +| Packet system (SimpleNetworkWrapper) | BREAKING_CHANGE | 100+ files | Becomes SimpleChannel | +| IInventory → IItemHandler (Capabilities) | BREAKING_CHANGE | 40+ containers | New system alongside old | + +--- + +## Critical Research Findings + +### The Hard Truth: Nobody Has Done This Before + +**No Minecraft mod in existence successfully shares code between 1.7.10 and modern (1.16+) versions.** Exhaustive GitHub search confirmed: + +| Pattern | Example | Lowest MC Version | Shared Code? | +|---|---|---|---| +| Preprocessor multi-version | Polyfrost/OneConfig (280★) | **1.8.9** (not 1.7.10) | Yes, via `#if MC>=` | +| Multi-module per-loader | JEI (Core/Common/NeoForge/Fabric) | Per-branch only | Yes, within one version | +| Branch-per-version | Applied Energistics 2 | 1.15+ (no 1.7.10 branch) | No — independent codebases | +| Separate repos | GregTechCEu (1.12) + GT-Modern (1.20) | 1.12 / 1.20 separately | No — complete rewrites | +| 1.7.10 only | GTNH ecosystem (93 repos) | 1.7.10 | N/A | + +**CustomNPC-Plus's platform-api/core approach is genuinely novel** — it's the JEI Core/Common pattern applied retroactively to 1.7.10, which nobody else has attempted. + +### Build System: Composite Builds, NOT Separate Wrappers + +Oracle recommended separate Gradle wrappers. **This is wrong.** Evidence from real implementations: + +| Tool | What It Does | Status | +|---|---|---| +| **Gradle Composite Builds** (`includeBuild`) | Each version is an independent build with its own plugin classpath | VERIFIED — only stable way to mix RFG + FG | +| **Gradle Toolchains** | Run Gradle on JDK 21, compile with JDK 8 or 17 per subproject | VERIFIED — standard Gradle feature | +| **ModStitch** (github.com/isXander/modstitch) | Unifies RFG + ForgeGradle + NeoGradle in one build | THEORETICAL — needs validation | +| **ReplayMod Preprocessor** | `#if MC>=` directives in Java comments | VERIFIED — works, but build tooling doesn't support 1.7.10 via Loom | +| **Essential Gradle Toolkit** | Wraps preprocessor with cleaner DSL | VERIFIED — plugin `gg.essential.multi-version` v0.6.7 | +| **Deftu multiversion** | Production multi-version plugin (used by OneConfig) | VERIFIED — `dev.deftu.gradle.multiversion-root` v2.73.0 | + +**Key constraint:** RFG and ForgeGradle/NeoGradle CANNOT share a Gradle classpath in multi-project builds. Composite builds (`includeBuild`) are required. + +### Preprocessor Limitations for 1.7.10 + +The ReplayMod preprocessor **syntax** supports 1.7.10 (version `10710`). But: +- The **build tooling** (Architectury Loom, Essential Loom) does NOT support 1.7.10 +- ReplayMod itself dropped 1.7.10 support when moving to Gradle 7 +- The preprocessor is a text tool — it works on any Java file regardless of MC version +- **For CustomNPC-Plus:** The preprocessor could process source files for 1.7.10 IF combined with RetroFuturaGradle (not Loom). This needs prototyping. + +--- + +## Corrected Architecture (Post-Critical-Review) + +### Oracle's Recommendation vs Evidence-Based Correction + +| Aspect | Oracle Said | Evidence Says | Decision | +|---|---|---|---| +| Build system | Separate Gradle wrappers per leaf | Composite builds + single wrapper | **Composite builds** | +| Layer count | 6 layers (platform-api → core → legacy-common → modern-common → leaves) | Preprocessor can replace family-common layers | **5 layers with optional preprocessor in version leaves** | +| legacy-common / modern-common | Dedicated modules | ~100+ files could go here, BUT preprocessor handles syntactic diffs | **Start without them; add only if code duplication proves >50 files** | +| 1.7.10→1.12.2 gap | Treated as equivalent to other gaps | Mostly IDENTICAL or MINOR_CHANGE (524 package renames + 1 breaking: packets) | **1.12.2 is a mechanical port — much easier than expected** | + +### Recommended Project Structure + +``` +CustomNPC-Plus/ + platform-api/ → Plain Java 8 library (interfaces) — SHARED BY ALL + core/ → Plain Java 8 library (game logic) — SHARED BY ALL + mc1710/ → Current src/main/java/ (RetroFuturaGradle) — COMPOSITE BUILD + mc1122/ → 1.12.2 (RetroFuturaGradle — yes, RFG handles 1.12.2) — COMPOSITE BUILD + mc1165/ → 1.16.5 (ForgeGradle 6) — COMPOSITE BUILD + mc1201/ → 1.20.1 (NeoGradle/ModDevGradle 2) — COMPOSITE BUILD + gradle-plugins/ → TypeScript .d.ts generator (unchanged) +``` + +**Why no legacy-common/modern-common initially:** +- The preprocessor can handle syntactic differences within version leaves +- Most LIGHT-MC code should be migrated to `core/` with platform interfaces instead of duplicated in a family-common layer +- If >50 files of genuine version-family-specific code emerges during porting, THEN add the intermediate layers +- Simpler architecture = less overhead = faster iteration + +### Build System Architecture + +``` +Root settings.gradle: + include 'platform-api', 'core' → Plain Java libraries (multi-project) + includeBuild 'mc1710' → Composite build (RetroFuturaGradle) + includeBuild 'mc1122' → Composite build (RetroFuturaGradle) + includeBuild 'mc1165' → Composite build (ForgeGradle 6) + includeBuild 'mc1201' → Composite build (NeoGradle) + includeBuild 'gradle-plugins' → Already composite + +Each mc*/ has its own: + settings.gradle → Declares dependency on root platform-api/core via includeBuild '..' + build.gradle → Applies version-specific Gradle plugin + gradle.properties → MC version, Forge version, mappings + src/main/java/ → Version-specific implementations +``` + +**Gradle Toolchains** handle JDK differences (8 for legacy, 17 for 1.20.1). + +--- + +## Revised Abstraction Order (Maximum Parallelism) + +The key insight: **1.12.2 is so close to 1.7.10 that most of the work is mechanical renaming (524 files of cpw.mods.fml → net.minecraftforge.fml).** This means: + +### Track A: Core Abstraction (enables ALL versions) +1. Finish mc1710 shadow files for migrated controllers +2. Implement `IUser` usage in core (unblocks Tier 2: ~15 files) +3. Implement `IStack` / inventory abstraction (unblocks Tier 1: ~8 files) +4. Dialog cluster → Quest cluster → PlayerData migration to core +5. Packet DTO abstraction in core +6. Command abstraction in core + +### Track B: 1.12.2 Port (CAN START IMMEDIATELY — mostly mechanical) +1. Copy mc1710/ → mc1122/ +2. Mass-rename cpw.mods.fml → net.minecraftforge.fml (524 files) +3. Update entity registration (minor API change) +4. Refactor packet system (SimpleNetworkWrapper → SimpleChannel — the ONE breaking change) +5. Set up RetroFuturaGradle for 1.12.2 (confirmed: RFG supports 1.12.2) +6. Test and iterate + +### Track C: 1.16.5 Port (start after Track A Phase 1-3) +1. Create mc1165/ with ForgeGradle 6 +2. Implement PlatformService for 1.16.5 +3. Port core controllers (they just work — MC-free) +4. Port networking (new packet system) +5. Port commands (Brigadier adapter) +6. Port blocks (BlockState — the Flattening work) +7. Port essential admin GUIs (rewrite, not port) + +### Track D: 1.20.1 Port (start after Track C is 50% done) +1. Create mc1201/ based on mc1165/ (close enough) +2. Implement PlatformService for 1.20.1 +3. Adapt for NeoForge API differences +4. Mostly rides on 1.16.5 work + +**Tracks A and B can run in parallel immediately.** Track C starts when core interfaces exist. Track D is incremental from C. + +--- + +## MVP Targets Per Version + +### 1.7.10 — Full Primary (unchanged) +All features, full parity. This is the production build. + +### 1.12.2 — "Bridge Build" (EASIEST — mostly mechanical port) +- NPC spawn, persist, despawn lifecycle +- Dialog system, Quest system, Faction system +- Core networking (NPC sync, player data) +- Basic AI + combat +- Essential editor/admin GUIs +- Commands (`/kam` hierarchy) +- **NOT initially:** Abilities, auction, animation maker, scripting IDE + +### 1.16.5 — "NPC Core" Modern +- Same feature set as 1.12.2 MVP +- Server-first: commands and admin workflows before full GUI +- Basic NPC editor screen +- **NOT initially:** Full GUI suite, abilities, auction, custom models + +### 1.20.1 — "NPC Core" Latest +- Same as 1.16.5 — incremental from it +- Client polish lags behind server feature parity + +--- + +## Critical Warnings + +1. **You're the first to do this** — no existing mod shares code between 1.7.10 and modern. Expect uncharted territory. +2. **Don't mirror Minecraft class-for-class in platform-api** — keep interfaces coarse and purpose-driven +3. **Don't promise full GUI parity on modern versions first** — 212 files, completely different per version, do LAST +4. **Don't let preprocessor guards spread into core/** — only in version-leaf code +5. **Don't try to abstract scripting, abilities, entities, or recipes** — Tier 4-5, rewrite per-version +6. **1.12.2 is much easier than you think** — 95% of APIs are identical/renamed, only packets truly break +7. **Composite builds, not separate wrappers** — one Gradle wrapper, `includeBuild` per version leaf + +--- + +## Open Questions / Future Decisions + +1. Can the ReplayMod preprocessor be made to work with RetroFuturaGradle (instead of Loom)? Needs prototyping. +2. Should version leaves share a single `build.gradle.kts` via the preprocessor's pattern (all versions point to `../../build.gradle.kts`)? Or keep independent build files? +3. Scripting API compatibility — can the same `.js`/`.java` scripts work across versions? +4. Addon compatibility — DBC Addon, Gecko Addon, AW Addon need version-specific builds +5. Data format compatibility — can NPC save files from 1.7.10 load on 1.20.1? +6. When to add `legacy-common/` and `modern-common/` layers — set threshold at >50 duplicated files + +--- + +## Research Agent Summary (12 agents deployed) + +| Agent | Type | Key Finding | +|---|---|---| +| explore #1 | MC-dependent code | 1,424 files import net.minecraft.*, GUI is biggest hotspot (212 files) | +| explore #2 | Build system | Single-version locked, GTNH Convention + RFG | +| explore #3 | Subsystem coupling | Controllers/data are LIGHT-MC, AI/networking are HEAVY-MC | +| explore #4 | 1.7.10→1.12.2 API diff | 95% identical, only packets break, 524 files need package rename | +| explore #5 | legacy-common validation | ~100+ files use pre-Flattening patterns (metadata, IInventory) | +| librarian #1 | Porting strategies | Architectury 1.16.5+ only, preprocessor for syntactic diffs | +| librarian #2 | Real multi-version repos | Essential Mod gold standard, modstitch bridges RFG+FG, Loom consumes plain Java libs | +| librarian #3 | ForgeGradle matrix | RFG handles 1.7.10+1.12.2, FG6 for 1.16.5, ModDevGradle for 1.20.1, composite builds required | +| unspecified-high #1 | Preprocessor research | ReplayMod preprocessor syntax supports 1.7.10 (10710), but Loom doesn't; Essential wraps it | +| unspecified-high #2 | Real multi-version mods | **Nobody shares code between 1.7.10 and modern** — CustomNPC+ approach is genuinely novel | +| unspecified-high #3 | Write MULTI_VERSION_RESEARCH.md | Compiled all external research to permanent doc | +| unspecified-high #4 | Write MC_COUPLING_ANALYSIS.md | Compiled all coupling data to permanent doc | +| Oracle | Architecture strategy | Two-family monorepo (partially overridden by evidence) | diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..0e6150f39 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,137 @@ +# AGENTS.md — CustomNPC-Plus + +## ⚠️ AGENT CONTEXT — Read First +**All documents below this line are created BY and FOR agents operating on this codebase.** +This is the master architecture reference. Before any work: +1. Read `.AGENTS/SESSION_MEMORY.md` — strategic vision, roadmap, critical decisions +2. Read `.AGENTS/CORE_PLAN.md` — platform abstraction design and naming conventions +3. Skim `.AGENTS/FORBIDDEN_PRACTICES.md` — architectural guardrails (NEVER violate these) +4. Reference `.AGENTS/MC_COUPLING_ANALYSIS.md` — what's MC-dependent, migration priority + **If working on multi-version porting**, also read: +- `.AGENTS/MULTI_VERSION_RESEARCH.md` — real-world strategies, tools, pitfalls +- `.AGENTS/BUILD_SYSTEM.md` — Gradle architecture, version-specific build requirements + +-**IMPORTANT** ALWAYS CHECK OUT `SESSION_MEMORY.md` WHEN WORKING ON MIGRATING/UPPORTING THIS PROJECT TO LATER MINECRAFT VERSIONS. +--- + + +## What This Is +Minecraft 1.7.10 Forge mod. NPC customization, AI, quests, abilities, scripting (JS/Java), economy. +~2,170 source files. Entry: `CustomNpcs.java` (`@Mod`). Packages: `noppes.npcs.*`, `kamkeel.npcs.*`. + +## Module Structure + +| Module | Path | Purpose | MC Dependencies | +|---|---|---|---| +| **platform-api** | `platform-api/` | Interfaces only (`PlatformService`, `NBTFactory`, `INBTCompound`) | None | +| **core** | `core/` | MC-free game logic: controllers, data classes, enums, utils | None (depends on platform-api) | +| **mc1710** (root) | `src/main/java/` | MC 1.7.10 implementations: entities, GUI, packets, wrappers | Full Forge/MC | +| **gradle-plugins** | `gradle-plugins/` | TypeScript `.d.ts` generator from Java API sources | Gradle only | +| **API** (submodule) | `src/api/java/` | Scripting API interfaces (`IPlayer`, `ICustomNpc`, `IWorld`, etc.) | Git submodule — run `./gradlew updateAPI` | + +**Dependency flow:** `platform-api` ← `core` ← `mc1710 (root src)` + +## Architecture Pattern +- **Split-package shadow**: Core class in `core/` + mc1710 version in `src/main/java/` same package. mc1710 shadows core at compile time (adds `implements IFaction`, SyncController calls, MC-specific methods). +- **Platform abstraction**: `PlatformServiceHolder.get()` → `PlatformService` impl registered at mod init. +- **NBT wrapping**: `NBTTagCompound` → `INBTCompound`, `new NBTTagCompound()` → `NBT.compound()`. +- **Entity wrapping**: `EntityPlayer` → `IUser` (platform-api), mc1710 provides `PlayerWrapper`. + +## Subsystem Location Map + +| Subsystem | Primary Path(s) | Key Files | +|---|---|---| +| **NPC Entities** | `src/.../noppes/npcs/entity/` | `EntityNPCInterface.java`, `EntityCustomNpc.java` | +| **NPC Data** | `src/.../noppes/npcs/Data*.java` | `DataAI`, `DataDisplay`, `DataStats`, `DataAbilities`, `DataAdvanced` | +| **AI System** | `src/.../noppes/npcs/ai/` | 28 AI tasks (`EntityAI*.java`), `CombatHandler`, `pathfinder/`, `selector/`, `target/` | +| **Quest System** | `src/.../noppes/npcs/quests/` | `QuestItem`, `QuestKill`, `QuestLocation`, `QuestDialog`, `QuestManual` | +| **Quest Controller** | `src/.../noppes/npcs/controllers/` | `QuestController.java`, `PlayerQuestController.java` | +| **Dialog System** | `src/.../noppes/npcs/controllers/` | `DialogController.java` + data in `controllers/data/` | +| **Faction System** | `core/.../noppes/npcs/controllers/` | `FactionController.java`, `Faction.java` (migrated to core) | +| **Ability System** | `src/.../kamkeel/npcs/controllers/` | `AbilityController.java`, `EnergyController.java`, `TelegraphController.java` | +| **Ability Entities** | `src/.../kamkeel/npcs/entity/` | `EntityAbility*.java`, `EntityEnergy*.java` (13 entity types) | +| **Scripting Engine** | `src/.../noppes/npcs/controllers/` | `ScriptController.java`, `ScriptContainer.java`, `ScriptHookController.java` | +| **Scripting Wrappers** | `src/.../noppes/npcs/scripted/` | `ScriptWorld`, `ScriptBlock`, `NpcAPI`, `event/`, `entity/`, `item/`, `gui/` | +| **Economy/Auction** | `src/.../noppes/npcs/controllers/` | `AuctionController.java`, `MarketRegistry.java` | +| **Roles & Jobs** | `src/.../noppes/npcs/roles/` | `RoleTrader`, `RoleBank`, `RoleFollower`, `JobGuard`, `JobBard`, etc. | +| **Profile System** | `src/.../kamkeel/npcs/controllers/` | `ProfileController.java` | +| **Animation** | `src/.../noppes/npcs/controllers/` | `AnimationController.java` | +| **Commands** | `src/.../kamkeel/npcs/command/` | Hierarchical `/kam` system. `CommandKamkeel.java` is root. | +| **Config** | `src/.../noppes/npcs/config/` | `ConfigMain`, `ConfigClient`, `ConfigScript`, `ConfigMarket`, `ConfigEnergy`, etc. | +| **Blocks** | `src/.../noppes/npcs/blocks/` | 34 block types + `tiles/` | +| **Items** | `src/.../noppes/npcs/items/` | Weapons, linked items, scripted items | +| **Networking** | `src/.../kamkeel/npcs/network/` | `PacketHandler.java` + `SyncController.java` | +| **Mixins** | `src/.../noppes/npcs/mixin/` | Forge/MC mixins | +| **Client** | `src/.../noppes/npcs/client/` + `src/.../kamkeel/npcs/client/` | GUI, rendering, overlays | +| **Compat** | `src/.../noppes/npcs/compat/` | Cross-mod compatibility | +| **TypeScript Gen** | `gradle-plugins/src/` | Gradle plugin: Java API → `.d.ts` definitions | + +## Core Migration Status +- **183 files** abstracted to `core/` + `platform-api/` out of ~1,810 total +- Migrated: Faction, Magic, Transport, Tag, GlobalData controllers + 60+ data classes +- See `CORE_MIGRATION_STATUS.md` for per-file blocker analysis +- See `CORE_PLAN.md` for migration roadmap and naming conventions + +## NEVER / DO NOT Rules + +1. **NEVER touch script system for migration** — `ScriptHandler`, `ScriptContainer`, all `I*Script*` interfaces, Action framework. Deeply coupled, not yet planned. +2. **NEVER touch Ability.java or ability type classes for migration** — 30+ MC imports, deeply coupled to Entity/World/DamageSource. +3. **NEVER touch entity classes for migration** — extend MC Entity directly, must stay platform-side. +4. **NEVER touch recipe system for migration** — `RecipeCarpentry` extends `ShapedRecipes`, `RecipeController` uses `CraftingManager`. +5. **NEVER import MC classes in `core/` or `platform-api/`** — use platform interfaces only. +6. **NEVER import wrapper classes in `core/`** — only interfaces from `platform-api/`. +7. **Platform interface naming**: Short `I` prefix, no `Platform` in name (`IUser` not `IPlatformUser`). +8. **MC1710 wrapper naming**: `[Thing]Wrapper` — no `MC1710` prefix. +9. **Scripting API** (`IPlayer`, `IEntity`, `ICustomNpc`) is a **separate concern** from platform interfaces — different package, different purpose. Do not conflate. +10. **Split-package rule**: When a class exists in both `core/` and `src/main/java/` with same package, mc1710 version shadows core. Never break this contract. + +## Build & Run + +```bash +# First-time setup (pulls API submodule) +./gradlew updateAPI + +# Build (includes TypeScript .d.ts generation) +./gradlew build + +# Build without mixin embedding +./gradlew buildNoMixin + +# Run game +./gradlew runClient +./gradlew runServer + +# Run without Nashorn scripting engine +./gradlew runClientNoNashorn +./gradlew runServerNoNashorn + +# Generate TypeScript definitions only +./gradlew generateTypeScriptDefinitions + +# IDE setup (IntelliJ) +./gradlew genIntellijRuns +# Then add args: --tweakClass org.spongepowered.asm.launch.MixinTweaker --mixin customnpcs.mixins.json +``` + +**Build system**: GTNH Convention plugin + RetroFuturaGradle. Java 8 target (core/platform-api), Java 8 compile with JDK 8 (mc1710). + +## Convention Summary +- Two root packages: `noppes.npcs.*` (original), `kamkeel.npcs.*` (additions) +- Controllers are singletons in `controllers/` packages — instantiated at server start +- Data classes use NBT serialization (`readNBT`/`writeNBT` pattern with `INBTCompound`) +- Commands: hierarchical under `/kam` — each subcommand is a `CommandKamkeelBase` subclass +- Script hooks: 154+ events across NPC, Player, Block, Item, Quest, Dialog, Ability, Auction, Animation +- Config: separate config classes per domain (`ConfigMain`, `ConfigScript`, `ConfigMarket`, etc.) +- Async saves: `CustomNPCsThreader` thread pool for controller persistence +- API submodule: `src/api/java/` — must `git submodule update --init --recursive` before build + +## Key Reference Files +- `SESSION_MEMORY.md` — **Multi-version porting strategy**, owner's vision, corrected architecture, research synthesis +- `MULTI_VERSION_RESEARCH.md` — External research: real multi-version mod repos, build tools, preprocessor details +- `MC_COUPLING_ANALYSIS.md` — Quantified MC-dependency breakdown by subsystem (1,424 files analyzed) +- `FORBIDDEN_PRACTICES.md` — Anti-patterns, deprecated components, architectural guardrails +- `CORE_MIGRATION_STATUS.md` — Detailed per-file blocker analysis for core migration +- `CORE_PLAN.md` — Migration roadmap, naming conventions, architecture decisions +- `CHANGELOG.md` — Version history +- `todo.txt` — Pending tasks +- `dts-patches/` — Manual patches applied to generated TypeScript definitions diff --git a/core/AGENTS.md b/core/AGENTS.md new file mode 100644 index 000000000..3dd66ee32 --- /dev/null +++ b/core/AGENTS.md @@ -0,0 +1,55 @@ +# core/ — MC-Free Game Logic + +Core contains version-independent game logic: controllers, data classes, constants, utilities. +It depends only on `platform-api/` interfaces — **never** on MC classes, wrappers, or Forge. + +## Structure + +``` +noppes/npcs/controllers/ → FactionController, MagicController, TransportController, etc. +noppes/npcs/controllers/data/ → Faction, Magic, Tag, TransportLocation, Frame, Lines, etc. +noppes/npcs/constants/ → 40+ enums (EnumRoleType, EnumQuestType, EnumAnimation, etc.) +noppes/npcs/core/ → NBT factory, CoreConfig +noppes/npcs/util/ → ValueUtil, LRUHashMap, CacheHashMap, MillisTimer +noppes/npcs/ → NBTTags.java +kamkeel/npcs/ → Additional controllers, network enums, utilities, developer registry +``` + +## Forbidden Imports + +Core code must **never** import: +- `net.minecraft.*`, `cpw.mods.*`, `net.minecraftforge.*`, `org.spongepowered.*` +- Wrapper classes from `src/main/java/` (mc1710 module) +- Only allowed: `java.*`, `javax.*`, `noppes.npcs.*`, `kamkeel.npcs.*` (from core + platform-api) + +## Key Patterns + +| MC Concept | Core Replacement | +|---|---| +| `new NBTTagCompound()` | `NBT.compound()` | +| `CompressedStreamTools` | `PlatformServiceHolder.get().readCompressedNBT()` | +| `LogWriter` | `PlatformServiceHolder.get().logError()` | +| `CustomNpcs.getWorldSaveDirectory()` | `PlatformServiceHolder.get().getWorldSaveDirectory()` | +| `EntityPlayer` param | `IUser` (via platform-api) | +| `EntityNPCInterface` param | `INpc` (via platform-api, not yet created) | + +## Split-Package Shadows + +Core classes share packages with mc1710 classes. The mc1710 version can: +- Add `implements IFaction`, `implements IFactionHandler` (scripting API) +- Re-add `SyncController` calls for network sync +- Override methods that need `ItemStack`, `EntityPlayer`, etc. + +## DO NOT TOUCH (Forbidden Zones) + +- **Script system** — ScriptHandler, ScriptContainer, I*Script*, Action framework +- **Ability system** — Ability.java and ability type classes (30+ MC imports) +- **Entity classes** — extend MC Entity directly +- **Recipe system** — extends MC recipe classes + +## Adding New Core Code + +1. Ensure zero MC imports — use platform-api interfaces +2. NBT via `NBT.compound()` / `NBT.list()`, file I/O via `PlatformServiceHolder` +3. Stub out methods needing MC types — mc1710 shadow adds them +4. Follow existing package structure (controllers → `controllers/`, data → `controllers/data/`) diff --git a/core/src/main/java/AGENTS.md b/core/src/main/java/AGENTS.md new file mode 100644 index 000000000..a71e18dce --- /dev/null +++ b/core/src/main/java/AGENTS.md @@ -0,0 +1,97 @@ +# AGENTS.md — core/ (Platform-Abstracted Game Logic) + +## What This Is +MC-free module containing game logic, enums, data classes, and controllers that compile without +Minecraft imports. Uses `platform-api/` interfaces for MC operations. 183 files migrated so far. +Dependency: `platform-api` ← `core` ← `mc1710 (root src)`. + +## Split-Package Shadow Pattern +Core classes and mc1710 classes share the **same package**. At compile time, mc1710 versions shadow +core by adding MC-specific functionality: + +``` +core/ Faction.java → Pure data + INBTCompound serialization +src/ Faction.java → adds `implements IFaction`, SyncController calls, EntityPlayer methods +``` + +**Rule**: Core class must compile independently. mc1710 version extends/overrides to add MC logic. + +## Module Structure + +### constants/ (42 files) +All game enums. No MC imports. Domains: +- **AI**: `AiMutex`, `EnumAnimation`, `EnumCombatPolicy`, `EnumMovingType`, `EnumNavType`, `EnumStandingType` +- **Quest**: `EnumQuestType`, `EnumQuestRepeat`, `EnumQuestCompletion` +- **Dialog**: `EnumAvailabilityDialog`, `EnumAvailabilityFaction`, `EnumAvailabilityFactionType`, `EnumAvailabilityQuest`, `EnumOptionType` +- **NPC**: `EnumJobType`, `EnumRoleType`, `EnumCompanionJobs`, `EnumCompanionStage` +- **Display**: `EnumTextureType`, `EnumBannerVariant`, `EnumDiagramLayout`, `EnumScrollData` +- **Economy**: `EnumAuctionPage`, `EnumAuctionSort`, `EnumStockReset`, `EnumTradeSlotType` +- **Party**: `EnumPartyExchange`, `EnumPartyObjectives`, `EnumPartyRequirements` +- **System**: `EnumGuiType`, `EnumPlayerData`, `EnumPlayerPacket`, `EnumScriptType`, `EnumProfileSync`, `EnumCategoryType` +- **Misc**: `EnumBardInstrument`, `EnumDayTime`, `EnumParticleType`, `MarkType`, `NBTTypes`, `EnumNpcToolMaterial` + +### controllers/ (8 files) +Migrated controller singletons using `INBTCompound` instead of `NBTTagCompound`: + +| Controller | Status | +|---|---| +| `FactionController` | Fully migrated. Load/save via `PlatformServiceHolder.get()` | +| `MagicController` | Migrated with TODO stubs for ItemStack methods | +| `TransportController` | Fully migrated | +| `GlobalDataController` | Migrated. Async save via `CustomNPCsThreader` | +| `TagController` | Fully migrated | +| `ServerTagMapController` | Migrated (clone folder management) | +| `CategoryManager` | Utility — filesystem category operations | +| `APIRegistry` | Simple name→URL map, no MC deps | + +### controllers/data/ (33 files) +Migrated data classes. Key groups: +- **Faction**: `Faction`, `Category` (base category class) +- **Magic**: `Magic`, `MagicCycle`, `MagicEntry`, `MagicAssociation`, `MagicData` +- **Transport**: `TransportCategory`, `TransportLocation` +- **Tags**: `Tag`, `TagMap` +- **Profile**: `ProfileOptions`, `ProfileInfoEntry` +- **Animation**: `Frame`, `FramePart`, `HitboxData`, `TintData`, `ItemDisplayData` +- **Dialog**: `DialogColorData`, `DialogImage`, `Line`, `Lines` +- **Player data fragments**: `PlayerDialogData`, `PlayerTransportData`, `PlayerEffectData`, `PlayerEffect`, `AbilityHotbarData`, `EffectKey` +- **Economy**: `AuctionFilter`, `TraderStock`, `SkinOverlay`, `InnDoorData` +- **Misc**: `CloneFolder`, `PartyOptions` + +### util/ (6 files) +- `CustomNPCsThreader` — Thread pool for async controller saves +- `CacheHashMap` — TTL-based cache (used by PlayerDataController) +- `LRUHashMap` — Least-recently-used eviction map +- `ValueUtil` — Numeric clamping utilities +- `MillisTimer` — Simple timing +- `SizeOfObjectUtil` — Object size estimation + +### kamkeel/ additions in core +- `controllers/data/ability/` — Ability enums (`AbilityPhase`, `HitType`, `TargetFilter`, `TargetingMode`, etc.) + data classes (`ProjectileData`, `EnergyBarrierData`, `EnergyHomingData`, etc.) +- `controllers/data/attribute/` — `AttributeDefinition`, `PlayerAttribute`, `PlayerAttributeMap`, `AttributeValueType` +- `controllers/data/profile/` — `Slot`, `ProfileOperation`, `EnumProfileOperation`, `ProfileInfoEntry` +- `controllers/data/telegraph/` — `Telegraph`, `TelegraphType` +- `network/enums/` — 9 network enum types (`EnumSyncType`, `EnumSyncAction`, `EnumDataPacket`, etc.) +- `util/` — `CNPCDebug`, `FileNameHelper`, `TextSplitter` +- `developer/` — `Developer` registry + +## Platform Abstraction +Core uses `platform-api/` interfaces: +- `INBTCompound` / `INBTList` instead of `NBTTagCompound` / `NBTTagList` +- `NBT.compound()` / `NBT.list()` factory methods instead of `new NBTTagCompound()` +- `PlatformServiceHolder.get()` for file I/O, logging, world save directory access +- `IUser` for player references (not yet widely implemented — blocks many migrations) + +## Migration Status +183/~1810 files migrated. Blockers for remaining classes: +- **IUser wrapper** needed for Availability, Dialog, Quest migrations +- **IStack wrapper** needed for item-dependent classes (inventory, trading, recipes) +- **Entity abstractions** not planned — entities stay mc1710-side permanently +- **Script system** not planned for migration — deeply coupled to engines + +See `CORE_MIGRATION_STATUS.md` and `CORE_PLAN.md` at project root for details. + +## Forbidden +- **NEVER import net.minecraft.* in core/** — use platform-api interfaces only +- **NEVER import wrapper classes in core/** — only interfaces from platform-api/ +- **NEVER break split-package shadow** — core class must compile alone, mc1710 adds MC logic +- **NEVER add IUser/IStack to core until platform-api interfaces are finalized** diff --git a/platform-api/AGENTS.md b/platform-api/AGENTS.md new file mode 100644 index 000000000..1eceb8a75 --- /dev/null +++ b/platform-api/AGENTS.md @@ -0,0 +1,39 @@ +# platform-api/ — Interface Definitions + +MC-free interfaces consumed by `core/`. Each MC version module provides implementations. + +## Structure + +``` +kamkeel/npcs/platform/ → PlatformService, PlatformServiceHolder, annotations +noppes/npcs/api/ → Entity, item, handler, NBT interfaces +noppes/npcs/platform/nbt/ → NBTFactory, NBTIO abstractions +``` + +## Naming Conventions + +- **Short `I` prefix**: `IMob`, `ILiving`, `IUser`, `INpc`, `IStack`, `IGameWorld`, `IDamage` +- **No `Platform` prefix** on interfaces — only `PlatformService` itself uses it +- **Scripting API** (`IPlayer`, `IEntity`, `ICustomNpc`) is in the same package but separate concern + +## Key Interfaces + +| Interface | Wraps | Extends | +|---|---|---| +| `IMob` | Entity | — | +| `ILiving` | EntityLivingBase | `IMob` | +| `IUser` | EntityPlayerMP | `ILiving` | +| `INpc` | EntityNPCInterface | `ILiving` *(planned)* | +| `IStack` | ItemStack | — | +| `IGameWorld` | World | — | +| `IDamage` | DamageSource | — | + +## PlatformService + +Central SPI (`kamkeel.npcs.platform.PlatformService`): NBT factory + I/O, file paths, entity/item/world wrapping, logging, environment queries, scheduling. Access: `PlatformServiceHolder.get()`. + +## Rules + +- **Interfaces only** — no MC imports allowed +- `@ClientOnly` / `@ServerOnly` annotations for side-specific contracts +- New interfaces follow `I[Thing]` naming — keep names short diff --git a/src/main/java/kamkeel/npcs/network/AGENTS.md b/src/main/java/kamkeel/npcs/network/AGENTS.md new file mode 100644 index 000000000..5561882f7 --- /dev/null +++ b/src/main/java/kamkeel/npcs/network/AGENTS.md @@ -0,0 +1,106 @@ +# AGENTS.md — Network Layer (`kamkeel.npcs.network`) + +## Purpose +All client-server packet communication. Three FML channels, ~200+ packet types, chunked large-packet support, and revision-based sync protocol. + +## Architecture Overview + +### Channels +| Channel | Name | Direction | Purpose | +|---|---|---|---| +| `REQUEST_PACKET` | `CNPC+\|Req` | Client → Server | Editor/admin operations (CRUD for dialogs, quests, factions, etc.) | +| `PLAYER_PACKET` | `CNPC+\|Player` | Client → Server | Player actions (dialog select, bank, auction, ability, profile, party) | +| `DATA_PACKET` | `CNPC+\|Data` | Server → Client | GUI data, entity sync, visual effects, ability state, overlays | + +### Core Classes + +| Class | Purpose | +|---|---| +| `PacketHandler` | Singleton. Registers all packets, routes incoming packets, provides send API | +| `AbstractPacket` | Base class for all packets. Defines `sendData()`/`receiveData()`, channel, type enum | +| `LargeAbstractPacket` | Extends `AbstractPacket`. Chunks data into 10KB segments with UUID reassembly | +| `PacketChannel` | Wraps an FML channel + registered packet map (ordinal → packet instance) | +| `PacketClient` | Client-side convenience: `sendClient(packet)` → `PacketHandler.Instance.sendToServer()` | +| `PacketUtil` | Verification utilities: permission checks, item validation, script handling | + +### Packet Enums (`enums/`) +Each channel has a corresponding enum whose ordinal is the packet ID: +- `EnumRequestPacket` — ~233 values for all editor/admin operations +- `EnumPlayerPacket` — ~45 values for player-initiated actions +- `EnumDataPacket` — ~91 values for server-to-client data +- `EnumChannelType` — `REQUEST`, `PLAYER`, `DATA`, `INFO` +- `EnumSyncType` — Data types for bulk sync: factions, dialogs, quests, recipes, effects, abilities +- `EnumSyncAction` — `RELOAD`, `UPDATE`, `REMOVE` + +## Packet Lifecycle + +### Defining a New Packet +1. Add enum value to the appropriate `Enum*Packet` +2. Create class extending `AbstractPacket` (or `LargeAbstractPacket` for >10KB data) +3. Implement: `getType()` → enum value, `getChannel()` → channel constant, `sendData(ByteBuf)`, `receiveData(ByteBuf, EntityPlayer)` +4. Register in `PacketHandler.register*Packets()` via `CHANNEL.registerPacket(new MyPacket())` + +### Sending +``` +// Client → Server +PacketClient.sendClient(new MyRequestPacket(...)); +// or: PacketHandler.Instance.sendToServer(packet); + +// Server → Client +PacketHandler.Instance.sendToPlayer(packet, playerMP); +PacketHandler.Instance.sendToAll(packet); +PacketHandler.Instance.sendToDimension(packet, dimId); +PacketHandler.Instance.sendTracking(packet, entity); // 60-block radius +``` + +### Receiving +`PacketHandler.handlePacket()` reads channel type ordinal + packet ID ordinal from buffer, looks up the registered `AbstractPacket`, and calls `receiveData(buf, player)`. + +Server-side checks before dispatch: +- `ConfigMain.OpsOnly` → rejects non-ops for REQUEST channel +- `abstractPacket.getPermission()` → `CustomNpcsPermissions` check +- `abstractPacket.needsNPC()` → requires `NoppesUtilServer.getEditingNpc(player)` to be non-null + +Client-side receive methods are annotated `@SideOnly(Side.CLIENT)`. + +## Large Packet Protocol +`LargeAbstractPacket` handles data exceeding FML's packet size limit: +1. `generatePackets()` serializes full data via `getData()`, splits into 10KB chunks +2. Each chunk includes: UUID, total size, offset, chunk count, chunk bytes +3. Receiver reassembles in `ConcurrentHashMap` +4. On complete assembly → calls `handleCompleteData(ByteBuf, EntityPlayer)` + +Used by: `SyncPacket`, `SyncEffectPacket`, `ScrollDataPacket`, `ScrollListPacket`, `GuiDataPacket`, `PartyDataPacket`, `ClonerPacket` + +## Sync Protocol (`SyncController`) +Revision-based sync ensures clients have current data without redundant transfers: +1. On player login → server sends full sync for all `EnumSyncType` categories +2. Each data type has a revision counter (incremented on server-side changes) +3. On data change → server sends incremental `SyncPacket` with action (`UPDATE`/`REMOVE`/`RELOAD`) +4. Client stores synced data in `ClientCacheHandler` +5. Player can send `SyncRevisionInfoPacket` to report current revisions → server sends only deltas + +### Synced Data Types +Factions, Dialogs, Dialog Categories, Quests, Quest Categories, PlayerData, Magic, Magic Cycles, Workbench/Carpentry/Anvil Recipes, Custom Effects, Custom Abilities, Chained Abilities + +## GUI ↔ Packet Integration +1. Server sends `GuiOpenPacket` → client opens GUI +2. GUI sends REQUEST packet to fetch data (e.g., `DialogGetPacket`) +3. Server processes, sends `GuiDataPacket` (NBT) or `ScrollDataPacket` (list data) back +4. Client GUI implements `IGuiData.setGuiData()` or `IScrollData.setData()` to populate +5. On save, GUI sends save REQUEST packet (e.g., `DialogSavePacket`) with serialized NBT + +## Packet Subdirectories (`packets/`) + +| Directory | Channel | Content | +|---|---|---| +| `request/` | REQUEST | ~25 subdirs: dialog, quest, faction, script, ability, animation, clone, etc. | +| `player/` | PLAYER | Player actions: ability, profile, party, customgui, item, auction | +| `data/` | DATA | Server pushes: gui, npc, script, energy, telegraph, ability, large | + +## Key Conventions +- **Never add packets without enum entries** — ordinal mismatch breaks all networking +- **Enum ordering is permanent** — never reorder or remove enum values, only append +- **`@SideOnly(Side.CLIENT)`** on `receiveData()` for DATA packets to prevent server-side class loading +- **Permission-gated**: REQUEST packets can declare `getPermission()` for fine-grained access control +- **NPC context**: REQUEST packets can declare `needsNPC() = true` to require an active NPC editing session diff --git a/src/main/java/noppes/npcs/AGENTS.md b/src/main/java/noppes/npcs/AGENTS.md new file mode 100644 index 000000000..edff834b8 --- /dev/null +++ b/src/main/java/noppes/npcs/AGENTS.md @@ -0,0 +1,75 @@ +# AGENTS.md — noppes.npcs (NPC Core Logic) + +## What This Is +MC1710 NPC entity system: mod entry point, NPC data models, AI tasks, entity types, roles/jobs, +event dispatching, server lifecycle, and utility classes. ~37 root files + 4 major subdirectories. + +## Key Files + +| File | Purpose | +|---|---| +| `CustomNpcs.java` | `@Mod` entry point. Registers entities, controllers, event buses, platform service. Server lifecycle via `@EventHandler` methods. | +| `EntityNPCInterface` (entity/) | Base class for ALL NPC entities. Owns Data* classes. Handles NBT save/load, AI task registration, combat. | +| `EventHooks.java` | Central event dispatcher. Static methods route events to global scripts, entity handlers, then `NpcAPI.EVENT_BUS`. 1400+ lines, 154+ hook types. | +| `ServerEventsHandler.java` | Forge `@SubscribeEvent` handler: entity interactions (wand/cloner), damage processing, quest updates, world saves. | +| `ServerTickHandler.java` | Server tick loop: player login/logout sync, periodic saves, controller updates. | + +## Data* Classes Pattern +Each NPC has 6 data containers owned by `EntityNPCInterface`: + +| Class | Configures | +|---|---| +| `DataAI` | Movement type, combat tactics (EnumNavType, EnumCombatPolicy), pathfinding, flying, sprint, door interaction | +| `DataStats` | HP, damage, armor, resistances, attack speed, projectile properties, respawn | +| `DataDisplay` | Skin, model type, name, overlays, tint, hitbox scale, visible body parts | +| `DataAbilities` | Ability slots, cooldowns, phase execution. Extends `AbstractDataAbilities` | +| `DataAdvanced` | Role/job instances, dialog lines, faction settings, sounds, transform | +| `DataInventory` | Equipment slots, drops, loot table. Implements `IInventory` | + +**Pattern**: All use `readToNBT(NBTTagCompound)` / `writeToNBT(NBTTagCompound)` serialization. +Values loaded in `EntityNPCInterface.readEntityFromNBT`, flow to entity attributes via `SharedMonsterAttributes`. + +## Subdirectories + +### ai/ (29 files) +MC EntityAIBase tasks registered on NPC entity. Key groups: +- **Combat**: `EntityAIAttackTarget`, `CombatHandler`, `EntityAIRangedAttack`, `EntityAILeapAtTargetNpc` +- **Tactical**: `EntityAIAmbushTarget`, `EntityAIDodgeShoot`, `EntityAIOrbitTarget`, `EntityAIZigZagTarget`, `EntityAIStalkTarget`, `EntityAIPounceTarget`, `EntityAISprintToTarget` +- **Navigation**: `EntityAIMovingPath`, `EntityAIWander`, `EntityAIReturn`, `EntityAIWaterNav`, `EntityAIFollow` +- **Behavior**: `EntityAIPanic`, `EntityAIAvoidTarget`, `EntityAIFindShade`, `EntityAIMoveIndoors`, `EntityAIBustDoor` +- **Utility**: `EntityAILook`, `EntityAIWatchClosest`, `EntityAIAnimation`, `EntityAIJob`, `EntityAIRole`, `EntityAITransform` +- Also: `pathfinder/`, `selector/`, `target/` subdirs for pathfinding and target selection. + +### entity/ (13 files + old/) +- `EntityNPCInterface` — abstract base, all NPCs extend this +- `EntityCustomNpc` — primary user-created NPC type +- Specialized: `EntityNPCFlying`, `EntityNPCGolem`, `EntityNpcDragon`, `EntityNpcSlime`, `EntityNpcCrystal`, `EntityNpcPony` +- Support: `EntityProjectile`, `EntityMagicProjectile`, `EntityChairMount`, `EntityDialogNpc`, `EntityFakeLiving` +- `old/` — 18 legacy NPC model classes (human, dwarf, elf, orc, etc.) + +### roles/ (19 files) +Two interfaces: `RoleInterface` (interactive function) + `JobInterface` (background task). +- **Roles**: Trader, Bank, Follower, Companion, Transporter, Postman, Innkeeper, Auctioneer, Mount +- **Jobs**: Guard, Healer, Bard, ItemGiver, Spawner, Conversation, ChunkLoader, Follower + +## Event Dispatch Flow +``` +Forge/Game Event → ServerEventsHandler / Script*EventHandler + → EventHooks.onXxx() (static) + → ScriptController global scripts + → Entity-specific IScriptHandler.callScript() + → NpcAPI.EVENT_BUS.post() (for addons) +``` + +## Integration Points +- **Controllers**: `CustomNpcs.java` initializes all controllers in `setAboutToStart()`, saves in `stopped()` +- **Scripting**: `ScriptPlayerEventHandler`, `ScriptItemEventHandler`, `ScriptForgeEventHandler` bridge Forge events to scripts +- **Platform**: `PlatformServiceHolder.set(new MC1710PlatformService())` in pre-init +- **Networking**: `PacketHandler` for client-server sync, `SyncController` for data push +- **Config**: `LoadConfiguration.init()` loads modular configs, syncs to `CoreConfig` + +## Forbidden +- **Do NOT migrate entity classes to core** — extend MC Entity directly, must stay platform-side +- **Do NOT migrate Data* classes yet** — depend on EntityNPCInterface, NBTTagCompound, SharedMonsterAttributes +- **Do NOT modify EventHooks dispatch order** — global → entity → bus ordering is contractual for addons +- **Do NOT mix NBTTags utility with platform-api INBTCompound** — NBTTags is MC-side only diff --git a/src/main/java/noppes/npcs/client/AGENTS.md b/src/main/java/noppes/npcs/client/AGENTS.md new file mode 100644 index 000000000..ae5c1e750 --- /dev/null +++ b/src/main/java/noppes/npcs/client/AGENTS.md @@ -0,0 +1,97 @@ +# AGENTS.md — Client Layer (`noppes.npcs.client` + `kamkeel.npcs.client`) + +## Purpose +Client-side rendering, event handling, caching, and utilities. Everything here is `@SideOnly(Side.CLIENT)`. + +## Entry Point +`ClientProxy` (extends `CommonProxy`) — registered via `@Mod`. Handles: +- Entity renderer registration (`RenderingRegistry.registerEntityRenderingHandler`) +- Key bindings (`ClientRegistry.registerKeyBinding`) +- GUI opening (`openGui(npc, EnumGuiType, x, y, z)` → maps type to GUI class) +- Client commands, resource listeners, tick handlers + +## Rendering Architecture + +### NPC Entity Renderers (`noppes.npcs.client.renderer/`) + +| Renderer | Entity | Model | +|---|---|---| +| `RenderCustomNpc` | `EntityCustomNpc` | Delegates to entity-specific renderers or `ModelMPM` | +| `RenderNPCInterface` | Base for all NPC renderers | Handles texture binding, overlays, scaling, Gecko hook | +| `RenderNPCHumanMale` | `EntityNPCGolem` | `ModelBiped` variant | +| `RenderNPCPony` | `EntityNpcPony` | Pony model | +| `RenderNpcDragon` | `EntityNpcDragon` | Dragon model | +| `RenderNpcSlime` | `EntityNpcSlime` | Slime model | +| `RenderNpcCrystal` | `EntityNpcCrystal` | Crystal model | +| `RenderCNPCPlayer` | Player entities | Skin overlay support | +| `RenderCNPCHand` | First-person hand | Hand rendering | +| `RenderProjectile` | `EntityProjectile` | NPC projectiles | + +### Rendering Pipeline +1. **Entity spawn** → Forge dispatches to registered renderer +2. **Renderer selection** → `RenderCustomNpc` checks for addon models (Gecko/DBC), delegates or uses `ModelMPM` +3. **Texture binding** → `RenderNPCInterface.getEntityTexture()`: skin type 0=custom, 1=player profile, 2/3=URL, fallback to Steve/Alex +4. **Model rendering** → `ModelMPM` with modular parts (body, limbs, overlays) +5. **Post-render** → Skin overlays via GL blending, glow effects, `MarkRenderer` for quest markers +6. **Animation** → `AnimationHelper` computes UV offsets for animated textures + +### Addon Integration +- **Gecko Addon**: `GeckoAddonClient.Instance.geckoRenderModel()` — bypasses standard rendering for Blockbench models +- **DBC Addon**: `DBCClient` — Dragon Block C model/animation support +- Addons are checked via reflection/instance nullability, no hard dependency + +### Ability Entity Renderers (`kamkeel.npcs.client.renderer/`) + +| Renderer | Entity | +|---|---| +| `RenderEnergyOrb` | `EntityAbilityOrb` | +| `RenderEnergyDisc` | `EntityAbilityDisc` | +| `RenderEnergyBeam` | `EntityAbilityBeam` | +| `RenderEnergyLaser` | `EntityAbilityLaser` | +| `RenderEnergyDome` | `EntityEnergyDome` | +| `RenderEnergyPanel` | `EntityEnergyPanel` | +| `RenderEnergySlicer` | `EntityEnergySlicer` | +| `RenderEnergyExplosion` | `EntityEnergyExplosion` | +| `RenderSweeper` | `EntityEnergySweeper` | +| `RenderZone` | `EntityAbilityZone` | +| `TelegraphRenderer` | Telegraph preview overlays | +| `EnergyChargePreviewRenderer` | Charge-up preview effects | + +All extend `RenderEnergy` base class or `Render` directly. `lightning/` subdirectory handles lightning VFX. + +### Block Renderers (`noppes.npcs.client.renderer.blocks/`) +~22 block renderers extending `BlockRendererInterface` (which extends `TileEntitySpecialRenderer`). Each handles a specific decorative block type (banners, chairs, signs, etc.). + +### Model System (`noppes.npcs.client.model/`) +- `ModelMPM` — Main humanoid model with configurable parts +- `ModelNPCMale` — Male NPC variant +- `ModelPonyArmor` / `ModelSkirtArmor` — Armor model variants +- `model/part/` — Modular body parts: tails (7 types), horns (4 types), legs (4 types), wings, ears, hair, beard, claws, fins, snout, skirt, breasts +- `model/util/` — Rendering helpers: `ModelScaleRenderer`, `ModelPlaneRenderer`, `Model2DRenderer`, `ModelPartInterface` + +## Other Client Components + +| File | Purpose | +|---|---| +| `ClientProxy` | Entry point: renderer registration, GUI dispatch, client init | +| `NoppesUtil` | GUI data routing: `setGuiData()`, `setScrollData()`, `requestOpenGUI()` | +| `ClientEventHandler` | Forge client event hooks (render, tick, input) | +| `ClientTickHandler` | Per-tick client logic | +| `ClientCacheHandler` | Client-side data cache for synced controller data | +| `ClientAbilityState` | Tracks player ability state on client | +| `KeyPressHandler` | Hotkey processing | +| `RenderChatMessages` | Custom chat bubble rendering | +| `EntityUtil` | Client entity utilities | +| `AssetsBrowser` | Asset file browsing | +| `ImageDownloadAlt` | Async skin/image downloading | +| `VersionChecker` | Mod version checking | +| `TranslateUtil` | i18n helper | +| `fx/` | Particle effects | +| `key/` | Key binding definitions | +| `controllers/` | Client-side controller instances | + +## Key Conventions +- **All classes** must be `@SideOnly(Side.CLIENT)` or guarded — server will crash if client classes load server-side. +- **Texture caching**: `ClientCacheHandler` caches downloaded skins and synced data to avoid re-fetching. +- **Addon checks**: Always null-check addon instances before calling addon rendering. No hard imports. +- **GUI dispatch**: `ClientProxy.openGui()` is the sole entry point for opening GUIs from packets. diff --git a/src/main/java/noppes/npcs/client/gui/AGENTS.md b/src/main/java/noppes/npcs/client/gui/AGENTS.md new file mode 100644 index 000000000..b67760337 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/AGENTS.md @@ -0,0 +1,78 @@ +# AGENTS.md — GUI Subsystem (`noppes.npcs.client.gui`) + +## Purpose +All NPC editor, player interaction, and admin GUIs. ~80+ files, entirely `@SideOnly(Side.CLIENT)`. + +## Class Hierarchy + +| Base Class | Extends | Use Case | +|---|---|---| +| `GuiNPCInterface` | `GuiScreen` | Non-inventory GUIs (dialogs, quests, factions, AI, etc.) | +| `GuiNPCInterface2` | `GuiNPCInterface` | Tabbed NPC editor GUIs with top menu bar (`GuiNpcMenu`) | +| `GuiContainerNPCInterface` | `GuiContainer` | Inventory GUIs (trader, bank, carpentry, inv editor) | +| `GuiContainerNPCInterface2` | `GuiContainerNPCInterface` | Tabbed container GUIs with top menu | +| `SubGuiInterface` | `GuiNPCInterface` | Modal sub-GUIs (popups). Calls `ISubGuiListener.subGuiClosed()` on parent | +| `GuiModelInterface` / `2` | `GuiNPCInterface` / `2` | Model editor variants with 3D NPC preview | + +## Widget System (`util/` package) +All widgets are integer-ID based, stored in `HashMap` on the parent GUI. + +| Widget | Purpose | +|---|---| +| `GuiNpcButton` | Standard button with hover text, icon support, right-click cycling | +| `GuiNpcTextField` | Text input with int/double/float validation, paste filtering | +| `GuiNpcLabel` | Static text label | +| `GuiCustomScroll` | Scrollable list. Variants: `GuiCustomScrollCloner`, `GuiCustomScrollIcons`, `GuiCustomScrollTagged` | +| `GuiNpcSlider` | Slider control | +| `GuiScrollWindow` | Scrollable content panel | +| `GuiDiagram` | Visual diagram widget | +| `GuiMenuTopButton` / `GuiMenuSideButton` | Tab navigation buttons | +| `GuiNpcMenu` | Top menu bar for `GuiNPCInterface2` — handles tab switching | +| `GuiScriptTextArea` / `1` | Code editor with syntax highlighting, autocomplete, error detection | +| `GuiTexturedButton` / `GuiToggleButton` | Specialized button variants | + +## Callback Interfaces +GUIs implement these to receive widget events: +- `IButtonListener` — button clicks +- `ICustomScrollListener` — scroll list selection/double-click +- `ISubGuiListener` — sub-GUI closed notification +- `ITextfieldListener` / `ITextChangeListener` — text field changes +- `ISliderListener` — slider value changes +- `ITopButtonListener` — top menu tab changes +- `IGuiData` — receives `NBTTagCompound` from server via `GuiDataPacket` +- `IScrollData` — receives scroll list data from server via `ScrollDataPacket`/`ScrollListPacket` + +## GUI Opening Flow +1. Player action (right-click NPC, use item, command) triggers server-side logic +2. Server sends `GuiOpenPacket` (DATA channel) with `EnumGuiType` + coordinates +3. Client `receiveData()` calls `ClientProxy.openGui(npc, guiType, x, y, z)` +4. `ClientProxy` maps `EnumGuiType` to GUI class, calls `Minecraft.displayGuiScreen()` +5. GUI `initGui()` populates widgets, may send REQUEST packets to fetch data +6. Server responds with `GuiDataPacket`/`ScrollDataPacket` → GUI's `setGuiData()`/`setData()` + +## Directory Layout + +| Directory | Content | +|---|---| +| `util/` | Base classes, widgets, callback interfaces, script editor components | +| `mainmenu/` | NPC editor tabs: Display, Stats, AI, Advanced, Inventory | +| `advanced/` | Ability config, faction setup, dialog options, marks, sounds (~29 files) | +| `roles/` | Role/job editors: Trader, Bank, Guard, Healer, Follower, etc. | +| `player/` | Player-facing GUIs: Trader, Dialog, Quest, Auction, Mailbox, Bank | +| `global/` | Global editor GUIs (factions, quests, dialogs, recipes, transports) | +| `model/` | NPC model editor | +| `script/` | Script editor GUIs | +| `select/` | Selection dialogs | +| `hud/` | HUD configuration GUIs | +| `custom/` | Scripted custom GUI rendering | +| `customoverlay/` | Script overlay rendering | +| `builder/` | GUI builder tools | +| `item/` | Item-related GUIs | +| `questtypes/` | Quest type-specific editors | + +## Key Patterns +- **Sub-GUI stacking**: Parent GUI calls `setSubGui(subGui)` — sub-GUI renders on top. On close, `SubGuiInterface.close()` calls `parent.subGuiClosed(this)`. +- **Server data flow**: GUIs never read server state directly. They send REQUEST packets and receive data via `IGuiData.setGuiData()` or `IScrollData.setData()`. +- **Save pattern**: `GuiNPCInterface2.save()` is abstract — each tab serializes to NBT and sends a save packet. +- **Viewport panning**: `GuiNPCInterface` supports pannable GUIs via `isPannableGUI` flag. +- **Ability GUIs**: Located separately in `kamkeel.npcs.controllers.data.ability.gui.GuiAbilityInterface` — extends `GuiNPCInterface2` with 3D preview rendering. diff --git a/src/main/java/noppes/npcs/client/gui/util/script/AGENTS.md b/src/main/java/noppes/npcs/client/gui/util/script/AGENTS.md new file mode 100644 index 000000000..03f2f5b2f --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/AGENTS.md @@ -0,0 +1,60 @@ +# Script Editor Infrastructure — `client/gui/util/script/` + +## Purpose +Full-featured code editor built into Minecraft's GUI. Syntax highlighting, autocomplete, +error detection, hover info, go-to-definition, and refactoring for JS (Nashorn) and Java (Janino). + +## Entry Points +| Class | Role | +|-------|------| +| `GuiScriptTextArea` | Main editor widget — rendering, input, scrolling, keybinds. Extends `GuiNpcTextField` | +| `GuiScriptInterface` | Editor GUI frame — tab management, hook list sidebar, settings, fullscreen toggle | +| `GuiNPCEventScripts` / `GuiScriptGlobal` | NPC-specific and global/player editor subclasses | + +## Helper Components (`script/`) +`ScrollState`, `SelectionState`, `BracketMatcher`, `IndentHelper`, `CommentHandler`, +`CursorNavigation`, `UndoManager`, `SearchReplaceBar`, `GoToLineDialog`, `RenameRefactorHandler`, `FormatHelper` + +## Interpreter System (`script/interpreter/`) +7-phase tokenization pipeline (strings/comments → imports → structure → marks → conflicts → tokens → indent guides). + +| Subpackage | Contents | +|------------|----------| +| `token/` | `Token`, `TokenType` (enum with hex colors/priorities), `ScriptColorScheme` | +| `type/` | `TypeInfo`, `TypeResolver`, `ClassIndex`, `TypeChecker`, `GenericContext`, `ImportData` | +| `method/` | `MethodInfo`, `MethodSignature`, `MethodCallInfo` | +| `field/` | `FieldInfo`, `FieldAccessInfo`, `AssignmentInfo`, `EnumConstantInfo` | +| `expression/` | `ExpressionParser`, `ExpressionTypeResolver`, `TypeRules`, `CastExpressionResolver` | +| `hover/` | `TokenHoverInfo`, `TokenHoverRenderer`, `HoverState`, `GutterIconRenderer` | +| `jsdoc/` | `JSDocParser`, `JSDocInfo` — Javadoc/JSDoc parsing for hover display | +| `bridge/` | `DtsJavaBridge` — maps reflected Java methods to `.d.ts` type info for Janino scripts | + +## JavaScript Type System (`interpreter/js_parser/`) +| Class | Role | +|-------|------| +| `JSTypeRegistry` | Singleton — all types from `.d.ts`, hook signatures, global objects | +| `TypeScriptDefinitionParser` | Parses `.d.ts` → `JSTypeInfo` | +| `JSScriptAnalyzer` | Analyzes JS source for local variables, scopes, type inference | +| `DtsModScanner` | Discovers `.d.ts` from all loaded mods (`assets//api/**/*.d.ts`) | + +## Autocomplete System (`script/autocomplete/`) +| Class | Role | +|-------|------| +| `AutocompleteManager` | Orchestrates triggers, filtering, insertion | +| `AutocompleteMenu` | Dropdown rendering with icons, descriptions | +| `JSAutocompleteProvider` | JS completions from `JSTypeRegistry` + `JSScriptAnalyzer` | +| `JavaAutocompleteProvider` | Java completions from reflection + `DtsJavaBridge` | +| `weighter/` | Scoring chain: match quality, member kind, context fit, deprecation, alphabetical | + +## How It Works +1. Editor opens → `JSTypeRegistry` initialized from `.d.ts` resources +2. Text changes → `ScriptTextContainer` runs 7-phase pipeline → `ScriptLine`/`Token` lists +3. Autocomplete triggers → provider (JS or Java) generates scored completions +4. Hover → `TokenHoverRenderer` + `DtsJavaBridge` build info panels +5. Errors → `DocumentError` + `ErrorUnderlineRenderer` underline type mismatches + +## Key Design Rules +- **Dual language**: JS uses `JSTypeRegistry` (from `.d.ts`), Java uses reflection + `DtsJavaBridge` +- **Context-aware hooks**: `ScriptContext` enum determines which hooks appear in the sidebar +- **Addon loading**: `DtsModScanner` scans all Forge mods for `assets//api/*.d.ts` +- **Non-blocking**: Type resolution designed for real-time use at GUI frame rate diff --git a/src/main/java/noppes/npcs/controllers/AGENTS.md b/src/main/java/noppes/npcs/controllers/AGENTS.md new file mode 100644 index 000000000..97200ffdd --- /dev/null +++ b/src/main/java/noppes/npcs/controllers/AGENTS.md @@ -0,0 +1,89 @@ +# AGENTS.md — noppes.npcs.controllers + kamkeel.npcs.controllers + +## What This Is +Singleton controller layer managing all persistent game data: dialogs, quests, factions, scripting, +economy, player data, abilities, profiles. 33 noppes controllers + 6 kamkeel controllers + 56 data classes. + +## Singleton Pattern +All controllers use `static Instance` initialized in constructor: `DialogController.Instance = this;`. +Instantiated in `CustomNpcs.setAboutToStart()` at server start, data saved in `CustomNpcs.stopped()`. +No dependency injection — access via `ControllerName.Instance` globally. + +## Controller Registry + +### noppes.npcs.controllers (33 files) +| Controller | Purpose | Storage | +|---|---|---| +| `DialogController` | Dialog trees + categories | JSON dirs `dialogs/` | +| `QuestController` | Quest definitions + categories | JSON dirs `quests/` | +| `FactionController` | Faction definitions + standings | `factions.dat` (NBT) | +| `PlayerDataController` | Per-player data, `CacheHashMap` (1hr TTL) | `playerdata/` per-player files | +| `PlayerQuestController` | Quest progress tracking | Via PlayerData | +| `ScriptController` | Script engines (Nashorn/Janino), global handlers | `scripts/` dirs | +| `ScriptContainer` | Individual script execution context, caching | In-memory | +| `ScriptHookController` | Hook definitions (154+ types) | Static | +| `AnimationController` | Frame-based NPC animations | JSON `animations/` | +| `AuctionController` | Listings, bids, claims, tax. ConcurrentHashMap, async save every 30s | `auction.dat` | +| `BankController` | NPC bank slot configs | `bank.dat` | +| `MarketRegistry` | Currency + trader integration | Config-driven | +| `RecipeController` | Carpentry/anvil recipes | `recipes/` | +| `PartyController` | Player grouping, quest sharing | Via PlayerData (transient) | +| `TransportController` | Transport locations + categories | `transport.dat` | +| `MagicController` | Magic system data | `magic.dat` | +| `GlobalDataController` | Cross-world persistent data | `globaldata.dat` | +| `SpawnController` | Natural NPC spawn rules | `spawns.dat` | +| `TagController` | Tag management for filtering | `tags.dat` | +| `CategoryManager` | Filesystem category operations | Utility | +| `CustomEffectController` | Custom status effects | JSON `effects/` | +| `CustomGuiController` | Script-created GUI tracking | In-memory | +| `ChunkController` | Chunk loading callbacks | Via ForgeChunkManager | +| `LinkedNpcController` / `LinkedItemController` | Linked NPC/item templates | JSON dirs | +| `ServerCloneController` / `ServerTagMapController` | Clone tab management | `clones/` | +| `APIRegistry` | Addon API registration (name→URL) | In-memory | + +### kamkeel.npcs.controllers (6 files) +| Controller | Purpose | Storage | +|---|---|---| +| `AbilityController` | Ability definitions, custom types, chained combos | JSON `abilities/` | +| `AttributeController` | Player attribute definitions + tracking | In-memory definitions | +| `EnergyController` | Energy entity spawning + damage routing | Transient | +| `ProfileController` | Multi-character profile slots | `profiles/` per-player DAT | +| `SyncController` | Client-server data sync, revision caching, chunked payloads | In-memory cache | +| `TelegraphController` | Visual telegraph presets for abilities | JSON `telegraphs/` | + +## data/ Subdirectory (56 files) +Data model classes owned by controllers. Key groups: +- **Dialog**: `Dialog`, `DialogCategory`, `DialogOption` — branching conversation data +- **Quest**: `Quest`, `QuestCategory`, `QuestData` — quest definitions + progress +- **Faction**: `Faction`, `FactionOptions` — faction config (also in core/) +- **Player**: `PlayerData` (central), `PlayerQuestData`, `PlayerFactionData`, `PlayerBankData`, `PlayerMailData`, `PlayerAbilityData`, `PlayerAbilityHotbarData`, `PlayerTradeData`, `PlayerItemGiverData`, `PlayerEffect`, `PlayerEffectData`, `PlayerDialogData` +- **Economy**: `AuctionListing`, `AuctionClaim`, `AuctionBlacklist`, `Bank`, `BankData` +- **Script**: `ScriptHandler`, `SingleScriptHandler`, `MultiScriptHandler`, `DataScript`, `PlayerDataScript`, `ForgeDataScript`, `GlobalNPCDataScript`, `AbilityScript`, `EffectScript`, `LinkedItemScript`, `RecipeScript`, `ChainedAbilityScript` + interfaces `IScriptHandler`, `IScriptBlockHandler`, `IScriptUnit` +- **Animation**: `Animation`, `AnimationData`, `BuiltInAnimation` +- **Party**: `Party` — membership + shared quest state +- **Other**: `Availability`, `CustomEffect`, `LinkedItem`, `MarkData`, `SpawnData`, `DataTransform`, `RecipeCarpentry`, `RecipeAnvil` +- **action/**: Sub-package for quest/dialog action framework + +## Data Persistence Flow +``` +Controller.load() → readNBT/JSON from world save dir + → populate in-memory maps (HashMap/LinkedHashMap) + → serve via Instance.getXxx() + +Controller.save() → writeNBT/JSON + → CustomNPCsThreader.customNPCThread.execute() (async) + → write to world save dir +``` + +## Cross-Controller Dependencies +- `SyncController` ← used by Dialog, Quest, Faction, Recipe, Effect, Ability, Magic controllers for client push +- `PlayerDataController` ← used by Party, Quest, Profile, Auction controllers for player state +- `AbilityController` → `EnergyController` (projectile spawning), `TelegraphController` (visuals) +- `ProfileController` → all player data controllers (slot switching reloads everything) +- `ScriptController` → provides execution context for all `*Script` data classes + +## Forbidden +- **Do NOT break singleton contract** — controllers are accessed globally via `.Instance` +- **Do NOT save synchronously on main thread** — use `CustomNPCsThreader` for file I/O +- **Do NOT touch ScriptHandler/ScriptContainer for migration** — deeply coupled to Nashorn/Janino engines +- **Do NOT modify RecipeController for migration** — extends MC CraftingManager diff --git a/src/main/java/noppes/npcs/scripted/AGENTS.md b/src/main/java/noppes/npcs/scripted/AGENTS.md new file mode 100644 index 000000000..b1ca307d8 --- /dev/null +++ b/src/main/java/noppes/npcs/scripted/AGENTS.md @@ -0,0 +1,106 @@ +# AGENTS.md — noppes.npcs.scripted (Scripting API Wrappers) + +## What This Is +Script-facing API layer. Wraps MC objects (entities, worlds, blocks, items, damage) into safe +interfaces for JavaScript/Java scripts. 16 root files + 3 subdirectories (entity/, event/, roles/). + +## Architecture +Scripts access game objects through wrapper classes that implement `noppes.npcs.api.*` interfaces. +The `NpcAPI` singleton is bound as the `API` global in every script context. + +``` +Script code → API.getIEntity(mcEntity) → ScriptPlayer/ScriptNpc wrapper + → wrapper.method() → delegates to underlying MC object +``` + +## Key Files + +| File | Purpose | +|---|---| +| `NpcAPI.java` | Singleton API entry point. `extends AbstractNpcAPI`. Factory methods: `getIEntity()`, `getIWorld()`, `getIBlock()`, `getIItemStack()`, `createNPC()`, `spawnNPC()`. Registers handlers for all controllers. 1000+ lines. | +| `ScriptWorld.java` | World wrapper: block/entity queries, weather, time, explosions, particles, sounds | +| `ScriptBlock.java` | Block wrapper: metadata, tile entity access, neighbor queries | +| `ScriptNbt.java` | NBT wrapper for script-safe NBT manipulation | +| `ScriptDamageSource.java` | Wraps MC `DamageSource` → `IDamageSource`. Exposes type, source entity, flags (unblockable, projectile, magic) | +| `ScriptParticle.java` | Particle configuration wrapper | +| `ScriptSound.java` | Sound playback wrapper | +| `ScriptTelegraph.java` | Telegraph visual configuration | +| `ScriptBlockPos.java` | Position wrapper with arithmetic | +| `ScriptContainer.java` | Inventory container wrapper (different from controllers.ScriptContainer) | +| `ScriptTileEntity.java` | Tile entity wrapper | +| `BlockScriptedWrapper.java` | Scripted block bridge | + +## entity/ (28 files) — Entity Wrapper Hierarchy +``` +ScriptEntity (base — all entities) + └─ ScriptLivingBase (health, effects, equipment) + ├─ ScriptLiving (AI, pathfinding) + │ ├─ ScriptNpc (NPC-specific: AI data, role, job, dialog, faction, abilities) + │ ├─ ScriptMonster + │ ├─ ScriptAnimal + │ └─ ScriptVillager + ├─ ScriptPlayer (quests, factions, currency, GUI, abilities, profile) + │ ├─ ScriptDBCPlayer (Dragon Block C addon) + │ └─ ScriptPixelmon (Pixelmon addon) + └─ ScriptEnergyAbility (base for energy entities) + ├─ ScriptEnergyOrb, ScriptEnergyDisc, ScriptEnergyLaser, ScriptEnergyBeam + ├─ ScriptEnergySweeper, ScriptEnergyZone, ScriptEnergyDome, ScriptEnergyPanel + ├─ ScriptEnergyProjectile, ScriptEnergySlicer, ScriptEnergyExplosion + └─ ScriptEnergyBarrier (ScriptEnergyDome parent) +ScriptEntityItem (dropped items) +ScriptArrow, ScriptThrowable, ScriptFishHook (projectiles) +ScriptProjectile (NPC projectile wrapper) +``` + +**Wrapper creation**: `NpcAPI.getIEntity(Entity)` auto-detects type and returns correct wrapper. + +## event/ (14 files + player/) — Script Event Types +Each file defines inner classes for specific hook points: + +| File | Events | +|---|---| +| `NpcEvent.java` | Init, Tick, Update, Interact, Target, Died, Killed, Damaged, Ranged, Melee, Collide, Dialog | +| `PlayerEvent.java` (player/) | Login, Logout, Chat, Damaged, Attack, Death, Interact, PickUp, Drop, KeyPressed, ContainerOpen/Close, Timer, LevelUp, Toss | +| `BlockEvent.java` | Interact, Redstone, NeighborChanged, Timer, Harvest, Exploded, Rain, Click, FallenUpon, Collide | +| `ItemEvent.java` | Init, Tick, Attack, Interact, Toss, PickUp, Spawn, RightClick | +| `AbilityEvent.java` | WindUp, Active, Dazed, Hit, Cancelled, PhaseChange | +| `AnimationEvent.java` | Started, Ended, FrameEnter, FrameExit | +| `ProjectileEvent.java` | Impact, Tick | +| `EnergyProjectileEvent.java` | Impact, Tick, Spawn, Despawn | +| `EnergyBarrierEvent.java` | Impact, Damaged, Destroyed | +| `ChainEvent.java` | ChainStart, ChainEnd, AbilityStart, AbilityEnd | +| `ForgeEvent.java` | Generic Forge event bridge | +| `PartyEvent.java` | Invite, Join, Leave, Disband, QuestComplete | +| `LinkedItemEvent.java` | Item-specific script hooks | +| `RecipeScriptEvent.java` | Crafting event hooks | +| `CustomNPCsEvent.java` | Base event class | + +## roles/ (15 files) — Scripted Role Wrappers +Wrap NPC role/job data for script access: +- `ScriptRoleTrader`, `ScriptRoleBank`, `ScriptRoleFollower`, `ScriptRoleTransporter` +- `ScriptRolePostman`, `ScriptRoleCompanion`, `ScriptRoleInnkeeper`, `ScriptRoleMount` +- `ScriptJobGuard`, `ScriptJobHealer`, `ScriptJobBard`, `ScriptJobItemGiver` +- `ScriptJobSpawner`, `ScriptJobConversation`, `ScriptJobFollower` + +## Event Flow +``` +Game action (e.g. NPC damaged) + → EventHooks.onNPCDamaged() + → ScriptController runs global scripts with EnumScriptType.DAMAGED + → EntityNPCInterface's IScriptHandler.callScript(EnumScriptType.DAMAGED, event) + → ScriptContainer compiles/caches script, binds API + event object + → Script runs: event.setCancelled(true) can cancel damage + → NpcAPI.EVENT_BUS.post(event) for addon listeners +``` + +## Integration Points +- **API interfaces** (`src/api/java/`): All wrappers implement `noppes.npcs.api.*` interfaces (IPlayer, ICustomNpc, IWorld, etc.) +- **ScriptContainer** (controllers/): Manages compilation, caching, and execution of script code +- **EventHooks** (noppes/npcs/): Dispatches events that create instances of event/ classes +- **Controllers**: `NpcAPI` exposes handler accessors: `getQuests()`, `getDialogs()`, `getFactions()`, `getAbilities()`, etc. + +## Forbidden +- **Do NOT migrate scripted/ to core** — every wrapper holds MC objects directly +- **Do NOT change wrapper constructors** — scripts depend on `NpcAPI.getIEntity()` factory, not direct construction +- **Do NOT add MC-specific methods to api interfaces** — wrappers implement API interfaces from the submodule +- **Do NOT break event cancellation** — `setCancelled(true)` contract is used by all user scripts