diff options
Diffstat (limited to 'versions/src/main/java/cc')
32 files changed, 1692 insertions, 0 deletions
diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ChatReceiveEvent.java b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ChatReceiveEvent.java new file mode 100644 index 0000000..6585729 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ChatReceiveEvent.java @@ -0,0 +1,22 @@ +package cc.polyfrost.oneconfig.events.event; + +import cc.polyfrost.oneconfig.libs.universal.wrappers.message.UTextComponent; +import net.minecraft.util.IChatComponent; + +/** + * Called when a chat message is received. + */ +public class ChatReceiveEvent extends CancellableEvent { + /** + * The message that was received. + */ + public final IChatComponent message; + + public ChatReceiveEvent(IChatComponent message) { + this.message = message; + } + + public String getFullyUnformattedMessage() { + return UTextComponent.Companion.stripFormatting(message.getUnformattedText()); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ReceivePacketEvent.java b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ReceivePacketEvent.java new file mode 100644 index 0000000..17bc16d --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ReceivePacketEvent.java @@ -0,0 +1,11 @@ +package cc.polyfrost.oneconfig.events.event; + +import net.minecraft.network.Packet; + +public class ReceivePacketEvent extends CancellableEvent { + public final Packet<?> packet; + + public ReceivePacketEvent(Packet<?> packet) { + this.packet = packet; + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ScreenOpenEvent.java b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ScreenOpenEvent.java new file mode 100644 index 0000000..4593638 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/ScreenOpenEvent.java @@ -0,0 +1,17 @@ +package cc.polyfrost.oneconfig.events.event; + +import net.minecraft.client.gui.GuiScreen; +import org.jetbrains.annotations.Nullable; + +/** + * Called when a screen is opened or closed. + * If the screen is closed, {@link ScreenOpenEvent#screen} will be null. + */ +public class ScreenOpenEvent extends CancellableEvent { + @Nullable + public final GuiScreen screen; + + public ScreenOpenEvent(@Nullable GuiScreen screen) { + this.screen = screen; + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/events/event/SendPacketEvent.java b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/SendPacketEvent.java new file mode 100644 index 0000000..3cee784 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/SendPacketEvent.java @@ -0,0 +1,11 @@ +package cc.polyfrost.oneconfig.events.event; + +import net.minecraft.network.Packet; + +public class SendPacketEvent extends CancellableEvent { + public final Packet<?> packet; + + public SendPacketEvent(Packet<?> packet) { + this.packet = packet; + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/events/event/TimerUpdateEvent.java b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/TimerUpdateEvent.java new file mode 100644 index 0000000..a8b88dc --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/events/event/TimerUpdateEvent.java @@ -0,0 +1,24 @@ +package cc.polyfrost.oneconfig.events.event; + +import net.minecraft.util.Timer; + +/** + * Called when the {@link Timer} is updated. + * Can be used as an alternative to getting instances of {@link Timer} + * via Mixin or Access Wideners / Transformers + */ +public class TimerUpdateEvent { + /** + * Whether the deltaTicks / renderPartialTicks was updated + */ + public final boolean updatedDeltaTicks; + /** + * The {@link Timer} instance + */ + public final Timer timer; + + public TimerUpdateEvent(Timer timer, boolean updatedDeltaTicks) { + this.timer = timer; + this.updatedDeltaTicks = updatedDeltaTicks; + } +}
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/OneConfig.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/OneConfig.java new file mode 100644 index 0000000..7ecfe98 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/OneConfig.java @@ -0,0 +1,93 @@ +package cc.polyfrost.oneconfig.internal; + +import cc.polyfrost.oneconfig.events.EventManager; +import cc.polyfrost.oneconfig.events.event.ShutdownEvent; +import cc.polyfrost.oneconfig.internal.command.OneConfigCommand; +import cc.polyfrost.oneconfig.internal.config.OneConfigConfig; +import cc.polyfrost.oneconfig.internal.config.Preferences; +import cc.polyfrost.oneconfig.internal.config.core.ConfigCore; +import cc.polyfrost.oneconfig.internal.config.core.KeyBindHandler; +import cc.polyfrost.oneconfig.internal.gui.BlurHandler; +import cc.polyfrost.oneconfig.internal.hud.HudCore; +import cc.polyfrost.oneconfig.libs.eventbus.Subscribe; +import cc.polyfrost.oneconfig.utils.commands.CommandManager; +import cc.polyfrost.oneconfig.utils.gui.GuiUtils; +import cc.polyfrost.oneconfig.utils.hypixel.HypixelUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.util.ServiceLoader; + +/** + * The main class of OneConfig. + */ +@net.minecraftforge.fml.common.Mod(modid = "@ID@", name = "@NAME@", version = "@VER@") +public class OneConfig { + + public OneConfig() { + EventManager.INSTANCE.register(this); + } + + public static final File oneConfigDir = new File("./OneConfig"); + public static final Logger LOGGER = LogManager.getLogger("@NAME@"); + private static boolean preLaunched = false; + private static boolean initialized = false; + private static boolean isObfuscated = true; + + /** + * Called before mods are loaded. + * <p><b>SHOULD NOT BE CALLED!</b></p> + */ + public static void preLaunch() { + if (preLaunched) return; + try { + Class.forName("net.minecraft.world.World"); + LOGGER.warn("OneConfig is NOT obfuscated!"); + isObfuscated = false; + } catch (Exception ignored) { + } + oneConfigDir.mkdirs(); + new File(oneConfigDir, "profiles").mkdirs(); + if (OneConfigConfig.getInstance() == null) { + OneConfigConfig.getInstance(); + } + if (Preferences.getInstance() == null) { + Preferences.getInstance(); + } + preLaunched = true; + } + + /** + * Called after mods are loaded. + * <p><b>SHOULD NOT BE CALLED!</b></p> + */ + @SuppressWarnings("ResultOfMethodCallIgnored") + public static void init() { + if (initialized) return; + GuiUtils.getDeltaTime(); // called to make sure static initializer is called + try { + EventManager.INSTANCE.register(BlurHandler.INSTANCE); + } catch (Exception e) { + e.printStackTrace(); + } + CommandManager.INSTANCE.registerCommand(OneConfigCommand.class); + EventManager.INSTANCE.register(new HudCore()); + HypixelUtils.INSTANCE.initialize(); + EventManager.INSTANCE.register(KeyBindHandler.INSTANCE); + ConfigCore.sortMods(); + + initialized = true; + } + + /** Returns weather this is an obfuscated environment, using a check for obfuscated name of net.minecraft.world.World.class. + * @return true if this is an obfuscated environment, which is normal for Minecraft or false if not. */ + public static boolean isObfuscated() { + return isObfuscated; + } + + @Subscribe + private void onShutdown(ShutdownEvent event) { + ConfigCore.saveAll(); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/gui/impl/BlurHandlerImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/gui/impl/BlurHandlerImpl.java new file mode 100644 index 0000000..0ef5f2b --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/gui/impl/BlurHandlerImpl.java @@ -0,0 +1,132 @@ +package cc.polyfrost.oneconfig.internal.gui.impl; + +import cc.polyfrost.oneconfig.events.event.RenderEvent; +import cc.polyfrost.oneconfig.events.event.ScreenOpenEvent; +import cc.polyfrost.oneconfig.events.event.Stage; +import cc.polyfrost.oneconfig.gui.OneConfigGui; +import cc.polyfrost.oneconfig.internal.config.Preferences; +import cc.polyfrost.oneconfig.internal.gui.BlurHandler; +import cc.polyfrost.oneconfig.internal.mixin.ShaderGroupAccessor; +import cc.polyfrost.oneconfig.libs.eventbus.Subscribe; +import cc.polyfrost.oneconfig.libs.universal.UMinecraft; +import cc.polyfrost.oneconfig.libs.universal.UScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.shader.Shader; +import net.minecraft.client.shader.ShaderUniform; +import net.minecraft.util.ResourceLocation; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +/** + * An implementation of the BlurMC mod by tterrag1098. + * <p> + * For the original source see <a href="https://github.com/tterrag1098/Blur/blob/1.8.9/src/main/java/com/tterrag/blur/Blur.java">...</a> + * For the public license, see <a href="https://github.com/tterrag1098/Blur/blob/1.8.9/LICENSE">...</a> + * <p> + * License available under <a href="https://github.com/boomboompower/ToggleChat/blob/master/src/main/resources/licenses/BlurMC-License.txt">...</a> + * + * @author tterrag1098, boomboompower + * <p> + * Taken from ToggleChat + * <a href="https://github.com/boomboompower/ToggleChat/blob/master/LICENSE">...</a> + */ +public class BlurHandlerImpl implements BlurHandler { + private final ResourceLocation blurShader = new ResourceLocation("shaders/post/fade_in_blur.json"); + private final Logger logger = LogManager.getLogger("OneConfig - Blur"); + private long start; + private float progress = 0; + + @Subscribe + private void onGuiChange(ScreenOpenEvent event) { + reloadBlur(event.screen); + } + + @Subscribe + private void onRenderTick(RenderEvent event) { + if (event.stage != Stage.END) { + return; + } + + // Only blur on our own menus + if (UScreen.getCurrentScreen() == null) { + return; + } + + // Only update the shader if one is active + if (!UMinecraft.getMinecraft().entityRenderer.isShaderActive()) { + return; + } + if (progress >= 5) return; + progress = getBlurStrengthProgress(); + + // This is hilariously bad, and could cause frame issues on low-end computers. + // Why is this being computed every tick? Surely there is a better way? + // This needs to be optimized. + try { + final List<Shader> listShaders = ((ShaderGroupAccessor) Minecraft.getMinecraft().entityRenderer.getShaderGroup()).getListShaders(); + + // Should not happen. Something bad happened. + if (listShaders == null) { + return; + } + + // Iterate through the list of shaders. + for (Shader shader : listShaders) { + ShaderUniform su = shader.getShaderManager().getShaderUniform("Progress"); + + if (su == null) { + continue; + } + + // All this for this. + su.set(progress); + } + } catch (IllegalArgumentException ex) { + this.logger.error("An error.png occurred while updating OneConfig's blur. Please report this!", ex); + } + } + + /** + * Activates/deactivates the blur in the current world if + * one of many conditions are met, such as no current other shader + * is being used, we actually have the blur setting enabled + */ + public void reloadBlur(Object gui) { + // Don't do anything if no world is loaded + if (UMinecraft.getWorld() == null) { + return; + } + + // If a shader is not already active and the UI is + // a one of ours, we should load our own blur! + + if (!UMinecraft.getMinecraft().entityRenderer.isShaderActive() && gui instanceof OneConfigGui && Preferences.enableBlur) { + UMinecraft.getMinecraft().entityRenderer.loadShader(this.blurShader); + + this.start = System.currentTimeMillis(); + this.progress = 0; + + // If a shader is active and the incoming UI is null or we have blur disabled, stop using the shader. + } else if (UMinecraft.getMinecraft().entityRenderer.isShaderActive() && (gui == null || !Preferences.enableBlur)) { + String name = UMinecraft.getMinecraft().entityRenderer.getShaderGroup().getShaderGroupName(); + + // Only stop our specific blur ;) + if (!name.endsWith("fade_in_blur.json")) { + return; + } + + UMinecraft.getMinecraft().entityRenderer.stopUseShader(); + } + } + + /** + * Returns the strength of the blur as determined by the duration the effect of the blur. + * <p> + * The strength of the blur does not go below 5.0F. + */ + private float getBlurStrengthProgress() { + return Math.min((System.currentTimeMillis() - this.start) / 50F, 5.0F); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/GuiIngameForgeMixin.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/GuiIngameForgeMixin.java new file mode 100644 index 0000000..2a89972 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/GuiIngameForgeMixin.java @@ -0,0 +1,19 @@ +//#if MC==10809 +package cc.polyfrost.oneconfig.internal.mixin; + +import cc.polyfrost.oneconfig.events.EventManager; +import cc.polyfrost.oneconfig.events.event.HudRenderEvent; +import net.minecraftforge.client.GuiIngameForge; +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(value = GuiIngameForge.class, remap = false) +public class GuiIngameForgeMixin { + @Inject(method = "renderGameOverlay", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/client/GuiIngameForge;post(Lnet/minecraftforge/client/event/RenderGameOverlayEvent$ElementType;)V", shift = At.Shift.AFTER, remap = false), remap = true) + private void onRenderGameOverlay(float partialTicks, CallbackInfo ci) { + EventManager.INSTANCE.post(new HudRenderEvent(partialTicks)); + } +} +//#endif
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/MinecraftMixin.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/MinecraftMixin.java new file mode 100644 index 0000000..0603d12 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/MinecraftMixin.java @@ -0,0 +1,100 @@ +//#if MC==10809 +package cc.polyfrost.oneconfig.internal.mixin; + +import cc.polyfrost.oneconfig.internal.OneConfig; +import cc.polyfrost.oneconfig.events.EventManager; +import cc.polyfrost.oneconfig.events.event.*; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Timer; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.fml.common.eventhandler.Event; +import org.objectweb.asm.Opcodes; +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.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Shadow + private Timer timer; + + @Inject(method = "shutdownMinecraftApplet", at = @At("HEAD")) + private void onShutdown(CallbackInfo ci) { + EventManager.INSTANCE.post(new PreShutdownEvent()); + } + + @Inject(method = "startGame", at = @At("HEAD")) + private void onStart(CallbackInfo ci) { + EventManager.INSTANCE.post(new StartEvent()); + Runtime.getRuntime().addShutdownHook(new Thread(() -> EventManager.INSTANCE.post(new ShutdownEvent()))); + } + + @Inject(method = "startGame", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/client/FMLClientHandler;beginMinecraftLoading(Lnet/minecraft/client/Minecraft;Ljava/util/List;Lnet/minecraft/client/resources/IReloadableResourceManager;)V", remap = false), remap = true) + private void onPreLaunch(CallbackInfo ci) { + OneConfig.preLaunch(); + } + + @Inject(method = "startGame", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/client/FMLClientHandler;onInitializationComplete()V", shift = At.Shift.AFTER, remap = false), remap = true) + private void onInit(CallbackInfo ci) { + EventManager.INSTANCE.post(new InitializationEvent()); + OneConfig.init(); + } + + @Inject(method = "runGameLoop", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/common/FMLCommonHandler;onRenderTickStart(F)V", shift = At.Shift.AFTER, remap = false), remap = true) + private void onRenderTickStart(CallbackInfo ci) { + EventManager.INSTANCE.post(new RenderEvent(Stage.START, timer.renderPartialTicks)); + } + + @Inject(method = "runGameLoop", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/common/FMLCommonHandler;onRenderTickEnd(F)V", shift = At.Shift.AFTER, remap = false), remap = true) + private void onRenderTickEnd(CallbackInfo ci) { + EventManager.INSTANCE.post(new RenderEvent(Stage.END, timer.renderPartialTicks)); + } + + @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/common/FMLCommonHandler;onPreClientTick()V", shift = At.Shift.AFTER, remap = false), remap = true) + private void onClientTickStart(CallbackInfo ci) { + EventManager.INSTANCE.post(new TickEvent(Stage.START)); + } + + @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/common/FMLCommonHandler;onPostClientTick()V", shift = At.Shift.AFTER, remap = false), remap = true) + private void onClientTickEnd(CallbackInfo ci) { + EventManager.INSTANCE.post(new TickEvent(Stage.END)); + } + + @ModifyArg(method = "displayGuiScreen", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/common/eventhandler/EventBus;post(Lnet/minecraftforge/fml/common/eventhandler/Event;)Z", remap = false), remap = true) + private Event onGuiOpenEvent(Event a) { + if (a instanceof GuiOpenEvent) { + GuiOpenEvent forgeEvent = (GuiOpenEvent) a; + ScreenOpenEvent event = new ScreenOpenEvent(forgeEvent.gui); + EventManager.INSTANCE.post(event); + if (event.isCancelled) { + forgeEvent.setCanceled(true); + } + return forgeEvent; + } + return a; + } + + @Inject(method = "runGameLoop", at = @At(value = "FIELD", target = "Lnet/minecraft/util/Timer;renderPartialTicks:F", opcode = Opcodes.PUTFIELD, shift = At.Shift.AFTER)) + private void onNonDeltaTickTimerUpdate(CallbackInfo ci) { + EventManager.INSTANCE.post(new TimerUpdateEvent(timer, false)); + } + + @Inject(method = "runGameLoop", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Timer;updateTimer()V", shift = At.Shift.AFTER, ordinal = 1)) + private void onDeltaTickTimerUpdate(CallbackInfo ci) { + EventManager.INSTANCE.post(new TimerUpdateEvent(timer, true)); + } + + @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/common/FMLCommonHandler;fireKeyInput()V")) + private void onKeyEvent(CallbackInfo ci) { + EventManager.INSTANCE.post(new KeyInputEvent()); + } + + @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/common/FMLCommonHandler;fireMouseInput()V")) + private void onMouseEvent(CallbackInfo ci) { + EventManager.INSTANCE.post(new MouseInputEvent()); + } +} +//#endif
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/NetHandlerPlayClientMixin.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/NetHandlerPlayClientMixin.java new file mode 100644 index 0000000..7a446c7 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/NetHandlerPlayClientMixin.java @@ -0,0 +1,38 @@ +//#if MC==10809 +package cc.polyfrost.oneconfig.internal.mixin; + +import cc.polyfrost.oneconfig.events.EventManager; +import cc.polyfrost.oneconfig.events.event.ChatReceiveEvent; +import cc.polyfrost.oneconfig.events.event.SendPacketEvent; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S02PacketChat; +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(value = NetHandlerPlayClient.class, priority = Integer.MAX_VALUE) +public class NetHandlerPlayClientMixin { + + @Inject(method = "addToSendQueue", at = @At("HEAD"), cancellable = true) + private void onSendPacket(Packet<?> p_147297_1_, CallbackInfo ci) { + SendPacketEvent event = new SendPacketEvent(p_147297_1_); + EventManager.INSTANCE.post(event); + if (event.isCancelled) { + ci.cancel(); + } + } + + @Inject(method = "handleChat", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/event/ForgeEventFactory;onClientChat(BLnet/minecraft/util/IChatComponent;)Lnet/minecraft/util/IChatComponent;", remap = false), cancellable = true, remap = true) + private void onClientChat(S02PacketChat packetIn, CallbackInfo ci) { + if (packetIn.getType() == 0) { + ChatReceiveEvent event = new ChatReceiveEvent(packetIn.getChatComponent()); + EventManager.INSTANCE.post(event); + if (event.isCancelled) { + ci.cancel(); + } + } + } +} +//#endif
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/NetworkManagerMixin.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/NetworkManagerMixin.java new file mode 100644 index 0000000..3da0c91 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/NetworkManagerMixin.java @@ -0,0 +1,25 @@ +//#if MC==10809 +package cc.polyfrost.oneconfig.internal.mixin; + +import cc.polyfrost.oneconfig.events.EventManager; +import cc.polyfrost.oneconfig.events.event.ReceivePacketEvent; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +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(value = NetworkManager.class, priority = Integer.MAX_VALUE) +public class NetworkManagerMixin { + @Inject(method = "channelRead0(Lio/netty/channel/ChannelHandlerContext;Lnet/minecraft/network/Packet;)V", at = @At("HEAD"), cancellable = true) + private void onReceivePacket(ChannelHandlerContext p_channelRead0_1_, Packet<?> p_channelRead0_2_, CallbackInfo ci) { + ReceivePacketEvent event = new ReceivePacketEvent(p_channelRead0_2_); + EventManager.INSTANCE.post(event); + if (event.isCancelled) { + ci.cancel(); + } + } +} +//#endif
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/OptifineConfigMixin.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/OptifineConfigMixin.java new file mode 100644 index 0000000..9012091 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/OptifineConfigMixin.java @@ -0,0 +1,23 @@ +//#if MC==10809 +package cc.polyfrost.oneconfig.internal.mixin; + +import cc.polyfrost.oneconfig.internal.plugin.hooks.OptifineConfigHook; +import org.spongepowered.asm.mixin.Dynamic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Pseudo +@Mixin(targets = "Config", remap = false) +public class OptifineConfigMixin { + @Dynamic("OptiFine") + @Inject(method = "isFastRender", at = @At("HEAD"), cancellable = true) + private static void cancelFastRender(CallbackInfoReturnable<Boolean> cir) { + if (OptifineConfigHook.shouldNotApplyFastRender()) { + cir.setReturnValue(false); + } + } +} +//#endif
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/ShaderGroupAccessor.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/ShaderGroupAccessor.java new file mode 100644 index 0000000..588da19 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/ShaderGroupAccessor.java @@ -0,0 +1,16 @@ +//#if MC==10809 +package cc.polyfrost.oneconfig.internal.mixin; + +import net.minecraft.client.shader.Shader; +import net.minecraft.client.shader.ShaderGroup; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(ShaderGroup.class) +public interface ShaderGroupAccessor { + @Accessor("listShaders") + List<Shader> getListShaders(); +} +//#endif
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/VigilantMixin.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/VigilantMixin.java new file mode 100644 index 0000000..6b474ab --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/VigilantMixin.java @@ -0,0 +1,10 @@ +//#if MC==10809 +package cc.polyfrost.oneconfig.internal.mixin; + +import gg.essential.vigilance.Vigilant; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(Vigilant.class) +public class VigilantMixin { +} +//#endif
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/WorldClientMixin.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/WorldClientMixin.java new file mode 100644 index 0000000..05c6920 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/mixin/WorldClientMixin.java @@ -0,0 +1,23 @@ +//#if MC==10809 +package cc.polyfrost.oneconfig.internal.mixin; + +import cc.polyfrost.oneconfig.events.EventManager; +import cc.polyfrost.oneconfig.events.event.WorldLoadEvent; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.profiler.Profiler; +import net.minecraft.world.EnumDifficulty; +import net.minecraft.world.WorldSettings; +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(WorldClient.class) +public class WorldClientMixin { + @Inject(method = "<init>", at = @At("RETURN")) + private void onWorldLoad(NetHandlerPlayClient p_i45063_1_, WorldSettings p_i45063_2_, int p_i45063_3_, EnumDifficulty p_i45063_4_, Profiler p_i45063_5_, CallbackInfo ci) { + EventManager.INSTANCE.post(new WorldLoadEvent()); + } +} +//#endif
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/ClassTransformer.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/ClassTransformer.java new file mode 100644 index 0000000..52256ca --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/ClassTransformer.java @@ -0,0 +1,102 @@ +package cc.polyfrost.oneconfig.internal.plugin.asm; + +import cc.polyfrost.oneconfig.internal.plugin.asm.tweakers.NanoVGGLConfigTransformer; +import cc.polyfrost.oneconfig.internal.plugin.asm.tweakers.VigilantTransformer; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import net.minecraft.launchwrapper.IClassTransformer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Collection; + +/** + * Taken from LWJGLTwoPointFive under The Unlicense + * <a href="https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/">https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/</a> + * <p>also half taken from asmworkspace by asbyth ty</p> + */ +@SuppressWarnings("unused") +public class ClassTransformer implements IClassTransformer { + private static final Logger logger = LogManager.getLogger("OneConfig ASM"); + private final Multimap<String, ITransformer> transformerMap = ArrayListMultimap.create(); + private static final boolean outputBytecode = Boolean.parseBoolean(System.getProperty("debugBytecode", "false")); + + public ClassTransformer() { + registerTransformer(new NanoVGGLConfigTransformer()); + registerTransformer(new VigilantTransformer()); + } + + private void registerTransformer(ITransformer transformer) { + // loop through names of classes + for (String cls : transformer.getClassName()) { + // put the classes into the transformer map + transformerMap.put(cls, transformer); + } + } + + @Override + public byte[] transform(String name, String transformedName, byte[] bytes) { + if (bytes == null) return null; + + Collection<ITransformer> transformers = transformerMap.get(transformedName); + if (transformers.isEmpty()) return bytes; + + ClassReader reader = new ClassReader(bytes); + ClassNode node = new ClassNode(); + reader.accept(node, ClassReader.EXPAND_FRAMES); + + for (ITransformer transformer : transformers) { + transformer.transform(transformedName, node); + } + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + try { + node.accept(cw); + } catch (Throwable t) { + logger.error("Exception when transforming " + transformedName + " : " + t.getClass().getSimpleName()); + t.printStackTrace(); + } + + if (outputBytecode) { + File bytecodeDirectory = new File("bytecode"); + String transformedClassName; + + // anonymous classes + if (transformedName.contains("$")) { + transformedClassName = transformedName.replace('$', '.') + ".class"; + } else { + transformedClassName = transformedName + ".class"; + } + + if (!bytecodeDirectory.exists()) { + bytecodeDirectory.mkdirs(); + } + + File bytecodeOutput = new File(bytecodeDirectory, transformedClassName); + + try { + if (!bytecodeOutput.exists()) { + bytecodeOutput.createNewFile(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + try (FileOutputStream os = new FileOutputStream(bytecodeOutput)) { + // write to the generated class to /run/bytecode/classfile.class + // with the class bytes from transforming + os.write(cw.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return cw.toByteArray(); + } +}
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/ITransformer.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/ITransformer.java new file mode 100644 index 0000000..1bc50d1 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/ITransformer.java @@ -0,0 +1,24 @@ +package cc.polyfrost.oneconfig.internal.plugin.asm; + +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +public interface ITransformer { + String[] getClassName(); + + void transform(String transformedName, ClassNode node); + + default void clearInstructions(MethodNode methodNode) { + methodNode.instructions.clear(); + + // dont waste time clearing local variables if they're empty + if (!methodNode.localVariables.isEmpty()) { + methodNode.localVariables.clear(); + } + + // dont waste time clearing try-catches if they're empty + if (!methodNode.tryCatchBlocks.isEmpty()) { + methodNode.tryCatchBlocks.clear(); + } + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/OneConfigTweaker.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/OneConfigTweaker.java new file mode 100644 index 0000000..d302b9d --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/OneConfigTweaker.java @@ -0,0 +1,117 @@ +package cc.polyfrost.oneconfig.internal.plugin.asm; + +import cc.polyfrost.oneconfig.internal.init.OneConfigInit; +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; +import net.minecraftforge.fml.relauncher.CoreModManager; +import org.spongepowered.asm.launch.MixinBootstrap; +import org.spongepowered.asm.launch.MixinTweaker; +import org.spongepowered.asm.mixin.Mixins; + +import java.io.File; +import java.lang.reflect.Field; +import java.net.URI; +import java.net.URL; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +public class OneConfigTweaker implements ITweaker { + + public OneConfigTweaker() { + for (URL url : Launch.classLoader.getSources()) { + doMagicMixinStuff(url); + } + } + + private void doMagicMixinStuff(URL url) { + try { + URI uri = url.toURI(); + if (Objects.equals(uri.getScheme(), "file")) { + File file = new File(uri); + if (file.exists() && file.isFile()) { + try (JarFile jarFile = new JarFile(file)) { + if (jarFile.getManifest() != null) { + Attributes attributes = jarFile.getManifest().getMainAttributes(); + String tweakerClass = attributes.getValue("TweakClass"); + if (Objects.equals(tweakerClass, "cc.polyfrost.oneconfigwrapper.OneConfigWrapper")) { + CoreModManager.getIgnoredMods().remove(file.getName()); + CoreModManager.getReparseableCoremods().add(file.getName()); + String mixinConfig = attributes.getValue("MixinConfigs"); + if (mixinConfig != null) { + try { + try { + List<String> tweakClasses = (List<String>) Launch.blackboard.get("TweakClasses"); // tweak classes before other mod trolling + if (tweakClasses.contains("org.spongepowered.asm.launch.MixinTweaker")) { // if there's already a mixin tweaker, we'll just load it like "usual" + new MixinTweaker(); // also we might not need to make a new mixin tweawker all the time but im just making sure + } else if (!Launch.blackboard.containsKey("mixin.initialised")) { // if there isnt, we do our own trolling + List<ITweaker> tweaks = (List<ITweaker>) Launch.blackboard.get("Tweaks"); + tweaks.add(new MixinTweaker()); + } + } catch (Exception ignored) { + // if it fails i *think* we can just ignore it + } + MixinBootstrap.getPlatform().addContainer(uri); + } catch (Exception ignored) { + + } + } + } + } + } + } + } + } catch (Exception ignored) { + + } + } + + @Override + public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) { + MixinBootstrap.init(); + boolean captureNext = false; + for (String arg : args) { + if (captureNext) { + Mixins.addConfiguration(arg); + } + captureNext = "--mixin".equals(arg); + } + } + + @Override + public void injectIntoClassLoader(LaunchClassLoader classLoader) { + removeLWJGLException(); + Launch.classLoader.registerTransformer(ClassTransformer.class.getName()); + OneConfigInit.initialize(new String[]{}); + Launch.blackboard.put("oneconfig.init.initialized", true); + Launch.classLoader.addClassLoaderExclusion("cc.polyfrost.oneconfig.internal.plugin.asm."); + } + + /** + * Taken from LWJGLTwoPointFive under The Unlicense + * <a href="https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/">https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/</a> + */ + private void removeLWJGLException() { + try { + Field f_exceptions = LaunchClassLoader.class.getDeclaredField("classLoaderExceptions"); + f_exceptions.setAccessible(true); + Set<String> exceptions = (Set<String>) f_exceptions.get(Launch.classLoader); + exceptions.remove("org.lwjgl."); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public String getLaunchTarget() { + return null; + } + + @Override + public String[] getLaunchArguments() { + return new String[0]; + } +}
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/tweakers/NanoVGGLConfigTransformer.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/tweakers/NanoVGGLConfigTransformer.java new file mode 100644 index 0000000..bbbf4a1 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/tweakers/NanoVGGLConfigTransformer.java @@ -0,0 +1,47 @@ +package cc.polyfrost.oneconfig.internal.plugin.asm.tweakers; + +import cc.polyfrost.oneconfig.internal.plugin.asm.ITransformer; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; + +/** + * Taken from LWJGLTwoPointFive under The Unlicense + * <a href="https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/">https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/</a> + */ +public class NanoVGGLConfigTransformer implements ITransformer { + @Override + public String[] getClassName() { + return new String[]{"org.lwjgl.nanovg.NanoVGGLConfig"}; + } + + @Override + public void transform(String transformedName, ClassNode node) { + for (MethodNode method : node.methods) { + if (method.name.equals("configGL")) { + InsnList list = new InsnList(); + + list.add(new VarInsnNode(Opcodes.LLOAD, 0)); + list.add(new TypeInsnNode(Opcodes.NEW, "cc/polyfrost/oneconfig/internal/plugin/hooks/Lwjgl2FunctionProvider")); + list.add(new InsnNode(Opcodes.DUP)); + list.add(new MethodInsnNode( + Opcodes.INVOKESPECIAL, + "cc/polyfrost/oneconfig/internal/plugin/hooks/Lwjgl2FunctionProvider", + "<init>", + "()V", + false + )); + list.add(new MethodInsnNode( + Opcodes.INVOKESTATIC, + "org/lwjgl/nanovg/NanoVGGLConfig", + "config", + "(JLorg/lwjgl/system/FunctionProvider;)V", + false + )); + list.add(new InsnNode(Opcodes.RETURN)); + + clearInstructions(method); + method.instructions.insert(list); + } + } + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/tweakers/VigilantTransformer.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/tweakers/VigilantTransformer.java new file mode 100644 index 0000000..8dd60cf --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/asm/tweakers/VigilantTransformer.java @@ -0,0 +1,89 @@ +package cc.polyfrost.oneconfig.internal.plugin.asm.tweakers; + +import cc.polyfrost.oneconfig.internal.plugin.asm.ITransformer; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.*; + +import java.io.File; + +public class VigilantTransformer implements ITransformer { + + @Override + public String[] getClassName() { + return new String[]{"gg.essential.vigilance.Vigilant"}; + } + + /** + * If anything here is changed, edit the corresponding method in OneConfigMixinPlugin! + */ + @Override + public void transform(String transformedName, ClassNode node) { + if (!node.interfaces.contains("cc/polyfrost/oneconfig/config/compatibility/vigilance/VigilantAccessor")) { + node.fields.add(new FieldNode(Opcodes.ACC_PUBLIC, "oneconfig$config", "Lcc/polyfrost/oneconfig/config/compatibility/vigilance/VigilanceConfig;", null, null)); + node.fields.add(new FieldNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "oneconfig$file", Type.getDescriptor(File.class), null, null)); + + node.interfaces.add("cc/polyfrost/oneconfig/config/compatibility/vigilance/VigilantAccessor"); + MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, "getPropertyCollector", "()Lgg/essential/vigilance/data/PropertyCollector;", null, null); + LabelNode labelNode = new LabelNode(); + methodNode.instructions.add(labelNode); + methodNode.instructions.add(new LineNumberNode(421421, labelNode)); + methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, "gg/essential/vigilance/Vigilant", "propertyCollector", "Lgg/essential/vigilance/data/PropertyCollector;")); + methodNode.instructions.add(new InsnNode(Opcodes.ARETURN)); + node.methods.add(methodNode); + + MethodNode methodNode2 = new MethodNode(Opcodes.ACC_PUBLIC, "handleOneConfigDependency", "(Lgg/essential/vigilance/data/PropertyData;Lgg/essential/vigilance/data/PropertyData;)V", null, null); + LabelNode labelNode2 = new LabelNode(); + LabelNode labelNode3 = new LabelNode(); + LabelNode labelNode4 = new LabelNode(); + methodNode2.instructions.add(labelNode2); + methodNode2.instructions.add(new LineNumberNode(15636436, labelNode2)); + methodNode2.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode2.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, "gg/essential/vigilance/Vigilant", "oneconfig$config", "Lcc/polyfrost/oneconfig/config/compatibility/vigilance/VigilanceConfig;")); + + methodNode2.instructions.add(new JumpInsnNode(Opcodes.IFNULL, labelNode4)); + + methodNode2.instructions.add(labelNode3); + methodNode2.instructions.add(new LineNumberNode(15636437, labelNode3)); + methodNode2.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode2.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, "gg/essential/vigilance/Vigilant", "oneconfig$config", "Lcc/polyfrost/oneconfig/config/compatibility/vigilance/VigilanceConfig;")); + methodNode2.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); + methodNode2.instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); + methodNode2.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "cc/polyfrost/oneconfig/config/compatibility/vigilance/VigilanceConfig", "addDependency", "(Lgg/essential/vigilance/data/PropertyData;Lgg/essential/vigilance/data/PropertyData;)V", false)); + + methodNode2.instructions.add(labelNode4); + methodNode2.instructions.add(new LineNumberNode(15636438, labelNode4)); + methodNode2.instructions.add(new InsnNode(Opcodes.RETURN)); + node.methods.add(methodNode2); + + for (MethodNode method : node.methods) { + if (method.name.equals("initialize")) { + InsnList list = new InsnList(); + list.add(new VarInsnNode(Opcodes.ALOAD, 0)); + list.add(new VarInsnNode(Opcodes.ALOAD, 0)); + list.add(new VarInsnNode(Opcodes.ALOAD, 0)); + list.add(new FieldInsnNode(Opcodes.GETFIELD, "gg/essential/vigilance/Vigilant", "oneconfig$file", Type.getDescriptor(File.class))); + list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "cc/polyfrost/oneconfig/internal/plugin/hooks/VigilantHook", "returnNewConfig", "(Lgg/essential/vigilance/Vigilant;Ljava/io/File;)Lcc/polyfrost/oneconfig/config/compatibility/vigilance/VigilanceConfig;", false)); + list.add(new FieldInsnNode(Opcodes.PUTFIELD, "gg/essential/vigilance/Vigilant", "oneconfig$config", "Lcc/polyfrost/oneconfig/config/compatibility/vigilance/VigilanceConfig;")); + method.instructions.insertBefore(method.instructions.getLast().getPrevious(), list); + } else if (method.name.equals("addDependency") && method.desc.equals("(Lgg/essential/vigilance/data/PropertyData;Lgg/essential/vigilance/data/PropertyData;)V")) { + InsnList list = new InsnList(); + + list.add(new VarInsnNode(Opcodes.ALOAD, 0)); + list.add(new VarInsnNode(Opcodes.ALOAD, 1)); + list.add(new VarInsnNode(Opcodes.ALOAD, 2)); + list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "gg/essential/vigilance/Vigilant", "handleOneConfigDependency", "(Lgg/essential/vigilance/data/PropertyData;Lgg/essential/vigilance/data/PropertyData;)V", false)); + + method.instructions.insertBefore(method.instructions.getLast().getPrevious(), list); + } else if (method.name.equals("<init>") && method.desc.equals("(Ljava/io/File;Ljava/lang/String;Lgg/essential/vigilance/data/PropertyCollector;Lgg/essential/vigilance/data/SortingBehavior;)V")) { + InsnList list = new InsnList(); + list.add(new VarInsnNode(Opcodes.ALOAD, 0)); + list.add(new VarInsnNode(Opcodes.ALOAD, 1)); + list.add(new FieldInsnNode(Opcodes.PUTFIELD, "gg/essential/vigilance/Vigilant", "oneconfig$file", Type.getDescriptor(File.class))); + method.instructions.insertBefore(method.instructions.getLast().getPrevious(), list); + } + } + } + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/Lwjgl2FunctionProvider.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/Lwjgl2FunctionProvider.java new file mode 100644 index 0000000..297c84d --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/Lwjgl2FunctionProvider.java @@ -0,0 +1,47 @@ +package cc.polyfrost.oneconfig.internal.plugin.hooks; + +import org.lwjgl.system.FunctionProvider; + +import java.lang.reflect.Method; +import java.nio.ByteBuffer; + +/** + * Taken from LWJGLTwoPointFive under The Unlicense + * <a href="https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/">https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/</a> + */ +public class Lwjgl2FunctionProvider implements FunctionProvider { + + private static final Class<?> GLContext; + private final Method m_getFunctionAddress; + + static { + try { + GLContext = Class.forName("org.lwjgl.opengl.GLContext"); + } catch (Throwable t) { + throw new RuntimeException("Unable to initialize LWJGL2FunctionProvider", t); + } + } + + public Lwjgl2FunctionProvider() { + try { + m_getFunctionAddress = GLContext.getDeclaredMethod("getFunctionAddress", String.class); + m_getFunctionAddress.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public long getFunctionAddress(CharSequence functionName) { + try { + return (long) m_getFunctionAddress.invoke(null, functionName.toString()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public long getFunctionAddress(ByteBuffer byteBuffer) { + throw new UnsupportedOperationException(); + } +}
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/OptifineConfigHook.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/OptifineConfigHook.java new file mode 100644 index 0000000..dea68cf --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/OptifineConfigHook.java @@ -0,0 +1,22 @@ +package cc.polyfrost.oneconfig.internal.plugin.hooks; + +import cc.polyfrost.oneconfig.gui.OneConfigGui; +import cc.polyfrost.oneconfig.platform.Platform; +import cc.polyfrost.oneconfig.utils.gui.GuiUtils; + +import java.util.Optional; + +public class OptifineConfigHook { + + public static boolean shouldNotApplyFastRender() { + if (Platform.getGuiPlatform().getCurrentScreen() instanceof OneConfigGui) { + return true; + } + for (Optional screen : GuiUtils.getScreenQueue()) { + if (screen.isPresent() && screen.get() instanceof OneConfigGui) { + return true; + } + } + return false; + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/VigilantHook.java b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/VigilantHook.java new file mode 100644 index 0000000..a012773 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/internal/plugin/hooks/VigilantHook.java @@ -0,0 +1,26 @@ +package cc.polyfrost.oneconfig.internal.plugin.hooks; + +import cc.polyfrost.oneconfig.config.compatibility.vigilance.VigilanceConfig; +import cc.polyfrost.oneconfig.config.data.Mod; +import cc.polyfrost.oneconfig.config.data.ModType; +import cc.polyfrost.oneconfig.internal.config.core.ConfigCore; +import cc.polyfrost.oneconfig.platform.Platform; +import gg.essential.vigilance.Vigilant; + +import java.io.File; + +@SuppressWarnings("unused") +public class VigilantHook { + public static VigilanceConfig returnNewConfig(Vigilant vigilant, File file) { + if (vigilant != null && Platform.getInstance().isCallingFromMinecraftThread()) { + String name = !vigilant.getGuiTitle().equals("Settings") ? vigilant.getGuiTitle() : !Platform.getLoaderPlatform().hasActiveModContainer() ? "Unknown" : Platform.getLoaderPlatform().getActiveModContainer().name; + if (name.equals("OneConfig")) name = "Essential"; + String finalName = name; + // duplicate fix + if (ConfigCore.mods.stream().anyMatch(mod -> mod.name.equals(finalName))) return null; + return new VigilanceConfig(new Mod(name, ModType.THIRD_PARTY), file.getAbsolutePath(), vigilant); + } else { + return null; + } + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/GLPlatformImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/GLPlatformImpl.java new file mode 100644 index 0000000..3ee962b --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/GLPlatformImpl.java @@ -0,0 +1,67 @@ +package cc.polyfrost.oneconfig.platform.impl; + +import cc.polyfrost.oneconfig.libs.universal.UMatrixStack; +import cc.polyfrost.oneconfig.libs.universal.UMinecraft; +import cc.polyfrost.oneconfig.platform.GLPlatform; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.shader.Framebuffer; + +@SuppressWarnings("unused") +public class GLPlatformImpl implements GLPlatform { + + @Override + public void drawRect(float x, float y, float x2, float y2, int color) { + if (x < x2) { + float i = x; + x = x2; + x2 = i; + } + + if (y < y2) { + float i = y; + y = y2; + y2 = i; + } + + float f = (float)(color >> 24 & 0xFF) / 255.0F; + float g = (float)(color >> 16 & 0xFF) / 255.0F; + float h = (float)(color >> 8 & 0xFF) / 255.0F; + float j = (float)(color & 0xFF) / 255.0F; + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldRenderer = tessellator.getWorldRenderer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.color(g, h, j, f); + worldRenderer.begin(7, DefaultVertexFormats.POSITION); + worldRenderer.pos(x, y2, 0.0).endVertex(); + worldRenderer.pos(x2, y2, 0.0).endVertex(); + worldRenderer.pos(x2, y, 0.0).endVertex(); + worldRenderer.pos(x, y, 0.0).endVertex(); + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } + + @Override + public void enableStencil() { + Framebuffer framebuffer = Minecraft.getMinecraft().getFramebuffer(); + if (!framebuffer.isStencilEnabled()) { + framebuffer.enableStencil(); + } + } + + @Override + public float drawText(UMatrixStack matrixStack, String text, float x, float y, int color, boolean shadow) { + return UMinecraft.getFontRenderer().drawString(text, x, y, color, shadow); + } + + @Override + public int getStringWidth(String text) { + return UMinecraft.getFontRenderer().getStringWidth(text); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/GuiPlatformImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/GuiPlatformImpl.java new file mode 100644 index 0000000..6ea3c03 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/GuiPlatformImpl.java @@ -0,0 +1,31 @@ +package cc.polyfrost.oneconfig.platform.impl; + +import cc.polyfrost.oneconfig.libs.universal.UMinecraft; +import cc.polyfrost.oneconfig.libs.universal.UScreen; +import cc.polyfrost.oneconfig.platform.GuiPlatform; +import net.minecraft.client.gui.GuiChat; +import net.minecraft.client.gui.GuiScreen; + +@SuppressWarnings("unused") +public class GuiPlatformImpl implements GuiPlatform { + + @Override + public Object getCurrentScreen() { + return UScreen.getCurrentScreen(); + } + + @Override + public void setCurrentScreen(Object screen) { + UScreen.displayScreen((GuiScreen) screen); + } + + @Override + public boolean isInChat() { + return getCurrentScreen() instanceof GuiChat; + } + + @Override + public boolean isInDebug() { + return UMinecraft.getSettings().showDebugInfo; + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/I18nPlatformImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/I18nPlatformImpl.java new file mode 100644 index 0000000..1913238 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/I18nPlatformImpl.java @@ -0,0 +1,13 @@ +package cc.polyfrost.oneconfig.platform.impl; + +import cc.polyfrost.oneconfig.platform.I18nPlatform; +import net.minecraft.client.resources.I18n; + +@SuppressWarnings("unused") +public class I18nPlatformImpl implements I18nPlatform { + + @Override + public String format(String key, Object... args) { + return I18n.format(key, args); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/LoaderPlatformImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/LoaderPlatformImpl.java new file mode 100644 index 0000000..01269cd --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/LoaderPlatformImpl.java @@ -0,0 +1,26 @@ +package cc.polyfrost.oneconfig.platform.impl; + +import cc.polyfrost.oneconfig.platform.LoaderPlatform; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; + +@SuppressWarnings("unused") +public class LoaderPlatformImpl implements LoaderPlatform { + @Override + public boolean isModLoaded(String id) { + return Loader.isModLoaded(id); + } + + @Override + public boolean hasActiveModContainer() { + return Loader.instance().activeModContainer() != null; + } + + @Override + public ActiveMod getActiveModContainer() { + ModContainer container = Loader.instance().activeModContainer(); + if (container == null) + return null; + return new ActiveMod(container.getName(), container.getModId(), container.getVersion()); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/MousePlatformImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/MousePlatformImpl.java new file mode 100644 index 0000000..1276000 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/MousePlatformImpl.java @@ -0,0 +1,53 @@ +package cc.polyfrost.oneconfig.platform.impl; + +import cc.polyfrost.oneconfig.platform.MousePlatform; +import org.lwjgl.input.Mouse; + +@SuppressWarnings("unused") +public class MousePlatformImpl implements MousePlatform { + + @Override + public int getMouseX() { + return Mouse.getX(); + } + + @Override + public int getMouseY() { + return Mouse.getY(); + } + + @Override + public int getDWheel() { + return Mouse.getDWheel(); + } + + @Override + public int getMouseDX() { + return Mouse.getDX(); + } + + @Override + public int getMouseDY() { + return Mouse.getDY(); + } + + @Override + public boolean next() { + return Mouse.next(); + } + + @Override + public boolean getEventButtonState() { + return Mouse.getEventButtonState(); + } + + @Override + public int getEventButton() { + return Mouse.getEventButton(); + } + + @Override + public boolean isButtonDown(int button) { + return Mouse.isButtonDown(button); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/PlatformImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/PlatformImpl.java new file mode 100644 index 0000000..7ad639c --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/PlatformImpl.java @@ -0,0 +1,12 @@ +package cc.polyfrost.oneconfig.platform.impl; + +import cc.polyfrost.oneconfig.platform.Platform; +import net.minecraft.client.Minecraft; + +@SuppressWarnings("unused") +public class PlatformImpl implements Platform { + @Override + public boolean isCallingFromMinecraftThread() { + return Minecraft.getMinecraft().isCallingFromMinecraftThread(); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/ServerPlatformImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/ServerPlatformImpl.java new file mode 100644 index 0000000..81454b0 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/platform/impl/ServerPlatformImpl.java @@ -0,0 +1,22 @@ +package cc.polyfrost.oneconfig.platform.impl; + +import cc.polyfrost.oneconfig.libs.universal.UMinecraft; +import cc.polyfrost.oneconfig.platform.ServerPlatform; +import net.minecraft.client.entity.EntityPlayerSP; + +@SuppressWarnings("unused") +public class ServerPlatformImpl implements ServerPlatform { + + @Override + public boolean inMultiplayer() { + return UMinecraft.getWorld() != null && !UMinecraft.getMinecraft().isSingleplayer(); + } + + @Override + public String getServerBrand() { + EntityPlayerSP player = UMinecraft.getPlayer(); + if (player == null) + return null; + return player.getClientBrand(); + } +} diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/utils/commands/PlatformCommandManagerImpl.java b/versions/src/main/java/cc/polyfrost/oneconfig/utils/commands/PlatformCommandManagerImpl.java new file mode 100644 index 0000000..8b6edcc --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/utils/commands/PlatformCommandManagerImpl.java @@ -0,0 +1,330 @@ +package cc.polyfrost.oneconfig.utils.commands; + +import cc.polyfrost.oneconfig.libs.universal.ChatColor; +import cc.polyfrost.oneconfig.libs.universal.UChat; +import cc.polyfrost.oneconfig.utils.commands.annotations.Command; +import cc.polyfrost.oneconfig.utils.commands.annotations.Greedy; +import cc.polyfrost.oneconfig.utils.commands.annotations.Name; +import cc.polyfrost.oneconfig.utils.commands.annotations.SubCommand; +import cc.polyfrost.oneconfig.utils.commands.arguments.ArgumentParser; +import cc.polyfrost.oneconfig.utils.commands.arguments.Arguments; +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.BlockPos; +import net.minecraftforge.client.ClientCommandHandler; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.ImmutableTriple; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.tuple.Triple; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Parameter; +import java.util.*; + +import static cc.polyfrost.oneconfig.utils.commands.CommandManager.*; + +public class PlatformCommandManagerImpl implements PlatformCommandManager { + + @Override + public void createCommand(CommandManager.InternalCommand root, Command annotation) { + ClientCommandHandler.instance.registerCommand(new CommandBase() { + @Override + public String getCommandName() { + return annotation.value(); + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return "/" + annotation.value(); + } + + @Override + public void processCommand(ICommandSender sender, String[] args) { + handleCommand(root, annotation, args); + } + + @Override + public int getRequiredPermissionLevel() { + return -1; + } + + @Override + public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) { + return handleTabCompletion(root, annotation, args); + } + }); + } + + private void handleCommand(CommandManager.InternalCommand root, Command annotation, String[] args) { + if (args.length == 0) { + if (!root.invokers.isEmpty()) { + try { + root.invokers.get(0).method.invoke(null); + } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException | + ExceptionInInitializerError e) { + e.printStackTrace(); + UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR); + } + } + } else { + if (annotation.helpCommand() && args[0].equalsIgnoreCase("help")) { + UChat.chat(sendHelpCommand(root)); + } else { + List<CommandManager.InternalCommand.InternalCommandInvoker> commands = new ArrayList<>(); + int depth = 0; + for (CommandManager.InternalCommand command : root.children) { + int newDepth = loopThroughCommands(commands, 0, command, args); + if (newDepth != -1) { + depth = newDepth; + break; + } + } + if (commands.isEmpty()) { + if (depth == -2) { + UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + TOO_MANY_PARAMETERS.replace("@ROOT_COMMAND@", annotation.value())); + } else { + UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + NOT_FOUND_TEXT.replace("@ROOT_COMMAND@", annotation.value())); + } + } else { + List<CommandManager.CustomError> errors = new ArrayList<>(); + for (CommandManager.InternalCommand.InternalCommandInvoker invoker : commands) { + try { + List<Object> params = getParametersForInvoker(invoker, depth, args); + if (params.size() == 1) { + Object first = params.get(0); + if (first instanceof CommandManager.CustomError) { + errors.add((CommandManager.CustomError) first); + continue; + } + } + invoker.method.invoke(null, params.toArray()); + return; + } catch (Exception e) { + e.printStackTrace(); + UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR); + return; + } + } + //noinspection ConstantConditions + if (!errors.isEmpty()) { + UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + "Multiple errors occurred:"); + for (CommandManager.CustomError error : errors) { + UChat.chat(" " + ChatColor.RED + ChatColor.BOLD + error.message); + } + } + } + } + } + } + + private List<String> handleTabCompletion(CommandManager.InternalCommand root, Command annotation, String[] args) { + try { + Set<Pair<CommandManager.InternalCommand.InternalCommandInvoker, Integer>> commands = new HashSet<>(); + for (CommandManager.InternalCommand command : root.children) { + loopThroughCommandsTab(commands, 0, command, args); + } + if (!commands.isEmpty() || annotation.helpCommand()) { + List<Triple<CommandManager.InternalCommand.InternalCommandInvoker, Integer, Integer>> validCommands = new ArrayList<>(); // command, depth, and all processed params + for (Pair<CommandManager.InternalCommand.InternalCommandInvoker, Integer> pair : commands) { + CommandManager.InternalCommand.InternalCommandInvoker invoker = pair.getLeft(); + int depth = pair.getRight(); + int currentParam = 0; + boolean failed = false; + while (args.length - depth > 1) { + Parameter param = invoker.method.getParameters()[currentParam]; + if (param.isAnnotationPresent(Greedy.class) && currentParam + 1 != invoker.parameterTypes.length) { + failed = true; + break; + } + ArgumentParser<?> parser = INSTANCE.parsers.get(param.getType()); + if (parser == null) { + failed = true; + break; + } + try { + Arguments arguments = new Arguments(Arrays.copyOfRange(args, depth, args.length), param.isAnnotationPresent(Greedy.class)); + if (parser.parse(arguments) != null) { + depth += arguments.getPosition(); + currentParam++; + } else { + failed = true; + break; + } + } catch (Exception e) { + failed = true; + break; + } + } + if (!failed) { + validCommands.add(new ImmutableTriple<>(pair.getLeft(), depth, currentParam)); + } + } + if (!validCommands.isEmpty() || annotation.helpCommand()) { + Set<String> completions = new HashSet<>(); + for (Triple<CommandManager.InternalCommand.InternalCommandInvoker, Integer, Integer> valid : validCommands) { + if (valid.getMiddle() == args.length) { + completions.add(valid.getLeft().name); + completions.addAll(Arrays.asList(valid.getLeft().aliases)); + continue; + } + if (valid.getRight() + 1 > valid.getLeft().parameterTypes.length) continue; + Parameter param = valid.getLeft().method.getParameters()[valid.getRight()]; + if (param.isAnnotationPresent(Greedy.class) && valid.getRight() + 1 != valid.getLeft().parameterTypes.length) { + continue; + } + ArgumentParser<?> parser = INSTANCE.parsers.get(param.getType()); + if (parser == null) { + continue; + } + try { + Arguments arguments = new Arguments(Arrays.copyOfRange(args, valid.getMiddle(), args.length), param.isAnnotationPresent(Greedy.class)); + List<String> possibleCompletions = parser.complete(arguments, param); + if (possibleCompletions != null) { + completions.addAll(possibleCompletions); + } + } catch (Exception ignored) { + + } + } + if (args.length == 1 && annotation.helpCommand()) { + if ("help".startsWith(args[0].toLowerCase(Locale.ENGLISH))) { + completions.add("help"); + } + } + return new ArrayList<>(completions); + } + } + } catch (Exception ignored) { + + } + return null; + } + + private List<Object> getParametersForInvoker(CommandManager.InternalCommand.InternalCommandInvoker invoker, int depth, String[] args) { + List<Object> parameters = new ArrayList<>(); + int processed = depth; + int currentParam = 0; + while (processed < args.length) { + Parameter param = invoker.method.getParameters()[currentParam]; + if (param.isAnnotationPresent(Greedy.class) && currentParam + 1 != invoker.parameterTypes.length) { + return Collections.singletonList(new CommandManager.CustomError("Parsing failed: Greedy parameter must be the last one.")); + } + ArgumentParser<?> parser = INSTANCE.parsers.get(param.getType()); + if (parser == null) { + return Collections.singletonList(new CommandManager.CustomError("No parser for " + invoker.method.getParameterTypes()[currentParam].getSimpleName() + "! Please report this to the mod author.")); + } + try { + Arguments arguments = new Arguments(Arrays.copyOfRange(args, processed, args.length), param.isAnnotationPresent(Greedy.class)); + try { + Object a = parser.parse(arguments); + if (a != null) { + parameters.add(a); + processed += arguments.getPosition(); + currentParam++; + } else { + return Collections.singletonList(new CommandManager.CustomError("Failed to parse " + param.getType().getSimpleName() + "! Please report this to the mod author.")); + } + } catch (Exception e) { + return Collections.singletonList(new CommandManager.CustomError("A " + e.getClass().getSimpleName() + " has occured while try to parse " + param.getType().getSimpleName() + "! Please report this to the mod author.")); + } + } catch (Exception e) { + return Collections.singletonList(new CommandManager.CustomError("A " + e.getClass().getSimpleName() + " has occured while try to parse " + param.getType().getSimpleName() + "! Please report this to the mod author.")); + } + } + return parameters; + } + + private int loopThroughCommands(List<CommandManager.InternalCommand.InternalCommandInvoker> commands, int depth, CommandManager.InternalCommand command, String[] args) { + int nextDepth = depth + 1; + boolean thatOneSpecialError = false; + if (command.isValid(args[depth], false)) { + for (CommandManager.InternalCommand child : command.children) { + if (args.length > nextDepth && child.isValid(args[nextDepth], false)) { + int result = loopThroughCommands(commands, nextDepth, child, args); + if (result > -1) { + return result; + } else if (result == -2) { + thatOneSpecialError = true; + } + } + } + boolean added = false; + for (CommandManager.InternalCommand.InternalCommandInvoker invoker : command.invokers) { + if (args.length - nextDepth == invoker.parameterTypes.length) { + commands.add(invoker); + added = true; + } else { + thatOneSpecialError = true; + } + } + if (added) { + return nextDepth; + } + } + return thatOneSpecialError ? -2 : -1; + } + + private void loopThroughCommandsTab(Set<Pair<CommandManager.InternalCommand.InternalCommandInvoker, Integer>> commands, int depth, CommandManager.InternalCommand command, String[] args) { + int nextDepth = depth + 1; + if (command.isValid(args[depth], args.length == nextDepth)) { + if (args.length != nextDepth) { + for (CommandManager.InternalCommand child : command.children) { + if (child.isValid(args[nextDepth], args.length == nextDepth + 1)) { + loopThroughCommandsTab(commands, nextDepth, child, args); + } + } + } + for (CommandManager.InternalCommand.InternalCommandInvoker invoker : command.invokers) { + commands.add(new ImmutablePair<>(invoker, nextDepth)); + } + } + } + + //TODO: someone make the help command actually look nice lmao + private String sendHelpCommand(CommandManager.InternalCommand root) { + StringBuilder builder = new StringBuilder(); + builder.append(ChatColor.GOLD).append("Help for ").append(ChatColor.BOLD).append(root.name).append(ChatColor.RESET).append(ChatColor.GOLD).append(":\n"); + if (!root.description.isEmpty()) { + builder.append("\n").append(ChatColor.GOLD).append("Description: ").append(ChatColor.BOLD).append(root.description); + } + for (CommandManager.InternalCommand command : root.children) { + runThroughCommandsHelp(root.name, command, builder); + } + builder.append("\n").append(ChatColor.GOLD).append("Aliases: ").append(ChatColor.BOLD); + int index = 0; + for (String alias : root.aliases) { + ++index; + builder.append(alias).append(index < root.aliases.length ? ", " : ""); + } + builder.append("\n"); + return builder.toString(); + } + + private void runThroughCommandsHelp(String append, CommandManager.InternalCommand command, StringBuilder builder) { + if (!command.invokers.isEmpty()) { + Class<?> declaringClass = command.invokers.get(0).method.getDeclaringClass(); + if (declaringClass.isAnnotationPresent(SubCommand.class)) { + String description = declaringClass.getAnnotation(SubCommand.class).description(); + if (!description.isEmpty()) { + builder.append("\n").append(ChatColor.GOLD).append("Description: ").append(ChatColor.BOLD).append(description); + } + } + } + for (CommandManager.InternalCommand.InternalCommandInvoker invoker : command.invokers) { + builder.append("\n").append(ChatColor.GOLD).append("/").append(append).append(" ").append(command.name); + for (Parameter parameter : invoker.method.getParameters()) { + String name = parameter.getName(); + if (parameter.isAnnotationPresent(Name.class)) { + name = parameter.getAnnotation(Name.class).value(); + } + builder.append(" <").append(name).append(">"); + } + if (!command.description.trim().isEmpty()) { + builder.append(": ").append(ChatColor.BOLD).append(command.description); + } + } + for (CommandManager.InternalCommand subCommand : command.children) { + runThroughCommandsHelp(append + " " + command.name, subCommand, builder); + } + } +}
\ No newline at end of file diff --git a/versions/src/main/java/cc/polyfrost/oneconfig/utils/gui/GuiUtils.java b/versions/src/main/java/cc/polyfrost/oneconfig/utils/gui/GuiUtils.java new file mode 100644 index 0000000..6217bb6 --- /dev/null +++ b/versions/src/main/java/cc/polyfrost/oneconfig/utils/gui/GuiUtils.java @@ -0,0 +1,100 @@ +package cc.polyfrost.oneconfig.utils.gui; + +import cc.polyfrost.oneconfig.events.EventManager; +import cc.polyfrost.oneconfig.events.event.RenderEvent; +import cc.polyfrost.oneconfig.events.event.Stage; +import cc.polyfrost.oneconfig.gui.OneConfigGui; +import cc.polyfrost.oneconfig.libs.eventbus.Subscribe; +import cc.polyfrost.oneconfig.libs.universal.UMinecraft; +import cc.polyfrost.oneconfig.libs.universal.UScreen; +import cc.polyfrost.oneconfig.utils.TickDelay; +import net.minecraft.client.gui.GuiScreen; + +import java.util.Deque; +import java.util.Optional; +import java.util.concurrent.ConcurrentLinkedDeque; + +/** + * A class containing utility methods for working with GuiScreens. + */ +public final class GuiUtils { + private static long time = -1L; + private static long deltaTime = 17L; + private static final Deque<Optional<GuiScreen>> screenQueue = new ConcurrentLinkedDeque<>(); + + static { + EventManager.INSTANCE.register(new GuiUtils()); + } + + /** + * Displays a screen after a tick, preventing mouse sync issues. + * + * @param screen the screen to display. + * @deprecated Not actually deprecated, but should not be used. + */ + @Deprecated + public static void displayScreen(Object screen) { + displayScreen(((GuiScreen) screen)); + } + + /** + * Displays a screen after a tick, preventing mouse sync issues. + * + * @param screen the screen to display. + */ + public static void displayScreen(GuiScreen screen) { + //noinspection ConstantConditions + displayScreen(screen, screen instanceof OneConfigGui ? 2 : 1); + } + + /** + * Displays a screen after the specified amount of ticks. + * + * @param screen the screen to display. + * @param ticks the amount of ticks to wait for before displaying the screen. + */ + public static void displayScreen(GuiScreen screen, int ticks) { + Optional<GuiScreen> optional = Optional.of(screen); + screenQueue.add(optional); + new TickDelay(() -> { + UScreen.displayScreen(screen); + screenQueue.remove(optional); + }, ticks); + } + + public static Deque<Optional<GuiScreen>> getScreenQueue() { + return screenQueue; + } + + /** + * Close the current open GUI screen. + */ + public static void closeScreen() { + UScreen.displayScreen(null); + } + + /** + * Gets the delta time (in milliseconds) between frames. + * <p><b> + * Not to be confused with Minecraft deltaTicks / renderPartialTicks, which can be gotten via + * {@link cc.polyfrost.oneconfig.events.event.TimerUpdateEvent} + * </b></p> + * + * @return the delta time. + */ + public static float getDeltaTime() { + return deltaTime; + } + + @Subscribe + private void onRenderEvent(RenderEvent event) { + if (event.stage == Stage.START) { + if (time == -1) time = UMinecraft.getTime(); + else { + long currentTime = UMinecraft.getTime(); + deltaTime = currentTime - time; + time = currentTime; + } + } + } +} |