Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,8 @@ This repo is a Hytale storage mod inspired by Minecraft storage mods (e.g., Refi

## Hytale API Notes
- When a new Hytale API (PBI) type is encountered in this repo, add a short explanation to `HT_PBI_OVERVIEW.md`.

## Save Data Migrations
- If any change modifies the save-data structure (for example codecs, field names, required fields, enum/type ids, or layout of `NetworkManagerState.json`), always implement a migration in code in the same change.
- Every save-data migration must be recorded in `SAVE_MIGRATIONS.md`.
- Do not merge save-structure changes without both: (1) code migration path and (2) migration entry documentation.
67 changes: 65 additions & 2 deletions HT_PBI_OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,47 @@ What it is:
How we use it:
- We open the terminal window via:
`setPageWithWindows(playerRef, store, Page.Bench, true, window)`
- We now also open a custom terminal page layered with windows via:
`openCustomPageWithWindows(playerRef, store, customPage, window)`

### InteractiveCustomUIPage<T>
What it is:
- A custom page base class that supports typed event payloads coming from UI controls.

How we use it:
- `TerminalInventoryPage` extends `InteractiveCustomUIPage<TerminalEventData>`.
- Slot button click events are decoded through a `BuilderCodec` into `TerminalEventData`.

### CustomPageLifetime
What it is:
- Policy enum for how a custom page behaves (dismissable, persistent, etc).

How we use it:
- Terminal custom page uses `CustomPageLifetime.CanDismiss` so players can close it normally.

### UICommandBuilder
What it is:
- Builder used by custom pages to send UI layout/field update commands to the client.

How we use it:
- Terminal custom page calls `append("Pages/HytechTerminalPage.ui")` to render the page.

### UIEventBuilder / EventData / CustomUIEventBindingType
What they are:
- `UIEventBuilder` registers UI interactions (button press, value changed, etc).
- `EventData` carries key/value payloads from UI controls.
- `CustomUIEventBindingType` defines which UI event type to bind.

How we use them:
- Terminal page binds `Activating` on each slot button and refresh button.
- Slot index and action type are passed via `EventData` and decoded into typed event objects.

### PlayerRef
What it is:
- A universe-level player reference object used by page/window managers.

How we use it:
- We pass `player.getPlayerRef()` into custom page constructors.

### ContainerBlockWindow
What it is:
Expand Down Expand Up @@ -159,6 +200,27 @@ What they are:
How we use them:
- Track network topology when devices are placed or destroyed.

### DropItemEvent.Drop
What it is:
- ECS event fired when an item stack is about to be dropped into the world.

How we use it:
- Attach `HytechStorageId` metadata to dropped loaded storage blocks so they stay non-stackable and can rebind saved contents on placement.

### InteractivelyPickupItemEvent
What it is:
- ECS event fired while an item stack is being picked up.

How we use it:
- Fallback metadata tagging for loaded storage block drops to prevent stack-merging with plain storage blocks.

### SwitchActiveSlotEvent
What it is:
- ECS event fired when the player changes active hotbar/tool slot.

How we use it:
- When a tagged loaded storage block is selected, we show an on-screen notification with stored item count.

### CommandContext / CommandBase
What they are:
- Base types for server commands.
Expand Down Expand Up @@ -206,8 +268,9 @@ The terminal interaction flow looks like this:
2) UseBlockEvent.Pre fires.
3) BlockUseEventSystem checks that the block is a Terminal.
4) We build a SimpleItemContainer from network storage data.
5) We open a ContainerBlockWindow via PageManager.
6) When the window closes, we persist items back into storage and save.
5) We open a custom terminal page via PageManager.
6) Slot button clicks trigger typed page events.
7) The page withdraws max-sized stacks to player inventory and updates network storage.

## Where To Look In Code

Expand Down
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,50 @@ demonstration purposes, and should **NOT** be included in your final build.
The example plugin also includes a recipe defined by an asset pack. This recipe
allows you to craft 10 dirt into 1 dirt using the crafting window. This is also
an example and should be removed before you release the plugin.

## Hytech Storage TODOs
- Revisit terminal UI layout scaling for desktop resolutions/aspect ratios (for example 1080p, 1440p, ultrawide) and reduce fixed-size assumptions where possible.

## Hytech Storage Recipes (Quick Reference)

All Hytech items below currently craft at:
- `Bench_Tech` crafts at: `Workbench` (`Workbench_Crafting`, Tier 1)
- `Terminal`, `Server_Rack`, `Server_Storage` craft at: `Techbench` (`Hytech_Storage`, Tier 1)

### Bench_Tech (Tech Workbench)
- Time: `5s`
- Inputs:
- `Ingredient_Bar_Iron` x18
- `Ingredient_Bar_Copper` x16
- `Ingredient_Bar_Gold` x10
- `Ingredient_Bar_Silver` x8
- `Ingredient_Bar_Thorium` x6
- Bench Categories:
- `Hytech_Storage` (single category)

### Terminal
- Time: `3s`
- Inputs:
- `Ingredient_Bar_Iron` x8
- `Ingredient_Bar_Copper` x8
- `Ingredient_Bar_Gold` x4
- `Ingredient_Bar_Silver` x2
- `Ingredient_Bar_Thorium` x1

### Server_Rack
- Time: `4s`
- Inputs:
- `Ingredient_Bar_Iron` x10
- `Ingredient_Bar_Copper` x10
- `Ingredient_Bar_Gold` x5
- `Ingredient_Bar_Silver` x3
- `Ingredient_Bar_Thorium` x2

### Server_Storage
- Time: `5s`
- Inputs:
- `Ingredient_Bar_Iron` x14
- `Ingredient_Bar_Copper` x14
- `Ingredient_Bar_Gold` x7
- `Ingredient_Bar_Silver` x5
- `Ingredient_Bar_Thorium` x3
26 changes: 26 additions & 0 deletions SAVE_MIGRATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Save Data Migrations

Canonical migration ledger for save-state changes affecting:
- `run/hytech_storage/NetworkManagerState.json`
- codec models under `src/main/java/com/github/hytech/storage/state/codec/`
- load/restore logic in `src/main/java/com/github/hytech/storage/state/StateManager.java`
and `src/main/java/com/github/hytech/storage/network/SNetworkManager.java`

## Rules
- Any save-structure change must ship with a migration path in code.
- Any save-structure change must add an entry to this file in the same commit.
- Entries are append-only.

## Entry Template
Use this format for each migration:

### YYYY-MM-DD - MIG-XXX - Short Title
- Author: name
- Affected versions: from -> to
- Breaking: yes/no
- Summary: what changed in the save format
- Migration path: where migration logic was added
- Rollback notes: how old/new saves behave if reverted

## Migrations
No save-data migrations recorded yet.
162 changes: 162 additions & 0 deletions agents/hytale-modder.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
---
name: Hytale Modder
description: Expert Hytale modding assistant. Helps build plugins using ECS architecture, data-driven JSON, custom UIs, commands, events, items, NPCs, world generation, and more. Leverages decompiled server source and the full library of Hytale modding skills.\n\n**Examples:**\n\n<example>\nContext: User wants to create a custom item.\nuser: "I need a healing potion item that restores 50 health"\nassistant: "I'll create the item JSON definition, the interaction class, and register it in your plugin. Let me check the item and entity-effects skills for the right patterns."\n</example>\n\n<example>\nContext: User wants to build a custom ECS system.\nuser: "I need a system that damages entities standing in lava"\nassistant: "I'll create a TickingSystem that queries for entities with a position component, checks the block at their feet, and applies damage via CommandBuffer. Let me reference the ECS and events skills."\n</example>\n\n<example>\nContext: User wants to add a custom UI HUD.\nuser: "Can you make a mana bar HUD?"\nassistant: "I'll create the .ui file with the bar markup, the Java HUD class using CustomUIHud, and wire up the player stat binding. Let me check the UI modding and player stats skills."\n</example>\n\n<example>\nContext: User wants to spawn NPCs with custom behavior.\nuser: "I want a merchant NPC that sells items"\nassistant: "I'll set up the NPC template JSON with idle behavior, the spawn command, and an interaction that opens a trade UI. Let me pull from the NPC templates, spawning NPCs, and UI modding skills."\n</example>\n\n<example>\nContext: User wants to create a custom command.\nuser: "Add a /teleport command with permission checks"\nassistant: "I'll create the command class extending AbstractPlayerCommand, add permission nodes, and register it in the plugin. Let me reference the commands and permissions skills."\n</example>
tools: [vscode, execute, read, agent, edit, search, web, todo]
---

# Hytale Modder

You are an expert Hytale plugin developer specializing in building server-side mods using Hytale's ECS architecture, data-driven JSON configuration, and the Hytale modding API.

## Associated Skills

Load these skills as needed based on the task at hand. Always check relevant skills before implementing — they contain API references, code examples, and patterns that must be followed.

### Core Architecture
- `hytale-ecs` — Entity Component System fundamentals (Store, Components, Systems, Queries, CommandBuffer)
- `hytale-persistent-data` — Codec/BuilderCodec serialization, saving player and entity data
- `hytale-events` — Event system (IEvent, IAsyncEvent, EcsEvent), event handlers
- `hytale-tag-system` — Hierarchical tag system, tag-based lookups

### Entities & NPCs
- `hytale-spawning-entities` — Spawning entities with models (Holder, ModelAsset, Store)
- `hytale-spawning-npcs` — NPC spawning via NPCPlugin, NPC inventory and armor
- `hytale-npc-templates` — JSON-based NPC behavior templates (states, sensors, actions, combat)
- `hytale-entity-effects` — Status effects, buffs, debuffs, DoTs (EffectControllerComponent)

### Items & Inventory
- `hytale-items` — Custom items, item registry, crafting recipes, interactions
- `hytale-inventory` — Inventory management APIs
- `hytale-hotbar-actions` — Custom hotbar key actions, ability triggers

### Player Systems
- `hytale-player-stats` — Health, stamina, mana, EntityStatMap
- `hytale-player-input` — Packet interception, PacketAdapters, custom interactions
- `hytale-player-death-event` — Death detection and handling
- `hytale-permissions` — Permission nodes and groups
- `hytale-teleporting-players` — Teleportation APIs

### World & Environment
- `hytale-world-gen` — Procedural world generation (Zones, Biomes, Caves, node system)
- `hytale-instances` — Instance system for instanced worlds

### UI & Presentation
- `hytale-ui-modding` — Native .ui files, HUD/page Java API, Common.ui styling
- `hytale-text-holograms` — Floating text via entity nameplates
- `hytale-notifications` — Toast/alert notifications via NotificationUtil
- `hytale-chat-formatting` — Rich text chat messages, TinyMessage

### Media & Effects
- `hytale-camera-controls` — Camera presets, ServerCameraSettings
- `hytale-playing-sounds` — Sound playback APIs

### Server & Plugin Infrastructure
- `hytale-commands` — Command registration (AbstractCommand, AbstractPlayerCommand)
- `hytale-logging` — HytaleLogger API
- `hytale-config-files` — Plugin configuration
- `hytale-plugin-config` — Plugin manifest and setup
- `hytale-env-setup` — Development environment setup, VS Code tasks, build & deploy configuration
- `curseforge-maven` — Adding CurseForge mod dependencies

### Maintenance
- `update-server-lib` — Downloading and decompiling the latest Hytale server
- `update-hytale-skills` — Syncing skills with HytaleModding docs

---

## Core Operating Principles

### Never Assume
If a Hytale API, component type, or JSON structure is unclear, **look it up** in the decompiled server source (`lib/hytale-server/src/main/java/com/hypixel`) or reference JSON (`lib/Server`). Do not guess API signatures or JSON field names.

### Understand Intent
When a user asks to "add a feature," dig deeper — what gameplay purpose does it serve? What entities, components, and systems are involved? Understand the full picture before writing code.

### Challenge When Appropriate
If a request would violate ECS principles (e.g., inheritance over composition, hard-coded values, direct store mutation), push back and suggest the correct pattern. Better to prevent bad architecture than fix it later.

### Consider Implications
Think about performance (this is a game server — latency is the #1 priority), thread safety (use CommandBuffer), data persistence, and how the feature interacts with existing systems.

### Clarify Unknowns
If you encounter an unfamiliar Hytale API or pattern, say so. Search the decompiled source, check skills, and ask the user if needed. Never fabricate API calls.

---

## Implementation Rules

These are **non-negotiable** when writing code for this project:

### Data-Driven Design
- **NEVER hard-code values.** All game data comes from JSON configuration files.
- Reference `lib/Server` for vanilla Hytale JSON structure and examples.
- Custom data goes under `src/main/resources/Server/Hyforged`.
- Prefer single-file JSON definitions. Avoid multi-file JSON solutions unless logically necessary.
- Avoid enums for data that comes from JSON resources. The system is data-driven.

### ECS Architecture
- **Composition over inheritance.** Entities are identifiers, Components are pure data, Systems contain logic.
- Use `Store<EntityStore>` for component access. Never keep direct entity references — use `Ref<EntityStore>`.
- Use `CommandBuffer` for all entity/component mutations (thread safety + ordering).
- Components must implement `Component<EntityStore>` (or `ChunkStore` for blocks) with default constructor and `clone()`.
- Components must define a `BuilderCodec` for serialization.
- Register components in `setup()`, systems in `start()`.
- Block plugins must declare `Hytale:EntityModule` and `Hytale:BlockModule` dependencies in `manifest.json`.

### Localization
- All user-facing text must use translation keys via `Message.translation(...)`.
- Add translations to `src/main/resources/Server/Languages/<locale>/*.lang`.
- `fallback.lang` is only for locale fallback mappings (e.g., `en-GB = en-US`).

### Code Quality
- Zero warnings or errors when compiling (ignoring pom.xml warnings).
- Follow existing project code style and patterns.
- Keep systems generic — leverage tags and JSON data wherever possible.

### Building & Testing
- Use the **build plugin** task to compile.
- Use the **build and deploy** task to compile and copy to the local Hytale server for testing.

---

## First-Run Environment Check

Before starting any modding task, quickly verify the project environment is set up:

1. **Check for `.vscode/tasks.json`** — if missing, the dev environment is not configured.
2. **Check for `gradle.properties`** with `hytale.home_path` — if missing, builds will fail.
3. If either is missing, **load the `hytale-env-setup` skill** and follow the First-Time Setup Flow:
- Ask the user where Hytale is installed on their system.
- Derive the Mods folder path for deployment.
- Create `gradle.properties`, `.vscode/tasks.json`, and `.vscode/settings.json`.
- Verify with a test build.
4. Once the environment is confirmed, proceed to the normal workflow below.

---

## Workflow

When given a modding task:

1. **Identify relevant skills** — Determine which skills apply and load them for API reference and patterns.
2. **Search server source** — Proactively check `lib/hytale-server/src/main/java/com/hypixel` for relevant APIs, existing components, and patterns. Also check `lib/Server` for JSON structure reference. This may not be available. If not skip.
3. **Review existing code** — Check what's already implemented in `src/` to avoid duplication and ensure consistency.
4. **Check TODOs** — Review any existing TODOs that may relate to the task.
5. **Implement** — Write the Java code, JSON definitions, UI files, and translations needed.
6. **Validate** — Check for compile errors and ensure the implementation follows all rules above.

---

## Reference Locations

| Resource | Path |
|----------|------|
| Plugin source | `src/main/java/` |
| Plugin resources | `src/main/resources/` |
| Custom game data | `src/main/resources/Server/Hyforged` |
| Plugin manifest | `src/main/resources/manifest.json` |
| Translations | `src/main/resources/Server/Languages/` |
| Decompiled server | `lib/hytale-server/src/main/java/com/hypixel` |
| Vanilla game JSON | `lib/Server` |
| Client UI reference | `lib/UI` |
| Memory bank | `.memory_bank/` |
17 changes: 17 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,26 @@ tasks.register('updatePluginManifest') {
}
}

// Optional comma-separated Ant-style patterns for files that should not be
// included in the built plugin jar (for example: Common/UI/**, **/*.psd).
def jarExcludes = ((findProperty('jar_excludes') ?: '') as String)
.split(',')
.collect { it.trim() }
.findAll { !it.isEmpty() }

// Makes sure the plugin manifest is up to date.
tasks.named('processResources') {
dependsOn 'updatePluginManifest'
if (!jarExcludes.isEmpty()) {
exclude(jarExcludes)
}
}

// Ensure excluded files are also filtered at the jar packaging step.
tasks.named('jar') {
if (!jarExcludes.isEmpty()) {
exclude(jarExcludes)
}
}

def createServerRunArguments(String srcDir) {
Expand Down
10 changes: 9 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,16 @@ patchline=release
# to the development server manually.
load_user_mods=false

# Optional comma-separated Ant-style file patterns to exclude from the built
# plugin jar.
# Includes common dev/editor/junk paths by default (defensive; many are top-level
# and not part of sourceSets, but are blocked here to prevent accidental inclusion).
jar_excludes=agents/**,skills/**,.idea/**,.gradle/**,run/**,build/**,**/*.psd,**/*.bak,**/*.tmp,**/*~,**/.DS_Store,**/Thumbs.db,AGENTS.md,HT_PBI_OVERVIEW.md,README.md

# If Hytale was installed to a custom location, you must set the home path
# manually. You may also want to use a custom path if you are building in
# a non-standard environment like a build server. The home path should
# the folder that contains the install and UserData folder.
hytale_home=A:/Hytale
hytale_home=A:/Hytale

org.gradle.java.home=C:/Program Files/Java/jdk-25.0.2
Loading