mirror of
https://github.com/FabricMC/fabric.git
synced 2025-03-28 07:40:02 -04:00
Lifecycle Events V1 [1.16] (#681)
* Lifecycle Events V1 (1.16) Now includes Chunk and (Block)Entity (un)load events (cherry picked from commit 82b372873fd930dd07768331f7b70f6f9d3d441d) * Move around code to work on 1.16 * Checkstyle * Remove primary server getters (cherry picked from commitc84f36209d
) * IJ DO YOU SPEAK RESOLVING IMPORTS * Prune the tests that shouldn't exist (cherry picked from commita5112223ca
) * Listen here checkstyle you bugger * Split up events to individual interfaces. Make Chunk events use WorldChunk instead. (cherry picked from commit3431c0d894
)
This commit is contained in:
parent
4d66bed54e
commit
16acbe5bfd
56 changed files with 2431 additions and 94 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.3")
|
||||
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,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,64 @@
|
|||
/*
|
||||
* 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.util.registry.RegistryKey;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
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<RegistryKey<World>, 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.getRegistryKey(), 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.getRegistryKey().getValue() + " - " + worldTicks + " ticks: " + world.getClass().getName());
|
||||
}
|
||||
|
||||
this.tickTracker.put(world.getRegistryKey(), 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.getRegistryKey().getValue());
|
||||
|
||||
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.getRegistryKey().getValue());
|
||||
|
||||
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 = "method_29741")
|
||||
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 inEntityTick;
|
||||
|
||||
// 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.inEntityTick) { // Copy vanilla logic, we cannot load entities while the game is ticking entities
|
||||
ServerEntityEvents.ENTITY_LOAD.invoker().onLoad(entity, (ServerWorld) (Object) this);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure "insideBlockTick" 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;inBlockTick: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.network.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.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket;
|
||||
|
||||
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.getRegistryKey().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,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.test.event.lifecycle;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
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<RegistryKey<World>, 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.isInBlockTick()) {
|
||||
throw new AssertionError("Start tick event should be fired while ServerWorld is inside of block tick");
|
||||
}
|
||||
});
|
||||
|
||||
ServerTickEvents.END_WORLD_TICK.register(world -> {
|
||||
final int worldTicks = tickTracker.computeIfAbsent(world.getRegistryKey(), 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.getRegistryKey().getValue());
|
||||
}
|
||||
|
||||
this.tickTracker.put(world.getRegistryKey(), 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,56 @@
|
|||
/*
|
||||
* 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.util.registry.RegistryKey;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
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<RegistryKey<World>, 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.getRegistryKey(), 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.getRegistryKey());
|
||||
}
|
||||
|
||||
this.tickTracker.put(world.getRegistryKey(), 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-crash-report-info-v1'
|
|||
include 'fabric-dimensions-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
Reference in a new issue