Sfoglia il codice sorgente

Add tooltip events, new events for server starting

shedaniel 4 anni fa
parent
commit
f9eeced624

+ 5 - 1
common/src/main/java/me/shedaniel/architectury/event/events/LifecycleEvent.java

@@ -27,7 +27,11 @@ import net.minecraft.world.level.Level;
 
 public interface LifecycleEvent {
     /**
-     * Invoked when server is starting, equivalent to forge's {@code FMLServerStartingEvent} and fabric's {@code ServerLifecycleEvents#SERVER_STARTING}.
+     * Invoked when server is starting, equivalent to forge's {@code FMLServerAboutToStartEvent} and fabric's {@code ServerLifecycleEvents#SERVER_STARTING}.
+     */
+    Event<ServerState> SERVER_BEFORE_START = EventFactory.createLoop(ServerState.class);
+    /**
+     * Invoked when server is starting, equivalent to forge's {@code FMLServerStartingEvent}.
      */
     Event<ServerState> SERVER_STARTING = EventFactory.createLoop(ServerState.class);
     /**

+ 60 - 0
common/src/main/java/me/shedaniel/architectury/event/events/TooltipEvent.java

@@ -19,11 +19,15 @@
 
 package me.shedaniel.architectury.event.events;
 
+import com.mojang.blaze3d.vertex.PoseStack;
 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.network.chat.Component;
+import net.minecraft.network.chat.FormattedText;
+import net.minecraft.util.FormattedCharSequence;
+import net.minecraft.world.InteractionResult;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.TooltipFlag;
 
@@ -32,9 +36,65 @@ import java.util.List;
 @Environment(EnvType.CLIENT)
 public interface TooltipEvent {
     Event<Item> ITEM = EventFactory.createLoop(Item.class);
+    /**
+     * Render vanilla events are not invoked on the forge side.
+     */
+    Event<RenderVanilla> RENDER_VANILLA_PRE = EventFactory.createInteractionResult(RenderVanilla.class);
+    /**
+     * Render forge events are only invoked on the forge side.
+     */
+    Event<RenderForge> RENDER_FORGE_PRE = EventFactory.createInteractionResult(RenderForge.class);
+    Event<RenderModifyPosition> RENDER_MODIFY_POSITION = EventFactory.createInteractionResult(RenderModifyPosition.class);
+    Event<RenderModifyColor> RENDER_MODIFY_COLOR = EventFactory.createInteractionResult(RenderModifyColor.class);
     
     @Environment(EnvType.CLIENT)
     interface Item {
         void append(ItemStack stack, List<Component> lines, TooltipFlag flag);
     }
+    
+    @Environment(EnvType.CLIENT)
+    interface RenderVanilla {
+        InteractionResult renderTooltip(PoseStack matrices, List<? extends FormattedCharSequence> texts, int x, int y);
+    }
+    
+    @Environment(EnvType.CLIENT)
+    interface RenderForge {
+        InteractionResult renderTooltip(PoseStack matrices, List<? extends FormattedText> texts, int x, int y);
+    }
+    
+    @Environment(EnvType.CLIENT)
+    interface RenderModifyPosition {
+        void renderTooltip(PoseStack matrices, PositionContext context);
+    }
+    
+    @Environment(EnvType.CLIENT)
+    interface RenderModifyColor {
+        void renderTooltip(PoseStack matrices, int x, int y, ColorContext context);
+    }
+    
+    @Environment(EnvType.CLIENT)
+    interface PositionContext {
+        int getTooltipX();
+        
+        void setTooltipX(int x);
+        
+        int getTooltipY();
+        
+        void setTooltipY(int y);
+    }
+    
+    @Environment(EnvType.CLIENT)
+    interface ColorContext {
+        int getBackgroundColor();
+        
+        void setBackgroundColor(int color);
+        
+        int getOutlineGradientTopColor();
+        
+        void setOutlineGradientTopColor(int color);
+        
+        int getOutlineGradientBottomColor();
+        
+        void setOutlineGradientBottomColor(int color);
+    }
 }

+ 68 - 0
common/src/main/java/me/shedaniel/architectury/impl/TooltipEventColorContextImpl.java

@@ -0,0 +1,68 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.impl;
+
+import me.shedaniel.architectury.event.events.TooltipEvent;
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Internal
+public class TooltipEventColorContextImpl implements TooltipEvent.ColorContext {
+    private int backgroundColor;
+    private int outlineGradientTopColor;
+    private int outlineGradientBottomColor;
+    
+    public TooltipEventColorContextImpl reset() {
+        this.backgroundColor = 0xf0100010;
+        this.outlineGradientTopColor = 0x505000ff;
+        this.outlineGradientBottomColor = 0x5028007f;
+        
+        return this;
+    }
+    
+    @Override
+    public int getBackgroundColor() {
+        return backgroundColor;
+    }
+    
+    @Override
+    public void setBackgroundColor(int color) {
+        this.backgroundColor = color;
+    }
+    
+    @Override
+    public int getOutlineGradientTopColor() {
+        return outlineGradientTopColor;
+    }
+    
+    @Override
+    public void setOutlineGradientTopColor(int color) {
+        this.outlineGradientTopColor = color;
+    }
+    
+    @Override
+    public int getOutlineGradientBottomColor() {
+        return outlineGradientBottomColor;
+    }
+    
+    @Override
+    public void setOutlineGradientBottomColor(int color) {
+        this.outlineGradientBottomColor = color;
+    }
+}

+ 56 - 0
common/src/main/java/me/shedaniel/architectury/impl/TooltipEventPositionContextImpl.java

@@ -0,0 +1,56 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.impl;
+
+import me.shedaniel.architectury.event.events.TooltipEvent;
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Internal
+public class TooltipEventPositionContextImpl implements TooltipEvent.PositionContext {
+    private int tooltipX;
+    private int tooltipY;
+    
+    public TooltipEventPositionContextImpl reset(int tooltipX, int tooltipY) {
+        this.tooltipX = tooltipX;
+        this.tooltipY = tooltipY;
+        
+        return this;
+    }
+    
+    @Override
+    public int getTooltipX() {
+        return tooltipX;
+    }
+    
+    @Override
+    public void setTooltipX(int x) {
+        this.tooltipX = x;
+    }
+    
+    @Override
+    public int getTooltipY() {
+        return tooltipY;
+    }
+    
+    @Override
+    public void setTooltipY(int y) {
+        this.tooltipY = y;
+    }
+}

+ 1 - 1
fabric/src/main/java/me/shedaniel/architectury/event/fabric/EventHandlerImpl.java

@@ -53,7 +53,7 @@ public class EventHandlerImpl {
     }
     
     public static void registerCommon() {
-        ServerLifecycleEvents.SERVER_STARTING.register(LifecycleEvent.SERVER_STARTING.invoker()::stateChanged);
+        ServerLifecycleEvents.SERVER_STARTING.register(LifecycleEvent.SERVER_BEFORE_START.invoker()::stateChanged);
         ServerLifecycleEvents.SERVER_STARTED.register(LifecycleEvent.SERVER_STARTED.invoker()::stateChanged);
         ServerLifecycleEvents.SERVER_STOPPING.register(LifecycleEvent.SERVER_STOPPING.invoker()::stateChanged);
         ServerLifecycleEvents.SERVER_STOPPED.register(LifecycleEvent.SERVER_STOPPED.invoker()::stateChanged);

+ 38 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinDedicatedServer.java

@@ -0,0 +1,38 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.mixin.fabric;
+
+import me.shedaniel.architectury.event.events.LifecycleEvent;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.dedicated.DedicatedServer;
+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.CallbackInfoReturnable;
+
+@Mixin(DedicatedServer.class)
+public class MixinDedicatedServer {
+    @Inject(method = "initServer", at = @At("RETURN"), cancellable = true)
+    private void initServer(CallbackInfoReturnable<Boolean> cir) {
+        if (cir.getReturnValueZ()) {
+            LifecycleEvent.SERVER_STARTING.invoker().stateChanged((MinecraftServer) (Object) this);
+        }
+    }
+}

+ 38 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinIntegratedServer.java

@@ -0,0 +1,38 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.mixin.fabric.client;
+
+import me.shedaniel.architectury.event.events.LifecycleEvent;
+import net.minecraft.client.server.IntegratedServer;
+import net.minecraft.server.MinecraftServer;
+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.CallbackInfoReturnable;
+
+@Mixin(IntegratedServer.class)
+public class MixinIntegratedServer {
+    @Inject(method = "initServer", at = @At("RETURN"), cancellable = true)
+    private void initServer(CallbackInfoReturnable<Boolean> cir) {
+        if (cir.getReturnValueZ()) {
+            LifecycleEvent.SERVER_STARTING.invoker().stateChanged((MinecraftServer) (Object) this);
+        }
+    }
+}

+ 53 - 4
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinScreen.java

@@ -19,27 +19,33 @@
 
 package me.shedaniel.architectury.mixin.fabric.client;
 
+import com.mojang.blaze3d.vertex.PoseStack;
 import me.shedaniel.architectury.event.events.GuiEvent;
+import me.shedaniel.architectury.event.events.TooltipEvent;
 import me.shedaniel.architectury.event.events.client.ClientChatEvent;
+import me.shedaniel.architectury.impl.TooltipEventColorContextImpl;
+import me.shedaniel.architectury.impl.TooltipEventPositionContextImpl;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.components.AbstractWidget;
 import net.minecraft.client.gui.components.events.GuiEventListener;
 import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.util.FormattedCharSequence;
 import net.minecraft.world.InteractionResult;
 import net.minecraft.world.InteractionResultHolder;
 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.ModifyVariable;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.*;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 
 import java.util.List;
 
 @Mixin(Screen.class)
 public abstract class MixinScreen {
-    @Shadow @Final protected List<AbstractWidget> buttons;
+    @Shadow @Final public List<AbstractWidget> buttons;
+    @Unique private static ThreadLocal<TooltipEventPositionContextImpl> tooltipPositionContext = ThreadLocal.withInitial(TooltipEventPositionContextImpl::new);
+    @Unique private static ThreadLocal<TooltipEventColorContextImpl> tooltipColorContext = ThreadLocal.withInitial(TooltipEventColorContextImpl::new);
     
     @Shadow
     public abstract List<? extends GuiEventListener> children();
@@ -66,4 +72,47 @@ public abstract class MixinScreen {
             return process.getObject();
         return message;
     }
+    
+    @Inject(method = "renderTooltip(Lcom/mojang/blaze3d/vertex/PoseStack;Ljava/util/List;II)V", at = @At("HEAD"), cancellable = true)
+    private void renderTooltip(PoseStack poseStack, List<? extends FormattedCharSequence> list, int x, int y, CallbackInfo ci) {
+        if (!list.isEmpty()) {
+            TooltipEventColorContextImpl colorContext = tooltipColorContext.get();
+            colorContext.reset();
+            TooltipEventPositionContextImpl positionContext = tooltipPositionContext.get();
+            positionContext.reset(x, y);
+            if (TooltipEvent.RENDER_VANILLA_PRE.invoker().renderTooltip(poseStack, list, x, y) == InteractionResult.FAIL) {
+                ci.cancel();
+            } else {
+                TooltipEvent.RENDER_MODIFY_COLOR.invoker().renderTooltip(poseStack, x, y, colorContext);
+                TooltipEvent.RENDER_MODIFY_POSITION.invoker().renderTooltip(poseStack, positionContext);
+            }
+        }
+    }
+    
+    @ModifyVariable(method = "renderTooltip(Lcom/mojang/blaze3d/vertex/PoseStack;Ljava/util/List;II)V",
+                    at = @At(value = "HEAD"), ordinal = 0)
+    private int modifyTooltipX(int original) {
+        return tooltipPositionContext.get().getTooltipX();
+    }
+    
+    @ModifyVariable(method = "renderTooltip(Lcom/mojang/blaze3d/vertex/PoseStack;Ljava/util/List;II)V",
+                    at = @At(value = "HEAD"), ordinal = 1)
+    private int modifyTooltipY(int original) {
+        return tooltipPositionContext.get().getTooltipY();
+    }
+    
+    @ModifyConstant(method = "renderTooltip(Lcom/mojang/blaze3d/vertex/PoseStack;Ljava/util/List;II)V", constant = @Constant(intValue = 0xf0100010))
+    private int modifyTooltipBackgroundColor(int original) {
+        return tooltipColorContext.get().getBackgroundColor();
+    }
+    
+    @ModifyConstant(method = "renderTooltip(Lcom/mojang/blaze3d/vertex/PoseStack;Ljava/util/List;II)V", constant = @Constant(intValue = 0x505000ff))
+    private int modifyTooltipOutlineGradientTopColor(int original) {
+        return tooltipColorContext.get().getOutlineGradientTopColor();
+    }
+    
+    @ModifyConstant(method = "renderTooltip(Lcom/mojang/blaze3d/vertex/PoseStack;Ljava/util/List;II)V", constant = @Constant(intValue = 0x5028007f))
+    private int modifyTooltipOutlineGradientBottomColor(int original) {
+        return tooltipColorContext.get().getOutlineGradientBottomColor();
+    }
 }

+ 1 - 1
fabric/src/main/java/me/shedaniel/architectury/utils/fabric/GameInstanceImpl.java

@@ -41,7 +41,7 @@ public class GameInstanceImpl {
     
     public static void init() {
         EventHandler.init();
-        LifecycleEvent.SERVER_STARTING.register(server -> GameInstanceImpl.server = server);
+        LifecycleEvent.SERVER_BEFORE_START.register(server -> GameInstanceImpl.server = server);
         LifecycleEvent.SERVER_STOPPED.register(server -> GameInstanceImpl.server = null);
     }
     

+ 4 - 10
fabric/src/main/resources/architectury.mixins.json

@@ -4,18 +4,12 @@
   "compatibilityLevel": "JAVA_8",
   "minVersion": "0.7.11",
   "client": [
-    "client.MixinClientLevel",
-    "client.MixinClientPacketListener",
-    "client.MixinDebugScreenOverlay",
-    "client.MixinGameRenderer",
-    "client.MixinMinecraft",
-    "client.MixinMultiPlayerGameMode",
-    "client.MixinScreen",
-    "client.MixinTextureAtlas"
+    "client.MixinClientLevel", "client.MixinClientPacketListener", "client.MixinDebugScreenOverlay", "client.MixinGameRenderer", "client.MixinIntegratedServer",
+    "client.MixinMinecraft", "client.MixinMultiPlayerGameMode", "client.MixinScreen", "client.MixinTextureAtlas"
   ],
   "mixins": [
-    "ExplosionPreInvoker", "LivingDeathInvoker", "MixinBlockItem", "MixinCommands", "MixinExplosion", "MixinFurnaceResultSlot", "MixinItemEntity",
-    "MixinLivingEntity", "MixinPlayer", "MixinPlayerAdvancements", "MixinPlayerList", "MixinResultSlot", "MixinServerGamePacketListenerImpl",
+    "ExplosionPreInvoker", "LivingDeathInvoker", "MixinBlockItem", "MixinCommands", "MixinDedicatedServer", "MixinExplosion", "MixinFurnaceResultSlot",
+    "MixinItemEntity", "MixinLivingEntity", "MixinPlayer", "MixinPlayerAdvancements", "MixinPlayerList", "MixinResultSlot", "MixinServerGamePacketListenerImpl",
     "MixinServerLevel", "MixinServerPlayer", "MixinServerPlayerGameMode", "PlayerAttackInvoker"
   ],
   "injectors": {

+ 32 - 0
forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java

@@ -25,6 +25,8 @@ import me.shedaniel.architectury.event.events.client.ClientChatEvent;
 import me.shedaniel.architectury.event.events.client.ClientLifecycleEvent;
 import me.shedaniel.architectury.event.events.client.ClientPlayerEvent;
 import me.shedaniel.architectury.event.events.client.ClientTickEvent;
+import me.shedaniel.architectury.impl.TooltipEventColorContextImpl;
+import me.shedaniel.architectury.impl.TooltipEventPositionContextImpl;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.IGuiEventListener;
 import net.minecraft.client.world.ClientWorld;
@@ -148,6 +150,36 @@ public class EventHandlerImplClient {
         RecipeUpdateEvent.EVENT.invoker().update(event.getRecipeManager());
     }
     
+    private static final ThreadLocal<TooltipEventColorContextImpl> tooltipColorContext = ThreadLocal.withInitial(TooltipEventColorContextImpl::new);
+    private static final ThreadLocal<TooltipEventPositionContextImpl> tooltipPositionContext = ThreadLocal.withInitial(TooltipEventPositionContextImpl::new);
+    
+    @SubscribeEvent
+    public static void event(RenderTooltipEvent.Pre event) {
+        if (TooltipEvent.RENDER_FORGE_PRE.invoker().renderTooltip(event.getMatrixStack(), event.getLines(), event.getX(), event.getY()) == ActionResultType.FAIL) {
+            event.setCanceled(true);
+            return;
+        }
+        
+        TooltipEventPositionContextImpl positionContext = tooltipPositionContext.get();
+        positionContext.reset(event.getX(), event.getY());
+        TooltipEvent.RENDER_MODIFY_POSITION.invoker().renderTooltip(event.getMatrixStack(), positionContext);
+        event.setX(positionContext.getTooltipX());
+        event.setY(positionContext.getTooltipY());
+    }
+    
+    @SubscribeEvent
+    public static void event(RenderTooltipEvent.Color event) {
+        TooltipEventColorContextImpl colorContext = tooltipColorContext.get();
+        colorContext.reset();
+        colorContext.setBackgroundColor(event.getBackground());
+        colorContext.setOutlineGradientTopColor(event.getBorderStart());
+        colorContext.setOutlineGradientBottomColor(event.getBorderEnd());
+        TooltipEvent.RENDER_MODIFY_COLOR.invoker().renderTooltip(event.getMatrixStack(), event.getX(), event.getY(), colorContext);
+        event.setBackground(colorContext.getBackgroundColor());
+        event.setBorderEnd(colorContext.getOutlineGradientBottomColor());
+        event.setBorderStart(colorContext.getOutlineGradientTopColor());
+    }
+    
     @OnlyIn(Dist.CLIENT)
     public static class ModBasedEventHandler {
         @SubscribeEvent

+ 6 - 4
forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplCommon.java

@@ -51,10 +51,7 @@ import net.minecraftforge.event.world.WorldEvent;
 import net.minecraftforge.eventbus.api.Event;
 import net.minecraftforge.eventbus.api.SubscribeEvent;
 import net.minecraftforge.fml.LogicalSide;
-import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
-import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
-import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
-import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
+import net.minecraftforge.fml.event.server.*;
 import net.minecraftforge.fml.server.ServerLifecycleHooks;
 
 public class EventHandlerImplCommon {
@@ -320,6 +317,11 @@ public class EventHandlerImplCommon {
         }
     }
     
+    @SubscribeEvent
+    public static void event(FMLServerAboutToStartEvent event) {
+        LifecycleEvent.SERVER_BEFORE_START.invoker().stateChanged(event.getServer());
+    }
+    
     public static class ModBasedEventHandler {
         
     }