diff --git a/build.gradle b/build.gradle index 4f9c008..904421d 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,13 @@ repositories { // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. // See https://docs.gradle.org/current/userguide/declaring_repositories.html // for more information about repositories. + mavenCentral() + jcenter() maven { url "https://maven.terraformersmc.com/releases/" } + maven { + name 'Xander Maven' + url 'https://maven.isxander.dev/releases' + } } dependencies { @@ -28,6 +34,8 @@ dependencies { modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + modImplementation "dev.isxander.yacl:yet-another-config-lib-fabric:${project.yacl_version}" + modApi "com.terraformersmc:modmenu:9.0.0" } diff --git a/gradle.properties b/gradle.properties index 27d3423..ba63423 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,4 +13,5 @@ org.gradle.parallel=true archives_base_name = dynamichud # Dependencies - fabric_version=0.91.1+1.20.4 \ No newline at end of file + fabric_version=0.91.1+1.20.4 + yacl_version=3.3.2+1.20.4 \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java index dd81dae..18b14c4 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java +++ b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java @@ -27,7 +27,7 @@ public class DynamicHUD implements ClientModInitializer { public static MinecraftClient MC = MinecraftClient.getInstance(); - private static final Logger logger = LoggerFactory.getLogger("DynamicHud"); + public static final Logger logger = LoggerFactory.getLogger("DynamicHud"); static AbstractMoveableScreen Screen; private static String keybingCategory = "DynamicHud"; private static String TranslationKey = "DynamicHud Editor Screen"; diff --git a/src/main/java/com/tanishisherewith/dynamichud/ModMenuIntegration.java b/src/main/java/com/tanishisherewith/dynamichud/ModMenuIntegration.java index 07cb3aa..c9aec49 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/ModMenuIntegration.java +++ b/src/main/java/com/tanishisherewith/dynamichud/ModMenuIntegration.java @@ -1,11 +1,15 @@ package com.tanishisherewith.dynamichud; +import com.tanishisherewith.dynamichud.newTrial.config.GlobalConfig; import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; +import net.minecraft.client.gui.screen.Screen; + public class ModMenuIntegration implements ModMenuApi { + public static Screen YACL_CONFIG_SCREEN = GlobalConfig.get().createYACLGUI(); @Override public ConfigScreenFactory getModConfigScreenFactory() { - return parent -> DynamicHUD.getScreen(); + return parent -> YACL_CONFIG_SCREEN; } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java index 75ac161..b87dd3e 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java @@ -211,20 +211,20 @@ public static void drawOutlinedBox(DrawContext drawContext, int x1, int y1, int /** * This method assumes that the element is widget in the top-left corner (i.e. all drawing happens with respect to the top-left corner). - * @param matrices * @param x X position of top-left corner of widget * @param y Y position of top-left corner of widget * @param scale Scale the matrices */ - public static void scaleAndPosition(MatrixStack matrices, float x, float y,float z, float scale) { + public static void scaleAndPosition(MatrixStack matrices, float x, float y, float scale) { matrices.push(); // Save the current transformation state - // Translate to the desired position - matrices.translate(x, y, z); + // Translate the origin back to the desired position + matrices.translate(x, y, 0); // Scale the matrix matrices.scale(scale, scale, 1.0F); } + public static void stopScaling(MatrixStack matrices){ matrices.pop(); // Restore the previous transformation state } diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java index 345e818..a3f274a 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java @@ -20,8 +20,6 @@ @Mixin(OptionsScreen.class) public class OptionsScreenMixin extends Screen { private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##"); - private final GameOptions settings = MinecraftClient.getInstance().options; - protected OptionsScreenMixin(Text title) { super(title); diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java index 852887d..d1e4259 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java @@ -3,20 +3,37 @@ import com.tanishisherewith.dynamichud.DynamicHudIntegration; import com.tanishisherewith.dynamichud.newTrial.DynamicHUD; import com.tanishisherewith.dynamichud.newTrial.DynamicHudTest; +import com.tanishisherewith.dynamichud.newTrial.widget.WidgetManager; import com.tanishisherewith.dynamichud.newTrial.widget.WidgetRenderer; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Screen.class) public abstract class ScreenMixin { + @Shadow public int width; + + @Shadow public int height; + @Inject(at = @At("TAIL"), method = "render") private void render(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { for(WidgetRenderer widgetRenderer: DynamicHUD.getWidgetRenderers()){ widgetRenderer.renderWidgets(context); } } + @Inject(at = @At("HEAD"), method = "resize") + private void onScreenResize(MinecraftClient client,int width, int height, CallbackInfo ci) { + WidgetManager.onScreenResized(width,height,this.width,this.height); + } + @Inject(at = @At("TAIL"), method = "close") + private void render(CallbackInfo ci) { + for(WidgetRenderer widgetRenderer: DynamicHUD.getWidgetRenderers()){ + widgetRenderer.onCloseScreen(); + } + } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/DynamicHUD.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/DynamicHUD.java index f2dda44..b73464d 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/newTrial/DynamicHUD.java +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/DynamicHUD.java @@ -2,8 +2,10 @@ import com.tanishisherewith.dynamichud.DynamicHudIntegration; import com.tanishisherewith.dynamichud.huds.AbstractMoveableScreen; +import com.tanishisherewith.dynamichud.newTrial.config.GlobalConfig; import com.tanishisherewith.dynamichud.newTrial.widget.WidgetManager; import com.tanishisherewith.dynamichud.newTrial.widget.WidgetRenderer; +import com.tanishisherewith.dynamichud.newTrial.widgets.TextWidget; import com.tanishisherewith.dynamichud.util.DynamicUtil; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; @@ -12,6 +14,7 @@ import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.ModMetadata; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.option.KeyBinding; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,6 +27,7 @@ public class DynamicHUD implements ClientModInitializer { public static MinecraftClient MC = MinecraftClient.getInstance(); + public static String MOD_ID = "dynamichud"; private static final Logger logger = LoggerFactory.getLogger("DynamicHud"); private static final List widgetRenderers = new ArrayList<>(); @@ -45,31 +49,16 @@ public static void printWarn(String msg) { @Override public void onInitializeClient() { - printInfo("DynamicHud Initialised"); - - //Save and Load - /* ClientTickEvents.START_CLIENT_TICK.register(server -> { - if (iWigdets != null) { - if (!WIDGETS_FILE.exists()) { - if (!dynamicutil.WidgetAdded) { - iWigdets.addWigdets(dynamicutil); - } - if (!dynamicutil.MainMenuWidgetAdded) { - iWigdets.addMainMenuWigdets(dynamicutil); - } - } + printInfo("Initialising DynamicHud"); - if (WIDGETS_FILE.exists() && !dynamicutil.WidgetLoaded) { - iWigdets.loadWigdets(dynamicutil); - printInfo("Widgets loaded"); - File FileDirectory = new File(fileDirectory, filename); - printInfo("Load file Directory: " + FileDirectory); - } - } - DynamicUtil.openDynamicScreen(EditorScreenKeyBinding, Screen); - }); + // Add WidgetData of included widgets + WidgetManager.addWidgetDatas( + TextWidget.DATA + ); + //YACL load + GlobalConfig.HANDLER.load(); - */ + printInfo("Integrating mods..."); FabricLoader.getInstance().getEntrypointContainers("dynamicHud", DynamicHudIntegration.class).forEach(entrypoint -> { ModMetadata metadata = entrypoint.getProvider().getMetadata(); String modId = metadata.getId(); @@ -88,11 +77,14 @@ public void onInitializeClient() { screen = DHIntegration.getMovableScreen(); KeyBinding binding =DHIntegration.EDITOR_SCREEN_KEY_BINDING; + WidgetRenderer widgetRenderer = DHIntegration.getWidgetRenderer(); addWidgetRenderer(widgetRenderer); //Register events for rendering, saving, loading, and opening the hudEditor - ClientTickEvents.START_CLIENT_TICK.register((client)->{ + ClientTickEvents.START_CLIENT_TICK.register((client)-> { + System.out.println("TICK FOR : " + modId); + System.out.println(binding); DynamicUtil.openDynamicScreen(binding, screen); }); @@ -101,6 +93,9 @@ public void onInitializeClient() { ServerLifecycleEvents.END_DATA_PACK_RELOAD.register((server, resourceManager, s) -> saveWidgetsSafely(widgetsFile)); ServerPlayConnectionEvents.DISCONNECT.register((handler, packetSender) -> saveWidgetsSafely(widgetsFile)); Runtime.getRuntime().addShutdownHook(new Thread(() -> saveWidgetsSafely(widgetsFile))); + + + printInfo(String.format("Integration of mod %s was successful",modId)); } catch (Throwable e) { if(e instanceof IOException){ logger.warn("An error has occured while loading widgets of mod {}", modId,e); @@ -109,6 +104,11 @@ public void onInitializeClient() { } } }); + + ServerLifecycleEvents.SERVER_STOPPING.register(server -> GlobalConfig.HANDLER.save()); + ServerLifecycleEvents.END_DATA_PACK_RELOAD.register((server, resourceManager, s) -> GlobalConfig.HANDLER.save()); + ServerPlayConnectionEvents.DISCONNECT.register((handler, packetSender) -> GlobalConfig.HANDLER.save()); + Runtime.getRuntime().addShutdownHook(new Thread(() -> GlobalConfig.HANDLER.save())); } private void saveWidgetsSafely(File widgetsFile) { try { diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/DynamicHudTest.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/DynamicHudTest.java index 78177ee..efad069 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/newTrial/DynamicHudTest.java +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/DynamicHudTest.java @@ -4,6 +4,7 @@ import com.tanishisherewith.dynamichud.huds.AbstractMoveableScreen; import com.tanishisherewith.dynamichud.huds.MoveableScreen; import com.tanishisherewith.dynamichud.newTrial.utils.DynamicValueRegistry; +import com.tanishisherewith.dynamichud.newTrial.widget.Widget; import com.tanishisherewith.dynamichud.newTrial.widget.WidgetManager; import com.tanishisherewith.dynamichud.newTrial.widget.WidgetRenderer; import com.tanishisherewith.dynamichud.newTrial.widgets.TextWidget; @@ -16,41 +17,45 @@ import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; public class DynamicHudTest implements DynamicHudIntegration { TextWidget textWidget; - - DynamicValueRegistry registry = new DynamicValueRegistry(); + DynamicValueRegistry registry = new DynamicValueRegistry(DynamicHUD.MOD_ID); WidgetRenderer renderer; @Override public void init() { - DynamicValueRegistry.registerGlobal("FPS",() -> String.valueOf(DynamicHUD.MC.getCurrentFps())); - registry.registerLocal("FPS",()->String.valueOf(DynamicHUD.MC.getCurrentFps())); - } + DynamicValueRegistry.registerGlobal("FPS",() -> "FPS: "+ DynamicHUD.MC.getCurrentFps()); + registry.registerLocal("FPS",()-> "FPS: "+ DynamicHUD.MC.getCurrentFps()); - @Override - public void addWidgets() { textWidget = new TextWidget.Builder() - .setX(0.6f) - .setY(0.6f) + .setX(300) + .setY(60) .setDraggable(true) - .shouldScale(false) .rainbow(false) - .setDHKey("FPS") + .setDRKey("FPS") + .setModID(DynamicHUD.MOD_ID) + .shouldScale(false) .build(); + } - + @Override + public void addWidgets() { WidgetManager.addWidget(textWidget); } @Override public AbstractMoveableScreen getMovableScreen() { - return new MoveableScreen(Text.of("Editor LOL"),new DynamicUtil(DynamicHUD.MC)); + return new MoveableScreen(Text.of("Editor"),new DynamicUtil(DynamicHUD.MC)); } @Override public WidgetRenderer getWidgetRenderer() { - renderer = new WidgetRenderer(Collections.singletonList(textWidget)); + // Get the widgets for this mod + List widgets = WidgetManager.getWidgetsForMod(DynamicHUD.MOD_ID); + + renderer = new WidgetRenderer(widgets); renderer.shouldRenderInGameHud(true); renderer.addScreen(TitleScreen.class); renderer.addScreen(MultiplayerScreen.class); diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/config/GlobalConfig.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/config/GlobalConfig.java new file mode 100644 index 0000000..22ae290 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/config/GlobalConfig.java @@ -0,0 +1,51 @@ +package com.tanishisherewith.dynamichud.newTrial.config; + +import dev.isxander.yacl3.api.*; +import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder; +import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; +import dev.isxander.yacl3.config.v2.api.ConfigClassHandler; +import dev.isxander.yacl3.config.v2.api.SerialEntry; +import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; +import dev.isxander.yacl3.gui.controllers.slider.FloatSliderController; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class GlobalConfig { + private static GlobalConfig INSTANCE = new GlobalConfig(); + public static ConfigClassHandler HANDLER = ConfigClassHandler.createBuilder(GlobalConfig.class) + .id(new Identifier("dynamichud", "dynamichud_config")) + .serializer(config -> GsonConfigSerializerBuilder.create(config) + .setPath(FabricLoader.getInstance().getConfigDir().resolve("dynamichud.json5")) + .setJson5(true) + .build()) + .build(); + + @SerialEntry + public float scale = 1.0f; + + public Screen createYACLGUI() { + return YetAnotherConfigLib.createBuilder() + .title(Text.literal("DynamicHUD config screen.")) + .category(ConfigCategory.createBuilder() + .name(Text.literal("General")) + .tooltip(Text.literal("Set the general settings for all widgets.")) + .group(OptionGroup.createBuilder() + .name(Text.literal("Global")) + .description(OptionDescription.of(Text.literal("Global settings for all widgets."))) + .option(Option.createBuilder() + .name(Text.literal("Scale")) + .description(OptionDescription.of(Text.literal("Set scale for all widgets."))) + .binding(1.0f, () -> this.scale, newVal -> this.scale = newVal) + .controller(floatOption -> FloatSliderControllerBuilder.create(floatOption).range(0.1f,2.5f).step(0.1f)) + .build()) + .build()) + .build()) + .build() + .generateScreen(null); + } + public static GlobalConfig get(){ + return INSTANCE; + } +} diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/screens/AbstractMoveableScreen.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/screens/AbstractMoveableScreen.java new file mode 100644 index 0000000..4908b11 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/screens/AbstractMoveableScreen.java @@ -0,0 +1,79 @@ +package com.tanishisherewith.dynamichud.newTrial.screens; + +import com.tanishisherewith.dynamichud.newTrial.widget.WidgetRenderer; +import com.tanishisherewith.dynamichud.widget.Widget; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; +public abstract class AbstractMoveableScreen extends Screen { + protected boolean ShouldPause = false; // To pause if the screen is opened or not + public final WidgetRenderer widgetRenderer; + + + /** + * Constructs a AbstractMoveableScreen object. + * + */ + public AbstractMoveableScreen(Text title, WidgetRenderer renderer) { + super(title); + this.widgetRenderer = renderer; + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + widgetRenderer.mouseDragged(mouseX,mouseY,button); + return false; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + widgetRenderer.mouseClicked(mouseX,mouseY,button); + return false; + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + widgetRenderer.mouseReleased(mouseX,mouseY,button); + return false; + } + + /** + * Renders this screen and its widgets on the screen. + * + * @param drawContext The matrix stack used for rendering + * @param mouseX The current x position of the mouse cursor + * @param mouseY The current y position of the mouse cursor + * @param delta The time elapsed since the last frame in seconds + */ + @Override + public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + super.render(drawContext, mouseX, mouseY, delta); + + // Draw each widget + widgetRenderer.isInEditor = true; + widgetRenderer.renderWidgets(drawContext); + } + + @Override + public void close() { + super.close(); + widgetRenderer.isInEditor = false; + } + + public void setShouldPause(boolean shouldPause) { + this.ShouldPause = shouldPause; + } + + + @Override + public void resize(MinecraftClient client, int width, int height) { + super.resize(client, width, height); + } + + @Override + public boolean shouldPause() { + return ShouldPause; + } +} + diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/utils/DynamicValueRegistry.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/utils/DynamicValueRegistry.java index 2927a35..43d62da 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/newTrial/utils/DynamicValueRegistry.java +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/utils/DynamicValueRegistry.java @@ -3,10 +3,13 @@ import java.util.*; import java.util.function.Supplier; -public class DynamicValueRegistry { +public class DynamicValueRegistry extends System { private static final Map> globalRegistry = new HashMap<>(); private final Map> localRegistry = new HashMap<>(); - + public DynamicValueRegistry(String modId) { + super(modId); + instances.computeIfAbsent(modId, k -> new ArrayList<>()).add(this); + } public static void registerGlobal(String key, Supplier supplier) { globalRegistry.put(key, supplier); } @@ -29,4 +32,8 @@ public Supplier get(String key) { return supplier; } + public void setLocalRegistry(Map> map){ + localRegistry.putAll(map); + } + } diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/utils/System.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/utils/System.java new file mode 100644 index 0000000..8022537 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/utils/System.java @@ -0,0 +1,24 @@ +package com.tanishisherewith.dynamichud.newTrial.utils; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class System { + protected final String modId; + + // A map to store all instances of DynamicValueRegistry by modId + protected static final Map> instances = new ConcurrentHashMap<>(); + + public System(String modId) { + this.modId = modId; + } + + public String getModId() { + return modId; + } + + public static List getInstances(String modId) { + return instances.get(modId); + } +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/Widget.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/Widget.java index ce5950d..4f1ea10 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/Widget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/Widget.java @@ -1,13 +1,14 @@ package com.tanishisherewith.dynamichud.newTrial.widget; -import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; +import com.tanishisherewith.dynamichud.newTrial.config.GlobalConfig; import com.tanishisherewith.dynamichud.newTrial.utils.UID; import com.tanishisherewith.dynamichud.widget.WidgetBox; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.nbt.NbtCompound; +import org.lwjgl.glfw.GLFW; import java.util.Set; @@ -17,20 +18,44 @@ public abstract class Widget { //This is the UID of the widget used to identify during loading and saving public UID uid = UID.generate(); - public boolean display = true; // Whether the widget is enabled + public boolean isInEditor = false; + // Whether the widget is enabled and should be displayed. + public boolean display = true; public boolean isDraggable = true; - protected float xPercent; // The x position of the widget as a percentage of the screen width - protected float yPercent; // The y position of the widget as a percentage of the screen height - public boolean shouldScale = false; + + //Boolean to check if the widget is being dragged + public boolean dragging; + + //To enable/disable snapping + public boolean shiftDown = false; + + // Used for dragging and snapping + int startX, startY, snapSize = 120; + + // Absolute position of the widget on screen in pixels. + public int x,y; + + // The x position of the widget as a percentage of the screen width, i.e. the relative x position of the widget for resizing and scaling + protected float xPercent; + // The y position of the widget as a percentage of the screen height, i.e. the relative y position of the widget for resizing and scaling + protected float yPercent; + public boolean shouldScale = true; + public String modId = "unknown"; + + //Dimensions of the widget protected WidgetBox widgetBox; public static WidgetData DATA; - public Widget(WidgetData DATA){ + public Widget(WidgetData DATA, String modId){ Widget.DATA = DATA; - widgetBox = new WidgetBox(0,0,0,0,0); + widgetBox = new WidgetBox(0,0,0,0,1); + this.modId = modId; init(); } + /** + * This method is called at the end of the {@link Widget#Widget(WidgetData)} constructor. + */ public void init(){ } @@ -39,8 +64,8 @@ public void init(){ * * @return The x position of the widget in pixels */ - public float getX() { - return DynamicHUD.MC.getWindow().getScaledWidth() * xPercent; + public int getX() { + return x; } /** @@ -48,8 +73,20 @@ public float getX() { * * @return The y position of the widget in pixels */ - public float getY() { - return DynamicHUD.MC.getWindow().getScaledHeight() * yPercent; + public int getY() { + return y; + } + + public float getWidth(){ + return widgetBox.getWidth(); + } + public float getHeight(){ + return widgetBox.getHeight(); + } + + public void setPosition(int x, int y){ + this.x = x; + this.y = y; } public void setDraggable(boolean draggable) { @@ -74,13 +111,16 @@ public boolean isOverlapping(Widget other) { * Renders the widget on the screen. */ public void render(DrawContext drawContext){ + if(!shouldDisplay())return; + if(shouldScale) { - DrawHelper.scaleAndPosition(drawContext.getMatrices(), getX(), getY(),0, 1.0f); + DrawHelper.scaleAndPosition(drawContext.getMatrices(), getX(), getY(), GlobalConfig.get().scale); + scale(GlobalConfig.get().scale); } - renderWidget(drawContext); if(shouldScale){ + reverseScale(GlobalConfig.get().scale); DrawHelper.stopScaling(drawContext.getMatrices()); } } @@ -89,12 +129,14 @@ public void render(DrawContext drawContext){ */ public void renderInEditor(DrawContext drawContext){ if(shouldScale) { - DrawHelper.scaleAndPosition(drawContext.getMatrices(), getX(), getY(),0, 1.0f); + DrawHelper.scaleAndPosition(drawContext.getMatrices(), getX(), getY(), GlobalConfig.get().scale); + scale(GlobalConfig.get().scale); } renderWidgetInEditor(drawContext); if(shouldScale){ + reverseScale(GlobalConfig.get().scale); DrawHelper.stopScaling(drawContext.getMatrices()); } } @@ -115,12 +157,51 @@ public void renderInEditor(DrawContext drawContext){ * * @param context */ - public void renderWidgetInEditor(DrawContext context){ + private void renderWidgetInEditor(DrawContext context){ displayBg(context); renderWidget(context); } + public void mouseClicked(double mouseX, double mouseY, int button){ + if(button == GLFW.GLFW_MOUSE_BUTTON_LEFT){ + toggle(); + } + } + public void mouseDragged(double mouseX, double mouseY, int button){ + if(this.isDraggable && button == GLFW.GLFW_MOUSE_BUTTON_LEFT){ + //Start dragging + startX = (int) (mouseX - x); + startY = (int) (mouseY - y); + dragging = true; + this.x = startX; + this.y = startY; + + // Divides the screen into several "grid boxes" which the elements snap to. Higher the snapSize, more the grid boxes + if (this.shiftDown) { + // Calculate the size of each snap box + int snapBoxWidth = (int) (widgetBox.getWidth() / this.snapSize); + int snapBoxHeight = (int) (widgetBox.getHeight() / this.snapSize); + + // Calculate the index of the snap box that the mouse is currently in + int snapBoxX = (int) (mouseX / snapBoxWidth); + int snapBoxY = (int) (mouseY / snapBoxHeight); + + // Snap the element to the top-left corner of the snap box + this.x = snapBoxX * snapBoxWidth; + this.y = snapBoxY * snapBoxHeight; + } + } + } + public void mouseReleased(double mouseX, double mouseY, int button) { + dragging = false; + } + + + public boolean toggle(){ + return this.display = !this.display; + } + /** * Displays a faint grayish background if enabled or faint reddish background if disabled. * Drawn with 2 pixel offset to all sides @@ -135,11 +216,13 @@ protected void displayBg(DrawContext context){ public void readFromTag(NbtCompound tag) { + modId = tag.getString("modId"); uid = new UID(tag.getString("UID")); - xPercent = tag.getFloat("xPercent"); - yPercent = tag.getFloat("yPercent"); + x = tag.getInt("x"); + y = tag.getInt("y"); display = tag.getBoolean("Display"); isDraggable = tag.getBoolean("isDraggable"); + shouldScale = tag.getBoolean("shouldScale"); } /** @@ -148,10 +231,13 @@ public void readFromTag(NbtCompound tag) { * @param tag The tag to write to */ public void writeToTag(NbtCompound tag) { + tag.putString("name", DATA.name()); + tag.putString("modId",modId); tag.putString("UID", uid.getUniqueID()); tag.putBoolean("isDraggable", isDraggable); - tag.putFloat("xPercent", xPercent); - tag.putFloat("yPercent", yPercent); + tag.putBoolean("shouldScale", shouldScale); + tag.putInt("x", x); + tag.putInt("y", y); tag.putBoolean("Display", display); } @@ -179,6 +265,18 @@ public void setShouldScale(boolean shouldScale) { this.shouldScale = shouldScale; } + public String getModId() { + return modId; + } + public void scale(float scale) { + this.xPercent *= scale; + this.yPercent *= scale; + } + public void reverseScale(float scale) { + this.xPercent /= scale; + this.yPercent /= scale; + } + @Override public String toString() { return "Widget{" + @@ -188,23 +286,24 @@ public String toString() { ", display=" + display + '}'; } - public abstract static class WidgetBuilder { - protected float xPercent; - protected float yPercent; + protected int x; + protected int y; protected boolean display = true; protected boolean isDraggable = true; protected boolean shouldScale = true; + protected String modID = "unknown"; + /** * X Position of the widget relative to the screen. * Should be between 0f - 1f * - * @param xPercent - * @return + * @param x + * @return Builder */ - public T setX(float xPercent) { - this.xPercent = xPercent; + public T setX(int x) { + this.x = x; return self(); } @@ -212,11 +311,11 @@ public T setX(float xPercent) { * Y Position of the widget relative to the screen. * Should be between 0f - 1f * - * @param yPercent + * @param y * @return */ - public T setY(float yPercent) { - this.yPercent = yPercent; + public T setY(int y) { + this.y = y; return self(); } @@ -234,11 +333,19 @@ public T shouldScale(boolean shouldScale) { this.shouldScale = shouldScale; return self(); } + public T setModID(String modID) { + this.modID = modID; + return self(); + } - // Method to be overridden in subclasses to return "this" correctly + /** + * Method to be overridden in subclasses to return "this" correctly + */ protected abstract T self(); - // Method to construct a Widget object + /** + * Method to construct a Widget object + */ public abstract S build(); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/WidgetManager.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/WidgetManager.java index 14f8dfc..02f384c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/WidgetManager.java +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/WidgetManager.java @@ -5,11 +5,12 @@ import java.nio.file.StandardCopyOption; import java.util.*; +import com.tanishisherewith.dynamichud.DynamicHUD; import net.fabricmc.fabric.api.util.NbtType; import net.minecraft.nbt.*; +import net.minecraft.util.math.MathHelper; -import static com.tanishisherewith.dynamichud.DynamicHUD.printInfo; -import static com.tanishisherewith.dynamichud.DynamicHUD.printWarn; +import static com.tanishisherewith.dynamichud.DynamicHUD.*; /** * Manages a collection of widgets, providing methods to add, remove, save, and load widgets. @@ -71,6 +72,77 @@ public static void addWidgets(Widget... widget) { public static void removeWidget(Widget widget) { widgets.remove(widget); } + /* public static void onScreenResized(int newWidth, int newHeight) { + float scaleX = (float) newWidth / MC.getWindow().getScaledWidth(); + float scaleY = (float) newHeight / MC.getWindow().getScaledHeight(); + System.out.println("newWidth: " + newWidth); + System.out.println("newHeight: " + newHeight); + + System.out.println("scaleX: " + scaleX); + + for (Widget widget : widgets) { + float newX = widget.getX() * scaleX; + float newY = widget.getY() * scaleY; + System.out.println("newX: " + newX); + + // Ensure the widget is within the screen bounds + newX = MathHelper.clamp(newX,0,newWidth - widget.getWidth()); + newY = MathHelper.clamp(newY,0,newHeight - widget.getHeight()); + System.out.println("newX2: " + newX); + + widget.setPosition(newX, newY); + } + } + + */ + + /** + * Attempts to restore the widgets back to their place on screen resize. + *

+ * It works by storing the position of widgets as relative to the screen size before the resize + * and then using that percentage to restore the widget to their appropriate place. + *

+ * Widgets will move around on smaller GUI scales. + * Larger the GUI scale, more accurate is the position. + *

+ *

+ * Called in {@link com.tanishisherewith.dynamichud.mixins.ScreenMixin} + *

+ *

+ * + * @param newWidth Screen width after resize + * @param newHeight Screen height after resize + * @param previousWidth Screen width before resize + * @param previousHeight Screen height before resize + */ + public static void onScreenResized(int newWidth, int newHeight, int previousWidth, int previousHeight) { + for (Widget widget : widgets) { + + // To ensure that infinite coords is not returned + if(widget.xPercent <= 0f){ + widget.xPercent = (float) widget.getX()/previousWidth; + } + if(widget.yPercent <= 0f){ + widget.yPercent = (float) widget.getY()/previousHeight; + } + + // Use the stored percentages to calculate the new position + int newX = (int) (widget.xPercent * newWidth); + int newY = (int) (widget.yPercent * newHeight); + + // Ensure the widget is within the screen bounds + newX = (int) MathHelper.clamp(newX, 0, newWidth - widget.getWidth()); + newY = (int) MathHelper.clamp(newY, 0, newHeight - widget.getHeight()); + + // Update the widget's position + widget.setPosition(newX, newY); + + // Update the stored percentages with the new screen size (after resize). + widget.xPercent = (float) widget.getX() / newWidth; + widget.yPercent = (float) widget.getY() / newHeight; + } + } + /** * Saves the state of all widgets to the given file. @@ -100,17 +172,11 @@ public static void saveWidgets(File file) throws IOException { rootTag.put("widgets", widgetList); - // Use a temporary file to write the data - File tempFile = new File(file.getAbsolutePath() + ".tmp"); - try (DataOutputStream out = new DataOutputStream(new FileOutputStream(tempFile))) { + //Write the data to the file + try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) { NbtIo.write(rootTag, out); - // Check if the data has been written successfully - if (tempFile.length() > 0) { - // Check if the temporary file exists and can be renamed - Files.move(tempFile.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); - } else { - throw new IOException("Failed to write data to temporary file OR Empty data passed"); - } + }catch (IOException e){ + DynamicHUD.logger.warn("Error while saving",e); } } @@ -146,4 +212,14 @@ public static void loadWidgets(File file) throws IOException { public static List getWidgets() { return widgets; } + /** + * Returns the list of managed widgets with the same modID. + * + * @return The list of managed widgets with the same modID. + */ + public static List getWidgetsForMod(String modID) { + return getWidgets().stream() + .filter(widget -> modID.equalsIgnoreCase(widget.getModId())) + .toList(); + } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/WidgetRenderer.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/WidgetRenderer.java index 6580509..fffdd2d 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/WidgetRenderer.java +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/widget/WidgetRenderer.java @@ -1,8 +1,13 @@ package com.tanishisherewith.dynamichud.newTrial.widget; import com.tanishisherewith.dynamichud.DynamicHUD; +import com.tanishisherewith.dynamichud.helpers.ColorHelper; +import com.tanishisherewith.dynamichud.helpers.DrawHelper; +import com.tanishisherewith.dynamichud.huds.AbstractMoveableScreen; +import com.tanishisherewith.dynamichud.widget.WidgetBox; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; +import org.lwjgl.glfw.GLFW; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -10,10 +15,14 @@ public class WidgetRenderer { public final List> allowedScreens = new CopyOnWriteArrayList<>(); private boolean renderInGameHud = true; + public boolean isInEditor = false; List widgets; public WidgetRenderer(List widgets){ this.widgets = widgets; } + public void addWidget(Widget widget){ + widgets.add(widget); + } public void addScreen(Class screen){ allowedScreens.add(screen); @@ -27,17 +36,88 @@ public void renderWidgets(DrawContext context) { if(WidgetManager.getWidgets().isEmpty()) return; Screen currentScreen = DynamicHUD.MC.currentScreen; + if(currentScreen == null && renderInGameHud){ for (Widget widget : widgets) { + widget.isInEditor = false; widget.render(context); } return; } - if (currentScreen!= null && allowedScreens.contains(DynamicHUD.MC.currentScreen.getClass())) { + if(currentScreen instanceof AbstractMoveableScreen){ + for (Widget widget : widgets) { + widget.isInEditor = true; + widget.renderInEditor(context); + } + return; + } + if (currentScreen != null && allowedScreens.contains(DynamicHUD.MC.currentScreen.getClass()) && !this.isInEditor) { for (Widget widget : widgets) { - // System.out.println("Rendering Widget: " + widget); + widget.isInEditor = false; widget.render(context); } } } + public void mouseClicked(double mouseX, double mouseY, int button){ + Screen currentScreen = DynamicHUD.MC.currentScreen; + if(currentScreen == null) { + return; + } + if(currentScreen instanceof AbstractMoveableScreen){ + for (Widget widget : widgets) { + widget.mouseClicked(mouseX,mouseY,button); + } + } + } + public void mouseDragged(double mouseX, double mouseY, int button){ + Screen currentScreen = DynamicHUD.MC.currentScreen; + if(currentScreen == null) { + return; + } + if(currentScreen instanceof AbstractMoveableScreen){ + for (Widget widget : widgets) { + widget.mouseDragged(mouseX,mouseY,button); + } + } + } + + public void keyPressed(int keyCode){ + Screen currentScreen = DynamicHUD.MC.currentScreen; + if(currentScreen instanceof AbstractMoveableScreen && (keyCode == GLFW.GLFW_KEY_LEFT_SHIFT || keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT)) { + for (Widget widget : widgets) { + widget.shiftDown = true; + } + } + } + public void keyReleased(int keyCode){ + Screen currentScreen = DynamicHUD.MC.currentScreen; + if(currentScreen instanceof AbstractMoveableScreen && (keyCode == GLFW.GLFW_KEY_LEFT_SHIFT || keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT)) { + for (Widget widget : widgets) { + widget.shiftDown = false; + } + } + } + public void onCloseScreen(){ + if(DynamicHUD.MC.currentScreen instanceof AbstractMoveableScreen){ + for (Widget widget : widgets) { + widget.shiftDown = false; + } + } + } + + public List getWidgets() { + return widgets; + } + + public void mouseReleased(double mouseX, double mouseY, int button){ + Screen currentScreen = DynamicHUD.MC.currentScreen; + if(currentScreen == null) { + return; + } + if(currentScreen instanceof AbstractMoveableScreen){ + for (Widget widget : widgets) { + widget.mouseReleased(mouseX,mouseY,button); + } + } + } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/newTrial/widgets/TextWidget.java b/src/main/java/com/tanishisherewith/dynamichud/newTrial/widgets/TextWidget.java index 5701b0b..0c816a1 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/newTrial/widgets/TextWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/newTrial/widgets/TextWidget.java @@ -1,8 +1,7 @@ package com.tanishisherewith.dynamichud.newTrial.widgets; -import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.ColorHelper; -import com.tanishisherewith.dynamichud.helpers.DrawHelper; +import com.tanishisherewith.dynamichud.newTrial.config.GlobalConfig; import com.tanishisherewith.dynamichud.newTrial.utils.DynamicValueRegistry; import com.tanishisherewith.dynamichud.newTrial.widget.Widget; import com.tanishisherewith.dynamichud.newTrial.widget.WidgetData; @@ -16,11 +15,12 @@ public class TextWidget extends Widget { public static WidgetData DATA = new WidgetData<>("TextWidget","Display Text on screen",TextWidget::new); Supplier textSupplier; String dynamicRegistryKey; + DynamicValueRegistry dynamicValueRegistry; protected boolean shadow; // Whether to draw a shadow behind the text protected boolean rainbow; // Whether to apply a rainbow effect to the text public TextWidget() { - this(null,false,false); + this(null,false,false,"unknown"); } /** @@ -30,8 +30,8 @@ public TextWidget() { * @param shadow * @param rainbow */ - public TextWidget(String dynamicRegistryKey, boolean shadow, boolean rainbow) { - super(DATA); + public TextWidget(String dynamicRegistryKey, boolean shadow, boolean rainbow,String modID) { + super(DATA,modID); this.dynamicRegistryKey = dynamicRegistryKey; textSupplier = (Supplier) DynamicValueRegistry.getGlobal(dynamicRegistryKey); this.shadow = shadow; @@ -45,9 +45,10 @@ public TextWidget(String dynamicRegistryKey, boolean shadow, boolean rainbow) { * @param shadow * @param rainbow */ - public TextWidget(DynamicValueRegistry dynamicValueRegistry,String dynamicRegistryKey, boolean shadow, boolean rainbow) { - super(DATA); + public TextWidget(DynamicValueRegistry dynamicValueRegistry,String dynamicRegistryKey, boolean shadow, boolean rainbow,String modID) { + super(DATA,modID); this.dynamicRegistryKey = dynamicRegistryKey; + this.dynamicValueRegistry = dynamicValueRegistry; textSupplier = (Supplier) dynamicValueRegistry.get(dynamicRegistryKey); this.shadow = shadow; this.rainbow = rainbow; @@ -55,15 +56,12 @@ public TextWidget(DynamicValueRegistry dynamicValueRegistry,String dynamicRegist @Override public void renderWidget(DrawContext drawContext) { - drawContext.getMatrices().push(); - drawContext.getMatrices().translate(0, 0, 420); - int color = rainbow ? ColorHelper.getColorFromHue((System.currentTimeMillis() % 10000) / (1 * 400f)) : Color.WHITE.getRGB(); + int color = rainbow ? ColorHelper.getColorFromHue((System.currentTimeMillis() % 10000) / 10000f) : Color.WHITE.getRGB(); if(textSupplier != null) { String text = textSupplier.get(); - drawContext.drawText(mc.textRenderer, text, (int) getX(), (int) getY(), color, shadow); - widgetBox.setSize(getX(),getY(),mc.textRenderer.getWidth(text),mc.textRenderer.fontHeight); + drawContext.drawText(mc.textRenderer, text, (int) getX(), (int)getY(), color, shadow); + widgetBox.setSize(getX() - 2,getY() - 2,mc.textRenderer.getWidth(text) + 2,mc.textRenderer.fontHeight + 2); } - drawContext.getMatrices().pop(); } @Override @@ -80,9 +78,13 @@ public void readFromTag(NbtCompound tag) { shadow = tag.getBoolean("shadow"); rainbow = tag.getBoolean("rainbow"); dynamicRegistryKey = tag.getString("DRKey"); + + for(DynamicValueRegistry dvr: DynamicValueRegistry.getInstances(modId)){ + textSupplier = (Supplier) dvr.get(dynamicRegistryKey); + break; + } } public static class Builder extends WidgetBuilder { - protected boolean shadow = false; protected boolean rainbow = false; protected String dynamicRegistryKey = ""; @@ -97,11 +99,11 @@ public Builder rainbow(boolean rainbow) { this.rainbow = rainbow; return self(); } - public Builder setDHKey(String dynamicRegistryKey) { + public Builder setDRKey(String dynamicRegistryKey) { this.dynamicRegistryKey = dynamicRegistryKey; return self(); } - public Builder setDH(DynamicValueRegistry dynamicValueRegistry) { + public Builder setDVR(DynamicValueRegistry dynamicValueRegistry) { this.dynamicValueRegistry = dynamicValueRegistry; return self(); } @@ -115,12 +117,11 @@ protected Builder self() { public TextWidget build() { TextWidget widget; if(dynamicValueRegistry == null) { - widget = new TextWidget(dynamicRegistryKey, shadow, rainbow); + widget = new TextWidget(dynamicRegistryKey, shadow, rainbow,modID); }else{ - widget = new TextWidget(dynamicValueRegistry,dynamicRegistryKey, shadow, rainbow); + widget = new TextWidget(dynamicValueRegistry,dynamicRegistryKey, shadow, rainbow,modID); } - widget.setxPercent(xPercent); - widget.setyPercent(yPercent); + widget.setPosition(x,y); widget.setDraggable(isDraggable); widget.setShouldScale(shouldScale); return widget; diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java index 6733d3f..fd845fa 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java @@ -6,8 +6,8 @@ public class WidgetBox { public float x1 = 0, x2 = 0, y1 = 0, y2 = 0; public WidgetBox(float x1, float y1, float x2, float y2, float scale) { - this.width = (float) ((x2 - x1) * scale); - this.height = (float) ((y2 - y1) * scale); + this.width = (x2 - x1) * scale; + this.height = (y2 - y1) * scale; this.x1 = x1; this.x2 = x1 + width; this.y1 = y1; diff --git a/src/main/resources/assets/DynamicHUD/DynamicHud-logo.png b/src/main/resources/assets/DynamicHUD/DynamicHud-logo.png deleted file mode 100644 index e2848ae..0000000 Binary files a/src/main/resources/assets/DynamicHUD/DynamicHud-logo.png and /dev/null differ diff --git a/src/main/resources/assets/DynamicHUD/logo.png b/src/main/resources/assets/DynamicHUD/logo.png new file mode 100644 index 0000000..bb4962c Binary files /dev/null and b/src/main/resources/assets/DynamicHUD/logo.png differ diff --git a/src/main/resources/dynamichud.mixins.json b/src/main/resources/dynamichud.mixins.json index 2dc77ad..a6212c5 100644 --- a/src/main/resources/dynamichud.mixins.json +++ b/src/main/resources/dynamichud.mixins.json @@ -9,6 +9,8 @@ "defaultRequire": 1 }, "client": [ + "KeyboardMixin", + "MouseMixin", "OptionsScreenMixin", "ScreenMixin" ] diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index c694091..cb56d52 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -10,7 +10,7 @@ "contributors": [ "LumaaDev" ], - "icon": "assets/DynamicHUD/DynamicHud-logo.png", + "icon": "assets/dynamichud/logo.png", "contact": { "repo": "https://github.com/V-Fast/DynamicHUD", "issues": "https://github.com/V-Fast/DynamicHUD/issues"