init
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# Overview
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
HubPlugin (entry)
|
||||
+-- HubWorldFilter decides if a world is a hub world (config-driven)
|
||||
+-- HubWorldService applies world-level WorldConfig flags (PvP, fall damage)
|
||||
+-- HubJoinListener PlayerReadyEvent: teleport to spawn + private welcome
|
||||
+-- HubMessageListener replaces/suppresses Hytale's built-in join/leave broadcasts
|
||||
+-- CancelBreakBlockSystem ECS: cancels BreakBlockEvent in hub worlds
|
||||
+-- CancelPlaceBlockSystem ECS: cancels PlaceBlockEvent in hub worlds
|
||||
+-- CancelDamageBlockSystem ECS: cancels DamageBlockEvent in hub worlds
|
||||
```
|
||||
|
||||
## What runs when
|
||||
|
||||
### Boot-time, in `start()`
|
||||
|
||||
1. Build `HubWorldFilter` from config (which worlds are hubs).
|
||||
2. Register `AllWorldsLoadedEvent` listener -> `HubWorldService.applyToConfiguredWorlds()`. Also call it once now (covers reload after worlds already loaded).
|
||||
3. Register `PlayerReadyEvent` -> `HubJoinListener.onReady(...)`.
|
||||
4. Register `AddPlayerToWorldEvent` / `RemovedPlayerFromWorldEvent` -> `HubMessageListener` (replaces Hytale's default join/leave broadcast text, or suppresses entirely).
|
||||
5. Register the three `EntityEventSystem` subclasses (one per protected event) with `getEntityStoreRegistry()`. Each is gated on its own `protection.disable_*` toggle.
|
||||
|
||||
`HubWorldService` walks every configured hub world and sets:
|
||||
- `isPvpEnabled = false` (if `protection.disable_pvp`)
|
||||
- `isFallDamageEnabled = false` (if `protection.disable_fall_damage`)
|
||||
|
||||
Only the flags that actually differ from current state are written. `markChanged()` is called once if anything changed.
|
||||
|
||||
### Per-player, on `PlayerReadyEvent`
|
||||
|
||||
For each player who's just finished joining a hub world (i.e. their world is in `worlds.hub_worlds`, or that list is empty meaning "every world on this server is a hub"):
|
||||
|
||||
1. Look up the world's spawn point via `WorldConfig.getSpawnProvider().getSpawnPoint(world, uuid)` and add a `Teleport` component to the player's entity.
|
||||
2. Send the welcome message privately to the joining player.
|
||||
|
||||
The join/leave announcements are NOT sent here. They are emitted by `HubMessageListener` riding on `AddPlayerToWorldEvent` / `RemovedPlayerFromWorldEvent`, which are the same events Hytale's own broadcast uses, so we get exactly one message instead of two.
|
||||
|
||||
## Why ECS systems instead of GameMode.Adventure
|
||||
|
||||
In Hytale, `GameMode` only has two values: `Adventure` and `Creative`. `Adventure` is what Minecraft players would call "Survival" - the player can still break and place blocks. It is NOT a block-protection mode. So we cancel `BreakBlockEvent`, `PlaceBlockEvent`, and `DamageBlockEvent` directly via ECS systems that filter on world. This actually prevents the action and is the same approach the server's own gating uses.
|
||||
|
||||
## Why intercept `AddPlayerToWorldEvent` for messages
|
||||
|
||||
Hytale's player-add system fires `AddPlayerToWorldEvent` with a default `joinMessage`, then broadcasts it after the listeners run (only if `shouldBroadcastJoinMessage()` returned true). We rewrite the message text (or call `setBroadcastJoinMessage(false)` to suppress entirely if the configured format is blank). Same pattern for `RemovedPlayerFromWorldEvent`. This way the hub's announcement is the one and only line players see; we never run alongside Hytale's default.
|
||||
|
||||
## Why `PlayerReadyEvent` for spawn-teleport
|
||||
|
||||
`PlayerConnectEvent` fires earlier in the flow, before the player is fully in the world. Teleporting at that point is racy. `PlayerReadyEvent` fires when the player is actually playable.
|
||||
|
||||
## File map
|
||||
|
||||
| File | Responsibility |
|
||||
|---|---|
|
||||
| [HubPlugin.java](../src/main/java/net/kewwbec/hub/HubPlugin.java) | Entry. Lifecycle, wiring. |
|
||||
| [config/HubConfig.java](../src/main/java/net/kewwbec/hub/config/HubConfig.java) | Config record. |
|
||||
| [config/HubConfigLoader.java](../src/main/java/net/kewwbec/hub/config/HubConfigLoader.java) | JSON loader. |
|
||||
| [protection/HubWorldFilter.java](../src/main/java/net/kewwbec/hub/protection/HubWorldFilter.java) | Is-this-world-a-hub predicate. |
|
||||
| [protection/CancelBreakBlockSystem.java](../src/main/java/net/kewwbec/hub/protection/CancelBreakBlockSystem.java) | ECS: cancel BreakBlockEvent in hubs. |
|
||||
| [protection/CancelPlaceBlockSystem.java](../src/main/java/net/kewwbec/hub/protection/CancelPlaceBlockSystem.java) | ECS: cancel PlaceBlockEvent in hubs. |
|
||||
| [protection/CancelDamageBlockSystem.java](../src/main/java/net/kewwbec/hub/protection/CancelDamageBlockSystem.java) | ECS: cancel DamageBlockEvent in hubs. |
|
||||
| [service/HubWorldService.java](../src/main/java/net/kewwbec/hub/service/HubWorldService.java) | Applies world-level flags (PvP, fall damage). |
|
||||
| [listener/HubJoinListener.java](../src/main/java/net/kewwbec/hub/listener/HubJoinListener.java) | PlayerReadyEvent: spawn-teleport + private welcome. |
|
||||
| [listener/HubMessageListener.java](../src/main/java/net/kewwbec/hub/listener/HubMessageListener.java) | Replaces/suppresses Hytale's built-in join/leave broadcast. |
|
||||
Reference in New Issue
Block a user