diff --git a/.gitattributes b/.gitattributes index 097f9f9..afd59d8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,4 +6,3 @@ # These are Windows script files and should use crlf *.bat text eol=crlf - diff --git a/.gitignore b/.gitignore index c476faf..8feea40 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ hs_err_*.log replay_*.log *.hprof *.jfr +/remappedSrc/ diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/build.gradle b/build.gradle index 62600cf..a76e836 100644 --- a/build.gradle +++ b/build.gradle @@ -1,90 +1,37 @@ plugins { - id 'fabric-loom' version "${loom_version}" - id 'maven-publish' + id 'net.fabricmc.fabric-loom' version "${loom_version}" } version = project.mod_version group = project.maven_group - -base { - archivesName = project.archives_base_name -} +base { archivesName = project.mod_id } repositories { - maven { - name = "Terraformers" - url = "https://maven.terraformersmc.com/" - } -} - -loom { - splitEnvironmentSourceSets() - - mods { - "better-compass" { - sourceSet sourceSets.main - sourceSet sourceSets.client - } - } - + maven { url "https://maven.terraformersmc.com/releases/" } } dependencies { - // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - modCompileOnly("com.terraformersmc:modmenu:${project.modmenu_version}") + implementation "net.fabricmc:fabric-loader:${project.loader_version}" + implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" + implementation "com.terraformersmc:modmenu:${project.modmenu_version}" } processResources { inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": inputs.properties.version - } + filteringCharset "UTF-8" + filesMatching("fabric.mod.json") { expand "version": project.version } } -tasks.withType(JavaCompile).configureEach { - it.options.release = 21 -} +tasks.withType(JavaCompile).configureEach { it.options.release = 25 } java { - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. withSourcesJar() - - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 } - jar { inputs.property "archivesName", project.base.archivesName - - from("LICENSE") { - rename { "${it}_${inputs.properties.archivesName}"} - } -} - -// configure the maven publication -publishing { - publications { - create("mavenJava", MavenPublication) { - artifactId = project.archives_base_name - from components.java - } - } - - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - // Add repositories to publish to here. - // Notice: This block does NOT have the same function as the block in the top level. - // The repositories here will be used for publishing your artifact, not for - // retrieving dependencies. - } + from("LICENSE.md") { rename { "${it}_${inputs.properties.archivesName}"} } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index ae42937..4bb23ea 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,19 +1,19 @@ -# Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx1G +# Done to increase the memory available to Gradle. +org.gradle.jvmargs=-Xmx2G org.gradle.parallel=true +org.gradle.configuration-cache=false -# Fabric Properties -# check these on https://fabricmc.net/develop -minecraft_version=1.21.11 -yarn_mappings=1.21.11+build.1 -loader_version=0.18.1 -loom_version=1.13-SNAPSHOT +# Fabric Properties on https://modmuss50.me/fabric.html +minecraft_version=26.3 +loom_version=1.18-SNAPSHOT +loader_version=0.19.5 +fabric_api_version=0.161.0+26.3 # Mod Properties mod_version=1.0.8 maven_group=fr.madu59 -archives_base_name=better-compass +mod_id=better-compass # Dependencies -fabric_version=0.139.4+1.21.11 -modmenu_version = 15.0.0 \ No newline at end of file +# Mod Menu from https://modrinth.com/mod/modmenu/versions +modmenu_version=21.0.0 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68..b14ad76 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/src/client/java/fr/madu59/bettercompass/BetterCompassClient.java b/src/client/java/fr/madu59/bettercompass/BetterCompassClient.java deleted file mode 100644 index 4b59cfd..0000000 --- a/src/client/java/fr/madu59/bettercompass/BetterCompassClient.java +++ /dev/null @@ -1,251 +0,0 @@ -package fr.madu59.bettercompass; - - -import java.lang.reflect.Type; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.lang.Math; -import java.io.*; -import java.nio.file.*; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import fr.madu59.bettercompass.config.ClientCommands; -import fr.madu59.bettercompass.config.SettingsManager; -import fr.madu59.bettercompass.mixin.client.FovMultiplierAccessor; - -import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; -import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry; -import net.fabricmc.fabric.api.client.rendering.v1.hud.VanillaHudElements; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.util.Identifier; -import net.minecraft.util.WorldSavePath; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.RenderTickCounter; -import net.minecraft.text.Text; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.network.ServerInfo; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.Items; -import net.minecraft.registry.RegistryKey; -import net.minecraft.registry.RegistryKeys; - - -public class BetterCompassClient implements ClientModInitializer { - - private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); - private static final float GUI_WIDTH = 0.5F; - - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - private static Map valueMap = new LinkedHashMap<>(); - - - private static RegistryKey lastDimension = null; - - public static BlockPos deathPointBlockPos = null; - public static RegistryKey deathDimension = null; - public static BlockPos netherPortalBlockPos = null; - public static String serverId; - - @Override - public void onInitializeClient() { - ClientCommands.register(); - // Attach our rendering code to before the chat hud layer. Our layer will render right before the chat. The API will take care of z spacing. - HudElementRegistry.attachElementBefore(VanillaHudElements.CHAT, Identifier.of(BetterCompass.MOD_ID, "before_chat"), BetterCompassClient::render); - - ClientTickEvents.END_CLIENT_TICK.register(client -> { - if (client.player != null && client.player.isDead()) { - deathPointBlockPos = client.player.getBlockPos(); - deathDimension = client.world.getRegistryKey(); - valueMap.put("deathPointBlockPos", blockPosToString(deathPointBlockPos)); - valueMap.put("deathDimension", registryKeyToString(deathDimension)); - saveValues(); - } - if (client.world != null) { - RegistryKey current = client.world.getRegistryKey(); - if (lastDimension != null && !lastDimension.equals(current)) { - if (current == World.NETHER) { - netherPortalBlockPos = client.player.getBlockPos(); - valueMap.put("netherPortalBlockPos", blockPosToString(netherPortalBlockPos)); - saveValues(); - } - else{ - netherPortalBlockPos = null; - } - } - lastDimension = current; - } - }); - ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { - // This runs when the client enters a world - - if (CLIENT.getServer() == null) { - // Multiplayer - ServerInfo info = CLIENT.getCurrentServerEntry(); - serverId = info != null ? info.address.replace(":", "_") : "unknown_server"; - } else { - // Singleplayer - serverId = CLIENT.getServer().getSavePath(WorldSavePath.ROOT) - .getParent().getFileName().toString(); - } - loadData(); - }); - } - - private static void render(DrawContext context, RenderTickCounter tickCounter) { - float compassPosition = 0.05F; - if(SettingsManager.COMPASS_POSITION.getValueAsString().equals("Bottom")){compassPosition = 1-0.18F;} - float deltaY = 0F; - float size = 1.5F; - int color = 0xFFFFFFFF; - PlayerEntity player = CLIENT.player; - int optionValueIndex = SettingsManager.SHOW_COMPASS_HUD.getValueAsIndex(); - if(optionValueIndex == 3 - || (optionValueIndex == 2 && !player.getMainHandStack().getItem().getTranslationKey().equals("item.minecraft.compass")) - || (optionValueIndex == 1 && !player.getInventory().containsAny(Set.of(Items.COMPASS))) - ){ - return; - } - TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; - Camera camera = CLIENT.gameRenderer.getCamera(); - if (camera == null) return; - - float fov = ((FovMultiplierAccessor)(Object)CLIENT.gameRenderer).getFovMultiplier() * CLIENT.options.getFov().getValue(); - float camDirection = camera.getYaw(); - - if(!SettingsManager.CARDINALS_DIRECTION_POSITION.getValue().equals("Disabled")){ - color = SettingsManager.getRGBColorFromSetting(SettingsManager.CARDINALS_DIRECTION_COLOR.getValueAsString()); - if(SettingsManager.CARDINALS_DIRECTION_POSITION.getValue().equals("Under")){deltaY = 0.03F; size = 0.8F;} - if(SettingsManager.CARDINALS_DIRECTION_POSITION.getValue().equals("Above")){deltaY = -0.03F; size = 0.8F;} - drawCompassSymbol(context, textRenderer, fov, "N", 180, camDirection, compassPosition + deltaY, color, size); - drawCompassSymbol(context, textRenderer, fov, "E", 270, camDirection, compassPosition + deltaY, color, size); - drawCompassSymbol(context, textRenderer, fov, "S", 0, camDirection, compassPosition + deltaY, color, size); - drawCompassSymbol(context, textRenderer, fov, "W", 90, camDirection, compassPosition + deltaY, color, size); - } - - for (int i = 0; i < 36; i++){ - if(i % 9 != 0 || !SettingsManager.CARDINALS_DIRECTION_POSITION.getValue().equals("Aligned")){ - drawCompassSymbol(context, textRenderer, fov, "|", i * 10, camDirection, compassPosition, 0xFFFFFFFF, 1); - } - } - - //Add death position to the compass HUD - if(deathPointBlockPos != null && CLIENT.world.getRegistryKey() == deathDimension && !SettingsManager.LAST_DEATH_DIRECTION_POSITION.getValue().equals("Disabled")){ - deltaY = 0; - size = 1.5F; - color = SettingsManager.getRGBColorFromSetting(SettingsManager.LAST_DEATH_DIRECTION_COLOR.getValueAsString()); - if(SettingsManager.LAST_DEATH_DIRECTION_POSITION.getValue().equals("Under")){deltaY = 0.03F; size = 0.8F;} - if(SettingsManager.LAST_DEATH_DIRECTION_POSITION.getValue().equals("Above")){deltaY = -0.03F; size = 0.8F;} - Vec3d deathPos = new Vec3d(deathPointBlockPos.getX(), 0, deathPointBlockPos.getZ()); - double dx = deathPos.x - player.getX(); - double dz = deathPos.z - player.getZ(); - drawCompassSymbol(context, textRenderer, fov, "๐Ÿ’€", (float)(MathHelper.atan2(dz, dx) * (180 / Math.PI)) - 90, camDirection, compassPosition + deltaY, color, size); - } - - //Add nether portal position to the compass HUD - if(netherPortalBlockPos != null && CLIENT.world.getRegistryKey() == World.NETHER && !SettingsManager.NETHER_PORTAL_DIRECTION_POSITION.getValue().equals("Disabled")){ - deltaY = 0; - size = 1.5F; - color = SettingsManager.getRGBColorFromSetting(SettingsManager.NETHER_PORTAL_DIRECTION_COLOR.getValueAsString()); - if(SettingsManager.NETHER_PORTAL_DIRECTION_POSITION.getValue().equals("Under")){deltaY = 0.03F; size = 0.8F;} - if(SettingsManager.NETHER_PORTAL_DIRECTION_POSITION.getValue().equals("Above")){deltaY = -0.03F; size = 0.8F;} - Vec3d netherPortalPos = new Vec3d(netherPortalBlockPos.getX(), 0, netherPortalBlockPos.getZ()); - double dx = netherPortalPos.x - player.getX(); - double dz = netherPortalPos.z - player.getZ(); - drawCompassSymbol(context, textRenderer, fov, "๐ŸŒ", (float)(MathHelper.atan2(dz, dx) * (180 / Math.PI)) - 90, camDirection, compassPosition + deltaY, color, size); - } - } - - public static void drawCompassSymbol(DrawContext context, TextRenderer textRenderer, float fov, String symbol, float targetDirection, float camDirection, float y, int color, float scale){ - int screenWidth = context.getScaledWindowWidth(); - int screenHeight = context.getScaledWindowHeight(); - - //Determine the position of the symbol depending on the targetDirection and the camDirection - int x = - (int) (screenWidth * 0.5 * GUI_WIDTH * MathHelper.wrapDegrees(camDirection-targetDirection)/fov); - if(Math.abs(MathHelper.wrapDegrees(camDirection-targetDirection)/fov)>1.0){ - return; - } - - //Adjust symbol transparency - color = color % 16777216; - int alpha = (int) (255 * (1-Math.abs(Math.sin(Math.toRadians(camDirection - targetDirection))))); - color += 16777216 * alpha; - - //Scale the GUI - var matrices = context.getMatrices(); - var before = new org.joml.Matrix3x2f(matrices); - matrices.scale(scale, scale); - - if(SettingsManager.COMPASS_STYLE.getValueAsString().equals("Shadows")){ - context.drawCenteredTextWithShadow(textRenderer, Text.literal(symbol),(int) ((screenWidth/2 + x)/scale),(int) ((screenHeight*y)/scale - textRenderer.fontHeight/2f),color); - } - else{ - context.drawText(textRenderer, symbol,(int) ((screenWidth/2 + x)/scale - textRenderer.getWidth(symbol)/2f),(int) ((screenHeight*y)/scale - textRenderer.fontHeight/2f),color, false); - } - - matrices.set(before); - } - - - - - public static void saveValues() { - Path configPath = FabricLoader.getInstance().getConfigDir().resolve(serverId).resolve(BetterCompass.MOD_ID + ".json"); - try { - Files.createDirectories(configPath.getParent()); - try (Writer writer = Files.newBufferedWriter(configPath)) { - GSON.toJson(valueMap, writer); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - private static void loadData() { - Path configPath = FabricLoader.getInstance().getConfigDir().resolve(serverId).resolve(BetterCompass.MOD_ID + ".json"); - try (Reader reader = Files.newBufferedReader(configPath)) { - Type type = new TypeToken>() {}.getType(); - valueMap = GSON.fromJson(reader, type); - } catch (IOException e) { - e.printStackTrace(); - return; - } - - if(valueMap.containsKey("deathPointBlockPos")){ - deathPointBlockPos = stringToBlockPos(valueMap.get("deathPointBlockPos")); - } - if(valueMap.containsKey("deathDimension")){ - deathDimension = RegistryKey.of(RegistryKeys.WORLD, Identifier.tryParse(valueMap.get("deathDimension"))); - } - if(valueMap.containsKey("netherPortalBlockPos")){ - netherPortalBlockPos = stringToBlockPos(valueMap.get("netherPortalBlockPos")); - } - } - - private static String blockPosToString(BlockPos pos){ - return pos.getX() + "," + pos.getY() + "," + pos.getZ(); - } - - private static String registryKeyToString(RegistryKey key){ - return key.getValue().toString(); - } - - private static BlockPos stringToBlockPos(String str){ - String[] coords = str.split(","); - return new BlockPos( - Integer.parseInt(coords[0]), - Integer.parseInt(coords[1]), - Integer.parseInt(coords[2]) - ); - } -} \ No newline at end of file diff --git a/src/client/java/fr/madu59/bettercompass/config/ClientCommands.java b/src/client/java/fr/madu59/bettercompass/config/ClientCommands.java deleted file mode 100644 index 3413991..0000000 --- a/src/client/java/fr/madu59/bettercompass/config/ClientCommands.java +++ /dev/null @@ -1,37 +0,0 @@ -package fr.madu59.bettercompass.config; - -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; -import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; -import net.minecraft.client.MinecraftClient; -import net.minecraft.command.CommandSource; -import net.minecraft.text.Text; -import com.mojang.brigadier.arguments.StringArgumentType; - -public class ClientCommands { - public static void register() { - ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { - dispatcher.register( - literal("BetterCompassConfig") - .then(argument("option", StringArgumentType.string()).suggests((context, builder) -> { return CommandSource.suggestMatching(SettingsManager.getAllOptionsId(), builder);}) - .then(argument("value", StringArgumentType.string()).suggests((context, builder) -> { return CommandSource.suggestMatching(SettingsManager.getOptionPossibleValues(StringArgumentType.getString(context, "option")), builder);}) - .executes(context -> { - String option = StringArgumentType.getString(context, "option"); - String value = StringArgumentType.getString(context, "value"); - - boolean success = SettingsManager.setOptionValue(option, (Object) value); - MinecraftClient.getInstance().player.sendMessage( - Text.literal(success ? "Updated " + option + " to " + value : "Failed to update setting."), - false - ); - if(success){ - SettingsManager.saveSettings(SettingsManager.ALL_OPTIONS); - } - return success ? 1 : 0; - }) - ) - ) - ); - }); - } -} - diff --git a/src/client/java/fr/madu59/bettercompass/config/configScreen/BetterCompassConfigScreen.java b/src/client/java/fr/madu59/bettercompass/config/configScreen/BetterCompassConfigScreen.java deleted file mode 100644 index d6501ae..0000000 --- a/src/client/java/fr/madu59/bettercompass/config/configScreen/BetterCompassConfigScreen.java +++ /dev/null @@ -1,80 +0,0 @@ -package fr.madu59.bettercompass.config.configScreen; - -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ButtonWidget; - -import fr.madu59.bettercompass.config.SettingsManager; - -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.Text; - -public class BetterCompassConfigScreen extends Screen { - private MyConfigListWidget list; - - private final String INDENT = " โคท "; - - protected BetterCompassConfigScreen(Screen parent) { - super(Text.literal("Projectile Trajectory Preview Config")); - this.parent = parent; - } - - private final Screen parent; - - @Override - protected void init() { - super.init(); - // Create the scrolling list - this.list = new MyConfigListWidget(this.client, this.width, this.height - 80, 40, 26); - - // Example: Add categories + buttons - list.addCategory("better-compass.config.compass_hud"); - list.addButton(SettingsManager.SHOW_COMPASS_HUD, btn -> { - SettingsManager.SHOW_COMPASS_HUD.setToNextValue(); - }); - list.addButton(SettingsManager.COMPASS_STYLE, btn -> { - SettingsManager.COMPASS_STYLE.setToNextValue(); - }, INDENT); - list.addButton(SettingsManager.COMPASS_POSITION, btn -> { - SettingsManager.COMPASS_POSITION.setToNextValue(); - }, INDENT); - list.addButton(SettingsManager.CARDINALS_DIRECTION_POSITION, btn -> { - SettingsManager.CARDINALS_DIRECTION_POSITION.setToNextValue(); - }); - list.addButton(SettingsManager.CARDINALS_DIRECTION_COLOR, btn -> { - SettingsManager.CARDINALS_DIRECTION_COLOR.setToNextValue(); - }, INDENT); - list.addButton(SettingsManager.LAST_DEATH_DIRECTION_POSITION, btn -> { - SettingsManager.LAST_DEATH_DIRECTION_POSITION.setToNextValue(); - }); - list.addButton(SettingsManager.LAST_DEATH_DIRECTION_COLOR, btn -> { - SettingsManager.LAST_DEATH_DIRECTION_COLOR.setToNextValue(); - }, INDENT); - list.addButton(SettingsManager.NETHER_PORTAL_DIRECTION_POSITION, btn -> { - SettingsManager.NETHER_PORTAL_DIRECTION_POSITION.setToNextValue(); - }); - list.addButton(SettingsManager.NETHER_PORTAL_DIRECTION_COLOR, btn -> { - SettingsManager.NETHER_PORTAL_DIRECTION_COLOR.setToNextValue(); - }, INDENT); - - ButtonWidget doneButton = ButtonWidget.builder(Text.literal("Done"), b -> { - this.client.setScreen(this.parent); - SettingsManager.saveSettings(SettingsManager.ALL_OPTIONS); - }).dimensions(this.width / 2 - 50, this.height - 30, 100, 20).build(); - - this.addDrawableChild(this.list); - this.addDrawableChild(doneButton); - } - - @Override - public void close() { - this.client.setScreen(this.parent); - SettingsManager.saveSettings(SettingsManager.ALL_OPTIONS); - } - - @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { - this.list.render(context, mouseX, mouseY, delta); - super.render(context, mouseX, mouseY, delta); - context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 15, 0xFFFFFF); - } -} \ No newline at end of file diff --git a/src/client/java/fr/madu59/bettercompass/config/configScreen/MyConfigListWidget.java b/src/client/java/fr/madu59/bettercompass/config/configScreen/MyConfigListWidget.java deleted file mode 100644 index db962b8..0000000 --- a/src/client/java/fr/madu59/bettercompass/config/configScreen/MyConfigListWidget.java +++ /dev/null @@ -1,132 +0,0 @@ -package fr.madu59.bettercompass.config.configScreen; - -import java.util.List; - -import fr.madu59.bettercompass.config.Option; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.Click; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.Selectable; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.ElementListWidget; -import net.minecraft.text.Text; -import net.minecraft.sound.SoundEvents; -import net.minecraft.client.sound.PositionedSoundInstance; - -public class MyConfigListWidget extends ElementListWidget { - - public MyConfigListWidget(MinecraftClient client, int width, int height, int top, int itemHeight) { - super(client, width, height, top, itemHeight); - } - - @Override - protected int getScrollbarX() { - return this.getX() + this.getWidth() - 6; - } - - @Override - public int getRowWidth() { - return this.width; - } - - public void addCategory(String name) { - this.addEntry(new CategoryEntry(name)); - } - - public void addButton(String name, ButtonWidget.PressAction onPress) { - this.addEntry(new ButtonEntry(ButtonWidget.builder(Text.literal(name), onPress).dimensions(0, 0, 100, 20).build(), null, "")); - } - - public void addButton(Option option, ButtonWidget.PressAction onPress) { - this.addEntry(new ButtonEntry(ButtonWidget.builder(Text.literal(option.getValueAsString()), onPress).dimensions(0, 0, 100, 20).build(), option, "")); - } - - public void addButton(Option option, ButtonWidget.PressAction onPress, String indent) { - this.addEntry(new ButtonEntry(ButtonWidget.builder(Text.literal(option.getValueAsString()), onPress).dimensions(0, 0, 100, 20).build(), option, indent)); - } - - // Base entry - public abstract static class Entry extends ElementListWidget.Entry {} - - // Category header - public static class CategoryEntry extends Entry { - private final String name; - - public CategoryEntry(String name) { - this.name = name; - } - - @Override - public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float tickDelta) { - TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; - int textX = getContentX() + getContentWidth() / 2; - int textY = getContentY() + (getContentHeight() - textRenderer.fontHeight) / 2; - context.drawCenteredTextWithShadow(textRenderer, Text.translatable(this.name), textX, textY, 0xFFFFFFFF); - } - - @Override - public List selectableChildren() { - return List.of(); - } - - @Override - public List children() { - return List.of(); - } - } - - // Button entry - public static class ButtonEntry extends Entry{ - private final ButtonWidget button; - private final String name; - private final String description; - private final String indent; - private final Option option; - - public ButtonEntry(ButtonWidget button, Option option, String indent) { - this.button = button; - this.name = option.getName(); - this.description = option.getDescription(); - this.indent = indent; - this.option = option; - } - - @Override - public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float tickDelta) { - this.button.setY(this.getContentY() + (this.getContentHeight() - this.button.getHeight()) / 2); - this.button.setX(this.getContentWidth() - this.button.getWidth() - 10); - this.button.render(context, mouseX, mouseY, tickDelta); - - if(this.description == null) return; - - TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; - context.drawText(textRenderer, Text.literal(indent + this.name), 10, this.getContentY() + (this.getContentHeight() - textRenderer.fontHeight) / 2, 0xFFFFFFFF, true); - } - - @Override - public List selectableChildren() { - return List.of(this.button); - } - - @Override - public List children() { - return List.of(this.button); - } - - @Override - public boolean mouseClicked(Click click, boolean doubleClick) { - if (this.button.mouseClicked(click, doubleClick)) { - System.out.println(this.name + " clicked"); - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - if(this.option != null){ - this.button.setMessage(Text.literal(this.option.getValueAsString())); - } - return true; - } - return false; - } - } -} \ No newline at end of file diff --git a/src/client/java/fr/madu59/bettercompass/mixin/client/FovMultiplierAccessor.java b/src/client/java/fr/madu59/bettercompass/mixin/client/FovMultiplierAccessor.java deleted file mode 100644 index 47fc10e..0000000 --- a/src/client/java/fr/madu59/bettercompass/mixin/client/FovMultiplierAccessor.java +++ /dev/null @@ -1,12 +0,0 @@ -package fr.madu59.bettercompass.mixin.client; - -import net.minecraft.client.render.GameRenderer; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(GameRenderer.class) -public interface FovMultiplierAccessor { - @Accessor("fovMultiplier") - float getFovMultiplier(); -} diff --git a/src/main/java/fr/madu59/bettercompass/BetterCompass.java b/src/main/java/fr/madu59/bettercompass/BetterCompass.java index 0de4d8e..08bc633 100644 --- a/src/main/java/fr/madu59/bettercompass/BetterCompass.java +++ b/src/main/java/fr/madu59/bettercompass/BetterCompass.java @@ -1,24 +1,265 @@ package fr.madu59.bettercompass; -import net.fabricmc.api.ModInitializer; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.mojang.brigadier.arguments.StringArgumentType; +import fr.madu59.bettercompass.config.SettingsManager; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.command.v2.ClientCommands; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.hud.VanillaHudElements; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.Camera; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.LevelResource; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix3x2f; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; -public class BetterCompass implements ModInitializer { +public class BetterCompass implements ClientModInitializer { public static final String MOD_ID = "better-compass"; - // This logger is used to write text to the console and the log file. - // It is considered best practice to use your mod id as the logger's name. - // That way, it's clear which mod wrote info, warnings, and errors. - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + private static final Minecraft CLIENT = Minecraft.getInstance(); + private static final float GUI_WIDTH = 0.5F; + + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static Map valueMap = new LinkedHashMap<>(); + + private static ResourceKey lastDimension = null; + + public static BlockPos deathPointBlockPos = null; + public static ResourceKey deathDimension = null; + public static BlockPos netherPortalBlockPos = null; + public static String serverId; @Override - public void onInitialize() { - // This code runs as soon as Minecraft is in a mod-load-ready state. - // However, some things (like resources) may still be uninitialized. - // Proceed with mild caution. + public void onInitializeClient() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, _) -> dispatcher.register(ClientCommands.literal("bettercompass") + .then(ClientCommands.argument("option", StringArgumentType.string()).suggests((_, builder) -> SharedSuggestionProvider.suggest(SettingsManager.getAllOptionsId(), builder)) + .then(ClientCommands.argument("value", StringArgumentType.string()).suggests((context, builder) -> SharedSuggestionProvider.suggest(SettingsManager.getOptionPossibleValues(StringArgumentType.getString(context, "option")), builder)) + .executes(context -> { + String option = StringArgumentType.getString(context, "option"); + String value = StringArgumentType.getString(context, "value"); + + boolean success = SettingsManager.setOptionValue(option, value); + context.getSource().sendFeedback(Component.literal(success ? "Updated " + option + " to " + value : "Failed to update setting.")); + if(success){ + SettingsManager.saveSettings(SettingsManager.ALL_OPTIONS); + } + return success ? 1 : 0; + }) + ) + ) + )); + + // Attach our rendering code to before the chat hud layer. Our layer will render right before the chat. The API will take care of z spacing. + HudElementRegistry.attachElementBefore(VanillaHudElements.CHAT, Identifier.fromNamespaceAndPath(MOD_ID, "before_chat"), BetterCompass::render); + + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (client.player != null && client.player.isDeadOrDying()) { + deathPointBlockPos = client.player.blockPosition(); + deathDimension = client.level.dimension(); + valueMap.put("deathPointBlockPos", blockPosToString(deathPointBlockPos)); + valueMap.put("deathDimension", registryKeyToString(deathDimension)); + saveValues(); + } + if (client.level != null) { + ResourceKey current = client.level.dimension(); + if (lastDimension != null && !lastDimension.equals(current)) { + if (current == Level.NETHER) { + netherPortalBlockPos = client.player.blockPosition(); + valueMap.put("netherPortalBlockPos", blockPosToString(netherPortalBlockPos)); + saveValues(); + } + else{ + netherPortalBlockPos = null; + } + } + lastDimension = current; + } + }); + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { + // This runs when the client enters a world + + if (CLIENT.getSingleplayerServer() == null) { + // Multiplayer + ServerData info = CLIENT.getCurrentServer(); + serverId = info != null ? info.ip.replace(":", "_") : "unknown_server"; + } else { + // Singleplayer + serverId = CLIENT.getSingleplayerServer().getWorldPath(LevelResource.ROOT) + .getParent().getFileName().toString(); + } + loadData(); + }); + } + + private static void render(GuiGraphicsExtractor context, DeltaTracker tickCounter) { + float compassPosition = 0.05F; + if(SettingsManager.COMPASS_POSITION.getValueAsString().equals("Bottom")){compassPosition = 1-0.18F;} + float deltaY = 0F; + float size = 1.5F; + int color; + Player player = CLIENT.player; + int optionValueIndex = SettingsManager.SHOW_COMPASS_HUD.getValueAsIndex(); + if(optionValueIndex == 3 + || (optionValueIndex == 2 && !player.getMainHandItem().getItem().getDescriptionId().equals("item.minecraft.compass")) + || (optionValueIndex == 1 && !player.getInventory().hasAnyOf(Set.of(Items.COMPASS))) + ){ + return; + } + Font textRenderer = Minecraft.getInstance().font; + Camera camera = CLIENT.gameRenderer.mainCamera(); + + float fov = camera.getFov(); + float camDirection = camera.yRot(); + + if(!SettingsManager.CARDINALS_DIRECTION_POSITION.getValue().equals("Disabled")){ + color = SettingsManager.getRGBColorFromSetting(SettingsManager.CARDINALS_DIRECTION_COLOR.getValueAsString()); + if(SettingsManager.CARDINALS_DIRECTION_POSITION.getValue().equals("Under")){deltaY = 0.03F; size = 0.8F;} + if(SettingsManager.CARDINALS_DIRECTION_POSITION.getValue().equals("Above")){deltaY = -0.03F; size = 0.8F;} + drawCompassSymbol(context, textRenderer, fov, "N", 180, camDirection, compassPosition + deltaY, color, size); + drawCompassSymbol(context, textRenderer, fov, "E", 270, camDirection, compassPosition + deltaY, color, size); + drawCompassSymbol(context, textRenderer, fov, "S", 0, camDirection, compassPosition + deltaY, color, size); + drawCompassSymbol(context, textRenderer, fov, "W", 90, camDirection, compassPosition + deltaY, color, size); + } + + for (int i = 0; i < 36; i++){ + if(i % 9 != 0 || !SettingsManager.CARDINALS_DIRECTION_POSITION.getValue().equals("Aligned")){ + drawCompassSymbol(context, textRenderer, fov, "|", i * 10, camDirection, compassPosition, 0xFFFFFFFF, 1); + } + } + + //Add death position to the compass HUD + if(deathPointBlockPos != null && CLIENT.level.dimension() == deathDimension && !SettingsManager.LAST_DEATH_DIRECTION_POSITION.getValue().equals("Disabled")){ + deltaY = 0; + size = 1.5F; + color = SettingsManager.getRGBColorFromSetting(SettingsManager.LAST_DEATH_DIRECTION_COLOR.getValueAsString()); + if(SettingsManager.LAST_DEATH_DIRECTION_POSITION.getValue().equals("Under")){deltaY = 0.03F; size = 0.8F;} + if(SettingsManager.LAST_DEATH_DIRECTION_POSITION.getValue().equals("Above")){deltaY = -0.03F; size = 0.8F;} + Vec3 deathPos = new Vec3(deathPointBlockPos.getX(), 0, deathPointBlockPos.getZ()); + double dx = deathPos.x - player.getX(); + double dz = deathPos.z - player.getZ(); + drawCompassSymbol(context, textRenderer, fov, "๐Ÿ’€", (float)(Mth.atan2(dz, dx) * (180 / Math.PI)) - 90, camDirection, compassPosition + deltaY, color, size); + } + + //Add nether portal position to the compass HUD + if(netherPortalBlockPos != null && CLIENT.level.dimension() == Level.NETHER && !SettingsManager.NETHER_PORTAL_DIRECTION_POSITION.getValue().equals("Disabled")){ + deltaY = 0; + size = 1.5F; + color = SettingsManager.getRGBColorFromSetting(SettingsManager.NETHER_PORTAL_DIRECTION_COLOR.getValueAsString()); + if(SettingsManager.NETHER_PORTAL_DIRECTION_POSITION.getValue().equals("Under")){deltaY = 0.03F; size = 0.8F;} + if(SettingsManager.NETHER_PORTAL_DIRECTION_POSITION.getValue().equals("Above")){deltaY = -0.03F; size = 0.8F;} + Vec3 netherPortalPos = new Vec3(netherPortalBlockPos.getX(), 0, netherPortalBlockPos.getZ()); + double dx = netherPortalPos.x - player.getX(); + double dz = netherPortalPos.z - player.getZ(); + drawCompassSymbol(context, textRenderer, fov, "๐ŸŒ", (float)(Mth.atan2(dz, dx) * (180 / Math.PI)) - 90, camDirection, compassPosition + deltaY, color, size); + } + } + + public static void drawCompassSymbol(GuiGraphicsExtractor context, Font textRenderer, float fov, String symbol, float targetDirection, float camDirection, float y, int color, float scale){ + int screenWidth = context.guiWidth(); + int screenHeight = context.guiHeight(); + + //Determine the position of the symbol depending on the targetDirection and the camDirection + int x = - (int) (screenWidth * 0.5 * GUI_WIDTH * Mth.wrapDegrees(camDirection - targetDirection) / fov); + if (Math.abs(Mth.wrapDegrees(camDirection - targetDirection) / fov)>1.0){ + return; + } + + //Adjust symbol transparency + color = color % 16777216; + int alpha = (int) (255 * (1-Math.abs(Math.sin(Math.toRadians(camDirection - targetDirection))))); + color += 16777216 * alpha; + + //Scale the GUI + var matrices = context.pose(); + var before = new Matrix3x2f(matrices); + matrices.scale(scale, scale); + + if (SettingsManager.COMPASS_STYLE.getValueAsString().equals("Shadows")) { + context.centeredText(textRenderer, Component.literal(symbol), (int) ((screenWidth / 2f + x) / scale), (int) ((screenHeight * y) / scale - textRenderer.lineHeight / 2f), color); + } else { + context.text(textRenderer, symbol,(int) ((screenWidth / 2f + x) / scale - textRenderer.width(symbol) / 2f), (int) ((screenHeight * y)/scale - textRenderer.lineHeight / 2f), color, false); + } + + matrices.set(before); + } + + public static void saveValues() { + Path configPath = FabricLoader.getInstance().getConfigDir().resolve(serverId).resolve(MOD_ID + ".json"); + try { + Files.createDirectories(configPath.getParent()); + try (Writer writer = Files.newBufferedWriter(configPath)) { + GSON.toJson(valueMap, writer); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void loadData() { + Path configPath = FabricLoader.getInstance().getConfigDir().resolve(serverId).resolve(MOD_ID + ".json"); + try (Reader reader = Files.newBufferedReader(configPath)) { + Type type = new TypeToken>() {}.getType(); + valueMap = GSON.fromJson(reader, type); + } catch (IOException e) { + e.printStackTrace(); + return; + } + + if(valueMap.containsKey("deathPointBlockPos")){ + deathPointBlockPos = stringToBlockPos(valueMap.get("deathPointBlockPos")); + } + if(valueMap.containsKey("deathDimension")){ + deathDimension = ResourceKey.create(Registries.DIMENSION, Identifier.tryParse(valueMap.get("deathDimension"))); + } + if(valueMap.containsKey("netherPortalBlockPos")){ + netherPortalBlockPos = stringToBlockPos(valueMap.get("netherPortalBlockPos")); + } + } + + private static String blockPosToString(BlockPos pos){ + return pos.getX() + "," + pos.getY() + "," + pos.getZ(); + } + + private static String registryKeyToString(ResourceKey key){ + return key.identifier().toString(); + } - LOGGER.info("Hello Fabric world!"); + private static BlockPos stringToBlockPos(String str){ + String[] coords = str.split(","); + return new BlockPos( + Integer.parseInt(coords[0]), + Integer.parseInt(coords[1]), + Integer.parseInt(coords[2]) + ); } } \ No newline at end of file diff --git a/src/client/java/fr/madu59/bettercompass/config/Option.java b/src/main/java/fr/madu59/bettercompass/config/Option.java similarity index 85% rename from src/client/java/fr/madu59/bettercompass/config/Option.java rename to src/main/java/fr/madu59/bettercompass/config/Option.java index a905b75..52b2d72 100644 --- a/src/client/java/fr/madu59/bettercompass/config/Option.java +++ b/src/main/java/fr/madu59/bettercompass/config/Option.java @@ -1,8 +1,8 @@ package fr.madu59.bettercompass.config; -import java.util.List; +import net.minecraft.client.resources.language.I18n; -import net.minecraft.client.resource.language.I18n; +import java.util.List; public class Option { public String id; @@ -39,11 +39,11 @@ public String getId() { } public String getName() { - return I18n.translate(this.name); + return I18n.get(this.name); } public String getDescription() { - return I18n.translate(this.description); + return I18n.get(this.description); } public List getPossibleValues(){ @@ -52,9 +52,9 @@ public List getPossibleValues(){ public String getValueAsString() { if( value instanceof Boolean boolValue) { - return boolValue ? I18n.translate("better-compass.config.enabled") : I18n.translate("better-compass.config.disabled"); + return boolValue ? I18n.get("better-compass.config.enabled") : I18n.get("better-compass.config.disabled"); } - return I18n.translate(this.value.toString()); + return I18n.get(this.value.toString()); } public int getValueAsIndex(){ diff --git a/src/client/java/fr/madu59/bettercompass/config/SettingsManager.java b/src/main/java/fr/madu59/bettercompass/config/SettingsManager.java similarity index 67% rename from src/client/java/fr/madu59/bettercompass/config/SettingsManager.java rename to src/main/java/fr/madu59/bettercompass/config/SettingsManager.java index 810e157..fae9f1e 100644 --- a/src/client/java/fr/madu59/bettercompass/config/SettingsManager.java +++ b/src/main/java/fr/madu59/bettercompass/config/SettingsManager.java @@ -3,18 +3,19 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; - import fr.madu59.bettercompass.BetterCompass; import net.fabricmc.loader.api.FabricLoader; -import java.io.*; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; import java.lang.reflect.Type; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; public class SettingsManager { - public static List