Merge pull request #1148 from i509VCB/1.17/lifecycle-events-v1

20w45a: Partially update Fabric API
This commit is contained in:
modmuss50 2020-11-05 08:49:31 +00:00 committed by GitHub
commit 9cb915787f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 56 additions and 77 deletions

View file

@ -19,7 +19,7 @@ def ENV = System.getenv()
class Globals {
static def baseVersion = "0.25.1"
static def mcVersion = "1.16.4"
static def mcVersion = "20w45a"
static def yarnVersion = "+build.1"
static def loaderVersion = "0.10.5+build.213"
}
@ -284,7 +284,7 @@ curseforge {
project {
id = "306612"
changelog = "A changelog can be found at https://github.com/FabricMC/fabric/commits"
releaseType = "release"
releaseType = "beta"
addGameVersion "1.16.4"
addGameVersion "Fabric"

View file

@ -43,6 +43,7 @@ public abstract class RuleListWidgetMixin extends net.minecraft.client.gui.widge
super(client, width, height, top, bottom, itemHeight);
}
// EditGameRulesScreen is effectively a synthetic parameter
@Inject(method = "<init>(Lnet/minecraft/client/gui/screen/world/EditGameRulesScreen;Lnet/minecraft/world/GameRules;)V", at = @At("TAIL"))
private void initializeFabricGameruleCategories(EditGameRulesScreen screen, GameRules gameRules, CallbackInfo ci) {
this.fabricCategories.forEach((category, widgetList) -> {
@ -54,6 +55,7 @@ public abstract class RuleListWidgetMixin extends net.minecraft.client.gui.widge
});
}
// Synthetic method
@Inject(method = "method_27638(Ljava/util/Map$Entry;)V", at = @At("HEAD"), cancellable = true)
private void ignoreKeysWithCustomCategories(Map.Entry<GameRules.Key<?>, EditGameRulesScreen.AbstractRuleWidget> entry, CallbackInfo ci) {
final GameRules.Key<?> ruleKey = entry.getKey();

View file

@ -79,12 +79,12 @@ public abstract class MinecraftServerMixin {
/**
* 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)
/*@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) {
for (BlockEntity blockEntity : serverWorld.blockEntities) {
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, serverWorld);
}
}
}*/
// The locals you have to manage for an inject are insane. And do it twice. A redirect is much cleaner.
// Here is what it looks like with an inject: https://gist.github.com/i509VCB/f80077cc536eb4dba62b794eba5611c1

View file

@ -33,7 +33,7 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
@Mixin(ServerWorld.class)
public abstract class ServerWorldMixin {
@Shadow
/*@Shadow
private boolean inEntityTick;
// Call our load event after vanilla has loaded the entity
@ -42,7 +42,7 @@ public abstract class ServerWorldMixin {
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))

View file

@ -16,27 +16,16 @@
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)
@ -47,7 +36,7 @@ public abstract class WorldMixin {
@Shadow
public abstract Profiler getProfiler();
@Inject(method = "addBlockEntity", at = @At("TAIL"))
/*@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);
@ -79,7 +68,7 @@ public abstract class WorldMixin {
// Mimic vanilla logic
return blockEntityList.removeAll(removals);
}
}*/
@Inject(at = @At("RETURN"), method = "tickBlockEntities")
protected void tickWorldAfterBlockEntities(CallbackInfo ci) {

View file

@ -16,6 +16,7 @@
package net.fabricmc.fabric.mixin.event.lifecycle.client;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -44,8 +45,8 @@ public abstract class ClientChunkManagerMixin {
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());
private void onChunkLoad(int x, int z, @Nullable BiomeArray biomes, PacketByteBuf buf, CompoundTag tag, int verticalStripBitmask, CallbackInfoReturnable<WorldChunk> info) {
ClientChunkEvents.CHUNK_LOAD.invoker().onChunkLoad(this.world, info.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)

View file

@ -17,27 +17,16 @@
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
/*@Shadow
private ClientWorld world;
@Inject(method = "onPlayerRespawn", at = @At(value = "NEW", target = "net/minecraft/client/world/ClientWorld"))
@ -53,7 +42,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
// No need to clear the `tickingBlockEntities` list since it will be null in just an instant
}
}
}
}*/
/**
* An explanation why we unload entities during onGameJoin:
@ -61,7 +50,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
* 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"))
/*@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) {
@ -90,5 +79,5 @@ public abstract class ClientPlayNetworkHandlerMixin {
// No need to clear the `tickingBlockEntities` list since it will be null in just an instant
}
}
}
}*/
}

View file

@ -16,33 +16,22 @@
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
/*// 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);
@ -52,10 +41,10 @@ public abstract class ClientWorldMixin extends WorldMixin {
@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
/*@Override
protected void onLoadBlockEntity(BlockEntity blockEntity, CallbackInfoReturnable<Boolean> cir) {
ClientBlockEntityEvents.BLOCK_ENTITY_LOAD.invoker().onLoad(blockEntity, (ClientWorld) (Object) this);
}
@ -78,7 +67,7 @@ public abstract class ClientWorldMixin extends WorldMixin {
}
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

View file

@ -19,16 +19,9 @@ 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 static boolean PRINT_SERVER_BLOCKENTITY_MESSAGES = System.getProperty("fabric-lifecycle-events-testmod.printServerBlockEntityMessages") != null;
@ -36,7 +29,7 @@ public class ServerBlockEntityLifecycleTests implements ModInitializer {
@Override
public void onInitialize() {
final Logger logger = ServerLifecycleTests.LOGGER;
/*final Logger logger = ServerLifecycleTests.LOGGER;
ServerBlockEntityEvents.BLOCK_ENTITY_LOAD.register((blockEntity, world) -> {
this.serverBlockEntities.add(blockEntity);
@ -89,6 +82,6 @@ public class ServerBlockEntityLifecycleTests implements ModInitializer {
if (this.serverBlockEntities.size() != 0) {
logger.error("[SERVER] Mismatch in tracked blockentities, expected 0");
}
});
});*/
}
}

View file

@ -37,7 +37,7 @@ public class ClientBlockEntityLifecycleTests implements ClientModInitializer {
@Override
public void onInitializeClient() {
final Logger logger = ServerLifecycleTests.LOGGER;
/*final Logger logger = ServerLifecycleTests.LOGGER;
ClientBlockEntityEvents.BLOCK_ENTITY_LOAD.register((blockEntity, world) -> {
this.clientBlockEntities.add(blockEntity);
@ -80,6 +80,6 @@ public class ClientBlockEntityLifecycleTests implements ClientModInitializer {
logger.error("[CLIENT] Mismatch in tracked blockentities, expected 0");
}
}
});
});*/
}
}

View file

@ -70,12 +70,12 @@ public class MixinClientPlayNetworkHandler {
}
}
@Redirect(method = "onChunkData", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/entity/BlockEntity;fromTag(Lnet/minecraft/block/BlockState;Lnet/minecraft/nbt/CompoundTag;)V"))
public void deserializeBlockEntityChunkData(BlockEntity entity, BlockState blockState, CompoundTag tag) {
if (entity instanceof BlockEntityClientSerializable) {
((BlockEntityClientSerializable) entity).fromClientTag(tag);
@Redirect(method = "onChunkData", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/entity/BlockEntity;fromTag(Lnet/minecraft/nbt/CompoundTag;)V"))
public void deserializeBlockEntityChunkData(BlockEntity blockEntity, CompoundTag tag) {
if (blockEntity instanceof BlockEntityClientSerializable) {
((BlockEntityClientSerializable) blockEntity).fromClientTag(tag);
} else {
entity.fromTag(blockState, tag);
blockEntity.fromTag(tag);
}
}
}

View file

@ -47,16 +47,18 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
private static final Pattern RESOURCE_PACK_PATH = Pattern.compile("[a-z0-9-_]+");
private final ModMetadata modInfo;
private final Path basePath;
private final ResourceType type;
private final boolean cacheable;
private final AutoCloseable closer;
private final String separator;
private final String name;
private final boolean defaultEnabled;
public ModNioResourcePack(ModMetadata modInfo, Path path, AutoCloseable closer, String name, boolean defaultEnabled) {
public ModNioResourcePack(ModMetadata modInfo, Path path, ResourceType type, AutoCloseable closer, String name, boolean defaultEnabled) {
super(null);
this.modInfo = modInfo;
this.basePath = path.toAbsolutePath().normalize();
this.type = type;
this.cacheable = false; /* TODO */
this.closer = closer;
this.separator = basePath.getFileSystem().getSeparator();
@ -101,7 +103,7 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
}
}
stream = ModResourcePackUtil.openDefault(modInfo, filename);
stream = ModResourcePackUtil.openDefault(this.modInfo, this.type, filename);
if (stream != null) {
return stream;

View file

@ -19,12 +19,15 @@ package net.fabricmc.fabric.impl.resource.loader;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourcePackProfile;
import net.minecraft.resource.ResourcePackProvider;
import net.minecraft.resource.ResourcePackSource;
import net.minecraft.resource.ResourceType;
import net.minecraft.resource.metadata.PackResourceMetadata;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.fabricmc.fabric.api.resource.ModResourcePack;
@ -35,10 +38,22 @@ import net.fabricmc.fabric.api.resource.ModResourcePack;
public class ModResourcePackCreator implements ResourcePackProvider {
public static final ResourcePackSource RESOURCE_PACK_SOURCE = text -> new TranslatableText("pack.nameAndSource", text, new TranslatableText("pack.source.fabricmod"));
public static final ModResourcePackCreator CLIENT_RESOURCE_PACK_PROVIDER = new ModResourcePackCreator(ResourceType.CLIENT_RESOURCES);
private final ResourcePackProfile.Factory factory;
private final ResourceType type;
public ModResourcePackCreator(ResourceType type) {
this.type = type;
this.factory = (name, text, bl, supplier, metadata, initialPosition, source) ->
new ResourcePackProfile(name, text, bl, supplier, metadata, type, initialPosition, source);
}
/**
* Registers the resource packs.
*
* @param consumer The resource pack profile consumer.
*/
public void register(Consumer<ResourcePackProfile> consumer) {
this.register(consumer, this.factory);
}
@Override

View file

@ -35,8 +35,6 @@ import net.fabricmc.loader.api.metadata.ModMetadata;
* Internal utilities for managing resource packs.
*/
public final class ModResourcePackUtil {
public static final int PACK_FORMAT_VERSION = SharedConstants.getGameVersion().getPackVersion();
private ModResourcePackUtil() { }
public static void appendModResourcePacks(List<ResourcePack> packList, ResourceType type) {
@ -46,7 +44,7 @@ public final class ModResourcePackUtil {
}
Path path = container.getRootPath();
ResourcePack pack = new ModNioResourcePack(container.getMetadata(), path, null, null, true);
ResourcePack pack = new ModNioResourcePack(container.getMetadata(), path, type, null, null, true);
if (!pack.getNamespaces(type).isEmpty()) {
packList.add(pack);
@ -58,7 +56,7 @@ public final class ModResourcePackUtil {
return "pack.mcmeta".equals(filename);
}
public static InputStream openDefault(ModMetadata info, String filename) {
public static InputStream openDefault(ModMetadata info, ResourceType type, String filename) {
switch (filename) {
case "pack.mcmeta":
String description = info.getName();
@ -69,7 +67,7 @@ public final class ModResourcePackUtil {
description = description.replaceAll("\"", "\\\"");
}
String pack = String.format("{\"pack\":{\"pack_format\":" + PACK_FORMAT_VERSION + ",\"description\":\"%s\"}}", description);
String pack = String.format("{\"pack\":{\"pack_format\":" + type.method_31438(SharedConstants.getGameVersion()) + ",\"description\":\"%s\"}}", description);
return IOUtils.toInputStream(pack, Charsets.UTF_8);
default:
return null;

View file

@ -76,7 +76,8 @@ public class ResourceManagerHelperImpl implements ResourceManagerHelper {
}
String name = id.getNamespace() + "/" + id.getPath();
builtinResourcePacks.add(new Pair<>(name, new ModNioResourcePack(container.getMetadata(), resourcePackPath, null, name, enabledByDefault)));
builtinResourcePacks.add(new Pair<>(name, new ModNioResourcePack(container.getMetadata(), resourcePackPath, ResourceType.CLIENT_RESOURCES, null, name, enabledByDefault)));
builtinResourcePacks.add(new Pair<>(name, new ModNioResourcePack(container.getMetadata(), resourcePackPath, ResourceType.SERVER_DATA, null, name, enabledByDefault)));
return true;
}

View file

@ -53,7 +53,7 @@ public class MixinCreateWorldScreen {
private static DataPackSettings onNew(DataPackSettings settings) {
ModResourcePackCreator modResourcePackCreator = new ModResourcePackCreator(ResourceType.SERVER_DATA);
List<ResourcePackProfile> moddedResourcePacks = new ArrayList<>();
modResourcePackCreator.register(moddedResourcePacks::add, ResourcePackProfile::new);
modResourcePackCreator.register(moddedResourcePacks::add);
List<String> enabled = new ArrayList<>(settings.getEnabled());
List<String> disabled = new ArrayList<>(settings.getDisabled());

View file

@ -42,7 +42,7 @@ public class MixinGameOptions {
// Add built-in resource packs if they are enabled by default only if the options file is blank.
if (this.resourcePacks.isEmpty()) {
List<ResourcePackProfile> profiles = new ArrayList<>();
ModResourcePackCreator.CLIENT_RESOURCE_PACK_PROVIDER.register(profiles::add, ResourcePackProfile::new);
ModResourcePackCreator.CLIENT_RESOURCE_PACK_PROVIDER.register(profiles::add);
this.resourcePacks = new ArrayList<>();
for (ResourcePackProfile profile : profiles) {