diff --git a/build.gradle b/build.gradle index 8fd9b9ebe..4daed6d1c 100644 --- a/build.gradle +++ b/build.gradle @@ -23,16 +23,16 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 archivesBaseName = "fabric" -version = "0.0.2" +version = "0.0.3-SNAPSHOT" minecraft { refmapName = "net.fabricmc.fabric.refmap.json" } dependencies { - minecraft "com.mojang:minecraft:18w45a" - mappings "net.fabricmc:pomf:18w45a.5" - modCompile "net.fabricmc:fabric-loader:18w44a-0.1.0.45" + minecraft "com.mojang:minecraft:18w46a" + mappings "net.fabricmc:pomf:18w46a.4" + modCompile "net.fabricmc:fabric-loader:18w44a-0.1.0.46" } apply from: 'https://github.com/FabricMC/fabric-docs/raw/master/gradle/maven.gradle' diff --git a/src/main/java/net/fabricmc/fabric/mixin/networking/MixinClientPlayNetworkHandler.java b/src/main/java/net/fabricmc/fabric/mixin/networking/MixinClientPlayNetworkHandler.java index 7538cb40c..2caa901d6 100644 --- a/src/main/java/net/fabricmc/fabric/mixin/networking/MixinClientPlayNetworkHandler.java +++ b/src/main/java/net/fabricmc/fabric/mixin/networking/MixinClientPlayNetworkHandler.java @@ -21,7 +21,7 @@ import net.fabricmc.fabric.networking.CustomPayloadHandlerRegistry; import net.fabricmc.fabric.networking.PacketContext; import net.fabricmc.fabric.networking.SPacketCustomPayloadAccessor; import net.minecraft.client.MinecraftGame; -import net.minecraft.client.network.handler.ClientGameNetworkHandler; +import net.minecraft.client.network.handler.ClientPlayNetworkHandler; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerServer; import net.minecraft.network.handler.ServerPlayNetworkHandler; @@ -35,15 +35,13 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(ClientGameNetworkHandler.class) +@Mixin(ClientPlayNetworkHandler.class) public class MixinClientPlayNetworkHandler implements PacketContext { @Shadow private MinecraftGame game; @Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true) public void onCustomPayload(CPacketCustomPayload packet, CallbackInfo info) { - MinecraftGame game = MinecraftGame.getInstance(); - if (CustomPayloadHandlerRegistry.CLIENT.accept(packet.getChannel(), this, packet.getData())) { info.cancel(); } diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/MixinBootstrap.java b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinBootstrap.java new file mode 100644 index 000000000..c1ea6cbde --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinBootstrap.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import net.fabricmc.fabric.networking.CustomPayloadHandlerRegistry; +import net.fabricmc.fabric.registry.ListenableRegistry; +import net.fabricmc.fabric.registry.RegistrySyncManager; +import net.fabricmc.fabric.registry.listeners.BootstrapBiomeRegistryListener; +import net.fabricmc.fabric.registry.listeners.BootstrapBlockRegistryListener; +import net.fabricmc.fabric.registry.listeners.BootstrapFluidRegistryListener; +import net.fabricmc.fabric.registry.listeners.BootstrapItemRegistryListener; +import net.minecraft.Bootstrap; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biomes; +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; + +@Mixin(Bootstrap.class) +public class MixinBootstrap { + @Inject(method = "setOutputStreams", at = @At("RETURN")) + private static void initialize(CallbackInfo info) { + // access Blocks, Items, ... + Object o0 = Biomes.THE_END; + Object o1 = Blocks.AIR; + Object o3 = Fluids.EMPTY; + Object o2 = Items.AIR; + + ((ListenableRegistry<Biome>) Registry.BIOMES).registerListener(new BootstrapBiomeRegistryListener()); + ((ListenableRegistry<Block>) Registry.BLOCKS).registerListener(new BootstrapBlockRegistryListener()); + ((ListenableRegistry<Fluid>) Registry.FLUIDS).registerListener(new BootstrapFluidRegistryListener()); + ((ListenableRegistry<Item>) Registry.ITEMS).registerListener(new BootstrapItemRegistryListener()); + + // The packet code is not side-specific, so this is fine! + CustomPayloadHandlerRegistry.CLIENT.register(RegistrySyncManager.ID, RegistrySyncManager::receivePacket); + } +} \ No newline at end of file diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/MixinIdList.java b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinIdList.java new file mode 100644 index 000000000..c64b423f1 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinIdList.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import net.fabricmc.fabric.registry.ExtendedIdList; +import net.minecraft.util.IdList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.IdentityHashMap; +import java.util.List; + +@Mixin(IdList.class) +public class MixinIdList implements ExtendedIdList { + @Shadow + private int field_11099; + @Shadow + private IdentityHashMap idMap; + @Shadow + private List list; + + @Override + public void clear() { + field_11099 = 0; + idMap.clear(); + list.clear(); + } +} diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/MixinIdRegistry.java b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinIdRegistry.java new file mode 100644 index 000000000..3a57b05b9 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinIdRegistry.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import com.google.common.collect.BiMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import net.fabricmc.fabric.registry.ListenableRegistry; +import net.fabricmc.fabric.registry.RegistryListener; +import net.fabricmc.fabric.registry.RemapException; +import net.fabricmc.fabric.registry.RemappableRegistry; +import net.minecraft.class_3513; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.IdRegistry; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +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.CallbackInfoReturnable; + +@Mixin(IdRegistry.class) +public abstract class MixinIdRegistry<T> implements RemappableRegistry, ListenableRegistry<T>, RegistryListener<T> { + @Shadow + protected static final Logger ID_LOGGER = LogManager.getLogger(); + @Shadow + protected class_3513<T> idStore; + @Shadow + protected BiMap<Identifier, T> objectMap; + + private Object2IntMap<Identifier> initialIdMap; + private RegistryListener[] listeners; + + @Override + public void registerListener(RegistryListener<T> listener) { + if (listeners == null) { + listeners = new RegistryListener[] { listener }; + } else { + RegistryListener[] newListeners = new RegistryListener[listeners.length + 1]; + System.arraycopy(listeners, 0, newListeners, 0, listeners.length); + newListeners[listeners.length] = listener; + listeners = newListeners; + } + } + + @Inject(method = "set", at = @At("HEAD")) + public void set(int id, Identifier identifier, Object object, CallbackInfoReturnable info) { + IdRegistry<Object> registry = (IdRegistry<Object>) (Object) this; + if (listeners != null) { + for (RegistryListener listener : listeners) { + listener.beforeRegistered(registry, id, identifier, object, !registry.contains(identifier)); + } + } + } + + @Override + public void remap(Object2IntMap<Identifier> idMap) throws RemapException { + //noinspection unchecked + IdRegistry<Object> registry = (IdRegistry<Object>) (Object) this; + + if (!idMap.keySet().equals(registry.keys())) { + throw new RemapException("Source and destination keys differ!"); + } + + if (initialIdMap == null) { + initialIdMap = new Object2IntOpenHashMap<>(); + for (Identifier id : registry.keys()) { + //noinspection unchecked + initialIdMap.put(id, registry.getRawId(registry.get(id))); + } + } + + if (listeners != null) { + for (RegistryListener listener : listeners) { + listener.beforeCleared(registry); + } + } + + // We don't really need to clear anything but idStore yet. + idStore.method_15229(); + + for (Identifier identifier : objectMap.keySet()) { + int id = idMap.getInt(identifier); + T object = objectMap.get(identifier); + idStore.method_15230(object, id); + + if (listeners != null) { + for (RegistryListener listener : listeners) { + listener.beforeRegistered(registry, id, identifier, object, false); + } + } + } + } + + @Override + public void unmap() throws RemapException { + if (initialIdMap != null) { + remap(initialIdMap); + initialIdMap = null; + } + } +} diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/MixinServerPlayNetworkHandler.java b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinServerPlayNetworkHandler.java new file mode 100644 index 000000000..437b6f798 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinServerPlayNetworkHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import net.fabricmc.api.Side; +import net.fabricmc.fabric.networking.CustomPayloadHandlerRegistry; +import net.fabricmc.fabric.networking.PacketContext; +import net.fabricmc.fabric.networking.SPacketCustomPayloadAccessor; +import net.fabricmc.fabric.registry.RegistrySyncManager; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerServer; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.Packet; +import net.minecraft.network.handler.ServerPlayNetworkHandler; +import net.minecraft.network.packet.server.SPacketCustomPayload; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ThreadTaskQueue; +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; + +@Mixin(ServerPlayNetworkHandler.class) +public abstract class MixinServerPlayNetworkHandler { + @Shadow + public abstract void sendPacket(Packet<?> var1); + + @Inject(method = "<init>", at = @At("RETURN")) + public void init(MinecraftServer server, ClientConnection connection, EntityPlayerServer player, CallbackInfo info) { + //if (server.isDedicated()) { + sendPacket(RegistrySyncManager.createPacket()); + //} + } +} diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinBlockColorMap.java b/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinBlockColorMap.java new file mode 100644 index 000000000..627422670 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinBlockColorMap.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry.client; + +import net.fabricmc.fabric.registry.ListenableRegistry; +import net.fabricmc.fabric.registry.listeners.IdListUpdater; +import net.minecraft.block.Block; +import net.minecraft.client.render.block.BlockColorMap; +import net.minecraft.client.render.block.BlockColorMapper; +import net.minecraft.client.render.item.ItemColorMap; +import net.minecraft.client.render.item.ItemColorMapper; +import net.minecraft.util.IdList; +import net.minecraft.util.registry.Registry; +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.CallbackInfoReturnable; + +@Mixin(BlockColorMap.class) +public class MixinBlockColorMap implements IdListUpdater.Container<BlockColorMapper> { + @Shadow + private IdList<BlockColorMapper> mappers; + + @Inject(method = "create", at = @At("RETURN")) + private static void create(CallbackInfoReturnable<BlockColorMap> info) { + ((ListenableRegistry) Registry.BLOCKS).registerListener(new IdListUpdater<Block, BlockColorMapper>((IdListUpdater.Container<BlockColorMapper>) (Object) info.getReturnValue())); + } + + @Override + public IdList<BlockColorMapper> getIdListForRegistryUpdating() { + return mappers; + } +} diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinItemColorMap.java b/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinItemColorMap.java new file mode 100644 index 000000000..b184aee34 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinItemColorMap.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry.client; + +import net.fabricmc.fabric.registry.ListenableRegistry; +import net.fabricmc.fabric.registry.listeners.IdListUpdater; +import net.minecraft.client.render.block.BlockColorMap; +import net.minecraft.client.render.item.ItemColorMap; +import net.minecraft.client.render.item.ItemColorMapper; +import net.minecraft.item.Item; +import net.minecraft.util.IdList; +import net.minecraft.util.registry.Registry; +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.CallbackInfoReturnable; + +@Mixin(ItemColorMap.class) +public class MixinItemColorMap implements IdListUpdater.Container<ItemColorMapper> { + @Shadow + private IdList<ItemColorMapper> field_1996; + + @Inject(method = "method_1706", at = @At("RETURN")) + private static void method_1706(BlockColorMap blockMap, CallbackInfoReturnable<ItemColorMap> info) { + ((ListenableRegistry) Registry.ITEMS).registerListener(new IdListUpdater<Item, ItemColorMapper>((IdListUpdater.Container<ItemColorMapper>) (Object) info.getReturnValue())); + } + + @Override + public IdList<ItemColorMapper> getIdListForRegistryUpdating() { + return field_1996; + } +} diff --git a/src/main/java/net/fabricmc/fabric/networking/CustomPayloadHandlerRegistry.java b/src/main/java/net/fabricmc/fabric/networking/CustomPayloadHandlerRegistry.java index e0db7486c..478b5c65d 100644 --- a/src/main/java/net/fabricmc/fabric/networking/CustomPayloadHandlerRegistry.java +++ b/src/main/java/net/fabricmc/fabric/networking/CustomPayloadHandlerRegistry.java @@ -42,9 +42,14 @@ public class CustomPayloadHandlerRegistry { } public boolean accept(Identifier identifier, PacketContext context, PacketByteBuf buf) { - BiConsumer<PacketContext, PacketByteBuf> consumer = consumerMap.get(context); + BiConsumer<PacketContext, PacketByteBuf> consumer = consumerMap.get(identifier); if (consumer != null) { - consumer.accept(context, buf); + try { + consumer.accept(context, buf); + } catch (Throwable t) { + // TODO: handle better + t.printStackTrace(); + } return true; } else { return false; diff --git a/src/main/java/net/fabricmc/fabric/registry/ExtendedIdList.java b/src/main/java/net/fabricmc/fabric/registry/ExtendedIdList.java new file mode 100644 index 000000000..5155438f1 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/ExtendedIdList.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +public interface ExtendedIdList { + void clear(); +} diff --git a/src/main/java/net/fabricmc/fabric/registry/ListenableRegistry.java b/src/main/java/net/fabricmc/fabric/registry/ListenableRegistry.java new file mode 100644 index 000000000..32e1f5f9f --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/ListenableRegistry.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +public interface ListenableRegistry<T> { + void registerListener(RegistryListener<T> listener); +} diff --git a/src/main/java/net/fabricmc/fabric/registry/RegistryListener.java b/src/main/java/net/fabricmc/fabric/registry/RegistryListener.java new file mode 100644 index 000000000..62c05d237 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/RegistryListener.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +public interface RegistryListener<T> { + default void beforeCleared(Registry<T> registry) {} + default void beforeRegistered(Registry<T> registry, int id, Identifier identifier, T object, boolean isNew) {} +} diff --git a/src/main/java/net/fabricmc/fabric/registry/RegistrySyncManager.java b/src/main/java/net/fabricmc/fabric/registry/RegistrySyncManager.java new file mode 100644 index 000000000..f5f590536 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/RegistrySyncManager.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import com.google.common.collect.ImmutableSet; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import net.fabricmc.fabric.networking.CustomPayloadHandlerRegistry; +import net.fabricmc.fabric.networking.PacketContext; +import net.minecraft.entity.player.EntityPlayerServer; +import net.minecraft.nbt.TagCompound; +import net.minecraft.network.packet.client.CPacketCustomPayload; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; +import net.minecraft.util.registry.IdRegistry; +import net.minecraft.util.registry.ModifiableRegistry; +import net.minecraft.util.registry.Registry; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public final class RegistrySyncManager { + public static final Identifier ID = new Identifier("fabric", "registry/sync"); + private static final Set<Identifier> REGISTRY_BLACKLIST = ImmutableSet.of(); + private static final Set<Identifier> REGISTRY_BLACKLIST_NETWORK = ImmutableSet.of(); + + private RegistrySyncManager() { + + } + + public static CPacketCustomPayload createPacket() { + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + buf.writeVarInt(1); + buf.writeTagCompound(toTag(true)); + + CPacketCustomPayload packet = new CPacketCustomPayload(ID, buf); + return packet; + } + + public static void receivePacket(PacketContext context, PacketByteBuf buf) { + int version = buf.readVarInt(); + if (version != 1) { + // TODO: log error + } + + TagCompound compound = buf.readTagCompound(); + try { + apply(compound); + } catch (RemapException e) { + // TODO: log error properly + e.printStackTrace(); + } + } + + public static TagCompound toTag(boolean isClientSync) { + TagCompound mainTag = new TagCompound(); + + for (Identifier registryId : Registry.REGISTRIES.keys()) { + if (REGISTRY_BLACKLIST.contains(registryId)) { + continue; + } else if (isClientSync && REGISTRY_BLACKLIST_NETWORK.contains(registryId)) { + continue; + } + + ModifiableRegistry registry = Registry.REGISTRIES.get(registryId); + if (registry instanceof IdRegistry && registry instanceof RemappableRegistry) { + TagCompound registryTag = new TagCompound(); + //noinspection unchecked + for (Identifier identifier : (Set<Identifier>) registry.keys()) { + registryTag.setInt(identifier.toString(), registry.getRawId(registry.get(identifier))); + } + mainTag.setTag(registryId.toString(), registryTag); + } + } + + return mainTag; + } + + public static void apply(TagCompound mainTag) throws RemapException { + for (Identifier registryId : Registry.REGISTRIES.keys()) { + if (!mainTag.hasKey(registryId.toString())) { + continue; + } + + TagCompound registryTag = mainTag.getTagCompound(registryId.toString()); + ModifiableRegistry registry = Registry.REGISTRIES.get(registryId); + if (registry instanceof IdRegistry && registry instanceof RemappableRegistry) { + Object2IntMap<Identifier> idMap = new Object2IntOpenHashMap<>(); + for (String key : registryTag.getKeys()) { + idMap.put(new Identifier(key), registryTag.getInt(key)); + } + ((RemappableRegistry) registry).remap(idMap); + } + } + } +} diff --git a/src/main/java/net/fabricmc/fabric/registry/RemapException.java b/src/main/java/net/fabricmc/fabric/registry/RemapException.java new file mode 100644 index 000000000..5e8328375 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/RemapException.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +public class RemapException extends Exception { + public RemapException(String message) { + super(message); + } +} diff --git a/src/main/java/net/fabricmc/fabric/registry/RemappableRegistry.java b/src/main/java/net/fabricmc/fabric/registry/RemappableRegistry.java new file mode 100644 index 000000000..6ecbe6e8e --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/RemappableRegistry.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.util.Identifier; + +public interface RemappableRegistry { + void remap(Object2IntMap<Identifier> idMap) throws RemapException; + void unmap() throws RemapException; +} diff --git a/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBiomeRegistryListener.java b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBiomeRegistryListener.java new file mode 100644 index 000000000..d95adc976 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBiomeRegistryListener.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry.listeners; + +import net.fabricmc.fabric.registry.ExtendedIdList; +import net.fabricmc.fabric.registry.RegistryListener; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; + +public class BootstrapBiomeRegistryListener implements RegistryListener<Biome> { + @Override + public void beforeCleared(Registry<Biome> registry) { + ((ExtendedIdList) Biome.PARENT_BIOME_ID_MAP).clear(); + } + + @Override + public void beforeRegistered(Registry<Biome> registry, int id, Identifier identifier, Biome object, boolean isNew) { + // refer net.minecraft.biome.Biomes + if (object.hasParent()) { + Biome.PARENT_BIOME_ID_MAP.add(object, id); + } + } +} diff --git a/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBlockRegistryListener.java b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBlockRegistryListener.java new file mode 100644 index 000000000..b0595e30a --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBlockRegistryListener.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry.listeners; + +import com.google.common.collect.UnmodifiableIterator; +import net.fabricmc.fabric.registry.ExtendedIdList; +import net.fabricmc.fabric.registry.RegistryListener; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +public class BootstrapBlockRegistryListener implements RegistryListener<Block> { + @Override + public void beforeCleared(Registry<Block> registry) { + ((ExtendedIdList) Block.BLOCKSTATE_ID_LIST).clear(); + } + + @Override + public void beforeRegistered(Registry<Block> registry, int id, Identifier identifier, Block object, boolean isNew) { + // refer net.minecraft.block.Blocks + for (BlockState state : object.getStateFactory().getStates()) { + state.method_11590(); + Block.BLOCKSTATE_ID_LIST.method_10205(state); + } + + object.getDropTableId(); + } +} diff --git a/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapFluidRegistryListener.java b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapFluidRegistryListener.java new file mode 100644 index 000000000..d1db91ea3 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapFluidRegistryListener.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry.listeners; + +import net.fabricmc.fabric.registry.ExtendedIdList; +import net.fabricmc.fabric.registry.RegistryListener; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +public class BootstrapFluidRegistryListener implements RegistryListener<Fluid> { + @Override + public void beforeCleared(Registry<Fluid> registry) { + ((ExtendedIdList) Block.BLOCKSTATE_ID_LIST).clear(); + } + + @Override + public void beforeRegistered(Registry<Fluid> registry, int id, Identifier identifier, Fluid object, boolean isNew) { + // refer net.minecraft.fluid.Fluids + for (FluidState state : object.getStateFactory().getStates()) { + Fluid.field_15904.method_10205(state); + } + } +} diff --git a/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapItemRegistryListener.java b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapItemRegistryListener.java new file mode 100644 index 000000000..124f48086 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapItemRegistryListener.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry.listeners; + +import net.fabricmc.fabric.registry.ExtendedIdList; +import net.fabricmc.fabric.registry.RegistryListener; +import net.minecraft.item.Item; +import net.minecraft.item.block.ItemBlock; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +public class BootstrapItemRegistryListener implements RegistryListener<Item> { + @Override + public void beforeCleared(Registry<Item> registry) { + Item.BLOCK_ITEM_MAP.clear(); + } + + @Override + public void beforeRegistered(Registry<Item> registry, int id, Identifier identifier, Item object, boolean isNew) { + // refer net.minecraft.item.Items + if (object instanceof ItemBlock) { + ((ItemBlock) object).method_7713(Item.BLOCK_ITEM_MAP, object); + } + } +} diff --git a/src/main/java/net/fabricmc/fabric/registry/listeners/IdListUpdater.java b/src/main/java/net/fabricmc/fabric/registry/listeners/IdListUpdater.java new file mode 100644 index 000000000..8c97c29f8 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/registry/listeners/IdListUpdater.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.registry.listeners; + +import net.fabricmc.fabric.registry.ExtendedIdList; +import net.fabricmc.fabric.registry.RegistryListener; +import net.minecraft.util.IdList; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import java.util.HashMap; +import java.util.Map; + +public class IdListUpdater<K, V> implements RegistryListener<K> { + public interface Container<V> { + IdList<V> getIdListForRegistryUpdating(); + } + + private final IdList<V> mappers; + private Map<Identifier, V> mapperCache = new HashMap<>(); + + public IdListUpdater(Container<V> container) { + this(container.getIdListForRegistryUpdating()); + } + + public IdListUpdater(IdList<V> mappers) { + this.mappers = mappers; + } + + @Override + public void beforeCleared(Registry<K> registry) { + mapperCache.clear(); + for (Identifier id : registry.keys()) { + int rawId = registry.getRawId(registry.get(id)); + V mapper = mappers.getInt(rawId); + if (mapper != null) { + mapperCache.put(id, mapper); + } + } + + ((ExtendedIdList) mappers).clear(); + } + + @Override + public void beforeRegistered(Registry<K> registry, int id, Identifier identifier, K object, boolean isNew) { + if (mapperCache.containsKey(identifier)) { + mappers.add(mapperCache.get(identifier), id); + } + } +} diff --git a/src/main/resources/net.fabricmc.fabric.mixins.client.json b/src/main/resources/net.fabricmc.fabric.mixins.client.json index a3943b5ae..bb2aad595 100644 --- a/src/main/resources/net.fabricmc.fabric.mixins.client.json +++ b/src/main/resources/net.fabricmc.fabric.mixins.client.json @@ -4,6 +4,8 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "networking.MixinClientPlayNetworkHandler", + "registry.client.MixinBlockColorMap", + "registry.client.MixinItemColorMap", "resources.MixinMinecraftGame" ], "injectors": { diff --git a/src/main/resources/net.fabricmc.fabric.mixins.common.json b/src/main/resources/net.fabricmc.fabric.mixins.common.json index a571e0a38..08d667486 100644 --- a/src/main/resources/net.fabricmc.fabric.mixins.common.json +++ b/src/main/resources/net.fabricmc.fabric.mixins.common.json @@ -6,6 +6,10 @@ "commands.MixinServerCommandManager", "networking.MixinServerPlayNetworkHandler", "networking.MixinSPacketCustomPayload", + "registry.MixinBootstrap", + "registry.MixinIdList", + "registry.MixinIdRegistry", + "registry.MixinServerPlayNetworkHandler", "resources.MixinMinecraftServer" ], "injectors": {