From af8e2906bdef21c5100eb67d56775a8c7c4d6ea6 Mon Sep 17 00:00:00 2001 From: Tara Date: Sun, 22 Jan 2023 13:30:03 -0700 Subject: [PATCH 01/28] Compile against new LZ --- gradle.properties | 4 ++-- src/main/resources/META-INF/mods.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 1c9bb6e..c2bb92f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,5 +5,5 @@ org.gradle.daemon=false mc_version=1.19.2 forge_version=43.2.3 -myversion=1.1.2.5 -libz_version=1.0.3.6 \ No newline at end of file +myversion=1.1.2.6 +libz_version=1.0.3.7 \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 592385b..64e919c 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -19,7 +19,7 @@ modId="watchmydurability" #mandatory # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it # ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata # see the associated build.gradle script for how to populate this completely automatically during a build -version="1.1.2.5" #mandatory +version="1.1.2.6" #mandatory # A display name for the mod displayName="Watch My Durability" #mandatory # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ From 0f250f76bb070b40224906d2814f1d65d078ddbe Mon Sep 17 00:00:00 2001 From: Aria Date: Wed, 1 Feb 2023 19:42:04 -0700 Subject: [PATCH 02/28] Make executable --- gradlew | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradlew b/gradlew index a69d9cb..abd9309 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,5 @@ #!/bin/sh - +# # # Copyright © 2015-2021 the original authors. # From 5a47daf797f211fc863338fdad5a406488c179bd Mon Sep 17 00:00:00 2001 From: Aria Date: Wed, 22 Feb 2023 02:42:55 -0700 Subject: [PATCH 03/28] Upgrade to 1.18.2 --- gradle.properties | 8 ++++---- gradle/wrapper/gradle-wrapper.properties | 2 +- .../dev/zontreck/mcmods/CheckInventory.java | 19 ++++++++++++++++--- .../zontreck/mcmods/WatchMyDurability.java | 11 ++++++----- .../mcmods/configs/WMDClientConfig.java | 4 ++-- ...sRenderer.java => HeartsRenderer.disabled} | 0 src/main/resources/META-INF/mods.toml | 10 +++++----- 7 files changed, 34 insertions(+), 20 deletions(-) rename src/main/java/dev/zontreck/mcmods/gui/{HeartsRenderer.java => HeartsRenderer.disabled} (100%) diff --git a/gradle.properties b/gradle.properties index c2bb92f..9d338dd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -mc_version=1.19.2 -forge_version=43.2.3 -myversion=1.1.2.6 -libz_version=1.0.3.7 \ No newline at end of file +mc_version=1.18.2 +forge_version=40.2.1 +myversion=1.1.2.7 +libz_version=1.0.4.9 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8049c68..ae04661 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/dev/zontreck/mcmods/CheckInventory.java b/src/main/java/dev/zontreck/mcmods/CheckInventory.java index 30481b6..8153c94 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckInventory.java +++ b/src/main/java/dev/zontreck/mcmods/CheckInventory.java @@ -7,11 +7,16 @@ import java.util.TimerTask; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.libzontreck.chat.ChatColorFactory; +import dev.zontreck.libzontreck.chat.HoverTip; import dev.zontreck.libzontreck.chat.ChatColor.ColorOptions; import dev.zontreck.mcmods.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.core.NonNullList; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextComponent; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; @@ -56,9 +61,10 @@ public class CheckInventory extends TimerTask if(current.shouldGiveAlert()) { String Msg = ChatColor.doColors("!Dark_Red!!bold!You need to eat!"); - Minecraft.getInstance().player.displayClientMessage(Component.literal(Msg), false); + Component chat = new TextComponent(Msg); + Minecraft.getInstance().player.displayClientMessage(chat, false); - SoundEvent sv = SoundEvents.WARDEN_ROAR; // It sounds like a growling stomach + SoundEvent sv = SoundEvents.WOLF_GROWL; // It sounds like a growling stomach Soundify(sv); } @@ -115,7 +121,14 @@ public class CheckInventory extends TimerTask Soundify(theSound); - Component X = Component.literal(replaced); + + MutableComponent X = new TextComponent(replaced); + + HoverEvent he = HoverTip.getItem(is1); + Style s = Style.EMPTY.withFont(Style.DEFAULT_FONT).withHoverEvent(he); + X=X.withStyle(s); + + Minecraft.getInstance().player.displayClientMessage(X, false); break; // Rule applies, break out of this loop, move to next item. } diff --git a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java index 5b09c46..bf85d94 100644 --- a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java @@ -4,7 +4,6 @@ import com.mojang.logging.LogUtils; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.mcmods.configs.WMDClientConfig; -import dev.zontreck.mcmods.gui.HeartsRenderer; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraftforge.common.MinecraftForge; @@ -18,6 +17,8 @@ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.event.server.ServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.client.event.ClientPlayerNetworkEvent; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent.LoggedInEvent; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent.LoggedOutEvent; import java.util.Timer; @@ -51,7 +52,7 @@ public class WatchMyDurability modEventBus.addListener(this::commonSetup); ModLoadingContext.get().registerConfig(Type.CLIENT, WMDClientConfig.SPEC, "watchmydurability-client.toml"); - MinecraftForge.EVENT_BUS.register(new HeartsRenderer()); + //MinecraftForge.EVENT_BUS.register(new HeartsRenderer()); // Register ourselves for server and other game events we are interested in MinecraftForge.EVENT_BUS.register(this); } @@ -97,7 +98,7 @@ public class WatchMyDurability { @SubscribeEvent - public static void onJoin(ClientPlayerNetworkEvent.LoggingIn event){ + public static void onJoin(LoggedInEvent event){ // Joined //LOGGER.info("PLAYER LOGGED IN"); LOGGER.info(WMDPrefix+": : : PLAYER LOGGED IN : : :"); @@ -105,14 +106,14 @@ public class WatchMyDurability } @SubscribeEvent - public static void onLeave(ClientPlayerNetworkEvent.LoggingOut event){ + public static void onLeave(LoggedOutEvent event){ //LOGGER.info("PLAYER LOGGED OUT"); LOGGER.info(WMDPrefix+": : : PLAYER LOGGED OUT : : :"); WatchMyDurability.isInGame=false; } @SubscribeEvent - public static void onClone(ClientPlayerNetworkEvent.Clone event) + public static void onClone(ClientPlayerNetworkEvent.RespawnEvent event) { LOGGER.info(WMDPrefix+": : : : PLAYER RESPAWNED OR MOVED TO A NEW WORLD : : : :"); diff --git a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java b/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java index 28b3369..0235027 100644 --- a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java +++ b/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java @@ -12,7 +12,7 @@ public class WMDClientConfig { public static ForgeConfigSpec.ConfigValue> alertPercents; public static ForgeConfigSpec.ConfigValue> alertMessages; public static ForgeConfigSpec.ConfigValue TimerVal; - public static ForgeConfigSpec.ConfigValue EnableExtraHearts; + //public static ForgeConfigSpec.ConfigValue EnableExtraHearts; public static ForgeConfigSpec.ConfigValue EnableHealthAlert; static{ @@ -33,7 +33,7 @@ public class WMDClientConfig { BUILDER.pop(); BUILDER.push("General"); - EnableExtraHearts = BUILDER.comment("Whether to enable the extra hearts rendering").define("compress_hearts", false); + //EnableExtraHearts = BUILDER.comment("Whether to enable the extra hearts rendering").define("compress_hearts", false); EnableHealthAlert = BUILDER.comment("The following was added for a friend. If you need reminders to eat in order to heal, turn the below option on").define("watchMyHunger", false); diff --git a/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java b/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.disabled similarity index 100% rename from src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java rename to src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.disabled diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 64e919c..04b3026 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -6,7 +6,7 @@ # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml modLoader="javafml" #mandatory # A version range to match for said mod loader - for regular FML @Mod it will be the forge version -loaderVersion="[43,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +loaderVersion="[40,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. license="GPL-v2" @@ -19,7 +19,7 @@ modId="watchmydurability" #mandatory # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it # ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata # see the associated build.gradle script for how to populate this completely automatically during a build -version="1.1.2.6" #mandatory +version="1.1.2.7" #mandatory # A display name for the mod displayName="Watch My Durability" #mandatory # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ @@ -55,7 +55,7 @@ Edit the config file to customize the alerts # Does this dependency have to exist - if not, ordering below must be specified mandatory=true #mandatory # The version range of the dependency - versionRange="[43,)" #mandatory + versionRange="[40,)" #mandatory # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory ordering="NONE" # Side this dependency is applied on - BOTH, CLIENT or SERVER @@ -65,12 +65,12 @@ Edit the config file to customize the alerts modId="minecraft" mandatory=true # This version range declares a minimum of the current minecraft version up to but not including the next major version - versionRange="[1.19.2,1.20)" + versionRange="[1.18.2,1.19)" ordering="NONE" side="CLIENT" [[dependencies.watchmydurability]] modId="libzontreck" mandatory=true - versionRange="[1.0.3.5,)" + versionRange="[1.0.4.9,1.0.5.0)" ordering="NONE" side="CLIENT" \ No newline at end of file From c07662bd29b4c8d1e2f0f0488986aad606a1bf3f Mon Sep 17 00:00:00 2001 From: Aria Date: Wed, 22 Feb 2023 02:44:06 -0700 Subject: [PATCH 04/28] Disable hearts renderer --- .../HeartsRenderer.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/{java/dev/zontreck/mcmods/gui/HeartsRenderer.disabled => disabledJavaFiles/HeartsRenderer.txt} (100%) diff --git a/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.disabled b/src/main/disabledJavaFiles/HeartsRenderer.txt similarity index 100% rename from src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.disabled rename to src/main/disabledJavaFiles/HeartsRenderer.txt From 3aee097fbcfb7f840ec3023d681b0f0f50c9f959 Mon Sep 17 00:00:00 2001 From: Aria Date: Wed, 22 Feb 2023 02:45:41 -0700 Subject: [PATCH 05/28] Update pack mcmeta. --- src/main/resources/pack.mcmeta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index 427b564..ccfcf37 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -3,6 +3,6 @@ "description": "Watch My Durability Resources", "pack_format": 9, "forge:resource_pack_format": 9, - "forge:data_pack_format": 10 + "forge:data_pack_format": 9 } } From 9f8b5582f1ef043a9bca0d401b11efbaf684c57a Mon Sep 17 00:00:00 2001 From: Aria Date: Mon, 6 Mar 2023 02:26:39 -0700 Subject: [PATCH 06/28] Update WMD to new LibZontreck API --- build.gradle | 5 ++--- gradle.properties | 4 ++-- src/main/resources/META-INF/mods.toml | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index aafb708..885035e 100644 --- a/build.gradle +++ b/build.gradle @@ -137,7 +137,6 @@ dependencies { implementation fg.deobf("dev.zontreck:libzontreck:${mc_version}-${libz_version}:dev") runtimeOnly fg.deobf("dev.zontreck:libzontreck:${mc_version}-${libz_version}") - compileOnly fg.deobf("dev.zontreck:libzontreck:${mc_version}-${libz_version}:dev") // Real mod deobf dependency examples - these get remapped to your current mappings // compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency @@ -157,9 +156,9 @@ jar { attributes([ "Specification-Title" : "watchmydurability", "Specification-Vendor" : "Zontreck", - "Specification-Version" : "1", // We are version 1 of ourselves + "Specification-Version" : "${myversion}", // We are version 1 of ourselves "Implementation-Title" : project.name, - "Implementation-Version" : project.jar.archiveVersion, + "Implementation-Version" : "${myversion}", "Implementation-Vendor" : "ZNI Creations", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") ]) diff --git a/gradle.properties b/gradle.properties index 9d338dd..30a2ffa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,5 +5,5 @@ org.gradle.daemon=false mc_version=1.18.2 forge_version=40.2.1 -myversion=1.1.2.7 -libz_version=1.0.4.9 \ No newline at end of file +myversion=1.1.3.0306230216 +libz_version=1.0.5.0306230154 \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 04b3026..4d3e479 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -9,7 +9,7 @@ modLoader="javafml" #mandatory loaderVersion="[40,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. -license="GPL-v2" +license="GPL-v3" # A URL to refer people to when problems occur with this mod #issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional # A list of mods - how many allowed here is determined by the individual mod loader @@ -19,7 +19,7 @@ modId="watchmydurability" #mandatory # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it # ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata # see the associated build.gradle script for how to populate this completely automatically during a build -version="1.1.2.7" #mandatory +version="${file.jarVersion}" #mandatory # A display name for the mod displayName="Watch My Durability" #mandatory # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ @@ -71,6 +71,6 @@ Edit the config file to customize the alerts [[dependencies.watchmydurability]] modId="libzontreck" mandatory=true - versionRange="[1.0.4.9,1.0.5.0)" + versionRange="[1.0.5.0,1.0.6.0)" ordering="NONE" side="CLIENT" \ No newline at end of file From 574faa7b8d8fa38d21f8e8d62e7b5963adefb058 Mon Sep 17 00:00:00 2001 From: Aria Date: Sat, 22 Apr 2023 03:31:22 -0700 Subject: [PATCH 07/28] Push update for 1.19.4 --- README.md | 2 +- build.gradle | 6 +++++- gradle.properties | 8 ++++---- .../dev/zontreck/mcmods/CheckInventory.java | 18 +++++++++++------ .../zontreck/mcmods/WatchMyDurability.java | 20 +++++++++++++------ src/main/resources/META-INF/mods.toml | 2 +- 6 files changed, 37 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 2911c5f..13bb5a8 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ HOW TO BUILD On your platform of choice ``` -gradlew clean jar +gradlew clean build ``` diff --git a/build.gradle b/build.gradle index 885035e..7a07657 100644 --- a/build.gradle +++ b/build.gradle @@ -124,7 +124,7 @@ repositories { // dir 'libs' // } maven { - name = "ZNI Creations" + name = "Aria's Creations" url = "https://maven.zontreck.dev" } } @@ -187,3 +187,7 @@ publishing { tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation } + +artifacts { + archives jar +} diff --git a/gradle.properties b/gradle.properties index 30a2ffa..ee5a3f9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -mc_version=1.18.2 -forge_version=40.2.1 -myversion=1.1.3.0306230216 -libz_version=1.0.5.0306230154 \ No newline at end of file +mc_version=1.19.4 +forge_version=45.0.46 +myversion=1.1.4.0422230321 +libz_version=1.0.7.0422230320 diff --git a/src/main/java/dev/zontreck/mcmods/CheckInventory.java b/src/main/java/dev/zontreck/mcmods/CheckInventory.java index 8153c94..5182ddf 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckInventory.java +++ b/src/main/java/dev/zontreck/mcmods/CheckInventory.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.TimerTask; +import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.libzontreck.chat.ChatColorFactory; import dev.zontreck.libzontreck.chat.HoverTip; @@ -16,21 +17,26 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; -import net.minecraft.network.chat.TextComponent; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -public class CheckInventory extends TimerTask -{ +public class CheckInventory implements Runnable { + private static final CheckInventory inst = new CheckInventory(); + public static CheckInventory getInstance(){ + return inst; + } @Override public void run() { try { if(!WatchMyDurability.isInGame)return; + + DelayedExecutorService.getInstance().schedule(this, + WMDClientConfig.TimerVal.get()); //WatchMyDurability.LOGGER.info("TICKING CHECK INVENTORY EVENT"); // Get the player inventory Inventory inv = Minecraft.getInstance().player.getInventory(); @@ -61,10 +67,10 @@ public class CheckInventory extends TimerTask if(current.shouldGiveAlert()) { String Msg = ChatColor.doColors("!Dark_Red!!bold!You need to eat!"); - Component chat = new TextComponent(Msg); + Component chat = Component.literal(Msg); Minecraft.getInstance().player.displayClientMessage(chat, false); - SoundEvent sv = SoundEvents.WOLF_GROWL; // It sounds like a growling stomach + SoundEvent sv = SoundEvents.WARDEN_ROAR; // It sounds like a growling stomach Soundify(sv); } @@ -122,7 +128,7 @@ public class CheckInventory extends TimerTask - MutableComponent X = new TextComponent(replaced); + MutableComponent X = Component.literal(replaced); HoverEvent he = HoverTip.getItem(is1); Style s = Style.EMPTY.withFont(Style.DEFAULT_FONT).withHoverEvent(he); diff --git a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java index bf85d94..0e21452 100644 --- a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java @@ -2,11 +2,13 @@ package dev.zontreck.mcmods; import com.mojang.logging.LogUtils; +import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.mcmods.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModLoadingContext; @@ -17,11 +19,10 @@ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.event.server.ServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.client.event.ClientPlayerNetworkEvent; -import net.minecraftforge.client.event.ClientPlayerNetworkEvent.LoggedInEvent; -import net.minecraftforge.client.event.ClientPlayerNetworkEvent.LoggedOutEvent; import java.util.Timer; +import net.minecraftforge.network.NetworkEvent; import org.slf4j.Logger; // The value here should match an entry in the META-INF/mods.toml file @@ -85,8 +86,13 @@ public class WatchMyDurability //LOGGER.info("HELLO FROM CLIENT SETUP"); //LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName()); WatchMyDurability.CurrentUser = Minecraft.getInstance().getUser(); + + DelayedExecutorService.getInstance().schedule(CheckInventory.getInstance(), + WMDClientConfig.TimerVal.get()); - time.schedule(new CheckInventory(), WMDClientConfig.TimerVal.get()*1000, WMDClientConfig.TimerVal.get()*1000); + //time.schedule(new CheckInventory(), + //WMDClientConfig.TimerVal.get()*1000, + //WMDClientConfig.TimerVal.get()*1000); ItemRegistry.Initialize(); @@ -98,22 +104,24 @@ public class WatchMyDurability { @SubscribeEvent - public static void onJoin(LoggedInEvent event){ + public static void onJoin(ClientPlayerNetworkEvent.LoggingIn event){ // Joined //LOGGER.info("PLAYER LOGGED IN"); LOGGER.info(WMDPrefix+": : : PLAYER LOGGED IN : : :"); WatchMyDurability.isInGame=true; + + DelayedExecutorService.getInstance().schedule(CheckInventory.getInstance(), WMDClientConfig.TimerVal.get()); } @SubscribeEvent - public static void onLeave(LoggedOutEvent event){ + public static void onLeave(ClientPlayerNetworkEvent.LoggingOut event){ //LOGGER.info("PLAYER LOGGED OUT"); LOGGER.info(WMDPrefix+": : : PLAYER LOGGED OUT : : :"); WatchMyDurability.isInGame=false; } @SubscribeEvent - public static void onClone(ClientPlayerNetworkEvent.RespawnEvent event) + public static void onClone(ClientPlayerNetworkEvent.Clone event) { LOGGER.info(WMDPrefix+": : : : PLAYER RESPAWNED OR MOVED TO A NEW WORLD : : : :"); diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 4d3e479..12ebb16 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -71,6 +71,6 @@ Edit the config file to customize the alerts [[dependencies.watchmydurability]] modId="libzontreck" mandatory=true - versionRange="[1.0.5.0,1.0.6.0)" + versionRange="[1.0.6.0,1.0.7.0)" ordering="NONE" side="CLIENT" \ No newline at end of file From 8289bdecaf91b9a6f1350a1d9f95cad3004425cd Mon Sep 17 00:00:00 2001 From: Aria Date: Sat, 22 Apr 2023 03:47:29 -0700 Subject: [PATCH 08/28] Patch for mods.toml to support 1.19 (oops) --- gradle.properties | 2 +- src/main/resources/META-INF/mods.toml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index ee5a3f9..655251c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,5 +5,5 @@ org.gradle.daemon=false mc_version=1.19.4 forge_version=45.0.46 -myversion=1.1.4.0422230321 +myversion=1.1.4.0422230346 libz_version=1.0.7.0422230320 diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 12ebb16..7289f15 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -6,7 +6,7 @@ # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml modLoader="javafml" #mandatory # A version range to match for said mod loader - for regular FML @Mod it will be the forge version -loaderVersion="[40,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +loaderVersion="[45,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. license="GPL-v3" @@ -55,7 +55,7 @@ Edit the config file to customize the alerts # Does this dependency have to exist - if not, ordering below must be specified mandatory=true #mandatory # The version range of the dependency - versionRange="[40,)" #mandatory + versionRange="[45,)" #mandatory # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory ordering="NONE" # Side this dependency is applied on - BOTH, CLIENT or SERVER @@ -65,12 +65,12 @@ Edit the config file to customize the alerts modId="minecraft" mandatory=true # This version range declares a minimum of the current minecraft version up to but not including the next major version - versionRange="[1.18.2,1.19)" + versionRange="[1.19.4,1.20)" ordering="NONE" side="CLIENT" [[dependencies.watchmydurability]] modId="libzontreck" mandatory=true - versionRange="[1.0.6.0,1.0.7.0)" + versionRange="[1.0.7.0,1.0.8.0)" ordering="NONE" side="CLIENT" \ No newline at end of file From b45e9c3fec38e821a47259c565e0e0700191985d Mon Sep 17 00:00:00 2001 From: Aria Date: Mon, 15 May 2023 22:06:21 -0700 Subject: [PATCH 09/28] Update to 1.19.3, update DelayedExecutorService references. --- build.gradle | 6 ++++-- gradle.properties | 10 ++++++---- settings.gradle | 1 + src/main/java/dev/zontreck/mcmods/CheckInventory.java | 7 ++++++- .../java/dev/zontreck/mcmods/WatchMyDurability.java | 5 +++-- src/main/resources/META-INF/mods.toml | 6 +++--- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 7a07657..ae2a734 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'eclipse' id 'maven-publish' id 'net.minecraftforge.gradle' version '5.1.+' + id 'org.parchmentmc.librarian.forgegradle' version '1.+' } version = "${mc_version}-${myversion}" @@ -26,7 +27,8 @@ minecraft { // // Use non-default mappings at your own risk. They may not always work. // Simply re-run your setup task after changing the mappings to update your workspace. - mappings channel: 'official', version: "${mc_version}" + // mappings channel: 'official', version: "${mc_version}" + mappings channel: 'parchment', version: "${parchment_version}-${mc_version}" // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Currently, this location cannot be changed from the default. @@ -159,7 +161,7 @@ jar { "Specification-Version" : "${myversion}", // We are version 1 of ourselves "Implementation-Title" : project.name, "Implementation-Version" : "${myversion}", - "Implementation-Vendor" : "ZNI Creations", + "Implementation-Vendor" : "Aria's Creations", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") ]) } diff --git a/gradle.properties b/gradle.properties index 655251c..3d41277 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,9 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -mc_version=1.19.4 -forge_version=45.0.46 -myversion=1.1.4.0422230346 -libz_version=1.0.7.0422230320 +mc_version=1.19.3 +forge_version=44.1.0 +myversion=1.1.4.0515232205 +libz_version=1.0.7.0515232132 + +parchment_version=2023.03.12 \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index fb61b26..c1a3a81 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,5 +2,6 @@ pluginManagement { repositories { gradlePluginPortal() maven { url = 'https://maven.minecraftforge.net/' } + maven { url = 'https://maven.parchmentmc.org' } // Add this line } } \ No newline at end of file diff --git a/src/main/java/dev/zontreck/mcmods/CheckInventory.java b/src/main/java/dev/zontreck/mcmods/CheckInventory.java index 5182ddf..d011393 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckInventory.java +++ b/src/main/java/dev/zontreck/mcmods/CheckInventory.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.TimerTask; +import dev.zontreck.ariaslib.terminal.Task; import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.libzontreck.chat.ChatColorFactory; @@ -22,9 +23,13 @@ import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -public class CheckInventory implements Runnable { +public class CheckInventory extends Task { private static final CheckInventory inst = new CheckInventory(); + public CheckInventory() { + super("checkinv", true); + } + public static CheckInventory getInstance(){ return inst; } diff --git a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java index 0e21452..8f73259 100644 --- a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java @@ -86,9 +86,8 @@ public class WatchMyDurability //LOGGER.info("HELLO FROM CLIENT SETUP"); //LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName()); WatchMyDurability.CurrentUser = Minecraft.getInstance().getUser(); + DelayedExecutorService.setup(); - DelayedExecutorService.getInstance().schedule(CheckInventory.getInstance(), - WMDClientConfig.TimerVal.get()); //time.schedule(new CheckInventory(), //WMDClientConfig.TimerVal.get()*1000, @@ -109,6 +108,7 @@ public class WatchMyDurability //LOGGER.info("PLAYER LOGGED IN"); LOGGER.info(WMDPrefix+": : : PLAYER LOGGED IN : : :"); WatchMyDurability.isInGame=true; + DelayedExecutorService.start(); DelayedExecutorService.getInstance().schedule(CheckInventory.getInstance(), WMDClientConfig.TimerVal.get()); } @@ -118,6 +118,7 @@ public class WatchMyDurability //LOGGER.info("PLAYER LOGGED OUT"); LOGGER.info(WMDPrefix+": : : PLAYER LOGGED OUT : : :"); WatchMyDurability.isInGame=false; + DelayedExecutorService.stop(); } @SubscribeEvent diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 7289f15..8618688 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -6,7 +6,7 @@ # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml modLoader="javafml" #mandatory # A version range to match for said mod loader - for regular FML @Mod it will be the forge version -loaderVersion="[45,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +loaderVersion="[44,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. license="GPL-v3" @@ -55,7 +55,7 @@ Edit the config file to customize the alerts # Does this dependency have to exist - if not, ordering below must be specified mandatory=true #mandatory # The version range of the dependency - versionRange="[45,)" #mandatory + versionRange="[44,)" #mandatory # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory ordering="NONE" # Side this dependency is applied on - BOTH, CLIENT or SERVER @@ -65,7 +65,7 @@ Edit the config file to customize the alerts modId="minecraft" mandatory=true # This version range declares a minimum of the current minecraft version up to but not including the next major version - versionRange="[1.19.4,1.20)" + versionRange="[1.19.3,1.20)" ordering="NONE" side="CLIENT" [[dependencies.watchmydurability]] From 928e57c104825f5855ff8817cbf76c5ea3562071 Mon Sep 17 00:00:00 2001 From: zontreck Date: Sun, 19 Nov 2023 06:14:32 -0700 Subject: [PATCH 10/28] Start updating to 1.20 --- build.gradle | 213 +++++++++++++---------- gradle.properties | 59 ++++++- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 61574 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 14 +- gradlew.bat | 1 + settings.gradle | 7 +- src/main/resources/META-INF/mods.toml | 64 +++---- src/main/resources/pack.mcmeta | 14 +- 9 files changed, 234 insertions(+), 141 deletions(-) diff --git a/build.gradle b/build.gradle index ae2a734..efa804f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,16 @@ plugins { id 'eclipse' + id 'idea' id 'maven-publish' - id 'net.minecraftforge.gradle' version '5.1.+' - id 'org.parchmentmc.librarian.forgegradle' version '1.+' + id 'net.minecraftforge.gradle' version '[6.0,6.2)' } -version = "${mc_version}-${myversion}" -group = 'dev.zontreck' // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = 'WatchMyDurability' +version = mod_version +group = mod_group_id + +base { + archivesName = mod_id +} // Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. java.toolchain.languageVersion = JavaLanguageVersion.of(17) @@ -23,19 +26,40 @@ minecraft { // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md // // Parchment is an unofficial project maintained by ParchmentMC, separate from MinecraftForge - // Additional setup is needed to use their mappings: https://github.com/ParchmentMC/Parchment/wiki/Getting-Started + // Additional setup is needed to use their mappings: https://parchmentmc.org/docs/getting-started // // Use non-default mappings at your own risk. They may not always work. // Simply re-run your setup task after changing the mappings to update your workspace. - // mappings channel: 'official', version: "${mc_version}" - mappings channel: 'parchment', version: "${parchment_version}-${mc_version}" + mappings channel: mapping_channel, version: mapping_version - // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Currently, this location cannot be changed from the default. + // When true, this property will have all Eclipse/IntelliJ IDEA run configurations run the "prepareX" task for the given run configuration before launching the game. + // In most cases, it is not necessary to enable. + // enableEclipsePrepareRuns = true + // enableIdeaPrepareRuns = true + + // This property allows configuring Gradle's ProcessResources task(s) to run on IDE output locations before launching the game. + // It is REQUIRED to be set to true for this template to function. + // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html + copyIdeResources = true + + // When true, this property will add the folder name of all declared run configurations to generated IDE run configurations. + // The folder name can be set on a run configuration using the "folderName" property. + // By default, the folder name of a run configuration is the name of the Gradle project containing it. + // generateRunFolders = true + + // This property enables access transformers for use in development. + // They will be applied to the Minecraft artifact. + // The access transformer file can be anywhere in the project. + // However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge. + // This default location is a best practice to automatically put the file in the right place in the final jar. + // See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information. + // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Default run configurations. // These can be tweaked, removed, or duplicated as needed. runs { - client { + // applies to all the run configs below + configureEach { workingDirectory project.file('run') // Recommended logging data for a userdev environment @@ -50,66 +74,36 @@ minecraft { // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels property 'forge.logging.console.level', 'debug' - // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. - property 'forge.enabledGameTestNamespaces', 'watchmydurability' - mods { - watchmydurability { + "${mod_id}" { source sourceSets.main } } } + client { + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + property 'forge.enabledGameTestNamespaces', mod_id + } + server { - workingDirectory project.file('run') - - property 'forge.logging.markers', 'REGISTRIES' - - property 'forge.logging.console.level', 'debug' - - property 'forge.enabledGameTestNamespaces', 'watchmydurability' - - mods { - watchmydurability { - source sourceSets.main - } - } + property 'forge.enabledGameTestNamespaces', mod_id + args '--nogui' } // This run config launches GameTestServer and runs all registered gametests, then exits. // By default, the server will crash when no gametests are provided. // The gametest system is also enabled by default for other run configs under the /test command. gameTestServer { - workingDirectory project.file('run') - - property 'forge.logging.markers', 'REGISTRIES' - - property 'forge.logging.console.level', 'debug' - - property 'forge.enabledGameTestNamespaces', 'watchmydurability' - - mods { - watchmydurability { - source sourceSets.main - } - } + property 'forge.enabledGameTestNamespaces', mod_id } data { - workingDirectory project.file('run') - - property 'forge.logging.markers', 'REGISTRIES' - - property 'forge.logging.console.level', 'debug' + // example of overriding the workingDirectory set in configureEach above + workingDirectory project.file('run-data') // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. - args '--mod', 'watchmydurability', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') - - mods { - watchmydurability { - source sourceSets.main - } - } + args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') } } } @@ -121,61 +115,106 @@ repositories { // Put repositories for dependencies here // ForgeGradle automatically adds the Forge maven and Maven Central for you - // If you have mod jar dependencies in ./libs, you can declare them as a repository like so: + // If you have mod jar dependencies in ./libs, you can declare them as a repository like so. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver // flatDir { // dir 'libs' // } maven { - name = "Aria's Creations" - url = "https://maven.zontreck.dev" + name = "Aria's Creations Caches" + url = "https://maven.zontreck.dev/repository/internal" + } + // Put repositories for dependencies here + // ForgeGradle automatically adds the Forge maven and Maven Central for you + + // If you have mod jar dependencies in ./libs, you can declare them as a repository like so: + flatDir { + dir 'libs' + } + + //maven { + // name = "CurseMaven" + // url = "https://cursemaven.com" + //} + + maven { + name = "zontreck Maven" + url = "https://maven.zontreck.dev/repository/zontreck" } } dependencies { - // Specify the version of Minecraft to use. If this is any group other than 'net.minecraft', it is assumed - // that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied. - // The userdev artifact is a special name and will get all sorts of transformations applied to it. - minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" + // Specify the version of Minecraft to use. + // Any artifact can be supplied so long as it has a "userdev" classifier artifact and is a compatible patcher artifact. + // The "userdev" classifier will be requested and setup by ForgeGradle. + // If the group id is "net.minecraft" and the artifact id is one of ["client", "server", "joined"], + // then special handling is done to allow a setup of a vanilla dependency without the use of an external repository. + minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" - implementation fg.deobf("dev.zontreck:libzontreck:${mc_version}-${libz_version}:dev") - runtimeOnly fg.deobf("dev.zontreck:libzontreck:${mc_version}-${libz_version}") - - // Real mod deobf dependency examples - these get remapped to your current mappings - // compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency - // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency - // implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency + compileOnly fg.deobf("dev.zontreck:LibZontreck:${minecraft_version}-${libzontreck}") + runtimeOnly fg.deobf("dev.zontreck:LibZontreck:${minecraft_version}-${libzontreck}") + // Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings + // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime + // compileOnly fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}") + // compileOnly fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}") + // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}-forge:${jei_version}") - // Examples using mod jars from ./libs + // Example mod dependency using a mod jar from ./libs with a flat dir repository + // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar + // The group id is ignored when searching -- in this case, it is "blank" // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}") - // For more info... + // For more info: // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html // http://www.gradle.org/docs/current/userguide/dependency_management.html } -jar { - manifest { - attributes([ - "Specification-Title" : "watchmydurability", - "Specification-Vendor" : "Zontreck", - "Specification-Version" : "${myversion}", // We are version 1 of ourselves - "Implementation-Title" : project.name, - "Implementation-Version" : "${myversion}", - "Implementation-Vendor" : "Aria's Creations", - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") - ]) +// This block of code expands all declared replace properties in the specified resource targets. +// A missing property will result in an error. Properties are expanded using ${} Groovy notation. +// When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments. +// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html +tasks.named('processResources', ProcessResources).configure { + var replaceProperties = [ + minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range, + forge_version: forge_version, forge_version_range: forge_version_range, + loader_version_range: loader_version_range, + mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, + mod_authors: mod_authors, mod_description: mod_description, + ] + inputs.properties replaceProperties + + filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { + expand replaceProperties + [project: project] } } -// Example configuration to allow publishing using the maven-publish plugin -// This is the preferred method to reobfuscate your jar file -jar.finalizedBy('reobfJar') -// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing -// publish.dependsOn('reobfJar') +// Example for how to get properties into the manifest for reading at runtime. +tasks.named('jar', Jar).configure { + manifest { + attributes([ + 'Specification-Title' : mod_id, + 'Specification-Vendor' : mod_authors, + 'Specification-Version' : '1', // We are version 1 of ourselves + 'Implementation-Title' : project.name, + 'Implementation-Version' : project.jar.archiveVersion, + 'Implementation-Vendor' : mod_authors, + 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ]) + } + // This is the preferred method to reobfuscate your jar file + finalizedBy 'reobfJar' +} + +// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing: +// tasks.named('publish').configure { +// dependsOn 'reobfJar' +// } + +// Example configuration to allow publishing using the maven-publish plugin publishing { publications { - mavenJava(MavenPublication) { + register('mavenJava', MavenPublication) { artifact jar } } @@ -189,7 +228,3 @@ publishing { tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation } - -artifacts { - archives jar -} diff --git a/gradle.properties b/gradle.properties index 3d41277..bffcd76 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,9 +3,58 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -mc_version=1.19.3 -forge_version=44.1.0 -myversion=1.1.4.0515232205 -libz_version=1.0.7.0515232132 +libzontreck=1.0.8.1119230513 -parchment_version=2023.03.12 \ No newline at end of file +## Environment Properties + +# The Minecraft version must agree with the Forge version to get a valid artifact +minecraft_version=1.20.1 +# The Minecraft version range can use any release version of Minecraft as bounds. +# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly +# as they do not follow standard versioning conventions. +minecraft_version_range=[1.20.1,1.21) +# The Forge version must agree with the Minecraft version to get a valid artifact +forge_version=47.2.0 +# The Forge version range can use any version of Forge as bounds or match the loader version range +forge_version_range=[47,) +# The loader version range can only use the major version of Forge/FML as bounds +loader_version_range=[47,) +# The mapping channel to use for mappings. +# The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"]. +# Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin. +# +# | Channel | Version | | +# |-----------|----------------------|--------------------------------------------------------------------------------| +# | official | MCVersion | Official field/method names from Mojang mapping files | +# | parchment | YYYY.MM.DD-MCVersion | Open community-sourced parameter names and javadocs layered on top of official | +# +# You must be aware of the Mojang license when using the 'official' or 'parchment' mappings. +# See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md +# +# Parchment is an unofficial project maintained by ParchmentMC, separate from Minecraft Forge. +# Additional setup is needed to use their mappings, see https://parchmentmc.org/docs/getting-started +mapping_channel=parchment +# The mapping version to query from the mapping channel. +# This must match the format required by the mapping channel. +mapping_version=2023.09.03-1.20.1 + + +## Mod Properties + +# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} +# Must match the String constant located in the main mod class annotated with @Mod. +mod_id=watchmydurability +# The human-readable display name for the mod. +mod_name=WatchMyDurability +# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. +mod_license=GPLv3 +# The mod version. See https://semver.org/ +mod_version=1.1.5.1119230555 +# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. +# This should match the base package used for the mod sources. +# See https://maven.apache.org/guides/mini/guide-naming-conventions.html +mod_group_id=dev.zontreck +# The authors of the mod. This is a simple text string that is used for display purposes in the mod list. +mod_authors=zontreck +# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. +mod_description=Watches the durability tools, and or your hunger. \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644 GIT binary patch delta 36524 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%0DGK?7GHTj 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 VwlMN}`%er%aGR6olj~j${vQ;P=LY}) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661..37aef8d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index abd9309..65dcd68 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,5 @@ #!/bin/sh -# + # # Copyright © 2015-2021 the original authors. # @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,10 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' @@ -143,12 +143,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac diff --git a/gradlew.bat b/gradlew.bat index 53a6b23..6689b85 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% diff --git a/settings.gradle b/settings.gradle index c1a3a81..891d211 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,10 @@ pluginManagement { repositories { gradlePluginPortal() - maven { url = 'https://maven.minecraftforge.net/' } - maven { url = 'https://maven.parchmentmc.org' } // Add this line + maven { url = "https://maven.zontreck.dev/repository/internal" } } +} + +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' } \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 8618688..48a7887 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -6,32 +6,30 @@ # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml modLoader="javafml" #mandatory # A version range to match for said mod loader - for regular FML @Mod it will be the forge version -loaderVersion="[44,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +loaderVersion="${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. -license="GPL-v3" +license="${mod_license}" # A URL to refer people to when problems occur with this mod #issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional # A list of mods - how many allowed here is determined by the individual mod loader [[mods]] #mandatory # The modid of the mod -modId="watchmydurability" #mandatory -# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it -# ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata -# see the associated build.gradle script for how to populate this completely automatically during a build -version="${file.jarVersion}" #mandatory - # A display name for the mod -displayName="Watch My Durability" #mandatory -# A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ +modId="${mod_id}" #mandatory +# The version number of the mod +version="${mod_version}" #mandatory +# A display name for the mod +displayName="${mod_name}" #mandatory +# A URL to query for updates for this mod. See the JSON update specification https://docs.minecraftforge.net/en/latest/misc/updatechecker/ #updateJSONURL="https://change.me.example.invalid/updates.json" #optional # A URL for the "homepage" for this mod, displayed in the mod UI #displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional # A file name (in the root of the mod JAR) containing a logo for display -# logoFile="examplemod.png" #optional +#logoFile="examplemod.png" #optional # A text field displayed in the mod UI -credits="zontreck @ ZNI Creations" #optional +#credits="" #optional # A text field displayed in the mod UI -authors="zontreck" #optional +authors="${mod_authors}" #optional # Display Test controls the display for your mod in the server connection screen # MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. # IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. @@ -41,36 +39,38 @@ authors="zontreck" #optional #displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional) # The description text for the mod (multi line!) (#mandatory) -description=''' -This mod watches durability of an item. - -This is most useful for armor or weapons to alert you to the fact that your armor or weapon might break soon. - -Edit the config file to customize the alerts -''' +description='''${mod_description}''' # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. -[[dependencies.watchmydurability]] #optional +[[dependencies.${mod_id}]] #optional # the modid of the dependency modId="forge" #mandatory # Does this dependency have to exist - if not, ordering below must be specified mandatory=true #mandatory # The version range of the dependency - versionRange="[44,)" #mandatory - # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory + versionRange="${forge_version_range}" #mandatory + # An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory + # BEFORE - This mod is loaded BEFORE the dependency + # AFTER - This mod is loaded AFTER the dependency ordering="NONE" - # Side this dependency is applied on - BOTH, CLIENT or SERVER - side="CLIENT" + # Side this dependency is applied on - BOTH, CLIENT, or SERVER + side="BOTH" # Here's another dependency -[[dependencies.watchmydurability]] +[[dependencies.${mod_id}]] modId="minecraft" mandatory=true -# This version range declares a minimum of the current minecraft version up to but not including the next major version - versionRange="[1.19.3,1.20)" + # This version range declares a minimum of the current minecraft version up to but not including the next major version + versionRange="${minecraft_version_range}" ordering="NONE" - side="CLIENT" -[[dependencies.watchmydurability]] + side="BOTH" + +[[dependencies.${mod_id}]] modId="libzontreck" mandatory=true - versionRange="[1.0.7.0,1.0.8.0)" + versionRange="[1.0.8,1.0.9)" ordering="NONE" - side="CLIENT" \ No newline at end of file + side="BOTH" +# Features are specific properties of the game environment, that you may want to declare you require. This example declares +# that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't +# stop your mod loading on the server for example. +#[features.${mod_id}] +#openGLVersion="[3.2,)" \ No newline at end of file diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index ccfcf37..eca79ae 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,8 +1,8 @@ { - "pack": { - "description": "Watch My Durability Resources", - "pack_format": 9, - "forge:resource_pack_format": 9, - "forge:data_pack_format": 9 - } -} + "pack": { + "description": { + "text": "${mod_id} resources" + }, + "pack_format": 15 + } +} \ No newline at end of file From 0b94cbbc2fa1348f4bc44685a628f1013cdf3853 Mon Sep 17 00:00:00 2001 From: zontreck Date: Sun, 19 Nov 2023 07:07:42 -0700 Subject: [PATCH 11/28] Mod is now functional on 1.20, but hunger watch is not functional --- build.gradle | 1 + gradle.properties | 2 +- src/main/java/dev/zontreck/mcmods/CheckInventory.java | 2 -- src/main/resources/META-INF/mods.toml | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index efa804f..01c4267 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ plugins { id 'idea' id 'maven-publish' id 'net.minecraftforge.gradle' version '[6.0,6.2)' + id 'org.parchmentmc.librarian.forgegradle' version '1.+' } version = mod_version diff --git a/gradle.properties b/gradle.properties index bffcd76..c44fcec 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -libzontreck=1.0.8.1119230513 +libzontreck=1.0.8.1119230646 ## Environment Properties diff --git a/src/main/java/dev/zontreck/mcmods/CheckInventory.java b/src/main/java/dev/zontreck/mcmods/CheckInventory.java index d011393..4651199 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckInventory.java +++ b/src/main/java/dev/zontreck/mcmods/CheckInventory.java @@ -8,9 +8,7 @@ import java.util.TimerTask; import dev.zontreck.ariaslib.terminal.Task; import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; -import dev.zontreck.libzontreck.chat.ChatColorFactory; import dev.zontreck.libzontreck.chat.HoverTip; -import dev.zontreck.libzontreck.chat.ChatColor.ColorOptions; import dev.zontreck.mcmods.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.core.NonNullList; diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 48a7887..85d5cd9 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -66,7 +66,7 @@ description='''${mod_description}''' [[dependencies.${mod_id}]] modId="libzontreck" mandatory=true - versionRange="[1.0.8,1.0.9)" + versionRange="[1.20.1-1.0.8,)" ordering="NONE" side="BOTH" # Features are specific properties of the game environment, that you may want to declare you require. This example declares From 5d62d175aff5825f662aba146caefa9cfa15bb30 Mon Sep 17 00:00:00 2001 From: zontreck Date: Sun, 19 Nov 2023 08:00:37 -0700 Subject: [PATCH 12/28] Add a hunger watcher instead of just health --- .../java/dev/zontreck/mcmods/CheckHealth.java | 49 +++++++++++++++++++ .../java/dev/zontreck/mcmods/CheckHunger.java | 40 +++++++++++++++ .../dev/zontreck/mcmods/CheckInventory.java | 29 +---------- src/main/java/dev/zontreck/mcmods/Hunger.java | 27 ++++++++++ .../zontreck/mcmods/WatchMyDurability.java | 10 ++++ .../mcmods/configs/WMDClientConfig.java | 5 +- 6 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 src/main/java/dev/zontreck/mcmods/CheckHealth.java create mode 100644 src/main/java/dev/zontreck/mcmods/CheckHunger.java create mode 100644 src/main/java/dev/zontreck/mcmods/Hunger.java diff --git a/src/main/java/dev/zontreck/mcmods/CheckHealth.java b/src/main/java/dev/zontreck/mcmods/CheckHealth.java new file mode 100644 index 0000000..b8a8156 --- /dev/null +++ b/src/main/java/dev/zontreck/mcmods/CheckHealth.java @@ -0,0 +1,49 @@ +package dev.zontreck.mcmods; + +import dev.zontreck.ariaslib.terminal.Task; +import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.mcmods.configs.WMDClientConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; + +public class CheckHealth extends Task +{ + private static CheckHealth inst = new CheckHealth(); + public static CheckHealth getInstance() + { + return inst; + } + public CheckHealth() { + super("CheckHealth", true); + } + + @Override + public void run() { + + + // Hijack this timer so we dont need to register yet another + if(!WMDClientConfig.EnableHealthAlert.get())return; + + + Health current = Health.of(Minecraft.getInstance().player); + if(WatchMyDurability.LastHealth == null)WatchMyDurability.LastHealth = current; + else{ + if(current.identical(WatchMyDurability.LastHealth))return; + } + + // Good to proceed + if(current.shouldGiveAlert()) + { + String Msg = ChatColor.doColors("!Dark_Red!!bold!You need to eat!"); + Component chat = Component.literal(Msg); + Minecraft.getInstance().player.displayClientMessage(chat, false); + + SoundEvent sv = SoundEvents.WARDEN_ROAR; // It sounds like a growling stomach + WatchMyDurability.Soundify(sv); + } + + WatchMyDurability.LastHealth=current; + } +} diff --git a/src/main/java/dev/zontreck/mcmods/CheckHunger.java b/src/main/java/dev/zontreck/mcmods/CheckHunger.java new file mode 100644 index 0000000..bb072ed --- /dev/null +++ b/src/main/java/dev/zontreck/mcmods/CheckHunger.java @@ -0,0 +1,40 @@ +package dev.zontreck.mcmods; + +import dev.zontreck.ariaslib.terminal.Task; +import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.mcmods.configs.WMDClientConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; + +public class CheckHunger extends Task +{ + public CheckHunger() + { + super("CheckHunger", true); + } + + @Override + public void run() { + if(!WMDClientConfig.EnableHungerAlert.get()) return; + + Hunger current = Hunger.of(Minecraft.getInstance().player); + + if(current.identical()) return; + if(current.shouldGiveAlert()) + { + + String Msg = ChatColor.doColors("!Dark_Red!!bold!You need to eat!"); + Component chat = Component.literal(Msg); + Minecraft.getInstance().player.displayClientMessage(chat, false); + + SoundEvent sv = SoundEvents.WARDEN_ROAR; // It sounds like a growling stomach + WatchMyDurability.Soundify(sv); + } + + WatchMyDurability.LastHunger = current; + + + } +} diff --git a/src/main/java/dev/zontreck/mcmods/CheckInventory.java b/src/main/java/dev/zontreck/mcmods/CheckInventory.java index 4651199..2974f57 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckInventory.java +++ b/src/main/java/dev/zontreck/mcmods/CheckInventory.java @@ -58,27 +58,6 @@ public class CheckInventory extends Task { } - // Hijack this timer so we dont need to register yet another - if(!WMDClientConfig.EnableHealthAlert.get())return; - Health current = Health.of(Minecraft.getInstance().player); - if(WatchMyDurability.LastHealth == null)WatchMyDurability.LastHealth = current; - else{ - if(current.identical(WatchMyDurability.LastHealth))return; - } - - // Good to proceed - if(current.shouldGiveAlert()) - { - String Msg = ChatColor.doColors("!Dark_Red!!bold!You need to eat!"); - Component chat = Component.literal(Msg); - Minecraft.getInstance().player.displayClientMessage(chat, false); - - SoundEvent sv = SoundEvents.WARDEN_ROAR; // It sounds like a growling stomach - Soundify(sv); - } - - WatchMyDurability.LastHealth=current; - } public void PushItems(String type, List stack) @@ -99,12 +78,6 @@ public class CheckInventory extends Task { ItemRegistry.register(type,items); } - public void Soundify(SoundEvent sound) - { - //WatchMyDurability.LOGGER.info("PLAY ALERT SOUND"); - Minecraft.getInstance().player.playSound(sound, 1.0f, 1.0f); - } - public void checkList(String type, NonNullList stacks){ Integer slotNum = 0; //boolean ret=false; @@ -127,7 +100,7 @@ public class CheckInventory extends Task { WatchMyDurability.LOGGER.info("Enqueue alert for an item. Playing sound for item: "+is1.getDisplayName().getString()); SoundEvent theSound = SoundEvents.ITEM_BREAK; - Soundify(theSound); + WatchMyDurability.Soundify(theSound); diff --git a/src/main/java/dev/zontreck/mcmods/Hunger.java b/src/main/java/dev/zontreck/mcmods/Hunger.java new file mode 100644 index 0000000..2b0f7cb --- /dev/null +++ b/src/main/java/dev/zontreck/mcmods/Hunger.java @@ -0,0 +1,27 @@ +package dev.zontreck.mcmods; + +import net.minecraft.world.entity.player.Player; + +public class Hunger +{ + public boolean needsToEat; + + public static Hunger of(Player player) + { + Hunger hunger = new Hunger(); + hunger.needsToEat = player.getFoodData().needsFood(); + return hunger; + } + + public boolean shouldGiveAlert() + { + if(needsToEat && !WatchMyDurability.LastHunger.needsToEat) return true; + else return false; + } + + public boolean identical() + { + if(needsToEat == WatchMyDurability.LastHunger.needsToEat) return true; + return false; + } +} diff --git a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java index 8f73259..94108d3 100644 --- a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java @@ -7,6 +7,7 @@ import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.mcmods.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.client.User; +import net.minecraft.sounds.SoundEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.IEventBus; @@ -39,6 +40,7 @@ public class WatchMyDurability public static boolean isInGame = false; // This locks the timer thread public static ItemRegistry REGISTRY; public static Health LastHealth; + public static Hunger LastHunger; public static String WMDPrefix; @@ -64,6 +66,12 @@ public class WatchMyDurability //LOGGER.info("HELLO FROM COMMON SETUP"); } + + public static void Soundify(SoundEvent sound) + { + //WatchMyDurability.LOGGER.info("PLAY ALERT SOUND"); + Minecraft.getInstance().player.playSound(sound, 1.0f, 1.0f); + } // You can use SubscribeEvent and let the Event Bus discover methods to call @SubscribeEvent public void onServerStarting(ServerStartingEvent event) @@ -96,6 +104,7 @@ public class WatchMyDurability ItemRegistry.Initialize(); } + } @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) @@ -111,6 +120,7 @@ public class WatchMyDurability DelayedExecutorService.start(); DelayedExecutorService.getInstance().schedule(CheckInventory.getInstance(), WMDClientConfig.TimerVal.get()); + DelayedExecutorService.getInstance().schedule(CheckHealth.getInstance(), WMDClientConfig.TimerVal.get()); } @SubscribeEvent diff --git a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java b/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java index 0235027..f12611a 100644 --- a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java +++ b/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java @@ -14,6 +14,7 @@ public class WMDClientConfig { public static ForgeConfigSpec.ConfigValue TimerVal; //public static ForgeConfigSpec.ConfigValue EnableExtraHearts; public static ForgeConfigSpec.ConfigValue EnableHealthAlert; + public static ForgeConfigSpec.ConfigValue EnableHungerAlert; static{ List alerts1 = new ArrayList<>(); @@ -34,8 +35,8 @@ public class WMDClientConfig { BUILDER.push("General"); //EnableExtraHearts = BUILDER.comment("Whether to enable the extra hearts rendering").define("compress_hearts", false); - EnableHealthAlert = BUILDER.comment("The following was added for a friend. If you need reminders to eat in order to heal, turn the below option on").define("watchMyHunger", false); - + EnableHealthAlert = BUILDER.comment("The following was added for a friend. If you need reminders to eat in order to heal, turn the below option on").define("watchMyHealth", false); + EnableHungerAlert = BUILDER.comment("This is a newer setting to watch your hunger status instead of your hunger to alert when you need to eat").define("watchMyHunger", true); SPEC=BUILDER.build(); } From d002986525f24275c192df1f6bc5136a787fbd98 Mon Sep 17 00:00:00 2001 From: zontreck Date: Sun, 19 Nov 2023 08:19:21 -0700 Subject: [PATCH 13/28] Finish updating to 1.20 --- gradle.properties | 2 +- src/main/java/dev/zontreck/mcmods/CheckHealth.java | 1 + src/main/java/dev/zontreck/mcmods/CheckHunger.java | 8 ++++++++ src/main/java/dev/zontreck/mcmods/CheckInventory.java | 3 +-- src/main/java/dev/zontreck/mcmods/WatchMyDurability.java | 5 +++-- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index c44fcec..1a963b2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ mod_name=WatchMyDurability # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1.1.5.1119230555 +mod_version=1.1.5.1119230818 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/dev/zontreck/mcmods/CheckHealth.java b/src/main/java/dev/zontreck/mcmods/CheckHealth.java index b8a8156..8f94592 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckHealth.java +++ b/src/main/java/dev/zontreck/mcmods/CheckHealth.java @@ -1,6 +1,7 @@ package dev.zontreck.mcmods; import dev.zontreck.ariaslib.terminal.Task; +import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.mcmods.configs.WMDClientConfig; import net.minecraft.client.Minecraft; diff --git a/src/main/java/dev/zontreck/mcmods/CheckHunger.java b/src/main/java/dev/zontreck/mcmods/CheckHunger.java index bb072ed..02cd33f 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckHunger.java +++ b/src/main/java/dev/zontreck/mcmods/CheckHunger.java @@ -1,6 +1,7 @@ package dev.zontreck.mcmods; import dev.zontreck.ariaslib.terminal.Task; +import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.mcmods.configs.WMDClientConfig; import net.minecraft.client.Minecraft; @@ -10,6 +11,11 @@ import net.minecraft.sounds.SoundEvents; public class CheckHunger extends Task { + private static CheckHunger inst = new CheckHunger(); + public static CheckHunger getInstance() + { + return inst; + } public CheckHunger() { super("CheckHunger", true); @@ -19,7 +25,9 @@ public class CheckHunger extends Task public void run() { if(!WMDClientConfig.EnableHungerAlert.get()) return; + Hunger current = Hunger.of(Minecraft.getInstance().player); + if(WatchMyDurability.LastHunger == null)WatchMyDurability.LastHunger = new Hunger(); if(current.identical()) return; if(current.shouldGiveAlert()) diff --git a/src/main/java/dev/zontreck/mcmods/CheckInventory.java b/src/main/java/dev/zontreck/mcmods/CheckInventory.java index 2974f57..330e89e 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckInventory.java +++ b/src/main/java/dev/zontreck/mcmods/CheckInventory.java @@ -38,8 +38,7 @@ public class CheckInventory extends Task { if(!WatchMyDurability.isInGame)return; - DelayedExecutorService.getInstance().schedule(this, - WMDClientConfig.TimerVal.get()); + //WatchMyDurability.LOGGER.info("TICKING CHECK INVENTORY EVENT"); // Get the player inventory Inventory inv = Minecraft.getInstance().player.getInventory(); diff --git a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java index 94108d3..3fdfef6 100644 --- a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java @@ -119,8 +119,9 @@ public class WatchMyDurability WatchMyDurability.isInGame=true; DelayedExecutorService.start(); - DelayedExecutorService.getInstance().schedule(CheckInventory.getInstance(), WMDClientConfig.TimerVal.get()); - DelayedExecutorService.getInstance().schedule(CheckHealth.getInstance(), WMDClientConfig.TimerVal.get()); + DelayedExecutorService.getInstance().scheduleRepeating(CheckInventory.getInstance(), WMDClientConfig.TimerVal.get()); + DelayedExecutorService.getInstance().scheduleRepeating(CheckHealth.getInstance(), WMDClientConfig.TimerVal.get()); + DelayedExecutorService.getInstance().scheduleRepeating(CheckHunger.getInstance(), WMDClientConfig.TimerVal.get()); } @SubscribeEvent From 1b369a0db5c5e98f699b135ea79f038879391b6e Mon Sep 17 00:00:00 2001 From: zontreck Date: Thu, 14 Dec 2023 22:15:55 -0700 Subject: [PATCH 14/28] Update libzontreck version --- build.gradle | 3 +-- gradle.properties | 4 ++-- src/main/resources/META-INF/mods.toml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 01c4267..1e95daa 100644 --- a/build.gradle +++ b/build.gradle @@ -152,8 +152,7 @@ dependencies { // then special handling is done to allow a setup of a vanilla dependency without the use of an external repository. minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" - compileOnly fg.deobf("dev.zontreck:LibZontreck:${minecraft_version}-${libzontreck}") - runtimeOnly fg.deobf("dev.zontreck:LibZontreck:${minecraft_version}-${libzontreck}") + implementation fg.deobf("dev.zontreck:LibZontreck:${libzontreck}") // Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime // compileOnly fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}") diff --git a/gradle.properties b/gradle.properties index 1a963b2..3144615 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -libzontreck=1.0.8.1119230646 +libzontreck=1.9.121423.1700 ## Environment Properties @@ -49,7 +49,7 @@ mod_name=WatchMyDurability # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1.1.5.1119230818 +mod_version=1.2.121423.2014 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 85d5cd9..9cbfe9e 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -66,7 +66,7 @@ description='''${mod_description}''' [[dependencies.${mod_id}]] modId="libzontreck" mandatory=true - versionRange="[1.20.1-1.0.8,)" + versionRange="[1.9,1.10)" ordering="NONE" side="BOTH" # Features are specific properties of the game environment, that you may want to declare you require. This example declares From f1fce3fbaa91be120fba266d77a6e9d41000e453 Mon Sep 17 00:00:00 2001 From: zontreck Date: Thu, 14 Dec 2023 22:19:05 -0700 Subject: [PATCH 15/28] Update libzontreck version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1e95daa..ed4b4de 100644 --- a/build.gradle +++ b/build.gradle @@ -152,7 +152,7 @@ dependencies { // then special handling is done to allow a setup of a vanilla dependency without the use of an external repository. minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" - implementation fg.deobf("dev.zontreck:LibZontreck:${libzontreck}") + implementation fg.deobf("dev.zontreck:LibZontreckMod:${libzontreck}") // Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime // compileOnly fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}") From bbf4e41abc0debc41121a3906710ac3c913a85df Mon Sep 17 00:00:00 2001 From: zontreck Date: Fri, 15 Dec 2023 19:41:18 -0700 Subject: [PATCH 16/28] Start re-adding the extra hearts function --- build.gradle | 2 +- .../zontreck/mcmods/WatchMyDurability.java | 3 +- .../mcmods/configs/WMDClientConfig.java | 4 +- .../zontreck/mcmods/gui/HeartsRenderer.java | 242 ++++++++++++++++++ .../resources/META-INF/accesstransformer.cfg | 5 + .../watchmydurability/textures/gui/absorb.png | Bin 5383 -> 0 bytes .../watchmydurability/textures/gui/hearts.png | Bin 5160 -> 14200 bytes 7 files changed, 252 insertions(+), 4 deletions(-) create mode 100644 src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java create mode 100644 src/main/resources/META-INF/accesstransformer.cfg delete mode 100644 src/main/resources/assets/watchmydurability/textures/gui/absorb.png diff --git a/build.gradle b/build.gradle index ed4b4de..c43a468 100644 --- a/build.gradle +++ b/build.gradle @@ -54,7 +54,7 @@ minecraft { // However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge. // This default location is a best practice to automatically put the file in the right place in the final jar. // See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information. - // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Default run configurations. // These can be tweaked, removed, or duplicated as needed. diff --git a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java index 3fdfef6..8198f35 100644 --- a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java @@ -5,6 +5,7 @@ import com.mojang.logging.LogUtils; import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.mcmods.configs.WMDClientConfig; +import dev.zontreck.mcmods.gui.HeartsRenderer; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraft.sounds.SoundEvent; @@ -55,7 +56,7 @@ public class WatchMyDurability modEventBus.addListener(this::commonSetup); ModLoadingContext.get().registerConfig(Type.CLIENT, WMDClientConfig.SPEC, "watchmydurability-client.toml"); - //MinecraftForge.EVENT_BUS.register(new HeartsRenderer()); + MinecraftForge.EVENT_BUS.register(new HeartsRenderer()); // Register ourselves for server and other game events we are interested in MinecraftForge.EVENT_BUS.register(this); } diff --git a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java b/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java index f12611a..d26912e 100644 --- a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java +++ b/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java @@ -12,7 +12,7 @@ public class WMDClientConfig { public static ForgeConfigSpec.ConfigValue> alertPercents; public static ForgeConfigSpec.ConfigValue> alertMessages; public static ForgeConfigSpec.ConfigValue TimerVal; - //public static ForgeConfigSpec.ConfigValue EnableExtraHearts; + public static ForgeConfigSpec.ConfigValue EnableExtraHearts; public static ForgeConfigSpec.ConfigValue EnableHealthAlert; public static ForgeConfigSpec.ConfigValue EnableHungerAlert; @@ -34,7 +34,7 @@ public class WMDClientConfig { BUILDER.pop(); BUILDER.push("General"); - //EnableExtraHearts = BUILDER.comment("Whether to enable the extra hearts rendering").define("compress_hearts", false); + EnableExtraHearts = BUILDER.comment("Whether to enable the extra hearts rendering").define("compress_hearts", true); EnableHealthAlert = BUILDER.comment("The following was added for a friend. If you need reminders to eat in order to heal, turn the below option on").define("watchMyHealth", false); EnableHungerAlert = BUILDER.comment("This is a newer setting to watch your hunger status instead of your hunger to alert when you need to eat").define("watchMyHunger", true); diff --git a/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java b/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java new file mode 100644 index 0000000..8892504 --- /dev/null +++ b/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java @@ -0,0 +1,242 @@ +/* + * + * DISCLAIMER: This code was taken from Mantle, and will be modified to fit the needs of this mod, such as adding more heat options. This code is subject to Mantle's license of MIT. + * Despite this code being taken from, and modified/updated to be modern, all textures are my own creation + * This disclaimer is here to give credit where credit is due. The author(s) of mantle have done a absolutely fantastic job. And if Mantle gets updated this shall be removed along with future plans of extra hearts and color options. + * + * + */ + +package dev.zontreck.mcmods.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; + +import dev.zontreck.mcmods.WatchMyDurability; +import dev.zontreck.mcmods.configs.WMDClientConfig; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ai.attributes.AttributeInstance; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.event.RenderGuiOverlayEvent; +import net.minecraftforge.client.gui.overlay.ForgeGui; +import net.minecraftforge.client.gui.overlay.GuiOverlayManager; +import net.minecraftforge.client.gui.overlay.NamedGuiOverlay; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import java.util.Random; + +public class HeartsRenderer { + private static final ResourceLocation ICON_HEARTS = new ResourceLocation(WatchMyDurability.MODID, + "textures/gui/hearts.png"); + private static final ResourceLocation ICON_VANILLA = Gui.GUI_ICONS_LOCATION; + + private final Minecraft mc = Minecraft.getInstance(); + + private int playerHealth = 0; + private int lastPlayerHealth = 0; + private long healthUpdateCounter = 0; + private long lastSystemTime = 0; + private final Random rand = new Random(); + + private int regen; + + /** + * Draws a texture to the screen + * + * @param matrixStack Matrix stack instance + * @param x X position + * @param y Y position + * @param textureX Texture X + * @param textureY Texture Y + * @param width Width to draw + * @param height Height to draw + */ + private void blit(GuiGraphics matrixStack, int x, int y, int textureX, int textureY, int width, int height) { + matrixStack.blit(ICON_HEARTS, x, y, textureX, textureY, width, height); + } + + private void renderHearts(GuiGraphics pGuiGraphics, Player pPlayer, int pX, int pY, int pHeight, int pOffsetHeartIndex, float pMaxHealth, int pCurrentHealth, int pDisplayHealth, int pAbsorptionAmount, boolean pRenderHighlight) { + Random random = new Random(); + HeartType hearttype = HeartType.forPlayer(pPlayer); + int offsetX = 9 * (pPlayer.level().getLevelData().isHardcore() ? 5 : 0); + int maxHearts = Mth.ceil((double)pMaxHealth / 2.0); + int absorbHearts = Mth.ceil((double)pAbsorptionAmount / 2.0); + int maxHealth = maxHearts * 2; + + for(int i1 = maxHearts + absorbHearts - 1; i1 >= 0; --i1) { + int j1 = i1 / 10; + int k1 = i1 % 10; + int x = pX + k1 * 8; + int y = pY - j1; //* pHeight; + int row = y * pHeight; + + + if (pCurrentHealth + pAbsorptionAmount <= 4) { + y += random.nextInt(2); + } + + if (i1 < maxHearts && i1 == pOffsetHeartIndex) { + y -= 2; + } + + this.renderHeart(pGuiGraphics, HeartType.CONTAINER, x, y, offsetX, pRenderHighlight, false, 0); + int j2 = i1 * 2; + boolean flag = i1 >= maxHearts; + if (flag) { + int k2 = j2 - maxHealth; + if (k2 < pAbsorptionAmount) { + boolean halfHeart = k2 + 1 == pAbsorptionAmount; + this.renderHeart(pGuiGraphics, hearttype == HeartType.WITHERED ? hearttype : HeartType.ABSORBING, x, y, offsetX, false, halfHeart, row); + } + } + + boolean flag3; + if (pRenderHighlight && j2 < pDisplayHealth) { + flag3 = j2 + 1 == pDisplayHealth; + this.renderHeart(pGuiGraphics, hearttype, x, y, offsetX, true, flag3, row); + } + + if (j2 < pCurrentHealth) { + flag3 = j2 + 1 == pCurrentHealth; + this.renderHeart(pGuiGraphics, hearttype, x, y, offsetX, false, flag3, row); + } + } + + } + + + private void renderHeart(GuiGraphics pGuiGraphics, HeartType pHeartType, int pX, int pY, int pYOffset, boolean pRenderHighlight, boolean pHalfHeart, int row) { + pGuiGraphics.blit(ICON_HEARTS, pX, pY, pHeartType.getX(row, pHalfHeart, pRenderHighlight), pHeartType.getY(), 9, 9); + } + /* HUD */ + /** + * Event listener + * + * @param event Event instance + */ + @SubscribeEvent(priority = EventPriority.LOW) + public void renderHealthbar(RenderGuiOverlayEvent.Pre event) { + NamedGuiOverlay ActualOverlay = GuiOverlayManager.findOverlay(new ResourceLocation("minecraft:player_health")); + + if (ActualOverlay == null) { + if (GuiOverlayManager.getOverlays() == null) { + WatchMyDurability.LOGGER.info("Overlays non existent?!"); + } + for (NamedGuiOverlay overlay : GuiOverlayManager.getOverlays()) { + // Next print + // LibZontreck.LOGGER.info("GUI OVERLAY: "+overlay.id().getPath()); + + if (overlay.id().getPath().equals("player_health")) { + ActualOverlay = overlay; + break; + } + } + } + if (event.isCanceled() || !WMDClientConfig.EnableExtraHearts.get() || event.getOverlay() != ActualOverlay) { + return; + } + // ensure its visible + if (!(mc.gui instanceof ForgeGui gui) || mc.options.hideGui || !gui.shouldDrawSurvivalElements()) { + return; + } + // extra setup stuff from us + int X = this.mc.getWindow().getGuiScaledWidth() / 2 - 91; + int Y = this.mc.getWindow().getGuiScaledHeight() / 2 + 91; + int updateCounter = this.mc.gui.getGuiTicks(); + long healthBlinkTime = this.mc.gui.healthBlinkTime; + int height = Math.max(10 - (Y - 2), 3); + int offset = -1; + Player player = Minecraft.getInstance().player; + int lastHealth = Minecraft.getInstance().gui.lastHealth; + int displayHealth = Minecraft.getInstance().gui.displayHealth; + boolean flag = healthBlinkTime > (long)updateCounter && (healthBlinkTime - (long)updateCounter) / 3L % 2L == 1L; + + float maxHealth = Math.max((float)player.getAttributeValue(Attributes.MAX_HEALTH), (float)Math.max(displayHealth, lastHealth)); + int absorb = Mth.ceil(player.getAbsorptionAmount()); + + if (player.hasEffect(MobEffects.REGENERATION)) { + offset = updateCounter % Mth.ceil(maxHealth + 5.0F); + } + + renderHearts(event.getGuiGraphics(), player, X, Y, height, offset, maxHealth, lastHealth, Minecraft.getInstance().gui.displayHealth, absorb, flag); + } + + @OnlyIn(Dist.CLIENT) + static enum HeartType { + CONTAINER(0, false), + NORMAL(1, true), + POISONED(2, true), + WITHERED(3, true), + ABSORBING(5, false), + FROZEN(4, false); + + private final int index; + private final boolean canBlink; + + private HeartType(int pIndex, boolean pCanBlink) { + this.index = pIndex; + this.canBlink = pCanBlink; + } + + public int getX(int rowNum, boolean halfHeart, boolean renderHighlight) + { + int heart = rowNum + (halfHeart ? 1 : 0) * 9; + + return heart; + } + + public int getY() + { + switch(this) + { + case CONTAINER -> { + return 144; + } + case POISONED -> { + return 9; + } + case WITHERED -> { + return 18; + } + case FROZEN -> { + return 27; + } + case ABSORBING -> { + return 80; + } + default -> { + // Normal and other unknowns + return 0; + } + } + } + + static HeartsRenderer.HeartType forPlayer(Player pPlayer) { + HeartsRenderer.HeartType hearttype; + if (pPlayer.hasEffect(MobEffects.POISON)) { + hearttype = POISONED; + } else if (pPlayer.hasEffect(MobEffects.WITHER)) { + hearttype = WITHERED; + } else if (pPlayer.isFullyFrozen()) { + hearttype = FROZEN; + } else { + hearttype = NORMAL; + } + + return hearttype; + } + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..b4796c8 --- /dev/null +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,5 @@ +public net.minecraft.client.gui.Gui +public net.minecraft.client.gui.Gui f_279580_ # GUI_ICONS_LOCATION +public net.minecraft.client.gui.Gui f_92974_ # displayHealth +public net.minecraft.client.gui.Gui f_92973_ # lastHealth +public net.minecraft.client.gui.Gui f_92976_ # healthBlinkTime \ No newline at end of file diff --git a/src/main/resources/assets/watchmydurability/textures/gui/absorb.png b/src/main/resources/assets/watchmydurability/textures/gui/absorb.png deleted file mode 100644 index 3e338e79e22b01a9efc25f40cfe2c1a276f7b18a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5383 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 xSGMU+&{M@f=%MnOPHq6mUO6O@ePBvC*>GLkb$ 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 From 80720c7fbf4b4345f8c8875dadf3c26c8810d84b Mon Sep 17 00:00:00 2001 From: zontreck Date: Fri, 15 Dec 2023 23:53:57 -0700 Subject: [PATCH 17/28] Get hearts working again --- .../zontreck/mcmods/gui/HeartsRenderer.java | 350 +++++++++++------- .../watchmydurability/textures/gui/absorb.png | Bin 0 -> 6946 bytes .../watchmydurability/textures/gui/hearts.png | Bin 14200 -> 5965 bytes 3 files changed, 221 insertions(+), 129 deletions(-) create mode 100644 src/main/resources/assets/watchmydurability/textures/gui/absorb.png diff --git a/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java b/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java index 8892504..2f76cae 100644 --- a/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java +++ b/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java @@ -26,8 +26,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.RenderGuiOverlayEvent; import net.minecraftforge.client.gui.overlay.ForgeGui; import net.minecraftforge.client.gui.overlay.GuiOverlayManager; @@ -41,6 +39,8 @@ import java.util.Random; public class HeartsRenderer { private static final ResourceLocation ICON_HEARTS = new ResourceLocation(WatchMyDurability.MODID, "textures/gui/hearts.png"); + private static final ResourceLocation ICON_ABSORB = new ResourceLocation(WatchMyDurability.MODID, + "textures/gui/absorb.png"); private static final ResourceLocation ICON_VANILLA = Gui.GUI_ICONS_LOCATION; private final Minecraft mc = Minecraft.getInstance(); @@ -64,64 +64,12 @@ public class HeartsRenderer { * @param width Width to draw * @param height Height to draw */ - private void blit(GuiGraphics matrixStack, int x, int y, int textureX, int textureY, int width, int height) { - matrixStack.blit(ICON_HEARTS, x, y, textureX, textureY, width, height); + private void blit(GuiGraphics matrixStack, int x, int y, int textureX, int textureY, int width, int height, ResourceLocation resource) { + matrixStack.blit(resource, x, y, textureX, textureY, width, height); } - private void renderHearts(GuiGraphics pGuiGraphics, Player pPlayer, int pX, int pY, int pHeight, int pOffsetHeartIndex, float pMaxHealth, int pCurrentHealth, int pDisplayHealth, int pAbsorptionAmount, boolean pRenderHighlight) { - Random random = new Random(); - HeartType hearttype = HeartType.forPlayer(pPlayer); - int offsetX = 9 * (pPlayer.level().getLevelData().isHardcore() ? 5 : 0); - int maxHearts = Mth.ceil((double)pMaxHealth / 2.0); - int absorbHearts = Mth.ceil((double)pAbsorptionAmount / 2.0); - int maxHealth = maxHearts * 2; - - for(int i1 = maxHearts + absorbHearts - 1; i1 >= 0; --i1) { - int j1 = i1 / 10; - int k1 = i1 % 10; - int x = pX + k1 * 8; - int y = pY - j1; //* pHeight; - int row = y * pHeight; - - - if (pCurrentHealth + pAbsorptionAmount <= 4) { - y += random.nextInt(2); - } - - if (i1 < maxHearts && i1 == pOffsetHeartIndex) { - y -= 2; - } - - this.renderHeart(pGuiGraphics, HeartType.CONTAINER, x, y, offsetX, pRenderHighlight, false, 0); - int j2 = i1 * 2; - boolean flag = i1 >= maxHearts; - if (flag) { - int k2 = j2 - maxHealth; - if (k2 < pAbsorptionAmount) { - boolean halfHeart = k2 + 1 == pAbsorptionAmount; - this.renderHeart(pGuiGraphics, hearttype == HeartType.WITHERED ? hearttype : HeartType.ABSORBING, x, y, offsetX, false, halfHeart, row); - } - } - - boolean flag3; - if (pRenderHighlight && j2 < pDisplayHealth) { - flag3 = j2 + 1 == pDisplayHealth; - this.renderHeart(pGuiGraphics, hearttype, x, y, offsetX, true, flag3, row); - } - - if (j2 < pCurrentHealth) { - flag3 = j2 + 1 == pCurrentHealth; - this.renderHeart(pGuiGraphics, hearttype, x, y, offsetX, false, flag3, row); - } - } - - } - - - private void renderHeart(GuiGraphics pGuiGraphics, HeartType pHeartType, int pX, int pY, int pYOffset, boolean pRenderHighlight, boolean pHalfHeart, int row) { - pGuiGraphics.blit(ICON_HEARTS, pX, pY, pHeartType.getX(row, pHalfHeart, pRenderHighlight), pHeartType.getY(), 9, 9); - } /* HUD */ + /** * Event listener * @@ -152,91 +100,235 @@ public class HeartsRenderer { if (!(mc.gui instanceof ForgeGui gui) || mc.options.hideGui || !gui.shouldDrawSurvivalElements()) { return; } + Entity renderViewEnity = this.mc.getCameraEntity(); + if (!(renderViewEnity instanceof Player player)) { + return; + } + gui.setupOverlayRenderState(true, false); + + this.mc.getProfiler().push("health"); + // extra setup stuff from us - int X = this.mc.getWindow().getGuiScaledWidth() / 2 - 91; - int Y = this.mc.getWindow().getGuiScaledHeight() / 2 + 91; + int left_height = gui.leftHeight; + int width = this.mc.getWindow().getGuiScaledWidth(); + int height = this.mc.getWindow().getGuiScaledHeight(); int updateCounter = this.mc.gui.getGuiTicks(); - long healthBlinkTime = this.mc.gui.healthBlinkTime; - int height = Math.max(10 - (Y - 2), 3); - int offset = -1; - Player player = Minecraft.getInstance().player; - int lastHealth = Minecraft.getInstance().gui.lastHealth; - int displayHealth = Minecraft.getInstance().gui.displayHealth; - boolean flag = healthBlinkTime > (long)updateCounter && (healthBlinkTime - (long)updateCounter) / 3L % 2L == 1L; - float maxHealth = Math.max((float)player.getAttributeValue(Attributes.MAX_HEALTH), (float)Math.max(displayHealth, lastHealth)); - int absorb = Mth.ceil(player.getAbsorptionAmount()); + // start default forge/mc rendering + // changes are indicated by comment - if (player.hasEffect(MobEffects.REGENERATION)) { - offset = updateCounter % Mth.ceil(maxHealth + 5.0F); + int health = Mth.ceil(player.getHealth()); + boolean highlight = this.healthUpdateCounter > (long) updateCounter + && (this.healthUpdateCounter - (long) updateCounter) / 3L % 2L == 1L; + + if (health < this.playerHealth && player.invulnerableTime > 0) { + this.lastSystemTime = Util.getMillis(); + this.healthUpdateCounter = (updateCounter + 20); + } else if (health > this.playerHealth && player.invulnerableTime > 0) { + this.lastSystemTime = Util.getMillis(); + this.healthUpdateCounter = (updateCounter + 10); } - renderHearts(event.getGuiGraphics(), player, X, Y, height, offset, maxHealth, lastHealth, Minecraft.getInstance().gui.displayHealth, absorb, flag); + if (Util.getMillis() - this.lastSystemTime > 1000L) { + this.playerHealth = health; + this.lastPlayerHealth = health; + this.lastSystemTime = Util.getMillis(); + } + + this.playerHealth = health; + int healthLast = this.lastPlayerHealth; + + AttributeInstance attrMaxHealth = player.getAttribute(Attributes.MAX_HEALTH); + float healthMax = attrMaxHealth == null ? 0 : (float) attrMaxHealth.getValue(); + float absorb = Mth.ceil(player.getAbsorptionAmount()); + + // CHANGE: simulate 10 hearts max if there's more, so vanilla only renders one + // row max + healthMax = Math.min(healthMax, 20f); + health = Math.min(health, 20); + absorb = Math.min(absorb, 20); + + int healthRows = Mth.ceil((healthMax + absorb) / 2.0F / 10.0F); + int rowHeight = Math.max(10 - (healthRows - 2), 3); + + this.rand.setSeed(updateCounter * 312871L); + + int left = width / 2 - 91; + int top = height - left_height; + // change: these are unused below, unneeded? should these adjust the Forge + // variable? + // left_height += (healthRows * rowHeight); + // if (rowHeight != 10) left_height += 10 - rowHeight; + + this.regen = -1; + if (player.hasEffect(MobEffects.REGENERATION)) { + this.regen = updateCounter % 25; + } + + assert this.mc.level != null; + final int TOP = 9 * (this.mc.level.getLevelData().isHardcore() ? 5 : 0); + final int BACKGROUND = (highlight ? 25 : 16); + int MARGIN = 16; + if (player.hasEffect(MobEffects.POISON)) + MARGIN += 36; + else if (player.hasEffect(MobEffects.WITHER)) + MARGIN += 72; + float absorbRemaining = absorb; + + GuiGraphics matrixStack = event.getGuiGraphics(); + for (int i = Mth.ceil((healthMax + absorb) / 2.0F) - 1; i >= 0; --i) { + int row = Mth.ceil((float) (i + 1) / 10.0F) - 1; + int x = left + i % 10 * 8; + int y = top - row * rowHeight; + + if (health <= 4) + y += this.rand.nextInt(2); + if (i == this.regen) + y -= 2; + + this.blit(matrixStack, x, y, BACKGROUND, TOP, 9, 9, ICON_VANILLA); + + if (highlight) { + if (i * 2 + 1 < healthLast) { + this.blit(matrixStack, x, y, MARGIN + 54, TOP, 9, 9, ICON_VANILLA); // 6 + } else if (i * 2 + 1 == healthLast) { + this.blit(matrixStack, x, y, MARGIN + 63, TOP, 9, 9, ICON_VANILLA); // 7 + } + } + + if (absorbRemaining > 0.0F) { + if (absorbRemaining == absorb && absorb % 2.0F == 1.0F) { + this.blit(matrixStack, x, y, MARGIN + 153, TOP, 9, 9, ICON_VANILLA); // 17 + absorbRemaining -= 1.0F; + } else { + this.blit(matrixStack, x, y, MARGIN + 144, TOP, 9, 9, ICON_VANILLA); // 16 + absorbRemaining -= 2.0F; + } + } else { + if (i * 2 + 1 < health) { + this.blit(matrixStack, x, y, MARGIN + 36, TOP, 9, 9, ICON_VANILLA); // 4 + } else if (i * 2 + 1 == health) { + this.blit(matrixStack, x, y, MARGIN + 45, TOP, 9, 9, ICON_VANILLA); // 5 + } + } + } + + this.renderExtraHearts(matrixStack, left, top, player); + this.renderExtraAbsorption(matrixStack, left, top - rowHeight, player); + + RenderSystem.setShaderTexture(0, ICON_VANILLA); + gui.leftHeight += 10; + if (absorb > 0) { + gui.leftHeight += 10; + } + + event.setCanceled(true); + RenderSystem.disableBlend(); + this.mc.getProfiler().pop(); + MinecraftForge.EVENT_BUS + .post(new RenderGuiOverlayEvent.Post(mc.getWindow(), event.getGuiGraphics(), event.getPartialTick(), ActualOverlay)); } - @OnlyIn(Dist.CLIENT) - static enum HeartType { - CONTAINER(0, false), - NORMAL(1, true), - POISONED(2, true), - WITHERED(3, true), - ABSORBING(5, false), - FROZEN(4, false); - - private final int index; - private final boolean canBlink; - - private HeartType(int pIndex, boolean pCanBlink) { - this.index = pIndex; - this.canBlink = pCanBlink; + /** + * Gets the texture from potion effects + * + * @param player Player instance + * @return Texture offset for potion effects + */ + private int getPotionOffset(Player player) { + int potionOffset = 0; + MobEffectInstance potion = player.getEffect(MobEffects.WITHER); + if (potion != null) { + potionOffset = 18; } - - public int getX(int rowNum, boolean halfHeart, boolean renderHighlight) - { - int heart = rowNum + (halfHeart ? 1 : 0) * 9; - - return heart; + potion = player.getEffect(MobEffects.POISON); + if (potion != null) { + potionOffset = 9; } + assert this.mc.level != null; + if (this.mc.level.getLevelData().isHardcore()) { + potionOffset += 27; + } + return potionOffset; + } - public int getY() - { - switch(this) - { - case CONTAINER -> { - return 144; - } - case POISONED -> { - return 9; - } - case WITHERED -> { - return 18; - } - case FROZEN -> { - return 27; - } - case ABSORBING -> { - return 80; - } - default -> { - // Normal and other unknowns - return 0; - } + /** + * Renders the health above 10 hearts + * + * @param matrixStack Matrix stack instance + * @param xBasePos Health bar top corner + * @param yBasePos Health bar top corner + * @param player Player instance + */ + private void renderExtraHearts(GuiGraphics matrixStack, int xBasePos, int yBasePos, Player player) { + int potionOffset = this.getPotionOffset(player); + + // Extra hearts + RenderSystem.setShaderTexture(0, ICON_HEARTS); + int hp = Mth.ceil(player.getHealth()); + this.renderCustomHearts(matrixStack, xBasePos, yBasePos, potionOffset, hp, false); + } + + /** + * Renders the absorption health above 10 hearts + * + * @param matrixStack Matrix stack instance + * @param xBasePos Health bar top corner + * @param yBasePos Health bar top corner + * @param player Player instance + */ + private void renderExtraAbsorption(GuiGraphics matrixStack, int xBasePos, int yBasePos, Player player) { + int potionOffset = this.getPotionOffset(player); + + // Extra hearts + RenderSystem.setShaderTexture(0, ICON_ABSORB); + int absorb = Mth.ceil(player.getAbsorptionAmount()); + this.renderCustomHearts(matrixStack, xBasePos, yBasePos, potionOffset, absorb, true); + } + + /** + * Gets the texture offset from the regen effect + * + * @param i Heart index + * @param offset Current offset + */ + private int getYRegenOffset(int i, int offset) { + return i + offset == this.regen ? -2 : 0; + } + + /** + * Shared logic to render custom hearts + * + * @param matrixStack Matrix stack instance + * @param xBasePos Health bar top corner + * @param yBasePos Health bar top corner + * @param potionOffset Offset from the potion effect + * @param count Number to render + * @param absorb If true, render absorption hearts + */ + private void renderCustomHearts(GuiGraphics matrixStack, int xBasePos, int yBasePos, int potionOffset, int count, + boolean absorb) { + int regenOffset = absorb ? 10 : 0; + for (int iter = 0; iter < count / 20; iter++) { + int renderHearts = (count - 20 * (iter + 1)) / 2; + int heartIndex = iter % 11; + if (renderHearts > 10) { + renderHearts = 10; } - } - - static HeartsRenderer.HeartType forPlayer(Player pPlayer) { - HeartsRenderer.HeartType hearttype; - if (pPlayer.hasEffect(MobEffects.POISON)) { - hearttype = POISONED; - } else if (pPlayer.hasEffect(MobEffects.WITHER)) { - hearttype = WITHERED; - } else if (pPlayer.isFullyFrozen()) { - hearttype = FROZEN; - } else { - hearttype = NORMAL; + for (int i = 0; i < renderHearts; i++) { + int y = this.getYRegenOffset(i, regenOffset); + if (absorb) { + this.blit(matrixStack, xBasePos + 8 * i, yBasePos + y, 0, 54, 9, 9, ICON_ABSORB); + } + this.blit(matrixStack, xBasePos + 8 * i, yBasePos + y, 18 * heartIndex, potionOffset, 9, 9, ICON_HEARTS); + } + if (count % 2 == 1 && renderHearts < 10) { + int y = this.getYRegenOffset(renderHearts, regenOffset); + if (absorb) { + this.blit(matrixStack, xBasePos + 8 * renderHearts, yBasePos + y, 0, 54, 9, 9, ICON_ABSORB); + } + this.blit(matrixStack, xBasePos + 8 * renderHearts, yBasePos + y, 9 + 18 * heartIndex, potionOffset, 9, 9, ICON_HEARTS); } - - return hearttype; } } } diff --git a/src/main/resources/assets/watchmydurability/textures/gui/absorb.png b/src/main/resources/assets/watchmydurability/textures/gui/absorb.png new file mode 100644 index 0000000000000000000000000000000000000000..37d83b505fb64501fc6389244a9148186c9e5137 GIT binary patch literal 6946 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 Date: Fri, 15 Dec 2023 23:56:35 -0700 Subject: [PATCH 18/28] Move hearts render over to Aria's Essentials --- src/main/disabledJavaFiles/HeartsRenderer.txt | 333 ----------------- .../zontreck/mcmods/WatchMyDurability.java | 4 +- .../mcmods/configs/WMDClientConfig.java | 1 - .../zontreck/mcmods/gui/HeartsRenderer.java | 334 ------------------ .../watchmydurability/textures/gui/absorb.png | Bin 6946 -> 0 bytes .../watchmydurability/textures/gui/hearts.png | Bin 5965 -> 0 bytes 6 files changed, 1 insertion(+), 671 deletions(-) delete mode 100644 src/main/disabledJavaFiles/HeartsRenderer.txt delete mode 100644 src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java delete mode 100644 src/main/resources/assets/watchmydurability/textures/gui/absorb.png delete mode 100644 src/main/resources/assets/watchmydurability/textures/gui/hearts.png diff --git a/src/main/disabledJavaFiles/HeartsRenderer.txt b/src/main/disabledJavaFiles/HeartsRenderer.txt deleted file mode 100644 index 110c85f..0000000 --- a/src/main/disabledJavaFiles/HeartsRenderer.txt +++ /dev/null @@ -1,333 +0,0 @@ -/* - * - * DISCLAIMER: This code was taken from Mantle, and will be modified to fit the needs of this mod, such as adding more heat options. This code is subject to Mantle's license of MIT. - * Despite this code being taken from, and modified/updated to be modern, all textures are my own creation - * This disclaimer is here to give credit where credit is due. The author(s) of mantle have done a absolutely fantastic job. And if Mantle gets updated this shall be removed along with future plans of extra hearts and color options. - * - * - */ - -package dev.zontreck.mcmods.gui; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; - -import dev.zontreck.mcmods.WatchMyDurability; -import dev.zontreck.mcmods.configs.WMDClientConfig; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.ai.attributes.AttributeInstance; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.player.Player; -import net.minecraftforge.client.event.RenderGuiOverlayEvent; -import net.minecraftforge.client.gui.overlay.ForgeGui; -import net.minecraftforge.client.gui.overlay.GuiOverlayManager; -import net.minecraftforge.client.gui.overlay.NamedGuiOverlay; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.eventbus.api.SubscribeEvent; - -import java.util.Random; - -public class HeartsRenderer { - private static final ResourceLocation ICON_HEARTS = new ResourceLocation(WatchMyDurability.MODID, - "textures/gui/hearts.png"); - private static final ResourceLocation ICON_ABSORB = new ResourceLocation(WatchMyDurability.MODID, - "textures/gui/absorb.png"); - private static final ResourceLocation ICON_VANILLA = GuiComponent.GUI_ICONS_LOCATION; - - private final Minecraft mc = Minecraft.getInstance(); - - private int playerHealth = 0; - private int lastPlayerHealth = 0; - private long healthUpdateCounter = 0; - private long lastSystemTime = 0; - private final Random rand = new Random(); - - private int regen; - - /** - * Draws a texture to the screen - * - * @param matrixStack Matrix stack instance - * @param x X position - * @param y Y position - * @param textureX Texture X - * @param textureY Texture Y - * @param width Width to draw - * @param height Height to draw - */ - private void blit(PoseStack matrixStack, int x, int y, int textureX, int textureY, int width, int height) { - Minecraft.getInstance().gui.blit(matrixStack, x, y, textureX, textureY, width, height); - } - - /* HUD */ - - /** - * Event listener - * - * @param event Event instance - */ - @SubscribeEvent(priority = EventPriority.LOW) - public void renderHealthbar(RenderGuiOverlayEvent.Pre event) { - NamedGuiOverlay ActualOverlay = GuiOverlayManager.findOverlay(new ResourceLocation("minecraft:player_health")); - - if (ActualOverlay == null) { - if (GuiOverlayManager.getOverlays() == null) { - WatchMyDurability.LOGGER.info("Overlays non existent?!"); - } - for (NamedGuiOverlay overlay : GuiOverlayManager.getOverlays()) { - // Next print - // LibZontreck.LOGGER.info("GUI OVERLAY: "+overlay.id().getPath()); - - if (overlay.id().getPath().equals("player_health")) { - ActualOverlay = overlay; - break; - } - } - } - if (event.isCanceled() || !WMDClientConfig.EnableExtraHearts.get() || event.getOverlay() != ActualOverlay) { - return; - } - // ensure its visible - if (!(mc.gui instanceof ForgeGui gui) || mc.options.hideGui || !gui.shouldDrawSurvivalElements()) { - return; - } - Entity renderViewEnity = this.mc.getCameraEntity(); - if (!(renderViewEnity instanceof Player player)) { - return; - } - gui.setupOverlayRenderState(true, false); - - this.mc.getProfiler().push("health"); - - // extra setup stuff from us - int left_height = gui.leftHeight; - int width = this.mc.getWindow().getGuiScaledWidth(); - int height = this.mc.getWindow().getGuiScaledHeight(); - int updateCounter = this.mc.gui.getGuiTicks(); - - // start default forge/mc rendering - // changes are indicated by comment - - int health = Mth.ceil(player.getHealth()); - boolean highlight = this.healthUpdateCounter > (long) updateCounter - && (this.healthUpdateCounter - (long) updateCounter) / 3L % 2L == 1L; - - if (health < this.playerHealth && player.invulnerableTime > 0) { - this.lastSystemTime = Util.getMillis(); - this.healthUpdateCounter = (updateCounter + 20); - } else if (health > this.playerHealth && player.invulnerableTime > 0) { - this.lastSystemTime = Util.getMillis(); - this.healthUpdateCounter = (updateCounter + 10); - } - - if (Util.getMillis() - this.lastSystemTime > 1000L) { - this.playerHealth = health; - this.lastPlayerHealth = health; - this.lastSystemTime = Util.getMillis(); - } - - this.playerHealth = health; - int healthLast = this.lastPlayerHealth; - - AttributeInstance attrMaxHealth = player.getAttribute(Attributes.MAX_HEALTH); - float healthMax = attrMaxHealth == null ? 0 : (float) attrMaxHealth.getValue(); - float absorb = Mth.ceil(player.getAbsorptionAmount()); - - // CHANGE: simulate 10 hearts max if there's more, so vanilla only renders one - // row max - healthMax = Math.min(healthMax, 20f); - health = Math.min(health, 20); - absorb = Math.min(absorb, 20); - - int healthRows = Mth.ceil((healthMax + absorb) / 2.0F / 10.0F); - int rowHeight = Math.max(10 - (healthRows - 2), 3); - - this.rand.setSeed(updateCounter * 312871L); - - int left = width / 2 - 91; - int top = height - left_height; - // change: these are unused below, unneeded? should these adjust the Forge - // variable? - // left_height += (healthRows * rowHeight); - // if (rowHeight != 10) left_height += 10 - rowHeight; - - this.regen = -1; - if (player.hasEffect(MobEffects.REGENERATION)) { - this.regen = updateCounter % 25; - } - - assert this.mc.level != null; - final int TOP = 9 * (this.mc.level.getLevelData().isHardcore() ? 5 : 0); - final int BACKGROUND = (highlight ? 25 : 16); - int MARGIN = 16; - if (player.hasEffect(MobEffects.POISON)) - MARGIN += 36; - else if (player.hasEffect(MobEffects.WITHER)) - MARGIN += 72; - float absorbRemaining = absorb; - - PoseStack matrixStack = event.getPoseStack(); - for (int i = Mth.ceil((healthMax + absorb) / 2.0F) - 1; i >= 0; --i) { - int row = Mth.ceil((float) (i + 1) / 10.0F) - 1; - int x = left + i % 10 * 8; - int y = top - row * rowHeight; - - if (health <= 4) - y += this.rand.nextInt(2); - if (i == this.regen) - y -= 2; - - this.blit(matrixStack, x, y, BACKGROUND, TOP, 9, 9); - - if (highlight) { - if (i * 2 + 1 < healthLast) { - this.blit(matrixStack, x, y, MARGIN + 54, TOP, 9, 9); // 6 - } else if (i * 2 + 1 == healthLast) { - this.blit(matrixStack, x, y, MARGIN + 63, TOP, 9, 9); // 7 - } - } - - if (absorbRemaining > 0.0F) { - if (absorbRemaining == absorb && absorb % 2.0F == 1.0F) { - this.blit(matrixStack, x, y, MARGIN + 153, TOP, 9, 9); // 17 - absorbRemaining -= 1.0F; - } else { - this.blit(matrixStack, x, y, MARGIN + 144, TOP, 9, 9); // 16 - absorbRemaining -= 2.0F; - } - } else { - if (i * 2 + 1 < health) { - this.blit(matrixStack, x, y, MARGIN + 36, TOP, 9, 9); // 4 - } else if (i * 2 + 1 == health) { - this.blit(matrixStack, x, y, MARGIN + 45, TOP, 9, 9); // 5 - } - } - } - - this.renderExtraHearts(matrixStack, left, top, player); - this.renderExtraAbsorption(matrixStack, left, top - rowHeight, player); - - RenderSystem.setShaderTexture(0, ICON_VANILLA); - gui.leftHeight += 10; - if (absorb > 0) { - gui.leftHeight += 10; - } - - event.setCanceled(true); - RenderSystem.disableBlend(); - this.mc.getProfiler().pop(); - MinecraftForge.EVENT_BUS - .post(new RenderGuiOverlayEvent.Post(mc.getWindow(), matrixStack, event.getPartialTick(), ActualOverlay)); - } - - /** - * Gets the texture from potion effects - * - * @param player Player instance - * @return Texture offset for potion effects - */ - private int getPotionOffset(Player player) { - int potionOffset = 0; - MobEffectInstance potion = player.getEffect(MobEffects.WITHER); - if (potion != null) { - potionOffset = 18; - } - potion = player.getEffect(MobEffects.POISON); - if (potion != null) { - potionOffset = 9; - } - assert this.mc.level != null; - if (this.mc.level.getLevelData().isHardcore()) { - potionOffset += 27; - } - return potionOffset; - } - - /** - * Renders the health above 10 hearts - * - * @param matrixStack Matrix stack instance - * @param xBasePos Health bar top corner - * @param yBasePos Health bar top corner - * @param player Player instance - */ - private void renderExtraHearts(PoseStack matrixStack, int xBasePos, int yBasePos, Player player) { - int potionOffset = this.getPotionOffset(player); - - // Extra hearts - RenderSystem.setShaderTexture(0, ICON_HEARTS); - int hp = Mth.ceil(player.getHealth()); - this.renderCustomHearts(matrixStack, xBasePos, yBasePos, potionOffset, hp, false); - } - - /** - * Renders the absorption health above 10 hearts - * - * @param matrixStack Matrix stack instance - * @param xBasePos Health bar top corner - * @param yBasePos Health bar top corner - * @param player Player instance - */ - private void renderExtraAbsorption(PoseStack matrixStack, int xBasePos, int yBasePos, Player player) { - int potionOffset = this.getPotionOffset(player); - - // Extra hearts - RenderSystem.setShaderTexture(0, ICON_ABSORB); - int absorb = Mth.ceil(player.getAbsorptionAmount()); - this.renderCustomHearts(matrixStack, xBasePos, yBasePos, potionOffset, absorb, true); - } - - /** - * Gets the texture offset from the regen effect - * - * @param i Heart index - * @param offset Current offset - */ - private int getYRegenOffset(int i, int offset) { - return i + offset == this.regen ? -2 : 0; - } - - /** - * Shared logic to render custom hearts - * - * @param matrixStack Matrix stack instance - * @param xBasePos Health bar top corner - * @param yBasePos Health bar top corner - * @param potionOffset Offset from the potion effect - * @param count Number to render - * @param absorb If true, render absorption hearts - */ - private void renderCustomHearts(PoseStack matrixStack, int xBasePos, int yBasePos, int potionOffset, int count, - boolean absorb) { - int regenOffset = absorb ? 10 : 0; - for (int iter = 0; iter < count / 20; iter++) { - int renderHearts = (count - 20 * (iter + 1)) / 2; - int heartIndex = iter % 11; - if (renderHearts > 10) { - renderHearts = 10; - } - for (int i = 0; i < renderHearts; i++) { - int y = this.getYRegenOffset(i, regenOffset); - if (absorb) { - this.blit(matrixStack, xBasePos + 8 * i, yBasePos + y, 0, 54, 9, 9); - } - this.blit(matrixStack, xBasePos + 8 * i, yBasePos + y, 18 * heartIndex, potionOffset, 9, 9); - } - if (count % 2 == 1 && renderHearts < 10) { - int y = this.getYRegenOffset(renderHearts, regenOffset); - if (absorb) { - this.blit(matrixStack, xBasePos + 8 * renderHearts, yBasePos + y, 0, 54, 9, 9); - } - this.blit(matrixStack, xBasePos + 8 * renderHearts, yBasePos + y, 9 + 18 * heartIndex, potionOffset, 9, 9); - } - } - } -} diff --git a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java index 8198f35..7026584 100644 --- a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java @@ -5,7 +5,6 @@ import com.mojang.logging.LogUtils; import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.mcmods.configs.WMDClientConfig; -import dev.zontreck.mcmods.gui.HeartsRenderer; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraft.sounds.SoundEvent; @@ -55,8 +54,7 @@ public class WatchMyDurability // Register the commonSetup method for modloading modEventBus.addListener(this::commonSetup); ModLoadingContext.get().registerConfig(Type.CLIENT, WMDClientConfig.SPEC, "watchmydurability-client.toml"); - - MinecraftForge.EVENT_BUS.register(new HeartsRenderer()); + // Register ourselves for server and other game events we are interested in MinecraftForge.EVENT_BUS.register(this); } diff --git a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java b/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java index d26912e..98a5210 100644 --- a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java +++ b/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java @@ -34,7 +34,6 @@ public class WMDClientConfig { BUILDER.pop(); BUILDER.push("General"); - EnableExtraHearts = BUILDER.comment("Whether to enable the extra hearts rendering").define("compress_hearts", true); EnableHealthAlert = BUILDER.comment("The following was added for a friend. If you need reminders to eat in order to heal, turn the below option on").define("watchMyHealth", false); EnableHungerAlert = BUILDER.comment("This is a newer setting to watch your hunger status instead of your hunger to alert when you need to eat").define("watchMyHunger", true); diff --git a/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java b/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java deleted file mode 100644 index 2f76cae..0000000 --- a/src/main/java/dev/zontreck/mcmods/gui/HeartsRenderer.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * - * DISCLAIMER: This code was taken from Mantle, and will be modified to fit the needs of this mod, such as adding more heat options. This code is subject to Mantle's license of MIT. - * Despite this code being taken from, and modified/updated to be modern, all textures are my own creation - * This disclaimer is here to give credit where credit is due. The author(s) of mantle have done a absolutely fantastic job. And if Mantle gets updated this shall be removed along with future plans of extra hearts and color options. - * - * - */ - -package dev.zontreck.mcmods.gui; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; - -import dev.zontreck.mcmods.WatchMyDurability; -import dev.zontreck.mcmods.configs.WMDClientConfig; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Gui; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.ai.attributes.AttributeInstance; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.player.Player; -import net.minecraftforge.client.event.RenderGuiOverlayEvent; -import net.minecraftforge.client.gui.overlay.ForgeGui; -import net.minecraftforge.client.gui.overlay.GuiOverlayManager; -import net.minecraftforge.client.gui.overlay.NamedGuiOverlay; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.eventbus.api.SubscribeEvent; - -import java.util.Random; - -public class HeartsRenderer { - private static final ResourceLocation ICON_HEARTS = new ResourceLocation(WatchMyDurability.MODID, - "textures/gui/hearts.png"); - private static final ResourceLocation ICON_ABSORB = new ResourceLocation(WatchMyDurability.MODID, - "textures/gui/absorb.png"); - private static final ResourceLocation ICON_VANILLA = Gui.GUI_ICONS_LOCATION; - - private final Minecraft mc = Minecraft.getInstance(); - - private int playerHealth = 0; - private int lastPlayerHealth = 0; - private long healthUpdateCounter = 0; - private long lastSystemTime = 0; - private final Random rand = new Random(); - - private int regen; - - /** - * Draws a texture to the screen - * - * @param matrixStack Matrix stack instance - * @param x X position - * @param y Y position - * @param textureX Texture X - * @param textureY Texture Y - * @param width Width to draw - * @param height Height to draw - */ - private void blit(GuiGraphics matrixStack, int x, int y, int textureX, int textureY, int width, int height, ResourceLocation resource) { - matrixStack.blit(resource, x, y, textureX, textureY, width, height); - } - - /* HUD */ - - /** - * Event listener - * - * @param event Event instance - */ - @SubscribeEvent(priority = EventPriority.LOW) - public void renderHealthbar(RenderGuiOverlayEvent.Pre event) { - NamedGuiOverlay ActualOverlay = GuiOverlayManager.findOverlay(new ResourceLocation("minecraft:player_health")); - - if (ActualOverlay == null) { - if (GuiOverlayManager.getOverlays() == null) { - WatchMyDurability.LOGGER.info("Overlays non existent?!"); - } - for (NamedGuiOverlay overlay : GuiOverlayManager.getOverlays()) { - // Next print - // LibZontreck.LOGGER.info("GUI OVERLAY: "+overlay.id().getPath()); - - if (overlay.id().getPath().equals("player_health")) { - ActualOverlay = overlay; - break; - } - } - } - if (event.isCanceled() || !WMDClientConfig.EnableExtraHearts.get() || event.getOverlay() != ActualOverlay) { - return; - } - // ensure its visible - if (!(mc.gui instanceof ForgeGui gui) || mc.options.hideGui || !gui.shouldDrawSurvivalElements()) { - return; - } - Entity renderViewEnity = this.mc.getCameraEntity(); - if (!(renderViewEnity instanceof Player player)) { - return; - } - gui.setupOverlayRenderState(true, false); - - this.mc.getProfiler().push("health"); - - // extra setup stuff from us - int left_height = gui.leftHeight; - int width = this.mc.getWindow().getGuiScaledWidth(); - int height = this.mc.getWindow().getGuiScaledHeight(); - int updateCounter = this.mc.gui.getGuiTicks(); - - // start default forge/mc rendering - // changes are indicated by comment - - int health = Mth.ceil(player.getHealth()); - boolean highlight = this.healthUpdateCounter > (long) updateCounter - && (this.healthUpdateCounter - (long) updateCounter) / 3L % 2L == 1L; - - if (health < this.playerHealth && player.invulnerableTime > 0) { - this.lastSystemTime = Util.getMillis(); - this.healthUpdateCounter = (updateCounter + 20); - } else if (health > this.playerHealth && player.invulnerableTime > 0) { - this.lastSystemTime = Util.getMillis(); - this.healthUpdateCounter = (updateCounter + 10); - } - - if (Util.getMillis() - this.lastSystemTime > 1000L) { - this.playerHealth = health; - this.lastPlayerHealth = health; - this.lastSystemTime = Util.getMillis(); - } - - this.playerHealth = health; - int healthLast = this.lastPlayerHealth; - - AttributeInstance attrMaxHealth = player.getAttribute(Attributes.MAX_HEALTH); - float healthMax = attrMaxHealth == null ? 0 : (float) attrMaxHealth.getValue(); - float absorb = Mth.ceil(player.getAbsorptionAmount()); - - // CHANGE: simulate 10 hearts max if there's more, so vanilla only renders one - // row max - healthMax = Math.min(healthMax, 20f); - health = Math.min(health, 20); - absorb = Math.min(absorb, 20); - - int healthRows = Mth.ceil((healthMax + absorb) / 2.0F / 10.0F); - int rowHeight = Math.max(10 - (healthRows - 2), 3); - - this.rand.setSeed(updateCounter * 312871L); - - int left = width / 2 - 91; - int top = height - left_height; - // change: these are unused below, unneeded? should these adjust the Forge - // variable? - // left_height += (healthRows * rowHeight); - // if (rowHeight != 10) left_height += 10 - rowHeight; - - this.regen = -1; - if (player.hasEffect(MobEffects.REGENERATION)) { - this.regen = updateCounter % 25; - } - - assert this.mc.level != null; - final int TOP = 9 * (this.mc.level.getLevelData().isHardcore() ? 5 : 0); - final int BACKGROUND = (highlight ? 25 : 16); - int MARGIN = 16; - if (player.hasEffect(MobEffects.POISON)) - MARGIN += 36; - else if (player.hasEffect(MobEffects.WITHER)) - MARGIN += 72; - float absorbRemaining = absorb; - - GuiGraphics matrixStack = event.getGuiGraphics(); - for (int i = Mth.ceil((healthMax + absorb) / 2.0F) - 1; i >= 0; --i) { - int row = Mth.ceil((float) (i + 1) / 10.0F) - 1; - int x = left + i % 10 * 8; - int y = top - row * rowHeight; - - if (health <= 4) - y += this.rand.nextInt(2); - if (i == this.regen) - y -= 2; - - this.blit(matrixStack, x, y, BACKGROUND, TOP, 9, 9, ICON_VANILLA); - - if (highlight) { - if (i * 2 + 1 < healthLast) { - this.blit(matrixStack, x, y, MARGIN + 54, TOP, 9, 9, ICON_VANILLA); // 6 - } else if (i * 2 + 1 == healthLast) { - this.blit(matrixStack, x, y, MARGIN + 63, TOP, 9, 9, ICON_VANILLA); // 7 - } - } - - if (absorbRemaining > 0.0F) { - if (absorbRemaining == absorb && absorb % 2.0F == 1.0F) { - this.blit(matrixStack, x, y, MARGIN + 153, TOP, 9, 9, ICON_VANILLA); // 17 - absorbRemaining -= 1.0F; - } else { - this.blit(matrixStack, x, y, MARGIN + 144, TOP, 9, 9, ICON_VANILLA); // 16 - absorbRemaining -= 2.0F; - } - } else { - if (i * 2 + 1 < health) { - this.blit(matrixStack, x, y, MARGIN + 36, TOP, 9, 9, ICON_VANILLA); // 4 - } else if (i * 2 + 1 == health) { - this.blit(matrixStack, x, y, MARGIN + 45, TOP, 9, 9, ICON_VANILLA); // 5 - } - } - } - - this.renderExtraHearts(matrixStack, left, top, player); - this.renderExtraAbsorption(matrixStack, left, top - rowHeight, player); - - RenderSystem.setShaderTexture(0, ICON_VANILLA); - gui.leftHeight += 10; - if (absorb > 0) { - gui.leftHeight += 10; - } - - event.setCanceled(true); - RenderSystem.disableBlend(); - this.mc.getProfiler().pop(); - MinecraftForge.EVENT_BUS - .post(new RenderGuiOverlayEvent.Post(mc.getWindow(), event.getGuiGraphics(), event.getPartialTick(), ActualOverlay)); - } - - /** - * Gets the texture from potion effects - * - * @param player Player instance - * @return Texture offset for potion effects - */ - private int getPotionOffset(Player player) { - int potionOffset = 0; - MobEffectInstance potion = player.getEffect(MobEffects.WITHER); - if (potion != null) { - potionOffset = 18; - } - potion = player.getEffect(MobEffects.POISON); - if (potion != null) { - potionOffset = 9; - } - assert this.mc.level != null; - if (this.mc.level.getLevelData().isHardcore()) { - potionOffset += 27; - } - return potionOffset; - } - - /** - * Renders the health above 10 hearts - * - * @param matrixStack Matrix stack instance - * @param xBasePos Health bar top corner - * @param yBasePos Health bar top corner - * @param player Player instance - */ - private void renderExtraHearts(GuiGraphics matrixStack, int xBasePos, int yBasePos, Player player) { - int potionOffset = this.getPotionOffset(player); - - // Extra hearts - RenderSystem.setShaderTexture(0, ICON_HEARTS); - int hp = Mth.ceil(player.getHealth()); - this.renderCustomHearts(matrixStack, xBasePos, yBasePos, potionOffset, hp, false); - } - - /** - * Renders the absorption health above 10 hearts - * - * @param matrixStack Matrix stack instance - * @param xBasePos Health bar top corner - * @param yBasePos Health bar top corner - * @param player Player instance - */ - private void renderExtraAbsorption(GuiGraphics matrixStack, int xBasePos, int yBasePos, Player player) { - int potionOffset = this.getPotionOffset(player); - - // Extra hearts - RenderSystem.setShaderTexture(0, ICON_ABSORB); - int absorb = Mth.ceil(player.getAbsorptionAmount()); - this.renderCustomHearts(matrixStack, xBasePos, yBasePos, potionOffset, absorb, true); - } - - /** - * Gets the texture offset from the regen effect - * - * @param i Heart index - * @param offset Current offset - */ - private int getYRegenOffset(int i, int offset) { - return i + offset == this.regen ? -2 : 0; - } - - /** - * Shared logic to render custom hearts - * - * @param matrixStack Matrix stack instance - * @param xBasePos Health bar top corner - * @param yBasePos Health bar top corner - * @param potionOffset Offset from the potion effect - * @param count Number to render - * @param absorb If true, render absorption hearts - */ - private void renderCustomHearts(GuiGraphics matrixStack, int xBasePos, int yBasePos, int potionOffset, int count, - boolean absorb) { - int regenOffset = absorb ? 10 : 0; - for (int iter = 0; iter < count / 20; iter++) { - int renderHearts = (count - 20 * (iter + 1)) / 2; - int heartIndex = iter % 11; - if (renderHearts > 10) { - renderHearts = 10; - } - for (int i = 0; i < renderHearts; i++) { - int y = this.getYRegenOffset(i, regenOffset); - if (absorb) { - this.blit(matrixStack, xBasePos + 8 * i, yBasePos + y, 0, 54, 9, 9, ICON_ABSORB); - } - this.blit(matrixStack, xBasePos + 8 * i, yBasePos + y, 18 * heartIndex, potionOffset, 9, 9, ICON_HEARTS); - } - if (count % 2 == 1 && renderHearts < 10) { - int y = this.getYRegenOffset(renderHearts, regenOffset); - if (absorb) { - this.blit(matrixStack, xBasePos + 8 * renderHearts, yBasePos + y, 0, 54, 9, 9, ICON_ABSORB); - } - this.blit(matrixStack, xBasePos + 8 * renderHearts, yBasePos + y, 9 + 18 * heartIndex, potionOffset, 9, 9, ICON_HEARTS); - } - } - } -} diff --git a/src/main/resources/assets/watchmydurability/textures/gui/absorb.png b/src/main/resources/assets/watchmydurability/textures/gui/absorb.png deleted file mode 100644 index 37d83b505fb64501fc6389244a9148186c9e5137..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6946 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 SHU<7a4$-}C058 Date: Mon, 18 Dec 2023 15:33:14 -0700 Subject: [PATCH 19/28] Update LibZ version --- gradle.properties | 4 ++-- src/main/resources/META-INF/accesstransformer.cfg | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 src/main/resources/META-INF/accesstransformer.cfg diff --git a/gradle.properties b/gradle.properties index 3144615..457171a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -libzontreck=1.9.121423.1700 +libzontreck=1.9.121823.1318 ## Environment Properties @@ -49,7 +49,7 @@ mod_name=WatchMyDurability # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1.2.121423.2014 +mod_version=1.2.121823.1532 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg deleted file mode 100644 index b4796c8..0000000 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ /dev/null @@ -1,5 +0,0 @@ -public net.minecraft.client.gui.Gui -public net.minecraft.client.gui.Gui f_279580_ # GUI_ICONS_LOCATION -public net.minecraft.client.gui.Gui f_92974_ # displayHealth -public net.minecraft.client.gui.Gui f_92973_ # lastHealth -public net.minecraft.client.gui.Gui f_92976_ # healthBlinkTime \ No newline at end of file From a4a961afcb25d548abea70a63740514ed3190d0d Mon Sep 17 00:00:00 2001 From: zontreck Date: Tue, 2 Jan 2024 18:09:34 -0700 Subject: [PATCH 20/28] Update LibZ version --- gradle.properties | 4 ++-- src/main/resources/META-INF/mods.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 457171a..6c34a47 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -libzontreck=1.9.121823.1318 +libzontreck=1.10.010224.1758 ## Environment Properties @@ -49,7 +49,7 @@ mod_name=WatchMyDurability # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1.2.121823.1532 +mod_version=1.2.010224.1806 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 9cbfe9e..282f267 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -66,7 +66,7 @@ description='''${mod_description}''' [[dependencies.${mod_id}]] modId="libzontreck" mandatory=true - versionRange="[1.9,1.10)" + versionRange="[1.10,1.11)" ordering="NONE" side="BOTH" # Features are specific properties of the game environment, that you may want to declare you require. This example declares From bdaa4328f4808f3bd44dd6a80d6896b94c5d0bfd Mon Sep 17 00:00:00 2001 From: zontreck Date: Sun, 7 Jan 2024 17:35:49 -0700 Subject: [PATCH 21/28] Update repository --- build.gradle | 4 ++-- settings.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index c43a468..765acb8 100644 --- a/build.gradle +++ b/build.gradle @@ -123,7 +123,7 @@ repositories { // } maven { name = "Aria's Creations Caches" - url = "https://maven.zontreck.dev/repository/internal" + url = "https://maven.zontreck.com/repository/internal" } // Put repositories for dependencies here // ForgeGradle automatically adds the Forge maven and Maven Central for you @@ -140,7 +140,7 @@ repositories { maven { name = "zontreck Maven" - url = "https://maven.zontreck.dev/repository/zontreck" + url = "https://maven.zontreck.com/repository/zontreck" } } diff --git a/settings.gradle b/settings.gradle index 891d211..4e8d059 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,7 @@ pluginManagement { repositories { gradlePluginPortal() - maven { url = "https://maven.zontreck.dev/repository/internal" } + maven { url = "https://maven.zontreck.com/repository/internal" } } } From bb135ebd6506e54b5294869c8937a21ac8240b63 Mon Sep 17 00:00:00 2001 From: zontreck Date: Sun, 7 Jan 2024 17:39:52 -0700 Subject: [PATCH 22/28] Update libz reference --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6c34a47..e175dd4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -libzontreck=1.10.010224.1758 +libzontreck=1.10.010224.1940 ## Environment Properties From d3cbcc3f361c952ac5cdebbc84411512743d884a Mon Sep 17 00:00:00 2001 From: zontreck Date: Tue, 9 Jan 2024 14:52:40 -0700 Subject: [PATCH 23/28] Rename package! --- gradle.properties | 4 +- .../zontreck/{mcmods => wmd}/CheckHealth.java | 4 +- .../zontreck/{mcmods => wmd}/CheckHunger.java | 4 +- .../{mcmods => wmd}/CheckInventory.java | 247 ++++++++------- .../dev/zontreck/{mcmods => wmd}/Health.java | 72 ++--- .../dev/zontreck/{mcmods => wmd}/Hunger.java | 2 +- .../{mcmods => wmd}/ItemRegistry.java | 176 +++++------ .../{mcmods => wmd}/WatchMyDurability.java | 280 +++++++++--------- .../configs/WMDClientConfig.java | 84 +++--- 9 files changed, 435 insertions(+), 438 deletions(-) rename src/main/java/dev/zontreck/{mcmods => wmd}/CheckHealth.java (94%) rename src/main/java/dev/zontreck/{mcmods => wmd}/CheckHunger.java (94%) rename src/main/java/dev/zontreck/{mcmods => wmd}/CheckInventory.java (95%) rename src/main/java/dev/zontreck/{mcmods => wmd}/Health.java (92%) rename src/main/java/dev/zontreck/{mcmods => wmd}/Hunger.java (95%) rename src/main/java/dev/zontreck/{mcmods => wmd}/ItemRegistry.java (95%) rename src/main/java/dev/zontreck/{mcmods => wmd}/WatchMyDurability.java (94%) rename src/main/java/dev/zontreck/{mcmods => wmd}/configs/WMDClientConfig.java (96%) diff --git a/gradle.properties b/gradle.properties index e175dd4..5acae1d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -libzontreck=1.10.010224.1940 +libzontreck=1.10.010924.1444 ## Environment Properties @@ -49,7 +49,7 @@ mod_name=WatchMyDurability # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1.2.010224.1806 +mod_version=1.2.010924.1451 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/dev/zontreck/mcmods/CheckHealth.java b/src/main/java/dev/zontreck/wmd/CheckHealth.java similarity index 94% rename from src/main/java/dev/zontreck/mcmods/CheckHealth.java rename to src/main/java/dev/zontreck/wmd/CheckHealth.java index 8f94592..4fd8899 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckHealth.java +++ b/src/main/java/dev/zontreck/wmd/CheckHealth.java @@ -1,9 +1,9 @@ -package dev.zontreck.mcmods; +package dev.zontreck.wmd; import dev.zontreck.ariaslib.terminal.Task; import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; -import dev.zontreck.mcmods.configs.WMDClientConfig; +import dev.zontreck.wmd.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvent; diff --git a/src/main/java/dev/zontreck/mcmods/CheckHunger.java b/src/main/java/dev/zontreck/wmd/CheckHunger.java similarity index 94% rename from src/main/java/dev/zontreck/mcmods/CheckHunger.java rename to src/main/java/dev/zontreck/wmd/CheckHunger.java index 02cd33f..51fea8b 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckHunger.java +++ b/src/main/java/dev/zontreck/wmd/CheckHunger.java @@ -1,9 +1,9 @@ -package dev.zontreck.mcmods; +package dev.zontreck.wmd; import dev.zontreck.ariaslib.terminal.Task; import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; -import dev.zontreck.mcmods.configs.WMDClientConfig; +import dev.zontreck.wmd.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvent; diff --git a/src/main/java/dev/zontreck/mcmods/CheckInventory.java b/src/main/java/dev/zontreck/wmd/CheckInventory.java similarity index 95% rename from src/main/java/dev/zontreck/mcmods/CheckInventory.java rename to src/main/java/dev/zontreck/wmd/CheckInventory.java index 330e89e..6429464 100644 --- a/src/main/java/dev/zontreck/mcmods/CheckInventory.java +++ b/src/main/java/dev/zontreck/wmd/CheckInventory.java @@ -1,124 +1,123 @@ -package dev.zontreck.mcmods; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimerTask; - -import dev.zontreck.ariaslib.terminal.Task; -import dev.zontreck.ariaslib.util.DelayedExecutorService; -import dev.zontreck.libzontreck.chat.ChatColor; -import dev.zontreck.libzontreck.chat.HoverTip; -import dev.zontreck.mcmods.configs.WMDClientConfig; -import net.minecraft.client.Minecraft; -import net.minecraft.core.NonNullList; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.HoverEvent; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.Style; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.item.ItemStack; - -public class CheckInventory extends Task { - private static final CheckInventory inst = new CheckInventory(); - - public CheckInventory() { - super("checkinv", true); - } - - public static CheckInventory getInstance(){ - return inst; - } - @Override - public void run() { - - try { - - if(!WatchMyDurability.isInGame)return; - - - //WatchMyDurability.LOGGER.info("TICKING CHECK INVENTORY EVENT"); - // Get the player inventory - Inventory inv = Minecraft.getInstance().player.getInventory(); - - checkList("_armor", inv.armor); - checkList("_items", inv.items); - checkList("_offhand", inv.offhand); - - - PushItems("_armor", inv.armor); - PushItems("_items", inv.items); - PushItems("_offhand", inv.offhand); - } catch (Exception e) { - WatchMyDurability.LOGGER.warn(": : : : [ERROR] : : : :"); - WatchMyDurability.LOGGER.warn("A error in the WatchMyDurability timer code has occurred. This could happen with hub worlds and the server transfers that occur. If this happened in another instance, please report this error to the developer, along with what you were doing."); - } - - - } - - public void PushItems(String type, List stack) - { - // OK - // Push the items into the registry, replacing the existing entry - ItemRegistry.purge(type); - Map items = new HashMap(); - Integer slotNum = 0; - for (ItemStack itemStack : stack) { - ItemRegistry.Item itx = WatchMyDurability.REGISTRY.GetNewItem(itemStack); - - items.put(slotNum, itx); - slotNum++; - - } - - ItemRegistry.register(type,items); - } - - public void checkList(String type, NonNullList stacks){ - Integer slotNum = 0; - //boolean ret=false; - for (ItemStack is1 : stacks) { - if(is1.isDamageableItem() && is1.isDamaged() && !ItemRegistry.contains(type, slotNum, WatchMyDurability.REGISTRY.GetNewItem(is1))){ - - int percent = 0; - int max = is1.getMaxDamage(); - int val = is1.getDamageValue(); - int cur = max - val; - percent = cur * 100 / max; - - //WatchMyDurability.LOGGER.debug("ITEM DURABILITY: "+cur+"; MAXIMUM: "+max+"; PERCENT: "+percent); - for (Integer entry : WMDClientConfig.alertPercents.get()) { - Integer idx = WMDClientConfig.alertPercents.get().indexOf(entry); - String entryStr = WMDClientConfig.alertMessages.get().get(idx); - - if(percent <= entry){ - String replaced = WatchMyDurability.WMDPrefix + ChatColor.DARK_RED + entryStr.replaceAll("!item!", is1.getDisplayName().getString()); - WatchMyDurability.LOGGER.info("Enqueue alert for an item. Playing sound for item: "+is1.getDisplayName().getString()); - - SoundEvent theSound = SoundEvents.ITEM_BREAK; - WatchMyDurability.Soundify(theSound); - - - - MutableComponent X = Component.literal(replaced); - - HoverEvent he = HoverTip.getItem(is1); - Style s = Style.EMPTY.withFont(Style.DEFAULT_FONT).withHoverEvent(he); - X=X.withStyle(s); - - - Minecraft.getInstance().player.displayClientMessage(X, false); - break; // Rule applies, break out of this loop, move to next item. - } - } - } - - slotNum ++; - } - //return ret; - } - -} +package dev.zontreck.wmd; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import dev.zontreck.ariaslib.terminal.Task; +import dev.zontreck.ariaslib.util.DelayedExecutorService; +import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.libzontreck.chat.HoverTip; +import dev.zontreck.wmd.configs.WMDClientConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; + +public class CheckInventory extends Task { + private static final CheckInventory inst = new CheckInventory(); + + public CheckInventory() { + super("checkinv", true); + } + + public static CheckInventory getInstance(){ + return inst; + } + @Override + public void run() { + + try { + + if(!WatchMyDurability.isInGame)return; + + + //WatchMyDurability.LOGGER.info("TICKING CHECK INVENTORY EVENT"); + // Get the player inventory + Inventory inv = Minecraft.getInstance().player.getInventory(); + + checkList("_armor", inv.armor); + checkList("_items", inv.items); + checkList("_offhand", inv.offhand); + + + PushItems("_armor", inv.armor); + PushItems("_items", inv.items); + PushItems("_offhand", inv.offhand); + } catch (Exception e) { + WatchMyDurability.LOGGER.warn(": : : : [ERROR] : : : :"); + WatchMyDurability.LOGGER.warn("A error in the WatchMyDurability timer code has occurred. This could happen with hub worlds and the server transfers that occur. If this happened in another instance, please report this error to the developer, along with what you were doing."); + } + + + } + + public void PushItems(String type, List stack) + { + // OK + // Push the items into the registry, replacing the existing entry + ItemRegistry.purge(type); + Map items = new HashMap(); + Integer slotNum = 0; + for (ItemStack itemStack : stack) { + ItemRegistry.Item itx = WatchMyDurability.REGISTRY.GetNewItem(itemStack); + + items.put(slotNum, itx); + slotNum++; + + } + + ItemRegistry.register(type,items); + } + + public void checkList(String type, NonNullList stacks){ + Integer slotNum = 0; + //boolean ret=false; + for (ItemStack is1 : stacks) { + if(is1.isDamageableItem() && is1.isDamaged() && !ItemRegistry.contains(type, slotNum, WatchMyDurability.REGISTRY.GetNewItem(is1))){ + + int percent = 0; + int max = is1.getMaxDamage(); + int val = is1.getDamageValue(); + int cur = max - val; + percent = cur * 100 / max; + + //WatchMyDurability.LOGGER.debug("ITEM DURABILITY: "+cur+"; MAXIMUM: "+max+"; PERCENT: "+percent); + for (Integer entry : WMDClientConfig.alertPercents.get()) { + Integer idx = WMDClientConfig.alertPercents.get().indexOf(entry); + String entryStr = WMDClientConfig.alertMessages.get().get(idx); + + if(percent <= entry){ + String replaced = WatchMyDurability.WMDPrefix + ChatColor.DARK_RED + entryStr.replaceAll("!item!", is1.getDisplayName().getString()); + WatchMyDurability.LOGGER.info("Enqueue alert for an item. Playing sound for item: "+is1.getDisplayName().getString()); + + SoundEvent theSound = SoundEvents.ITEM_BREAK; + WatchMyDurability.Soundify(theSound); + + + + MutableComponent X = Component.literal(replaced); + + HoverEvent he = HoverTip.getItem(is1); + Style s = Style.EMPTY.withFont(Style.DEFAULT_FONT).withHoverEvent(he); + X=X.withStyle(s); + + + Minecraft.getInstance().player.displayClientMessage(X, false); + break; // Rule applies, break out of this loop, move to next item. + } + } + } + + slotNum ++; + } + //return ret; + } + +} diff --git a/src/main/java/dev/zontreck/mcmods/Health.java b/src/main/java/dev/zontreck/wmd/Health.java similarity index 92% rename from src/main/java/dev/zontreck/mcmods/Health.java rename to src/main/java/dev/zontreck/wmd/Health.java index 90c88f6..1786b2a 100644 --- a/src/main/java/dev/zontreck/mcmods/Health.java +++ b/src/main/java/dev/zontreck/wmd/Health.java @@ -1,36 +1,36 @@ -package dev.zontreck.mcmods; - -import net.minecraft.world.entity.player.Player; - -public class Health { - - public float maximum; - public float current; - - public int asPercent() - { - return (int)Math.round(Math.abs((current * 100 / maximum))); - } - public Health lastHealthState; - - - public static Health of(Player player){ - Health obj = new Health(); - obj.current = player.getHealth(); - obj.maximum = player.getMaxHealth(); - - return obj; - } - - public boolean shouldGiveAlert() - { - if(asPercent()<=50){ - return true; - }else return false; - } - public boolean identical(Health other) - { - if(other.current == current && other.maximum == maximum)return true; - else return false; - } -} +package dev.zontreck.wmd; + +import net.minecraft.world.entity.player.Player; + +public class Health { + + public float maximum; + public float current; + + public int asPercent() + { + return (int)Math.round(Math.abs((current * 100 / maximum))); + } + public Health lastHealthState; + + + public static Health of(Player player){ + Health obj = new Health(); + obj.current = player.getHealth(); + obj.maximum = player.getMaxHealth(); + + return obj; + } + + public boolean shouldGiveAlert() + { + if(asPercent()<=50){ + return true; + }else return false; + } + public boolean identical(Health other) + { + if(other.current == current && other.maximum == maximum)return true; + else return false; + } +} diff --git a/src/main/java/dev/zontreck/mcmods/Hunger.java b/src/main/java/dev/zontreck/wmd/Hunger.java similarity index 95% rename from src/main/java/dev/zontreck/mcmods/Hunger.java rename to src/main/java/dev/zontreck/wmd/Hunger.java index 2b0f7cb..b566926 100644 --- a/src/main/java/dev/zontreck/mcmods/Hunger.java +++ b/src/main/java/dev/zontreck/wmd/Hunger.java @@ -1,4 +1,4 @@ -package dev.zontreck.mcmods; +package dev.zontreck.wmd; import net.minecraft.world.entity.player.Player; diff --git a/src/main/java/dev/zontreck/mcmods/ItemRegistry.java b/src/main/java/dev/zontreck/wmd/ItemRegistry.java similarity index 95% rename from src/main/java/dev/zontreck/mcmods/ItemRegistry.java rename to src/main/java/dev/zontreck/wmd/ItemRegistry.java index de1e2c5..d791527 100644 --- a/src/main/java/dev/zontreck/mcmods/ItemRegistry.java +++ b/src/main/java/dev/zontreck/wmd/ItemRegistry.java @@ -1,88 +1,88 @@ -package dev.zontreck.mcmods; - -import java.util.HashMap; -import java.util.Map; - -import net.minecraft.world.item.ItemStack; - -public class ItemRegistry { - public class Item { - public String Name; - public int PercentDamaged; - public int Count; - - - public boolean Compare(Item other) - { - if(other.Name.equals(Name) && Count == other.Count){ - if(PercentDamaged != other.PercentDamaged) return false; - else return true; - }else return false; - } - } - - public class Health { - } - - - public Map> CachedItems; - public ItemRegistry() - { - CachedItems = new HashMap>(); - } - - public static void Initialize() - { - WatchMyDurability.REGISTRY = new ItemRegistry(); - } - - public static void purge(String type) { - if(WatchMyDurability.REGISTRY.CachedItems.containsKey(type)) - WatchMyDurability.REGISTRY.CachedItems.remove(type); - } - - public Item GetNewItem(ItemStack itemStack) { - Item x = new Item(); - x.Name = itemStack.getDisplayName().getString(); - if(itemStack.isDamageableItem() && itemStack.isDamaged()){ - int max = itemStack.getMaxDamage(); - int val = itemStack.getDamageValue(); - int cur = max-val; - int percent = cur * 100 /max; - x.PercentDamaged=percent; - } - - x.Count = itemStack.getCount(); - //WatchMyDurability.LOGGER.debug("ITEM: "+x.Name + "; "+x.PercentDamaged+"; "+x.Type+"; "+x.Count); - return x; - } - - public static void register(String type, Map items) { - - WatchMyDurability.REGISTRY.CachedItems.put(type, items); - } - - public static boolean contains(String type, Integer slot, Item getNewItem) { - ItemRegistry reg = WatchMyDurability.REGISTRY; - if(reg.CachedItems.containsKey(type)){ - //WatchMyDurability.LOGGER.debug("Registry contains "+type); - Map items = reg.CachedItems.get(type); - if(items.containsKey(slot)){ - //WatchMyDurability.LOGGER.debug("ItemRegistry contains slot: "+slot); - Item x = items.get(slot); - if(x.Compare(getNewItem)){ - //WatchMyDurability.LOGGER.debug("Items are identical!"); - // Items are identical - return true; - }else { - //WatchMyDurability.LOGGER.debug("ITEMS ARE NOT IDENTICAL"); - return false; - } - }else return false; - - } - - return false; - } - -} +package dev.zontreck.wmd; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.world.item.ItemStack; + +public class ItemRegistry { + public class Item { + public String Name; + public int PercentDamaged; + public int Count; + + + public boolean Compare(Item other) + { + if(other.Name.equals(Name) && Count == other.Count){ + if(PercentDamaged != other.PercentDamaged) return false; + else return true; + }else return false; + } + } + + public class Health { + } + + + public Map> CachedItems; + public ItemRegistry() + { + CachedItems = new HashMap>(); + } + + public static void Initialize() + { + WatchMyDurability.REGISTRY = new ItemRegistry(); + } + + public static void purge(String type) { + if(WatchMyDurability.REGISTRY.CachedItems.containsKey(type)) + WatchMyDurability.REGISTRY.CachedItems.remove(type); + } + + public Item GetNewItem(ItemStack itemStack) { + Item x = new Item(); + x.Name = itemStack.getDisplayName().getString(); + if(itemStack.isDamageableItem() && itemStack.isDamaged()){ + int max = itemStack.getMaxDamage(); + int val = itemStack.getDamageValue(); + int cur = max-val; + int percent = cur * 100 /max; + x.PercentDamaged=percent; + } + + x.Count = itemStack.getCount(); + //WatchMyDurability.LOGGER.debug("ITEM: "+x.Name + "; "+x.PercentDamaged+"; "+x.Type+"; "+x.Count); + return x; + } + + public static void register(String type, Map items) { + + WatchMyDurability.REGISTRY.CachedItems.put(type, items); + } + + public static boolean contains(String type, Integer slot, Item getNewItem) { + ItemRegistry reg = WatchMyDurability.REGISTRY; + if(reg.CachedItems.containsKey(type)){ + //WatchMyDurability.LOGGER.debug("Registry contains "+type); + Map items = reg.CachedItems.get(type); + if(items.containsKey(slot)){ + //WatchMyDurability.LOGGER.debug("ItemRegistry contains slot: "+slot); + Item x = items.get(slot); + if(x.Compare(getNewItem)){ + //WatchMyDurability.LOGGER.debug("Items are identical!"); + // Items are identical + return true; + }else { + //WatchMyDurability.LOGGER.debug("ITEMS ARE NOT IDENTICAL"); + return false; + } + }else return false; + + } + + return false; + } + +} diff --git a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java b/src/main/java/dev/zontreck/wmd/WatchMyDurability.java similarity index 94% rename from src/main/java/dev/zontreck/mcmods/WatchMyDurability.java rename to src/main/java/dev/zontreck/wmd/WatchMyDurability.java index 7026584..17d84ef 100644 --- a/src/main/java/dev/zontreck/mcmods/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/wmd/WatchMyDurability.java @@ -1,141 +1,139 @@ -package dev.zontreck.mcmods; - -import com.mojang.logging.LogUtils; - -import dev.zontreck.ariaslib.util.DelayedExecutorService; -import dev.zontreck.libzontreck.chat.ChatColor; -import dev.zontreck.mcmods.configs.WMDClientConfig; -import net.minecraft.client.Minecraft; -import net.minecraft.client.User; -import net.minecraft.sounds.SoundEvent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.config.ModConfig.Type; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.event.server.ServerStartingEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.client.event.ClientPlayerNetworkEvent; - -import java.util.Timer; - -import net.minecraftforge.network.NetworkEvent; -import org.slf4j.Logger; - -// The value here should match an entry in the META-INF/mods.toml file -@Mod(WatchMyDurability.MODID) -public class WatchMyDurability -{ - // Define mod id in a common place for everything to reference - public static final String MODID = "watchmydurability"; - // Directly reference a slf4j logger - public static final Logger LOGGER = LogUtils.getLogger(); - - /// DO NOT USE FROM ANY THIRD PARTY PACKAGES - public static User CurrentUser = null; // This is initialized by the client - public static boolean isInGame = false; // This locks the timer thread - public static ItemRegistry REGISTRY; - public static Health LastHealth; - public static Hunger LastHunger; - public static String WMDPrefix; - - - - public WatchMyDurability() - { - WatchMyDurability.WMDPrefix = ChatColor.doColors("!Dark_Gray![!Bold!!Dark_Green!WMD!Reset!!Dark_Gray!]!reset!"); - - IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); - - // Register the commonSetup method for modloading - modEventBus.addListener(this::commonSetup); - ModLoadingContext.get().registerConfig(Type.CLIENT, WMDClientConfig.SPEC, "watchmydurability-client.toml"); - - // Register ourselves for server and other game events we are interested in - MinecraftForge.EVENT_BUS.register(this); - } - - private void commonSetup(final FMLCommonSetupEvent event) - { - // Some common setup code - //LOGGER.info("HELLO FROM COMMON SETUP"); - } - - - public static void Soundify(SoundEvent sound) - { - //WatchMyDurability.LOGGER.info("PLAY ALERT SOUND"); - Minecraft.getInstance().player.playSound(sound, 1.0f, 1.0f); - } - // You can use SubscribeEvent and let the Event Bus discover methods to call - @SubscribeEvent - public void onServerStarting(ServerStartingEvent event) - { - // Do something when the server starts - //LOGGER.warn("If this is running on a server, it is doing absolutely nothing, please remove me."); - } - - // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent - @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD) - public static class ClientModEvents - { - static Timer time = new Timer(); - - @SubscribeEvent - public static void onClientSetup(FMLClientSetupEvent event) - { - LOGGER.info(WMDPrefix+": : : CLIENT SETUP : : :"); - // Some client setup code - //LOGGER.info("HELLO FROM CLIENT SETUP"); - //LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName()); - WatchMyDurability.CurrentUser = Minecraft.getInstance().getUser(); - DelayedExecutorService.setup(); - - - //time.schedule(new CheckInventory(), - //WMDClientConfig.TimerVal.get()*1000, - //WMDClientConfig.TimerVal.get()*1000); - - ItemRegistry.Initialize(); - - } - - } - - @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) - public static class ClientEvents - { - - @SubscribeEvent - public static void onJoin(ClientPlayerNetworkEvent.LoggingIn event){ - // Joined - //LOGGER.info("PLAYER LOGGED IN"); - LOGGER.info(WMDPrefix+": : : PLAYER LOGGED IN : : :"); - WatchMyDurability.isInGame=true; - DelayedExecutorService.start(); - - DelayedExecutorService.getInstance().scheduleRepeating(CheckInventory.getInstance(), WMDClientConfig.TimerVal.get()); - DelayedExecutorService.getInstance().scheduleRepeating(CheckHealth.getInstance(), WMDClientConfig.TimerVal.get()); - DelayedExecutorService.getInstance().scheduleRepeating(CheckHunger.getInstance(), WMDClientConfig.TimerVal.get()); - } - - @SubscribeEvent - public static void onLeave(ClientPlayerNetworkEvent.LoggingOut event){ - //LOGGER.info("PLAYER LOGGED OUT"); - LOGGER.info(WMDPrefix+": : : PLAYER LOGGED OUT : : :"); - WatchMyDurability.isInGame=false; - DelayedExecutorService.stop(); - } - - @SubscribeEvent - public static void onClone(ClientPlayerNetworkEvent.Clone event) - { - LOGGER.info(WMDPrefix+": : : : PLAYER RESPAWNED OR MOVED TO A NEW WORLD : : : :"); - - } - } -} +package dev.zontreck.wmd; + +import com.mojang.logging.LogUtils; + +import dev.zontreck.ariaslib.util.DelayedExecutorService; +import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.wmd.configs.WMDClientConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.client.User; +import net.minecraft.sounds.SoundEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig.Type; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.event.server.ServerStartingEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent; + +import java.util.Timer; + +import org.slf4j.Logger; + +// The value here should match an entry in the META-INF/mods.toml file +@Mod(WatchMyDurability.MODID) +public class WatchMyDurability +{ + // Define mod id in a common place for everything to reference + public static final String MODID = "watchmydurability"; + // Directly reference a slf4j logger + public static final Logger LOGGER = LogUtils.getLogger(); + + /// DO NOT USE FROM ANY THIRD PARTY PACKAGES + public static User CurrentUser = null; // This is initialized by the client + public static boolean isInGame = false; // This locks the timer thread + public static ItemRegistry REGISTRY; + public static Health LastHealth; + public static Hunger LastHunger; + public static String WMDPrefix; + + + + public WatchMyDurability() + { + WatchMyDurability.WMDPrefix = ChatColor.doColors("!Dark_Gray![!Bold!!Dark_Green!WMD!Reset!!Dark_Gray!]!reset!"); + + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + + // Register the commonSetup method for modloading + modEventBus.addListener(this::commonSetup); + ModLoadingContext.get().registerConfig(Type.CLIENT, WMDClientConfig.SPEC, "watchmydurability-client.toml"); + + // Register ourselves for server and other game events we are interested in + MinecraftForge.EVENT_BUS.register(this); + } + + private void commonSetup(final FMLCommonSetupEvent event) + { + // Some common setup code + //LOGGER.info("HELLO FROM COMMON SETUP"); + } + + + public static void Soundify(SoundEvent sound) + { + //WatchMyDurability.LOGGER.info("PLAY ALERT SOUND"); + Minecraft.getInstance().player.playSound(sound, 1.0f, 1.0f); + } + // You can use SubscribeEvent and let the Event Bus discover methods to call + @SubscribeEvent + public void onServerStarting(ServerStartingEvent event) + { + // Do something when the server starts + //LOGGER.warn("If this is running on a server, it is doing absolutely nothing, please remove me."); + } + + // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent + @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD) + public static class ClientModEvents + { + static Timer time = new Timer(); + + @SubscribeEvent + public static void onClientSetup(FMLClientSetupEvent event) + { + LOGGER.info(WMDPrefix+": : : CLIENT SETUP : : :"); + // Some client setup code + //LOGGER.info("HELLO FROM CLIENT SETUP"); + //LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName()); + WatchMyDurability.CurrentUser = Minecraft.getInstance().getUser(); + DelayedExecutorService.setup(); + + + //time.schedule(new CheckInventory(), + //WMDClientConfig.TimerVal.get()*1000, + //WMDClientConfig.TimerVal.get()*1000); + + ItemRegistry.Initialize(); + + } + + } + + @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) + public static class ClientEvents + { + + @SubscribeEvent + public static void onJoin(ClientPlayerNetworkEvent.LoggingIn event){ + // Joined + //LOGGER.info("PLAYER LOGGED IN"); + LOGGER.info(WMDPrefix+": : : PLAYER LOGGED IN : : :"); + WatchMyDurability.isInGame=true; + DelayedExecutorService.start(); + + DelayedExecutorService.getInstance().scheduleRepeating(CheckInventory.getInstance(), WMDClientConfig.TimerVal.get()); + DelayedExecutorService.getInstance().scheduleRepeating(CheckHealth.getInstance(), WMDClientConfig.TimerVal.get()); + DelayedExecutorService.getInstance().scheduleRepeating(CheckHunger.getInstance(), WMDClientConfig.TimerVal.get()); + } + + @SubscribeEvent + public static void onLeave(ClientPlayerNetworkEvent.LoggingOut event){ + //LOGGER.info("PLAYER LOGGED OUT"); + LOGGER.info(WMDPrefix+": : : PLAYER LOGGED OUT : : :"); + WatchMyDurability.isInGame=false; + DelayedExecutorService.stop(); + } + + @SubscribeEvent + public static void onClone(ClientPlayerNetworkEvent.Clone event) + { + LOGGER.info(WMDPrefix+": : : : PLAYER RESPAWNED OR MOVED TO A NEW WORLD : : : :"); + + } + } +} diff --git a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java b/src/main/java/dev/zontreck/wmd/configs/WMDClientConfig.java similarity index 96% rename from src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java rename to src/main/java/dev/zontreck/wmd/configs/WMDClientConfig.java index 98a5210..980092e 100644 --- a/src/main/java/dev/zontreck/mcmods/configs/WMDClientConfig.java +++ b/src/main/java/dev/zontreck/wmd/configs/WMDClientConfig.java @@ -1,42 +1,42 @@ -package dev.zontreck.mcmods.configs; - -import java.util.ArrayList; -import java.util.List; - -import net.minecraftforge.common.ForgeConfigSpec; - -public class WMDClientConfig { - public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); - public static final ForgeConfigSpec SPEC; - - public static ForgeConfigSpec.ConfigValue> alertPercents; - public static ForgeConfigSpec.ConfigValue> alertMessages; - public static ForgeConfigSpec.ConfigValue TimerVal; - public static ForgeConfigSpec.ConfigValue EnableExtraHearts; - public static ForgeConfigSpec.ConfigValue EnableHealthAlert; - public static ForgeConfigSpec.ConfigValue EnableHungerAlert; - - static{ - List alerts1 = new ArrayList<>(); - alerts1.add(10); - - List alerts2 = new ArrayList<>(); - alerts2.add("!item! is about to break"); - - - BUILDER.push("Alerts"); - BUILDER.comment("Both of the following lists must have the same number of entries. NOTE: Percents do NOT stack. After the first rule is applied, it will move to the next item, so please make the list ascend, and not descend. Example: 10, 50").define("VERSION", "1.1.1.1"); - - alertPercents = BUILDER.comment("The list of alerts you want at what percentages of remaining durability").define("Percents", alerts1); - alertMessages = BUILDER.comment("The messages you want displayed when a alert is triggered. You must have the same amount of messages as alerts").define("Messages", alerts2); - TimerVal = BUILDER.comment("How many seconds between timer ticks to check your inventory items?").define("Timer", 5); - - BUILDER.pop(); - - BUILDER.push("General"); - EnableHealthAlert = BUILDER.comment("The following was added for a friend. If you need reminders to eat in order to heal, turn the below option on").define("watchMyHealth", false); - EnableHungerAlert = BUILDER.comment("This is a newer setting to watch your hunger status instead of your hunger to alert when you need to eat").define("watchMyHunger", true); - - SPEC=BUILDER.build(); - } -} +package dev.zontreck.wmd.configs; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraftforge.common.ForgeConfigSpec; + +public class WMDClientConfig { + public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); + public static final ForgeConfigSpec SPEC; + + public static ForgeConfigSpec.ConfigValue> alertPercents; + public static ForgeConfigSpec.ConfigValue> alertMessages; + public static ForgeConfigSpec.ConfigValue TimerVal; + public static ForgeConfigSpec.ConfigValue EnableExtraHearts; + public static ForgeConfigSpec.ConfigValue EnableHealthAlert; + public static ForgeConfigSpec.ConfigValue EnableHungerAlert; + + static{ + List alerts1 = new ArrayList<>(); + alerts1.add(10); + + List alerts2 = new ArrayList<>(); + alerts2.add("!item! is about to break"); + + + BUILDER.push("Alerts"); + BUILDER.comment("Both of the following lists must have the same number of entries. NOTE: Percents do NOT stack. After the first rule is applied, it will move to the next item, so please make the list ascend, and not descend. Example: 10, 50").define("VERSION", "1.1.1.1"); + + alertPercents = BUILDER.comment("The list of alerts you want at what percentages of remaining durability").define("Percents", alerts1); + alertMessages = BUILDER.comment("The messages you want displayed when a alert is triggered. You must have the same amount of messages as alerts").define("Messages", alerts2); + TimerVal = BUILDER.comment("How many seconds between timer ticks to check your inventory items?").define("Timer", 5); + + BUILDER.pop(); + + BUILDER.push("General"); + EnableHealthAlert = BUILDER.comment("The following was added for a friend. If you need reminders to eat in order to heal, turn the below option on").define("watchMyHealth", false); + EnableHungerAlert = BUILDER.comment("This is a newer setting to watch your hunger status instead of your hunger to alert when you need to eat").define("watchMyHunger", true); + + SPEC=BUILDER.build(); + } +} From 131cd673f8cac5cf432e30e313bce9f5ac3d276e Mon Sep 17 00:00:00 2001 From: zontreck Date: Tue, 9 Jan 2024 14:57:08 -0700 Subject: [PATCH 24/28] Restructure some stuff --- src/main/java/dev/zontreck/wmd/WatchMyDurability.java | 6 ++++++ .../java/dev/zontreck/wmd/{ => checkers}/CheckHealth.java | 5 +++-- .../java/dev/zontreck/wmd/{ => checkers}/CheckHunger.java | 5 +++-- .../dev/zontreck/wmd/{ => checkers}/CheckInventory.java | 5 +++-- src/main/java/dev/zontreck/wmd/{ => types}/Health.java | 2 +- src/main/java/dev/zontreck/wmd/{ => types}/Hunger.java | 3 ++- .../java/dev/zontreck/wmd/{ => types}/ItemRegistry.java | 3 ++- 7 files changed, 20 insertions(+), 9 deletions(-) rename src/main/java/dev/zontreck/wmd/{ => checkers}/CheckHealth.java (92%) rename src/main/java/dev/zontreck/wmd/{ => checkers}/CheckHunger.java (91%) rename src/main/java/dev/zontreck/wmd/{ => checkers}/CheckInventory.java (97%) rename src/main/java/dev/zontreck/wmd/{ => types}/Health.java (95%) rename src/main/java/dev/zontreck/wmd/{ => types}/Hunger.java (88%) rename src/main/java/dev/zontreck/wmd/{ => types}/ItemRegistry.java (97%) diff --git a/src/main/java/dev/zontreck/wmd/WatchMyDurability.java b/src/main/java/dev/zontreck/wmd/WatchMyDurability.java index 17d84ef..07c8b6c 100644 --- a/src/main/java/dev/zontreck/wmd/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/wmd/WatchMyDurability.java @@ -4,7 +4,13 @@ import com.mojang.logging.LogUtils; import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.wmd.checkers.CheckHealth; +import dev.zontreck.wmd.checkers.CheckHunger; +import dev.zontreck.wmd.checkers.CheckInventory; import dev.zontreck.wmd.configs.WMDClientConfig; +import dev.zontreck.wmd.types.Health; +import dev.zontreck.wmd.types.Hunger; +import dev.zontreck.wmd.types.ItemRegistry; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraft.sounds.SoundEvent; diff --git a/src/main/java/dev/zontreck/wmd/CheckHealth.java b/src/main/java/dev/zontreck/wmd/checkers/CheckHealth.java similarity index 92% rename from src/main/java/dev/zontreck/wmd/CheckHealth.java rename to src/main/java/dev/zontreck/wmd/checkers/CheckHealth.java index 4fd8899..590246a 100644 --- a/src/main/java/dev/zontreck/wmd/CheckHealth.java +++ b/src/main/java/dev/zontreck/wmd/checkers/CheckHealth.java @@ -1,8 +1,9 @@ -package dev.zontreck.wmd; +package dev.zontreck.wmd.checkers; import dev.zontreck.ariaslib.terminal.Task; -import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.wmd.types.Health; +import dev.zontreck.wmd.WatchMyDurability; import dev.zontreck.wmd.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; diff --git a/src/main/java/dev/zontreck/wmd/CheckHunger.java b/src/main/java/dev/zontreck/wmd/checkers/CheckHunger.java similarity index 91% rename from src/main/java/dev/zontreck/wmd/CheckHunger.java rename to src/main/java/dev/zontreck/wmd/checkers/CheckHunger.java index 51fea8b..c43557f 100644 --- a/src/main/java/dev/zontreck/wmd/CheckHunger.java +++ b/src/main/java/dev/zontreck/wmd/checkers/CheckHunger.java @@ -1,8 +1,9 @@ -package dev.zontreck.wmd; +package dev.zontreck.wmd.checkers; import dev.zontreck.ariaslib.terminal.Task; -import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.wmd.types.Hunger; +import dev.zontreck.wmd.WatchMyDurability; import dev.zontreck.wmd.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; diff --git a/src/main/java/dev/zontreck/wmd/CheckInventory.java b/src/main/java/dev/zontreck/wmd/checkers/CheckInventory.java similarity index 97% rename from src/main/java/dev/zontreck/wmd/CheckInventory.java rename to src/main/java/dev/zontreck/wmd/checkers/CheckInventory.java index 6429464..e5703f7 100644 --- a/src/main/java/dev/zontreck/wmd/CheckInventory.java +++ b/src/main/java/dev/zontreck/wmd/checkers/CheckInventory.java @@ -1,13 +1,14 @@ -package dev.zontreck.wmd; +package dev.zontreck.wmd.checkers; import java.util.HashMap; import java.util.List; import java.util.Map; import dev.zontreck.ariaslib.terminal.Task; -import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.libzontreck.chat.HoverTip; +import dev.zontreck.wmd.types.ItemRegistry; +import dev.zontreck.wmd.WatchMyDurability; import dev.zontreck.wmd.configs.WMDClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.core.NonNullList; diff --git a/src/main/java/dev/zontreck/wmd/Health.java b/src/main/java/dev/zontreck/wmd/types/Health.java similarity index 95% rename from src/main/java/dev/zontreck/wmd/Health.java rename to src/main/java/dev/zontreck/wmd/types/Health.java index 1786b2a..d13121a 100644 --- a/src/main/java/dev/zontreck/wmd/Health.java +++ b/src/main/java/dev/zontreck/wmd/types/Health.java @@ -1,4 +1,4 @@ -package dev.zontreck.wmd; +package dev.zontreck.wmd.types; import net.minecraft.world.entity.player.Player; diff --git a/src/main/java/dev/zontreck/wmd/Hunger.java b/src/main/java/dev/zontreck/wmd/types/Hunger.java similarity index 88% rename from src/main/java/dev/zontreck/wmd/Hunger.java rename to src/main/java/dev/zontreck/wmd/types/Hunger.java index b566926..cb5bfb6 100644 --- a/src/main/java/dev/zontreck/wmd/Hunger.java +++ b/src/main/java/dev/zontreck/wmd/types/Hunger.java @@ -1,5 +1,6 @@ -package dev.zontreck.wmd; +package dev.zontreck.wmd.types; +import dev.zontreck.wmd.WatchMyDurability; import net.minecraft.world.entity.player.Player; public class Hunger diff --git a/src/main/java/dev/zontreck/wmd/ItemRegistry.java b/src/main/java/dev/zontreck/wmd/types/ItemRegistry.java similarity index 97% rename from src/main/java/dev/zontreck/wmd/ItemRegistry.java rename to src/main/java/dev/zontreck/wmd/types/ItemRegistry.java index d791527..eebba51 100644 --- a/src/main/java/dev/zontreck/wmd/ItemRegistry.java +++ b/src/main/java/dev/zontreck/wmd/types/ItemRegistry.java @@ -1,8 +1,9 @@ -package dev.zontreck.wmd; +package dev.zontreck.wmd.types; import java.util.HashMap; import java.util.Map; +import dev.zontreck.wmd.WatchMyDurability; import net.minecraft.world.item.ItemStack; public class ItemRegistry { From bf2d5c83d92b4b8cc6720ecbcbc6fc1d3f78f95f Mon Sep 17 00:00:00 2001 From: zontreck Date: Wed, 10 Jan 2024 03:31:48 -0700 Subject: [PATCH 25/28] Add a basic config gui to WMD when the jar is on the server --- gradle.properties | 4 +- .../dev/zontreck/wmd/WatchMyDurability.java | 27 ++-- .../zontreck/wmd/checkers/CheckHealth.java | 3 +- .../zontreck/wmd/checkers/CheckHunger.java | 3 +- .../zontreck/wmd/checkers/CheckInventory.java | 7 +- .../zontreck/wmd/commands/ModCommands.java | 14 ++ .../wmd/commands/impl/SettingsCommand.java | 21 +++ .../zontreck/wmd/configs/WMDClientConfig.java | 40 +++++- .../dev/zontreck/wmd/events/EventHandler.java | 17 +++ .../zontreck/wmd/networking/ModMessages.java | 76 +++++++++++ .../packets/c2s/ClientConfigResponse.java | 126 ++++++++++++++++++ .../packets/s2c/PushClientConfigUpdate.java | 36 +++++ .../packets/s2c/RequestClientConfig.java | 35 +++++ .../packets/s2c/S2CResetConfig.java | 45 +++++++ .../packets/s2c/WMDServerAvailable.java | 42 ++++++ .../zontreck/wmd/utils/client/Helpers.java | 14 ++ 16 files changed, 488 insertions(+), 22 deletions(-) create mode 100644 src/main/java/dev/zontreck/wmd/commands/ModCommands.java create mode 100644 src/main/java/dev/zontreck/wmd/commands/impl/SettingsCommand.java create mode 100644 src/main/java/dev/zontreck/wmd/events/EventHandler.java create mode 100644 src/main/java/dev/zontreck/wmd/networking/ModMessages.java create mode 100644 src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java create mode 100644 src/main/java/dev/zontreck/wmd/networking/packets/s2c/PushClientConfigUpdate.java create mode 100644 src/main/java/dev/zontreck/wmd/networking/packets/s2c/RequestClientConfig.java create mode 100644 src/main/java/dev/zontreck/wmd/networking/packets/s2c/S2CResetConfig.java create mode 100644 src/main/java/dev/zontreck/wmd/networking/packets/s2c/WMDServerAvailable.java create mode 100644 src/main/java/dev/zontreck/wmd/utils/client/Helpers.java diff --git a/gradle.properties b/gradle.properties index 5acae1d..8a18026 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -libzontreck=1.10.010924.1444 +libzontreck=1.10.011024.0312 ## Environment Properties @@ -49,7 +49,7 @@ mod_name=WatchMyDurability # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1.2.010924.1451 +mod_version=1.2.011024.0208 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/dev/zontreck/wmd/WatchMyDurability.java b/src/main/java/dev/zontreck/wmd/WatchMyDurability.java index 07c8b6c..1707751 100644 --- a/src/main/java/dev/zontreck/wmd/WatchMyDurability.java +++ b/src/main/java/dev/zontreck/wmd/WatchMyDurability.java @@ -7,13 +7,15 @@ import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.wmd.checkers.CheckHealth; import dev.zontreck.wmd.checkers.CheckHunger; import dev.zontreck.wmd.checkers.CheckInventory; +import dev.zontreck.wmd.commands.ModCommands; import dev.zontreck.wmd.configs.WMDClientConfig; +import dev.zontreck.wmd.networking.ModMessages; import dev.zontreck.wmd.types.Health; import dev.zontreck.wmd.types.Hunger; import dev.zontreck.wmd.types.ItemRegistry; import net.minecraft.client.Minecraft; import net.minecraft.client.User; -import net.minecraft.sounds.SoundEvent; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -45,13 +47,12 @@ public class WatchMyDurability public static ItemRegistry REGISTRY; public static Health LastHealth; public static Hunger LastHunger; - public static String WMDPrefix; + public static boolean WMD_SERVER_AVAILABLE =false; public WatchMyDurability() { - WatchMyDurability.WMDPrefix = ChatColor.doColors("!Dark_Gray![!Bold!!Dark_Green!WMD!Reset!!Dark_Gray!]!reset!"); IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); @@ -61,20 +62,17 @@ public class WatchMyDurability // Register ourselves for server and other game events we are interested in MinecraftForge.EVENT_BUS.register(this); + MinecraftForge.EVENT_BUS.register(new ModCommands()); } private void commonSetup(final FMLCommonSetupEvent event) { // Some common setup code //LOGGER.info("HELLO FROM COMMON SETUP"); + ModMessages.register(); } - public static void Soundify(SoundEvent sound) - { - //WatchMyDurability.LOGGER.info("PLAY ALERT SOUND"); - Minecraft.getInstance().player.playSound(sound, 1.0f, 1.0f); - } // You can use SubscribeEvent and let the Event Bus discover methods to call @SubscribeEvent public void onServerStarting(ServerStartingEvent event) @@ -84,7 +82,7 @@ public class WatchMyDurability } // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent - @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD) + @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public static class ClientModEvents { static Timer time = new Timer(); @@ -92,7 +90,7 @@ public class WatchMyDurability @SubscribeEvent public static void onClientSetup(FMLClientSetupEvent event) { - LOGGER.info(WMDPrefix+": : : CLIENT SETUP : : :"); + LOGGER.info(": : : CLIENT SETUP : : :"); // Some client setup code //LOGGER.info("HELLO FROM CLIENT SETUP"); //LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName()); @@ -110,7 +108,7 @@ public class WatchMyDurability } - @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) + @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) public static class ClientEvents { @@ -118,7 +116,7 @@ public class WatchMyDurability public static void onJoin(ClientPlayerNetworkEvent.LoggingIn event){ // Joined //LOGGER.info("PLAYER LOGGED IN"); - LOGGER.info(WMDPrefix+": : : PLAYER LOGGED IN : : :"); + LOGGER.info(": : : PLAYER LOGGED IN : : :"); WatchMyDurability.isInGame=true; DelayedExecutorService.start(); @@ -130,15 +128,16 @@ public class WatchMyDurability @SubscribeEvent public static void onLeave(ClientPlayerNetworkEvent.LoggingOut event){ //LOGGER.info("PLAYER LOGGED OUT"); - LOGGER.info(WMDPrefix+": : : PLAYER LOGGED OUT : : :"); + LOGGER.info(": : : PLAYER LOGGED OUT : : :"); WatchMyDurability.isInGame=false; + WatchMyDurability.WMD_SERVER_AVAILABLE=false; DelayedExecutorService.stop(); } @SubscribeEvent public static void onClone(ClientPlayerNetworkEvent.Clone event) { - LOGGER.info(WMDPrefix+": : : : PLAYER RESPAWNED OR MOVED TO A NEW WORLD : : : :"); + LOGGER.info(": : : : PLAYER RESPAWNED OR MOVED TO A NEW WORLD : : : :"); } } diff --git a/src/main/java/dev/zontreck/wmd/checkers/CheckHealth.java b/src/main/java/dev/zontreck/wmd/checkers/CheckHealth.java index 590246a..3578a62 100644 --- a/src/main/java/dev/zontreck/wmd/checkers/CheckHealth.java +++ b/src/main/java/dev/zontreck/wmd/checkers/CheckHealth.java @@ -5,6 +5,7 @@ import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.wmd.types.Health; import dev.zontreck.wmd.WatchMyDurability; import dev.zontreck.wmd.configs.WMDClientConfig; +import dev.zontreck.wmd.utils.client.Helpers; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvent; @@ -43,7 +44,7 @@ public class CheckHealth extends Task Minecraft.getInstance().player.displayClientMessage(chat, false); SoundEvent sv = SoundEvents.WARDEN_ROAR; // It sounds like a growling stomach - WatchMyDurability.Soundify(sv); + Helpers.Soundify(sv); } WatchMyDurability.LastHealth=current; diff --git a/src/main/java/dev/zontreck/wmd/checkers/CheckHunger.java b/src/main/java/dev/zontreck/wmd/checkers/CheckHunger.java index c43557f..58e2654 100644 --- a/src/main/java/dev/zontreck/wmd/checkers/CheckHunger.java +++ b/src/main/java/dev/zontreck/wmd/checkers/CheckHunger.java @@ -5,6 +5,7 @@ import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.wmd.types.Hunger; import dev.zontreck.wmd.WatchMyDurability; import dev.zontreck.wmd.configs.WMDClientConfig; +import dev.zontreck.wmd.utils.client.Helpers; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvent; @@ -39,7 +40,7 @@ public class CheckHunger extends Task Minecraft.getInstance().player.displayClientMessage(chat, false); SoundEvent sv = SoundEvents.WARDEN_ROAR; // It sounds like a growling stomach - WatchMyDurability.Soundify(sv); + Helpers.Soundify(sv); } WatchMyDurability.LastHunger = current; diff --git a/src/main/java/dev/zontreck/wmd/checkers/CheckInventory.java b/src/main/java/dev/zontreck/wmd/checkers/CheckInventory.java index e5703f7..fbb112a 100644 --- a/src/main/java/dev/zontreck/wmd/checkers/CheckInventory.java +++ b/src/main/java/dev/zontreck/wmd/checkers/CheckInventory.java @@ -7,9 +7,11 @@ import java.util.Map; import dev.zontreck.ariaslib.terminal.Task; import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.libzontreck.chat.HoverTip; +import dev.zontreck.libzontreck.util.ChatHelpers; import dev.zontreck.wmd.types.ItemRegistry; import dev.zontreck.wmd.WatchMyDurability; import dev.zontreck.wmd.configs.WMDClientConfig; +import dev.zontreck.wmd.utils.client.Helpers; import net.minecraft.client.Minecraft; import net.minecraft.core.NonNullList; import net.minecraft.network.chat.Component; @@ -34,6 +36,7 @@ public class CheckInventory extends Task { @Override public void run() { + if(!WMDClientConfig.EnableToolWatcher.get()) return; try { if(!WatchMyDurability.isInGame)return; @@ -95,11 +98,11 @@ public class CheckInventory extends Task { String entryStr = WMDClientConfig.alertMessages.get().get(idx); if(percent <= entry){ - String replaced = WatchMyDurability.WMDPrefix + ChatColor.DARK_RED + entryStr.replaceAll("!item!", is1.getDisplayName().getString()); + String replaced = ChatColor.doColors(WMDClientConfig.WMD_PREFIX.get()) + ChatColor.DARK_RED + entryStr.replaceAll("!item!", is1.getDisplayName().getString()); WatchMyDurability.LOGGER.info("Enqueue alert for an item. Playing sound for item: "+is1.getDisplayName().getString()); SoundEvent theSound = SoundEvents.ITEM_BREAK; - WatchMyDurability.Soundify(theSound); + Helpers.Soundify(theSound); diff --git a/src/main/java/dev/zontreck/wmd/commands/ModCommands.java b/src/main/java/dev/zontreck/wmd/commands/ModCommands.java new file mode 100644 index 0000000..8541f01 --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/commands/ModCommands.java @@ -0,0 +1,14 @@ +package dev.zontreck.wmd.commands; + +import dev.zontreck.wmd.commands.impl.SettingsCommand; +import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +public class ModCommands +{ + @SubscribeEvent + public void register(final RegisterCommandsEvent event) + { + SettingsCommand.register(event.getDispatcher()); + } +} diff --git a/src/main/java/dev/zontreck/wmd/commands/impl/SettingsCommand.java b/src/main/java/dev/zontreck/wmd/commands/impl/SettingsCommand.java new file mode 100644 index 0000000..c52215d --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/commands/impl/SettingsCommand.java @@ -0,0 +1,21 @@ +package dev.zontreck.wmd.commands.impl; + +import com.mojang.brigadier.CommandDispatcher; +import dev.zontreck.wmd.networking.ModMessages; +import dev.zontreck.wmd.networking.packets.s2c.RequestClientConfig; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; + +public class SettingsCommand +{ + public static void register(CommandDispatcher dispatcher) + { + dispatcher.register(Commands.literal("wmdsettings").executes(c->settingsPrompt(c.getSource()))); + } + + public static int settingsPrompt(CommandSourceStack sender) + { + ModMessages.sendToPlayer(new RequestClientConfig(), sender.getPlayer()); + return 0; + } +} diff --git a/src/main/java/dev/zontreck/wmd/configs/WMDClientConfig.java b/src/main/java/dev/zontreck/wmd/configs/WMDClientConfig.java index 980092e..7c27ba3 100644 --- a/src/main/java/dev/zontreck/wmd/configs/WMDClientConfig.java +++ b/src/main/java/dev/zontreck/wmd/configs/WMDClientConfig.java @@ -3,6 +3,7 @@ package dev.zontreck.wmd.configs; import java.util.ArrayList; import java.util.List; +import net.minecraft.nbt.CompoundTag; import net.minecraftforge.common.ForgeConfigSpec; public class WMDClientConfig { @@ -12,9 +13,12 @@ public class WMDClientConfig { public static ForgeConfigSpec.ConfigValue> alertPercents; public static ForgeConfigSpec.ConfigValue> alertMessages; public static ForgeConfigSpec.ConfigValue TimerVal; - public static ForgeConfigSpec.ConfigValue EnableExtraHearts; public static ForgeConfigSpec.ConfigValue EnableHealthAlert; public static ForgeConfigSpec.ConfigValue EnableHungerAlert; + public static ForgeConfigSpec.ConfigValue EnableToolWatcher; + + + public static ForgeConfigSpec.ConfigValue WMD_PREFIX; static{ List alerts1 = new ArrayList<>(); @@ -35,8 +39,40 @@ public class WMDClientConfig { BUILDER.push("General"); EnableHealthAlert = BUILDER.comment("The following was added for a friend. If you need reminders to eat in order to heal, turn the below option on").define("watchMyHealth", false); - EnableHungerAlert = BUILDER.comment("This is a newer setting to watch your hunger status instead of your hunger to alert when you need to eat").define("watchMyHunger", true); + EnableHungerAlert = BUILDER.comment("This is a newer setting to watch your hunger status instead of your hunger to alert when you need to eat").define("watchMyHunger", false); + EnableToolWatcher = BUILDER.comment("Enable watching tool durability").define("watchDurability", true); + BUILDER.pop(); + + + BUILDER.push("Messages"); + + WMD_PREFIX = BUILDER.comment("The prefix string for WMD").define("prefix", "!Dark_Gray![!Bold!!Dark_Green!WMD!Reset!!Dark_Gray!]!Reset!"); SPEC=BUILDER.build(); } + + public static CompoundTag serialize() + { + CompoundTag ret = new CompoundTag(); + + ret.putBoolean("watchMyHealth", EnableHealthAlert.get()); + ret.putBoolean("watchMyHunger", EnableHungerAlert.get()); + ret.putBoolean("watchDurability", EnableToolWatcher.get()); + + + + return ret; + } + + public static void deserialize(CompoundTag tag) + { + EnableHealthAlert.set(tag.getBoolean("watchMyHealth")); + EnableHealthAlert.save(); + + EnableHungerAlert.set(tag.getBoolean("watchMyHunger")); + EnableHungerAlert.save(); + + EnableToolWatcher.set(tag.getBoolean("watchDurability")); + EnableToolWatcher.save(); + } } diff --git a/src/main/java/dev/zontreck/wmd/events/EventHandler.java b/src/main/java/dev/zontreck/wmd/events/EventHandler.java new file mode 100644 index 0000000..a304a75 --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/events/EventHandler.java @@ -0,0 +1,17 @@ +package dev.zontreck.wmd.events; + +import dev.zontreck.libzontreck.LibZontreck; +import dev.zontreck.wmd.WatchMyDurability; +import dev.zontreck.wmd.networking.packets.s2c.WMDServerAvailable; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +public class EventHandler +{ + @SubscribeEvent + public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) + { + WMDServerAvailable avail = new WMDServerAvailable(); + avail.send(event.getEntity().getUUID()); + } +} diff --git a/src/main/java/dev/zontreck/wmd/networking/ModMessages.java b/src/main/java/dev/zontreck/wmd/networking/ModMessages.java new file mode 100644 index 0000000..727b396 --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/networking/ModMessages.java @@ -0,0 +1,76 @@ +package dev.zontreck.wmd.networking; + +import dev.zontreck.wmd.WatchMyDurability; +import dev.zontreck.wmd.networking.packets.c2s.ClientConfigResponse; +import dev.zontreck.wmd.networking.packets.s2c.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.NetworkRegistry; +import net.minecraftforge.network.PacketDistributor; +import net.minecraftforge.network.simple.SimpleChannel; + +public class ModMessages +{ + private static SimpleChannel channel; + private static int PACKET_ID = 0; + private static int id() + { + return PACKET_ID++; + } + + public static void register() + { + SimpleChannel net = NetworkRegistry.ChannelBuilder.named(new ResourceLocation(WatchMyDurability.MODID, "messages")) + .networkProtocolVersion(()->"1.0") + .clientAcceptedVersions(s->true) + .serverAcceptedVersions(s->true) + .simpleChannel(); + channel = net; + + net.messageBuilder(WMDServerAvailable.class, id(), NetworkDirection.PLAY_TO_CLIENT) + .encoder(WMDServerAvailable::toBytes) + .decoder(WMDServerAvailable::new) + .consumerMainThread(WMDServerAvailable::handle) + .add(); + + net.messageBuilder(S2CResetConfig.class, id(), NetworkDirection.PLAY_TO_CLIENT) + .encoder(S2CResetConfig::toBytes) + .decoder(S2CResetConfig::new) + .consumerMainThread(S2CResetConfig::handle) + .add(); + + net.messageBuilder(RequestClientConfig.class, id(), NetworkDirection.PLAY_TO_CLIENT) + .encoder(RequestClientConfig::toBytes) + .decoder(RequestClientConfig::new) + .consumerMainThread(RequestClientConfig::handle) + .add(); + + net.messageBuilder(ClientConfigResponse.class, id(), NetworkDirection.PLAY_TO_SERVER) + .encoder(ClientConfigResponse::toBytes) + .decoder(ClientConfigResponse::new) + .consumerMainThread(ClientConfigResponse::handle) + .add(); + + net.messageBuilder(PushClientConfigUpdate.class, id(), NetworkDirection.PLAY_TO_CLIENT) + .encoder(PushClientConfigUpdate::toBytes) + .decoder(PushClientConfigUpdate::new) + .consumerMainThread(PushClientConfigUpdate::handle) + .add(); + } + + + public static void sendToServer(MSG message){ + channel.sendToServer(message); + } + + public static void sendToPlayer(MSG message, ServerPlayer player) + { + channel.send(PacketDistributor.PLAYER.with(()->player), message); + } + + public static void sendToAll(MSG message) + { + channel.send(PacketDistributor.ALL.noArg(), message); + } +} diff --git a/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java b/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java new file mode 100644 index 0000000..9354f18 --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java @@ -0,0 +1,126 @@ +package dev.zontreck.wmd.networking.packets.c2s; + +import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.libzontreck.chestgui.ChestGUI; +import dev.zontreck.libzontreck.chestgui.ChestGUIButton; +import dev.zontreck.libzontreck.chestgui.ChestGUIIdentifier; +import dev.zontreck.libzontreck.lore.LoreEntry; +import dev.zontreck.libzontreck.util.ServerUtilities; +import dev.zontreck.libzontreck.vectors.Vector2i; +import dev.zontreck.wmd.WatchMyDurability; +import dev.zontreck.wmd.configs.WMDClientConfig; +import dev.zontreck.wmd.networking.ModMessages; +import dev.zontreck.wmd.networking.packets.s2c.PushClientConfigUpdate; +import dev.zontreck.wmd.networking.packets.s2c.RequestClientConfig; +import dev.zontreck.wmd.networking.packets.s2c.S2CResetConfig; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraftforge.network.NetworkEvent; + +import java.util.UUID; +import java.util.function.Supplier; + +public class ClientConfigResponse +{ + public CompoundTag tag; + public UUID id; + + public ClientConfigResponse(FriendlyByteBuf buf) + { + tag = buf.readAnySizeNbt(); + id = buf.readUUID(); + } + + public ClientConfigResponse(UUID playerID) + { + tag = WMDClientConfig.serialize(); + id = playerID; + } + + public void toBytes(FriendlyByteBuf buf) + { + buf.writeNbt(tag); + buf.writeUUID(id); + } + + public void handle(Supplier supplier) + { + NetworkEvent.Context ctx = supplier.get(); + + ctx.enqueueWork(()->{ + // Open config editor for player + boolean enableHealth = tag.getBoolean("watchMyHealth"); + boolean enableHunger = tag.getBoolean("watchMyHunger"); + boolean enableDurability = tag.getBoolean("watchDurability"); + + ServerPlayer player = ServerUtilities.getPlayerByID(id.toString()); + + try { + ChestGUI prompt = ChestGUI.builder().withGUIId(new ChestGUIIdentifier("wmdsettings")).withPlayer(player.getUUID()).withTitle("WMD Settings"); + ItemStack wtd = new ItemStack(Items.DIAMOND_PICKAXE, 1); + wtd.setHoverName(Component.literal("Watch Tool Durability")); + + prompt.withButton(new ChestGUIButton(wtd, ()-> { + tag.putBoolean("watchDurability", !enableDurability); + + ModMessages.sendToPlayer(new PushClientConfigUpdate(tag), player); + + prompt.close(); + + ModMessages.sendToPlayer(new RequestClientConfig(), player); + }, new Vector2i(0,0)) + .withInfo(new LoreEntry.Builder().text(ChatColor.doColors("!Dark_Green!Status: " + (enableDurability ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled"))).build()) + + ); + + ItemStack wmhunger = new ItemStack(Items.APPLE, 1); + wmhunger.setHoverName(Component.literal("Watch My Hunger")); + + prompt.withButton(new ChestGUIButton(wmhunger, ()->{ + tag.putBoolean("watchMyHunger", !enableHunger); + ModMessages.sendToPlayer(new PushClientConfigUpdate(tag), player); + + prompt.close(); + ModMessages.sendToPlayer(new RequestClientConfig(), player); + }, new Vector2i(0, 1)) + .withInfo(new LoreEntry.Builder().text(ChatColor.doColors("!Dark_Green!Status: " + (enableHunger ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled"))).build()) + ); + ItemStack wmhealth = new ItemStack(Items.PUFFERFISH, 1); + wmhealth.setHoverName(Component.literal("Watch My Health")); + + prompt.withButton(new ChestGUIButton(wmhealth, ()->{ + tag.putBoolean("watchMyHealth", !enableHealth); + ModMessages.sendToPlayer(new PushClientConfigUpdate(tag), player); + + prompt.close(); + + ModMessages.sendToPlayer(new RequestClientConfig(), player); + }, new Vector2i(0, 2)) + .withInfo(new LoreEntry.Builder().text(ChatColor.doColors("!Dark_Green!Status: " + (enableHealth ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled"))).build()) + ); + + prompt.withReset(()->{ + ModMessages.sendToPlayer(new S2CResetConfig(), ServerUtilities.getPlayerByID(id.toString())); + + prompt.close(); + + ModMessages.sendToPlayer(new RequestClientConfig(), player); + }); + + + prompt.updateUtilityButtons(); + prompt.open(); + }catch(Exception e) + { + WatchMyDurability.LOGGER.error(e.getMessage()); + e.printStackTrace(); + } + + }); + } +} diff --git a/src/main/java/dev/zontreck/wmd/networking/packets/s2c/PushClientConfigUpdate.java b/src/main/java/dev/zontreck/wmd/networking/packets/s2c/PushClientConfigUpdate.java new file mode 100644 index 0000000..3550b7c --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/networking/packets/s2c/PushClientConfigUpdate.java @@ -0,0 +1,36 @@ +package dev.zontreck.wmd.networking.packets.s2c; + +import dev.zontreck.wmd.configs.WMDClientConfig; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +public class PushClientConfigUpdate +{ + public CompoundTag tag; + public PushClientConfigUpdate(FriendlyByteBuf buf) + { + tag = buf.readAnySizeNbt(); + } + + public PushClientConfigUpdate(CompoundTag tag) + { + this.tag=tag; + } + + public void toBytes(FriendlyByteBuf buf) + { + buf.writeNbt(tag); + } + + public void handle(Supplier supplier) + { + NetworkEvent.Context ctx = supplier.get(); + + ctx.enqueueWork(()->{ + WMDClientConfig.deserialize(tag); + }); + } +} diff --git a/src/main/java/dev/zontreck/wmd/networking/packets/s2c/RequestClientConfig.java b/src/main/java/dev/zontreck/wmd/networking/packets/s2c/RequestClientConfig.java new file mode 100644 index 0000000..414dc0e --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/networking/packets/s2c/RequestClientConfig.java @@ -0,0 +1,35 @@ +package dev.zontreck.wmd.networking.packets.s2c; + +import dev.zontreck.wmd.networking.ModMessages; +import dev.zontreck.wmd.networking.packets.c2s.ClientConfigResponse; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +public class RequestClientConfig +{ + public RequestClientConfig(FriendlyByteBuf buf) + { + + } + + public RequestClientConfig(){ + + } + + public void toBytes(FriendlyByteBuf buf){ + + } + + public void handle(Supplier supplier) + { + NetworkEvent.Context ctx = supplier.get(); + + ctx.enqueueWork(()->{ + ClientConfigResponse reply = new ClientConfigResponse(Minecraft.getInstance().player.getUUID()); + ModMessages.sendToServer(reply); + }); + } +} diff --git a/src/main/java/dev/zontreck/wmd/networking/packets/s2c/S2CResetConfig.java b/src/main/java/dev/zontreck/wmd/networking/packets/s2c/S2CResetConfig.java new file mode 100644 index 0000000..6186ae4 --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/networking/packets/s2c/S2CResetConfig.java @@ -0,0 +1,45 @@ +package dev.zontreck.wmd.networking.packets.s2c; + +import dev.zontreck.wmd.configs.WMDClientConfig; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +public class S2CResetConfig +{ + public S2CResetConfig(FriendlyByteBuf buf) + { + + } + + public S2CResetConfig() + { + + } + + public void toBytes(FriendlyByteBuf buf) + { + } + + public void handle(Supplier supplier) + { + NetworkEvent.Context ctx = supplier.get(); + + ctx.enqueueWork(()-> + { + + WMDClientConfig.WMD_PREFIX.set(WMDClientConfig.WMD_PREFIX.getDefault()); + WMDClientConfig.WMD_PREFIX.save(); + + WMDClientConfig.EnableHealthAlert.set(WMDClientConfig.EnableHealthAlert.getDefault()); + WMDClientConfig.EnableHealthAlert.save(); + + WMDClientConfig.EnableHungerAlert.set(WMDClientConfig.EnableHungerAlert.getDefault()); + WMDClientConfig.EnableHealthAlert.save(); + + WMDClientConfig.EnableToolWatcher.set(WMDClientConfig.EnableToolWatcher.getDefault()); + WMDClientConfig.EnableToolWatcher.save(); + }); + } +} diff --git a/src/main/java/dev/zontreck/wmd/networking/packets/s2c/WMDServerAvailable.java b/src/main/java/dev/zontreck/wmd/networking/packets/s2c/WMDServerAvailable.java new file mode 100644 index 0000000..22ed6ac --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/networking/packets/s2c/WMDServerAvailable.java @@ -0,0 +1,42 @@ +package dev.zontreck.wmd.networking.packets.s2c; + +import dev.zontreck.libzontreck.util.ServerUtilities; +import dev.zontreck.wmd.WatchMyDurability; +import dev.zontreck.wmd.networking.ModMessages; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import java.util.UUID; +import java.util.function.Supplier; + +public class WMDServerAvailable +{ + public WMDServerAvailable(FriendlyByteBuf buf) + { + + } + + public WMDServerAvailable() + { + + } + + public void toBytes(FriendlyByteBuf buf) + { + + } + + public void handle(Supplier supplier) + { + NetworkEvent.Context ctx = supplier.get(); + + ctx.enqueueWork(()->{ + WatchMyDurability.WMD_SERVER_AVAILABLE =true; + }); + } + + public void send(UUID ID) + { + ModMessages.sendToPlayer(this, ServerUtilities.getPlayerByID(ID.toString())); + } +} diff --git a/src/main/java/dev/zontreck/wmd/utils/client/Helpers.java b/src/main/java/dev/zontreck/wmd/utils/client/Helpers.java new file mode 100644 index 0000000..6ae95c9 --- /dev/null +++ b/src/main/java/dev/zontreck/wmd/utils/client/Helpers.java @@ -0,0 +1,14 @@ +package dev.zontreck.wmd.utils.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.sounds.SoundEvent; + +public class Helpers +{ + + public static void Soundify(SoundEvent sound) + { + //WatchMyDurability.LOGGER.info("PLAY ALERT SOUND"); + Minecraft.getInstance().player.playSound(sound, 1.0f, 1.0f); + } +} From b6d5c0c502c7c9e7ba873ea491ec0601f097499d Mon Sep 17 00:00:00 2001 From: zontreck Date: Wed, 10 Jan 2024 03:46:34 -0700 Subject: [PATCH 26/28] Fix non-functional reset button --- .../wmd/networking/packets/c2s/ClientConfigResponse.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java b/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java index 9354f18..11504b3 100644 --- a/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java +++ b/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java @@ -4,6 +4,7 @@ import dev.zontreck.libzontreck.chat.ChatColor; import dev.zontreck.libzontreck.chestgui.ChestGUI; import dev.zontreck.libzontreck.chestgui.ChestGUIButton; import dev.zontreck.libzontreck.chestgui.ChestGUIIdentifier; +import dev.zontreck.libzontreck.items.ModItems; import dev.zontreck.libzontreck.lore.LoreEntry; import dev.zontreck.libzontreck.util.ServerUtilities; import dev.zontreck.libzontreck.vectors.Vector2i; @@ -104,16 +105,16 @@ public class ClientConfigResponse .withInfo(new LoreEntry.Builder().text(ChatColor.doColors("!Dark_Green!Status: " + (enableHealth ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled"))).build()) ); - prompt.withReset(()->{ + prompt.withButton(new ChestGUIButton(ModItems.CHESTGUI_RESET.get(), "Reset", ()->{ ModMessages.sendToPlayer(new S2CResetConfig(), ServerUtilities.getPlayerByID(id.toString())); prompt.close(); ModMessages.sendToPlayer(new RequestClientConfig(), player); - }); + }, new Vector2i(2,4))); - prompt.updateUtilityButtons(); + prompt.hasReset=false; prompt.open(); }catch(Exception e) { From dbd34125f8e1fef26cd83b4fe696d9fb8912877a Mon Sep 17 00:00:00 2001 From: zontreck Date: Wed, 10 Jan 2024 03:48:53 -0700 Subject: [PATCH 27/28] Fix non-functional reset button --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8a18026..7ee8b5d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ mod_name=WatchMyDurability # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1.2.011024.0208 +mod_version=1.2.011024.0346 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html From 68aac66094f4a44072be8d0d9fd7bd37ced0e4f0 Mon Sep 17 00:00:00 2001 From: zontreck Date: Mon, 15 Jan 2024 00:56:27 -0700 Subject: [PATCH 28/28] Update ChestGUI to new LibZontreck API --- gradle.properties | 4 +- .../packets/c2s/ClientConfigResponse.java | 63 ++++++++++--------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/gradle.properties b/gradle.properties index 7ee8b5d..e2e0ee1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -libzontreck=1.10.011024.0312 +libzontreck=1.10.011524.0045 ## Environment Properties @@ -49,7 +49,7 @@ mod_name=WatchMyDurability # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1.2.011024.0346 +mod_version=1.2.011524.0055 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java b/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java index 11504b3..f641a30 100644 --- a/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java +++ b/src/main/java/dev/zontreck/wmd/networking/packets/c2s/ClientConfigResponse.java @@ -5,6 +5,7 @@ import dev.zontreck.libzontreck.chestgui.ChestGUI; import dev.zontreck.libzontreck.chestgui.ChestGUIButton; import dev.zontreck.libzontreck.chestgui.ChestGUIIdentifier; import dev.zontreck.libzontreck.items.ModItems; +import dev.zontreck.libzontreck.lore.LoreContainer; import dev.zontreck.libzontreck.lore.LoreEntry; import dev.zontreck.libzontreck.util.ServerUtilities; import dev.zontreck.libzontreck.vectors.Vector2i; @@ -17,7 +18,6 @@ import dev.zontreck.wmd.networking.packets.s2c.S2CResetConfig; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -26,39 +26,35 @@ import net.minecraftforge.network.NetworkEvent; import java.util.UUID; import java.util.function.Supplier; -public class ClientConfigResponse -{ +public class ClientConfigResponse { public CompoundTag tag; public UUID id; - public ClientConfigResponse(FriendlyByteBuf buf) - { + public ClientConfigResponse(FriendlyByteBuf buf) { tag = buf.readAnySizeNbt(); id = buf.readUUID(); } - public ClientConfigResponse(UUID playerID) - { + public ClientConfigResponse(UUID playerID) { tag = WMDClientConfig.serialize(); id = playerID; } - public void toBytes(FriendlyByteBuf buf) - { + public void toBytes(FriendlyByteBuf buf) { buf.writeNbt(tag); buf.writeUUID(id); } - public void handle(Supplier supplier) - { + public void handle(Supplier supplier) { NetworkEvent.Context ctx = supplier.get(); - ctx.enqueueWork(()->{ + ctx.enqueueWork(() -> { // Open config editor for player boolean enableHealth = tag.getBoolean("watchMyHealth"); boolean enableHunger = tag.getBoolean("watchMyHunger"); boolean enableDurability = tag.getBoolean("watchDurability"); + ServerPlayer player = ServerUtilities.getPlayerByID(id.toString()); try { @@ -66,15 +62,18 @@ public class ClientConfigResponse ItemStack wtd = new ItemStack(Items.DIAMOND_PICKAXE, 1); wtd.setHoverName(Component.literal("Watch Tool Durability")); - prompt.withButton(new ChestGUIButton(wtd, ()-> { - tag.putBoolean("watchDurability", !enableDurability); + prompt.withButton(new ChestGUIButton(wtd, (stack, container, lore) -> { + var wd = !tag.getBoolean("watchDurability"); + tag.putBoolean("watchDurability", wd); ModMessages.sendToPlayer(new PushClientConfigUpdate(tag), player); - prompt.close(); - ModMessages.sendToPlayer(new RequestClientConfig(), player); - }, new Vector2i(0,0)) + lore.miscData.loreData.get(0).text = ChatColor.doColors("!Dark_Green!Status: " + (wd ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled")); + lore.commitLore(); + + + }, new Vector2i(0, 0)) .withInfo(new LoreEntry.Builder().text(ChatColor.doColors("!Dark_Green!Status: " + (enableDurability ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled"))).build()) ); @@ -82,42 +81,46 @@ public class ClientConfigResponse ItemStack wmhunger = new ItemStack(Items.APPLE, 1); wmhunger.setHoverName(Component.literal("Watch My Hunger")); - prompt.withButton(new ChestGUIButton(wmhunger, ()->{ - tag.putBoolean("watchMyHunger", !enableHunger); + prompt.withButton(new ChestGUIButton(wmhunger, (stack, container, lore) -> { + var eh = !tag.getBoolean("watchMyHunger"); + tag.putBoolean("watchMyHunger", eh); ModMessages.sendToPlayer(new PushClientConfigUpdate(tag), player); - prompt.close(); - ModMessages.sendToPlayer(new RequestClientConfig(), player); + lore.miscData.loreData.get(0).text = ChatColor.doColors("!Dark_Green!Status: " + (eh ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled")); + lore.commitLore(); + + }, new Vector2i(0, 1)) .withInfo(new LoreEntry.Builder().text(ChatColor.doColors("!Dark_Green!Status: " + (enableHunger ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled"))).build()) ); ItemStack wmhealth = new ItemStack(Items.PUFFERFISH, 1); wmhealth.setHoverName(Component.literal("Watch My Health")); - prompt.withButton(new ChestGUIButton(wmhealth, ()->{ - tag.putBoolean("watchMyHealth", !enableHealth); + prompt.withButton(new ChestGUIButton(wmhealth, (stack, container, lore) -> { + var eh = !tag.getBoolean("watchMyHealth"); + tag.putBoolean("watchMyHealth", eh); ModMessages.sendToPlayer(new PushClientConfigUpdate(tag), player); - prompt.close(); - ModMessages.sendToPlayer(new RequestClientConfig(), player); + lore.miscData.loreData.get(0).text = ChatColor.doColors("!Dark_Green!Status: " + (eh ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled")); + lore.commitLore(); + }, new Vector2i(0, 2)) .withInfo(new LoreEntry.Builder().text(ChatColor.doColors("!Dark_Green!Status: " + (enableHealth ? "!Dark_Green!Enabled" : "!Dark_Red!Disabled"))).build()) ); - prompt.withButton(new ChestGUIButton(ModItems.CHESTGUI_RESET.get(), "Reset", ()->{ + prompt.withButton(new ChestGUIButton(ModItems.CHESTGUI_RESET.get(), "Reset", (stack, container, lore) -> { ModMessages.sendToPlayer(new S2CResetConfig(), ServerUtilities.getPlayerByID(id.toString())); prompt.close(); ModMessages.sendToPlayer(new RequestClientConfig(), player); - }, new Vector2i(2,4))); + }, new Vector2i(2, 4))); - prompt.hasReset=false; + prompt.hasReset = false; prompt.open(); - }catch(Exception e) - { + } catch (Exception e) { WatchMyDurability.LOGGER.error(e.getMessage()); e.printStackTrace(); }