Add tooltip events, new events for server starting

This commit is contained in:
shedaniel
2020-11-26 18:43:27 +08:00
parent eaba509f2b
commit f9eeced624
12 changed files with 362 additions and 21 deletions

View File

@@ -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);
/**

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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": {

View File

@@ -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

View File

@@ -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 {
}