Browse Source

More hooks for registering keybinds, render types, creative tabs, block entity renderers

shedaniel 4 years ago
parent
commit
76cf64adf0
24 changed files with 476 additions and 21 deletions
  1. 3 2
      common/src/main/java/me/shedaniel/architectury/event/EventFactory.java
  2. 16 4
      common/src/main/java/me/shedaniel/architectury/event/events/LifecycleEvent.java
  3. 44 0
      common/src/main/java/me/shedaniel/architectury/event/events/PlayerEvent.java
  4. 4 8
      common/src/main/java/me/shedaniel/architectury/event/events/TickEvent.java
  5. 32 0
      common/src/main/java/me/shedaniel/architectury/registry/BlockEntityRenderers.java
  6. 29 0
      common/src/main/java/me/shedaniel/architectury/registry/CreativeTabs.java
  7. 27 0
      common/src/main/java/me/shedaniel/architectury/registry/KeyBindings.java
  8. 3 3
      common/src/main/java/me/shedaniel/architectury/registry/ReloadListeners.java
  9. 36 0
      common/src/main/java/me/shedaniel/architectury/registry/RenderTypes.java
  10. 29 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinPlayerList.java
  11. 37 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinClientPacketListener.java
  12. 23 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMinecraft.java
  13. 17 0
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/BlockEntityRenderersImpl.java
  14. 16 0
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/CreativeTabsImpl.java
  15. 12 0
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/KeyBindingsImpl.java
  16. 2 2
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/ReloadListenersImpl.java
  17. 19 0
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/RenderTypesImpl.java
  18. 16 0
      fabric/src/main/resources/architectury.mixins.json
  19. 35 0
      forge/src/main/java/me/shedaniel/architectury/event/forge/EventFactoryImpl.java
  20. 17 0
      forge/src/main/java/me/shedaniel/architectury/registry/forge/BlockEntityRenderersImpl.java
  21. 22 0
      forge/src/main/java/me/shedaniel/architectury/registry/forge/CreativeTabsImpl.java
  22. 12 0
      forge/src/main/java/me/shedaniel/architectury/registry/forge/KeyBindingsImpl.java
  23. 2 2
      forge/src/main/java/me/shedaniel/architectury/registry/forge/ReloadListenersImpl.java
  24. 23 0
      forge/src/main/java/me/shedaniel/architectury/registry/forge/RenderTypesImpl.java

+ 3 - 2
common/src/main/java/me/shedaniel/architectury/event/EventFactory.java

@@ -25,6 +25,7 @@ import net.fabricmc.api.Environment;
 import net.jodah.typetools.TypeResolver;
 import net.minecraft.world.InteractionResult;
 import org.apache.commons.lang3.ArrayUtils;
+import org.jetbrains.annotations.NotNull;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Method;
@@ -47,7 +48,7 @@ public final class EventFactory {
     public static <T> Event<T> createLoop(Class<T> clazz) {
         return create(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
             @Override
-            protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+            protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
                 for (T listener : listeners) {
                     method.invoke(listener, args);
                 }
@@ -60,7 +61,7 @@ public final class EventFactory {
     public static <T> Event<T> createInteractionResult(Class<T> clazz) {
         return create(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
             @Override
-            protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+            protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
                 for (T listener : listeners) {
                     InteractionResult result = (InteractionResult) method.invoke(listener, args);
                     if (result != InteractionResult.PASS) {

+ 16 - 4
common/src/main/java/me/shedaniel/architectury/event/events/LifecycleEvent.java

@@ -21,17 +21,21 @@ import me.shedaniel.architectury.event.EventFactory;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.Minecraft;
+import net.minecraft.resources.ResourceKey;
 import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+
+import java.util.logging.Level;
 
 public interface LifecycleEvent {
-    @Environment(EnvType.CLIENT)
-    Event<ClientState> CLIENT_STARTED = EventFactory.createLoop(ClientState.class);
-    @Environment(EnvType.CLIENT)
-    Event<ClientState> CLIENT_STOPPING = EventFactory.createLoop(ClientState.class);
+    @Environment(EnvType.CLIENT) Event<ClientState> CLIENT_STARTED = EventFactory.createLoop(ClientState.class);
+    @Environment(EnvType.CLIENT) Event<ClientState> CLIENT_STOPPING = EventFactory.createLoop(ClientState.class);
     Event<ServerState> SERVER_STARTING = EventFactory.createLoop(ServerState.class);
     Event<ServerState> SERVER_STARTED = EventFactory.createLoop(ServerState.class);
     Event<ServerState> SERVER_STOPPING = EventFactory.createLoop(ServerState.class);
     Event<ServerState> SERVER_STOPPED = EventFactory.createLoop(ServerState.class);
+    Event<WorldLoad> WORLD_LOAD = EventFactory.createLoop(WorldLoad.class);
+    Event<WorldSave> WORLD_SAVE = EventFactory.createLoop(WorldSave.class);
     
     interface InstanceState<T> {
         void stateChanged(T instance);
@@ -41,4 +45,12 @@ public interface LifecycleEvent {
     interface ClientState extends InstanceState<Minecraft> {}
     
     interface ServerState extends InstanceState<MinecraftServer> {}
+    
+    interface WorldLoad {
+        void load(ResourceKey<Level> key, ServerLevel world);
+    }
+    
+    interface WorldSave {
+        void save(ServerLevel world);
+    }
 }

+ 44 - 0
common/src/main/java/me/shedaniel/architectury/event/events/PlayerEvent.java

@@ -0,0 +1,44 @@
+package me.shedaniel.architectury.event.events;
+
+import me.shedaniel.architectury.event.Event;
+import me.shedaniel.architectury.event.EventFactory;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.player.LocalPlayer;
+import net.minecraft.server.level.ServerPlayer;
+
+public interface PlayerEvent {
+    Event<PlayerJoin> PLAYER_JOIN = EventFactory.createLoop(PlayerJoin.class);
+    Event<PlayerQuit> PLAYER_QUIT = EventFactory.createLoop(PlayerQuit.class);
+    Event<PlayerRespawn> PLAYER_RESPAWN = EventFactory.createLoop(PlayerRespawn.class);
+    @Environment(EnvType.CLIENT) Event<ClientPlayerJoin> CLIENT_PLAYER_JOIN = EventFactory.createLoop(ClientPlayerJoin.class);
+    @Environment(EnvType.CLIENT) Event<ClientPlayerQuit> CLIENT_PLAYER_QUIT = EventFactory.createLoop(ClientPlayerQuit.class);
+    @Environment(EnvType.CLIENT) Event<ClientPlayerRespawn> CLIENT_PLAYER_RESPAWN = EventFactory.createLoop(ClientPlayerRespawn.class);
+    
+    interface PlayerJoin {
+        void join(ServerPlayer player);
+    }
+    
+    interface PlayerQuit {
+        void quit(ServerPlayer player);
+    }
+    
+    interface PlayerRespawn {
+        void respawn(ServerPlayer newPlayer, boolean conqueredEnd);
+    }
+    
+    @Environment(EnvType.CLIENT)
+    interface ClientPlayerJoin {
+        void join(LocalPlayer player);
+    }
+    
+    @Environment(EnvType.CLIENT)
+    interface ClientPlayerQuit {
+        void quit(LocalPlayer player);
+    }
+    
+    @Environment(EnvType.CLIENT)
+    interface ClientPlayerRespawn {
+        void respawn(LocalPlayer oldPlayer, LocalPlayer newPlayer);
+    }
+}

+ 4 - 8
common/src/main/java/me/shedaniel/architectury/event/events/TickEvent.java

@@ -27,16 +27,12 @@ import net.minecraft.server.level.ServerLevel;
 import net.minecraft.world.level.Level;
 
 public interface TickEvent<T> {
-    @Environment(EnvType.CLIENT)
-    Event<Client> CLIENT_PRE = EventFactory.createLoop(Client.class);
-    @Environment(EnvType.CLIENT)
-    Event<Client> CLIENT_POST = EventFactory.createLoop(Client.class);
+    @Environment(EnvType.CLIENT) Event<Client> CLIENT_PRE = EventFactory.createLoop(Client.class);
+    @Environment(EnvType.CLIENT) Event<Client> CLIENT_POST = EventFactory.createLoop(Client.class);
     Event<Server> SERVER_PRE = EventFactory.createLoop(Server.class);
     Event<Server> SERVER_POST = EventFactory.createLoop(Server.class);
-    @Environment(EnvType.CLIENT)
-    Event<ClientWorld> CLIENT_WORLD_PRE = EventFactory.createLoop(ClientWorld.class);
-    @Environment(EnvType.CLIENT)
-    Event<ClientWorld> CLIENT_WORLD_POST = EventFactory.createLoop(ClientWorld.class);
+    @Environment(EnvType.CLIENT) Event<ClientWorld> CLIENT_WORLD_PRE = EventFactory.createLoop(ClientWorld.class);
+    @Environment(EnvType.CLIENT) Event<ClientWorld> CLIENT_WORLD_POST = EventFactory.createLoop(ClientWorld.class);
     Event<ServerWorld> SERVER_WORLD_PRE = EventFactory.createLoop(ServerWorld.class);
     Event<ServerWorld> SERVER_WORLD_POST = EventFactory.createLoop(ServerWorld.class);
     

+ 32 - 0
common/src/main/java/me/shedaniel/architectury/registry/BlockEntityRenderers.java

@@ -0,0 +1,32 @@
+package me.shedaniel.architectury.registry;
+
+import me.shedaniel.architectury.ArchitecturyPopulator;
+import me.shedaniel.architectury.Populatable;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
+import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.BlockEntityType;
+
+import java.util.function.Function;
+
+@Environment(EnvType.CLIENT)
+public final class BlockEntityRenderers {
+    private BlockEntityRenderers() {}
+    
+    @Populatable
+    private static final Impl IMPL = null;
+    
+    public static <T extends BlockEntity> void registerRenderer(BlockEntityType<T> type, Function<BlockEntityRenderDispatcher, BlockEntityRenderer<T>> provider) {
+        IMPL.registerRenderer(type, provider);
+    }
+    
+    public interface Impl {
+        <T extends BlockEntity> void registerRenderer(BlockEntityType<T> type, Function<BlockEntityRenderDispatcher, BlockEntityRenderer<T>> provider);
+    }
+    
+    static {
+        ArchitecturyPopulator.populate(BlockEntityRenderers.class);
+    }
+}

+ 29 - 0
common/src/main/java/me/shedaniel/architectury/registry/CreativeTabs.java

@@ -0,0 +1,29 @@
+package me.shedaniel.architectury.registry;
+
+import me.shedaniel.architectury.ArchitecturyPopulator;
+import me.shedaniel.architectury.Populatable;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.item.CreativeModeTab;
+import net.minecraft.world.item.ItemStack;
+
+import java.util.function.Supplier;
+
+public final class CreativeTabs {
+    public CreativeTabs() {}
+    
+    @Populatable
+    private static final Impl IMPL = null;
+    
+    // I am sorry, fabric wants a resource location instead of the translation key for whatever reason
+    public static CreativeModeTab create(ResourceLocation name, Supplier<ItemStack> icon) {
+        return IMPL.create(name, icon);
+    }
+    
+    public interface Impl {
+        CreativeModeTab create(ResourceLocation name, Supplier<ItemStack> icon);
+    }
+    
+    static {
+        ArchitecturyPopulator.populate(CreativeTabs.class);
+    }
+}

+ 27 - 0
common/src/main/java/me/shedaniel/architectury/registry/KeyBindings.java

@@ -0,0 +1,27 @@
+package me.shedaniel.architectury.registry;
+
+import me.shedaniel.architectury.ArchitecturyPopulator;
+import me.shedaniel.architectury.Populatable;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.KeyMapping;
+
+@Environment(EnvType.CLIENT)
+public final class KeyBindings {
+    private KeyBindings() {}
+    
+    @Populatable
+    private static final Impl IMPL = null;
+    
+    public static void registerKeyBinding(KeyMapping binding) {
+        IMPL.registerKeyBinding(binding);
+    }
+    
+    public interface Impl {
+        void registerKeyBinding(KeyMapping binding);
+    }
+    
+    static {
+        ArchitecturyPopulator.populate(KeyBindings.class);
+    }
+}

+ 3 - 3
common/src/main/java/me/shedaniel/architectury/registry/ReloadListenerRegistry.java → common/src/main/java/me/shedaniel/architectury/registry/ReloadListeners.java

@@ -5,8 +5,8 @@ import me.shedaniel.architectury.Populatable;
 import net.minecraft.server.packs.PackType;
 import net.minecraft.server.packs.resources.PreparableReloadListener;
 
-public final class ReloadListenerRegistry {
-    private ReloadListenerRegistry() {}
+public final class ReloadListeners {
+    private ReloadListeners() {}
     
     @Populatable
     private static final Impl IMPL = null;
@@ -20,6 +20,6 @@ public final class ReloadListenerRegistry {
     }
     
     static {
-        ArchitecturyPopulator.populate(ReloadListenerRegistry.class);
+        ArchitecturyPopulator.populate(ReloadListeners.class);
     }
 }

+ 36 - 0
common/src/main/java/me/shedaniel/architectury/registry/RenderTypes.java

@@ -0,0 +1,36 @@
+package me.shedaniel.architectury.registry;
+
+import me.shedaniel.architectury.ArchitecturyPopulator;
+import me.shedaniel.architectury.Populatable;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.material.Fluid;
+
+@Environment(EnvType.CLIENT)
+public final class RenderTypes {
+    private RenderTypes() {}
+    
+    @Populatable
+    private static final Impl IMPL = null;
+    
+    public static void register(RenderType type, Block... blocks) {
+        IMPL.register(type, blocks);
+    }
+    
+    public static void register(RenderType type, Fluid... fluids) {
+        IMPL.register(type, fluids);
+    }
+    
+    public interface Impl {
+        void register(RenderType type, Block... blocks);
+        
+        void register(RenderType type, Fluid... fluids);
+    }
+    
+    static {
+        ArchitecturyPopulator.populate(RenderTypes.class);
+    }
+}
+

+ 29 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinPlayerList.java

@@ -0,0 +1,29 @@
+package me.shedaniel.architectury.mixin.fabric;
+
+import me.shedaniel.architectury.event.events.PlayerEvent;
+import net.minecraft.network.Connection;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.players.PlayerList;
+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;
+
+@Mixin(PlayerList.class)
+public class MixinPlayerList {
+    @Inject(method = "placeNewPlayer", at = @At("RETURN"))
+    private void placeNewPlayer(Connection connection, ServerPlayer serverPlayer, CallbackInfo ci) {
+        PlayerEvent.PLAYER_JOIN.invoker().join(serverPlayer);
+    }
+    
+    @Inject(method = "remove", at = @At("HEAD"))
+    private void remove(ServerPlayer serverPlayer, CallbackInfo ci) {
+        PlayerEvent.PLAYER_QUIT.invoker().quit(serverPlayer);
+    }
+    
+    @Inject(method = "respawn", at = @At("RETURN"))
+    private void respawn(ServerPlayer serverPlayer, boolean bl, CallbackInfoReturnable<ServerPlayer> cir) {
+        PlayerEvent.PLAYER_RESPAWN.invoker().respawn(cir.getReturnValue(), bl);
+    }
+}

+ 37 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinClientPacketListener.java

@@ -0,0 +1,37 @@
+package me.shedaniel.architectury.mixin.fabric.client;
+
+import me.shedaniel.architectury.event.events.PlayerEvent;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.multiplayer.ClientPacketListener;
+import net.minecraft.client.player.LocalPlayer;
+import net.minecraft.network.protocol.game.ClientboundLoginPacket;
+import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(ClientPacketListener.class)
+public class MixinClientPacketListener {
+    @Shadow private Minecraft minecraft;
+    @Unique private LocalPlayer tmpPlayer;
+    
+    @Inject(method = "handleLogin", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;broadcastOptions()V"))
+    private void handleLogin(ClientboundLoginPacket clientboundLoginPacket, CallbackInfo ci) {
+        PlayerEvent.CLIENT_PLAYER_JOIN.invoker().join(minecraft.player);
+    }
+    
+    @Inject(method = "handleRespawn", at = @At("HEAD"))
+    private void handleRespawnPre(ClientboundRespawnPacket clientboundRespawnPacket, CallbackInfo ci) {
+        this.tmpPlayer = minecraft.player;
+    }
+    
+    @Inject(method = "handleRespawn", at = @At(value = "INVOKE",
+                                               target = "Lnet/minecraft/client/multiplayer/ClientLevel;addPlayer(ILnet/minecraft/client/player/AbstractClientPlayer;)V"))
+    private void handleRespawn(ClientboundRespawnPacket clientboundRespawnPacket, CallbackInfo ci) {
+        PlayerEvent.CLIENT_PLAYER_RESPAWN.invoker().respawn(tmpPlayer, minecraft.player);
+        this.tmpPlayer = null;
+    }
+}

+ 23 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMinecraft.java

@@ -0,0 +1,23 @@
+package me.shedaniel.architectury.mixin.fabric.client;
+
+import me.shedaniel.architectury.event.events.PlayerEvent;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.client.player.LocalPlayer;
+import org.jetbrains.annotations.Nullable;
+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(Minecraft.class)
+public class MixinMinecraft {
+    @Shadow @Nullable public LocalPlayer player;
+    
+    @Inject(method = "clearLevel(Lnet/minecraft/client/gui/screens/Screen;)V",
+            at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/chat/NarratorChatListener;clear()V"))
+    private void handleLogin(Screen screen, CallbackInfo ci) {
+        PlayerEvent.CLIENT_PLAYER_QUIT.invoker().quit(player);
+    }
+}

+ 17 - 0
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/BlockEntityRenderersImpl.java

@@ -0,0 +1,17 @@
+package me.shedaniel.architectury.registry.fabric;
+
+import me.shedaniel.architectury.registry.BlockEntityRenderers;
+import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry;
+import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
+import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.BlockEntityType;
+
+import java.util.function.Function;
+
+public class BlockEntityRenderersImpl implements BlockEntityRenderers.Impl {
+    @Override
+    public <T extends BlockEntity> void registerRenderer(BlockEntityType<T> type, Function<BlockEntityRenderDispatcher, BlockEntityRenderer<T>> provider) {
+        BlockEntityRendererRegistry.INSTANCE.register(type, provider);
+    }
+}

+ 16 - 0
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/CreativeTabsImpl.java

@@ -0,0 +1,16 @@
+package me.shedaniel.architectury.registry.fabric;
+
+import me.shedaniel.architectury.registry.CreativeTabs;
+import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.item.CreativeModeTab;
+import net.minecraft.world.item.ItemStack;
+
+import java.util.function.Supplier;
+
+public class CreativeTabsImpl implements CreativeTabs.Impl {
+    @Override
+    public CreativeModeTab create(ResourceLocation name, Supplier<ItemStack> icon) {
+        return FabricItemGroupBuilder.build(name, icon);
+    }
+}

+ 12 - 0
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/KeyBindingsImpl.java

@@ -0,0 +1,12 @@
+package me.shedaniel.architectury.registry.fabric;
+
+import me.shedaniel.architectury.registry.KeyBindings;
+import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
+import net.minecraft.client.KeyMapping;
+
+public class KeyBindingsImpl implements KeyBindings.Impl {
+    @Override
+    public void registerKeyBinding(KeyMapping binding) {
+        KeyBindingHelper.registerKeyBinding(binding);
+    }
+}

+ 2 - 2
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/ReloadListenerRegistryImpl.java → fabric/src/main/java/me/shedaniel/architectury/registry/fabric/ReloadListenersImpl.java

@@ -1,7 +1,7 @@
 package me.shedaniel.architectury.registry.fabric;
 
 import com.google.common.primitives.Longs;
-import me.shedaniel.architectury.registry.ReloadListenerRegistry;
+import me.shedaniel.architectury.registry.ReloadListeners;
 import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
 import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
 import net.minecraft.resources.ResourceLocation;
@@ -15,7 +15,7 @@ import java.security.SecureRandom;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 
-public class ReloadListenerRegistryImpl implements ReloadListenerRegistry.Impl {
+public class ReloadListenersImpl implements ReloadListeners.Impl {
     private static final SecureRandom RANDOM = new SecureRandom();
     
     @Override

+ 19 - 0
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/RenderTypesImpl.java

@@ -0,0 +1,19 @@
+package me.shedaniel.architectury.registry.fabric;
+
+import me.shedaniel.architectury.registry.RenderTypes;
+import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.material.Fluid;
+
+public class RenderTypesImpl implements RenderTypes.Impl {
+    @Override
+    public void register(RenderType type, Block... blocks) {
+        BlockRenderLayerMap.INSTANCE.putBlocks(type, blocks);
+    }
+    
+    @Override
+    public void register(RenderType type, Fluid... fluids) {
+        BlockRenderLayerMap.INSTANCE.putFluids(type, fluids);
+    }
+}

+ 16 - 0
fabric/src/main/resources/architectury.mixins.json

@@ -0,0 +1,16 @@
+{
+  "required": true,
+  "package": "me.shedaniel.architectury.mixin.fabric",
+  "compatibilityLevel": "JAVA_8",
+  "minVersion": "0.7.11",
+  "client": [
+    "client.MixinClientPacketListener",
+    "client.MixinMinecraft"
+  ],
+  "mixins": [
+    "MixinPlayerList"
+  ],
+  "injectors": {
+    "defaultRequire": 1
+  }
+}

+ 35 - 0
forge/src/main/java/me/shedaniel/architectury/event/forge/EventFactoryImpl.java

@@ -19,9 +19,11 @@ package me.shedaniel.architectury.event.forge;
 import me.shedaniel.architectury.event.EventFactory;
 import me.shedaniel.architectury.event.events.*;
 import net.minecraft.client.Minecraft;
+import net.minecraft.entity.player.ServerPlayerEntity;
 import net.minecraft.world.server.ServerWorld;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.OnlyIn;
+import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
 import net.minecraftforge.client.event.RenderGameOverlayEvent;
 import net.minecraftforge.common.MinecraftForge;
 import net.minecraftforge.event.RegisterCommandsEvent;
@@ -30,6 +32,9 @@ import net.minecraftforge.event.TickEvent.Phase;
 import net.minecraftforge.event.TickEvent.ServerTickEvent;
 import net.minecraftforge.event.TickEvent.WorldTickEvent;
 import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent;
+import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedOutEvent;
+import net.minecraftforge.event.entity.player.PlayerEvent.PlayerRespawnEvent;
 import net.minecraftforge.eventbus.api.SubscribeEvent;
 import net.minecraftforge.fml.LogicalSide;
 import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
@@ -73,6 +78,21 @@ public class EventFactoryImpl implements EventFactory.Impl {
         public static void event(RenderGameOverlayEvent.Post event) {
             GuiEvent.RENDER_HUD.invoker().renderHud(event.getMatrixStack(), event.getPartialTicks());
         }
+        
+        @SubscribeEvent
+        public static void event(ClientPlayerNetworkEvent.LoggedInEvent event) {
+            PlayerEvent.CLIENT_PLAYER_JOIN.invoker().join(event.getPlayer());
+        }
+        
+        @SubscribeEvent
+        public static void event(ClientPlayerNetworkEvent.LoggedOutEvent event) {
+            PlayerEvent.CLIENT_PLAYER_QUIT.invoker().quit(event.getPlayer());
+        }
+        
+        @SubscribeEvent
+        public static void event(ClientPlayerNetworkEvent.RespawnEvent event) {
+            PlayerEvent.CLIENT_PLAYER_RESPAWN.invoker().respawn(event.getOldPlayer(), event.getNewPlayer());
+        }
     }
     
     public static class Common {
@@ -118,6 +138,21 @@ public class EventFactoryImpl implements EventFactory.Impl {
         public static void event(RegisterCommandsEvent event) {
             CommandRegistrationEvent.EVENT.invoker().register(event.getDispatcher());
         }
+        
+        @SubscribeEvent
+        public static void event(PlayerLoggedInEvent event) {
+            PlayerEvent.PLAYER_JOIN.invoker().join((ServerPlayerEntity) event.getPlayer());
+        }
+        
+        @SubscribeEvent
+        public static void event(PlayerLoggedOutEvent event) {
+            PlayerEvent.PLAYER_QUIT.invoker().quit((ServerPlayerEntity) event.getPlayer());
+        }
+        
+        @SubscribeEvent
+        public static void event(PlayerRespawnEvent event) {
+            PlayerEvent.PLAYER_RESPAWN.invoker().respawn((ServerPlayerEntity) event.getPlayer(), event.isEndConquered());
+        }
     }
     
     @OnlyIn(Dist.DEDICATED_SERVER)

+ 17 - 0
forge/src/main/java/me/shedaniel/architectury/registry/forge/BlockEntityRenderersImpl.java

@@ -0,0 +1,17 @@
+package me.shedaniel.architectury.registry.forge;
+
+import me.shedaniel.architectury.registry.BlockEntityRenderers;
+import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
+import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.tileentity.TileEntityType;
+import net.minecraftforge.fml.client.registry.ClientRegistry;
+
+import java.util.function.Function;
+
+public class BlockEntityRenderersImpl implements BlockEntityRenderers.Impl {
+    @Override
+    public <T extends TileEntity> void registerRenderer(TileEntityType<T> type, Function<TileEntityRendererDispatcher, TileEntityRenderer<T>> provider) {
+        ClientRegistry.bindTileEntityRenderer(type, provider);
+    }
+}

+ 22 - 0
forge/src/main/java/me/shedaniel/architectury/registry/forge/CreativeTabsImpl.java

@@ -0,0 +1,22 @@
+package me.shedaniel.architectury.registry.forge;
+
+import me.shedaniel.architectury.registry.CreativeTabs;
+import net.minecraft.item.ItemGroup;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ResourceLocation;
+
+import javax.annotation.Nonnull;
+import java.util.function.Supplier;
+
+public class CreativeTabsImpl implements CreativeTabs.Impl {
+    @Override
+    public ItemGroup create(ResourceLocation resourceLocation, Supplier<ItemStack> supplier) {
+        return new ItemGroup(String.format("%s.%s", resourceLocation.getNamespace(), resourceLocation.getPath())) {
+            @Override
+            @Nonnull
+            public ItemStack makeIcon() {
+                return supplier.get();
+            }
+        };
+    }
+}

+ 12 - 0
forge/src/main/java/me/shedaniel/architectury/registry/forge/KeyBindingsImpl.java

@@ -0,0 +1,12 @@
+package me.shedaniel.architectury.registry.forge;
+
+import me.shedaniel.architectury.registry.KeyBindings;
+import net.minecraft.client.settings.KeyBinding;
+import net.minecraftforge.fml.client.registry.ClientRegistry;
+
+public class KeyBindingsImpl implements KeyBindings.Impl {
+    @Override
+    public void registerKeyBinding(KeyBinding keyBinding) {
+        ClientRegistry.registerKeyBinding(keyBinding);
+    }
+}

+ 2 - 2
forge/src/main/java/me/shedaniel/architectury/registry/forge/ReloadListenerRegistryImpl.java → forge/src/main/java/me/shedaniel/architectury/registry/forge/ReloadListenersImpl.java

@@ -13,10 +13,10 @@ import net.minecraftforge.event.AddReloadListenerEvent;
 
 import java.util.List;
 
-public class ReloadListenerRegistryImpl implements ReloadListenerRegistry.Impl {
+public class ReloadListenersImpl implements ReloadListenerRegistry.Impl {
     private List<IFutureReloadListener> serverDataReloadListeners = Lists.newArrayList();
     
-    public ReloadListenerRegistryImpl() {
+    public ReloadListenersImpl() {
         MinecraftForge.EVENT_BUS.<AddReloadListenerEvent>addListener(event -> {
             for (IFutureReloadListener listener : serverDataReloadListeners) {
                 event.addListener(listener);

+ 23 - 0
forge/src/main/java/me/shedaniel/architectury/registry/forge/RenderTypesImpl.java

@@ -0,0 +1,23 @@
+package me.shedaniel.architectury.registry.forge;
+
+import me.shedaniel.architectury.registry.RenderTypes;
+import net.minecraft.block.Block;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.RenderTypeLookup;
+import net.minecraft.fluid.Fluid;
+
+public class RenderTypesImpl implements RenderTypes.Impl {
+    @Override
+    public void register(RenderType type, Block... blocks) {
+        for (Block block : blocks) {
+            RenderTypeLookup.setRenderLayer(block, type);
+        }
+    }
+    
+    @Override
+    public void register(RenderType type, Fluid... fluids) {
+        for (Fluid fluid : fluids) {
+            RenderTypeLookup.setRenderLayer(fluid, type);
+        }
+    }
+}