Files
async/binding/README.md
T
kayjaydee f23bb2178f feat(binding): Hytale SDK glue
The only module that imports com.hypixel.*. Provides World.asExecutor,
EntityHandle adapters for Ref/PlayerRef/Player, scope helpers
(playerScope, worldScope, pluginScope), and installAsync() which wires
PlayerDisconnectEvent to PlayerScopes.cancel.
2026-04-28 16:30:16 +02:00

49 lines
1.8 KiB
Markdown

# `:binding`
The Hytale-specific glue. This is the only module that imports anything from
`com.hypixel.hytale.*` — everything else in the project is plain Kotlin you
can compile without the SDK on the classpath.
## What's in here
```kotlin
World.asExecutor(): WorldExecutor
Ref<EntityStore>.toEntityHandle(world: World): EntityHandle
PlayerRef.toEntityHandle(): EntityHandle
Player.handle(): EntityHandle
JavaPlugin.installAsync() // wires PlayerDisconnectEvent → PlayerScopes.cancel
playerScope(player): CoroutineScope
worldScope(world): CoroutineScope
pluginScope(plugin): CoroutineScope
```
Each is a thin delegating wrapper. The interesting code lives in `:core` and
`:ecs`.
## No unit tests
`World` and `WorldConfig` break MockK's bytecode retransformer on JDK 25
(`InternalError: class redefinition failed`). Adding `mockk-agent` plus a JVM
arg flag would let us mock them, but they'd be testing five lines of method
delegation. Not worth the maintenance.
The actual behaviour — dispatcher confinement, scope cancellation, the DSL —
is covered by the `:core` and `:ecs` unit tests, which run in milliseconds
against in-memory stubs.
If you want to verify the binding against a live server, build the shaded
JAR (`./gradlew :dist:shadowJar`), drop it in `mods/`, and call
`installAsync()` from a plugin's `start()`. If `playerScope(player).launch { modify<T>(...) { ... } }`
runs without throwing `Assert not in thread!`, the binding works.
## Known SDK gotchas
- **No `WorldUnloadEvent`.** Until it ships, call `WorldScopes.cancel(uuid)`
yourself when you unload a world.
- **Race on world death.** If a world dies between an `isAlive()` check and
the actual `execute()` call, the task is silently dropped by Hytale's task
queue and the awaiting coroutine never completes. Wrap long world-bound
work in `withTimeout(...)` if it matters.