mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-21 11:20:55 -04:00
Lifecycle Events V1 [1.15] (#619)
* Lifecycle Events V1 Now includes Chunk and (Block)Entity (un)load events * Add some tests to verify worlds are ticking in the log * Lambda boogaloo * Add some docs. Distinguish between a server starting to stop and server which has stopped. * Split up test mods, some tweaks to (block)entity (un)load events. Bind the ServerWorld being closed during shutdown to unload (block)entities. * Shift around a few profiler variables and finalize * Complete the tests, Block entities on server should be reliably tracked now. Entities on the server obviously still need to be wrangled. * Drop Server Entity Unload callback. Believe me, this was a hard decision but it stands on the fact that about 20-40% of entities silently unload without going through the proper "unloadEntity" method in ServerWorld. No amount of debug hacks, double tracking unload events and even replacing the entity maps do not fix this issue. So I have decided to drop this from the feature set. * checkstyle * generic-events -> item-api * Server start -> Server started * Allow getting current server from Lifecycle People have asked for this, but it is not encouraged for obvious reasons. Should be staged well enough to revert if we decide to. * checkstyle lol * update injection name * Checkstyle lol: Redundant modifiers * Add client starting, stopping and stopped callbacks. * Loicenses * Reorganize so each event category has it's own class. Also this collapses the pretty widely reaching interfaces into more specific inner classes to avoid issues with generics. * Some docs and slight name changes * Add start tick callbacks to worlds, server and client * Enhance some client related docs to life cycle * Deprecate for reasons of discouraging singletonish server getter methods in lifecycle * Add some description related to integrated server on server stopping. * Add small test to verify tick starts are right spot of load * Docs and a tiny bit more testing. * Try clarifying client docs * Drop a slightly unnessecary event * Actually call and implement START_SERVER_TICK event * Remove non-existent test * again * Refer to minecraft itself in client lifecycle docs * Refer to Minecraft itself within ServerLifecycleEvents * Remove primary server getters * IJ DO YOU SPEAK RESOLVING IMPORTS (cherry picked from commit c9257e8a11d8361469349f4171263121bb111af7) * Prune the tests that shouldn't exist * Listen here checkstyle you bugger (cherry picked from commit 9701bba4002cec089c9d3738b1f226128078c130) * Split up events to individual interfaces. Make Chunk events use WorldChunk instead.
This commit is contained in:
parent
b2771bdedd
commit
2f23104bdd
57 changed files with 2428 additions and 142 deletions
fabric-events-lifecycle-v0
build.gradle
src
main
java/net/fabricmc/fabric
api/event
client
server
world
impl/event/lifecycle
mixin/event/lifecycle
resources
testmod
java/net/fabricmc/fabric/test/event/lifecycle/legacy
resources
fabric-item-api-v1
fabric-lifecycle-events-v1
build.gradle
settings.gradlesrc
main
java/net/fabricmc/fabric
api
client/event/lifecycle/v1
ClientBlockEntityEvents.javaClientChunkEvents.javaClientEntityEvents.javaClientLifecycleEvents.javaClientTickEvents.java
event/lifecycle/v1
mixin/event/lifecycle
resources
testmod
java/net/fabricmc/fabric/test/event/lifecycle
ServerBlockEntityLifecycleTests.javaServerEntityLifecycleTests.javaServerLifecycleTests.javaServerTickTests.java
client
resources
|
@ -1,6 +1,8 @@
|
|||
archivesBaseName = "fabric-events-lifecycle-v0"
|
||||
version = getSubprojectVersion(project, "0.1.2")
|
||||
version = getSubprojectVersion(project, "0.2.0")
|
||||
|
||||
dependencies {
|
||||
compile project(path: ':fabric-api-base', configuration: 'dev')
|
||||
compile project(path: ':fabric-item-api-v1', configuration: 'dev')
|
||||
compile project(path: ':fabric-lifecycle-events-v1', configuration: 'dev')
|
||||
}
|
||||
|
|
|
@ -18,10 +18,16 @@ package net.fabricmc.fabric.api.event.client;
|
|||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Deprecated
|
||||
public interface ClientTickCallback {
|
||||
/**
|
||||
* @deprecated Please use {@link ClientTickEvents#END_CLIENT_TICK}.
|
||||
*/
|
||||
@Deprecated
|
||||
Event<ClientTickCallback> EVENT = EventFactory.createArrayBacked(ClientTickCallback.class,
|
||||
(listeners) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
|
|
|
@ -25,10 +25,15 @@ import net.minecraft.text.Text;
|
|||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
/**
|
||||
* @deprecated Please use {@link net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback}
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ItemTooltipCallback {
|
||||
/**
|
||||
* Fired after the game has appended all base tooltip lines to the list.
|
||||
*/
|
||||
@Deprecated
|
||||
Event<ItemTooltipCallback> EVENT = EventFactory.createArrayBacked(ItemTooltipCallback.class, (listeners) -> (stack, tooltipContext, lines) -> {
|
||||
for (ItemTooltipCallback callback : listeners) {
|
||||
callback.getTooltip(stack, tooltipContext, lines);
|
||||
|
|
|
@ -21,7 +21,12 @@ import net.minecraft.server.MinecraftServer;
|
|||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Deprecated
|
||||
public interface ServerStartCallback {
|
||||
/**
|
||||
* @deprecated Please use {@link net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents#SERVER_STARTED}
|
||||
*/
|
||||
@Deprecated
|
||||
Event<ServerStartCallback> EVENT = EventFactory.createArrayBacked(ServerStartCallback.class,
|
||||
(listeners) -> (server) -> {
|
||||
for (ServerStartCallback event : listeners) {
|
||||
|
|
|
@ -21,7 +21,12 @@ import net.minecraft.server.MinecraftServer;
|
|||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Deprecated
|
||||
public interface ServerStopCallback {
|
||||
/**
|
||||
* @deprecated Please use {@link net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents#SERVER_STOPPING}
|
||||
*/
|
||||
@Deprecated
|
||||
Event<ServerStopCallback> EVENT = EventFactory.createArrayBacked(ServerStopCallback.class,
|
||||
(listeners) -> (server) -> {
|
||||
for (ServerStopCallback event : listeners) {
|
||||
|
|
|
@ -20,8 +20,14 @@ import net.minecraft.server.MinecraftServer;
|
|||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
@Deprecated
|
||||
public interface ServerTickCallback {
|
||||
/**
|
||||
* @deprecated Please use {@link ServerTickEvents#END_SERVER_TICK}
|
||||
*/
|
||||
@Deprecated
|
||||
Event<ServerTickCallback> EVENT = EventFactory.createArrayBacked(ServerTickCallback.class,
|
||||
(listeners) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
|
|
|
@ -18,10 +18,18 @@ package net.fabricmc.fabric.api.event.world;
|
|||
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
@Deprecated
|
||||
public interface WorldTickCallback {
|
||||
/**
|
||||
* @deprecated The new WorldTickCallback has been split into a client and server callback.
|
||||
* Please use the {@link ServerTickEvents#END_WORLD_TICK server} or {@link ClientTickEvents#END_WORLD_TICK client} callbacks.
|
||||
*/
|
||||
@Deprecated
|
||||
Event<WorldTickCallback> EVENT = EventFactory.createArrayBacked(WorldTickCallback.class,
|
||||
(listeners) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.event.lifecycle;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.server.ServerStartCallback;
|
||||
import net.fabricmc.fabric.api.event.server.ServerStopCallback;
|
||||
import net.fabricmc.fabric.api.event.server.ServerTickCallback;
|
||||
import net.fabricmc.fabric.api.event.world.WorldTickCallback;
|
||||
|
||||
public class LegacyEventInvokers implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
// Allows deprecated events to still be invoked by the newer implementations
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> ServerStartCallback.EVENT.invoker().onStartServer(server));
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register(server -> ServerStopCallback.EVENT.invoker().onStopServer(server));
|
||||
ServerTickEvents.END_SERVER_TICK.register(server -> ServerTickCallback.EVENT.invoker().tick(server));
|
||||
// Tick old events on ServerWorld
|
||||
ServerTickEvents.END_WORLD_TICK.register(world -> WorldTickCallback.EVENT.invoker().tick(world));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.event.lifecycle.client;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.event.client.ClientTickCallback;
|
||||
import net.fabricmc.fabric.api.event.client.ItemTooltipCallback;
|
||||
import net.fabricmc.fabric.api.event.world.WorldTickCallback;
|
||||
|
||||
public class LegacyClientEventInvokers implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
// Allows deprecated events to still be invoked by the newer implementations
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> ClientTickCallback.EVENT.invoker().tick(client));
|
||||
// Tick old events on ClientWorld
|
||||
ClientTickEvents.END_WORLD_TICK.register(world -> WorldTickCallback.EVENT.invoker().tick(world));
|
||||
// This is part of item api now.
|
||||
net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback.EVENT.register((stack, context, lines) -> ItemTooltipCallback.EVENT.invoker().getTooltip(stack, context, lines));
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
import net.fabricmc.fabric.api.event.client.ClientTickCallback;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public class MixinMinecraftClient {
|
||||
@Inject(at = @At("RETURN"), method = "tick")
|
||||
public void tick(CallbackInfo info) {
|
||||
ClientTickCallback.EVENT.invoker().tick((MinecraftClient) (Object) this);
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import net.fabricmc.fabric.api.event.server.ServerStartCallback;
|
||||
import net.fabricmc.fabric.api.event.server.ServerStopCallback;
|
||||
import net.fabricmc.fabric.api.event.server.ServerTickCallback;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MixinMinecraftServer {
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;setFavicon(Lnet/minecraft/server/ServerMetadata;)V", ordinal = 0), method = "run")
|
||||
public void afterSetupServer(CallbackInfo info) {
|
||||
ServerStartCallback.EVENT.invoker().onStartServer((MinecraftServer) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "shutdown")
|
||||
public void beforeShutdownServer(CallbackInfo info) {
|
||||
ServerStopCallback.EVENT.invoker().onStopServer((MinecraftServer) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "tick")
|
||||
protected void tick(BooleanSupplier var1, CallbackInfo info) {
|
||||
ServerTickCallback.EVENT.invoker().tick((MinecraftServer) (Object) this);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.event.world.WorldTickCallback;
|
||||
|
||||
@Mixin(World.class)
|
||||
public class MixinWorld {
|
||||
// TODO split into ClientWorld/ServerWorld ticks? mmm need more mappings
|
||||
@Inject(at = @At("RETURN"), method = "tickBlockEntities")
|
||||
public void tickBlockEntitiesAfter(CallbackInfo info) {
|
||||
WorldTickCallback.EVENT.invoker().tick((World) (Object) this);
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.event.lifecycle",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"MixinMinecraftServer",
|
||||
"MixinWorld"
|
||||
],
|
||||
"client": [
|
||||
"MixinItemStack",
|
||||
"MixinMinecraftClient"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
|
@ -15,12 +15,19 @@
|
|||
"authors": [
|
||||
"FabricMC"
|
||||
],
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.impl.event.lifecycle.LegacyEventInvokers"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.impl.event.lifecycle.client.LegacyClientEventInvokers"
|
||||
]
|
||||
},
|
||||
"depends": {
|
||||
"fabricloader": ">=0.4.0",
|
||||
"fabric-api-base": "*"
|
||||
"fabric-api-base": "*",
|
||||
"fabric-item-api-v1": "*",
|
||||
"fabric-lifecycle-events-v1": "*"
|
||||
},
|
||||
"description": "Events for the game's lifecycle.",
|
||||
"mixins": [
|
||||
"fabric-events-lifecycle-v0.mixins.json"
|
||||
]
|
||||
"description": "Legacy events for the game's lifecycle, superseded by fabric-lifecycle-events-v1 and fabric-item-api-v1."
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle.legacy;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.server.ServerStartCallback;
|
||||
import net.fabricmc.fabric.api.event.server.ServerStopCallback;
|
||||
import net.fabricmc.fabric.api.event.server.ServerTickCallback;
|
||||
import net.fabricmc.fabric.api.event.world.WorldTickCallback;
|
||||
|
||||
public class LegacyLifecycleEventsTest implements ModInitializer {
|
||||
public static final Logger LOGGER = LogManager.getLogger("LegacyLifecycleEventsTest");
|
||||
private Map<DimensionType, Integer> tickTracker = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
ServerTickCallback.EVENT.register(server -> {
|
||||
if (server.getTicks() % 200 == 0) { // Log every 200 ticks to verify the tick callback works on the server
|
||||
LOGGER.info("Ticked Server at " + server.getTicks() + " ticks. (Legacy)");
|
||||
}
|
||||
});
|
||||
|
||||
ServerStartCallback.EVENT.register(server -> {
|
||||
LOGGER.info("Started Server! (Legacy)");
|
||||
});
|
||||
|
||||
ServerStopCallback.EVENT.register(server -> {
|
||||
LOGGER.info("Stopping Server! (Legacy)");
|
||||
});
|
||||
|
||||
WorldTickCallback.EVENT.register(world -> {
|
||||
final int worldTicks = tickTracker.computeIfAbsent(world.dimension.getType(), k -> 0);
|
||||
|
||||
if (worldTicks % 200 == 0) { // Log every 200 ticks to verify the tick callback works on the server world
|
||||
LOGGER.info("[LEGACY] Ticked World " + world.dimension.getType() + " - " + worldTicks + " ticks: " + world.getClass().getName());
|
||||
}
|
||||
|
||||
this.tickTracker.put(world.dimension.getType(), worldTicks + 1);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle.legacy.client;
|
||||
|
||||
import net.minecraft.text.LiteralText;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.event.client.ClientTickCallback;
|
||||
import net.fabricmc.fabric.api.event.client.ItemTooltipCallback;
|
||||
import net.fabricmc.fabric.test.event.lifecycle.legacy.LegacyLifecycleEventsTest;
|
||||
|
||||
public class LegacyClientLifecycleEventsTest implements ClientModInitializer {
|
||||
private int ticks;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientTickCallback.EVENT.register(client -> {
|
||||
this.ticks++; // Just track our own tick since the client doesn't have a ticks value.
|
||||
|
||||
if (this.ticks % 200 == 0) {
|
||||
LegacyLifecycleEventsTest.LOGGER.info("Ticked Client at " + this.ticks + " ticks. (Legacy)");
|
||||
}
|
||||
});
|
||||
|
||||
ItemTooltipCallback.EVENT.register((stack, context, lines) -> {
|
||||
lines.add(new LiteralText("A Legacy Tooltip"));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-events-lifecycle-v0-testmod",
|
||||
"name": "Fabric Events Lifecycle (v0) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-events-lifecycle-v0": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.event.lifecycle.legacy.LegacyLifecycleEventsTest"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.event.lifecycle.legacy.client.LegacyClientLifecycleEventsTest"
|
||||
]
|
||||
}
|
||||
}
|
6
fabric-item-api-v1/build.gradle
Normal file
6
fabric-item-api-v1/build.gradle
Normal file
|
@ -0,0 +1,6 @@
|
|||
archivesBaseName = "fabric-item-api-v1"
|
||||
version = getSubprojectVersion(project, "1.0.0")
|
||||
|
||||
dependencies {
|
||||
compile project(path: ':fabric-api-base', configuration: 'dev')
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.item.v1;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.item.TooltipContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public interface ItemTooltipCallback {
|
||||
/**
|
||||
* Fired after the game has appended all base tooltip lines to the list.
|
||||
*/
|
||||
Event<ItemTooltipCallback> EVENT = EventFactory.createArrayBacked(ItemTooltipCallback.class, callbacks -> (stack, context, lines) -> {
|
||||
for (ItemTooltipCallback callback : callbacks) {
|
||||
callback.getTooltip(stack, context, lines);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called when an item stack's tooltip is rendered. Text added to {@code lines} will be
|
||||
* rendered with the tooltip.
|
||||
*
|
||||
* @param lines the list containing the lines of text displayed on the stack's tooltip
|
||||
*/
|
||||
void getTooltip(ItemStack stack, TooltipContext context, List<Text> lines);
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle;
|
||||
package net.fabricmc.fabric.mixin.item.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -28,10 +28,10 @@ import net.minecraft.entity.player.PlayerEntity;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.api.event.client.ItemTooltipCallback;
|
||||
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
|
||||
|
||||
@Mixin(ItemStack.class)
|
||||
public class MixinItemStack {
|
||||
public abstract class ItemStackMixin {
|
||||
@Inject(method = "getTooltip", at = @At("RETURN"))
|
||||
private void getTooltip(PlayerEntity entity, TooltipContext tooltipContext, CallbackInfoReturnable<List<Text>> info) {
|
||||
ItemTooltipCallback.EVENT.invoker().getTooltip((ItemStack) (Object) this, tooltipContext, info.getReturnValue());
|
Binary file not shown.
After ![]() (image error) Size: 1.5 KiB |
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.item",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"client": [
|
||||
"client.ItemStackMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
26
fabric-item-api-v1/src/main/resources/fabric.mod.json
Normal file
26
fabric-item-api-v1/src/main/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-item-api-v1",
|
||||
"name": "Fabric Item API (v1)",
|
||||
"version": "${version}",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"icon": "assets/fabric-item-api-v1/icon.png",
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net",
|
||||
"irc": "irc://irc.esper.net:6667/fabric",
|
||||
"issues": "https://github.com/FabricMC/fabric/issues",
|
||||
"sources": "https://github.com/FabricMC/fabric"
|
||||
},
|
||||
"authors": [
|
||||
"FabricMC"
|
||||
],
|
||||
"mixins": [
|
||||
"fabric-item-api-v1.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.4.0",
|
||||
"fabric-api-base": "*"
|
||||
},
|
||||
"description": "Hooks for items"
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.item.client;
|
||||
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Formatting;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class TooltipTests implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
// Adds a tooltip to all items so testing can be verified easily.
|
||||
ItemTooltipCallback.EVENT.register((stack, context, lines) -> {
|
||||
lines.add(new LiteralText("Fancy Tooltips").formatted(Formatting.LIGHT_PURPLE));
|
||||
});
|
||||
}
|
||||
}
|
16
fabric-item-api-v1/src/testmod/resources/fabric.mod.json
Normal file
16
fabric-item-api-v1/src/testmod/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-item-api-v1-testmod",
|
||||
"name": "Fabric Item API (v1) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-item-api-v1": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.item.client.TooltipTests"
|
||||
]
|
||||
}
|
||||
}
|
6
fabric-lifecycle-events-v1/build.gradle
Normal file
6
fabric-lifecycle-events-v1/build.gradle
Normal file
|
@ -0,0 +1,6 @@
|
|||
archivesBaseName = "fabric-lifecycle-events-v1"
|
||||
version = getSubprojectVersion(project, "1.0.0")
|
||||
|
||||
dependencies {
|
||||
compile project(path: ':fabric-api-base', configuration: 'dev')
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ClientBlockEntityEvents {
|
||||
private ClientBlockEntityEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a BlockEntity is loaded into a ClientWorld.
|
||||
*
|
||||
* <p>When this event is called, the block entity is already in the world.
|
||||
*/
|
||||
public static final Event<ClientBlockEntityEvents.Load> BLOCK_ENTITY_LOAD = EventFactory.createArrayBacked(ClientBlockEntityEvents.Load.class, callbacks -> (blockEntity, world) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricClientBlockEntityLoad");
|
||||
|
||||
for (ClientBlockEntityEvents.Load callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onLoad(blockEntity, world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ClientBlockEntityEvents.Load callback : callbacks) {
|
||||
callback.onLoad(blockEntity, world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called when a BlockEntity is about to be unloaded from a ClientWorld.
|
||||
*
|
||||
* <p>When this event is called, the block entity is still present on the world.
|
||||
*/
|
||||
public static final Event<ClientBlockEntityEvents.Unload> BLOCK_ENTITY_UNLOAD = EventFactory.createArrayBacked(ClientBlockEntityEvents.Unload.class, callbacks -> (blockEntity, world) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricClientBlockEntityUnload");
|
||||
|
||||
for (ClientBlockEntityEvents.Unload callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onUnload(blockEntity, world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ClientBlockEntityEvents.Unload callback : callbacks) {
|
||||
callback.onUnload(blockEntity, world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public interface Load {
|
||||
void onLoad(BlockEntity blockEntity, ClientWorld world);
|
||||
}
|
||||
|
||||
public interface Unload {
|
||||
void onUnload(BlockEntity blockEntity, ClientWorld world);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
import net.minecraft.world.chunk.WorldChunk;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ClientChunkEvents {
|
||||
private ClientChunkEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a chunk is loaded into a ClientWorld.
|
||||
*
|
||||
* <p>When this event is called, the chunk is already in the world.
|
||||
*/
|
||||
public static final Event<ClientChunkEvents.Load> CHUNK_LOAD = EventFactory.createArrayBacked(ClientChunkEvents.Load.class, callbacks -> (clientWorld, chunk) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
Profiler profiler = clientWorld.getProfiler();
|
||||
profiler.push("fabricClientChunkLoad");
|
||||
|
||||
for (ClientChunkEvents.Load callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onChunkLoad(clientWorld, chunk);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ClientChunkEvents.Load callback : callbacks) {
|
||||
callback.onChunkLoad(clientWorld, chunk);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called when a chunk is about to be unloaded from a ClientWorld.
|
||||
*
|
||||
* <p>When this event is called, the chunk is still present in the world.
|
||||
*/
|
||||
public static final Event<ClientChunkEvents.Unload> CHUNK_UNLOAD = EventFactory.createArrayBacked(ClientChunkEvents.Unload.class, callbacks -> (clientWorld, chunk) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = clientWorld.getProfiler();
|
||||
profiler.push("fabricClientChunkUnload");
|
||||
|
||||
for (ClientChunkEvents.Unload callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onChunkUnload(clientWorld, chunk);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ClientChunkEvents.Unload callback : callbacks) {
|
||||
callback.onChunkUnload(clientWorld, chunk);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public interface Load {
|
||||
void onChunkLoad(ClientWorld world, WorldChunk chunk);
|
||||
}
|
||||
|
||||
public interface Unload {
|
||||
void onChunkUnload(ClientWorld world, WorldChunk chunk);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ClientEntityEvents {
|
||||
public ClientEntityEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an Entity is loaded into a ClientWorld.
|
||||
*
|
||||
* <p>When this event is called, the chunk is already in the world.
|
||||
*/
|
||||
public static final Event<ClientEntityEvents.Load> ENTITY_LOAD = EventFactory.createArrayBacked(ClientEntityEvents.Load.class, callbacks -> (entity, world) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricClientEntityLoad");
|
||||
|
||||
for (ClientEntityEvents.Load callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onLoad(entity, world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ClientEntityEvents.Load callback : callbacks) {
|
||||
callback.onLoad(entity, world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called when an Entity is about to be unloaded from a ClientWorld.
|
||||
*
|
||||
* <p>When this event is called, the entity is still present in the world.
|
||||
*/
|
||||
public static final Event<ClientEntityEvents.Unload> ENTITY_UNLOAD = EventFactory.createArrayBacked(ClientEntityEvents.Unload.class, callbacks -> (entity, world) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricClientEntityLoad");
|
||||
|
||||
for (ClientEntityEvents.Unload callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onUnload(entity, world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ClientEntityEvents.Unload callback : callbacks) {
|
||||
callback.onUnload(entity, world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public interface Load {
|
||||
void onLoad(Entity entity, ClientWorld world);
|
||||
}
|
||||
|
||||
public interface Unload {
|
||||
void onUnload(Entity entity, ClientWorld world);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ClientLifecycleEvents {
|
||||
private ClientLifecycleEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Minecraft has started and it's client about to tick for the first time.
|
||||
*
|
||||
* <p>This occurs while the splash screen is displayed.
|
||||
*/
|
||||
public static final Event<ClientStarted> CLIENT_STARTED = EventFactory.createArrayBacked(ClientStarted.class, callbacks -> client -> {
|
||||
for (ClientStarted callback : callbacks) {
|
||||
callback.onClientStarted(client);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called when Minecraft's client begins to stop.
|
||||
* This is caused by quitting while in game, or closing the game window.
|
||||
*
|
||||
* <p>This will be called before the integrated server is stopped if it is running.
|
||||
*/
|
||||
public static final Event<ClientStopping> CLIENT_STOPPING = EventFactory.createArrayBacked(ClientStopping.class, callbacks -> client -> {
|
||||
for (ClientStopping callback : callbacks) {
|
||||
callback.onClientStopping(client);
|
||||
}
|
||||
});
|
||||
|
||||
public interface ClientStarted {
|
||||
void onClientStarted(MinecraftClient client);
|
||||
}
|
||||
|
||||
public interface ClientStopping {
|
||||
void onClientStopping(MinecraftClient client);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ClientTickEvents {
|
||||
public ClientTickEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at the start of the client tick.
|
||||
*/
|
||||
public static final Event<StartTick> START_CLIENT_TICK = EventFactory.createArrayBacked(StartTick.class, callbacks -> client -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = client.getProfiler();
|
||||
profiler.push("fabricStartClientTick");
|
||||
|
||||
for (StartTick event : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(event));
|
||||
event.onStartTick(client);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (StartTick event : callbacks) {
|
||||
event.onStartTick(client);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called at the end of the client tick.
|
||||
*/
|
||||
public static final Event<EndTick> END_CLIENT_TICK = EventFactory.createArrayBacked(EndTick.class, callbacks -> client -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = client.getProfiler();
|
||||
profiler.push("fabricEndClientTick");
|
||||
|
||||
for (EndTick event : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(event));
|
||||
event.onEndTick(client);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (EndTick event : callbacks) {
|
||||
event.onEndTick(client);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called at the start of a ClientWorld's tick.
|
||||
*/
|
||||
public static final Event<StartWorldTick> START_WORLD_TICK = EventFactory.createArrayBacked(StartWorldTick.class, callbacks -> world -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricStartClientWorldTick");
|
||||
|
||||
for (StartWorldTick callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onStartTick(world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (StartWorldTick callback : callbacks) {
|
||||
callback.onStartTick(world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called at the end of a ClientWorld's tick.
|
||||
*
|
||||
* <p>End of world tick may be used to start async computations for the next tick.
|
||||
*/
|
||||
public static final Event<EndWorldTick> END_WORLD_TICK = EventFactory.createArrayBacked(EndWorldTick.class, callbacks -> world -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricEndClientWorldTick");
|
||||
|
||||
for (EndWorldTick callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onEndTick(world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (EndWorldTick callback : callbacks) {
|
||||
callback.onEndTick(world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public interface StartTick {
|
||||
void onStartTick(MinecraftClient client);
|
||||
}
|
||||
|
||||
public interface EndTick {
|
||||
void onEndTick(MinecraftClient client);
|
||||
}
|
||||
|
||||
public interface StartWorldTick {
|
||||
void onStartTick(ClientWorld world);
|
||||
}
|
||||
|
||||
public interface EndWorldTick {
|
||||
void onEndTick(ClientWorld world);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
public final class ServerBlockEntityEvents {
|
||||
private ServerBlockEntityEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an BlockEntity is loaded into a ServerWorld.
|
||||
*
|
||||
* <p>When this is event is called, the block entity is already in the world.
|
||||
*/
|
||||
public static final Event<ServerBlockEntityEvents.Load> BLOCK_ENTITY_LOAD = EventFactory.createArrayBacked(ServerBlockEntityEvents.Load.class, callbacks -> (blockEntity, world) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricServerBlockEntityLoad");
|
||||
|
||||
for (ServerBlockEntityEvents.Load callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onLoad(blockEntity, world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ServerBlockEntityEvents.Load callback : callbacks) {
|
||||
callback.onLoad(blockEntity, world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called when an BlockEntity is about to be unloaded from a ServerWorld.
|
||||
*
|
||||
* <p>When this event is called, the block entity is still present on the world.
|
||||
*/
|
||||
public static final Event<Unload> BLOCK_ENTITY_UNLOAD = EventFactory.createArrayBacked(ServerBlockEntityEvents.Unload.class, callbacks -> (blockEntity, world) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricServerBlockEntityUnload");
|
||||
|
||||
for (ServerBlockEntityEvents.Unload callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onUnload(blockEntity, world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ServerBlockEntityEvents.Unload callback : callbacks) {
|
||||
callback.onUnload(blockEntity, world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public interface Load {
|
||||
void onLoad(BlockEntity blockEntity, ServerWorld world);
|
||||
}
|
||||
|
||||
public interface Unload {
|
||||
void onUnload(BlockEntity blockEntity, ServerWorld world);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
import net.minecraft.world.chunk.WorldChunk;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
public final class ServerChunkEvents {
|
||||
private ServerChunkEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an chunk is loaded into a ServerWorld.
|
||||
*
|
||||
* <p>When this event is called, the chunk is already in the world.
|
||||
*/
|
||||
public static final Event<ServerChunkEvents.Load> CHUNK_LOAD = EventFactory.createArrayBacked(ServerChunkEvents.Load.class, callbacks -> (serverWorld, chunk) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = serverWorld.getProfiler();
|
||||
profiler.push("fabricServerChunkLoad");
|
||||
|
||||
for (ServerChunkEvents.Load callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onChunkLoad(serverWorld, chunk);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ServerChunkEvents.Load callback : callbacks) {
|
||||
callback.onChunkLoad(serverWorld, chunk);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called when an chunk is unloaded from a ServerWorld.
|
||||
*
|
||||
* <p>When this event is called, the chunk is still present in the world.
|
||||
*/
|
||||
public static final Event<ServerChunkEvents.Unload> CHUNK_UNLOAD = EventFactory.createArrayBacked(ServerChunkEvents.Unload.class, callbacks -> (serverWorld, chunk) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = serverWorld.getProfiler();
|
||||
profiler.push("fabricServerChunkUnload");
|
||||
|
||||
for (ServerChunkEvents.Unload callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onChunkUnload(serverWorld, chunk);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ServerChunkEvents.Unload callback : callbacks) {
|
||||
callback.onChunkUnload(serverWorld, chunk);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public interface Load {
|
||||
void onChunkLoad(ServerWorld world, WorldChunk chunk);
|
||||
}
|
||||
|
||||
public interface Unload {
|
||||
void onChunkUnload(ServerWorld world, WorldChunk chunk);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
public final class ServerEntityEvents {
|
||||
private ServerEntityEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an Entity is loaded into a ServerWorld.
|
||||
*
|
||||
* <p>When this event is called, the entity is already in the world.
|
||||
*
|
||||
* <p>Note there is no corresponding unload event because entity unloads cannot be reliably tracked.
|
||||
*/
|
||||
public static final Event<ServerEntityEvents.Load> ENTITY_LOAD = EventFactory.createArrayBacked(ServerEntityEvents.Load.class, callbacks -> (entity, world) -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricServerEntityLoad");
|
||||
|
||||
for (ServerEntityEvents.Load callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onLoad(entity, world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (ServerEntityEvents.Load callback : callbacks) {
|
||||
callback.onLoad(entity, world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public interface Load {
|
||||
void onLoad(Entity entity, ServerWorld world);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
public final class ServerLifecycleEvents {
|
||||
private ServerLifecycleEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<ServerStarted> SERVER_STARTED = EventFactory.createArrayBacked(ServerStarted.class, (callbacks) -> (server) -> {
|
||||
for (ServerStarted callback : callbacks) {
|
||||
callback.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 it's client may continue to run.
|
||||
*
|
||||
* <p>All worlds are still present and can be modified.
|
||||
*/
|
||||
public static final Event<ServerStopping> SERVER_STOPPING = EventFactory.createArrayBacked(ServerStopping.class, (callbacks) -> (server) -> {
|
||||
for (ServerStopping callback : callbacks) {
|
||||
callback.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 it's 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<ServerStopped> SERVER_STOPPED = EventFactory.createArrayBacked(ServerStopped.class, callbacks -> server -> {
|
||||
for (ServerStopped callback : callbacks) {
|
||||
callback.onServerStopped(server);
|
||||
}
|
||||
});
|
||||
|
||||
public interface ServerStarted {
|
||||
void onServerStarted(MinecraftServer server);
|
||||
}
|
||||
|
||||
public interface ServerStopping {
|
||||
void onServerStopping(MinecraftServer server);
|
||||
}
|
||||
|
||||
public interface ServerStopped {
|
||||
void onServerStopped(MinecraftServer server);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.event.lifecycle.v1;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
public final class ServerTickEvents {
|
||||
private ServerTickEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at the start of the server tick.
|
||||
*/
|
||||
public static final Event<StartTick> START_SERVER_TICK = EventFactory.createArrayBacked(StartTick.class, callbacks -> server -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = server.getProfiler();
|
||||
profiler.push("fabricStartServerTick");
|
||||
|
||||
for (StartTick event : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(event));
|
||||
event.onStartTick(server);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (StartTick event : callbacks) {
|
||||
event.onStartTick(server);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called at the end of the server tick.
|
||||
*/
|
||||
public static final Event<EndTick> END_SERVER_TICK = EventFactory.createArrayBacked(EndTick.class, callbacks -> server -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = server.getProfiler();
|
||||
profiler.push("fabricEndServerTick");
|
||||
|
||||
for (EndTick event : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(event));
|
||||
event.onEndTick(server);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (EndTick event : callbacks) {
|
||||
event.onEndTick(server);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Called at the start of a ServerWorld's tick.
|
||||
*/
|
||||
public static final Event<StartWorldTick> START_WORLD_TICK = EventFactory.createArrayBacked(StartWorldTick.class, callbacks -> world -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricStartServerWorldTick_" + world.dimension.getType().toString());
|
||||
|
||||
for (StartWorldTick callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onStartTick(world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (StartWorldTick callback : callbacks) {
|
||||
callback.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<EndWorldTick> END_WORLD_TICK = EventFactory.createArrayBacked(EndWorldTick.class, callbacks -> world -> {
|
||||
if (EventFactory.isProfilingEnabled()) {
|
||||
final Profiler profiler = world.getProfiler();
|
||||
profiler.push("fabricEndServerWorldTick_" + world.dimension.getType().toString());
|
||||
|
||||
for (EndWorldTick callback : callbacks) {
|
||||
profiler.push(EventFactory.getHandlerName(callback));
|
||||
callback.onEndTick(world);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
profiler.pop();
|
||||
} else {
|
||||
for (EndWorldTick callback : callbacks) {
|
||||
callback.onEndTick(world);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public interface StartTick {
|
||||
void onStartTick(MinecraftServer server);
|
||||
}
|
||||
|
||||
public interface EndTick {
|
||||
void onEndTick(MinecraftServer server);
|
||||
}
|
||||
|
||||
public interface StartWorldTick {
|
||||
void onStartTick(ServerWorld world);
|
||||
}
|
||||
|
||||
public interface EndWorldTick {
|
||||
void onEndTick(ServerWorld world);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public abstract class MinecraftServerMixin {
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;setFavicon(Lnet/minecraft/server/ServerMetadata;)V", ordinal = 0), method = "run")
|
||||
private void afterSetupServer(CallbackInfo info) {
|
||||
ServerLifecycleEvents.SERVER_STARTED.invoker().onServerStarted((MinecraftServer) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "shutdown")
|
||||
private void beforeShutdownServer(CallbackInfo info) {
|
||||
ServerLifecycleEvents.SERVER_STOPPING.invoker().onServerStopping((MinecraftServer) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "shutdown")
|
||||
private void afterShutdownServer(CallbackInfo info) {
|
||||
ServerLifecycleEvents.SERVER_STOPPED.invoker().onServerStopped((MinecraftServer) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tickWorlds(Ljava/util/function/BooleanSupplier;)V"), method = "tick")
|
||||
private void onStartTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) {
|
||||
ServerTickEvents.START_SERVER_TICK.invoker().onStartTick((MinecraftServer) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "tick")
|
||||
private void onEndTick(BooleanSupplier shouldKeepTicking, CallbackInfo info) {
|
||||
ServerTickEvents.END_SERVER_TICK.invoker().onEndTick((MinecraftServer) (Object) this);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a world is closed, it means the world will be unloaded.
|
||||
*/
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;close()V"), method = "shutdown", locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
private void closeWorld(CallbackInfo ci, Iterator<ServerWorld> worlds, ServerWorld serverWorld) {
|
||||
final List<Entity> entities = serverWorld.getEntities(null, entity -> true); // Get every single entity in the world
|
||||
|
||||
for (BlockEntity blockEntity : serverWorld.blockEntities) {
|
||||
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, serverWorld);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
@Mixin(ServerWorld.class)
|
||||
public abstract class ServerWorldMixin {
|
||||
@Shadow
|
||||
private boolean ticking;
|
||||
|
||||
// Call our load event after vanilla has loaded the entity
|
||||
@Inject(method = "loadEntityUnchecked", at = @At("TAIL"))
|
||||
private void onLoadEntity(Entity entity, CallbackInfo ci) {
|
||||
if (!this.ticking) { // Copy vanilla logic, we cannot load entities while the game is ticking entities
|
||||
ServerEntityEvents.ENTITY_LOAD.invoker().onLoad(entity, (ServerWorld) (Object) this);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure "insideTick" is true before we call the start tick, so inject after it is set
|
||||
@Inject(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/server/world/ServerWorld;insideTick:Z", opcode = Opcodes.PUTFIELD, ordinal = 0, shift = At.Shift.AFTER))
|
||||
private void startWorldTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) {
|
||||
ServerTickEvents.START_WORLD_TICK.invoker().onStartTick((ServerWorld) (Object) this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.server.world.ChunkHolder;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.server.world.ThreadedAnvilChunkStorage;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.WorldChunk;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
||||
|
||||
@Mixin(ThreadedAnvilChunkStorage.class)
|
||||
public abstract class ThreadedAnvilChunkStorageMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private ServerWorld world;
|
||||
|
||||
// Chunk (Un)Load events, An explanation:
|
||||
// Must of this code is wrapped inside of futures and consumers, so it's generally a mess.
|
||||
|
||||
/**
|
||||
* Injection is inside of tryUnloadChunk.
|
||||
* We inject just after "setLoadedToWorld" is made false, since here the WorldChunk is guaranteed to be unloaded.
|
||||
*/
|
||||
@Inject(method = "method_18843", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/WorldChunk;setLoadedToWorld(Z)V", shift = At.Shift.AFTER))
|
||||
private void onChunkUnload(ChunkHolder chunkHolder, CompletableFuture<Chunk> chunkFuture, long pos, Chunk chunk, CallbackInfo ci) {
|
||||
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(this.world, (WorldChunk) chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection is inside of convertToFullChunk?
|
||||
*
|
||||
* <p>The following is expected contractually
|
||||
*
|
||||
* <ul><li>the chunk being loaded MUST be a WorldChunk.
|
||||
* <li>everything within the chunk has been loaded into the world. Entities, BlockEntities, etc.</ul>
|
||||
*/
|
||||
@Inject(method = "method_17227", at = @At("TAIL"))
|
||||
private void onChunkLoad(ChunkHolder chunkHolder, Chunk protoChunk, CallbackInfoReturnable<Chunk> callbackInfoReturnable) {
|
||||
// We fire the event at TAIL since the chunk is guaranteed to be a WorldChunk then.
|
||||
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad(this.world, (WorldChunk) callbackInfoReturnable.getReturnValue());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
@Mixin(World.class)
|
||||
public abstract class WorldMixin {
|
||||
@Shadow
|
||||
public abstract boolean isClient();
|
||||
|
||||
@Shadow
|
||||
public abstract Profiler getProfiler();
|
||||
|
||||
@Inject(method = "addBlockEntity", at = @At("TAIL"))
|
||||
protected void onLoadBlockEntity(BlockEntity blockEntity, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (!this.isClient()) { // Only fire this event if we are a server world
|
||||
ServerBlockEntityEvents.BLOCK_ENTITY_LOAD.invoker().onLoad(blockEntity, (ServerWorld) (Object) this);
|
||||
}
|
||||
}
|
||||
|
||||
// Mojang what hell, why do you need three ways to unload block entities
|
||||
@Inject(method = "removeBlockEntity", at = @At(value = "INVOKE", target = "Ljava/util/List;remove(Ljava/lang/Object;)Z", ordinal = 1), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
protected void onUnloadBlockEntity(BlockPos pos, CallbackInfo ci, BlockEntity blockEntity) {
|
||||
if (!this.isClient()) { // Only fire this event if we are a server world
|
||||
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, (ServerWorld) (Object) this);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tickBlockEntities", at = @At(value = "INVOKE", target = "Ljava/util/List;remove(Ljava/lang/Object;)Z"), slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;pop()V"), to = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/WorldChunk;removeBlockEntity(Lnet/minecraft/util/math/BlockPos;)V")), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
protected void onRemoveBlockEntity(CallbackInfo ci, Profiler profiler, Iterator iterator, BlockEntity blockEntity) {
|
||||
if (!this.isClient()) {
|
||||
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, (ServerWorld) (Object) this);
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "tickBlockEntities", at = @At(value = "INVOKE", target = "Ljava/util/List;removeAll(Ljava/util/Collection;)Z", ordinal = 1))
|
||||
protected boolean onPurgeRemovedBlockEntities(List<BlockEntity> blockEntityList, Collection<BlockEntity> removals) {
|
||||
if (!this.isClient()) {
|
||||
for (BlockEntity removal : removals) {
|
||||
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(removal, (ServerWorld) (Object) this);
|
||||
}
|
||||
}
|
||||
|
||||
// Mimic vanilla logic
|
||||
return blockEntityList.removeAll(removals);
|
||||
}
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "tickBlockEntities")
|
||||
protected void tickWorldAfterBlockEntities(CallbackInfo ci) {
|
||||
if (!this.isClient()) {
|
||||
ServerTickEvents.END_WORLD_TICK.invoker().onEndTick((ServerWorld) (Object) this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.client.world.ClientChunkManager;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
import net.minecraft.world.biome.source.BiomeArray;
|
||||
import net.minecraft.world.chunk.WorldChunk;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(ClientChunkManager.class)
|
||||
public abstract class ClientChunkManagerMixin {
|
||||
@Final
|
||||
@Shadow
|
||||
private ClientWorld world;
|
||||
|
||||
@Inject(method = "loadChunkFromPacket", at = @At("TAIL")) // 1.16 has a boolean param here. I think it means whether the packet is complete.
|
||||
private void onChunkLoad(int chunkX, int chunkZ, BiomeArray biomes, PacketByteBuf buf, CompoundTag tag, int k, /* boolean complete, */ CallbackInfoReturnable<WorldChunk> cir) {
|
||||
ClientChunkEvents.CHUNK_LOAD.invoker().onChunkLoad(this.world, cir.getReturnValue());
|
||||
}
|
||||
|
||||
@Inject(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
private void onChunkUnload(int chunkX, int chunkZ, CallbackInfo ci, int i, WorldChunk chunk) {
|
||||
ClientChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(this.world, chunk);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.packet.GameJoinS2CPacket;
|
||||
import net.minecraft.client.network.packet.PlayerRespawnS2CPacket;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(ClientPlayNetworkHandler.class)
|
||||
public abstract class ClientPlayNetworkHandlerMixin {
|
||||
@Shadow
|
||||
private ClientWorld world;
|
||||
|
||||
@Inject(method = "onPlayerRespawn", at = @At(value = "NEW", target = "net/minecraft/client/world/ClientWorld"))
|
||||
private void onPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) {
|
||||
// If a world already exists, we need to unload all (block)entities in the world.
|
||||
if (this.world != null) {
|
||||
for (Entity entity : world.getEntities()) {
|
||||
ClientEntityEvents.ENTITY_UNLOAD.invoker().onUnload(entity, this.world);
|
||||
}
|
||||
|
||||
for (BlockEntity blockEntity : world.blockEntities) {
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, this.world);
|
||||
// No need to clear the `tickingBlockEntities` list since it will be null in just an instant
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An explanation why we unload entities during onGameJoin:
|
||||
* Proxies such as Waterfall may send another Game Join packet if entity meta rewrite is disabled, so we will cover ourselves.
|
||||
* Velocity by default will send a Game Join packet when the player changes servers, which will create a new client world.
|
||||
* Also anyone can send another GameJoinPacket at any time, so we need to watch out.
|
||||
*/
|
||||
@Inject(method = "onGameJoin", at = @At(value = "NEW", target = "net/minecraft/client/world/ClientWorld"))
|
||||
private void onGameJoin(GameJoinS2CPacket packet, CallbackInfo ci) {
|
||||
// If a world already exists, we need to unload all (block)entities in the world.
|
||||
if (this.world != null) {
|
||||
for (Entity entity : world.getEntities()) {
|
||||
ClientEntityEvents.ENTITY_UNLOAD.invoker().onUnload(entity, this.world);
|
||||
}
|
||||
|
||||
for (BlockEntity blockEntity : world.blockEntities) {
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, this.world);
|
||||
// No need to clear the `tickingBlockEntities` list since it will be null in just an instant
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the client disconnects from a server.
|
||||
@Inject(method = "clearWorld", at = @At("HEAD"))
|
||||
private void onClearWorld(CallbackInfo ci) {
|
||||
// If a world already exists, we need to unload all (block)entities in the world.
|
||||
if (this.world != null) {
|
||||
for (Entity entity : world.getEntities()) {
|
||||
ClientEntityEvents.ENTITY_UNLOAD.invoker().onUnload(entity, this.world);
|
||||
}
|
||||
|
||||
for (BlockEntity blockEntity : world.blockEntities) {
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, this.world);
|
||||
// No need to clear the `tickingBlockEntities` list since it will be null in just an instant
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle.client;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.mixin.event.lifecycle.WorldMixin;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(ClientWorld.class)
|
||||
public abstract class ClientWorldMixin extends WorldMixin {
|
||||
// Call our load event after vanilla has loaded the entity
|
||||
@Inject(method = "addEntityPrivate", at = @At("TAIL"))
|
||||
private void onEntityLoad(int id, Entity entity, CallbackInfo ci) {
|
||||
ClientEntityEvents.ENTITY_LOAD.invoker().onLoad(entity, (ClientWorld) (Object) this);
|
||||
}
|
||||
|
||||
// Call our unload event before vanilla does.
|
||||
@Inject(method = "finishRemovingEntity", at = @At("HEAD"))
|
||||
private void onEntityUnload(Entity entity, CallbackInfo ci) {
|
||||
ClientEntityEvents.ENTITY_UNLOAD.invoker().onUnload(entity, (ClientWorld) (Object) this);
|
||||
}
|
||||
|
||||
// We override our injection on the clientworld so only the client's block entity invocations will run
|
||||
@Override
|
||||
protected void onLoadBlockEntity(BlockEntity blockEntity, CallbackInfoReturnable<Boolean> cir) {
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_LOAD.invoker().onLoad(blockEntity, (ClientWorld) (Object) this);
|
||||
}
|
||||
|
||||
// We override our injection on the clientworld so only the client's block entity invocations will run
|
||||
@Override
|
||||
protected void onUnloadBlockEntity(BlockPos pos, CallbackInfo ci, BlockEntity blockEntity) {
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, (ClientWorld) (Object) this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemoveBlockEntity(CallbackInfo ci, Profiler profiler, Iterator iterator, BlockEntity blockEntity) {
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, (ClientWorld) (Object) this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onPurgeRemovedBlockEntities(List<BlockEntity> blockEntityList, Collection<BlockEntity> removals) {
|
||||
for (BlockEntity removal : removals) {
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(removal, (ClientWorld) (Object) this);
|
||||
}
|
||||
|
||||
return super.onPurgeRemovedBlockEntities(blockEntityList, removals); // Call super
|
||||
}
|
||||
|
||||
// We override our injection on the clientworld so only the client world's tick invocations will run
|
||||
@Override
|
||||
protected void tickWorldAfterBlockEntities(CallbackInfo ci) {
|
||||
ClientTickEvents.END_WORLD_TICK.invoker().onEndTick((ClientWorld) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(method = "tickEntities", at = @At("HEAD"))
|
||||
private void startWorldTick(CallbackInfo ci) {
|
||||
ClientTickEvents.START_WORLD_TICK.invoker().onStartTick((ClientWorld) (Object) this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.event.lifecycle.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(MinecraftClient.class)
|
||||
public abstract class MinecraftClientMixin {
|
||||
@Inject(at = @At("HEAD"), method = "tick")
|
||||
private void onStartTick(CallbackInfo info) {
|
||||
ClientTickEvents.START_CLIENT_TICK.invoker().onStartTick((MinecraftClient) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "tick")
|
||||
private void onEndTick(CallbackInfo info) {
|
||||
ClientTickEvents.END_CLIENT_TICK.invoker().onEndTick((MinecraftClient) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;info(Ljava/lang/String;)V", shift = At.Shift.AFTER), method = "stop")
|
||||
private void onStopping(CallbackInfo ci) {
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.invoker().onClientStopping((MinecraftClient) (Object) this);
|
||||
}
|
||||
|
||||
// We inject after the thread field is set so `ThreadExecutor#getThread` will work
|
||||
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;thread:Ljava/lang/Thread;", shift = At.Shift.AFTER), method = "run")
|
||||
private void onStart(CallbackInfo ci) {
|
||||
ClientLifecycleEvents.CLIENT_STARTED.invoker().onClientStarted((MinecraftClient) (Object) this);
|
||||
}
|
||||
}
|
Binary file not shown.
After ![]() (image error) Size: 1.5 KiB |
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.event.lifecycle",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"MinecraftServerMixin",
|
||||
"ServerWorldMixin",
|
||||
"ThreadedAnvilChunkStorageMixin",
|
||||
"WorldMixin"
|
||||
],
|
||||
"client": [
|
||||
"client.ClientChunkManagerMixin",
|
||||
"client.ClientPlayNetworkHandlerMixin",
|
||||
"client.ClientWorldMixin",
|
||||
"client.MinecraftClientMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-lifecycle-events-v1",
|
||||
"name": "Fabric Lifecycle Events (v1)",
|
||||
"version": "${version}",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"icon": "assets/fabric-lifecycle-events-v1/icon.png",
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net",
|
||||
"irc": "irc://irc.esper.net:6667/fabric",
|
||||
"issues": "https://github.com/FabricMC/fabric/issues",
|
||||
"sources": "https://github.com/FabricMC/fabric"
|
||||
},
|
||||
"authors": [
|
||||
"FabricMC"
|
||||
],
|
||||
"mixins": [
|
||||
"fabric-lifecycle-events-v1.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.4.0",
|
||||
"fabric-api-base": "*"
|
||||
},
|
||||
"description": "Events for the game's lifecycle."
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
public class ServerBlockEntityLifecycleTests implements ModInitializer {
|
||||
private List<BlockEntity> serverBlockEntities = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
final Logger logger = ServerLifecycleTests.LOGGER;
|
||||
|
||||
ServerBlockEntityEvents.BLOCK_ENTITY_LOAD.register((blockEntity, world) -> {
|
||||
this.serverBlockEntities.add(blockEntity);
|
||||
logger.info("[SERVER] LOADED " + Registry.BLOCK_ENTITY_TYPE.getId(blockEntity.getType()).toString() + " - BlockEntities: " + this.serverBlockEntities.size());
|
||||
});
|
||||
|
||||
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.register((blockEntity, world) -> {
|
||||
this.serverBlockEntities.remove(blockEntity);
|
||||
logger.info("[SERVER] UNLOADED " + Registry.BLOCK_ENTITY_TYPE.getId(blockEntity.getType()).toString() + " - BlockEntities: " + this.serverBlockEntities.size());
|
||||
});
|
||||
|
||||
ServerTickEvents.END_SERVER_TICK.register(minecraftServer -> {
|
||||
if (minecraftServer.getTicks() % 200 == 0) {
|
||||
int entities = 0;
|
||||
logger.info("[SERVER] Tracked BlockEntities:" + this.serverBlockEntities.size() + " Ticked at: " + minecraftServer.getTicks() + "ticks");
|
||||
|
||||
for (ServerWorld world : minecraftServer.getWorlds()) {
|
||||
int worldEntities = world.blockEntities.size();
|
||||
logger.info("[SERVER] Tracked BlockEntities in " + world.dimension.getType().toString() + " - " + worldEntities);
|
||||
entities += worldEntities;
|
||||
}
|
||||
|
||||
logger.info("[SERVER] Actual Total BlockEntities: " + entities);
|
||||
|
||||
if (entities != this.serverBlockEntities.size()) {
|
||||
logger.error("[SERVER] Mismatch in tracked blockentities and actual blockentities");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ServerLifecycleEvents.SERVER_STOPPED.register(minecraftServer -> {
|
||||
logger.info("[SERVER] Disconnected. Tracking: " + this.serverBlockEntities.size() + " blockentities");
|
||||
|
||||
if (this.serverBlockEntities.size() != 0) {
|
||||
logger.error("[SERVER] Mismatch in tracked blockentities, expected 0");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
|
||||
|
||||
/**
|
||||
* Tests related to the lifecycle of entities.
|
||||
*/
|
||||
public class ServerEntityLifecycleTests implements ModInitializer {
|
||||
private List<Entity> serverEntities = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
final Logger logger = ServerLifecycleTests.LOGGER;
|
||||
|
||||
ServerEntityEvents.ENTITY_LOAD.register((entity, world) -> {
|
||||
this.serverEntities.add(entity);
|
||||
logger.info("[SERVER] LOADED " + entity.toString() + " - Entities: " + this.serverEntities.size());
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
|
||||
/**
|
||||
* Tests related to the lifecycle of a server.
|
||||
*/
|
||||
public class ServerLifecycleTests implements ModInitializer {
|
||||
public static final Logger LOGGER = LogManager.getLogger("LifecycleEventsTest");
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
|
||||
LOGGER.info("Started Server!");
|
||||
});
|
||||
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
|
||||
LOGGER.info("Stopping Server!");
|
||||
});
|
||||
|
||||
ServerLifecycleEvents.SERVER_STOPPED.register(server -> {
|
||||
LOGGER.info("Stopped Server!");
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
/**
|
||||
* Test related to ticking events on the server.
|
||||
*/
|
||||
public class ServerTickTests implements ModInitializer {
|
||||
private Map<DimensionType, Integer> tickTracker = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||
if (server.getTicks() % 200 == 0) { // Log every 200 ticks to verify the tick callback works on the server
|
||||
ServerLifecycleTests.LOGGER.info("Ticked Server at " + server.getTicks() + " ticks.");
|
||||
}
|
||||
});
|
||||
|
||||
ServerTickEvents.START_WORLD_TICK.register(world -> {
|
||||
// Verify we are inside the tick
|
||||
if (!world.isInsideTick()) {
|
||||
throw new AssertionError("Start tick event should be fired while ServerWorld is inside of tick");
|
||||
}
|
||||
});
|
||||
|
||||
ServerTickEvents.END_WORLD_TICK.register(world -> {
|
||||
final int worldTicks = tickTracker.computeIfAbsent(world.dimension.getType(), k -> 0);
|
||||
|
||||
if (worldTicks % 200 == 0) { // Log every 200 ticks to verify the tick callback works on the server world
|
||||
ServerLifecycleTests.LOGGER.info("Ticked Server World - " + worldTicks + " ticks:" + world.dimension.getType());
|
||||
}
|
||||
|
||||
this.tickTracker.put(world.dimension.getType(), worldTicks + 1);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.test.event.lifecycle.ServerLifecycleTests;
|
||||
|
||||
public class ClientBlockEntityLifecycleTests implements ClientModInitializer {
|
||||
private List<BlockEntity> clientBlockEntities = new ArrayList<>();
|
||||
private int clientTicks;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
final Logger logger = ServerLifecycleTests.LOGGER;
|
||||
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_LOAD.register((blockEntity, world) -> {
|
||||
this.clientBlockEntities.add(blockEntity);
|
||||
logger.info("[CLIENT]" + " LOADED " + Registry.BLOCK_ENTITY_TYPE.getId(blockEntity.getType()).toString() + " - BlockEntities: " + this.clientBlockEntities.size());
|
||||
});
|
||||
|
||||
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.register((blockEntity, world) -> {
|
||||
this.clientBlockEntities.remove(blockEntity);
|
||||
logger.info("[CLIENT]" + " UNLOADED " + Registry.BLOCK_ENTITY_TYPE.getId(blockEntity.getType()).toString() + " - BlockEntities: " + this.clientBlockEntities.size());
|
||||
});
|
||||
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
if (this.clientTicks++ % 200 == 0 && client.world != null) {
|
||||
final int blockEntities = client.world.blockEntities.size();
|
||||
logger.info("[CLIENT] Tracked BlockEntities:" + this.clientBlockEntities.size() + " Ticked at: " + this.clientTicks + "ticks");
|
||||
logger.info("[CLIENT] Actual BlockEntities: " + client.world.blockEntities.size());
|
||||
|
||||
if (blockEntities != this.clientBlockEntities.size()) {
|
||||
logger.error("[CLIENT] Mismatch in tracked blockentities and actual blockentities");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ServerLifecycleEvents.SERVER_STOPPED.register(minecraftServer -> {
|
||||
if (!minecraftServer.isDedicated()) { // fixme: Use ClientNetworking#PLAY_DISCONNECTED instead of the server stop callback for testing.
|
||||
logger.info("[CLIENT] Disconnected. Tracking: " + this.clientBlockEntities.size() + " blockentities");
|
||||
|
||||
if (this.clientBlockEntities.size() != 0) {
|
||||
logger.error("[CLIENT] Mismatch in tracked blockentities, expected 0");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.test.event.lifecycle.ServerLifecycleTests;
|
||||
|
||||
/**
|
||||
* Tests related to the lifecycle of entities.
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class ClientEntityLifecycleTests implements ClientModInitializer {
|
||||
private List<Entity> clientEntities = new ArrayList<>();
|
||||
private int clientTicks;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
final Logger logger = ServerLifecycleTests.LOGGER;
|
||||
|
||||
ClientEntityEvents.ENTITY_LOAD.register((entity, world) -> {
|
||||
this.clientEntities.add(entity);
|
||||
logger.info("[CLIENT]" + " LOADED " + Registry.ENTITY_TYPE.getId(entity.getType()).toString() + " - Entities: " + this.clientEntities.size());
|
||||
});
|
||||
|
||||
ClientEntityEvents.ENTITY_UNLOAD.register((entity, world) -> {
|
||||
this.clientEntities.remove(entity);
|
||||
logger.info("[CLIENT]" + " UNLOADED " + Registry.ENTITY_TYPE.getId(entity.getType()).toString() + " - Entities: " + this.clientEntities.size());
|
||||
});
|
||||
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
if (this.clientTicks++ % 200 == 0 && client.world != null) {
|
||||
final int entities = Iterables.toArray(client.world.getEntities(), Entity.class).length;
|
||||
logger.info("[CLIENT] Tracked Entities:" + this.clientEntities.size() + " Ticked at: " + this.clientTicks + "ticks");
|
||||
logger.info("[CLIENT] Actual Entities: " + entities);
|
||||
|
||||
if (entities != this.clientEntities.size()) {
|
||||
logger.error("[CLIENT] Mismatch in tracked entities and actual entities");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ServerLifecycleEvents.SERVER_STOPPED.register(minecraftServer -> {
|
||||
if (!minecraftServer.isDedicated()) { // fixme: Use ClientNetworking#PLAY_DISCONNECTED instead of the server stop callback for testing.
|
||||
logger.info("[CLIENT] Disconnected. Tracking: " + this.clientEntities.size() + " entities");
|
||||
|
||||
if (this.clientEntities.size() != 0) {
|
||||
logger.error("[CLIENT] Mismatch in tracked entities, expected 0");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle.client;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class ClientLifecycleTests implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientLifecycleEvents.CLIENT_STARTED.register(client -> {
|
||||
client.submitAndJoin(() -> { // This should fail if the client thread was not bound yet.
|
||||
System.out.println("Started the client");
|
||||
});
|
||||
});
|
||||
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register(client -> {
|
||||
System.out.println("Client has started stopping!");
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.event.lifecycle.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.test.event.lifecycle.ServerLifecycleTests;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class ClientTickTests implements ClientModInitializer {
|
||||
private Map<DimensionType, Integer> tickTracker = new HashMap<>();
|
||||
private int ticks;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
this.ticks++; // Just track our own tick since the client doesn't have a ticks value.
|
||||
|
||||
if (this.ticks % 200 == 0) {
|
||||
ServerLifecycleTests.LOGGER.info("Ticked Client at " + this.ticks + " ticks.");
|
||||
}
|
||||
});
|
||||
|
||||
ClientTickEvents.END_WORLD_TICK.register(world -> {
|
||||
final int worldTicks = this.tickTracker.computeIfAbsent(world.dimension.getType(), k -> 0);
|
||||
|
||||
if (worldTicks % 200 == 0) { // Log every 200 ticks to verify the tick callback works on the client world
|
||||
ServerLifecycleTests.LOGGER.info("Ticked Client World - " + worldTicks + " ticks:" + world.dimension.getType());
|
||||
}
|
||||
|
||||
this.tickTracker.put(world.dimension.getType(), worldTicks + 1);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-lifecycle-events-v1-testmod",
|
||||
"name": "Fabric Lifecycle Events (v1) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-lifecycle-events-v1": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.event.lifecycle.ServerBlockEntityLifecycleTests",
|
||||
"net.fabricmc.fabric.test.event.lifecycle.ServerEntityLifecycleTests",
|
||||
"net.fabricmc.fabric.test.event.lifecycle.ServerLifecycleTests",
|
||||
"net.fabricmc.fabric.test.event.lifecycle.ServerTickTests"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.event.lifecycle.client.ClientBlockEntityLifecycleTests",
|
||||
"net.fabricmc.fabric.test.event.lifecycle.client.ClientEntityLifecycleTests",
|
||||
"net.fabricmc.fabric.test.event.lifecycle.client.ClientLifecycleTests",
|
||||
"net.fabricmc.fabric.test.event.lifecycle.client.ClientTickTests",
|
||||
]
|
||||
}
|
||||
}
|
|
@ -24,9 +24,11 @@ include 'fabric-content-registries-v0'
|
|||
include 'fabric-crash-report-info-v1'
|
||||
include 'fabric-events-interaction-v0'
|
||||
include 'fabric-events-lifecycle-v0'
|
||||
include 'fabric-item-api-v1'
|
||||
include 'fabric-item-groups-v0'
|
||||
include 'fabric-keybindings-v0'
|
||||
include 'fabric-key-binding-api-v1'
|
||||
include 'fabric-lifecycle-events-v1'
|
||||
include 'fabric-loot-tables-v1'
|
||||
include 'fabric-mining-levels-v0'
|
||||
include 'fabric-models-v0'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue