Skip to content

Commit

Permalink
add lifecycle-events (WIP), add registerEvent method on `event-ba…
Browse files Browse the repository at this point in the history
…se-neo`, rename `load` to `loadService` in `ModUtils`
  • Loading branch information
TexBlock committed Aug 4, 2024
1 parent 5e428ce commit b353bea
Show file tree
Hide file tree
Showing 19 changed files with 623 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ build

.idea

!.idea/icon.svg
!.idea/icon.svg
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.util.ServiceLoader;

public class ModUtils {
public static <T> T load(Class<T> clazz) {
public static <T> T loadService(Class<T> clazz) {
return ServiceLoader.load(clazz).findFirst().orElseThrow(() -> new AssertionError("No impl found for " + clazz.getName()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package band.kessoku.lib.event;

public class KessokuEventBaseEntrypoint {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package band.kessoku.lib.event.util;

import net.neoforged.bus.api.Event;
import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.IEventBus;

import java.util.function.Consumer;

public class NeoEventUtils {
public static <T extends Event> void registerEvent(IEventBus eventBus, Class<T> eventClass, Consumer<T> consumer) {
eventBus.addListener(EventPriority.HIGHEST, eventClass, consumer);
}
}
16 changes: 16 additions & 0 deletions lifecycle-events-common/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
group = "band.kessoku.lib.event"
version = libs.versions.mod.get() + "+common." + libs.versions.minecraft.get()

base {
archivesName = rootProject.name + "-lifecycle-events"
}

architectury {
common(["fabric", "neoforge"])
}

dependencies {
modImplementation libs.fabric.loader
implementation(project(":base-common"))
implementation(project(":event-base-common"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package band.kessoku.lib.events.lifecycle;

public class KessokuLifecycleEvents {
public static final String MOD_ID = "kessoku_lifecycle_events";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package band.kessoku.lib.events.lifecycle.api;

import band.kessoku.lib.event.api.Event;
import net.minecraft.registry.DynamicRegistryManager;

public final class LifecycleEvents {

/**
* Called when tags are loaded or updated.
*/
public static final Event<TagLoaded> TAG_LOADED = Event.of(tagLoadeds -> (registries, client) -> {
for (TagLoaded tagLoaded : tagLoadeds) {
tagLoaded.onTagsLoaded(registries, client);
}
});

public interface TagLoaded {
/**
* @param registries Up-to-date registries from which the tags can be retrieved.
* @param client True if the client just received a sync packet, false if the server just (re)loaded the tags.
*/
void onTagsLoaded(DynamicRegistryManager registries, boolean client);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package band.kessoku.lib.events.lifecycle.api.server;

import band.kessoku.lib.event.api.Event;
import net.minecraft.resource.LifecycledResourceManager;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;

public class ServerLifecycleEvents {

/**
* Called when a Minecraft server is starting.
*
* <p>This occurs before the {@link net.minecraft.server.PlayerManager player manager} and any worlds are loaded.
*/
public static final Event<Server.Starting> STARTING = Event.of(startings -> server -> {
for (Server.Starting serverStarting : startings) {
serverStarting.onServerStarting(server);
}
});

/**
* Called when a Minecraft server has started and is about to tick for the first time.
*
* <p>At this stage, all worlds are live.
*/
public static final Event<Server.Started> STARTED = Event.of(starteds -> server -> {
for (Server.Started serverStarted : starteds) {
serverStarted.onServerStarted(server);
}
});

/**
* Called when a Minecraft server has started shutting down.
* This occurs before the server's network channel is closed and before any players are disconnected.
*
* <p>For example, an integrated server will begin stopping, but its client may continue to run.
*
* <p>All worlds are still present and can be modified.
*/
public static final Event<Server.Stopping> STOPPING = Event.of(stoppings -> server -> {
for (Server.Stopping serverStopping : stoppings) {
serverStopping.onServerStopping(server);
}
});

/**
* Called when a Minecraft server has stopped.
* All worlds have been closed and all (block)entities and players have been unloaded.
*
* <p>For example, an {@link net.fabricmc.api.EnvType#CLIENT integrated server} will begin stopping, but its client may continue to run.
* Meanwhile, for a {@link net.fabricmc.api.EnvType#SERVER dedicated server}, this will be the last event called.
*/
public static final Event<Server.Stopped> STOPPED = Event.of(stoppeds -> server -> {
for (Server.Stopped serverStopped : stoppeds) {
serverStopped.onServerStopped(server);
}
});

/**
* Called when a Minecraft server is about to send tag and recipe data to a player.
* @see Datapack.SyncContents
*/
public static final Event<Datapack.SyncContents> SYNC_DATA_PACK_CONTENTS = Event.of(syncContents -> (player, joined) -> {
for (Datapack.SyncContents syncDataPackContents : syncContents) {
syncDataPackContents.onSyncDataPackContents(player, joined);
}
});

/**
* Called before a Minecraft server reloads data packs.
*/
public static final Event<Datapack.StartReload> START_DATA_PACK_RELOAD = Event.of(startReloads -> (server, serverResourceManager) -> {
for (Datapack.StartReload startDataPackReload : startReloads) {
startDataPackReload.startDataPackReload(server, serverResourceManager);
}
});

/**
* Called after a Minecraft server has reloaded data packs.
*
* <p>If reloading data packs was unsuccessful, the current data packs will be kept.
*/
public static final Event<Datapack.EndReload> END_DATA_PACK_RELOAD = Event.of(endReloads -> (server, serverResourceManager, success) -> {
for (Datapack.EndReload endDataPackReload : endReloads) {
endDataPackReload.endDataPackReload(server, serverResourceManager, success);
}
});

/**
* Called before a Minecraft server begins saving data.
*/
public static final Event<SaveData.Before> BEFORE_SAVE = Event.of(befores -> (server, flush, force) -> {
for (SaveData.Before beforeSaveData : befores) {
beforeSaveData.onBeforeSaveData(server, flush, force);
}
});

/**
* Called after a Minecraft server finishes saving data.
*/
public static final Event<SaveData.After> AFTER_SAVE = Event.of(afters -> (server, flush, force) -> {
for (SaveData.After afterSaveData : afters) {
afterSaveData.onAfterSaveData(server, flush, force);
}
});

public interface Server {
@FunctionalInterface
interface Starting {
void onServerStarting(MinecraftServer server);
}

@FunctionalInterface
interface Started {
void onServerStarted(MinecraftServer server);
}

@FunctionalInterface
interface Stopping {
void onServerStopping(MinecraftServer server);
}

@FunctionalInterface
interface Stopped {
void onServerStopped(MinecraftServer server);
}
}

public interface Datapack {
@FunctionalInterface
interface SyncContents {
/**
* Called right before tags and recipes are sent to a player,
* either because the player joined, or because the server reloaded resources.
* The {@linkplain MinecraftServer#getResourceManager() server resource manager} is up-to-date when this is called.
*
* <p>For example, this event can be used to sync data loaded with custom resource reloaders.
*
* @param player Player to which the data is being sent.
* @param joined True if the player is joining the server, false if the server finished a successful resource reload.
*/
void onSyncDataPackContents(ServerPlayerEntity player, boolean joined);
}

@FunctionalInterface
interface StartReload {
void startDataPackReload(MinecraftServer server, LifecycledResourceManager resourceManager);
}

@FunctionalInterface
interface EndReload {
/**
* Called after data packs on a Minecraft server have been reloaded.
*
* <p>If the reload was not successful, the old data packs will be kept.
*
* @param server the server
* @param resourceManager the resource manager
* @param success if the reload was successful
*/
void endDataPackReload(MinecraftServer server, LifecycledResourceManager resourceManager, boolean success);
}
}

public interface SaveData {
@FunctionalInterface
interface Before {
/**
* Called before a Minecraft server begins saving data.
*
* @param server the server
* @param flush is true when all chunks are being written to disk, server will likely freeze during this time
* @param force whether servers that have save-off set should save
*/
void onBeforeSaveData(MinecraftServer server, boolean flush, boolean force);
}

@FunctionalInterface
interface After {
/**
* Called after a Minecraft server begins saving data.
*
* @param server the server
* @param flush is true when all chunks are being written to disk, server will likely freeze during this time
* @param force whether servers that have save-off set should save
*/
void onAfterSaveData(MinecraftServer server, boolean flush, boolean force);
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package band.kessoku.lib.events.lifecycle.api.server;

import band.kessoku.lib.event.api.Event;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;

public final class ServerTickEvents {

/**
* Called at the start of the server tick.
*/
public static final Event<ServerTick.Start> START_SERVER_TICK = Event.of(starts -> server -> {
for (ServerTick.Start start : starts) {
start.onStartTick(server);
}
});

/**
* Called at the end of the server tick.
*/
public static final Event<ServerTick.End> END_SERVER_TICK = Event.of(ends -> server -> {
for (ServerTick.End end : ends) {
end.onEndTick(server);
}
});

/**
* Called at the start of a ServerWorld's tick.
*/
public static final Event<WorldTick.Start> START_WORLD_TICK = Event.of(starts -> world -> {
for (WorldTick.Start start : starts) {
start.onStartTick(world);
}
});

/**
* Called at the end of a ServerWorld's tick.
*
* <p>End of world tick may be used to start async computations for the next tick.
*/
public static final Event<WorldTick.End> END_WORLD_TICK = Event.of(ends -> world -> {
for (WorldTick.End callback : ends) {
callback.onEndTick(world);
}
});

public interface ServerTick {
@FunctionalInterface
interface Start {
void onStartTick(MinecraftServer server);
}

@FunctionalInterface
interface End {
void onEndTick(MinecraftServer server);
}
}

public interface WorldTick {
@FunctionalInterface
interface Start {
void onStartTick(ServerWorld world);
}

@FunctionalInterface
interface End {
void onEndTick(ServerWorld world);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package band.kessoku.lib.events.lifecycle.api.server;

import band.kessoku.lib.event.api.Event;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;

public class ServerWorldEvents {

/**
* Called just after a world is loaded by a Minecraft server.
*
* <p>This can be used to load world specific metadata or initialize a {@link net.minecraft.world.PersistentState} on a server world.
*/
public static final Event<Loaded> LOADED = Event.of(loadeds -> (server, world) -> {
for (Loaded loaded : loadeds) {
loaded.onWorldLoaded(server, world);
}
});

/**
* Called before a world is unloaded by a Minecraft server.
*
* <p>This typically occurs after a server has {@link ServerLifecycleEvents#STOPPING started shutting down}.
* Mods which allow dynamic world (un)registration should call this event so mods can let go of world handles when a world is removed.
*/
public static final Event<Unloaded> UNLOADED = Event.of(unloadeds -> (server, world) -> {
for (Unloaded unloaded : unloadeds) {
unloaded.onWorldUnloaded(server, world);
}
});

@FunctionalInterface
public interface Loaded {
void onWorldLoaded(MinecraftServer server, ServerWorld world);
}

@FunctionalInterface
public interface Unloaded {
void onWorldUnloaded(MinecraftServer server, ServerWorld world);
}
}
Loading

0 comments on commit b353bea

Please sign in to comment.