- Replace portfolio-only SHOWCASE with unified README as sole project entry page - Add full user guide: commands table, wand flow, region anatomy (all 15 config fields sourced from GravityFlipRegion.CODEC), visual modes, regions.json path - Add developer section: prerequisites (JDK 25, Hytale API), project structure, build/test/deploy commands, extension snippets - Add architecture overview with ASCII diagram (tick loop, wand flow, persistence) - Correct subcommand list (wand/define/list/delete/toggle/tp) to match GravityFlipCommand source - Preserve showcase content: video placeholder, screenshot grid (HTML table), 12 showcase regions table, feature list - Add shields.io badges, tech-stack, roadmap, credits, license sections
18 KiB
Hytale Gravity Flip
Builder-friendly anti-gravity zones for Hytale servers.
Define a region with a wand, name it, walk on the ceiling — no code, no restarts.
Showcase
Click to watch on YouTube
Screenshots
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Features
- Builder-first workflow — define regions entirely in-game with a custom wand. No config editing required for the common case.
- Six subcommands —
wand,define,list,delete,toggle,tp. - Per-UUID wand selection store — each builder owns their own pair of corners; survives rejoin.
- Persistent regions — every zone serialised to
regions.json, reloaded on boot via the HytaleConfig<T>API. - Two visualization modes —
Outline(AABB wireframe) andParticles(volumetric emitters on edges) with configurable color, opacity, refresh rate, and density.Nonefor production. - Per-entity affect toggles — target players only, items only, NPCs only, or any combination.
- Configurable physics —
VerticalForce(lift strength) andGracePeriodMs(smooth entry transition) per region. - Optional fall-damage immunity — suppress fall damage when leaving a zone so demos don't hurt.
- Tick-loop detection — efficient AABB containment check each tick (~100 ms), scales to dozens of active regions.
- First-run bootstrap — the plugin auto-seeds a demo region on first boot so the mechanic works out of the box.
Quick Start
- Install — drop
hytale-gravity-flip-<version>.jarinto<HytaleServer>/Server/mods/and start the server. - Get the wand — run
/gravityflip wandin-game. You receive the Gravity Flip Wand item. - Pick two corners — primary-click block A (pos1), secondary-click block B (pos2).
- Name the region —
/gravityflip define my_zone. Gravity inverts inside the box immediately. - Fly up. Congratulations.
User Guide
Commands
All commands are sub-commands of /gravityflip.
| Command | Description | Example |
|---|---|---|
/gravityflip wand |
Gives the caller a Gravity Flip Wand item. | /gravityflip wand |
/gravityflip define <name> |
Creates a region from the caller's current wand selection (both corners required). | /gravityflip define arena |
/gravityflip list |
Prints every registered region with its AABB coordinates and enabled state. | /gravityflip list |
/gravityflip delete <name> |
Removes a region from disk and memory. | /gravityflip delete arena |
/gravityflip toggle <name> |
Enables or disables a region without deleting its config. | /gravityflip toggle arena |
/gravityflip tp <name> |
Teleports the caller to the center of a region (handy for large or hidden zones). | /gravityflip tp arena |
The Wand
The Gravity Flip Wand is a custom item registered through Hytale's item asset pack and Interaction.CODEC.
- Primary click on a block → sets pos1 (min corner candidate).
- Secondary click on a block → sets pos2 (max corner candidate).
- Selection is stored per player UUID in an in-memory
WandSelectionStore. Rejoining the server preserves the selection for the session. - Once both corners are set,
/gravityflip define <name>normalizes them into an axis-alignedBox(min, max)and persists the region.
Region Anatomy
Every region is serialised to regions.json via GravityFlipRegion.CODEC. Only Name and Box are mandatory; every other field has a sensible default and can be omitted.
| Field | Type | Default | Description |
|---|---|---|---|
Name |
string | (required) | Unique region identifier used by commands. |
Box |
AABB | (required) | Axis-aligned box { "min": [x,y,z], "max": [x,y,z] }. Min must be component-wise ≤ Max. |
Enabled |
boolean | true |
If false, the region is persisted but dormant (no detection, no visualization). |
FallDamage |
boolean | false |
If true, vanilla fall damage is preserved. false suppresses fall damage on exit. |
GracePeriodMs |
integer | 2500 |
Smooth entry transition window (ms). 0 = instant flip. |
VerticalForce |
double | 0.1 |
Upward force applied per tick. Gentle lift ≈ 0.05. Launch pad ≈ 0.3. |
AffectPlayers |
boolean | true |
Flip players inside the region. |
AffectNpcs |
boolean | true |
Flip NPCs / mobs inside the region. |
AffectItems |
boolean | true |
Flip dropped items inside the region. |
VisualColor |
string | #00FFFF |
Hex color for the outline / particle tint. |
VisualMode |
string | Outline |
One of Outline, Particles, None. |
VisualRefreshMs |
integer | 1000 |
How often the visualization is re-emitted (ms). Lower = smoother, heavier. |
VisualOpacity |
double | 0.5 |
Overlay opacity, 0.0–1.0. |
VisualParticleId |
string | Torch_Fire |
Hytale particle asset id used in Particles mode. Dust_Sparkles_Fine is invisible in-world. |
VisualParticleDensity |
double | 0.3 |
Particles per edge unit. 1.0 saturates; 0.1 is sparse. |
Visual Modes
Outline— colored AABB wireframe, refreshed everyVisualRefreshMs. Best for builders and debugging.Particles— particle emitters along the box edges, density and id configurable. Best for gameplay / showcase.None— region is invisible. Use in production once builders are done.
Configuration File
The region file lives at <HytaleServer>/Server/mods/Mythlane_GravityFlip/regions.json and is written by the plugin whenever a command mutates the registry.
- Hot-reload: not currently exposed as a subcommand — restart the server (or reload the plugin host) after hand-edits.
- Auto-save contract: command handlers save immediately after mutations. External edits must restart.
- First-run: if
regions.jsonis empty/missing, the plugin seeds one showcase region (demo-gravity-flip, box(0,100,0)..(10,120,10), particles on).
Showcase Regions
A set of curated regions ships with the dev server's regions.json. They collectively exercise every plugin capability. Spawn is (0, 81, 0) on a superflat surface.
| Region | Min | Max | What it demonstrates |
|---|---|---|---|
tutorial_walk_on_ceiling |
(10, 81, 10) | (15, 86, 15) | Baseline player-only flip with cyan outline. |
item_fountain |
(20, 80, 10) | (23, 100, 13) | Tall vertical zone, items only — drop stuff and watch it rise. |
mob_chamber |
(30, 81, 10) | (40, 89, 20) | NPC-only flip with red outline. |
full_chaos |
(-15, 81, 10) | (0, 91, 25) | Players + NPCs + items, purple particles. |
gentle_lift |
(-40, 80, -20) | (-20, 85, 0) | Soft VerticalForce=0.05 — slow drift. |
strong_launch |
(-15, 80, -15) | (-10, 83, -10) | Aggressive VerticalForce=0.3 — launch pad. |
grace_period_demo |
(15, 81, -20) | (23, 87, -12) | GracePeriodMs=5000 — smooth fade-in. |
no_grace |
(25, 81, -20) | (33, 87, -12) | GracePeriodMs=0 — instant flip, side-by-side comparison. |
fall_damage_off |
(40, 110, 0) | (50, 120, 10) | Elevated zone with FallDamage=false — safe exit. |
disabled_example |
(-30, 81, 0) | (-25, 86, 5) | Enabled=false — persisted but inert, proves state handling. |
showcase_arena |
(-80, 81, -80) | (-50, 96, -50) | 30×15×30 gold-outlined arena — hero shot for video. |
dense_particles |
(50, 81, 50) | (58, 89, 58) | VisualParticleDensity=1.0 — maxed visual saturation. |
Installation
# 1. Build the plugin jar
./gradlew clean shadowJar
# 2. Copy the fat-jar into your Hytale server's mods folder
cp build/libs/hytale-gravity-flip-*.jar "<HytaleServer>/Server/mods/"
# 3. (Re)start the server — the plugin auto-registers its item, interaction, and tick loop.
On first boot the plugin creates Server/mods/Mythlane_GravityFlip/regions.json and seeds a demo region. Edit in-game via commands, or hand-edit the file and restart.
Development
Prerequisites
- JDK 25 (toolchain enforced by Gradle).
- Hytale Plugin API — pulled from
https://maven.hytale.com/releaseascom.hypixel.hytale:Server. Version pinned viahytaleServerVersioningradle.properties. - A local Hytale dev server (for the optional
copyJarToDevServerdeploy task).
Project Structure
src/main/java/com/mythlane/gravityflip/
GravityFlipPlugin.java # Entry point (setup / start / shutdown lifecycle)
command/ # /gravityflip root + 6 sub-commands
config/ # GravityFlipConfig — persisted region list codec
region/ # GravityFlipRegion, RegionRegistry, RegionSnapshot
wand/ # WandSelectionStore + Interaction (CODEC-registered)
tick/ # RegionTickLoop — per-tick AABB detection
physics/ # GravityApplier, FallDamageGuard, FallDamageSuppressorSystem
viz/ # RegionVisualizer + ParticleEdgeEmitter
src/main/resources/
manifest.json # Hytale plugin manifest (filtered by processResources)
Server/Item/Items/
gravityflip_wand.json # Custom wand item asset
Server/Interaction/RootInteractions/
gravityflip_wand_root.json # Wand root interaction definition
src/test/java/... # JUnit 5 unit tests (pure-data stores, codec round-trips)
docs/screenshots/ # Portfolio assets
Build
# Fat-jar (shadow) with gson relocated to com.mythlane.gravityflip.libs.gson
./gradlew clean shadowJar
# Run tests
./gradlew test
# Build + auto-deploy to the configured dev server
./gradlew shadowJar
# The shadowJar task is finalized by copyJarToDevServer, which copies to:
# C:/Users/minit/Desktop/HYTALE SERVER/Server/mods (default)
# Override with: -PdevServerMods=<path> or set in gradle.properties
# Disable with: -PdevServerMods=disabled
Extending the Plugin
Adding a new subcommand is three lines:
// In GravityFlipCommand.java
this.addSubCommand(new GravityFlipMySubCommand(plugin));
Adding a new wand-triggered interaction: register an additional Interaction.CODEC entry in GravityFlipPlugin#setup() and reference it from your item's Interactions block in src/main/resources/Server/Item/Items/<item>.json.
Adding a new region field: append a KeyedCodec<> entry to GravityFlipRegion.CODEC with a setter/getter pair. Absence in existing regions.json preserves the Java default (no migration needed).
Architecture
+-----------------------+ +--------------------------+
| Player / NPC / Item | | regions.json (Config<T>)|
+-----------+-----------+ +-------------+------------+
| |
| per-tick AABB check | loaded at start()
v v
+-------+--------+ +--------+---------+
| RegionTickLoop | <------------ | RegionRegistry |
+-------+--------+ +------------------+
|
| entity in enabled region?
v
+-------+---------+ +-------------------+
| GravityApplier | ----> | y-velocity invert |
| + FallDamageGrd | | + fall-dmg guard |
+-----------------+ +-------------------+
Wand flow (independent, command-driven):
Player primary/secondary click
|
v
GravityFlipWandInteraction (Interaction.CODEC registered)
|
v
WandSelectionStore (keyed by UUID)
|
v (on /gravityflip define <name>)
RegionRegistry.add(...) -> configHolder.save()
Key technical notes:
- Plugin entrypoint (
GravityFlipPlugin) owns the lifecycle and all singletons. Wand interaction and item codec are registered insetup(); tick loop and command registry are wired instart(). - Persistence uses
Config<GravityFlipConfig>from the Hytale core API — typed JSON codec, atomic save semantics. Theget()call is deferred pastsetup()because it blocks onpreLoad(). - Tick loop runs every ~100 ms with a 2 s startup delay to let
Universe.get()settle.Worldis resolved lazily each tick, so the tick is a no-op until the world is ready. - Wand interaction is registered through
Interaction.CODECunder the key"GravityFlipWand", matching thegravityflip_wand_root.jsonroot interaction that the item references. - Asset pack is bundled inside the jar (
IncludesAssetPack: trueinmanifest.json) and includes the wand model, icon, interaction root, and item definition. - Concurrency —
Config<T>#get()returns a shared mutable reference;RegionRegistrysnapshots it into anAtomicReferencefor lock-free tick-loop reads.
Tech Stack
- Java 25 — modern records, pattern matching, sealed types.
- Gradle 8 +
com.gradleup.shadow9.3.1 — fat-jar build with gson relocation. - Hytale Plugin API (
com.hypixel.hytale:Server) —JavaPlugin,Config<T>,Interaction.CODEC,BuilderCodec,KeyedCodec,Universe/Worldaccess. - Gson 2.10.1 — relocated under
com.mythlane.gravityflip.libs.gsonto avoid classpath clashes. - JUnit 5.10 — pure-data unit tests for selection store and codec round-trips.
Roadmap
v1 — shipped — custom wand, 6 subcommands, outline + particle visualization, per-region physics tuning, per-entity affect toggles, JSON persistence, first-run bootstrap, dev-server auto-deploy task.
v2 — planned:
- Hot-reload subcommand (
/gravityflip reload) without restart. - HUD indicator when entering/leaving a zone.
- Border visualization improvements (antialiased, beveled corners).
- Multi-world support (regions keyed by world id).
- Custom gravity profiles per region (horizontal push, directional gravity, zero-G).
- Import / export region sets as shareable JSON bundles.
- Permissions integration (who can create / edit / delete).
Credits
Built by the Mythlane team.
Plugin structure and conventions informed by the VotePipe and myth_* Hytale plugin family (Kotlin/Java scaffolding, CamelCase manifests, gradle.properties versioning).
License
License TBD. Contact socials@mythlane.com for usage inquiries.





