Loading...
Loading...
Handle Hytale server events including player actions, world changes, entity interactions, and custom events. Use when asked to "listen for events", "handle player actions", "react to block changes", "create event handlers", or "implement event listeners".
npx skill4agent add mnkyarts/hytale-skills hytale-events-apisetup()@Override
protected void setup() {
// Global listener - receives ALL events of this type
getEventRegistry().registerGlobal(
PlayerConnectEvent.class,
this::onPlayerConnect
);
// Keyed listener - receives events with specific key
getEventRegistry().register(
AddPlayerToWorldEvent.class,
"world_name",
this::onPlayerAddToWorld
);
// Priority listener
getEventRegistry().registerGlobal(
EventPriority.FIRST,
SomeEvent.class,
this::onSomeEvent
);
// Unhandled listener - only if no keyed handler processed
getEventRegistry().registerUnhandled(
SomeEvent.class,
this::onUnhandledEvent
);
}public enum EventPriority {
FIRST((short)-21844), // Runs first
EARLY((short)-10922),
NORMAL((short)0), // Default
LATE((short)10922),
LAST((short)21844); // Runs last
}private void onPlayerInteract(PlayerInteractEvent event) {
if (shouldBlock(event)) {
event.setCancelled(true);
}
}private void onEvent(SomeEvent event) {
if (event instanceof ICancellable cancellable && cancellable.isCancelled()) {
return; // Already cancelled by earlier handler
}
// Process event
}// Player connecting (before entering world)
getEventRegistry().registerGlobal(PlayerConnectEvent.class, event -> {
Player player = event.getPlayer();
getLogger().atInfo().log("Player connecting: %s", player.getName());
});
// Player setup connect (cancellable)
getEventRegistry().registerGlobal(PlayerSetupConnectEvent.class, event -> {
if (isBanned(event.getPlayer())) {
event.setCancelled(true);
event.setDisconnectReason("You are banned!");
}
});
// Player disconnecting
getEventRegistry().registerGlobal(PlayerDisconnectEvent.class, event -> {
Player player = event.getPlayer();
savePlayerData(player);
});
// Player added to world
getEventRegistry().register(AddPlayerToWorldEvent.class, "main", event -> {
event.getPlayer().sendMessage("Welcome to the main world!");
});
// Player ready (fully loaded)
getEventRegistry().registerGlobal(PlayerReadyEvent.class, event -> {
Player player = event.getPlayer();
showWelcomeScreen(player);
});// Async event - returns CompletableFuture
getEventRegistry().registerAsyncGlobal(
PlayerChatEvent.class,
future -> future.thenApply(event -> {
String message = event.getMessage();
// Modify message
event.setMessage("[Custom] " + message);
// Or cancel
if (containsBadWords(message)) {
event.setCancelled(true);
}
return event;
})
);getEventRegistry().registerGlobal(PlayerInteractEvent.class, event -> {
Player player = event.getPlayer();
InteractionType type = event.getInteractionType();
switch (type) {
case USE -> handleUse(event);
case ATTACK -> handleAttack(event);
case LOOK -> handleLook(event);
}
});// World being added (cancellable)
getEventRegistry().register(AddWorldEvent.class, "new_world", event -> {
World world = event.getWorld();
initializeWorld(world);
});
// World being removed (cancellable except EXCEPTIONAL)
getEventRegistry().register(RemoveWorldEvent.class, "old_world", event -> {
if (event.getReason() != RemoveWorldEvent.Reason.EXCEPTIONAL) {
saveWorldData(event.getWorld());
}
});
// World started
getEventRegistry().register(StartWorldEvent.class, "main", event -> {
spawnInitialEntities(event.getWorld());
});
// All worlds loaded
getEventRegistry().registerGlobal(AllWorldsLoadedEvent.class, event -> {
getLogger().atInfo().log("All worlds ready!");
});// Chunk pre-load processing
getEventRegistry().registerGlobal(
EventPriority.FIRST,
ChunkPreLoadProcessEvent.class,
event -> {
// Modify chunk before it's fully loaded
Chunk chunk = event.getChunk();
}
);getEventRegistry().register(EntityRemoveEvent.class, "world_name", event -> {
Entity entity = event.getEntity();
if (entity instanceof NPCEntity npc) {
logNPCRemoval(npc);
}
});getEventRegistry().register(
LivingEntityInventoryChangeEvent.class,
"world_name",
event -> {
LivingEntity entity = event.getEntity();
ItemStack oldItem = event.getOldItem();
ItemStack newItem = event.getNewItem();
int slot = event.getSlot();
}
);@Override
protected void setup() {
// Register event systems
getEntityStoreRegistry().registerSystem(new BreakBlockHandler());
getEntityStoreRegistry().registerSystem(new PlaceBlockHandler());
getEntityStoreRegistry().registerSystem(new UseBlockHandler());
}
public class BreakBlockHandler extends EntityEventSystem<EntityStore, BreakBlockEvent> {
public BreakBlockHandler() {
super(BreakBlockEvent.class);
}
@Override
public void handle(
int index,
ArchetypeChunk<EntityStore> chunk,
Store<EntityStore> store,
CommandBuffer<EntityStore> buffer,
BreakBlockEvent event
) {
BlockType blockType = event.getBlockType();
Vector3i position = event.getPosition();
Player player = event.getPlayer();
// Cancel if protected
if (isProtected(position)) {
event.setCancelled(true);
player.sendMessage("This area is protected!");
return;
}
// Custom drops
if (blockType.getId().equals("MyPlugin:CustomOre")) {
event.setDrops(createCustomDrops());
}
}
}public class PlaceBlockHandler extends EntityEventSystem<EntityStore, PlaceBlockEvent> {
public PlaceBlockHandler() {
super(PlaceBlockEvent.class);
}
@Override
public void handle(..., PlaceBlockEvent event) {
BlockType blockType = event.getBlockType();
Vector3i position = event.getPosition();
// Prevent placing in certain areas
if (isRestrictedArea(position)) {
event.setCancelled(true);
}
}
}public class UseBlockHandler extends EntityEventSystem<EntityStore, UseBlockEvent.Pre> {
public UseBlockHandler() {
super(UseBlockEvent.Pre.class);
}
@Override
public void handle(..., UseBlockEvent.Pre event) {
BlockType blockType = event.getBlockType();
Player player = event.getPlayer();
// Custom interaction
if (blockType.getId().equals("MyPlugin:TeleportBlock")) {
teleportPlayer(player);
event.setCancelled(true); // Prevent default behavior
}
}
}public class DamageHandler extends EntityEventSystem<EntityStore, Damage> {
private ComponentAccess<EntityStore, TransformComponent> transforms;
public DamageHandler() {
super(Damage.class);
}
@Override
protected void register(Store<EntityStore> store) {
transforms = registerComponent(TransformComponent.class);
}
@Override
public void handle(..., Damage event) {
float amount = event.getAmount();
DamageCause cause = event.getCause();
Entity source = event.getSource();
// Modify damage
if (isInSafeZone(transforms.get(chunk, index).getPosition())) {
event.setAmount(0);
event.setCancelled(true);
}
// Increase damage for critical
if (event.isCritical()) {
event.setAmount(amount * 1.5f);
}
}
}// Drop item
public class DropHandler extends EntityEventSystem<EntityStore, DropItemEvent> {
public DropHandler() {
super(DropItemEvent.class);
}
@Override
public void handle(..., DropItemEvent event) {
ItemStack item = event.getItemStack();
if (isSoulbound(item)) {
event.setCancelled(true);
}
}
}
// Pickup item
public class PickupHandler extends EntityEventSystem<EntityStore, InteractivelyPickupItemEvent> {
public PickupHandler() {
super(InteractivelyPickupItemEvent.class);
}
@Override
public void handle(..., InteractivelyPickupItemEvent event) {
ItemStack item = event.getItemStack();
Entity entity = event.getEntity();
if (!canPickup(entity, item)) {
event.setCancelled(true);
}
}
}public class CraftHandler extends EntityEventSystem<EntityStore, CraftRecipeEvent> {
public CraftHandler() {
super(CraftRecipeEvent.class);
}
@Override
public void handle(..., CraftRecipeEvent event) {
CraftingRecipe recipe = event.getRecipe();
Player player = event.getPlayer();
// Check permissions
if (!hasRecipeUnlocked(player, recipe)) {
event.setCancelled(true);
player.sendMessage("Recipe not unlocked!");
}
}
}getEventRegistry().register(
LoadedAssetsEvent.class,
BlockType.class,
event -> {
for (BlockType block : event.getLoadedAssets()) {
processBlockType(block);
}
}
);
getEventRegistry().register(
LoadedAssetsEvent.class,
Item.class,
event -> {
for (Item item : event.getLoadedAssets()) {
processItem(item);
}
}
);getEventRegistry().register(
RemovedAssetsEvent.class,
BlockType.class,
event -> {
for (String removedId : event.getRemovedIds()) {
cleanupBlockType(removedId);
}
}
);getEventRegistry().registerGlobal(AssetPackRegisterEvent.class, event -> {
AssetPack pack = event.getAssetPack();
getLogger().atInfo().log("Asset pack registered: %s", pack.getName());
});
getEventRegistry().registerGlobal(AssetPackUnregisterEvent.class, event -> {
AssetPack pack = event.getAssetPack();
getLogger().atInfo().log("Asset pack unregistered: %s", pack.getName());
});// When another plugin completes setup
getEventRegistry().register(
PluginSetupEvent.class,
OtherPlugin.class,
event -> {
OtherPlugin plugin = (OtherPlugin) event.getPlugin();
integrateWith(plugin);
}
);public class MyCustomEvent implements IEvent<Void> {
private final Player player;
private final String data;
public MyCustomEvent(Player player, String data) {
this.player = player;
this.data = data;
}
public Player getPlayer() { return player; }
public String getData() { return data; }
}
// Dispatch the event
HytaleServer.get().getEventBus()
.dispatchFor(MyCustomEvent.class)
.dispatch(new MyCustomEvent(player, "some data"));public class MyWorldEvent implements IEvent<String> {
private final World world;
public MyWorldEvent(World world) {
this.world = world;
}
public World getWorld() { return world; }
}
// Dispatch with key
HytaleServer.get().getEventBus()
.dispatchFor(MyWorldEvent.class, world.getName())
.dispatch(new MyWorldEvent(world));public class MyCancellableEvent implements IEvent<Void>, ICancellable {
private boolean cancelled = false;
private final Player player;
public MyCancellableEvent(Player player) {
this.player = player;
}
public Player getPlayer() { return player; }
@Override
public boolean isCancelled() { return cancelled; }
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}
// Dispatch and check
MyCancellableEvent event = HytaleServer.get().getEventBus()
.dispatchFor(MyCancellableEvent.class)
.dispatch(new MyCancellableEvent(player));
if (!event.isCancelled()) {
// Proceed with action
}public class MyAsyncEvent implements IAsyncEvent<Void>, ICancellable {
private boolean cancelled = false;
private final Player player;
private String result;
public MyAsyncEvent(Player player) {
this.player = player;
}
public Player getPlayer() { return player; }
public String getResult() { return result; }
public void setResult(String result) { this.result = result; }
@Override
public boolean isCancelled() { return cancelled; }
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}
// Dispatch async
HytaleServer.get().getEventBus()
.dispatchForAsync(MyAsyncEvent.class)
.dispatch(new MyAsyncEvent(player))
.thenAccept(event -> {
if (!event.isCancelled()) {
processResult(event.getResult());
}
});public class MyEntityEvent extends CancellableEcsEvent {
private final ItemStack item;
private float modifier = 1.0f;
public MyEntityEvent(ItemStack item) {
this.item = item;
}
public ItemStack getItem() { return item; }
public float getModifier() { return modifier; }
public void setModifier(float modifier) { this.modifier = modifier; }
}
// Register event type
EntityEventType<EntityStore, MyEntityEvent> eventType =
getEntityStoreRegistry().registerEntityEventType(MyEntityEvent.class);
// Invoke on entity
store.invoke(entityRef, new MyEntityEvent(itemStack));// Check for listeners before creating event
IEventDispatcher dispatcher = HytaleServer.get().getEventBus()
.dispatchFor(ExpensiveEvent.class);
if (dispatcher.hasListener()) {
dispatcher.dispatch(new ExpensiveEvent(computeExpensiveData()));
}private EventRegistration registration;
@Override
protected void setup() {
registration = getEventRegistry().registerGlobal(
SomeEvent.class,
this::handler
);
}
public void disableFeature() {
if (registration != null) {
registration.unregister();
registration = null;
}
}private void onPlayerConnect(PlayerConnectEvent event) {
try {
processPlayer(event.getPlayer());
} catch (Exception e) {
getLogger().atSevere().withCause(e).log("Error processing player connect");
// Don't rethrow - let other handlers run
}
}setup()references/event-list.mdreferences/ecs-events.md