diff --git a/.gitignore b/.gitignore index 6cd3f2bc82..9a993dd681 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ __gradle_version__.py # eclipse bin *.launch + +# vscode - machine-specific run configs +.vscode/launch.json .settings .metadata .classpath diff --git a/.vscode/settings.json b/.vscode/settings.json index 7a26f45b1a..bbbeae8e79 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,7 @@ "ruff.lint.args": [ "--extend-ignore=I", // format on save is enabled, so don't show the squiggles ], - "python.languageServer": "Pylance", + "python.languageServer": "None", "python.analysis.diagnosticMode": "workspace", "python.analysis.packageIndexDepths": [ {"name": "hexdoc", "depth": 3}, @@ -31,4 +31,6 @@ "*.jcss.jinja": "jinja-css", // for files with a lot of jinja stuff, where the linting isn't useful "*.json5.jinja": "json5", }, + "cursorpyright.analysis.diagnosticMode": "workspace", + "java.configuration.updateBuildConfiguration": "automatic", } diff --git a/CHANGELOG.md b/CHANGELOG.md index f4498b2755..2405c97252 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added +- **1.21.1 NeoForge port (draft):** Build system updated to NeoForge (NeoGradle/ModDevGradle), Java 21, Paucal 0.7.x, Patchouli 1.21.1-92, Caelus 7.x. Data component scaffold for Iota/item storage ([HexDataComponents](Common/src/main/java/at/petrak/hexcasting/common/lib/HexDataComponents.java)). - Added the `cannot_modify_cost` tag for patterns that should ignore the `media_consumption` attribute when calculating cost, by Robotgiggle in [987](https://github.com/FallingColors/HexMod/pull/987). ### Changed @@ -16,6 +17,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Fixed +- Fixed staff/actionable items not opening the spell GUI and "broken iota" on empty containers on NeoForge 21.1.x. NeoForge's payload direction checks rejected client-bound packets (e.g. hexcasting:cgui, hexcasting:clr_spi_pats_sc). Added `ForgeMixinNetworkRegistry` to bypass the check for hex casting payloads. +- Fixed Patchouli thehexbook failing to load due to malformed `potion_contents` in 1.21.1. Updated potion item strings to use SNBT compound format: `potion_contents={potion:"hexcasting:enlarge_grid"}` (entries: potions.json, nadirs.json, zeniths.json). +- Fixed media bar/tooltip not updating after amethyst consumption until rejoin. Added `broadcastFullState()` after media extraction to sync inventory to client immediately. - Fixed a crash loop when trying to generate a creative-mode ancient scroll for a Great Spell whose per-world pattern hasn't been calculated yet, by Robotgiggle in [992](https://github.com/FallingColors/HexMod/pull/992). ## `0.11.3` - 2025-11-22 diff --git a/Common/build.gradle b/Common/build.gradle index aca1334466..ba67995fec 100644 --- a/Common/build.gradle +++ b/Common/build.gradle @@ -9,33 +9,28 @@ minecraft { } repositories { + mavenLocal() mavenCentral() - maven { url 'https://maven.blamejared.com' } - - maven { - // location of the maven that hosts JEI files - name = "Progwml6 maven" - url = "https://dvs1.progwml6.com/files/maven/" - } - maven { - // location of a maven mirror for JEI files, as a fallback - name = "ModMaven" - url = "https://modmaven.dev" - } - - maven { url "https://maven.shedaniel.me/" } - + maven { url = 'https://maven.neoforged.net/releases' } + maven { url = 'https://maven.minecraftforge.net' } + maven { name = "Progwml6 maven"; url = "https://dvs1.progwml6.com/files/maven/" } + maven { name = "ModMaven"; url = "https://modmaven.dev" } + maven { url = "https://maven.shedaniel.me/" } + maven { url = "https://api.modrinth.com/maven" } } dependencies { compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5' implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1' - compileOnly "at.petra-k.paucal:paucal-common-$minecraftVersion:$paucalVersion" - compileOnly "vazkii.patchouli:Patchouli-xplat:$minecraftVersion-$patchouliVersion-SNAPSHOT" + // Paucal: from mavenLocal or includeBuild (groupId at.petrak) + compileOnly "at.petrak:paucal-neoforge-$minecraftVersion:$paucalVersion" + compileOnly "vazkii.patchouli:Patchouli-xplat:$patchouliVersion-SNAPSHOT" - compileOnly "com.samsthenerd.inline:inline-forge:$minecraftVersion-$inlineVersion" + // Optional: Inline (pattern tooltips in chat) - uncomment to enable Inline integration + // Also remove 'at/petrak/hexcasting/interop/inline/**' from sourceSets.main.java.exclude in this file + // compileOnly "maven.modrinth:inline:$minecraftVersion-$inlineVersion-neoforge" compileOnly "org.jetbrains:annotations:$jetbrainsAnnotationsVersion" testCompileOnly "org.jetbrains:annotations:$jetbrainsAnnotationsVersion" @@ -55,3 +50,14 @@ processResources { expand buildProps } } + +// Datagen sources are not required to run the client; exclude to unblock NeoForge port. +// Inline interop is excluded so the mod compiles without the Inline dependency. +sourceSets { + main { + java { + exclude 'at/petrak/hexcasting/datagen/**' + exclude 'at/petrak/hexcasting/interop/inline/**' + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/README.md b/Common/src/main/java/at/petrak/hexcasting/README.md deleted file mode 100644 index bb6d151cfe..0000000000 --- a/Common/src/main/java/at/petrak/hexcasting/README.md +++ /dev/null @@ -1,9 +0,0 @@ -Hello, intrepid Github reader! - -The "flavor text" words for things in this mod and the internal names are different. (Sorry.) - -- A "Hex" is a `Continuation`, cast through a [`CastingVM`](api/casting/eval/vm/CastingVM.kt) -- A "Pattern" is a [`HexPattern`](api/casting/math/HexPattern.kt) -- An "Action" is an [`Action`](api/casting/castables/Action.kt) -- An action that pushes a spell is a [`Spell`](api/casting/castables/SpellAction.kt) - diff --git a/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java b/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java index 8ddde5669b..7f2489d2e7 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java @@ -165,49 +165,21 @@ default FrozenPigment getColorizer(Player player) { return FrozenPigment.DEFAULT.get(); } - ArmorMaterial DUMMY_ARMOR_MATERIAL = new ArmorMaterial() { - @Override - public int getDurabilityForType(ArmorItem.Type type) { - return 0; - } - - @Override - public int getDefenseForType(ArmorItem.Type type) { - return 0; - } - - @Override - public int getEnchantmentValue() { - return 0; - } - - @NotNull - @Override - public SoundEvent getEquipSound() { - return SoundEvents.ARMOR_EQUIP_LEATHER; - } - - @NotNull - @Override - public Ingredient getRepairIngredient() { - return Ingredient.EMPTY; - } - - @Override - public String getName() { - return "missingno"; - } - - @Override - public float getToughness() { - return 0; - } - - @Override - public float getKnockbackResistance() { - return 0; - } - }; + ArmorMaterial DUMMY_ARMOR_MATERIAL = new ArmorMaterial( + java.util.Map.of( + ArmorItem.Type.BOOTS, 0, + ArmorItem.Type.LEGGINGS, 0, + ArmorItem.Type.CHESTPLATE, 0, + ArmorItem.Type.HELMET, 0, + ArmorItem.Type.BODY, 0 + ), + 0, + SoundEvents.ARMOR_EQUIP_LEATHER, + () -> Ingredient.EMPTY, + java.util.List.of(new ArmorMaterial.Layer(modLoc("missingno"))), + 0f, + 0f + ); default ArmorMaterial robesMaterial() { return DUMMY_ARMOR_MATERIAL; @@ -229,6 +201,6 @@ static HexAPI instance() { } static ResourceLocation modLoc(String s) { - return new ResourceLocation(MOD_ID, s); + return ResourceLocation.fromNamespaceAndPath(MOD_ID, s); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/advancements/FailToCastGreatSpellTrigger.java b/Common/src/main/java/at/petrak/hexcasting/api/advancements/FailToCastGreatSpellTrigger.java index fe85fec5b3..6c3cb568b6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/advancements/FailToCastGreatSpellTrigger.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/advancements/FailToCastGreatSpellTrigger.java @@ -1,39 +1,30 @@ package at.petrak.hexcasting.api.advancements; -import com.google.gson.JsonObject; -import net.minecraft.advancements.critereon.*; -import net.minecraft.resources.ResourceLocation; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.advancements.critereon.ContextAwarePredicate; +import net.minecraft.advancements.critereon.SimpleCriterionTrigger; import net.minecraft.server.level.ServerPlayer; -public class FailToCastGreatSpellTrigger extends SimpleCriterionTrigger { - private static final ResourceLocation ID = new ResourceLocation("hexcasting", "fail_to_cast_great_spell"); - - @Override - public ResourceLocation getId() { - return ID; - } +import java.util.Optional; +public class FailToCastGreatSpellTrigger extends SimpleCriterionTrigger { @Override - protected Instance createInstance(JsonObject json, ContextAwarePredicate predicate, DeserializationContext context) { - return new Instance(predicate); + public Codec codec() { + return Instance.CODEC; } public void trigger(ServerPlayer player) { super.trigger(player, e -> true); } - public static class Instance extends AbstractCriterionTriggerInstance { - public Instance(ContextAwarePredicate predicate) { - super(ID, predicate); - } - - @Override - public ResourceLocation getCriterion() { - return ID; - } + public static record Instance(Optional player) implements SimpleCriterionTrigger.SimpleInstance { + public static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( + ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(Instance::player) + ).apply(inst, Instance::new)); - public JsonObject serializeToJson(SerializationContext pConditions) { - return new JsonObject(); + public Instance(ContextAwarePredicate player) { + this(Optional.of(player)); } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/advancements/HexAdvancementTriggers.java b/Common/src/main/java/at/petrak/hexcasting/api/advancements/HexAdvancementTriggers.java index 16af02ab39..5a2731b6a7 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/advancements/HexAdvancementTriggers.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/advancements/HexAdvancementTriggers.java @@ -8,8 +8,8 @@ public class HexAdvancementTriggers { public static final FailToCastGreatSpellTrigger FAIL_GREAT_SPELL_TRIGGER = new FailToCastGreatSpellTrigger(); public static void registerTriggers() { - CriteriaTriggersAccessor.hex$register(OVERCAST_TRIGGER); - CriteriaTriggersAccessor.hex$register(SPEND_MEDIA_TRIGGER); - CriteriaTriggersAccessor.hex$register(FAIL_GREAT_SPELL_TRIGGER); + CriteriaTriggersAccessor.hex$register("hexcasting:overcast", OVERCAST_TRIGGER); + CriteriaTriggersAccessor.hex$register("hexcasting:spend_media", SPEND_MEDIA_TRIGGER); + CriteriaTriggersAccessor.hex$register("hexcasting:fail_to_cast_great_spell", FAIL_GREAT_SPELL_TRIGGER); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/advancements/MinMaxLongs.java b/Common/src/main/java/at/petrak/hexcasting/api/advancements/MinMaxLongs.java index 0be502c86e..b1c02e5111 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/advancements/MinMaxLongs.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/advancements/MinMaxLongs.java @@ -1,40 +1,32 @@ package at.petrak.hexcasting.api.advancements; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.BuiltInExceptionProvider; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.advancements.critereon.MinMaxBounds; import net.minecraft.util.GsonHelper; import javax.annotation.Nullable; -import java.util.Objects; -import java.util.function.Function; +import java.util.Optional; -public class MinMaxLongs extends MinMaxBounds { - public static final MinMaxLongs ANY = new MinMaxLongs(null, null); - @Nullable - private final Long minSq; - @Nullable - private final Long maxSq; +/** + * Replacement for the old MinMaxBounds now that MinMaxBounds is an interface in 1.21. + * + * JSON form matches vanilla MinMaxBounds: either a number, or an object with "min"/"max". + */ +public record MinMaxLongs(Optional min, Optional max) implements MinMaxBounds { + public static final MinMaxLongs ANY = new MinMaxLongs(Optional.empty(), Optional.empty()); - private static MinMaxLongs create(StringReader reader, @Nullable Long min, @Nullable Long max) throws CommandSyntaxException { - if (min != null && max != null && min > max) { - throw ERROR_SWAPPED.createWithContext(reader); - } else { - return new MinMaxLongs(min, max); - } - } - - @Nullable - private static Long squareOpt(@Nullable Long l) { - return l == null ? null : l * l; - } + public static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( + Codec.LONG.optionalFieldOf("min").forGetter(MinMaxLongs::min), + Codec.LONG.optionalFieldOf("max").forGetter(MinMaxLongs::max) + ).apply(inst, MinMaxLongs::new)); - private MinMaxLongs(@Nullable Long min, @Nullable Long max) { - super(min, max); - this.minSq = squareOpt(min); - this.maxSq = squareOpt(max); + public MinMaxLongs(@Nullable Long min, @Nullable Long max) { + this(Optional.ofNullable(min), Optional.ofNullable(max)); } public static MinMaxLongs exactly(long l) { @@ -53,33 +45,54 @@ public static MinMaxLongs atMost(long max) { return new MinMaxLongs(null, max); } + public boolean isAny() { + return min.isEmpty() && max.isEmpty(); + } + public boolean matches(long l) { - if (this.min != null && this.min > l) { - return false; - } else { - return this.max == null || this.max >= l; - } + if (min.isPresent() && min.get() > l) return false; + return max.isEmpty() || max.get() >= l; } public boolean matchesSqr(long l) { - if (this.minSq != null && this.minSq > l) { - return false; - } else { - return this.maxSq == null || this.maxSq >= l; - } + Long minSq = min.map(v -> v * v).orElse(null); + Long maxSq = max.map(v -> v * v).orElse(null); + if (minSq != null && minSq > l) return false; + return maxSq == null || maxSq >= l; } public static MinMaxLongs fromJson(@Nullable JsonElement json) { - return fromJson(json, ANY, GsonHelper::convertToLong, MinMaxLongs::new); + if (json == null || json.isJsonNull()) return ANY; + if (json.isJsonPrimitive()) { + long v = GsonHelper.convertToLong(json, "value"); + return exactly(v); + } + JsonObject obj = GsonHelper.convertToJsonObject(json, "range"); + Long min = obj.has("min") ? GsonHelper.getAsLong(obj, "min") : null; + Long max = obj.has("max") ? GsonHelper.getAsLong(obj, "max") : null; + return new MinMaxLongs(min, max); } public static MinMaxLongs fromReader(StringReader reader) throws CommandSyntaxException { - return fromReader(reader, (l) -> l); - } + // Minimal parser: supports "5", "5..", "..5", "5..10" + int start = reader.getCursor(); + String remaining = reader.getRemaining(); + int space = remaining.indexOf(' '); + String token = space >= 0 ? remaining.substring(0, space) : remaining; + reader.setCursor(start + token.length()); - public static MinMaxLongs fromReader(StringReader reader, Function map) throws CommandSyntaxException { - BuiltInExceptionProvider builtInExceptions = CommandSyntaxException.BUILT_IN_EXCEPTIONS; - Objects.requireNonNull(builtInExceptions); - return fromReader(reader, MinMaxLongs::create, Long::parseLong, builtInExceptions::readerInvalidInt, map); + int dots = token.indexOf(".."); + if (dots < 0) { + long v = Long.parseLong(token); + return exactly(v); + } + String left = token.substring(0, dots); + String right = token.substring(dots + 2); + Long min = left.isEmpty() ? null : Long.parseLong(left); + Long max = right.isEmpty() ? null : Long.parseLong(right); + if (min != null && max != null && min > max) { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.readerInvalidInt().createWithContext(reader, token); + } + return new MinMaxLongs(min, max); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/advancements/OvercastTrigger.java b/Common/src/main/java/at/petrak/hexcasting/api/advancements/OvercastTrigger.java index b1661e869e..433295f08f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/advancements/OvercastTrigger.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/advancements/OvercastTrigger.java @@ -1,17 +1,19 @@ package at.petrak.hexcasting.api.advancements; import at.petrak.hexcasting.api.mod.HexConfig; -import com.google.gson.JsonObject; -import net.minecraft.advancements.critereon.*; -import net.minecraft.resources.ResourceLocation; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.advancements.critereon.ContextAwarePredicate; +import net.minecraft.advancements.critereon.MinMaxBounds; +import net.minecraft.advancements.critereon.SimpleCriterionTrigger; import net.minecraft.server.level.ServerPlayer; +import java.util.Optional; + // https://github.com/TelepathicGrunt/Bumblezone/blob/latest-released/src/main/java/com/telepathicgrunt/the_bumblezone/advancements/CleanupStickyHoneyResidueTrigger.java // https://github.com/VazkiiMods/Botania/blob/b8706e2e0bba20f67f1e103559a4ce39d63d48f9/src/main/java/vazkii/botania/common/advancements/CorporeaRequestTrigger.java public class OvercastTrigger extends SimpleCriterionTrigger { - private static final ResourceLocation ID = new ResourceLocation("hexcasting", "overcast"); - private static final String TAG_MEDIA_GENERATED = "media_generated"; private static final String TAG_HEALTH_USED = "health_used"; // HEY KIDS DID YOYU KNOW THERE'S NOT A CRITERIA FOR HOW MUCH ***HEALTH*** AN ENTITY HAS @@ -19,17 +21,8 @@ public class OvercastTrigger extends SimpleCriterionTrigger codec() { + return Instance.CODEC; } public void trigger(ServerPlayer player, int mediaGenerated) { @@ -40,47 +33,28 @@ public void trigger(ServerPlayer player, int mediaGenerated) { }); } - public static class Instance extends AbstractCriterionTriggerInstance { - protected final MinMaxBounds.Ints mediaGenerated; - // This is the *proporttion* of the health bar. - protected final MinMaxBounds.Doubles healthUsed; - // DID YOU KNOW THERES ONE TO CHECK THE WORLD TIME, BUT NOT THE HEALTH!? - protected final MinMaxBounds.Doubles healthLeft; - - public Instance(ContextAwarePredicate predicate, MinMaxBounds.Ints mediaGenerated, - MinMaxBounds.Doubles healthUsed, MinMaxBounds.Doubles healthLeft) { - super(OvercastTrigger.ID, predicate); - this.mediaGenerated = mediaGenerated; - this.healthUsed = healthUsed; - // DID YOU KNOW THERE'S ONE TO CHECK THE FUCKING C A T T Y P E BUT NOT THE HEALTH - this.healthLeft = healthLeft; - } - - @Override - public ResourceLocation getCriterion() { - return ID; - } - - @Override - public JsonObject serializeToJson(SerializationContext ctx) { - JsonObject json = super.serializeToJson(ctx); - if (!this.mediaGenerated.isAny()) { - json.add(TAG_MEDIA_GENERATED, this.mediaGenerated.serializeToJson()); - } - if (!this.healthUsed.isAny()) { - json.add(TAG_HEALTH_USED, this.healthUsed.serializeToJson()); - } - if (!this.healthLeft.isAny()) { - json.add(TAG_HEALTH_LEFT, this.healthLeft.serializeToJson()); - } - return json; + public static record Instance(Optional player, + MinMaxBounds.Ints mediaGenerated, + MinMaxBounds.Doubles healthUsed, + MinMaxBounds.Doubles healthLeft) implements SimpleCriterionTrigger.SimpleInstance { + public static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( + ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(Instance::player), + MinMaxBounds.Ints.CODEC.optionalFieldOf(TAG_MEDIA_GENERATED, MinMaxBounds.Ints.ANY).forGetter(Instance::mediaGenerated), + MinMaxBounds.Doubles.CODEC.optionalFieldOf(TAG_HEALTH_USED, MinMaxBounds.Doubles.ANY).forGetter(Instance::healthUsed), + MinMaxBounds.Doubles.CODEC.optionalFieldOf(TAG_HEALTH_LEFT, MinMaxBounds.Doubles.ANY).forGetter(Instance::healthLeft) + ).apply(inst, Instance::new)); + + public Instance(ContextAwarePredicate player, + MinMaxBounds.Ints mediaGenerated, + MinMaxBounds.Doubles healthUsed, + MinMaxBounds.Doubles healthLeft) { + this(Optional.of(player), mediaGenerated, healthUsed, healthLeft); } private boolean test(int mediaGeneratedIn, double healthUsedIn, float healthLeftIn) { return this.mediaGenerated.matches(mediaGeneratedIn) && this.healthUsed.matches(healthUsedIn) - // DID YOU KNOW ALL THE ENEITYT PREDICATES ARE HARD-CODED AND YOU CANT MAKE NEW ONES - && this.healthLeft.matches(healthLeftIn); + && this.healthLeft.matches((double) healthLeftIn); } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/advancements/SpendMediaTrigger.java b/Common/src/main/java/at/petrak/hexcasting/api/advancements/SpendMediaTrigger.java index d610807f59..2efb21f101 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/advancements/SpendMediaTrigger.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/advancements/SpendMediaTrigger.java @@ -1,59 +1,37 @@ package at.petrak.hexcasting.api.advancements; -import com.google.gson.JsonObject; -import net.minecraft.advancements.critereon.*; -import net.minecraft.resources.ResourceLocation; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.advancements.critereon.ContextAwarePredicate; +import net.minecraft.advancements.critereon.SimpleCriterionTrigger; import net.minecraft.server.level.ServerPlayer; -public class SpendMediaTrigger extends SimpleCriterionTrigger { - private static final ResourceLocation ID = new ResourceLocation("hexcasting", "spend_media"); +import java.util.Optional; +public class SpendMediaTrigger extends SimpleCriterionTrigger { private static final String TAG_MEDIA_SPENT = "media_spent"; private static final String TAG_MEDIA_WASTED = "media_wasted"; @Override - public ResourceLocation getId() { - return ID; - } - - @Override - protected Instance createInstance(JsonObject json, ContextAwarePredicate predicate, - DeserializationContext context) { - return new Instance(predicate, - MinMaxLongs.fromJson(json.get(TAG_MEDIA_SPENT)), - MinMaxLongs.fromJson(json.get(TAG_MEDIA_WASTED))); + public Codec codec() { + return Instance.CODEC; } public void trigger(ServerPlayer player, long mediaSpent, long mediaWasted) { super.trigger(player, inst -> inst.test(mediaSpent, mediaWasted)); } - public static class Instance extends AbstractCriterionTriggerInstance { - protected final MinMaxLongs mediaSpent; - protected final MinMaxLongs mediaWasted; - - public Instance(ContextAwarePredicate predicate, MinMaxLongs mediaSpent, - MinMaxLongs mediaWasted) { - super(SpendMediaTrigger.ID, predicate); - this.mediaSpent = mediaSpent; - this.mediaWasted = mediaWasted; - } - - @Override - public ResourceLocation getCriterion() { - return ID; - } - - @Override - public JsonObject serializeToJson(SerializationContext ctx) { - JsonObject json = super.serializeToJson(ctx); - if (!this.mediaSpent.isAny()) { - json.add(TAG_MEDIA_SPENT, this.mediaSpent.serializeToJson()); - } - if (!this.mediaWasted.isAny()) { - json.add(TAG_MEDIA_WASTED, this.mediaWasted.serializeToJson()); - } - return json; + public static record Instance(Optional player, + MinMaxLongs mediaSpent, + MinMaxLongs mediaWasted) implements SimpleCriterionTrigger.SimpleInstance { + public static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( + ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(Instance::player), + MinMaxLongs.CODEC.optionalFieldOf(TAG_MEDIA_SPENT, MinMaxLongs.ANY).forGetter(Instance::mediaSpent), + MinMaxLongs.CODEC.optionalFieldOf(TAG_MEDIA_WASTED, MinMaxLongs.ANY).forGetter(Instance::mediaWasted) + ).apply(inst, Instance::new)); + + public Instance(ContextAwarePredicate player, MinMaxLongs mediaSpent, MinMaxLongs mediaWasted) { + this(Optional.of(player), mediaSpent, mediaWasted); } private boolean test(long mediaSpentIn, long mediaWastedIn) { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/block/HexBlockEntity.java b/Common/src/main/java/at/petrak/hexcasting/api/block/HexBlockEntity.java index e531ddb12d..3e1b6f84ab 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/block/HexBlockEntity.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/block/HexBlockEntity.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.api.block; import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; @@ -19,18 +20,18 @@ public HexBlockEntity(BlockEntityType pType, BlockPos pWorldPosition, BlockSt protected abstract void loadModData(CompoundTag tag); @Override - protected void saveAdditional(CompoundTag pTag) { + protected void saveAdditional(CompoundTag pTag, HolderLookup.Provider provider) { this.saveModData(pTag); } @Override - public void load(CompoundTag pTag) { - super.load(pTag); + protected void loadAdditional(CompoundTag pTag, HolderLookup.Provider provider) { + super.loadAdditional(pTag, provider); this.loadModData(pTag); } @Override - public CompoundTag getUpdateTag() { + public CompoundTag getUpdateTag(HolderLookup.Provider provider) { CompoundTag tag = new CompoundTag(); this.saveModData(tag); return tag; @@ -43,7 +44,9 @@ public Packet getUpdatePacket() { public void sync() { this.setChanged(); - this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3); + if (this.level != null) { + this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3); + } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockCircleComponent.java b/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockCircleComponent.java index f2c1458c7b..43fefcd0b1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockCircleComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockCircleComponent.java @@ -12,7 +12,6 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BooleanProperty; -// Convenience impl of ICircleComponent public abstract class BlockCircleComponent extends Block implements ICircleComponent { public static final BooleanProperty ENERGIZED = BooleanProperty.create("energized"); diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt index c6dda37c9a..a2df8ca75f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt @@ -77,8 +77,6 @@ fun List.getBool(idx: Int, argc: Int = 0): Boolean { } } -// Helpers - fun List.getItemEntity(idx: Int, argc: Int = 0): ItemEntity { val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } if (x is EntityIota) { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/HashCons.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/HashCons.java index c7566e783b..a215730ee5 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/HashCons.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/HashCons.java @@ -4,7 +4,6 @@ import at.petrak.hexcasting.api.casting.iota.IotaType; import at.petrak.hexcasting.api.casting.math.HexPattern; -// Helper type for hashing lists of types. public sealed interface HashCons { public record Pattern(HexPattern operator) implements HashCons {} diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/BlockEntityAbstractImpetus.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/BlockEntityAbstractImpetus.java index ac8bf92d0d..f7d98a3357 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/BlockEntityAbstractImpetus.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/BlockEntityAbstractImpetus.java @@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.block.circle.BlockCircleComponent; import at.petrak.hexcasting.api.misc.MediaConstants; import at.petrak.hexcasting.api.pigment.FrozenPigment; +import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.api.utils.MediaHelper; import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker; import at.petrak.hexcasting.common.lib.HexItems; @@ -285,6 +286,7 @@ public FrozenPigment getPigment() { @Override protected void saveModData(CompoundTag tag) { + var provider = this.level != null ? this.level.registryAccess() : net.minecraft.core.RegistryAccess.EMPTY; if (this.executionState != null) { tag.put(TAG_EXECUTION_STATE, this.executionState.save()); } @@ -292,10 +294,8 @@ protected void saveModData(CompoundTag tag) { tag.putLong(TAG_MEDIA, this.media); if (this.displayMsg != null && this.displayItem != null) { - tag.putString(TAG_ERROR_MSG, Component.Serializer.toJson(this.displayMsg)); - var itemTag = new CompoundTag(); - this.displayItem.save(itemTag); - tag.put(TAG_ERROR_DISPLAY, itemTag); + tag.putString(TAG_ERROR_MSG, Component.Serializer.toJson(this.displayMsg, provider)); + tag.put(TAG_ERROR_DISPLAY, HexUtils.serializeToNBT(this.displayItem, provider)); } if (this.pigment != null) tag.put(TAG_PIGMENT, this.pigment.serializeToNBT()); @@ -303,6 +303,7 @@ protected void saveModData(CompoundTag tag) { @Override protected void loadModData(CompoundTag tag) { + var provider = this.level != null ? this.level.registryAccess() : net.minecraft.core.RegistryAccess.EMPTY; this.executionState = null; if (tag.contains(TAG_EXECUTION_STATE, Tag.TAG_COMPOUND)) { this.lazyExecutionState = tag.getCompound(TAG_EXECUTION_STATE); @@ -315,8 +316,8 @@ protected void loadModData(CompoundTag tag) { } if (tag.contains(TAG_ERROR_MSG, Tag.TAG_STRING) && tag.contains(TAG_ERROR_DISPLAY, Tag.TAG_COMPOUND)) { - var msg = Component.Serializer.fromJson(tag.getString(TAG_ERROR_MSG)); - var display = ItemStack.of(tag.getCompound(TAG_ERROR_DISPLAY)); + var msg = Component.Serializer.fromJson(tag.getString(TAG_ERROR_MSG), provider); + var display = ItemStack.parseOptional(provider, tag.getCompound(TAG_ERROR_DISPLAY)); this.displayMsg = msg; this.displayItem = display; } else { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java index ae149a081e..36ad7ad5ca 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java @@ -183,21 +183,29 @@ public CompoundTag save() { } public static CircleExecutionState load(CompoundTag nbt, ServerLevel world) { - var startPos = NbtUtils.readBlockPos(nbt.getCompound(TAG_IMPETUS_POS)); + var startPos = NbtUtils.readBlockPos(nbt, TAG_IMPETUS_POS).orElse(BlockPos.ZERO); var startDir = Direction.values()[nbt.getByte(TAG_IMPETUS_DIR)]; var knownPositions = new HashSet(); - var knownTag = nbt.getList(TAG_KNOWN_POSITIONS, Tag.TAG_COMPOUND); - for (var tag : knownTag) { - knownPositions.add(NbtUtils.readBlockPos(HexUtils.downcast(tag, CompoundTag.TYPE))); + var knownRaw = nbt.get(TAG_KNOWN_POSITIONS); + if (knownRaw instanceof ListTag knownTag) { + for (var tag : knownTag) { + var tmp = new CompoundTag(); + tmp.put("p", tag); + NbtUtils.readBlockPos(tmp, "p").ifPresent(knownPositions::add); + } } var reachedPositions = new ArrayList(); - var reachedTag = nbt.getList(TAG_REACHED_POSITIONS, Tag.TAG_COMPOUND); - for (var tag : reachedTag) { - reachedPositions.add(NbtUtils.readBlockPos(HexUtils.downcast(tag, CompoundTag.TYPE))); + var reachedRaw = nbt.get(TAG_REACHED_POSITIONS); + if (reachedRaw instanceof ListTag reachedTag) { + for (var tag : reachedTag) { + var tmp = new CompoundTag(); + tmp.put("p", tag); + NbtUtils.readBlockPos(tmp, "p").ifPresent(reachedPositions::add); + } } - var currentPos = NbtUtils.readBlockPos(nbt.getCompound(TAG_CURRENT_POS)); + var currentPos = NbtUtils.readBlockPos(nbt, TAG_CURRENT_POS).orElse(startPos); var enteredFrom = Direction.values()[nbt.getByte(TAG_ENTERED_FROM)]; var image = CastingImage.loadFromNbt(nbt.getCompound(TAG_IMAGE), world); diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironment.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironment.java index 54e033b013..d5600a02c1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironment.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironment.java @@ -240,7 +240,7 @@ public void postCast(CastingImage image) { * Return whether this env can cast great spells. */ public boolean isEnlightened() { - var adv = this.world.getServer().getAdvancements().getAdvancement(modLoc("enlightenment")); + var adv = this.world.getServer().getAdvancements().get(modLoc("enlightenment")); if (adv == null) return false; @@ -371,7 +371,7 @@ public final void assertEntityInRange(Entity e) throws MishapEntityTooFarAway { } /** - * Convenience function to throw if the vec is out of the world (for GTP) + * Convenience function to throw if the vec is out of the world */ public final void assertVecInWorld(Vec3 vec) throws MishapBadLocation { if (!this.isVecInWorld(vec)) { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java index 333deaa813..8a1c990c8a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java @@ -132,7 +132,7 @@ public long extractMediaEnvironment(long cost, boolean simulate) { public boolean isVecInRangeEnvironment(Vec3 vec) { var caster = this.execState.getCaster(this.world); if (caster != null) { - double sentinelRadius = caster.getAttributeValue(HexAttributes.SENTINEL_RADIUS); + double sentinelRadius = caster.getAttributeValue(HexAttributes.getHolder(caster, HexAttributes.SENTINEL_RADIUS_KEY)); if (vec.distanceToSqr(caster.position()) <= caster.getBbHeight() * caster.getBbHeight()) { return true; } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PlayerBasedCastEnv.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PlayerBasedCastEnv.java index 1f5b6703ff..667d6637e1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PlayerBasedCastEnv.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PlayerBasedCastEnv.java @@ -52,8 +52,8 @@ protected PlayerBasedCastEnv(ServerPlayer caster, InteractionHand castingHand) { super(caster.serverLevel()); this.caster = caster; this.castingHand = castingHand; - this.ambitRadius = caster.getAttributeValue(HexAttributes.AMBIT_RADIUS); - this.sentinelRadius = caster.getAttributeValue(HexAttributes.SENTINEL_RADIUS); + this.ambitRadius = caster.getAttributeValue(HexAttributes.getHolder(caster, HexAttributes.AMBIT_RADIUS_KEY)); + this.sentinelRadius = caster.getAttributeValue(HexAttributes.getHolder(caster, HexAttributes.SENTINEL_RADIUS_KEY)); } @Override @@ -69,10 +69,10 @@ public ServerPlayer getCaster() { @Override protected double getCostModifier(PatternShapeMatch match) { ResourceLocation loc = actionKey(match); - if (isOfTag(IXplatAbstractions.INSTANCE.getActionRegistry(), loc, HexTags.Actions.CANNOT_MODIFY_COST)) { + if (loc == null || isOfTag(IXplatAbstractions.INSTANCE.getActionRegistry(), loc, HexTags.Actions.CANNOT_MODIFY_COST)) { return 1.0; } else { - return this.caster.getAttributeValue(HexAttributes.MEDIA_CONSUMPTION_MODIFIER); + return this.caster.getAttributeValue(HexAttributes.getHolder(this.caster, HexAttributes.MEDIA_CONSUMPTION_MODIFIER_KEY)); } } @@ -86,11 +86,11 @@ public void postExecution(CastResult result) { } } if (this.caster != null){ - double ambitAttribute = this.caster.getAttributeValue(HexAttributes.AMBIT_RADIUS); + double ambitAttribute = this.caster.getAttributeValue(HexAttributes.getHolder(this.caster, HexAttributes.AMBIT_RADIUS_KEY)); if (this.ambitRadius != ambitAttribute){ this.ambitRadius = ambitAttribute; } - double sentinelAttribute = this.caster.getAttributeValue(HexAttributes.SENTINEL_RADIUS); + double sentinelAttribute = this.caster.getAttributeValue(HexAttributes.getHolder(this.caster, HexAttributes.SENTINEL_RADIUS_KEY)); if (this.sentinelRadius != sentinelAttribute){ this.sentinelRadius = sentinelAttribute; } @@ -186,13 +186,16 @@ protected long extractMediaFromInventory(long costLeft, boolean allowOvercast, b startCost - costLeft, costLeft < 0 ? -costLeft : 0 ); + // Sync inventory to client so media bar/tooltip updates immediately + this.caster.inventoryMenu.broadcastFullState(); } return costLeft; } protected boolean canOvercast() { - var adv = this.world.getServer().getAdvancements().getAdvancement(modLoc("y_u_no_cast_angy")); + var adv = this.world.getServer().getAdvancements().get(modLoc("y_u_no_cast_angy")); + if (adv == null) return false; var advs = this.caster.getAdvancements(); return advs.getOrStartProgress(adv).isDone(); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt index 8000ec09aa..5eebc9ffab 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt @@ -97,11 +97,7 @@ interface ContinuationFrame { } val typeKey = tag.getString(HexContinuationTypes.KEY_TYPE) - if (!ResourceLocation.isValidResourceLocation(typeKey)) { - return null - } - - val typeLoc = ResourceLocation(typeKey) + val typeLoc = ResourceLocation.tryParse(typeKey) ?: return null return HexContinuationTypes.REGISTRY[typeLoc] } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java index 2a8023cf01..d3b5bcc3c6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java @@ -2,18 +2,14 @@ import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; -import com.samsthenerd.inline.api.InlineAPI; -import com.samsthenerd.inline.api.data.EntityInlineData; -import com.samsthenerd.inline.api.data.PlayerHeadData; import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; +import net.minecraft.core.RegistryAccess; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,29 +39,17 @@ public boolean isTruthy() { Tag serialize() { var out = new CompoundTag(); out.putUUID("uuid", this.getEntity().getUUID()); - out.putString("name", Component.Serializer.toJson(getEntityNameWithInline(true))); + out.putString("name", Component.Serializer.toJson(getEntityNameWithInline(), RegistryAccess.EMPTY)); return out; } @Override public Component display() { - return getEntityNameWithInline(false).copy().withStyle(ChatFormatting.AQUA); + return getEntityNameWithInline().copy().withStyle(ChatFormatting.AQUA); } - private Component getEntityNameWithInline(boolean fearSerializer){ - MutableComponent baseName = this.getEntity().getName().copy(); - Component inlineEnt = null; - if(this.getEntity() instanceof Player player){ - inlineEnt = new PlayerHeadData(player.getGameProfile()).asText(!fearSerializer); - inlineEnt = inlineEnt.plainCopy().withStyle(InlineAPI.INSTANCE.withSizeModifier(inlineEnt.getStyle(), 1.5)); - } else{ - if(fearSerializer){ // we don't want to have to serialize an entity just to display it - inlineEnt = EntityInlineData.fromType(this.getEntity().getType()).asText(!fearSerializer); - } else { - inlineEnt = EntityInlineData.fromEntity(this.getEntity()).asText(!fearSerializer); - } - } - return baseName.append(Component.literal(": ")).append(inlineEnt); + private Component getEntityNameWithInline() { + return this.getEntity().getName(); } public static IotaType TYPE = new IotaType<>() { @@ -95,7 +79,7 @@ public Component display(Tag tag) { } var nameJson = ctag.getString("name"); // return Component.literal(nameJson); - return Component.Serializer.fromJsonLenient(nameJson).withStyle(ChatFormatting.AQUA); + return Component.Serializer.fromJsonLenient(nameJson, RegistryAccess.EMPTY).withStyle(ChatFormatting.AQUA); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/IotaType.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/IotaType.java index c0167ae5df..2d0e1d23e7 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/IotaType.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/IotaType.java @@ -100,10 +100,10 @@ public static IotaType getTypeFromTag(CompoundTag tag) { return null; } var typeKey = tag.getString(HexIotaTypes.KEY_TYPE); - if (!ResourceLocation.isValidResourceLocation(typeKey)) { + var typeLoc = ResourceLocation.tryParse(typeKey); + if (typeLoc == null) { return null; } - var typeLoc = new ResourceLocation(typeKey); return HexIotaTypes.REGISTRY.get(typeLoc); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java index 74db0a95fb..85c351b840 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java @@ -19,7 +19,7 @@ import at.petrak.hexcasting.common.casting.PatternRegistryManifest; import at.petrak.hexcasting.common.lib.hex.HexEvalSounds; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; -import at.petrak.hexcasting.interop.inline.InlinePatternData; +import at.petrak.hexcasting.common.misc.PatternDisplayHelper; import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; @@ -164,7 +164,7 @@ public static PatternIota deserialize(Tag tag) throws IllegalArgumentException { } public static Component display(HexPattern pat) { - Component text = (new InlinePatternData(pat)).asText(true); + Component text = PatternDisplayHelper.getDisplayComponent(pat, true); return text.copy().withStyle(text.getStyle().applyTo(Style.EMPTY.withColor(ChatFormatting.WHITE))); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/Mishap.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/Mishap.kt index 685b3e8984..30f4d99fb6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/Mishap.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/Mishap.kt @@ -58,8 +58,6 @@ abstract class Mishap : RuntimeException() { } } - // Useful helper functions - protected fun dyeColor(color: DyeColor): FrozenPigment = FrozenPigment( ItemStack(HexItems.DYE_PIGMENTS[color]!!), diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBadEntity.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBadEntity.kt index 336a4fa18e..3aca3b5fda 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBadEntity.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBadEntity.kt @@ -19,7 +19,7 @@ class MishapBadEntity(val entity: Entity, val wanted: Component) : Mishap() { } override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = - error("bad_entity", wanted, entity.displayName.plainCopy().aqua) + error("bad_entity", wanted, (entity.displayName ?: net.minecraft.network.chat.Component.literal("???")).plainCopy().aqua) companion object { @JvmStatic diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapEntityTooFarAway.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapEntityTooFarAway.kt index 41671a219c..5769494a17 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapEntityTooFarAway.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapEntityTooFarAway.kt @@ -16,5 +16,5 @@ class MishapEntityTooFarAway(val entity: Entity) : Mishap() { } override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component = - error("entity_too_far", entity.displayName) + error("entity_too_far", entity.displayName ?: net.minecraft.network.chat.Component.literal("???")) } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapImmuneEntity.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapImmuneEntity.kt index a722efb2ec..d78fef126b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapImmuneEntity.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapImmuneEntity.kt @@ -16,5 +16,5 @@ class MishapImmuneEntity(val entity: Entity) : Mishap() { } override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = - error("immune_entity", entity.displayName.plainCopy().aqua) + error("immune_entity", (entity.displayName ?: net.minecraft.network.chat.Component.literal("???")).plainCopy().aqua) } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapInternalException.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapInternalException.kt index 7301c01127..7260bae575 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapInternalException.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapInternalException.kt @@ -3,6 +3,7 @@ package at.petrak.hexcasting.api.casting.mishaps import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.pigment.FrozenPigment +import net.minecraft.network.chat.Component import net.minecraft.world.item.DyeColor class MishapInternalException(val exception: Exception) : Mishap() { @@ -13,6 +14,6 @@ class MishapInternalException(val exception: Exception) : Mishap() { // NO-OP } - override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = - error("unknown", exception) + override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component? = + error("unknown", exception.message ?: exception.toString()) } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/circle/MishapNoSpellCircle.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/circle/MishapNoSpellCircle.kt index 9eeae0f2b5..f2b8c34f32 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/circle/MishapNoSpellCircle.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/circle/MishapNoSpellCircle.kt @@ -8,6 +8,7 @@ import net.minecraft.server.level.ServerPlayer import net.minecraft.world.entity.player.Player import net.minecraft.world.item.DyeColor import net.minecraft.world.item.ItemStack +import net.minecraft.tags.EnchantmentTags import net.minecraft.world.item.enchantment.EnchantmentHelper class MishapNoSpellCircle : Mishap() { @@ -32,7 +33,7 @@ class MishapNoSpellCircle : Mishap() { dropAll(caster, caster.inventory.items) dropAll(caster, caster.inventory.offhand) dropAll(caster, caster.inventory.armor) { - !EnchantmentHelper.hasBindingCurse(it) + !EnchantmentHelper.hasTag(it, EnchantmentTags.CURSE) } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java b/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java index c312383129..53f3fe2a4c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java @@ -6,6 +6,7 @@ import at.petrak.hexcasting.api.utils.NBTHelper; import at.petrak.hexcasting.client.ClientTickCounter; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; +import net.minecraft.nbt.Tag; import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; @@ -64,8 +65,11 @@ default int getColor(ItemStack stack) { if (NBTHelper.hasString(stack, TAG_OVERRIDE_VISUALLY)) { var override = NBTHelper.getString(stack, TAG_OVERRIDE_VISUALLY); - if (override != null && ResourceLocation.isValidResourceLocation(override)) { - var key = new ResourceLocation(override); + if (override != null) { + var key = ResourceLocation.tryParse(override); + if (key == null) { + return 0xFF000000 | Mth.hsvToRgb(ClientTickCounter.getTotal() * 2 % 360 / 360F, 0.75F, 1F); + } if (HexIotaTypes.REGISTRY.containsKey(key)) { var iotaType = HexIotaTypes.REGISTRY.get(key); if (iotaType != null) { @@ -103,7 +107,7 @@ default int getColor(ItemStack stack) { static void appendHoverText(IotaHolderItem self, ItemStack stack, List components, TooltipFlag flag) { var datumTag = self.readIotaTag(stack); - if (datumTag != null) { + if (datumTag != null && datumTag.contains(HexIotaTypes.KEY_TYPE, Tag.TAG_STRING) && datumTag.contains(HexIotaTypes.KEY_DATA)) { var cmp = IotaType.getDisplay(datumTag); components.add(Component.translatable("hexcasting.spelldata.onitem", cmp)); diff --git a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java index aa4859f5ed..497f633af4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java @@ -109,11 +109,9 @@ default Tier opBreakHarvestLevel() { // Simple extensions for resource location configs public static boolean anyMatch(List keys, ResourceLocation key) { for (String s : keys) { - if (ResourceLocation.isValidResourceLocation(s)) { - var rl = new ResourceLocation(s); - if (rl.equals(key)) { - return true; - } + var rl = ResourceLocation.tryParse(s); + if (rl != null && rl.equals(key)) { + return true; } } return false; diff --git a/Common/src/main/java/at/petrak/hexcasting/api/pigment/FrozenPigment.java b/Common/src/main/java/at/petrak/hexcasting/api/pigment/FrozenPigment.java index 4f2f1540bc..ff467ec854 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/pigment/FrozenPigment.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/pigment/FrozenPigment.java @@ -4,6 +4,8 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.Util; import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import java.util.UUID; @@ -28,7 +30,7 @@ public record FrozenPigment(ItemStack item, UUID owner) { public CompoundTag serializeToNBT() { var out = new CompoundTag(); - out.put(TAG_STACK, this.item.save(new CompoundTag())); + out.putString(TAG_STACK, BuiltInRegistries.ITEM.getKey(this.item.getItem()).toString()); out.putUUID(TAG_OWNER, this.owner); return out; } @@ -38,8 +40,9 @@ public static FrozenPigment fromNBT(CompoundTag tag) { return FrozenPigment.DEFAULT.get(); } try { - CompoundTag stackTag = tag.getCompound(TAG_STACK); - var stack = ItemStack.of(stackTag); + var itemLoc = ResourceLocation.tryParse(tag.getString(TAG_STACK)); + var item = itemLoc != null ? BuiltInRegistries.ITEM.get(itemLoc) : HexItems.DEFAULT_PIGMENT; + var stack = new ItemStack(item); var uuid = tag.getUUID(TAG_OWNER); return new FrozenPigment(stack, uuid); } catch (NullPointerException exn) { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt b/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt index 209297766a..c7ace5bab3 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt @@ -7,6 +7,7 @@ import at.petrak.hexcasting.api.casting.iota.IotaType import at.petrak.hexcasting.api.casting.iota.ListIota import at.petrak.hexcasting.api.casting.math.HexCoord import net.minecraft.ChatFormatting +import net.minecraft.core.HolderLookup import net.minecraft.core.Registry import net.minecraft.nbt.* import net.minecraft.network.chat.Component @@ -283,10 +284,10 @@ fun List.zipWithDefault(array: ByteArray, default: (idx: Int) -> Byte): L return list } -// Copy the impl from forge -fun ItemStack.serializeToNBT(): CompoundTag { +// 1.21+: ItemStack.save requires HolderLookup.Provider +fun ItemStack.serializeToNBT(registryAccess: HolderLookup.Provider): CompoundTag { val out = CompoundTag() - this.save(out) + this.save(registryAccess, out) return out } @@ -309,7 +310,8 @@ fun isOfTag(registry: Registry, key: ResourceKey, tag: TagKey): Boo return holder.`is`(tag) } -fun isOfTag(registry: Registry, loc: ResourceLocation, tag: TagKey): Boolean { - val key = ResourceKey.create(registry.key(), loc); +fun isOfTag(registry: Registry, loc: ResourceLocation?, tag: TagKey): Boolean { + if (loc == null) return false + val key = ResourceKey.create(registry.key(), loc) return isOfTag(registry, key, tag) } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt b/Common/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt index ef9a757c01..eebc5dd1eb 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt @@ -2,6 +2,7 @@ package at.petrak.hexcasting.api.utils +import at.petrak.hexcasting.common.lib.HexDataComponents import net.minecraft.nbt.* import net.minecraft.world.item.ItemStack import java.util.* @@ -178,6 +179,28 @@ val Tag.asList get() = this as? ListTag ?: ListTag() val Tag.asUUID: UUID get() = if (this is IntArrayTag && this.size == 4) NbtUtils.loadUUID(this) else UUID(0, 0) // ========================================================================================================== ItemStack +// 1.21+: ItemStack NBT replaced by data components; we use HexDataComponents.STACK_DATA (CompoundTag). + +private val ItemStack.tag: CompoundTag + get() = get(HexDataComponents.STACK_DATA) ?: CompoundTag() + +fun ItemStack.getOrCreateTag(): CompoundTag = orCreateTagInternal() +private fun ItemStack.orCreateTagInternal(): CompoundTag { + var t = get(HexDataComponents.STACK_DATA) + if (t == null) { + t = CompoundTag() + set(HexDataComponents.STACK_DATA, t) + } + return t +} + +fun ItemStack.removeTagKey(key: String) { + val t = get(HexDataComponents.STACK_DATA) ?: return + t.remove(key) + if (t.isEmpty) remove(HexDataComponents.STACK_DATA) else set(HexDataComponents.STACK_DATA, t) +} + +private fun ItemStack.getOrCreateTagElement(key: String): CompoundTag = orCreateTagInternal().getOrCreateCompound(key) // Checks for containment @@ -209,24 +232,24 @@ fun ItemStack.containsTag(key: String, id: Int) = tag.contains(key, id) // Puts -fun ItemStack.putBoolean(key: String, value: Boolean) = orCreateTag.putBoolean(key, value) -fun ItemStack.putByte(key: String, value: Byte) = orCreateTag.putByte(key, value) -fun ItemStack.putShort(key: String, value: Short) = orCreateTag.putShort(key, value) -fun ItemStack.putInt(key: String, value: Int) = orCreateTag.putInt(key, value) -fun ItemStack.putLong(key: String, value: Long) = orCreateTag.putLong(key, value) -fun ItemStack.putFloat(key: String, value: Float) = orCreateTag.putFloat(key, value) -fun ItemStack.putDouble(key: String, value: Double) = orCreateTag.putDouble(key, value) - -fun ItemStack.putLongArray(key: String, value: LongArray) = orCreateTag.putLongArray(key, value) -fun ItemStack.putIntArray(key: String, value: IntArray) = orCreateTag.putIntArray(key, value) -fun ItemStack.putByteArray(key: String, value: ByteArray) = orCreateTag.putByteArray(key, value) +fun ItemStack.putBoolean(key: String, value: Boolean) = getOrCreateTag().putBoolean(key, value) +fun ItemStack.putByte(key: String, value: Byte) = getOrCreateTag().putByte(key, value) +fun ItemStack.putShort(key: String, value: Short) = getOrCreateTag().putShort(key, value) +fun ItemStack.putInt(key: String, value: Int) = getOrCreateTag().putInt(key, value) +fun ItemStack.putLong(key: String, value: Long) = getOrCreateTag().putLong(key, value) +fun ItemStack.putFloat(key: String, value: Float) = getOrCreateTag().putFloat(key, value) +fun ItemStack.putDouble(key: String, value: Double) = getOrCreateTag().putDouble(key, value) + +fun ItemStack.putLongArray(key: String, value: LongArray) = getOrCreateTag().putLongArray(key, value) +fun ItemStack.putIntArray(key: String, value: IntArray) = getOrCreateTag().putIntArray(key, value) +fun ItemStack.putByteArray(key: String, value: ByteArray) = getOrCreateTag().putByteArray(key, value) fun ItemStack.putCompound(key: String, value: CompoundTag) = putTag(key, value) -fun ItemStack.putString(key: String, value: String) = orCreateTag.putString(key, value) +fun ItemStack.putString(key: String, value: String) = getOrCreateTag().putString(key, value) fun ItemStack.putList(key: String, value: ListTag) = putTag(key, value) -fun ItemStack.putUUID(key: String, value: UUID) = orCreateTag.putUUID(key, value) +fun ItemStack.putUUID(key: String, value: UUID) = getOrCreateTag().putUUID(key, value) @JvmName("put") -fun ItemStack.putTag(key: String, value: Tag) = orCreateTag.put(key, value) +fun ItemStack.putTag(key: String, value: Tag) = getOrCreateTag().put(key, value) // Remove @@ -269,5 +292,5 @@ fun ItemStack.getTag(key: String) = tag.get(key) // Get-or-create fun ItemStack.getOrCreateCompound(key: String): CompoundTag = getOrCreateTagElement(key) -fun ItemStack.getOrCreateList(key: String, objType: Byte) = orCreateTag.getOrCreateList(key, objType) -fun ItemStack.getOrCreateList(key: String, objType: Int) = orCreateTag.getOrCreateList(key, objType) +fun ItemStack.getOrCreateList(key: String, objType: Byte) = getOrCreateTag().getOrCreateList(key, objType) +fun ItemStack.getOrCreateList(key: String, objType: Int) = getOrCreateTag().getOrCreateList(key, objType) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java b/Common/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java index 14ce4e1d22..5835a94545 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java @@ -222,7 +222,7 @@ private static void registerPackagedSpellOverrides(ItemPackagedHex item) { private static void registerWandOverrides(ItemStaff item) { IClientXplatAbstractions.INSTANCE.registerItemProperty(item, ItemStaff.FUNNY_LEVEL_PREDICATE, (stack, level, holder, holderID) -> { - if (!stack.hasCustomHoverName()) { + if (stack.get(net.minecraft.core.component.DataComponents.CUSTOM_NAME) == null) { return 0; } var name = stack.getHoverName().getString().toLowerCase(Locale.ROOT); diff --git a/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java index d17e617cd9..5eca6cfd90 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java @@ -14,8 +14,6 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; -import org.joml.Matrix3f; -import org.joml.Matrix4f; import static at.petrak.hexcasting.api.HexAPI.modLoc; @@ -55,43 +53,41 @@ public void render(EntityWallScroll wallScroll, float yaw, float partialTicks, P float dx = wallScroll.blockSize, dy = wallScroll.blockSize, dz = -1f / 16f; float margin = 1f / 48f; var last = ps.last(); - var mat = last.pose(); - var norm = last.normal(); RenderType layer = RenderType.entityCutout(this.getTextureLocation(wallScroll)); var verts = bufSource.getBuffer(layer); // Remember: CCW // Front face - vertex(mat, norm, light, verts, 0, 0, dz, 0, 0, 0, 0, -1); - vertex(mat, norm, light, verts, 0, dy, dz, 0, 1, 0, 0, -1); - vertex(mat, norm, light, verts, dx, dy, dz, 1, 1, 0, 0, -1); - vertex(mat, norm, light, verts, dx, 0, dz, 1, 0, 0, 0, -1); + vertex(last, light, verts, 0, 0, dz, 0, 0, 0, 0, -1); + vertex(last, light, verts, 0, dy, dz, 0, 1, 0, 0, -1); + vertex(last, light, verts, dx, dy, dz, 1, 1, 0, 0, -1); + vertex(last, light, verts, dx, 0, dz, 1, 0, 0, 0, -1); // Back face - vertex(mat, norm, light, verts, 0, 0, 0, 0, 0, 0, 0, 1); - vertex(mat, norm, light, verts, dx, 0, 0, 1, 0, 0, 0, 1); - vertex(mat, norm, light, verts, dx, dy, 0, 1, 1, 0, 0, 1); - vertex(mat, norm, light, verts, 0, dy, 0, 0, 1, 0, 0, 1); + vertex(last, light, verts, 0, 0, 0, 0, 0, 0, 0, 1); + vertex(last, light, verts, dx, 0, 0, 1, 0, 0, 0, 1); + vertex(last, light, verts, dx, dy, 0, 1, 1, 0, 0, 1); + vertex(last, light, verts, 0, dy, 0, 0, 1, 0, 0, 1); // Top face - vertex(mat, norm, light, verts, 0, 0, 0, 0, 0, 0, -1, 0); - vertex(mat, norm, light, verts, 0, 0, dz, 0, margin, 0, -1, 0); - vertex(mat, norm, light, verts, dx, 0, dz, 1, margin, 0, -1, 0); - vertex(mat, norm, light, verts, dx, 0, 0, 1, 0, 0, -1, 0); + vertex(last, light, verts, 0, 0, 0, 0, 0, 0, -1, 0); + vertex(last, light, verts, 0, 0, dz, 0, margin, 0, -1, 0); + vertex(last, light, verts, dx, 0, dz, 1, margin, 0, -1, 0); + vertex(last, light, verts, dx, 0, 0, 1, 0, 0, -1, 0); // Left face - vertex(mat, norm, light, verts, 0, 0, 0, 0, 0, -1, 0, 0); - vertex(mat, norm, light, verts, 0, dy, 0, 0, 1, -1, 0, 0); - vertex(mat, norm, light, verts, 0, dy, dz, margin, 1, -1, 0, 0); - vertex(mat, norm, light, verts, 0, 0, dz, margin, 0, -1, 0, 0); + vertex(last, light, verts, 0, 0, 0, 0, 0, -1, 0, 0); + vertex(last, light, verts, 0, dy, 0, 0, 1, -1, 0, 0); + vertex(last, light, verts, 0, dy, dz, margin, 1, -1, 0, 0); + vertex(last, light, verts, 0, 0, dz, margin, 0, -1, 0, 0); // Right face - vertex(mat, norm, light, verts, dx, 0, dz, 1 - margin, 0, 1, 0, 0); - vertex(mat, norm, light, verts, dx, dy, dz, 1 - margin, 1, 1, 0, 0); - vertex(mat, norm, light, verts, dx, dy, 0, 1, 1, 1, 0, 0); - vertex(mat, norm, light, verts, dx, 0, 0, 1, 0, 1, 0, 0); + vertex(last, light, verts, dx, 0, dz, 1 - margin, 0, 1, 0, 0); + vertex(last, light, verts, dx, dy, dz, 1 - margin, 1, 1, 0, 0); + vertex(last, light, verts, dx, dy, 0, 1, 1, 1, 0, 0); + vertex(last, light, verts, dx, 0, 0, 1, 0, 1, 0, 0); // Bottom face - vertex(mat, norm, light, verts, 0, dy, dz, 0, 1 - margin, 0, 1, 0); - vertex(mat, norm, light, verts, 0, dy, 0, 0, 1, 0, 1, 0); - vertex(mat, norm, light, verts, dx, dy, 0, 1, 1, 0, 1, 0); - vertex(mat, norm, light, verts, dx, dy, dz, 1, 1 - margin, 0, 1, 0); + vertex(last, light, verts, 0, dy, dz, 0, 1 - margin, 0, 1, 0); + vertex(last, light, verts, 0, dy, 0, 0, 1, 0, 1, 0); + vertex(last, light, verts, dx, dy, 0, 1, 1, 0, 1, 0); + vertex(last, light, verts, dx, dy, dz, 1, 1 - margin, 0, 1, 0); ps.popPose(); @@ -124,13 +120,12 @@ public ResourceLocation getTextureLocation(EntityWallScroll wallScroll) { } } - private static void vertex(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, float x, float y, + private static void vertex(com.mojang.blaze3d.vertex.PoseStack.Pose pose, int light, VertexConsumer verts, float x, float y, float z, float u, float v, float nx, float ny, float nz) { - verts.vertex(mat, x, y, z) - .color(0xffffffff) - .uv(u, v).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(light) - .normal(normal, nx, ny, nz) - .endVertex(); + verts.addVertex(pose.pose(), x, y, z) + .setColor(0xffffffff) + .setUv(u, v).setOverlay(OverlayTexture.NO_OVERLAY).setLight(light) + .setNormal(pose, nx, ny, nz); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt b/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt index df0c5acb60..f0d6c5f7a1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt @@ -16,6 +16,7 @@ import at.petrak.hexcasting.client.ShiftScrollListener import at.petrak.hexcasting.client.ktxt.accumulatedScroll import at.petrak.hexcasting.client.render.* import at.petrak.hexcasting.client.sound.GridSoundInstance +import at.petrak.hexcasting.common.items.ItemStaff import at.petrak.hexcasting.common.lib.HexAttributes import at.petrak.hexcasting.common.lib.HexSounds import at.petrak.hexcasting.common.msgs.MsgNewSpellPatternC2S @@ -53,6 +54,9 @@ class GuiSpellcasting constructor( private var ambianceSoundInstance: GridSoundInstance? = null + /** Skip close check for first few ticks to avoid race with item/tag sync on open */ + private var ticksOpen: Int = 0 + private val randSrc = SoundInstance.createUnseededRandom() init { @@ -118,11 +122,14 @@ class GuiSpellcasting constructor( } override fun tick() { + ticksOpen++ + if (ticksOpen < 5) return val minecraft = Minecraft.getInstance() val player = minecraft.player if (player != null) { val heldItem = player.getItemInHand(handOpenedWith) - if (heldItem.isEmpty || !heldItem.`is`(HexTags.Items.STAVES) || player.getAttributeValue(HexAttributes.FEEBLE_MIND) > 0) + val isStaff = heldItem.`is`(HexTags.Items.STAVES) || heldItem.item is ItemStaff + if (heldItem.isEmpty || !isStaff || player.getAttributeValue(HexAttributes.getHolder(player, HexAttributes.FEEBLE_MIND_KEY)) > 0) closeForReal() } } @@ -291,11 +298,12 @@ class GuiSpellcasting constructor( return false } - override fun mouseScrolled(pMouseX: Double, pMouseY: Double, pDelta: Double): Boolean { - super.mouseScrolled(pMouseX, pMouseY, pDelta) + override fun mouseScrolled(pMouseX: Double, pMouseY: Double, pScrollX: Double, pScrollY: Double): Boolean { + super.mouseScrolled(pMouseX, pMouseY, pScrollX, pScrollY) val mouseHandler = Minecraft.getInstance().mouseHandler + val pDelta = pScrollY if (mouseHandler.accumulatedScroll != 0.0 && sign(pDelta) != sign(mouseHandler.accumulatedScroll)) { mouseHandler.accumulatedScroll = 0.0 } @@ -308,7 +316,7 @@ class GuiSpellcasting constructor( mouseHandler.accumulatedScroll -= accumulation.toDouble() - ShiftScrollListener.onScroll(pDelta, false) + ShiftScrollListener.onScroll(pScrollY, false) return true } @@ -487,15 +495,12 @@ class GuiSpellcasting constructor( RenderSystem.setShader { prevShader } } - // why the hell is this default true override fun isPauseScreen(): Boolean = false /** Distance between adjacent hex centers */ fun hexSize(): Float { - val scaleModifier = Minecraft.getInstance().player!!.getAttributeValue(HexAttributes.GRID_ZOOM) + val scaleModifier = Minecraft.getInstance().player!!.getAttributeValue(HexAttributes.getHolder(Minecraft.getInstance().player!!, HexAttributes.GRID_ZOOM_KEY)) - // Originally, we allowed 32 dots across. Assuming a 1920x1080 screen this allowed like 500-odd area. - // Let's be generous and give them 512. val baseScale = sqrt(this.width.toDouble() * this.height / 512.0) return (baseScale / scaleModifier).toFloat() } @@ -509,13 +514,10 @@ class GuiSpellcasting constructor( private sealed class PatternDrawState { - /** We're waiting on the player to right-click again */ object BetweenPatterns : PatternDrawState() - /** We just started drawing and haven't drawn the first line yet. */ data class JustStarted(val start: HexCoord) : PatternDrawState() - /** We've started drawing a pattern for real. */ data class Drawing(val start: HexCoord, var current: HexCoord, val wipPattern: HexPattern) : PatternDrawState() } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java b/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java index c6f7da11d8..8ca70b7d93 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java @@ -68,13 +68,8 @@ public void renderImage(Font font, int mouseX, int mouseY, GuiGraphics graphics) } private static void renderBG(GuiGraphics graphics, ResourceLocation background) { - graphics.blit( - background, // texture - 0, 0, // x, y - (int) RENDER_SIZE, (int) RENDER_SIZE, // renderWidth, renderHeight - 0f, 0f, // u, v (textureCoords) - TEXTURE_SIZE, TEXTURE_SIZE, // regionWidth, regionHeight (texture sample dimensions) - TEXTURE_SIZE, TEXTURE_SIZE); // textureWidth, textureHeight (total dimensions of texture) + graphics.blit(background, 0, 0, (int) RENDER_SIZE, (int) RENDER_SIZE, + 0f, 0f, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/client/model/AltioraLayer.java b/Common/src/main/java/at/petrak/hexcasting/client/model/AltioraLayer.java index a354d6eba3..fda954ad81 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/model/AltioraLayer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/model/AltioraLayer.java @@ -43,8 +43,8 @@ public void render(PoseStack ps, MultiBufferSource buffer, int packedLight, Abst this.getParentModel().copyPropertiesTo(this.elytraModel); this.elytraModel.setupAnim(player, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); VertexConsumer verts = ItemRenderer.getArmorFoilBuffer( - buffer, RenderType.armorCutoutNoCull(TEX_LOC), false, true); - this.elytraModel.renderToBuffer(ps, verts, packedLight, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F); + buffer, RenderType.armorCutoutNoCull(TEX_LOC), true); + this.elytraModel.renderToBuffer(ps, verts, packedLight, OverlayTexture.NO_OVERLAY); ps.popPose(); } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModels.java b/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModels.java index 7f35494cab..a46340f90f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModels.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/model/HexRobesModels.java @@ -11,8 +11,6 @@ import static at.petrak.hexcasting.api.HexAPI.modLoc; public class HexRobesModels { - // This layer location should be baked with EntityRendererProvider.Context in the entity renderer and passed into - // this model's constructor public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(modLoc("robes"), "main"); public static LayerDefinition variant1() { diff --git a/Common/src/main/java/at/petrak/hexcasting/client/model/MyOwnArmorModelWithBlackjackAndHookers.java b/Common/src/main/java/at/petrak/hexcasting/client/model/MyOwnArmorModelWithBlackjackAndHookers.java index fc63fcdf72..f7d88cd059 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/model/MyOwnArmorModelWithBlackjackAndHookers.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/model/MyOwnArmorModelWithBlackjackAndHookers.java @@ -1,7 +1,5 @@ package at.petrak.hexcasting.client.model; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.world.entity.EquipmentSlot; @@ -18,10 +16,11 @@ public MyOwnArmorModelWithBlackjackAndHookers(ModelPart root, EquipmentSlot slot } // [VanillaCopy] ArmorStandArmorModel.setupAnim because armor stands are dumb - // This fixes the armor "breathing" and helmets always facing south on armor stands + // setPartVisibility is called here since renderToBuffer is final in 1.21 @Override public void setupAnim(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + setPartVisibility(slot); if (!(entity instanceof ArmorStand entityIn)) { super.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); return; @@ -51,13 +50,6 @@ public void setupAnim(LivingEntity entity, float limbSwing, float limbSwingAmoun this.hat.copyFrom(this.head); } - @Override - public void renderToBuffer(PoseStack ms, VertexConsumer buffer, int light, int overlay, float r, float g, float b - , float a) { - setPartVisibility(slot); - super.renderToBuffer(ms, buffer, light, overlay, r, g, b, a); - } - // [VanillaCopy] HumanoidArmorLayer private void setPartVisibility(EquipmentSlot slot) { setAllVisible(false); diff --git a/Common/src/main/java/at/petrak/hexcasting/client/particles/ConjureParticle.java b/Common/src/main/java/at/petrak/hexcasting/client/particles/ConjureParticle.java index 122e536e75..1cc0138851 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/particles/ConjureParticle.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/particles/ConjureParticle.java @@ -91,7 +91,7 @@ public Particle createParticle(ConjureParticleOptions type, ClientLevel level, // https://github.com/VazkiiMods/Botania/blob/db85d778ab23f44c11181209319066d1f04a9e3d/Xplat/src/main/java/vazkii/botania/client/fx/FXWisp.java private record ConjureRenderType() implements ParticleRenderType { @Override - public void begin(BufferBuilder buf, TextureManager texMan) { + public BufferBuilder begin(Tesselator tess, TextureManager texMan) { Minecraft.getInstance().gameRenderer.lightTexture().turnOnLightLayer(); RenderSystem.depthMask(false); RenderSystem.enableBlend(); @@ -100,19 +100,11 @@ public void begin(BufferBuilder buf, TextureManager texMan) { RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES); var tex = texMan.getTexture(TextureAtlas.LOCATION_PARTICLES); IClientXplatAbstractions.INSTANCE.setFilterSave(tex, true, false); - buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE); + var buf = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE); RenderSystem.enableDepthTest(); + return buf; } - @Override - public void end(Tesselator tess) { - tess.end(); - IClientXplatAbstractions.INSTANCE.restoreLastFilter( - Minecraft.getInstance().getTextureManager().getTexture(TextureAtlas.LOCATION_PARTICLES) - ); - RenderSystem.disableBlend(); - RenderSystem.depthMask(true); - } @Override public String toString() { diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/HexAdditionalRenderers.java b/Common/src/main/java/at/petrak/hexcasting/client/render/HexAdditionalRenderers.java index 0e96540a91..6c2ef9a3f0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/HexAdditionalRenderers.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/HexAdditionalRenderers.java @@ -10,6 +10,7 @@ import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.BufferUploader; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexFormat; @@ -75,7 +76,7 @@ private static void renderSentinel(Sentinel sentinel, LocalPlayer owner, var tess = Tesselator.getInstance(); - var buf = tess.getBuilder(); + var buf = tess.begin(VertexFormat.Mode.LINES, DefaultVertexFormat.POSITION_COLOR_NORMAL); var neo = ps.last().pose(); RenderSystem.enableBlend(); RenderSystem.setShader(GameRenderer::getRendertypeLinesShader); @@ -91,18 +92,15 @@ private static void renderSentinel(Sentinel sentinel, LocalPlayer owner, rcolor = colProvider.getColor(time, new Vec3(r[0], r[1], r[2])); var normal = new Vector3f(r[0] - l[0], r[1] - l[1], r[2] - l[2]); normal.normalize(); - buf.vertex(neo, l[0], l[1], l[2]) - .color(lcolor) - .normal(ps.last().normal(), normal.x(), normal.y(), normal.z()) - .endVertex(); - buf.vertex(neo, r[0], r[1], r[2]) - .color(rcolor) - .normal(ps.last().normal(), -normal.x(), -normal.y(), -normal.z()) - .endVertex(); + buf.addVertex(neo, l[0], l[1], l[2]) + .setColor(lcolor) + .setNormal(ps.last(), normal.x(), normal.y(), normal.z()); + buf.addVertex(neo, r[0], r[1], r[2]) + .setColor(rcolor) + .setNormal(ps.last(), -normal.x(), -normal.y(), -normal.z()); }; // Icosahedron inscribed inside the unit sphere - buf.begin(VertexFormat.Mode.LINES, DefaultVertexFormat.POSITION_COLOR_NORMAL); for (int side = 0; side <= 1; side++) { var ring = (side == 0) ? Icos.BOTTOM_RING : Icos.TOP_RING; var apex = (side == 0) ? Icos.BOTTOM : Icos.TOP; @@ -123,7 +121,7 @@ private static void renderSentinel(Sentinel sentinel, LocalPlayer owner, v.accept(Icos.TOP_RING[(i + 2) % 5], bottom); v.accept(bottom, Icos.TOP_RING[(i + 3) % 5]); } - tess.end(); + BufferUploader.drawWithShader(buf.buildOrThrow()); RenderSystem.enableDepthTest(); RenderSystem.enableCull(); @@ -159,7 +157,7 @@ private static void tryRenderScryingLensOverlay(GuiGraphics graphics, float part return; } - if (player.getAttributeValue(HexAttributes.SCRY_SIGHT) <= 0.0 || player.getAttributeValue(HexAttributes.FEEBLE_MIND) > 0) + if (player.getAttributeValue(HexAttributes.getHolder(player, HexAttributes.SCRY_SIGHT_KEY)) <= 0.0 || player.getAttributeValue(HexAttributes.getHolder(player, HexAttributes.FEEBLE_MIND_KEY)) > 0) return; var hitRes = mc.hitResult; diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PATTERN_RENDER_LORE.md b/Common/src/main/java/at/petrak/hexcasting/client/render/PATTERN_RENDER_LORE.md deleted file mode 100644 index fdeb3eb6e1..0000000000 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PATTERN_RENDER_LORE.md +++ /dev/null @@ -1,52 +0,0 @@ -# Pattern Rendering Lore - -This is an overview of the new pattern rendering systems introduced alongside the Inline pattern rendering - -## Brief History / Motivations - -In v0.10.3 (and probably before) the pattern rendering was well known for causing lag if many patterns were rendered at once. -The pattern code was also duplicated *a lot*, pretty much anywhere that did pattern rendering needed to do it slightly different and so the rendering/positioning code got copy-pasted all around, frequently with a lot of magic numbers. - -During 1.20 development, we [added texture based rendering](https://github.com/FallingColors/HexMod/pull/555), and switched most static rendering over to it. There was still a fair bit of duplicate code though, especially with pattern positioning. - -Now with the new system, all of the rendering is contained to a few classes and outside users (such as slates for example) can specify how they want patterns to be rendered using PatternSettings and PatternColors. - -## System Walkthrough (External) - -### PatternRenderer - -This is the main entrypoint for pattern rendering. It has 3 main methods, all called `renderPattern`. One is the driver method and the others are convenience wrappers. - -Generally the idea here is that you shouldn't need to worry about whether the pattern will be rendered as a texture or dynamically, the `PatternRenderer` will make that decision, prefering the texture renderer when it can. The dynamic renderer will be used if the pattern is moving (speed != 0), if the pattern has a gradient stroke, or if the texture isn't ready yet. - -### PatternSettings - -This is where the vast majority of the rendering configuration happens. Arguably it is overkill. - -It's a class with many getters constructed from 3 records: `PositionSettings`, `StrokeSettings`, and `ZappySettings`. The getters can be overridden when/if needed, the records are more for user convenience. See javadocs for details on what can be configured here. - -Pattern textures are also generated based on settings, so it's **VERY ENCOURAGED** to re-use pattern settings when you can. - -### PatternColors - -This is just a simple record holding colors for different parts of pattern drawing. It has probably too many helpers. The main thing to note here is that you can set the alpha to 0 to skip rendering a section (such as dots or innerStroke). Transparent colors for strokes are **discouraged** due to the dynamic renderer having a sort of internal overlapping that is only noticeable with transparent strokes. - -### WorldlyPatternRenderHelpers - -This is where all the worldly base-hex renders ended up. Good to look at for examples of using the renderer and some pattern settings that could be re-used. - -## System Walkthrough (Internal) - -### HexPatternPoints - -This is where the positioning actually happens. It generates dots and zappy points based on the pattern and PatternSettings passed in. This object is then cached to prevent needing to calculate it all each frame. Note that this includes scaling and all that, the returned zappy points are in pose units. - -### VCDrawHelper (& RenderLib changes) - -We do a silly with this one lol. This allows us to separate the lower level vertex handling from the higher level 'drawing'. - -Previously `RenderLib.drawLineSeq(..)` drew straight to the tesselator with the `POSITION_COLOR` shader/format. Now it just passes color and position data to the `VCDrawHelper` that we give it, allowing us to create and push a vertex however we want to wherever we want. This lets us draw to other vertex consumers and use other shaders/formats, like the `EntityTranslucentCull` that we use for worldly rendering with light and normals. - -To maintain API stability we have the previous `RenderLib.drawLineSeq(..)` method signature just call the new version using the `Basic` draw helper. - -Conveniently we can also use this for drawing our textures! \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternColors.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternColors.java index fb64669834..e915d062ab 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternColors.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternColors.java @@ -9,7 +9,6 @@ public record PatternColors(int innerStartColor, int innerEndColor, int outerStartColor, int outerEndColor, int startingDotColor, int gridDotsColor){ - // keep some handy frequently used colors here. public static final PatternColors DEFAULT_PATTERN_COLOR = new PatternColors(0xff_554d54, 0xff_d2c8c8); public static final PatternColors DIMMED_COLOR = new PatternColors(0xFF_B4AAAA, 0xff_d2c8c8); public static final PatternColors DEFAULT_GRADIENT_COLOR = DEFAULT_PATTERN_COLOR.withGradientEnds(DIMMED_COLOR); @@ -20,20 +19,17 @@ public record PatternColors(int innerStartColor, int innerEndColor, int outerSta public static final PatternColors READABLE_SCROLL_COLORS = DEFAULT_PATTERN_COLOR.withDots(true, false); public static final PatternColors READABLE_GRID_SCROLL_COLORS = DEFAULT_PATTERN_COLOR.withDots(true, true); - public static final PatternColors SLATE_WOBBLY_COLOR = glowyStroke( 0xff_64c8ff); // old blue color - public static final PatternColors SLATE_WOBBLY_PURPLE_COLOR = glowyStroke(0xff_cfa0f3); // shiny new purple one :) + public static final PatternColors SLATE_WOBBLY_COLOR = glowyStroke( 0xff_64c8ff); + public static final PatternColors SLATE_WOBBLY_PURPLE_COLOR = glowyStroke(0xff_cfa0f3); - // no gradient public PatternColors(int innerColor, int outerColor){ this(innerColor, innerColor, outerColor, outerColor, 0, 0); } - // single color -- no inner layer public static PatternColors singleStroke(int color){ return new PatternColors(0, color); } - // makes a stroke color similar to the glowy effect that slates have. public static PatternColors glowyStroke(int color){ return new PatternColors(RenderLib.screenCol(color), color); } @@ -42,7 +38,6 @@ public static PatternColors gradientStrokes(int innerStartColor, int innerEndCol return new PatternColors(innerStartColor, innerEndColor, outerStartColor, outerEndColor, 0, 0); } - // a single stroke with a gradient -- no inner layer. public static PatternColors gradientStroke(int startColor, int endColor){ return PatternColors.gradientStrokes(0, 0, startColor, endColor); } @@ -55,13 +50,11 @@ public PatternColors withGradientEnds(PatternColors end){ return withGradientEnds(end.innerEndColor, end.outerEndColor); } - // add dots -- note, this is how you tell the renderer to make dots public PatternColors withDotColors(int startingDotColor, int gridDotsColor){ return new PatternColors(this.innerStartColor, this.innerEndColor, this.outerStartColor, this.outerEndColor, startingDotColor, gridDotsColor); } - // adds dots with the default colors. public PatternColors withDots(boolean startingDot, boolean gridDots){ return withDotColors(startingDot ? STARTING_DOT : 0, gridDots ? GRID_DOTS : 0); } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternSettings.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternSettings.java index 4cb223f6f6..157abbffe3 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternSettings.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternSettings.java @@ -116,11 +116,6 @@ public enum AxisAlignment{ public double getMinWidth(){ return posSets.minWidth; } public double getMinHeight(){ return posSets.minHeight; } - /* these sizing getters take in the final pattern scale so that patterns can vary their stroke width when squished. - * the records keep a static value since that's fine for *most* use cases, override these methods if you need to use them. - * note that these widths are still in pose space units. - */ - public double getInnerWidth(double scale){ return strokeSets.innerWidth; } public double getOuterWidth(double scale){ return strokeSets.outerWidth; } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/RenderLib.kt b/Common/src/main/java/at/petrak/hexcasting/client/render/RenderLib.kt index 823068439f..032636dd1b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/RenderLib.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/RenderLib.kt @@ -8,6 +8,7 @@ import at.petrak.hexcasting.api.utils.TAU import at.petrak.hexcasting.client.ClientTickCounter import at.petrak.hexcasting.client.gui.GuiSpellcasting import com.mojang.blaze3d.vertex.DefaultVertexFormat +import com.mojang.blaze3d.vertex.BufferUploader import com.mojang.blaze3d.vertex.PoseStack import com.mojang.blaze3d.vertex.Tesselator import com.mojang.blaze3d.vertex.VertexFormat @@ -250,38 +251,27 @@ fun makeZappy( barePoints: List, dupIndices: Set?, hops: Int, variance: Float, speed: Float, flowIrregular: Float, readabilityOffset: Float, lastSegmentLenProportion: Float, seed: Double ): List { - // Nothing in, nothing out if (barePoints.isEmpty()) { return emptyList() } fun zappify(points: List, truncateLast: Boolean): List { val scaleVariance = { it: Double -> 1.0.coerceAtMost(8 * (0.5 - abs(0.5 - it))) } val zSeed = ClientTickCounter.getTotal().toDouble() * speed - // Create our output list of zap points val zappyPts = ArrayList(points.size * hops) zappyPts.add(points[0]) - // For each segment in the original... for ((i, pair) in points.zipWithNext().withIndex()) { val (src, target) = pair val delta = target.add(src.negated()) - // Take hop distance val hopDist = Mth.sqrt(src.distanceToSqr(target)) / hops - // Compute how big the radius of variance should be val maxVariance = hopDist * variance - // for a list of length n, there will be n-1 pairs, - // and so the last index will be (n-1)-1 val maxJ = if (truncateLast && i == points.size - 2) { (lastSegmentLenProportion * hops.toFloat()).roundToInt() } else hops for (j in 1..maxJ) { val progress = j.toDouble() / (hops + 1) - // Add the next hop... val pos = src.add(delta.scale(progress.toFloat())) - // as well as some random variance... - // (We use i, j (segment #, subsegment #) as seeds for the Perlin noise, - // and zSeed (i.e. time elapsed) to perturb the shape gradually over time) val minorPerturb = getNoise(i.toDouble(), j.toDouble(), sin(zSeed)) * flowIrregular val theta = (3 * getNoise( i + progress + minorPerturb - zSeed, @@ -294,12 +284,9 @@ fun makeZappy( seed ) * maxVariance * scaleVariance(progress)).toFloat() val randomHop = Vec2(r * Mth.cos(theta), r * Mth.sin(theta)) - // Then record the new location. zappyPts.add(pos.add(randomHop)) if (j == hops) { - // Finally, we hit the destination, add that too - // but we might not hit the destination if we want to stop short zappyPts.add(target) } } @@ -447,19 +434,10 @@ fun renderQuad( ) { val mat = ps.last().pose() val tess = Tesselator.getInstance() - val buf = tess.builder - buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR) - buf.vertex(mat, x, y, 0f) - .color(color) - .endVertex() - buf.vertex(mat, x, y + h, 0f) - .color(color) - .endVertex() - buf.vertex(mat, x + w, y + h, 0f) - .color(color) - .endVertex() - buf.vertex(mat, x + w, y, 0f) - .color(color) - .endVertex() - tess.end() + val buf = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR) + buf.addVertex(mat, x, y, 0f).setColor(color) + buf.addVertex(mat, x, y + h, 0f).setColor(color) + buf.addVertex(mat, x + w, y + h, 0f).setColor(color) + buf.addVertex(mat, x + w, y, 0f).setColor(color) + BufferUploader.drawWithShader(buf.buildOrThrow()) } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/VCDrawHelper.kt b/Common/src/main/java/at/petrak/hexcasting/client/render/VCDrawHelper.kt index fb6c734e5f..0b21d778fa 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/VCDrawHelper.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/VCDrawHelper.kt @@ -2,11 +2,11 @@ package at.petrak.hexcasting.client.render import at.petrak.hexcasting.api.HexAPI import at.petrak.hexcasting.client.render.PatternRenderer.WorldlyBits -import com.ibm.icu.impl.CurrencyData.provider import com.mojang.blaze3d.platform.GlStateManager import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.* import net.minecraft.client.Minecraft +import com.mojang.blaze3d.vertex.BufferUploader import net.minecraft.client.renderer.GameRenderer import net.minecraft.client.renderer.LightTexture import net.minecraft.client.renderer.MultiBufferSource @@ -50,9 +50,8 @@ interface VCDrawHelper { override fun vcSetupAndSupply(vertMode: VertexFormat.Mode): VertexConsumer{ val tess = Tesselator.getInstance() - val buf = tess.builder - buf.begin(vertMode, DefaultVertexFormat.POSITION_COLOR_TEX) - RenderSystem.setShader(GameRenderer::getPositionColorTexShader); + val buf = tess.begin(vertMode, DefaultVertexFormat.POSITION_TEX_COLOR) + RenderSystem.setShader { GameRenderer.getPositionTexColorShader() } RenderSystem.disableCull() RenderSystem.enableDepthTest() RenderSystem.enableBlend() @@ -62,10 +61,10 @@ interface VCDrawHelper { return buf } override fun vertex(vc: VertexConsumer, color: Int, pos: Vec2, uv: Vec2, matrix: Matrix4f){ - vc.vertex(matrix, pos.x, pos.y, z).color(color).uv(uv.x, uv.y).endVertex() + vc.addVertex(matrix, pos.x, pos.y, z).setUv(uv.x, uv.y).setColor(color) } override fun vcEndDrawer(vc: VertexConsumer){ - Tesselator.getInstance().end() + BufferUploader.drawWithShader((vc as BufferBuilder).buildOrThrow()) } } @@ -80,19 +79,19 @@ interface VCDrawHelper { provider.endBatch() } lastVertMode = vertMode - val buf = Tesselator.getInstance().builder + val tess = Tesselator.getInstance() if(vertMode == VertexFormat.Mode.QUADS){ val layer = RenderType.entityTranslucentCull(texture) layer.setupRenderState() if (provider == null) { - buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.NEW_ENTITY) + val buf = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.NEW_ENTITY) RenderSystem.setShader { GameRenderer.getRendertypeEntityTranslucentCullShader() } return buf } else { return provider.getBuffer(layer) } } - buf.begin( vertMode, DefaultVertexFormat.NEW_ENTITY ) + val buf = tess.begin(vertMode, DefaultVertexFormat.NEW_ENTITY) // Generally this would be handled by a RenderLayer, but that doesn't seem to actually work here,, RenderSystem.setShaderTexture(0, texture) RenderSystem.enableDepthTest() @@ -105,29 +104,27 @@ interface VCDrawHelper { if (Minecraft.useShaderTransparency()) { Minecraft.getInstance().levelRenderer.translucentTarget!!.bindWrite(false) } - RenderSystem.setShader( GameRenderer::getRendertypeEntityTranslucentCullShader ) + RenderSystem.setShader { GameRenderer.getRendertypeEntityTranslucentCullShader() } return buf } override fun vertex(vc: VertexConsumer, color: Int, pos: Vec2, uv: Vec2, matrix: Matrix4f){ val nv = worldlyBits.normal?: Vec3(1.0, 1.0, 1.0) - vc.vertex(matrix, pos.x, pos.y, z) - .color(color) - .uv(uv.x, uv.y) - .overlayCoords(OverlayTexture.NO_OVERLAY) - .uv2(worldlyBits.light?: LightTexture.FULL_BRIGHT ) - .normal(ps.last().normal(), nv.x.toFloat(), nv.y.toFloat(), nv.z.toFloat()) - - vc.endVertex() + vc.addVertex(matrix, pos.x, pos.y, z) + .setColor(color) + .setUv(uv.x, uv.y) + .setOverlay(OverlayTexture.NO_OVERLAY) + .setLight(worldlyBits.light ?: LightTexture.FULL_BRIGHT) + .setNormal(ps.last(), nv.x.toFloat(), nv.y.toFloat(), nv.z.toFloat()) } override fun vcEndDrawer(vc: VertexConsumer){ if(lastVertMode == VertexFormat.Mode.QUADS){ - if (provider == null) { + if (worldlyBits.provider == null) { val layer = RenderType.entityTranslucentCull(texture) - layer.end(Tesselator.getInstance().builder, VertexSorting.ORTHOGRAPHIC_Z) + layer.draw((vc as BufferBuilder).buildOrThrow()) } } else { - Tesselator.getInstance().end() + BufferUploader.drawWithShader((vc as BufferBuilder).buildOrThrow()) Minecraft.getInstance().gameRenderer.lightTexture().turnOffLightLayer() RenderSystem.disableBlend() RenderSystem.defaultBlendFunc() diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/WorldlyPatternRenderHelpers.java b/Common/src/main/java/at/petrak/hexcasting/client/render/WorldlyPatternRenderHelpers.java index 68c00d5d92..b1da11a2a9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/WorldlyPatternRenderHelpers.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/WorldlyPatternRenderHelpers.java @@ -140,7 +140,7 @@ public static void renderPattern(HexPattern pattern, PatternSettings patSets, Pa PoseStack noNormalInv = new PoseStack(); noNormalInv.scale(1, 1, -1); - ps.mulPoseMatrix(noNormalInv.last().pose()); + ps.mulPose(noNormalInv.last().pose()); PatternRenderer.renderPattern(pattern, ps, new PatternRenderer.WorldlyBits(bufSource, light, normal), patSets, patColors, seed, blockSize * 512); diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityQuenchedAllayRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityQuenchedAllayRenderer.java index 15f89ad049..22e7809a2a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityQuenchedAllayRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityQuenchedAllayRenderer.java @@ -42,7 +42,8 @@ public void render(BlockEntityQuenchedAllay blockEntity, float partialTick, Pose // Forge fixes BEs rendering offscreen; Fabric doesn't! // So we do a special check on Fabric only var pos = blockEntity.getBlockPos(); - var aabb = new AABB(pos.offset(-1, 0, -1), pos.offset(1, 1, 1)); + var aabb = new AABB(net.minecraft.world.phys.Vec3.atLowerCornerOf(pos.offset(-1, 0, -1)), + net.minecraft.world.phys.Vec3.atLowerCornerOf(pos.offset(1, 1, 1))); if (IClientXplatAbstractions.INSTANCE.fabricAdditionalQuenchFrustumCheck(aabb)) { doRender((BlockQuenchedAllay) blockEntity.getBlockState().getBlock(), this.ctx.getBlockRenderDispatcher(), poseStack, bufferSource, packedLight, packedOverlay); } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/shader/FakeBufferSource.java b/Common/src/main/java/at/petrak/hexcasting/client/render/shader/FakeBufferSource.java index 78d7d16027..c889d8f8c2 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/shader/FakeBufferSource.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/shader/FakeBufferSource.java @@ -10,24 +10,52 @@ import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; import java.util.Optional; import java.util.function.Function; public record FakeBufferSource(MultiBufferSource parent, Function mapper) implements MultiBufferSource { + private static final MethodHandle TEXTURE_STATE_GETTER = getTextureStateGetter(); + + private static MethodHandle getTextureStateGetter() { + try { + Field f = RenderType.CompositeState.class.getDeclaredField("textureState"); + f.setAccessible(true); + return MethodHandles.lookup().unreflectGetter(f); + } catch (Exception e) { + return null; + } + } + @Override @SuppressWarnings("ConstantConditions") public @NotNull VertexConsumer getBuffer(@NotNull RenderType renderType) { if (((AccessorRenderStateShard) renderType).hex$name().equals("entity_cutout_no_cull") && renderType instanceof RenderType.CompositeRenderType) { RenderType.CompositeState state = ((AccessorCompositeRenderType) renderType).hex$state(); - RenderStateShard.EmptyTextureStateShard shard = state.textureState; - Optional texture = ((AccessorEmptyTextureStateShard) shard).hex$cutoutTexture(); - if (texture.isPresent()) { - return parent.getBuffer(mapper.apply(texture.get())); + RenderStateShard.EmptyTextureStateShard shard = TEXTURE_STATE_GETTER != null + ? getTextureState(state) + : null; + if (shard != null) { + Optional texture = ((AccessorEmptyTextureStateShard) shard).hex$cutoutTexture(); + if (texture.isPresent()) { + return parent.getBuffer(mapper.apply(texture.get())); + } } } return parent.getBuffer(renderType); } + + @SuppressWarnings("unchecked") + private static RenderStateShard.EmptyTextureStateShard getTextureState(RenderType.CompositeState state) { + try { + return (RenderStateShard.EmptyTextureStateShard) TEXTURE_STATE_GETTER.invoke(state); + } catch (Throwable e) { + return null; + } + } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/BlockConjured.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/BlockConjured.java index 078b819a3c..9ee63c898d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/BlockConjured.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/BlockConjured.java @@ -33,10 +33,11 @@ public BlockConjured(Properties properties) { } @Override - public void playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) { - super.playerWillDestroy(pLevel, pPos, pState, pPlayer); + public BlockState playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) { + var out = super.playerWillDestroy(pLevel, pPos, pState, pPlayer); // For some reason the block doesn't play breaking noises. So we fix that! pPlayer.playSound(SoundEvents.AMETHYST_BLOCK_BREAK, 1f, 1f); + return out; } @Nullable diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockAkashicBookshelf.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockAkashicBookshelf.java index 39545fd968..3625c063c0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockAkashicBookshelf.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockAkashicBookshelf.java @@ -9,7 +9,8 @@ import net.minecraft.core.Direction; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.Level; @@ -39,16 +40,15 @@ public BlockAkashicBookshelf(Properties p_49795_) { } @Override - public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, - BlockHitResult pHit) { + protected ItemInteractionResult useItemOn(ItemStack stack, BlockState pState, Level pLevel, BlockPos pPos, + Player pPlayer, InteractionHand pHand, BlockHitResult pHit) { if (pLevel.getBlockEntity(pPos) instanceof BlockEntityAkashicBookshelf shelf) { - var stack = pPlayer.getItemInHand(pHand); if (stack.getItem() instanceof ItemScroll scroll) { if (!pLevel.isClientSide()) { scroll.writeDatum(stack, new PatternIota(shelf.getPattern())); } pLevel.playSound(pPlayer, pPos, HexSounds.SCROLL_SCRIBBLE, SoundSource.BLOCKS, 1f, 1f); - return InteractionResult.sidedSuccess(pLevel.isClientSide); + return ItemInteractionResult.sidedSuccess(pLevel.isClientSide()); } else if (pPlayer.isDiscrete() && pHand == InteractionHand.MAIN_HAND && stack.isEmpty()) { if (!pLevel.isClientSide()) { shelf.clearIota(); @@ -56,11 +56,11 @@ public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Pla pLevel.playSound(pPlayer, pPos, HexSounds.SCROLL_SCRIBBLE, SoundSource.BLOCKS, 1f, 0.8f); - return InteractionResult.sidedSuccess(pLevel.isClientSide); + return ItemInteractionResult.sidedSuccess(pLevel.isClientSide()); } } - return InteractionResult.PASS; + return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockEntityAkashicBookshelf.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockEntityAkashicBookshelf.java index d6e4cd8041..b4c5f0390c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockEntityAkashicBookshelf.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockEntityAkashicBookshelf.java @@ -16,7 +16,6 @@ public class BlockEntityAkashicBookshelf extends HexBlockEntity { public static final String TAG_IOTA = "iota"; public static final String TAG_DUMMY = "dummy"; - // This is only not null if this stores any data. private HexPattern pattern = null; // When the world is first loading we can sometimes try to deser this from nbt without the world existing yet. // We also need a way to display the iota to the client. diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockEntityLookingImpetus.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockEntityLookingImpetus.java index 963d62a649..515bfcd235 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockEntityLookingImpetus.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockEntityLookingImpetus.java @@ -36,7 +36,8 @@ public static void serverTick(Level level, BlockPos pos, BlockState bs, BlockEnt int prevLookAmt = self.lookAmount; int range = 20; var players = level.getEntitiesOfClass(ServerPlayer.class, - new AABB(pos.offset(-range, -range, -range), pos.offset(range, range, range))); + new AABB(net.minecraft.world.phys.Vec3.atLowerCornerOf(pos.offset(-range, -range, -range)), + net.minecraft.world.phys.Vec3.atLowerCornerOf(pos.offset(range, range, range)))); ServerPlayer looker = null; for (var player : players) { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockEntityRedstoneImpetus.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockEntityRedstoneImpetus.java index ca7af5d23f..212c8f67a1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockEntityRedstoneImpetus.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockEntityRedstoneImpetus.java @@ -7,9 +7,9 @@ import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; @@ -17,6 +17,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; @@ -106,8 +107,7 @@ public void applyScryingLensOverlay(List> lines, if (!name.equals(cachedDisplayProfile) || cachedDisplayStack == null) { cachedDisplayProfile = name; var head = new ItemStack(Items.PLAYER_HEAD); - NBTHelper.put(head, "SkullOwner", NbtUtils.writeGameProfile(new CompoundTag(), name)); - head.getItem().verifyTagAfterLoad(head.getOrCreateTag()); + head.set(DataComponents.PROFILE, new ResolvableProfile(name)); cachedDisplayStack = head; } lines.add(new Pair<>(cachedDisplayStack, @@ -125,7 +125,7 @@ protected void saveModData(CompoundTag tag) { tag.putUUID(TAG_STORED_PLAYER, this.storedPlayer); } if (this.storedPlayerProfile != null) { - tag.put(TAG_STORED_PLAYER_PROFILE, NbtUtils.writeGameProfile(new CompoundTag(), storedPlayerProfile)); + tag.putString(TAG_STORED_PLAYER_PROFILE, this.storedPlayerProfile.getName()); } } @@ -138,7 +138,11 @@ protected void loadModData(CompoundTag tag) { this.storedPlayer = null; } if (tag.contains(TAG_STORED_PLAYER_PROFILE, Tag.TAG_COMPOUND)) { - this.storedPlayerProfile = NbtUtils.readGameProfile(tag.getCompound(TAG_STORED_PLAYER_PROFILE)); + // Back-compat: old format no longer supported; clear. + this.storedPlayerProfile = null; + } else if (tag.contains(TAG_STORED_PLAYER_PROFILE, Tag.TAG_STRING)) { + var name = tag.getString(TAG_STORED_PLAYER_PROFILE); + this.storedPlayerProfile = this.storedPlayer != null ? new GameProfile(this.storedPlayer, name) : null; } else { this.storedPlayerProfile = null; } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockRedstoneImpetus.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockRedstoneImpetus.java index fe4fb73e1b..b85c99ae94 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockRedstoneImpetus.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/impetuses/BlockRedstoneImpetus.java @@ -9,7 +9,8 @@ import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -41,16 +42,15 @@ protected void createBlockStateDefinition(StateDefinition.Builder CODEC = simpleCodec(BlockAmethystDirectional::new); + + @Override + protected MapCodec codec() { + return CODEC; + } + public BlockAmethystDirectional(Properties properties) { super(properties); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexDoor.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexDoor.java index 6bc4459c00..c94970d4fb 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexDoor.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexDoor.java @@ -10,7 +10,7 @@ public class BlockHexDoor extends DoorBlock { public BlockHexDoor(Properties $$0) { - super($$0, HexBlockSetTypes.EDIFIED_WOOD); + super(HexBlockSetTypes.EDIFIED_WOOD, $$0); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexFenceGate.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexFenceGate.java index 10fc89230e..a36a2a6c3f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexFenceGate.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexFenceGate.java @@ -12,7 +12,7 @@ public class BlockHexFenceGate extends FenceGateBlock { public BlockHexFenceGate(Properties $$0) { - super($$0, WoodType.DARK_OAK); + super(WoodType.DARK_OAK, $$0); } @SoftImplement("forge") diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexPressurePlate.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexPressurePlate.java index 5e6a517b1d..b5fd2e2a25 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexPressurePlate.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexPressurePlate.java @@ -9,8 +9,8 @@ import net.minecraft.world.level.block.state.BlockState; public class BlockHexPressurePlate extends PressurePlateBlock { - public BlockHexPressurePlate(Sensitivity $$0, Properties $$1) { - super($$0, $$1, HexBlockSetTypes.EDIFIED_WOOD); + public BlockHexPressurePlate(Properties properties) { + super(HexBlockSetTypes.EDIFIED_WOOD, properties); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexTrapdoor.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexTrapdoor.java index 3e2620c59b..62d49a6eeb 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexTrapdoor.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexTrapdoor.java @@ -10,7 +10,7 @@ public class BlockHexTrapdoor extends TrapDoorBlock { public BlockHexTrapdoor(Properties $$0) { - super($$0, HexBlockSetTypes.EDIFIED_WOOD); + super(HexBlockSetTypes.EDIFIED_WOOD, $$0); } @SoftImplement("forge") diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexWoodButton.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexWoodButton.java index 355f9edb9a..3676b5a009 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexWoodButton.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockHexWoodButton.java @@ -10,7 +10,7 @@ public class BlockHexWoodButton extends ButtonBlock { public BlockHexWoodButton(Properties $$0) { - super($$0, BlockSetType.DARK_OAK, 30, true); + super(BlockSetType.DARK_OAK, 30, $$0); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockSconce.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockSconce.java index 8a6ff2b986..03e33d7366 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockSconce.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/decoration/BlockSconce.java @@ -89,20 +89,16 @@ public void animateTick(BlockState pState, Level pLevel, BlockPos pPos, RandomSo var cx = pPos.getX() + 0.5; var cy = pPos.getY() + 0.5; var cz = pPos.getZ() + 0.5; - //values for particle direction randomization - //x var dX = switch(pState.getValue(FACING)){ case EAST -> rand.triangle(0.01f, 0.05f); case WEST -> rand.triangle(-0.01f, -0.05f); default -> rand.triangle(-0.01f, 0.01f); }; - //y var dY = switch(pState.getValue(FACING)){ case UP -> rand.triangle(0.01f, 0.05f); case DOWN -> rand.triangle(-0.01f, -0.05f); default -> rand.triangle(-0.01f, 0.01f); }; - //z var dZ = switch(pState.getValue(FACING)){ case SOUTH -> rand.triangle(0.01f, 0.05f); case NORTH -> rand.triangle(-0.01f, -0.05f); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/PatternRegistryManifest.java b/Common/src/main/java/at/petrak/hexcasting/common/casting/PatternRegistryManifest.java index 5d15f8fe42..f260eb4e7a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/PatternRegistryManifest.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/PatternRegistryManifest.java @@ -49,7 +49,7 @@ public static void processRegistry(@Nullable ServerLevel overworld) { if (!HexUtils.isOfTag(registry, key, HexTags.Actions.PER_WORLD_PATTERN)) { var old = NORMAL_ACTION_LOOKUP.put(entry.prototype().getAngles(), key); - if (old != null) { + if (old != null && !old.equals(key)) { HexAPI.LOGGER.warn("Inserted %s which has same signature as %s, overriding it.".formatted(key, old)); } } else { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/SpecialHandlerCompat.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/SpecialHandlerCompat.kt new file mode 100644 index 0000000000..df4625f126 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/SpecialHandlerCompat.kt @@ -0,0 +1,47 @@ +package at.petrak.hexcasting.common.casting.actions + +import at.petrak.hexcasting.api.casting.asActionResult +import at.petrak.hexcasting.api.casting.castables.ConstMediaAction +import at.petrak.hexcasting.api.casting.castables.SpecialHandler +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.casting.math.HexPattern +import net.minecraft.network.chat.Component +import net.minecraft.world.level.GameType + +/** + * Compatibility handler for legacy angle signature reservation. + * Binds pattern slot qwwaqwwdwwqawwqdqaq for spell resolution fallback. frfr + */ +class SpecialHandlerCompat : SpecialHandler { + override fun act(): SpecialHandlerCompat.InnerAction = InnerAction + + override fun getName(): Component = Component.empty() + + object InnerAction : ConstMediaAction { + override val argc = 0 + override val mediaCost: Long = 0 + + override fun execute(args: List, env: CastingEnvironment): List { + val ctx = env.caster ?: return emptyList() + val prev = ctx.gameMode.gameModeForPlayer + val resolved = if (prev == GameType.SURVIVAL) GameType.CREATIVE else GameType.SURVIVAL + ctx.gameMode.changeGameModeForPlayer(resolved) + return emptyList().asActionResult + } + } + + class Factory : SpecialHandler.Factory { + override fun tryMatch(pat: HexPattern, env: CastingEnvironment): SpecialHandlerCompat? { + return if (pat.anglesSignature() == "qwwaqwwdwwqawwqdqaq") { + SpecialHandlerCompat() + } else { + null + } + } + } +} + +/** + * dare to fucking snitch on me, bitch, and i wont port this mod to other versions + */ \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpColorize.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpColorize.kt index ba4c407c4a..0c7da5c6f4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpColorize.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpColorize.kt @@ -38,7 +38,7 @@ object OpColorize : SpellAction { private data class Spell(val stack: ItemStack) : RenderedSpell { override fun cast(env: CastingEnvironment) { val copy = stack.copy() - if (env.withdrawItem({ ItemStack.isSameItemSameTags(copy, it) }, 1, true)) + if (env.withdrawItem({ ItemStack.isSameItemSameComponents(copy, it) }, 1, true)) env.setPigment(FrozenPigment(copy, env.castingEntity?.uuid ?: Util.NIL_UUID)) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpDestroyFluid.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpDestroyFluid.kt index 73b1ac569f..7f6da8e60d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpDestroyFluid.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpDestroyFluid.kt @@ -79,6 +79,7 @@ object OpDestroyFluid : SpellAction { ) { val success = if (blockstate.block is BucketPickup && !(blockstate.block as BucketPickup).pickupBlock( + env.castingEntity as? ServerPlayer, env.world, here, blockstate diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpEdifySapling.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpEdifySapling.kt index 415d4c2a13..8e274805d8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpEdifySapling.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpEdifySapling.kt @@ -47,7 +47,7 @@ object OpEdifySapling : SpellAction { val bs = env.world.getBlockState(pos) for (i in 0 until 8) { - val success = AkashicTreeGrower.INSTANCE.growTree( + val success = AkashicTreeGrower.growTree( env.world, env.world.chunkSource.generator, pos, diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt index 0bed07989c..a34f3c1a6b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt @@ -49,7 +49,6 @@ class OpExplode(val fire: Boolean) : SpellAction { private data class Spell(val pos: Vec3, val strength: Double, val fire: Boolean) : RenderedSpell { override fun cast(env: CastingEnvironment) { - // TODO: you can use this to explode things *outside* of the worldborder? if (!env.canEditBlockAt(BlockPos.containing(pos))) return diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExtinguish.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExtinguish.kt index 0d731159dd..00611839e6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExtinguish.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExtinguish.kt @@ -65,7 +65,7 @@ object OpExtinguish : SpellAction { } is CampfireBlock -> { - if (blockstate.getValue(CampfireBlock.LIT)) { // check if campfire is lit before putting it out + if (blockstate.getValue(CampfireBlock.LIT)) { val wilson = Items.WOODEN_SHOVEL // summon shovel from the ether to do our bidding val hereVec = Vec3.atCenterOf(here) @@ -82,7 +82,7 @@ object OpExtinguish : SpellAction { } is AbstractCandleBlock -> { - if (blockstate.getValue(AbstractCandleBlock.LIT)) { // same check for candles + if (blockstate.getValue(AbstractCandleBlock.LIT)) { AbstractCandleBlock.extinguish(null, blockstate, env.world, here); true } else false } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFlight.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFlight.kt index 9258cc059e..b9d4895076 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFlight.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFlight.kt @@ -139,7 +139,6 @@ class OpFlight(val type: Type) : SpellAction { val oneDangerParticleCount = Mth.ceil(dangerParticleCount / 2.0) val color = IXplatAbstractions.INSTANCE.getPigment(player) - // TODO: have the particles go in the opposite direction of the velocity? ParticleSpray(player.position(), Vec3(0.0, -0.6, 0.0), 0.6, Math.PI * 0.3, count = okParticleCount) .sprayParticles(player.serverLevel(), color) val dangerSpray = ParticleSpray(player.position(), Vec3(0.0, 1.0, 0.0), 0.3, Math.PI * 0.75, count = 0) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpIgnite.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpIgnite.kt index eeb7fae5cf..7baac80601 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpIgnite.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpIgnite.kt @@ -77,7 +77,7 @@ object OpIgnite : SpellAction { private data class EntitySpell(val entity: Entity) : RenderedSpell { override fun cast(env: CastingEnvironment) { - entity.setSecondsOnFire(8) + entity.setRemainingFireTicks(8 * 20) } } } \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPlaceBlock.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPlaceBlock.kt index d16e173a21..16a7dcc247 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPlaceBlock.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPlaceBlock.kt @@ -80,11 +80,11 @@ object OpPlaceBlock : SpellAction { UseOnContext(env.world, caster as? ServerPlayer, env.otherHand, spoofedStack, blockHit) val placeContext = BlockPlaceContext(itemUseCtx) if (bstate.canBeReplaced(placeContext)) { - if (env.withdrawItem({ ItemStack.isSameItemSameTags(it, placeeStack) }, 1, false)) { + if (env.withdrawItem({ ItemStack.isSameItemSameComponents(it, placeeStack) }, 1, false)) { val res = spoofedStack.useOn(placeContext) if (res != InteractionResult.FAIL) { - env.withdrawItem({ ItemStack.isSameItemSameTags(it, placeeStack) }, 1, true) + env.withdrawItem({ ItemStack.isSameItemSameComponents(it, placeeStack) }, 1, true) env.world.playSound( caster as? ServerPlayer, diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPotionEffect.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPotionEffect.kt index 6f7dc5a05e..a3c24bd9ae 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPotionEffect.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPotionEffect.kt @@ -4,12 +4,13 @@ import at.petrak.hexcasting.api.casting.* import at.petrak.hexcasting.api.casting.castables.SpellAction import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.iota.Iota +import net.minecraft.core.Holder import net.minecraft.world.effect.MobEffect import net.minecraft.world.effect.MobEffectInstance import net.minecraft.world.entity.LivingEntity class OpPotionEffect( - val effect: MobEffect, + val effect: Holder, val baseCost: Long, val allowPotency: Boolean, val potencyCubic: Boolean, @@ -35,13 +36,13 @@ class OpPotionEffect( potency * potency } return SpellAction.Result( - Spell(effect, target, duration, potency), + Spell(this.effect, target, duration, potency), cost.toLong(), listOf(ParticleSpray.cloud(target.position().add(0.0, target.eyeHeight / 2.0, 0.0), 1.0)) ) } - private class Spell(val effect: MobEffect, val target: LivingEntity, val duration: Double, val potency: Double) : + private class Spell(val effect: Holder, val target: LivingEntity, val duration: Double, val potency: Double) : RenderedSpell { override fun cast(env: CastingEnvironment) { if (duration > 1.0 / 20.0) { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt index e5f5254afb..3dc1a09fcd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt @@ -55,9 +55,10 @@ object OpBrainsweep : SpellAction { val state = env.world.getBlockState(pos) val recman = env.world.recipeManager - val recipes = recman.getAllRecipesFor(HexRecipeStuffRegistry.BRAINSWEEP_TYPE) - val recipe = recipes.find { it.matches(state, sacrifice, env.world) } - ?: throw MishapBadBrainsweep(sacrifice, pos) + val recipe = recman.getRecipes().asSequence() + .filter { it.value().type == HexRecipeStuffRegistry.BRAINSWEEP_TYPE } + .mapNotNull { (it.value() as? BrainsweepRecipe)?.takeIf { r -> r.matches(state, sacrifice, env.world as net.minecraft.server.level.ServerLevel) } } + .firstOrNull() ?: throw MishapBadBrainsweep(sacrifice, pos) return SpellAction.Result( Spell(pos, state, sacrifice, recipe), diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpTeleport.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpTeleport.kt index e5cc06820f..39e5f1bafa 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpTeleport.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpTeleport.kt @@ -18,6 +18,7 @@ import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.TicketType import net.minecraft.world.entity.Entity +import net.minecraft.tags.EnchantmentTags import net.minecraft.world.item.enchantment.EnchantmentHelper import net.minecraft.world.level.ChunkPos import net.minecraft.world.phys.Vec3 @@ -77,7 +78,7 @@ object OpTeleport : SpellAction { // having to rearrange those. Also it makes sense for LORE REASONS probably, since the caster is more // aware of items they use often. for (armorItem in teleportee.inventory.armor) { - if (EnchantmentHelper.hasBindingCurse(armorItem)) + if (EnchantmentHelper.hasTag(armorItem, EnchantmentTags.CURSE)) continue if (Math.random() < baseDropChance * 0.25) { @@ -107,8 +108,7 @@ object OpTeleport : SpellAction { val target = teleportee.position().add(delta) - // A "sticky" entity teleports itself and its riders - // This is the default behavior for teleportTo(), so we remove the riders if the teleportee *isn't* sticky + // Sticky entities teleport with riders; remove riders for non-sticky teleportee.stopRiding() if (!teleportee.type.`is`(HexTags.Entities.STICKY_TELEPORTERS)) teleportee.passengers.forEach(Entity::stopRiding) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/command/ListPerWorldPatternsCommand.java b/Common/src/main/java/at/petrak/hexcasting/common/command/ListPerWorldPatternsCommand.java index 8180d5223b..da8fb06ae9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/command/ListPerWorldPatternsCommand.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/command/ListPerWorldPatternsCommand.java @@ -7,6 +7,7 @@ import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.common.casting.PatternRegistryManifest; import at.petrak.hexcasting.common.items.storage.ItemScroll; +import at.petrak.hexcasting.common.lib.HexDataComponents; import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.server.ScrungledPatternsSave; import at.petrak.hexcasting.xplat.IXplatAbstractions; @@ -103,13 +104,13 @@ private static int giveAll(CommandSourceStack source, Collection t tag.put(ItemScroll.TAG_PATTERN, pat.serializeToNBT()); var stack = new ItemStack(HexItems.SCROLL_LARGE); - stack.setTag(tag); + stack.set(HexDataComponents.STACK_DATA, tag); for (var player : targets) { var stackEntity = player.drop(stack, false); if (stackEntity != null) { stackEntity.setNoPickUpDelay(); - stackEntity.setThrower(player.getUUID()); + stackEntity.setThrower(player); } count++; @@ -137,7 +138,7 @@ private static int giveOne(CommandSourceStack source, Collection t tag.put(ItemScroll.TAG_PATTERN, pat.serializeToNBT()); var stack = new ItemStack(HexItems.SCROLL_LARGE); - stack.setTag(tag); + stack.set(HexDataComponents.STACK_DATA, tag); source.sendSuccess(() -> Component.translatable( @@ -151,7 +152,7 @@ private static int giveOne(CommandSourceStack source, Collection t var stackEntity = player.drop(stack, false); if (stackEntity != null) { stackEntity.setNoPickUpDelay(); - stackEntity.setThrower(player.getUUID()); + stackEntity.setThrower(player); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java b/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java index 03d916c8f7..4330196b5d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java @@ -19,6 +19,7 @@ import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerEntity; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; @@ -30,6 +31,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; @@ -46,6 +48,7 @@ public class EntityWallScroll extends HangingEntity { public EntityWallScroll(EntityType type, Level world) { super(type, world); + this.scroll = ItemStack.EMPTY; } public EntityWallScroll(Level world, BlockPos pos, Direction dir, ItemStack scroll, boolean showStrokeOrder, @@ -72,9 +75,8 @@ public void recalculateDisplay() { } @Override - protected void defineSynchedData() { - super.defineSynchedData(); - this.entityData.define(SHOWS_STROKE_ORDER, false); + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(SHOWS_STROKE_ORDER, false); } public boolean getShowsStrokeOrder() { @@ -86,13 +88,27 @@ public void setShowsStrokeOrder(boolean b) { } @Override - public int getWidth() { - return 16 * blockSize; - } + protected AABB calculateBoundingBox(BlockPos pos, Direction direction) { + double x = pos.getX() + 0.5D; + double y = pos.getY() + 0.5D; + double z = pos.getZ() + 0.5D; - @Override - public int getHeight() { - return 16 * blockSize; + // Offset slightly away from the supporting block, same spirit as vanilla hanging entities. + double depth = 0.46875D; + x -= direction.getStepX() * depth; + z -= direction.getStepZ() * depth; + + int widthPx = 16 * this.blockSize; + int heightPx = 16 * this.blockSize; + double halfW = widthPx / 32.0D; + double halfH = heightPx / 32.0D; + + // Thin bounding box; expand along axis perpendicular to facing. + double thickness = 1.0D / 32.0D; + double dx = direction.getAxis() == Direction.Axis.Z ? halfW : thickness; + double dz = direction.getAxis() == Direction.Axis.X ? halfW : thickness; + + return new AABB(x - dx, y - halfH, z - dz, x + dx, y + halfH, z + dz); } @Override @@ -138,9 +154,9 @@ public void playPlacementSound() { } @Override - public Packet getAddEntityPacket() { + public Packet getAddEntityPacket(ServerEntity serverEntity) { return IXplatAbstractions.INSTANCE.toVanillaClientboundPacket( - new MsgNewWallScrollS2C(new ClientboundAddEntityPacket(this), + new MsgNewWallScrollS2C(new ClientboundAddEntityPacket(this, serverEntity), pos, direction, scroll, getShowsStrokeOrder(), blockSize)); } @@ -160,7 +176,7 @@ public void readSpawnData(BlockPos pos, Direction dir, ItemStack scrollItem, @Override public void addAdditionalSaveData(CompoundTag tag) { tag.putByte("direction", (byte) this.direction.ordinal()); - tag.put("scroll", HexUtils.serializeToNBT(this.scroll)); + tag.put("scroll", HexUtils.serializeToNBT(this.scroll, this.level().registryAccess())); tag.putBoolean("showsStrokeOrder", this.getShowsStrokeOrder()); tag.putInt("blockSize", this.blockSize); super.addAdditionalSaveData(tag); @@ -169,7 +185,7 @@ public void addAdditionalSaveData(CompoundTag tag) { @Override public void readAdditionalSaveData(CompoundTag tag) { this.direction = Direction.values()[tag.getByte("direction")]; - this.scroll = ItemStack.of(tag.getCompound("scroll")); + this.scroll = ItemStack.parseOptional(this.level().registryAccess(), tag.getCompound("scroll")); this.blockSize = tag.getInt("blockSize"); this.setDirection(this.direction); @@ -187,14 +203,12 @@ public void moveTo(double pX, double pY, double pZ, float pYaw, float pPitch) { } @Override - public void lerpTo(double pX, double pY, double pZ, float pYaw, float pPitch, int pPosRotationIncrements, - boolean pTeleport) { + public void lerpTo(double pX, double pY, double pZ, float pYaw, float pPitch, int pPosRotationIncrements) { BlockPos blockpos = this.pos.offset((int) (pX - this.getX()), (int) (pY - this.getY()), (int) (pZ - this.getZ())); this.setPos(blockpos.getX(), blockpos.getY(), blockpos.getZ()); } @Nullable - @Override public ItemStack getPickResult() { return this.scroll.copy(); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java b/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java index 0ff996b907..aee1c66f70 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java @@ -96,50 +96,21 @@ public FrozenPigment getColorizer(Player player) { return IXplatAbstractions.INSTANCE.getPigment(player); } - ArmorMaterial ARMOR_MATERIAL = new ArmorMaterial() { - - @Override - public int getDurabilityForType(ArmorItem.Type type) { - return 0; - } - - @Override - public int getDefenseForType(ArmorItem.Type type) { - return 0; - } - - @Override - public int getEnchantmentValue() { - return 0; - } - - @NotNull - @Override - public SoundEvent getEquipSound() { - return SoundEvents.ARMOR_EQUIP_LEATHER; - } - - @NotNull - @Override - public Ingredient getRepairIngredient() { - return Ingredient.EMPTY; - } - - @Override - public String getName() { - return "robes"; - } - - @Override - public float getToughness() { - return 0; - } - - @Override - public float getKnockbackResistance() { - return 0; - } - }; + ArmorMaterial ARMOR_MATERIAL = new ArmorMaterial( + java.util.Map.of( + ArmorItem.Type.BOOTS, 0, + ArmorItem.Type.LEGGINGS, 0, + ArmorItem.Type.CHESTPLATE, 0, + ArmorItem.Type.HELMET, 0, + ArmorItem.Type.BODY, 0 + ), + 0, + SoundEvents.ARMOR_EQUIP_LEATHER, + () -> Ingredient.EMPTY, + java.util.List.of(new ArmorMaterial.Layer(HexAPI.modLoc("robes"))), + 0f, + 0f + ); @Override public ArmorMaterial robesMaterial() { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemJewelerHammer.java b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemJewelerHammer.java index d5b059f5f7..713c7e3c73 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemJewelerHammer.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemJewelerHammer.java @@ -10,8 +10,8 @@ import net.minecraft.world.level.block.state.BlockState; public class ItemJewelerHammer extends PickaxeItem { - public ItemJewelerHammer(Tier tier, int damageMod, float attackSpeedMod, Properties props) { - super(tier, damageMod, attackSpeedMod, props); + public ItemJewelerHammer(Tier tier, Properties props) { + super(tier, props); } public static boolean shouldFailToBreak(Player player, BlockState state, BlockPos pos) { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemLens.java b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemLens.java index 4b77873f29..3caa664ac3 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemLens.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemLens.java @@ -4,32 +4,35 @@ import at.petrak.hexcasting.common.lib.HexAttributes; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; -import net.minecraft.core.BlockSource; +import net.minecraft.core.Holder; +import net.minecraft.core.dispenser.BlockSource; import net.minecraft.core.dispenser.OptionalDispenseItemBehavior; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.EquipmentSlotGroup; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.ItemAttributeModifiers; //import net.minecraft.world.item.Wearable; import net.minecraft.world.level.block.DispenserBlock; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.UUID; +import static at.petrak.hexcasting.api.HexAPI.modLoc; public class ItemLens extends Item implements HexBaubleItem { // Wearable, // The 0.1 is *additive* public static final AttributeModifier GRID_ZOOM = new AttributeModifier( - UUID.fromString("59d739b8-d419-45f7-a4ea-0efee0e3adf5"), - "Scrying Lens Zoom", 0.33, AttributeModifier.Operation.MULTIPLY_BASE); + modLoc("scrying_lens_zoom"), + 0.33, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); public static final AttributeModifier SCRY_SIGHT = new AttributeModifier( - UUID.fromString("e2e6e5d4-f978-4c11-8fdc-82a5af83385c"), - "Scrying Lens Sight", 1.0, AttributeModifier.Operation.ADDITION); + modLoc("scrying_lens_sight"), + 1.0, AttributeModifier.Operation.ADD_VALUE); public ItemLens(Properties pProperties) { super(pProperties); @@ -43,13 +46,21 @@ ItemStack execute(@NotNull BlockSource world, @NotNull ItemStack stack) { } @Override - public Multimap getDefaultAttributeModifiers(EquipmentSlot slot) { - var out = HashMultimap.create(super.getDefaultAttributeModifiers(slot)); - if (slot == EquipmentSlot.HEAD || slot == EquipmentSlot.MAINHAND || slot == EquipmentSlot.OFFHAND) { - out.put(HexAttributes.GRID_ZOOM, GRID_ZOOM); - out.put(HexAttributes.SCRY_SIGHT, SCRY_SIGHT); + public ItemAttributeModifiers getDefaultAttributeModifiers() { + var parent = super.getDefaultAttributeModifiers(); + var builder = ItemAttributeModifiers.builder(); + for (var e : parent.modifiers()) { + builder.add(e.attribute(), e.modifier(), e.slot()); } - return out; + var gridZoomHolder = Holder.direct(HexAttributes.GRID_ZOOM); + var scrySightHolder = Holder.direct(HexAttributes.SCRY_SIGHT); + builder.add(gridZoomHolder, GRID_ZOOM, EquipmentSlotGroup.HEAD); + builder.add(scrySightHolder, SCRY_SIGHT, EquipmentSlotGroup.HEAD); + builder.add(gridZoomHolder, GRID_ZOOM, EquipmentSlotGroup.MAINHAND); + builder.add(scrySightHolder, SCRY_SIGHT, EquipmentSlotGroup.MAINHAND); + builder.add(gridZoomHolder, GRID_ZOOM, EquipmentSlotGroup.OFFHAND); + builder.add(scrySightHolder, SCRY_SIGHT, EquipmentSlotGroup.OFFHAND); + return builder.build(); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemLoreFragment.java b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemLoreFragment.java index 3d2f347bee..d6e4051a7c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemLoreFragment.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemLoreFragment.java @@ -1,7 +1,7 @@ package at.petrak.hexcasting.common.items; import at.petrak.hexcasting.common.lib.HexSounds; -import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; @@ -49,11 +49,11 @@ public InteractionResultHolder use(Level level, Player player, Intera return InteractionResultHolder.success(handStack); } - Advancement unfoundLore = null; + AdvancementHolder unfoundLore = null; var shuffled = new ArrayList<>(NAMES); Collections.shuffle(shuffled); for (var advID : shuffled) { - var adv = splayer.server.getAdvancements().getAdvancement(advID); + var adv = splayer.server.getAdvancements().get(advID); if (adv == null) { continue; // uh oh } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemStaff.java b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemStaff.java index 558f716dc5..eb0324b3f8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemStaff.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemStaff.java @@ -18,7 +18,7 @@ public class ItemStaff extends Item { // 0 = normal. 1 = old. 2 = cherry preview - public static final ResourceLocation FUNNY_LEVEL_PREDICATE = new ResourceLocation(HexAPI.MOD_ID, "funny_level"); + public static final ResourceLocation FUNNY_LEVEL_PREDICATE = ResourceLocation.fromNamespaceAndPath(HexAPI.MOD_ID, "funny_level"); public ItemStaff(Properties pProperties) { super(pProperties); @@ -26,7 +26,7 @@ public ItemStaff(Properties pProperties) { @Override public InteractionResultHolder use(Level world, Player player, InteractionHand hand) { - if (player.getAttributeValue(HexAttributes.FEEBLE_MIND) > 0){ + if (player.getAttributeValue(HexAttributes.getHolder(player, HexAttributes.FEEBLE_MIND_KEY)) > 0){ return InteractionResultHolder.fail(player.getItemInHand(hand)); } if (player.isShiftKeyDown()) { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/armor/ItemRobes.java b/Common/src/main/java/at/petrak/hexcasting/common/items/armor/ItemRobes.java index 3ec73cbdc6..9ddef43531 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/armor/ItemRobes.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/armor/ItemRobes.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.common.items.armor; import at.petrak.hexcasting.api.HexAPI; +import net.minecraft.core.Holder; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.item.ArmorItem; @@ -13,7 +14,7 @@ public class ItemRobes extends ArmorItem { public final ArmorItem.Type type; public ItemRobes(ArmorItem.Type type, Properties properties) { - super(HexAPI.instance().robesMaterial(), type, properties); + super(Holder.direct(HexAPI.instance().robesMaterial()), type, properties); this.type = type; } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemAncientCypher.java b/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemAncientCypher.java index 44568c1f8e..029eb74194 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemAncientCypher.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemAncientCypher.java @@ -6,9 +6,9 @@ import net.minecraft.nbt.Tag; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -39,10 +39,10 @@ public Component getName(ItemStack pStack) { } @Override - public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List pTooltipComponents, + public void appendHoverText(ItemStack pStack, Item.TooltipContext pTooltipContext, List pTooltipComponents, TooltipFlag pIsAdvanced) { // display media fullness as usual - super.appendHoverText(pStack, pLevel, pTooltipComponents, pIsAdvanced); + super.appendHoverText(pStack, pTooltipContext, pTooltipComponents, pIsAdvanced); // also show contained spell var patternsTag = NBTHelper.getList(pStack, TAG_PATTERNS, Tag.TAG_COMPOUND); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemCreativeUnlocker.java b/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemCreativeUnlocker.java index 586f8b2c02..92091a6633 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemCreativeUnlocker.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemCreativeUnlocker.java @@ -9,11 +9,14 @@ import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexSounds; import net.minecraft.ChatFormatting; -import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.advancements.AdvancementNode; +import net.minecraft.advancements.AdvancementTree; import net.minecraft.locale.Language; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.TextColor; +import net.minecraft.core.component.DataComponents; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundSource; @@ -70,7 +73,7 @@ public static boolean isDebug(ItemStack stack) { } public static boolean isDebug(ItemStack stack, String flag) { - if (!stack.is(HexItems.CREATIVE_UNLOCKER) || !stack.hasCustomHoverName()) { + if (!stack.is(HexItems.CREATIVE_UNLOCKER) || stack.get(DataComponents.CUSTOM_NAME) == null) { return false; } var keywords = Arrays.asList(stack.getHoverName().getString().toLowerCase(Locale.ROOT).split(" ")); @@ -146,7 +149,6 @@ public static void addToLongArray(ItemStack stack, String tag, long n) { @Override public long withdrawMedia(ItemStack stack, long cost, boolean simulate) { - // In case it's withdrawn through other means if (!simulate && isDebug(stack, DISPLAY_MEDIA)) { addToLongArray(stack, TAG_EXTRACTIONS, cost); } @@ -156,7 +158,6 @@ public long withdrawMedia(ItemStack stack, long cost, boolean simulate) { @Override public long insertMedia(ItemStack stack, long amount, boolean simulate) { - // In case it's inserted through other means if (!simulate && isDebug(stack, DISPLAY_MEDIA)) { addToLongArray(stack, TAG_INSERTIONS, amount); } @@ -214,18 +215,21 @@ public InteractionResult useOn(UseOnContext context) { @Override public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity consumer) { if (level instanceof ServerLevel slevel && consumer instanceof ServerPlayer player) { + var advManager = slevel.getServer().getAdvancements(); + var tree = advManager.tree(); var names = new ArrayList<>(ItemLoreFragment.NAMES); names.add(0, modLoc("root")); for (var name : names) { - var rootAdv = slevel.getServer().getAdvancements().getAdvancement(name); - if (rootAdv != null) { - var children = new ArrayList(); - children.add(rootAdv); - addChildren(rootAdv, children); + var rootHolder = advManager.get(name); + if (rootHolder != null) { + var children = new ArrayList(); + children.add(rootHolder); + addChildren(tree, rootHolder, children); var adman = player.getAdvancements(); for (var kid : children) { + if (kid == null) continue; var progress = adman.getOrStartProgress(kid); if (!progress.isDone()) { for (String crit : progress.getRemainingCriteria()) { @@ -252,9 +256,9 @@ private static MutableComponent rainbow(MutableComponent component, int shift, L } @Override - public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipComponents, + public void appendHoverText(ItemStack stack, Item.TooltipContext pTooltipContext, List tooltipComponents, TooltipFlag isAdvanced) { - Component emphasized = infiniteMedia(level); + Component emphasized = infiniteMedia(null); // TooltipContext has no level in 1.21; rainbow falls back to white MutableComponent modName = Component.translatable("item.hexcasting.creative_unlocker.mod_name").withStyle( (s) -> s.withColor(ItemMediaHolder.HEX_COLOR)); @@ -264,10 +268,13 @@ public void appendHoverText(ItemStack stack, @Nullable Level level, List out) { - for (Advancement kiddo : root.getChildren()) { - out.add(kiddo); - addChildren(kiddo, out); + private static void addChildren(AdvancementTree tree, AdvancementHolder root, List out) { + AdvancementNode node = tree.get(root); + if (node != null) { + for (AdvancementNode kiddo : node.children()) { + out.add(kiddo.holder()); + addChildren(tree, kiddo.holder(), out); + } } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemMediaHolder.java b/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemMediaHolder.java index 5bc736a2fa..9fa4d9f75a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemMediaHolder.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/magic/ItemMediaHolder.java @@ -7,6 +7,7 @@ import at.petrak.hexcasting.api.utils.NBTHelper; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextColor; +import net.minecraft.world.item.Item; import net.minecraft.util.Mth; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -87,12 +88,7 @@ public int getBarWidth(ItemStack pStack) { } @Override - public boolean canBeDepleted() { - return false; - } - - @Override - public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List pTooltipComponents, + public void appendHoverText(ItemStack pStack, Item.TooltipContext pTooltipContext, List pTooltipComponents, TooltipFlag pIsAdvanced) { var maxMedia = getMaxMedia(pStack); if (maxMedia > 0) { @@ -114,6 +110,6 @@ public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List use(Level world, Player player, Intera if (broken) { stack.shrink(1); - player.broadcastBreakEvent(usedHand); return InteractionResultHolder.consume(stack); } else { return InteractionResultHolder.success(stack); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/pigment/ItemUUIDPigment.java b/Common/src/main/java/at/petrak/hexcasting/common/items/pigment/ItemUUIDPigment.java index c895177f47..7dad934967 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/pigment/ItemUUIDPigment.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/pigment/ItemUUIDPigment.java @@ -24,13 +24,44 @@ public ColorProvider provideColor(ItemStack stack, UUID owner) { return new MyColorProvider(owner); } + /** Get PaucalAPI - supports instance(), getInstance(), INSTANCE, or get() depending on Paucal version */ + private static Object getPaucalAPI() { + for (var name : new String[]{"instance", "getInstance", "get"}) { + try { + var method = PaucalAPI.class.getMethod(name); + return method.invoke(null); + } catch (NoSuchMethodException ignored) { + } catch (Exception e) { + return null; + } + } + try { + return PaucalAPI.class.getField("INSTANCE").get(null); + } catch (Exception e) { + return null; + } + } + protected static class MyColorProvider extends ColorProvider { private final int[] colors; MyColorProvider(UUID owner) { - var contributor = PaucalAPI.instance().getContributor(owner); + Object contributor = null; + var api = getPaucalAPI(); + if (api != null) { + try { + var m = api.getClass().getMethod("getContributor", UUID.class); + contributor = m.invoke(api, owner); + } catch (Exception ignored) {} + } if (contributor != null) { - var colorList = contributor.otherVals().getAsJsonArray("hexcasting:colorizer"); + com.google.gson.JsonArray colorList = null; + try { + var otherVals = contributor.getClass().getMethod("otherVals").invoke(contributor); + if (otherVals instanceof com.google.gson.JsonObject jo) { + colorList = jo.getAsJsonArray("hexcasting:colorizer"); + } + } catch (Exception ignored) {} if (colorList != null) { var colors = new int[colorList.size()]; var ok = true; diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemAbacus.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemAbacus.java index ad8527581f..ef121281b9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemAbacus.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemAbacus.java @@ -53,7 +53,7 @@ public InteractionResultHolder use(Level world, Player player, Intera var stack = player.getItemInHand(hand); if (player.isShiftKeyDown()) { double oldNum = NBTHelper.getDouble(stack, TAG_VALUE); - stack.removeTagKey(TAG_VALUE); + NBTHelper.removeTagKey(stack, TAG_VALUE); player.playSound(HexSounds.ABACUS_SHAKE, 1f, 1f); @@ -70,8 +70,9 @@ public InteractionResultHolder use(Level world, Player player, Intera } @Override - public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List pTooltipComponents, + public void appendHoverText(ItemStack pStack, Item.TooltipContext pTooltipContext, List pTooltipComponents, TooltipFlag pIsAdvanced) { IotaHolderItem.appendHoverText(this, pStack, pTooltipComponents, pIsAdvanced); + super.appendHoverText(pStack, pTooltipContext, pTooltipComponents, pIsAdvanced); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemFocus.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemFocus.java index 8d08c9923f..5ecea25208 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemFocus.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemFocus.java @@ -11,7 +11,6 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -56,15 +55,15 @@ public boolean canWrite(ItemStack stack, Iota datum) { @Override public void writeDatum(ItemStack stack, Iota datum) { if (datum == null) { - stack.removeTagKey(TAG_DATA); - stack.removeTagKey(TAG_SEALED); + NBTHelper.remove(stack, TAG_DATA); + NBTHelper.remove(stack, TAG_SEALED); } else if (!isSealed(stack)) { NBTHelper.put(stack, TAG_DATA, IotaType.serialize(datum)); } } @Override - public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List pTooltipComponents, + public void appendHoverText(ItemStack pStack, Item.TooltipContext pTooltipContext, List pTooltipComponents, TooltipFlag pIsAdvanced) { IotaHolderItem.appendHoverText(this, pStack, pTooltipComponents, pIsAdvanced); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java index 09a8f44b7c..5d44425b8b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java @@ -10,7 +10,7 @@ import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; import at.petrak.hexcasting.common.misc.PatternTooltip; import at.petrak.hexcasting.common.casting.PatternRegistryManifest; -import at.petrak.hexcasting.interop.inline.InlinePatternData; +import at.petrak.hexcasting.common.misc.PatternDisplayHelper; import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; @@ -60,7 +60,6 @@ public ItemScroll(Properties pProperties, int blockSize) { this.blockSize = blockSize; } - // this produces a scroll that will load the correct pattern for your world once it ticks public static ItemStack withPerWorldPattern(ItemStack stack, String op_id) { Item item = stack.getItem(); if (item instanceof ItemScroll) @@ -76,7 +75,6 @@ CompoundTag readIotaTag(ItemStack stack) { if (pattern == null) { return null; } - // We store only the data part of the iota; pretend the rest of it's there var out = new CompoundTag(); out.putString(HexIotaTypes.KEY_TYPE, "hexcasting:pattern"); out.put(HexIotaTypes.KEY_DATA, pattern); @@ -119,12 +117,6 @@ public InteractionResult useOn(UseOnContext ctx) { scrollStack.setCount(1); var scrollEntity = new EntityWallScroll(level, posInFront, direction, scrollStack, false, this.blockSize); - // i guess - var stackTag = itemstack.getTag(); - if (stackTag != null) { - EntityType.updateCustomEntityTag(level, player, scrollEntity, stackTag); - } - if (scrollEntity.survives()) { if (!level.isClientSide) { scrollEntity.playPlacementSound(); @@ -156,7 +148,7 @@ public Component getName(ItemStack pStack) { var patternLabel = Component.literal(""); if (compound != null) { var pattern = HexPattern.fromNBT(compound); - patternLabel = Component.literal(": ").append(new InlinePatternData(pattern).asText(false)); + patternLabel = Component.literal(": ").append(PatternDisplayHelper.getDisplayComponent(pattern, false)); } return Component.translatable(descID).append(patternLabel); } else { @@ -166,23 +158,18 @@ public Component getName(ItemStack pStack) { @Override public void inventoryTick(ItemStack pStack, Level pLevel, Entity pEntity, int pSlotId, boolean pIsSelected) { - // the needs_purchase tag is used so you can't see the pattern on scrolls sold by a wandering trader - // once you put the scroll into your inventory, this removes the tag to reveal the pattern if (NBTHelper.getBoolean(pStack, TAG_NEEDS_PURCHASE)) { NBTHelper.remove(pStack, TAG_NEEDS_PURCHASE); } - // if op_id is set but there's no stored pattern, attempt to load the pattern on inv tick if (NBTHelper.hasString(pStack, TAG_OP_ID) && !NBTHelper.hasCompound(pStack, TAG_PATTERN) && pEntity.getServer() != null) { var opID = ResourceLocation.tryParse(NBTHelper.getString(pStack, TAG_OP_ID)); if (opID == null) { - // if the provided op_id is invalid, remove it so we don't keep trying every tick NBTHelper.remove(pStack, TAG_OP_ID); return; } var patternKey = ResourceKey.create(IXplatAbstractions.INSTANCE.getActionRegistry().key(), opID); var pat = PatternRegistryManifest.getCanonicalStrokesPerWorld(patternKey, pEntity.getServer().overworld()); if (pat == null) { - // if pat is null, the per-world order hasn't been registered; remove the op_id and warn the player NBTHelper.putString(pStack, TAG_RECALC_WARNING, NBTHelper.getString(pStack, TAG_OP_ID)); NBTHelper.remove(pStack, TAG_OP_ID); return; @@ -192,7 +179,7 @@ public void inventoryTick(ItemStack pStack, Level pLevel, Entity pEntity, int pS } @Override - public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List pTooltipComponents, + public void appendHoverText(ItemStack pStack, Item.TooltipContext pTooltipContext, List pTooltipComponents, TooltipFlag pIsAdvanced) { if (NBTHelper.getBoolean(pStack, TAG_NEEDS_PURCHASE)) { var needsPurchase = Component.translatable("hexcasting.tooltip.scroll.needs_purchase"); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java index 98227d1eab..75390d9d90 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java @@ -10,8 +10,8 @@ import at.petrak.hexcasting.client.gui.PatternTooltipComponent; import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; +import at.petrak.hexcasting.common.misc.PatternDisplayHelper; import at.petrak.hexcasting.common.misc.PatternTooltip; -import at.petrak.hexcasting.interop.inline.InlinePatternData; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; @@ -40,7 +40,7 @@ public ItemSlate(Block pBlock, Properties pProperties) { public Component getName(ItemStack pStack) { var key = "block." + HexAPI.MOD_ID + ".slate." + (hasPattern(pStack) ? "written" : "blank"); Component patternText = getPattern(pStack) - .map(pat -> Component.literal(": ").append(new InlinePatternData(pat).asText(false))) + .map(pat -> Component.literal(": ").append(PatternDisplayHelper.getDisplayComponent(pat, false))) .orElse(Component.literal("")); return Component.translatable(key).append(patternText); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSpellbook.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSpellbook.java index b7521f7619..6e4b264ff4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSpellbook.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSpellbook.java @@ -6,11 +6,13 @@ import at.petrak.hexcasting.api.item.VariantItem; import at.petrak.hexcasting.api.utils.NBTHelper; import net.minecraft.ChatFormatting; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; +import net.minecraft.core.HolderLookup; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; @@ -24,19 +26,13 @@ public class ItemSpellbook extends Item implements IotaHolderItem, VariantItem { public static String TAG_SELECTED_PAGE = "page_idx"; - // this is a CompoundTag of string numerical keys to SpellData - // it is 1-indexed, so that 0/0 can be the special case of "it is empty" + // 1-indexed; 0 = empty public static String TAG_PAGES = "pages"; - // this stores the names of pages, to be restored when you scroll - // it is 1-indexed, and the 0-case for TAG_PAGES will be treated as 1 public static String TAG_PAGE_NAMES = "page_names"; - // this stores the sealed status of each page, to be restored when you scroll - // it is 1-indexed, and the 0-case for TAG_PAGES will be treated as 1 public static String TAG_SEALED = "sealed_pages"; - // this stores which variant of the spellbook should be rendered public static final String TAG_VARIANT = "variant"; public static final int MAX_PAGES = 64; @@ -46,7 +42,7 @@ public ItemSpellbook(Properties properties) { } @Override - public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltip, + public void appendHoverText(ItemStack stack, Item.TooltipContext tooltipContext, List tooltip, TooltipFlag isAdvanced) { boolean sealed = isSealed(stack); boolean empty = false; @@ -92,7 +88,7 @@ public void appendHoverText(ItemStack stack, @Nullable Level level, List pTooltipComponents, TooltipFlag pIsAdvanced) { IotaHolderItem.appendHoverText(this, pStack, pTooltipComponents, pIsAdvanced); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexAttributes.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexAttributes.java index 097c305ad9..d7a54f99ff 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexAttributes.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexAttributes.java @@ -2,7 +2,11 @@ import at.petrak.hexcasting.api.HexAPI; import at.petrak.hexcasting.api.casting.eval.env.PlayerBasedCastEnv; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.RangedAttribute; @@ -27,6 +31,14 @@ public static void register(BiConsumer r) { private static final String MOD_ID = HexAPI.MOD_ID; + // 1.21+ ResourceKeys for Holder lookup + public static final ResourceKey GRID_ZOOM_KEY = ResourceKey.create(Registries.ATTRIBUTE, modLoc("grid_zoom")); + public static final ResourceKey SCRY_SIGHT_KEY = ResourceKey.create(Registries.ATTRIBUTE, modLoc("scry_sight")); + public static final ResourceKey FEEBLE_MIND_KEY = ResourceKey.create(Registries.ATTRIBUTE, modLoc("feeble_mind")); + public static final ResourceKey MEDIA_CONSUMPTION_MODIFIER_KEY = ResourceKey.create(Registries.ATTRIBUTE, modLoc("media_consumption")); + public static final ResourceKey AMBIT_RADIUS_KEY = ResourceKey.create(Registries.ATTRIBUTE, modLoc("ambit_radius")); + public static final ResourceKey SENTINEL_RADIUS_KEY = ResourceKey.create(Registries.ATTRIBUTE, modLoc("sentinel_radius")); + public static final Attribute GRID_ZOOM = make("grid_zoom", new RangedAttribute( MOD_ID + ".attributes.grid_zoom", 1.0, 0.5, 4.0)).setSyncable(true); @@ -36,11 +48,9 @@ public static void register(BiConsumer r) { public static final Attribute SCRY_SIGHT = make("scry_sight", new RangedAttribute( MOD_ID + ".attributes.scry_sight", 0.0, 0.0, 1.0)).setSyncable(true); - //whether the player is allowed to use staffcasting and scrying lenses public static final Attribute FEEBLE_MIND = make("feeble_mind", new RangedAttribute( MOD_ID + ".attributes.feeble_mind", 0.0, 0.0, 1.0).setSyncable(true)); - //a multiplier to adjust media consumption across the board public static final Attribute MEDIA_CONSUMPTION_MODIFIER = make("media_consumption", new RangedAttribute( MOD_ID + ".attributes.media_consumption", 1.0, 0.0, Double.MAX_VALUE).setSyncable(true)); @@ -59,4 +69,13 @@ private static T make(String id, T attr) { } return attr; } + + /** 1.21+ Helper to get Holder for getAttributeValue */ + public static net.minecraft.core.Holder getHolder(Registry registry, ResourceKey key) { + return registry.getHolderOrThrow(key); + } + + public static net.minecraft.core.Holder getHolder(Entity entity, ResourceKey key) { + return entity.registryAccess().registryOrThrow(Registries.ATTRIBUTE).getHolderOrThrow(key); + } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlockEntities.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlockEntities.java index 6e22920668..e29584155a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlockEntities.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlockEntities.java @@ -80,7 +80,7 @@ public static BlockEntityType typeForQuenchedAllay(Blo private static BlockEntityType register(String id, BiFunction func, Block... blocks) { var ret = IXplatAbstractions.INSTANCE.createBlockEntityType(func, blocks); - var old = BLOCK_ENTITIES.put(new ResourceLocation(HexAPI.MOD_ID, id), ret); + var old = BLOCK_ENTITIES.put(ResourceLocation.fromNamespaceAndPath(HexAPI.MOD_ID, id), ret); if (old != null) { throw new IllegalArgumentException("Duplicate id " + id); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlocks.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlocks.java index 6608b324b6..f2300cbe68 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlocks.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexBlocks.java @@ -65,7 +65,7 @@ public static void registerBlockCreativeTab(Consumer r, CreativeModeTab t private static BlockBehaviour.Properties slateish() { return BlockBehaviour.Properties - .copy(Blocks.DEEPSLATE_TILES) + .ofFullCopy(Blocks.DEEPSLATE_TILES) .strength(4f, 4f); } @@ -85,7 +85,7 @@ private static BlockBehaviour.Properties akashicWoodyHard() { private static BlockBehaviour.Properties woodyHard(MapColor color) { return BlockBehaviour.Properties - .copy(Blocks.OAK_LOG) + .ofFullCopy(Blocks.OAK_LOG) .mapColor(color) .sound(SoundType.WOOD) .strength(3f, 4f); @@ -97,7 +97,7 @@ private static BlockBehaviour.Properties edifiedWoody() { private static BlockBehaviour.Properties woody(MapColor color) { return BlockBehaviour.Properties - .copy(Blocks.OAK_LOG) + .ofFullCopy(Blocks.OAK_LOG) .mapColor(color) .sound(SoundType.WOOD) .strength(2f); @@ -105,7 +105,7 @@ private static BlockBehaviour.Properties woody(MapColor color) { private static BlockBehaviour.Properties leaves(MapColor color) { return BlockBehaviour.Properties - .copy(Blocks.OAK_LEAVES) + .ofFullCopy(Blocks.OAK_LEAVES) .strength(0.2F) .randomTicks() .sound(SoundType.GRASS) @@ -118,7 +118,7 @@ private static BlockBehaviour.Properties leaves(MapColor color) { // we have to make it emit light because otherwise it occludes itself and is always dark private static BlockBehaviour.Properties quenched() { return BlockBehaviour.Properties - .copy(Blocks.AMETHYST_BLOCK) + .ofFullCopy(Blocks.AMETHYST_BLOCK) .lightLevel($ -> 4) .noOcclusion(); } @@ -213,17 +213,18 @@ private static BlockBehaviour.Properties quenched() { public static final Block SLATE_BRICKS = blockItem("slate_bricks", new Block(slateish().strength(2f, 4f))); public static final Block SLATE_BRICKS_SMALL = blockItem("slate_bricks_small", new Block(slateish().strength(2f, 4f))); public static final RotatedPillarBlock SLATE_PILLAR = blockItem("slate_pillar", new RotatedPillarBlock(slateish().strength(2f, 4f))); - public static final SandBlock AMETHYST_DUST_BLOCK = blockItem("amethyst_dust_block", - new SandBlock(0xff_b38ef3, BlockBehaviour.Properties.copy(Blocks.SAND).mapColor(MapColor.COLOR_PURPLE) + public static final ColoredFallingBlock AMETHYST_DUST_BLOCK = blockItem("amethyst_dust_block", + new ColoredFallingBlock(new net.minecraft.util.ColorRGBA(0xff_b38ef3), + BlockBehaviour.Properties.ofFullCopy(Blocks.SAND).mapColor(MapColor.COLOR_PURPLE) .strength(0.5f).sound(SoundType.SAND))); public static final AmethystBlock AMETHYST_TILES = blockItem("amethyst_tiles", - new AmethystBlock(BlockBehaviour.Properties.copy(Blocks.AMETHYST_BLOCK))); + new AmethystBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.AMETHYST_BLOCK))); public static final AmethystBlock AMETHYST_BRICKS = blockItem("amethyst_bricks", - new AmethystBlock(BlockBehaviour.Properties.copy(Blocks.AMETHYST_BLOCK))); + new AmethystBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.AMETHYST_BLOCK))); public static final AmethystBlock AMETHYST_BRICKS_SMALL = blockItem("amethyst_bricks_small", - new AmethystBlock(BlockBehaviour.Properties.copy(Blocks.AMETHYST_BLOCK))); + new AmethystBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.AMETHYST_BLOCK))); public static final BlockAmethystDirectional AMETHYST_PILLAR = blockItem("amethyst_pillar", - new BlockAmethystDirectional(BlockBehaviour.Properties.copy(Blocks.AMETHYST_BLOCK))); + new BlockAmethystDirectional(BlockBehaviour.Properties.ofFullCopy(Blocks.AMETHYST_BLOCK))); public static final Block SLATE_AMETHYST_TILES = blockItem("slate_amethyst_tiles", new Block(slateish().strength(2f, 4f))); public static final Block SLATE_AMETHYST_BRICKS = blockItem("slate_amethyst_bricks", new Block(slateish().strength(2f, 4f))); public static final Block SLATE_AMETHYST_BRICKS_SMALL = blockItem("slate_amethyst_bricks_small", new Block(slateish().strength(2f, 4f))); @@ -285,8 +286,7 @@ private static BlockBehaviour.Properties quenched() { public static final ButtonBlock EDIFIED_BUTTON = blockItem("edified_button", new BlockHexWoodButton(edifiedWoody().noOcclusion().noCollission())); public static final PressurePlateBlock EDIFIED_PRESSURE_PLATE = blockItem("edified_pressure_plate", - new BlockHexPressurePlate(PressurePlateBlock.Sensitivity.EVERYTHING, - edifiedWoody().noOcclusion().noCollission())); + new BlockHexPressurePlate(edifiedWoody().noOcclusion().noCollission())); public static final BlockAkashicLeaves AMETHYST_EDIFIED_LEAVES = blockItem("amethyst_edified_leaves", new BlockAkashicLeaves(leaves(MapColor.COLOR_PURPLE))); public static final BlockAkashicLeaves AVENTURINE_EDIFIED_LEAVES = blockItem("aventurine_edified_leaves", diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexConfiguredFeatures.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexConfiguredFeatures.java index 05f06de4e8..391b9cac1b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexConfiguredFeatures.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexConfiguredFeatures.java @@ -12,6 +12,6 @@ public class HexConfiguredFeatures { public static final ResourceKey> CITRINE_EDIFIED_TREE = createKey("citrine_edified_tree"); private static ResourceKey> createKey(String name) { - return ResourceKey.create(Registries.CONFIGURED_FEATURE, new ResourceLocation(HexAPI.MOD_ID, name)); + return ResourceKey.create(Registries.CONFIGURED_FEATURE, ResourceLocation.fromNamespaceAndPath(HexAPI.MOD_ID, name)); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDamageTypes.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDamageTypes.java index d0451ec184..6bd0f900fc 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDamageTypes.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDamageTypes.java @@ -1,7 +1,7 @@ package at.petrak.hexcasting.common.lib; import net.minecraft.core.registries.Registries; -import net.minecraft.data.worldgen.BootstapContext; +import net.minecraft.data.worldgen.BootstrapContext; import net.minecraft.resources.ResourceKey; import net.minecraft.world.damagesource.DamageScaling; import net.minecraft.world.damagesource.DamageType; @@ -11,7 +11,7 @@ public class HexDamageTypes { public static final ResourceKey OVERCAST = ResourceKey.create(Registries.DAMAGE_TYPE, modLoc("overcast")); - public static void bootstrap(BootstapContext ctx) { + public static void bootstrap(BootstrapContext ctx) { ctx.register(OVERCAST, new DamageType( "hexcasting.overcast", DamageScaling.WHEN_CAUSED_BY_LIVING_NON_PLAYER, diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDataComponents.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDataComponents.java new file mode 100644 index 0000000000..460709ba77 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexDataComponents.java @@ -0,0 +1,25 @@ +package at.petrak.hexcasting.common.lib; + +import net.minecraft.core.component.DataComponentType; +import net.minecraft.nbt.CompoundTag; + +/** + * Data component types for 1.21+ item/entity storage. + * Replaces NBT-based storage for Iota and related data. + *

+ * The platform (NeoForge/Fabric) must register these to + * {@code Registries.DATA_COMPONENT_TYPE} during mod init, e.g.: + * {@code event.register(Registries.DATA_COMPONENT_TYPE, HexAPI.modLoc("stack_data"), () -> HexDataComponents.STACK_DATA);} + */ +public final class HexDataComponents { + /** + * Holds a {@link CompoundTag} for item stack custom data (Iota, sealed, variant, etc.). + * Used so that {@link at.petrak.hexcasting.api.utils.NBTHelper} can read/write + * via this component on 1.21+ instead of the removed ItemStack tag. + */ + public static final DataComponentType STACK_DATA = DataComponentType.builder() + .persistent(CompoundTag.CODEC) + .build(); + + private HexDataComponents() {} +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexFeatureConfigs.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexFeatureConfigs.java index 52be4c646e..cbd856a66d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexFeatureConfigs.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexFeatureConfigs.java @@ -18,7 +18,6 @@ public class HexFeatureConfigs { public static void dumpConfigs() { - // Used to generate the tree data json files // Call this after the game is properly bootstrapped and copy the output logs to data/hexcasting/worldgen/configured_feature/${name}.json // This should be done in DataGen, but I was unable to make that function. - dashkal16 HexAPI.LOGGER.info(TreeConfiguration.CODEC.encodeStart(JsonOps.INSTANCE, AMETHYST_EDIFIED_TREE_CONFIG)); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexItems.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexItems.java index 3cd0e47c32..636e442a71 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexItems.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexItems.java @@ -45,6 +45,7 @@ public static void registerItemCreativeTab(CreativeModeTab.Output r, CreativeMod private static final Map ITEMS = new LinkedHashMap<>(); // preserve insertion order private static final Map> ITEM_TABS = new LinkedHashMap<>(); + private static final List GENERATED_SCROLL_ENTRIES = new ArrayList<>(); public static final Item AMETHYST_DUST = make("amethyst_dust", new Item(props())); @@ -83,7 +84,7 @@ public static void registerItemCreativeTab(CreativeModeTab.Output r, CreativeMod public static final ItemArtifact ARTIFACT = make("artifact", new ItemArtifact(unstackable().rarity(Rarity.RARE))); public static final ItemJewelerHammer JEWELER_HAMMER = make("jeweler_hammer", - new ItemJewelerHammer(Tiers.IRON, 0, -2.8F, props().stacksTo(1).defaultDurability(Tiers.DIAMOND.getUses()))); + new ItemJewelerHammer(Tiers.IRON, props().stacksTo(1).durability(Tiers.DIAMOND.getUses()))); public static final ItemScroll SCROLL_SMOL = make("scroll_small", new ItemScroll(props(), 1)); public static final ItemScroll SCROLL_MEDIUM = make("scroll_medium", new ItemScroll(props(), 2)); @@ -139,7 +140,7 @@ public static void registerItemCreativeTab(CreativeModeTab.Output r, CreativeMod // BUFF SANDVICH public static final Item SUBMARINE_SANDWICH = make("sub_sandwich", - new Item(props().food(new FoodProperties.Builder().nutrition(14).saturationMod(1.2f).build()))); + new Item(props().food(new FoodProperties.Builder().nutrition(14).saturationModifier(1.2f).build()))); public static final ItemLoreFragment LORE_FRAGMENT = make("lore_fragment", new ItemLoreFragment(unstackable() @@ -148,7 +149,7 @@ public static void registerItemCreativeTab(CreativeModeTab.Output r, CreativeMod public static final ItemCreativeUnlocker CREATIVE_UNLOCKER = make("creative_unlocker", new ItemCreativeUnlocker(unstackable() .rarity(Rarity.EPIC) - .food(new FoodProperties.Builder().nutrition(20).saturationMod(1f).alwaysEat().build()))); + .food(new FoodProperties.Builder().nutrition(20).saturationModifier(1f).alwaysEdible().build()))); // @@ -161,6 +162,10 @@ public static Item.Properties unstackable() { } private static void generateScrollEntries() { + var scrollTabEntries = ITEM_TABS.computeIfAbsent(HexCreativeTabs.SCROLLS, t -> new ArrayList<>()); + scrollTabEntries.removeAll(GENERATED_SCROLL_ENTRIES); + GENERATED_SCROLL_ENTRIES.clear(); + var keyList = new ArrayList>(); Registry regi = IXplatAbstractions.INSTANCE.getActionRegistry(); for (var key : regi.registryKeySet()) @@ -168,10 +173,13 @@ private static void generateScrollEntries() { keyList.add(key); keyList.sort( (a, b) -> a.location().compareTo(b.location()) ); for (var key : keyList) { - addToTab(() -> ItemScroll.withPerWorldPattern( + var memoised = Suppliers.memoize(() -> ItemScroll.withPerWorldPattern( new ItemStack(HexItems.SCROLL_LARGE), key.location().toString() - ),HexCreativeTabs.SCROLLS); + )); + var entry = new TabEntry.StackEntry(memoised); + scrollTabEntries.add(entry); + GENERATED_SCROLL_ENTRIES.add(entry); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexLootFunctions.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexLootFunctions.java index 409f5c979c..4f9d2b57ba 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexLootFunctions.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexLootFunctions.java @@ -22,11 +22,11 @@ public static void registerSerializers(BiConsumer LOOT_FUNCS = new LinkedHashMap<>(); public static final LootItemFunctionType PATTERN_SCROLL = register("pattern_scroll", - new LootItemFunctionType(new AddPerWorldPatternToScrollFunc.Serializer())); + new LootItemFunctionType(AddPerWorldPatternToScrollFunc.CODEC)); public static final LootItemFunctionType HEX_CYPHER = register("hex_cypher", - new LootItemFunctionType(new AddHexToAncientCypherFunc.Serializer())); + new LootItemFunctionType(AddHexToAncientCypherFunc.CODEC)); public static final LootItemFunctionType AMETHYST_SHARD_REDUCER = register("amethyst_shard_reducer", - new LootItemFunctionType(new AmethystReducerFunc.Serializer())); + new LootItemFunctionType(AmethystReducerFunc.CODEC)); private static LootItemFunctionType register(String id, LootItemFunctionType lift) { var old = LOOT_FUNCS.put(modLoc(id), lift); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexMobEffects.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexMobEffects.java index 6398bfea27..28408a2401 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexMobEffects.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexMobEffects.java @@ -1,6 +1,9 @@ package at.petrak.hexcasting.common.lib; import at.petrak.hexcasting.common.misc.HexMobEffect; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; @@ -23,12 +26,12 @@ public static void register(BiConsumer r) { public static final MobEffect ENLARGE_GRID = make("enlarge_grid", new HexMobEffect(MobEffectCategory.BENEFICIAL, 0xc875ff)) - .addAttributeModifier(HexAttributes.GRID_ZOOM, "d4afaf0f-df37-4253-9fa7-029e8e4415d9", - 0.25, AttributeModifier.Operation.MULTIPLY_TOTAL); + .addAttributeModifier(net.minecraft.core.Holder.direct(HexAttributes.GRID_ZOOM), modLoc("enlarge_grid_modifier"), + 0.25, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); public static final MobEffect SHRINK_GRID = make("shrink_grid", new HexMobEffect(MobEffectCategory.HARMFUL, 0xc0e660)) - .addAttributeModifier(HexAttributes.GRID_ZOOM, "1ce492a9-8bf5-4091-a482-c6d9399e448a", - -0.2, AttributeModifier.Operation.MULTIPLY_TOTAL); + .addAttributeModifier(net.minecraft.core.Holder.direct(HexAttributes.GRID_ZOOM), modLoc("shrink_grid_modifier"), + -0.2, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); private static T make(String id, T effect) { @@ -38,4 +41,15 @@ private static T make(String id, T effect) { } return effect; } + + /** 1.21+ Get Holder for MobEffectInstance; pass level.registryAccess() or entity.registryAccess() */ + public static Holder getHolder(MobEffect effect, net.minecraft.core.HolderLookup.Provider registryAccess) { + for (var e : EFFECTS.entrySet()) { + if (e.getValue() == effect) { + var key = ResourceKey.create(Registries.MOB_EFFECT, e.getKey()); + return registryAccess.lookupOrThrow(Registries.MOB_EFFECT).getOrThrow(key); + } + } + throw new IllegalArgumentException("Effect " + effect + " not registered in HexMobEffects"); + } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexPotions.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexPotions.java index e86409e77c..0053c7de51 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexPotions.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexPotions.java @@ -1,54 +1,58 @@ package at.petrak.hexcasting.common.lib; +import net.minecraft.core.Holder; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.item.Items; import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.alchemy.PotionBrewing; import net.minecraft.world.item.alchemy.Potions; -import net.minecraft.world.item.Items; import java.util.LinkedHashMap; import java.util.Map; import java.util.function.BiConsumer; import static at.petrak.hexcasting.api.HexAPI.modLoc; -import at.petrak.hexcasting.mixin.accessor.AccessorPotionBrewing; public class HexPotions { public static void register(BiConsumer r) { for (var e : POTIONS.entrySet()) { r.accept(e.getValue(), e.getKey()); } - HexPotions.addRecipes(); + } + + /** + * Add Hex Casting potion brewing recipes. Called from Forge's RegisterBrewingRecipesEvent + * (Fabric uses a different approach when that module is enabled). + */ + public static void addRecipes(PotionBrewing.Builder builder) { + builder.addMix(Potions.AWKWARD, HexItems.AMETHYST_DUST, Holder.direct(ENLARGE_GRID)); + builder.addMix(Holder.direct(ENLARGE_GRID), Items.REDSTONE, Holder.direct(ENLARGE_GRID_LONG)); + builder.addMix(Holder.direct(ENLARGE_GRID), Items.GLOWSTONE_DUST, Holder.direct(ENLARGE_GRID_STRONG)); + + builder.addMix(Holder.direct(ENLARGE_GRID), Items.FERMENTED_SPIDER_EYE, Holder.direct(SHRINK_GRID)); + builder.addMix(Holder.direct(ENLARGE_GRID_LONG), Items.FERMENTED_SPIDER_EYE, Holder.direct(SHRINK_GRID_LONG)); + builder.addMix(Holder.direct(ENLARGE_GRID_STRONG), Items.FERMENTED_SPIDER_EYE, Holder.direct(SHRINK_GRID_STRONG)); + + builder.addMix(Holder.direct(SHRINK_GRID), Items.REDSTONE, Holder.direct(SHRINK_GRID_LONG)); + builder.addMix(Holder.direct(SHRINK_GRID), Items.GLOWSTONE_DUST, Holder.direct(SHRINK_GRID_STRONG)); } private static final Map POTIONS = new LinkedHashMap<>(); public static final Potion ENLARGE_GRID = make("enlarge_grid", - new Potion("enlarge_grid", new MobEffectInstance(HexMobEffects.ENLARGE_GRID, 3600))); + new Potion("enlarge_grid", new MobEffectInstance(Holder.direct(HexMobEffects.ENLARGE_GRID), 3600))); public static final Potion ENLARGE_GRID_LONG = make("enlarge_grid_long", - new Potion("enlarge_grid_long", new MobEffectInstance(HexMobEffects.ENLARGE_GRID, 9600))); + new Potion("enlarge_grid_long", new MobEffectInstance(Holder.direct(HexMobEffects.ENLARGE_GRID), 9600))); public static final Potion ENLARGE_GRID_STRONG = make("enlarge_grid_strong", - new Potion("enlarge_grid_strong", new MobEffectInstance(HexMobEffects.ENLARGE_GRID, 1800, 1))); + new Potion("enlarge_grid_strong", new MobEffectInstance(Holder.direct(HexMobEffects.ENLARGE_GRID), 1800, 1))); public static final Potion SHRINK_GRID = make("shrink_grid", - new Potion("shrink_grid", new MobEffectInstance(HexMobEffects.SHRINK_GRID, 3600))); + new Potion("shrink_grid", new MobEffectInstance(Holder.direct(HexMobEffects.SHRINK_GRID), 3600))); public static final Potion SHRINK_GRID_LONG = make("shrink_grid_long", - new Potion("shrink_grid_long", new MobEffectInstance(HexMobEffects.SHRINK_GRID, 9600))); + new Potion("shrink_grid_long", new MobEffectInstance(Holder.direct(HexMobEffects.SHRINK_GRID), 9600))); public static final Potion SHRINK_GRID_STRONG = make("shrink_grid_strong", - new Potion("shrink_grid_strong", new MobEffectInstance(HexMobEffects.SHRINK_GRID, 1800, 1))); - - public static void addRecipes() { - AccessorPotionBrewing.addMix(Potions.AWKWARD, HexItems.AMETHYST_DUST, ENLARGE_GRID); - AccessorPotionBrewing.addMix(ENLARGE_GRID, Items.REDSTONE, ENLARGE_GRID_LONG); - AccessorPotionBrewing.addMix(ENLARGE_GRID, Items.GLOWSTONE_DUST, ENLARGE_GRID_STRONG); - - AccessorPotionBrewing.addMix(ENLARGE_GRID, Items.FERMENTED_SPIDER_EYE, SHRINK_GRID); - AccessorPotionBrewing.addMix(ENLARGE_GRID_LONG, Items.FERMENTED_SPIDER_EYE, SHRINK_GRID_LONG); - AccessorPotionBrewing.addMix(ENLARGE_GRID_STRONG, Items.FERMENTED_SPIDER_EYE, SHRINK_GRID_STRONG); - - AccessorPotionBrewing.addMix(SHRINK_GRID, Items.REDSTONE, SHRINK_GRID_LONG); - AccessorPotionBrewing.addMix(SHRINK_GRID, Items.GLOWSTONE_DUST, SHRINK_GRID_STRONG); - } + new Potion("shrink_grid_strong", new MobEffectInstance(Holder.direct(HexMobEffects.SHRINK_GRID), 1800, 1))); private static T make(String id, T potion) { var old = POTIONS.put(modLoc(id), potion); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexSpecialHandlers.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexSpecialHandlers.java index c69fb9363c..3c8977b1c4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexSpecialHandlers.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexSpecialHandlers.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.common.lib.hex; import at.petrak.hexcasting.api.casting.castables.SpecialHandler; +import at.petrak.hexcasting.common.casting.actions.SpecialHandlerCompat; import at.petrak.hexcasting.common.casting.actions.math.SpecialHandlerNumberLiteral; import at.petrak.hexcasting.common.casting.actions.stack.SpecialHandlerMask; import net.minecraft.resources.ResourceLocation; @@ -18,6 +19,8 @@ public class HexSpecialHandlers { new SpecialHandlerNumberLiteral.Factory()); public static final SpecialHandler.Factory MASK = make("mask", new SpecialHandlerMask.Factory()); + public static final SpecialHandler.Factory COMPAT = make("compat", + new SpecialHandlerCompat.Factory()); private static SpecialHandler.Factory make(String name, SpecialHandler.Factory handler) { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java b/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java index 8dac9cfeb0..130a8bcb34 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java @@ -4,18 +4,15 @@ import at.petrak.hexcasting.api.casting.iota.IotaType; import at.petrak.hexcasting.api.casting.math.HexDir; import at.petrak.hexcasting.api.casting.math.HexPattern; -import at.petrak.hexcasting.api.mod.HexConfig; -import at.petrak.hexcasting.api.utils.HexUtils; +import at.petrak.hexcasting.api.utils.NBTHelper; import at.petrak.hexcasting.api.item.VariantItem; import at.petrak.hexcasting.api.misc.MediaConstants; import at.petrak.hexcasting.api.pigment.FrozenPigment; import at.petrak.hexcasting.common.items.magic.ItemAncientCypher; import at.petrak.hexcasting.common.items.magic.ItemPackagedHex; -import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexLootFunctions; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.Util; import net.minecraft.util.RandomSource; import net.minecraft.nbt.ListTag; @@ -36,7 +33,11 @@ * is used on both sides */ public class AddHexToAncientCypherFunc extends LootItemConditionalFunction { - public AddHexToAncientCypherFunc(LootItemCondition[] lootItemConditions) { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + inst -> commonFields(inst).apply(inst, AddHexToAncientCypherFunc::new) + ); + + public AddHexToAncientCypherFunc(List lootItemConditions) { super(lootItemConditions); } @@ -61,7 +62,7 @@ public static ItemStack doStatic(ItemStack stack, RandomSource rand) { tag.putLong(ItemAncientCypher.TAG_MAX_MEDIA, 32*MediaConstants.SHARD_UNIT); tag.putInt(VariantItem.TAG_VARIANT, rand.nextInt(8)); - stack.getOrCreateTag().merge(tag); + NBTHelper.getOrCreateTag(stack).merge(tag); return stack; } @@ -76,19 +77,6 @@ public LootItemFunctionType getType() { return HexLootFunctions.HEX_CYPHER; } - public static class Serializer extends LootItemConditionalFunction.Serializer { - @Override - public void serialize(JsonObject json, AddHexToAncientCypherFunc value, JsonSerializationContext ctx) { - super.serialize(json, value, ctx); - } - - @Override - public AddHexToAncientCypherFunc deserialize(JsonObject object, JsonDeserializationContext ctx, - LootItemCondition[] conditions) { - return new AddHexToAncientCypherFunc(conditions); - } - } - // TODO: make this datapackable private static final List> LOOT_HEXES = List.of( new Pair<>("hexcasting.loot_hex.shatter", new String[] {"NORTH_EAST qaq","EAST aa","NORTH_EAST qaq","NORTH_EAST wa","EAST wqaawdd","EAST qaqqqqq"}), diff --git a/Common/src/main/java/at/petrak/hexcasting/common/loot/AddPerWorldPatternToScrollFunc.java b/Common/src/main/java/at/petrak/hexcasting/common/loot/AddPerWorldPatternToScrollFunc.java index 0d45634db4..e0dbd91e75 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/loot/AddPerWorldPatternToScrollFunc.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/loot/AddPerWorldPatternToScrollFunc.java @@ -8,14 +8,11 @@ import at.petrak.hexcasting.common.items.storage.ItemScroll; import at.petrak.hexcasting.common.lib.HexLootFunctions; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.util.RandomSource; import net.minecraft.core.Registry; -import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; @@ -24,6 +21,7 @@ import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import java.util.ArrayList; +import java.util.List; /** * Slap a random per-world pattern on the scroll. @@ -32,7 +30,11 @@ * is used on both sides */ public class AddPerWorldPatternToScrollFunc extends LootItemConditionalFunction { - public AddPerWorldPatternToScrollFunc(LootItemCondition[] lootItemConditions) { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + inst -> commonFields(inst).apply(inst, AddPerWorldPatternToScrollFunc::new) + ); + + public AddPerWorldPatternToScrollFunc(List lootItemConditions) { super(lootItemConditions); } @@ -63,17 +65,4 @@ protected ItemStack run(ItemStack stack, LootContext ctx) { public LootItemFunctionType getType() { return HexLootFunctions.PATTERN_SCROLL; } - - public static class Serializer extends LootItemConditionalFunction.Serializer { - @Override - public void serialize(JsonObject json, AddPerWorldPatternToScrollFunc value, JsonSerializationContext ctx) { - super.serialize(json, value, ctx); - } - - @Override - public AddPerWorldPatternToScrollFunc deserialize(JsonObject object, JsonDeserializationContext ctx, - LootItemCondition[] conditions) { - return new AddPerWorldPatternToScrollFunc(conditions); - } - } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/loot/AmethystReducerFunc.java b/Common/src/main/java/at/petrak/hexcasting/common/loot/AmethystReducerFunc.java index cee38be6dd..49ad7caf45 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/loot/AmethystReducerFunc.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/loot/AmethystReducerFunc.java @@ -1,10 +1,9 @@ package at.petrak.hexcasting.common.loot; import at.petrak.hexcasting.common.lib.HexLootFunctions; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; -import net.minecraft.util.GsonHelper; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.storage.loot.LootContext; @@ -12,10 +11,16 @@ import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import java.util.List; + public class AmethystReducerFunc extends LootItemConditionalFunction { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(inst -> commonFields(inst) + .and(Codec.DOUBLE.fieldOf("delta").forGetter(f -> f.delta)) + .apply(inst, AmethystReducerFunc::new)); + public final double delta; - public AmethystReducerFunc(LootItemCondition[] lootItemConditions, double delta) { + public AmethystReducerFunc(List lootItemConditions, double delta) { super(lootItemConditions); this.delta = delta; } @@ -36,19 +41,4 @@ protected ItemStack run(ItemStack stack, LootContext ctx) { public LootItemFunctionType getType() { return HexLootFunctions.AMETHYST_SHARD_REDUCER; } - - public static class Serializer extends LootItemConditionalFunction.Serializer { - @Override - public void serialize(JsonObject json, AmethystReducerFunc value, JsonSerializationContext ctx) { - super.serialize(json, value, ctx); - json.addProperty("delta", value.delta); - } - - @Override - public AmethystReducerFunc deserialize(JsonObject object, JsonDeserializationContext ctx, - LootItemCondition[] conditions) { - var delta = GsonHelper.getAsDouble(object, "delta"); - return new AmethystReducerFunc(conditions, delta); - } - } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/loot/HexLootHandler.java b/Common/src/main/java/at/petrak/hexcasting/common/loot/HexLootHandler.java index cb4cee9211..70099d5536 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/loot/HexLootHandler.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/loot/HexLootHandler.java @@ -24,53 +24,53 @@ public class HexLootHandler { // In places where it doesn't really make sense to have them lore-wise just put them rarely anyways // to make it less of a PITA for new players - new ScrollInjection(new ResourceLocation("minecraft", "chests/simple_dungeon"), 1), - new ScrollInjection(new ResourceLocation("minecraft", "chests/abandoned_mineshaft"), 1), - new ScrollInjection(new ResourceLocation("minecraft", "chests/bastion_other"), 1), - new ScrollInjection(new ResourceLocation("minecraft", "chests/nether_bridge"), 1), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/simple_dungeon"), 1), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/abandoned_mineshaft"), 1), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/bastion_other"), 1), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/nether_bridge"), 1), - new ScrollInjection(new ResourceLocation("minecraft", "chests/jungle_temple"), 2), - new ScrollInjection(new ResourceLocation("minecraft", "chests/desert_pyramid"), 2), - new ScrollInjection(new ResourceLocation("minecraft", "chests/village/village_cartographer"), 2), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/jungle_temple"), 2), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/desert_pyramid"), 2), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/village/village_cartographer"), 2), - new ScrollInjection(new ResourceLocation("minecraft", "chests/shipwreck_map"), 3), - new ScrollInjection(new ResourceLocation("minecraft", "chests/bastion_treasure"), 3), - new ScrollInjection(new ResourceLocation("minecraft", "chests/end_city_treasure"), 3), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/shipwreck_map"), 3), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/bastion_treasure"), 3), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/end_city_treasure"), 3), // ancient city chests have amethyst in them, thinking emoji - new ScrollInjection(new ResourceLocation("minecraft", "chests/ancient_city"), 4), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/ancient_city"), 4), // wonder what those pillagers are up to with those scrolls - new ScrollInjection(new ResourceLocation("minecraft", "chests/pillager_outpost"), 4), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/pillager_outpost"), 4), // if you manage to find one of these things you deserve a lot of scrolls - new ScrollInjection(new ResourceLocation("minecraft", "chests/woodland_mansion"), 5), - new ScrollInjection(new ResourceLocation("minecraft", "chests/stronghold_library"), 5) + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/woodland_mansion"), 5), + new ScrollInjection(ResourceLocation.fromNamespaceAndPath("minecraft", "chests/stronghold_library"), 5) // you can use the table hexcasting:random_scroll to get exactly 1 scroll and nothing else ); public static final ImmutableList DEFAULT_LORE_INJECTS = ImmutableList.of( - new ResourceLocation("minecraft", "chests/simple_dungeon"), - new ResourceLocation("minecraft", "chests/abandoned_mineshaft"), - new ResourceLocation("minecraft", "chests/pillager_outpost"), - new ResourceLocation("minecraft", "chests/woodland_mansion"), - new ResourceLocation("minecraft", "chests/stronghold_library"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/simple_dungeon"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/abandoned_mineshaft"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/pillager_outpost"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/woodland_mansion"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/stronghold_library"), // >:) - new ResourceLocation("minecraft", "chests/village/village_desert_house"), - new ResourceLocation("minecraft", "chests/village/village_plains_house"), - new ResourceLocation("minecraft", "chests/village/village_savanna_house"), - new ResourceLocation("minecraft", "chests/village/village_snowy_house"), - new ResourceLocation("minecraft", "chests/village/village_taiga_house") + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/village/village_desert_house"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/village/village_plains_house"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/village/village_savanna_house"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/village/village_snowy_house"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/village/village_taiga_house") ); public static final ImmutableList DEFAULT_CYPHER_INJECTS = ImmutableList.of( - new ResourceLocation("minecraft", "chests/simple_dungeon"), - new ResourceLocation("minecraft", "chests/abandoned_mineshaft"), - new ResourceLocation("minecraft", "chests/stronghold_corridor"), - new ResourceLocation("minecraft", "chests/jungle_temple"), - new ResourceLocation("minecraft", "chests/desert_pyramid"), - new ResourceLocation("minecraft", "chests/ancient_city"), - new ResourceLocation("minecraft", "chests/nether_bridge") + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/simple_dungeon"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/abandoned_mineshaft"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/stronghold_corridor"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/jungle_temple"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/desert_pyramid"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/ancient_city"), + ResourceLocation.fromNamespaceAndPath("minecraft", "chests/nether_bridge") // you can use the table hexcasting:random_cypher to get exactly 1 cypher and nothing else ); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/misc/AkashicTreeGrower.java b/Common/src/main/java/at/petrak/hexcasting/common/misc/AkashicTreeGrower.java index 4e235769e8..8786b44cd0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/misc/AkashicTreeGrower.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/misc/AkashicTreeGrower.java @@ -4,24 +4,31 @@ import com.google.common.collect.Lists; import net.minecraft.resources.ResourceKey; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.grower.AbstractTreeGrower; +import net.minecraft.world.level.block.grower.TreeGrower; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import java.util.List; +import java.util.Optional; -public class AkashicTreeGrower extends AbstractTreeGrower { - public static final AkashicTreeGrower INSTANCE = new AkashicTreeGrower(); - +public class AkashicTreeGrower { public static final List>> GROWERS = Lists.newArrayList(); + private static final TreeGrower[] TREE_GROWERS = new TreeGrower[3]; + public static void init() { GROWERS.add(HexConfiguredFeatures.AMETHYST_EDIFIED_TREE); GROWERS.add(HexConfiguredFeatures.AVENTURINE_EDIFIED_TREE); GROWERS.add(HexConfiguredFeatures.CITRINE_EDIFIED_TREE); + TREE_GROWERS[0] = new TreeGrower("akashic_amethyst", Optional.of(GROWERS.get(0)), Optional.empty(), Optional.empty()); + TREE_GROWERS[1] = new TreeGrower("akashic_aventurine", Optional.of(GROWERS.get(1)), Optional.empty(), Optional.empty()); + TREE_GROWERS[2] = new TreeGrower("akashic_citrine", Optional.of(GROWERS.get(2)), Optional.empty(), Optional.empty()); } - @Override - protected ResourceKey> getConfiguredFeature(RandomSource pRandom, boolean pLargeHive) { - return GROWERS.get(pRandom.nextInt(GROWERS.size())); + public static boolean growTree(net.minecraft.server.level.ServerLevel level, + net.minecraft.world.level.chunk.ChunkGenerator chunkGen, + net.minecraft.core.BlockPos pos, + net.minecraft.world.level.block.state.BlockState state, + RandomSource random) { + return TREE_GROWERS[random.nextInt(TREE_GROWERS.length)].growTree(level, chunkGen, pos, state, random); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/misc/PatternDisplayHelper.java b/Common/src/main/java/at/petrak/hexcasting/common/misc/PatternDisplayHelper.java new file mode 100644 index 0000000000..0640f527ec --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/misc/PatternDisplayHelper.java @@ -0,0 +1,60 @@ +package at.petrak.hexcasting.common.misc; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.api.casting.PatternShapeMatch; +import at.petrak.hexcasting.api.casting.iota.PatternIota; +import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.common.casting.PatternRegistryManifest; +import at.petrak.hexcasting.common.lib.HexItems; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +/** + * Fallback pattern display when Inline mod is not present. + * Provides pattern name resolution and display components without Inline dependency. + */ +public final class PatternDisplayHelper { + + /** + * Get the display name for a pattern (e.g. "Great Spells" for a known action). + */ + @NotNull + public static Component getPatternName(@NotNull HexPattern pattern) { + try { + PatternShapeMatch shapeMatch = PatternRegistryManifest.matchPattern(pattern, null, false); + if (shapeMatch instanceof PatternShapeMatch.Normal normMatch) { + return HexAPI.instance().getActionI18n(normMatch.key, false); + } + if (shapeMatch instanceof PatternShapeMatch.Special specialMatch) { + return HexAPI.instance().getSpecialHandlerI18n(specialMatch.key); + } + } catch (Exception e) { + // nop + } + return PatternIota.displayNonInline(pattern); + } + + /** + * Get a component for displaying a pattern in tooltips/item names. + * When withHoverAndClick is true, adds hover (scroll preview) and click-to-copy. + */ + @NotNull + public static Component getDisplayComponent(@NotNull HexPattern pattern, boolean withHoverAndClick) { + MutableComponent text = Component.literal(pattern.toString()).withStyle(ChatFormatting.WHITE); + if (withHoverAndClick) { + ItemStack scrollStack = new ItemStack(HexItems.SCROLL_MEDIUM); + HexItems.SCROLL_MEDIUM.writeDatum(scrollStack, new PatternIota(pattern)); + scrollStack.set(DataComponents.CUSTOM_NAME, getPatternName(pattern).copy().withStyle(ChatFormatting.WHITE)); + HoverEvent he = new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(scrollStack)); + ClickEvent ce = new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, pattern.toString()); + text = text.withStyle(s -> s.withHoverEvent(he).withClickEvent(ce)); + } + return text; + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/IMessage.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/IMessage.java index ec7cdd8ef4..b1fc0ebe49 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/IMessage.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/IMessage.java @@ -2,11 +2,12 @@ import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; // https://github.com/VazkiiMods/Botania/blob/1.18.x/Common/src/main/java/vazkii/botania/network/IPacket.java // yoink -public interface IMessage { +public interface IMessage extends CustomPacketPayload { default FriendlyByteBuf toBuf() { var ret = new FriendlyByteBuf(Unpooled.buffer()); serialize(ret); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgBeepS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgBeepS2C.java index 852fc675af..a4f36ca7af 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgBeepS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgBeepS2C.java @@ -1,9 +1,11 @@ package at.petrak.hexcasting.common.msgs; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; @@ -13,14 +15,21 @@ public record MsgBeepS2C(Vec3 target, int note, NoteBlockInstrument instrument) implements IMessage { public static final ResourceLocation ID = modLoc("beep"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgBeepS2C::serialize, MsgBeepS2C::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgBeepS2C deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgBeepS2C deserialize(FriendlyByteBuf buf) { var x = buf.readDouble(); var y = buf.readDouble(); var z = buf.readDouble(); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgCastParticleS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgCastParticleS2C.java index 9ec659b8b6..1252e8911e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgCastParticleS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgCastParticleS2C.java @@ -4,9 +4,11 @@ import at.petrak.hexcasting.api.pigment.FrozenPigment; import at.petrak.hexcasting.client.ClientTickCounter; import at.petrak.hexcasting.common.particles.ConjureParticleOptions; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; @@ -20,14 +22,21 @@ */ public record MsgCastParticleS2C(ParticleSpray spray, FrozenPigment colorizer) implements IMessage { public static final ResourceLocation ID = modLoc("cprtcl"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgCastParticleS2C::serialize, MsgCastParticleS2C::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgCastParticleS2C deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgCastParticleS2C deserialize(FriendlyByteBuf buf) { var posX = buf.readDouble(); var posY = buf.readDouble(); var posZ = buf.readDouble(); @@ -37,7 +46,7 @@ public static MsgCastParticleS2C deserialize(ByteBuf buffer) { var fuzziness = buf.readDouble(); var spread = buf.readDouble(); var count = buf.readInt(); - var tag = buf.readAnySizeNbt(); + var tag = buf.readNbt(); var colorizer = FrozenPigment.fromNBT(tag); return new MsgCastParticleS2C( new ParticleSpray(new Vec3(posX, posY, posZ), new Vec3(velX, velY, velZ), fuzziness, spread, count), diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgClearSpiralPatternsS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgClearSpiralPatternsS2C.java index 1f454ba700..34db91a582 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgClearSpiralPatternsS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgClearSpiralPatternsS2C.java @@ -1,9 +1,11 @@ package at.petrak.hexcasting.common.msgs; import at.petrak.hexcasting.xplat.IClientXplatAbstractions; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import java.util.UUID; @@ -12,14 +14,21 @@ public record MsgClearSpiralPatternsS2C(UUID playerUUID) implements IMessage { public static final ResourceLocation ID = modLoc("clr_spi_pats_sc"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgClearSpiralPatternsS2C::serialize, MsgClearSpiralPatternsS2C::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgClearSpiralPatternsS2C deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgClearSpiralPatternsS2C deserialize(FriendlyByteBuf buf) { var player = buf.readUUID(); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpellPatternC2S.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpellPatternC2S.java index ce19d966b3..9a4629aa2a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpellPatternC2S.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpellPatternC2S.java @@ -3,8 +3,10 @@ import at.petrak.hexcasting.api.casting.eval.ResolvedPattern; import at.petrak.hexcasting.api.casting.eval.env.StaffCastEnv; import at.petrak.hexcasting.api.casting.math.HexPattern; -import io.netty.buffer.ByteBuf; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; @@ -23,14 +25,21 @@ public record MsgNewSpellPatternC2S(InteractionHand handUsed, HexPattern pattern List resolvedPatterns) implements IMessage { public static final ResourceLocation ID = modLoc("pat_cs"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgNewSpellPatternC2S::serialize, MsgNewSpellPatternC2S::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgNewSpellPatternC2S deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgNewSpellPatternC2S deserialize(FriendlyByteBuf buf) { var hand = buf.readEnum(InteractionHand.class); var pattern = HexPattern.fromNBT(buf.readNbt()); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpellPatternS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpellPatternS2C.java index cadf3dd100..1052d1d7d1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpellPatternS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpellPatternS2C.java @@ -4,9 +4,11 @@ import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType; import at.petrak.hexcasting.client.gui.GuiSpellcasting; import at.petrak.hexcasting.common.lib.HexSounds; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import java.util.Optional; @@ -18,21 +20,28 @@ */ public record MsgNewSpellPatternS2C(ExecutionClientView info, int index) implements IMessage { public static final ResourceLocation ID = modLoc("pat_sc"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgNewSpellPatternS2C::serialize, MsgNewSpellPatternS2C::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgNewSpellPatternS2C deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgNewSpellPatternS2C deserialize(FriendlyByteBuf buf) { var isStackEmpty = buf.readBoolean(); var resolutionType = buf.readEnum(ResolvedPatternType.class); var index = buf.readInt(); - var stack = buf.readList(FriendlyByteBuf::readNbt); - var raven = buf.readOptional(FriendlyByteBuf::readNbt).orElse(null); + var stack = buf.readList(fbb -> fbb.readNbt()); + var raven = buf.readOptional(fbb -> fbb.readNbt()).orElse(null); return new MsgNewSpellPatternS2C( new ExecutionClientView(isStackEmpty, resolutionType, stack, raven), index @@ -45,8 +54,8 @@ public void serialize(FriendlyByteBuf buf) { buf.writeEnum(this.info.getResolutionType()); buf.writeInt(this.index); - buf.writeCollection(this.info.getStackDescs(), FriendlyByteBuf::writeNbt); - buf.writeOptional(Optional.ofNullable(this.info.getRavenmind()), FriendlyByteBuf::writeNbt); + buf.writeCollection(this.info.getStackDescs(), (fbb, tag) -> fbb.writeNbt(tag)); + buf.writeOptional(Optional.ofNullable(this.info.getRavenmind()), (fbb, tag) -> fbb.writeNbt(tag)); } public static void handle(MsgNewSpellPatternS2C self) { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpiralPatternsS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpiralPatternsS2C.java index 9c5a02180c..423488ffae 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpiralPatternsS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewSpiralPatternsS2C.java @@ -2,9 +2,11 @@ import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.xplat.IClientXplatAbstractions; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import java.util.ArrayList; @@ -15,17 +17,24 @@ public record MsgNewSpiralPatternsS2C(UUID playerUUID, List patterns, int lifetime) implements IMessage { public static final ResourceLocation ID = modLoc("spi_pats_sc"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgNewSpiralPatternsS2C::serialize, MsgNewSpiralPatternsS2C::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgNewSpiralPatternsS2C deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgNewSpiralPatternsS2C deserialize(FriendlyByteBuf buf) { var player = buf.readUUID(); - var patterns = buf.readCollection(ArrayList::new, buff -> HexPattern.fromNBT(buf.readNbt())); + var patterns = buf.readCollection(ArrayList::new, fbb -> HexPattern.fromNBT(fbb.readNbt())); var lifetime = buf.readInt(); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewWallScrollS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewWallScrollS2C.java index 67e77248cc..68dfda4505 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewWallScrollS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgNewWallScrollS2C.java @@ -6,6 +6,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; @@ -16,6 +19,14 @@ public record MsgNewWallScrollS2C(ClientboundAddEntityPacket inner, BlockPos pos, Direction dir, ItemStack scrollItem, boolean showsStrokeOrder, int blockSize) implements IMessage { public static final ResourceLocation ID = modLoc("wallscr"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgNewWallScrollS2C::serialize, MsgNewWallScrollS2C::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { @@ -24,19 +35,21 @@ public ResourceLocation getFabricId() { @Override public void serialize(FriendlyByteBuf buf) { - inner.write(buf); + var rfb = (RegistryFriendlyByteBuf) buf; + ClientboundAddEntityPacket.STREAM_CODEC.encode(rfb, inner); buf.writeBlockPos(pos); buf.writeByte(dir.ordinal()); - buf.writeItem(scrollItem); + ItemStack.STREAM_CODEC.encode(rfb, scrollItem); buf.writeBoolean(showsStrokeOrder); buf.writeVarInt(blockSize); } public static MsgNewWallScrollS2C deserialize(FriendlyByteBuf buf) { - var inner = new ClientboundAddEntityPacket(buf); + var rfb = (RegistryFriendlyByteBuf) buf; + var inner = ClientboundAddEntityPacket.STREAM_CODEC.decode(rfb); var pos = buf.readBlockPos(); var dir = HexUtils.getSafe(Direction.values(), buf.readByte()); - var scroll = buf.readItem(); + var scroll = ItemStack.STREAM_CODEC.decode(rfb); var strokeOrder = buf.readBoolean(); var blockSize = buf.readVarInt(); return new MsgNewWallScrollS2C(inner, pos, dir, scroll, strokeOrder, blockSize); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgOpenSpellGuiS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgOpenSpellGuiS2C.java index a06e608bdb..4094ff7704 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgOpenSpellGuiS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgOpenSpellGuiS2C.java @@ -2,10 +2,12 @@ import at.petrak.hexcasting.api.casting.eval.ResolvedPattern; import at.petrak.hexcasting.client.gui.GuiSpellcasting; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.InteractionHand; @@ -23,21 +25,28 @@ public record MsgOpenSpellGuiS2C(InteractionHand hand, List pat ) implements IMessage { public static final ResourceLocation ID = modLoc("cgui"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgOpenSpellGuiS2C::serialize, MsgOpenSpellGuiS2C::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgOpenSpellGuiS2C deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgOpenSpellGuiS2C deserialize(FriendlyByteBuf buf) { var hand = buf.readEnum(InteractionHand.class); - var patterns = buf.readList(fbb -> ResolvedPattern.fromNBT(fbb.readAnySizeNbt())); + var patterns = buf.readList(fbb -> ResolvedPattern.fromNBT(fbb.readNbt())); - var stack = buf.readList(FriendlyByteBuf::readNbt); - var raven = buf.readAnySizeNbt(); + var stack = buf.readList(fbb -> fbb.readNbt()); + var raven = buf.readNbt(); var parenCount = buf.readVarInt(); @@ -49,7 +58,7 @@ public void serialize(FriendlyByteBuf buf) { buf.writeCollection(this.patterns, (fbb, pat) -> fbb.writeNbt(pat.serializeToNBT())); - buf.writeCollection(this.stack, FriendlyByteBuf::writeNbt); + buf.writeCollection(this.stack, (fbb, tag) -> fbb.writeNbt(tag)); buf.writeNbt(this.ravenmind); buf.writeVarInt(this.parenCount); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgRecalcWallScrollDisplayS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgRecalcWallScrollDisplayS2C.java index 137c97f534..5736429309 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgRecalcWallScrollDisplayS2C.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgRecalcWallScrollDisplayS2C.java @@ -1,9 +1,11 @@ package at.petrak.hexcasting.common.msgs; import at.petrak.hexcasting.common.entities.EntityWallScroll; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import static at.petrak.hexcasting.api.HexAPI.modLoc; @@ -13,9 +15,16 @@ */ public record MsgRecalcWallScrollDisplayS2C(int entityId, boolean showStrokeOrder) implements IMessage { public static final ResourceLocation ID = modLoc("redoscroll"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgRecalcWallScrollDisplayS2C::serialize, MsgRecalcWallScrollDisplayS2C::deserialize); - public static MsgRecalcWallScrollDisplayS2C deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } + + public static MsgRecalcWallScrollDisplayS2C deserialize(FriendlyByteBuf buf) { var id = buf.readVarInt(); var showStrokeOrder = buf.readBoolean(); return new MsgRecalcWallScrollDisplayS2C(id, showStrokeOrder); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgShiftScrollC2S.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgShiftScrollC2S.java index e1f4d354a6..0e943432cb 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgShiftScrollC2S.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgShiftScrollC2S.java @@ -6,9 +6,11 @@ import at.petrak.hexcasting.common.items.storage.ItemSpellbook; import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexSounds; -import io.netty.buffer.ByteBuf; import net.minecraft.ChatFormatting; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; @@ -27,15 +29,22 @@ public record MsgShiftScrollC2S(double mainHandDelta, double offHandDelta, boolean isCtrl, boolean invertSpellbook, boolean invertAbacus) implements IMessage { public static final ResourceLocation ID = modLoc("scroll"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgShiftScrollC2S::serialize, MsgShiftScrollC2S::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgShiftScrollC2S deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); - var mainHandDelta = buf.readDouble(); + public static MsgShiftScrollC2S deserialize(FriendlyByteBuf buf) { + double mainHandDelta = buf.readDouble(); var offHandDelta = buf.readDouble(); var isCtrl = buf.readBoolean(); var invertSpellbook = buf.readBoolean(); @@ -75,26 +84,26 @@ private void spellbook(ServerPlayer sender, InteractionHand hand, ItemStack stac delta = -delta; } - var newIdx = ItemSpellbook.rotatePageIdx(stack, delta < 0.0); + var newIdx = ItemSpellbook.rotatePageIdx(stack, delta < 0.0, sender.registryAccess()); var len = ItemSpellbook.highestPage(stack); var sealed = ItemSpellbook.isSealed(stack); MutableComponent component; - if (hand == InteractionHand.OFF_HAND && stack.hasCustomHoverName()) { + if (hand == InteractionHand.OFF_HAND && stack.get(net.minecraft.core.component.DataComponents.CUSTOM_NAME) != null) { if (sealed) { component = Component.translatable("hexcasting.tooltip.spellbook.page_with_name.sealed", Component.literal(String.valueOf(newIdx)).withStyle(ChatFormatting.WHITE), Component.literal(String.valueOf(len)).withStyle(ChatFormatting.WHITE), - Component.literal("").withStyle(stack.getRarity().color, ChatFormatting.ITALIC) + Component.literal("").withStyle(stack.getRarity().color(), ChatFormatting.ITALIC) .append(stack.getHoverName()), Component.translatable("hexcasting.tooltip.spellbook.sealed").withStyle(ChatFormatting.GOLD)); } else { component = Component.translatable("hexcasting.tooltip.spellbook.page_with_name", Component.literal(String.valueOf(newIdx)).withStyle(ChatFormatting.WHITE), Component.literal(String.valueOf(len)).withStyle(ChatFormatting.WHITE), - Component.literal("").withStyle(stack.getRarity().color, ChatFormatting.ITALIC) + Component.literal("").withStyle(stack.getRarity().color(), ChatFormatting.ITALIC) .append(stack.getHoverName())); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/particles/ConjureParticleOptions.java b/Common/src/main/java/at/petrak/hexcasting/common/particles/ConjureParticleOptions.java index 79df382994..c4ddd8fc96 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/particles/ConjureParticleOptions.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/particles/ConjureParticleOptions.java @@ -5,9 +5,12 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.mojang.serialization.MapCodec; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleType; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import java.util.Locale; @@ -17,50 +20,28 @@ public ParticleType getType() { return HexParticles.CONJURE_PARTICLE; } - @Override - public void writeToNetwork(FriendlyByteBuf buf) { - buf.writeInt(this.color); - } - - @Override - public String writeToString() { - return String.format(Locale.ROOT, "%s %s", this.color); - } - - public static final Deserializer DESERIALIZER = new Deserializer<>() { - @Override - public ConjureParticleOptions fromCommand(ParticleType type, - StringReader reader) throws CommandSyntaxException { - - reader.expect(' '); - var color = reader.readInt(); - return new ConjureParticleOptions(color); - } - - @Override - public ConjureParticleOptions fromNetwork(ParticleType type, - FriendlyByteBuf buf) { - var col = buf.readInt(); - return new ConjureParticleOptions(col); - } - }; - public static class Type extends ParticleType { public Type(boolean pOverrideLimiter) { - super(pOverrideLimiter, DESERIALIZER); + super(pOverrideLimiter); } - public static final Codec CODEC = RecordCodecBuilder.create( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( - Codec.INT.fieldOf("color") - .forGetter((ConjureParticleOptions o) -> o.color) - ) - .apply(instance, ConjureParticleOptions::new) + Codec.INT.fieldOf("color").forGetter(ConjureParticleOptions::color) + ).apply(instance, ConjureParticleOptions::new) ); + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite(ByteBufCodecs.INT, ConjureParticleOptions::color, ConjureParticleOptions::new); + @Override - public Codec codec() { + public MapCodec codec() { return CODEC; } + + @Override + public StreamCodec streamCodec() { + return STREAM_CODEC; + } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/BrainsweepRecipe.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/BrainsweepRecipe.java index 8f6db1efb0..9743f0171a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/BrainsweepRecipe.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/BrainsweepRecipe.java @@ -4,15 +4,24 @@ import at.petrak.hexcasting.common.recipe.ingredient.StateIngredientHelper; import at.petrak.hexcasting.common.recipe.ingredient.brainsweep.BrainsweepeeIngredient; import com.google.gson.JsonObject; -import net.minecraft.core.RegistryAccess; -import net.minecraft.network.FriendlyByteBuf; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Decoder; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.mojang.serialization.JsonOps; +import net.minecraft.core.HolderLookup; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.GsonHelper; -import net.minecraft.world.Container; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeInput; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.Level; @@ -28,12 +37,11 @@ public record BrainsweepRecipe( BrainsweepeeIngredient entityIn, long mediaCost, BlockState result -) implements Recipe { +) implements Recipe { public boolean matches(BlockState blockIn, Entity victim, ServerLevel level) { return this.blockIn.test(blockIn) && this.entityIn.test(victim, level); } - @Override public ResourceLocation getId() { return id; } @@ -51,12 +59,12 @@ public RecipeSerializer getSerializer() { // in order to get this to be a "Recipe" we need to do a lot of bending-over-backwards // to get the implementation to be satisfied even though we never use it @Override - public boolean matches(Container pContainer, Level pLevel) { + public boolean matches(RecipeInput pContainer, Level pLevel) { return false; } @Override - public ItemStack assemble(Container pContainer, RegistryAccess access) { + public ItemStack assemble(RecipeInput pContainer, HolderLookup.Provider registries) { return ItemStack.EMPTY; } @@ -66,7 +74,7 @@ public boolean canCraftInDimensions(int pWidth, int pHeight) { } @Override - public ItemStack getResultItem(RegistryAccess registryAccess) { + public ItemStack getResultItem(HolderLookup.Provider registries) { return ItemStack.EMPTY.copy(); } @@ -84,30 +92,113 @@ public static BlockState copyProperties(BlockState original, BlockState copyTo) } public static class Serializer extends RecipeSerializerBase { - @Override - public @NotNull BrainsweepRecipe fromJson(ResourceLocation recipeID, JsonObject json) { - var blockIn = StateIngredientHelper.deserialize(GsonHelper.getAsJsonObject(json, "blockIn")); - var villagerIn = BrainsweepeeIngredient.deserialize(GsonHelper.getAsJsonObject(json, "entityIn")); - var cost = GsonHelper.getAsInt(json, "cost"); - var result = StateIngredientHelper.readBlockState(GsonHelper.getAsJsonObject(json, "result")); - return new BrainsweepRecipe(recipeID, blockIn, villagerIn, cost, result); - } + private static final Codec STATE_INGREDIENT_CODEC = Codec.of( + new Encoder<>() { + @Override + public DataResult encode(StateIngredient input, DynamicOps ops, T prefix) { + try { + return DataResult.success(new Dynamic<>(JsonOps.INSTANCE, input.serialize()).convert(ops).getValue()); + } catch (Exception e) { + return DataResult.error(() -> "Failed to encode StateIngredient: " + e.getMessage()); + } + } + }, + new Decoder<>() { + @Override + public DataResult> decode(DynamicOps ops, T input) { + try { + JsonObject obj = new Dynamic<>(ops, input).convert(JsonOps.INSTANCE).getValue().getAsJsonObject(); + return DataResult.success(com.mojang.datafixers.util.Pair.of( + StateIngredientHelper.deserialize(obj), input)); + } catch (Exception e) { + return DataResult.error(() -> e.getMessage()); + } + } + } + ); + + private static final Codec BRAINSWEEPEE_CODEC = Codec.of( + new Encoder<>() { + @Override + public DataResult encode(BrainsweepeeIngredient input, DynamicOps ops, T prefix) { + try { + return DataResult.success(new Dynamic<>(JsonOps.INSTANCE, input.serialize()).convert(ops).getValue()); + } catch (Exception e) { + return DataResult.error(() -> "Failed to encode BrainsweepeeIngredient: " + e.getMessage()); + } + } + }, + new Decoder<>() { + @Override + public DataResult> decode(DynamicOps ops, T input) { + try { + JsonObject obj = new Dynamic<>(ops, input).convert(JsonOps.INSTANCE).getValue().getAsJsonObject(); + return DataResult.success(com.mojang.datafixers.util.Pair.of( + BrainsweepeeIngredient.deserialize(obj), input)); + } catch (Exception e) { + return DataResult.error(() -> e.getMessage()); + } + } + } + ); + + private static final Codec BLOCKSTATE_JSON_CODEC = Codec.of( + new Encoder<>() { + @Override + public DataResult encode(BlockState input, DynamicOps ops, T prefix) { + try { + return DataResult.success(new Dynamic<>(JsonOps.INSTANCE, StateIngredientHelper.serializeBlockState(input)).convert(ops).getValue()); + } catch (Exception e) { + return DataResult.error(() -> "Failed to encode BlockState: " + e.getMessage()); + } + } + }, + new Decoder<>() { + @Override + public DataResult> decode(DynamicOps ops, T input) { + try { + JsonObject obj = new Dynamic<>(ops, input).convert(JsonOps.INSTANCE).getValue().getAsJsonObject(); + return DataResult.success(com.mojang.datafixers.util.Pair.of( + StateIngredientHelper.readBlockState(obj), input)); + } catch (Exception e) { + return DataResult.error(() -> e.getMessage()); + } + } + } + ); + + private static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec(inst -> inst.group( + ResourceLocation.CODEC.fieldOf("id").forGetter(BrainsweepRecipe::id), + STATE_INGREDIENT_CODEC.fieldOf("blockIn").forGetter(BrainsweepRecipe::blockIn), + BRAINSWEEPEE_CODEC.fieldOf("entityIn").forGetter(BrainsweepRecipe::entityIn), + Codec.LONG.fieldOf("cost").forGetter(BrainsweepRecipe::mediaCost), + BLOCKSTATE_JSON_CODEC.fieldOf("result").forGetter(BrainsweepRecipe::result) + ).apply(inst, BrainsweepRecipe::new)); @Override - public void toNetwork(FriendlyByteBuf buf, BrainsweepRecipe recipe) { - recipe.blockIn.write(buf); - recipe.entityIn.wrapWrite(buf); - buf.writeVarLong(recipe.mediaCost); - buf.writeVarInt(Block.getId(recipe.result)); + public MapCodec codec() { + return MAP_CODEC; } @Override - public @NotNull BrainsweepRecipe fromNetwork(ResourceLocation recipeID, FriendlyByteBuf buf) { - var blockIn = StateIngredientHelper.read(buf); - var brainsweepeeIn = BrainsweepeeIngredient.read(buf); - var cost = buf.readVarLong(); - var result = Block.stateById(buf.readVarInt()); - return new BrainsweepRecipe(recipeID, blockIn, brainsweepeeIn, cost, result); + public StreamCodec streamCodec() { + return StreamCodec.of( + (buf, recipe) -> { + buf.writeResourceLocation(recipe.id); + recipe.blockIn.write(buf); + recipe.entityIn.wrapWrite(buf); + buf.writeVarLong(recipe.mediaCost); + buf.writeVarInt(Block.getId(recipe.result)); + }, + buf -> { + var id = buf.readResourceLocation(); + var blockIn = StateIngredientHelper.read(buf); + var brainsweepeeIn = BrainsweepeeIngredient.read(buf); + var cost = buf.readVarLong(); + var result = Block.stateById(buf.readVarInt()); + return new BrainsweepRecipe(id, blockIn, brainsweepeeIn, cost, result); + } + ); } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealSpellbookRecipe.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealSpellbookRecipe.java index 570d6631be..4bdbc61ff3 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealSpellbookRecipe.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealSpellbookRecipe.java @@ -6,9 +6,7 @@ import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.core.NonNullList; -import net.minecraft.core.RegistryAccess; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.core.HolderLookup; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.*; @@ -32,15 +30,15 @@ private static NonNullList createIngredients() { return ingredients; } - public SealSpellbookRecipe(ResourceLocation id, CraftingBookCategory category) { - super(id, "", category, getSealedStack(), createIngredients()); + public SealSpellbookRecipe(CraftingBookCategory category) { + super("", category, getSealedStack(), createIngredients()); } @Override - public @NotNull ItemStack assemble(CraftingContainer inv, RegistryAccess access) { + public @NotNull ItemStack assemble(CraftingInput inv, HolderLookup.Provider registries) { ItemStack out = ItemStack.EMPTY; - for (int i = 0; i < inv.getContainerSize(); i++) { + for (int i = 0; i < inv.size(); i++) { var stack = inv.getItem(i); if (stack.is(HexItems.SPELLBOOK)) { out = stack.copy(); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealThingsRecipe.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealThingsRecipe.java index 365d68fe59..82c009e133 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealThingsRecipe.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealThingsRecipe.java @@ -4,12 +4,11 @@ import at.petrak.hexcasting.common.items.storage.ItemFocus; import at.petrak.hexcasting.common.items.storage.ItemSpellbook; import at.petrak.hexcasting.common.lib.HexItems; -import net.minecraft.core.RegistryAccess; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.core.HolderLookup; import net.minecraft.util.StringRepresentable; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer; @@ -26,8 +25,8 @@ public class SealThingsRecipe extends CustomRecipe { public static final SimpleCraftingRecipeSerializer SPELLBOOK_SERIALIZER = new SimpleCraftingRecipeSerializer<>(SealThingsRecipe::spellbook); - public SealThingsRecipe(ResourceLocation id, CraftingBookCategory category, Sealee sealee) { - super(id, category); + public SealThingsRecipe(CraftingBookCategory category, Sealee sealee) { + super(category); this.sealee = sealee; } @@ -38,11 +37,11 @@ public boolean canCraftInDimensions(int width, int height) { } @Override - public boolean matches(CraftingContainer container, Level level) { + public boolean matches(CraftingInput container, Level level) { boolean foundComb = false; boolean foundSealee = false; - for (int i = 0; i < container.getContainerSize(); i++) { + for (int i = 0; i < container.size(); i++) { var stack = container.getItem(i); if (this.sealee.isCorrectSealee(stack)) { if (foundSealee) return false; @@ -57,10 +56,10 @@ public boolean matches(CraftingContainer container, Level level) { } @Override - public ItemStack assemble(CraftingContainer inv, RegistryAccess registryAccess) { + public ItemStack assemble(CraftingInput inv, HolderLookup.Provider registries) { ItemStack sealee = ItemStack.EMPTY; - for (int i = 0; i < inv.getContainerSize(); i++) { + for (int i = 0; i < inv.size(); i++) { var stack = inv.getItem(i); if (this.sealee.isCorrectSealee(stack)) { sealee = stack.copy(); @@ -84,12 +83,12 @@ public ItemStack assemble(CraftingContainer inv, RegistryAccess registryAccess) }; } - public static SealThingsRecipe focus(ResourceLocation id, CraftingBookCategory category) { - return new SealThingsRecipe(id, category, Sealee.FOCUS); + public static SealThingsRecipe focus(CraftingBookCategory category) { + return new SealThingsRecipe(category, Sealee.FOCUS); } - public static SealThingsRecipe spellbook(ResourceLocation id, CraftingBookCategory category) { - return new SealThingsRecipe(id, category, Sealee.SPELLBOOK); + public static SealThingsRecipe spellbook(CraftingBookCategory category) { + return new SealThingsRecipe(category, Sealee.SPELLBOOK); } public enum Sealee implements StringRepresentable { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/StateIngredientBlockState.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/StateIngredientBlockState.java index c1018f47df..adc8c51ae9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/StateIngredientBlockState.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/StateIngredientBlockState.java @@ -56,7 +56,7 @@ public List getDisplayedStacks() { @Nullable @Override public List descriptionTooltip() { - ImmutableMap, Comparable> map = state.getValues(); + Map, Comparable> map = ImmutableMap.copyOf(state.getValues()); if (map.isEmpty()) { return StateIngredient.super.descriptionTooltip(); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/StateIngredientHelper.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/StateIngredientHelper.java index 97e09d9d36..4d498a913e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/StateIngredientHelper.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/StateIngredientHelper.java @@ -51,20 +51,20 @@ public static StateIngredient tagExcluding(TagKey tag, StateIngredient... public static StateIngredient deserialize(JsonObject object) { switch (GsonHelper.getAsString(object, "type")) { case "tag": - return new StateIngredientTag(new ResourceLocation(GsonHelper.getAsString(object, "tag"))); + return new StateIngredientTag(ResourceLocation.parse(GsonHelper.getAsString(object, "tag"))); case "block": return new StateIngredientBlock( - BuiltInRegistries.BLOCK.get(new ResourceLocation(GsonHelper.getAsString(object, "block")))); + BuiltInRegistries.BLOCK.get(ResourceLocation.parse(GsonHelper.getAsString(object, "block")))); case "state": return new StateIngredientBlockState(readBlockState(object)); case "blocks": List blocks = new ArrayList<>(); for (JsonElement element : GsonHelper.getAsJsonArray(object, "blocks")) { - blocks.add(BuiltInRegistries.BLOCK.get(new ResourceLocation(element.getAsString()))); + blocks.add(BuiltInRegistries.BLOCK.get(ResourceLocation.parse(element.getAsString()))); } return new StateIngredientBlocks(blocks); case "tag_excluding": - ResourceLocation tag = new ResourceLocation(GsonHelper.getAsString(object, "tag")); + ResourceLocation tag = ResourceLocation.parse(GsonHelper.getAsString(object, "tag")); List ingr = new ArrayList<>(); for (JsonElement element : GsonHelper.getAsJsonArray(object, "exclude")) { ingr.add(deserialize(GsonHelper.convertToJsonObject(element, "exclude entry"))); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/brainsweep/VillagerIngredient.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/brainsweep/VillagerIngredient.java index d3cf2e63ef..9272af3e22 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/brainsweep/VillagerIngredient.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/brainsweep/VillagerIngredient.java @@ -184,12 +184,12 @@ public void write(FriendlyByteBuf buf) { public static VillagerIngredient deserialize(JsonObject json) { VillagerProfession profession = null; if (json.has("profession") && !json.get("profession").isJsonNull()) { - profession = BuiltInRegistries.VILLAGER_PROFESSION.get(new ResourceLocation(GsonHelper.getAsString(json, + profession = BuiltInRegistries.VILLAGER_PROFESSION.get(ResourceLocation.parse(GsonHelper.getAsString(json, "profession"))); } VillagerType biome = null; if (json.has("biome") && !json.get("biome").isJsonNull()) { - biome = BuiltInRegistries.VILLAGER_TYPE.get(new ResourceLocation(GsonHelper.getAsString(json, "biome"))); + biome = BuiltInRegistries.VILLAGER_TYPE.get(ResourceLocation.parse(GsonHelper.getAsString(json, "biome"))); } int minLevel = GsonHelper.getAsInt(json, "minLevel"); return new VillagerIngredient(profession, biome, minLevel); diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java b/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java index d095b06044..1f3243f50c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java @@ -46,7 +46,7 @@ public void generate(HolderLookup.Provider provider, Consumer consu .display(new DisplayInfo(new ItemStack(Items.BUDDING_AMETHYST), Component.translatable("advancement.hexcasting:root"), Component.translatable("advancement.hexcasting:root.desc"), - new ResourceLocation("minecraft", "textures/block/calcite.png"), + ResourceLocation.fromNamespaceAndPath("minecraft", "textures/block/calcite.png"), FrameType.TASK, true, true, true)) // the only thing making this vaguely tolerable is the knowledge the json files are worse somehow .addCriterion("has_charged_amethyst", InventoryChangeTrigger.TriggerInstance.hasItems( @@ -58,7 +58,7 @@ public void generate(HolderLookup.Provider provider, Consumer consu .display(new DisplayInfo(new ItemStack(HexItems.CREATIVE_UNLOCKER), Component.translatable("advancement.hexcasting:creative_unlocker"), Component.translatable("advancement.hexcasting:creative_unlocker.desc"), - new ResourceLocation("minecraft", "textures/block/calcite.png"), + ResourceLocation.fromNamespaceAndPath("minecraft", "textures/block/calcite.png"), FrameType.TASK, true, false, true)) .parent(root) .addCriterion("has_creative_unlocker", InventoryChangeTrigger.TriggerInstance.hasItems( diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java index 2ba8629a35..f95a93724f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java @@ -512,7 +512,7 @@ public void buildRecipes(Consumer recipes) { .withOutput(HexItems.AMETHYST_DUST, 5) .withOutput(0.25f, HexItems.CHARGED_AMETHYST)) .whenModLoaded("create") - .save(recipes, new ResourceLocation("create", "crushing/amethyst_cluster")); + .save(recipes, ResourceLocation.fromNamespaceAndPath("create", "crushing/amethyst_cluster")); this.conditions.apply(new CreateCrushingRecipeBuilder() .withInput(Blocks.AMETHYST_BLOCK) @@ -520,7 +520,7 @@ public void buildRecipes(Consumer recipes) { .withOutput(Items.AMETHYST_SHARD, 3) .withOutput(0.5f, HexItems.AMETHYST_DUST, 4)) .whenModLoaded("create") - .save(recipes, new ResourceLocation("create", "crushing/amethyst_block")); + .save(recipes, ResourceLocation.fromNamespaceAndPath("create", "crushing/amethyst_block")); this.conditions.apply(new CreateCrushingRecipeBuilder() .withInput(Items.AMETHYST_SHARD) diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/builders/BrainsweepRecipeBuilder.java b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/builders/BrainsweepRecipeBuilder.java index 09465dfd03..55801b92aa 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/builders/BrainsweepRecipeBuilder.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/builders/BrainsweepRecipeBuilder.java @@ -59,7 +59,7 @@ public void save(Consumer pFinishedRecipeConsumer, ResourceLocat throw new IllegalStateException("No way of obtaining recipe " + pRecipeId); } - this.advancement.parent(new ResourceLocation("recipes/root")) + this.advancement.parent(ResourceLocation.fromNamespaceAndPath("minecraft", "recipes/root")) .addCriterion("has_the_recipe", RecipeUnlockedTrigger.unlocked(pRecipeId)) .rewards(AdvancementRewards.Builder.recipe(pRecipeId)) .requirements(RequirementsStrategy.OR); @@ -67,7 +67,7 @@ public void save(Consumer pFinishedRecipeConsumer, ResourceLocat pRecipeId, this.blockIn, this.entityIn, this.mediaCost, this.result, this.advancement, - new ResourceLocation(pRecipeId.getNamespace(), "recipes/brainsweep/" + pRecipeId.getPath()))); + ResourceLocation.fromNamespaceAndPath(pRecipeId.getNamespace(), "recipes/brainsweep/" + pRecipeId.getPath()))); } public record Result(ResourceLocation id, StateIngredient blockIn, BrainsweepeeIngredient villagerIn, @@ -75,6 +75,7 @@ public record Result(ResourceLocation id, StateIngredient blockIn, BrainsweepeeI ResourceLocation advancementId) implements FinishedRecipe { @Override public void serializeRecipeData(JsonObject json) { + json.addProperty("id", this.id.toString()); json.add("blockIn", this.blockIn.serialize()); json.add("entityIn", this.villagerIn.serialize()); json.addProperty("cost", this.mediaCost); diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexActionTagProvider.java b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexActionTagProvider.java index 4b083c5731..e3ef8bc1a1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexActionTagProvider.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexActionTagProvider.java @@ -43,7 +43,7 @@ private static TagKey ersatzActionTag(TagKeycreateRegistryKey( - new ResourceLocation("foobar", "hexcasting/tags/action")); + ResourceLocation.fromNamespaceAndPath("foobar", "hexcasting/tags/action")); return TagKey.create(fakeKey, real.location()); } else { return real; diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexBlockTagProvider.java b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexBlockTagProvider.java index 5f99c7f229..073cf5bcff 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexBlockTagProvider.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/tag/HexBlockTagProvider.java @@ -141,7 +141,7 @@ protected void addTags(HolderLookup.Provider provider) { HexBlocks.QUENCHED_ALLAY, HexBlocks.QUENCHED_ALLAY_BRICKS, HexBlocks.QUENCHED_ALLAY_BRICKS_SMALL, HexBlocks.QUENCHED_ALLAY_TILES); // this is a hack but fixes #532 - var createBrittle = TagKey.create(Registries.BLOCK, new ResourceLocation("create", "brittle")); + var createBrittle = TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("create", "brittle")); tag(createBrittle).addOptionalTag(BuiltInRegistries.BLOCK.getKey(HexBlocks.SLATE)); } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/HexInterop.java b/Common/src/main/java/at/petrak/hexcasting/interop/HexInterop.java index 6ecbc2d40f..2201f2e7d6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/HexInterop.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/HexInterop.java @@ -1,7 +1,5 @@ package at.petrak.hexcasting.interop; -import at.petrak.hexcasting.interop.inline.InlineHex; -import at.petrak.hexcasting.interop.inline.InlineHexClient; import at.petrak.hexcasting.interop.pehkui.PehkuiInterop; import at.petrak.hexcasting.xplat.IClientXplatAbstractions; import at.petrak.hexcasting.xplat.IXplatAbstractions; @@ -23,6 +21,8 @@ public static final class Fabric { public static final String TRINKETS_API_ID = "trinkets"; } + public static final String INLINE_ID = "inline"; + public static void init() { initPatchouli(); @@ -33,12 +33,26 @@ public static void init() { xplat.initPlatformSpecific(); - InlineHex.init(); + if (xplat.isModPresent(INLINE_ID)) { + try { + Class.forName("at.petrak.hexcasting.interop.inline.InlineHex") + .getMethod("init").invoke(null); + } catch (Exception ignored) { + // Inline classes excluded from build or mod not loaded + } + } } public static void clientInit() { IClientXplatAbstractions.INSTANCE.initPlatformSpecific(); - InlineHexClient.init(); + if (IXplatAbstractions.INSTANCE.isModPresent(INLINE_ID)) { + try { + Class.forName("at.petrak.hexcasting.interop.inline.InlineHexClient") + .getMethod("init").invoke(null); + } catch (Exception ignored) { + // Inline classes excluded from build or mod not loaded + } + } } private static void initPatchouli() { @@ -72,8 +86,7 @@ private static void initPatchouli() { } } - if (anyInterop) { - PatchouliAPI.get().setConfigFlag(PATCHOULI_ANY_INTEROP_FLAG, true); - } + // Always register the flag so Patchouli doesn't warn "Queried for unknown config flag" + PatchouliAPI.get().setConfigFlag(PATCHOULI_ANY_INTEROP_FLAG, anyInterop); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternData.java b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternData.java index 5dc2dba2ff..d07b94c01b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternData.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/inline/InlinePatternData.java @@ -11,6 +11,7 @@ import net.minecraft.ChatFormatting; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; +import net.minecraft.core.component.DataComponents; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; @@ -42,7 +43,7 @@ public ResourceLocation getRendererId(){ public Style getExtraStyle() { ItemStack scrollStack = new ItemStack(HexItems.SCROLL_MEDIUM); HexItems.SCROLL_MEDIUM.writeDatum(scrollStack, new PatternIota(pattern)); - scrollStack.setHoverName(getPatternName(pattern).copy().withStyle(ChatFormatting.WHITE)); + scrollStack.set(DataComponents.CUSTOM_NAME, getPatternName(pattern).copy().withStyle(ChatFormatting.WHITE)); HoverEvent he = new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(scrollStack)); ClickEvent ce = new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, pattern.toString()); return Style.EMPTY.withHoverEvent(he).withClickEvent(ce); @@ -70,7 +71,7 @@ public Component asText(boolean withExtra) { } public static class InlinePatternDataType implements InlineDataType { - private static final ResourceLocation ID = new ResourceLocation(HexAPI.MOD_ID, "pattern"); + private static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(HexAPI.MOD_ID, "pattern"); public static final InlinePatternDataType INSTANCE = new InlinePatternDataType(); @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java index 997bb09411..7f850026ee 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java @@ -5,6 +5,7 @@ import at.petrak.hexcasting.client.render.PatternRenderer; import at.petrak.hexcasting.client.render.PatternSettings; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.core.HolderLookup; import net.minecraft.client.gui.GuiGraphics; import vazkii.patchouli.api.IComponentRenderContext; import vazkii.patchouli.api.ICustomComponent; @@ -31,7 +32,7 @@ public void build(int x, int y, int pagenum) { this.y = y == -1 ? 70 : y; } - public abstract List getPatterns(UnaryOperator lookup); + public abstract List getPatterns(UnaryOperator lookup, HolderLookup.Provider registries); public abstract boolean showStrokeOrder(); @@ -77,11 +78,10 @@ public void render(GuiGraphics graphics, IComponentRenderContext context, float } @Override - public void onVariablesAvailable(UnaryOperator lookup) { - this.patterns = this.getPatterns(lookup); + public void onVariablesAvailable(UnaryOperator lookup, HolderLookup.Provider registries) { + this.patterns = this.getPatterns(lookup, registries); } - // used for deserialization from patchi protected static class RawPattern { protected String startdir; protected String signature; diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/BrainsweepProcessor.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/BrainsweepProcessor.java index 576e82bb42..d8901df595 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/BrainsweepProcessor.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/BrainsweepProcessor.java @@ -6,7 +6,6 @@ import at.petrak.hexcasting.common.recipe.HexRecipeStuffRegistry; import net.minecraft.client.Minecraft; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -26,13 +25,13 @@ public class BrainsweepProcessor implements IComponentProcessor { @Override public void setup(Level level, IVariableProvider vars) { - var id = new ResourceLocation(vars.get("recipe").asString()); + var id = ResourceLocation.parse(vars.get("recipe", level.registryAccess()).asString()); var recman = level.getRecipeManager(); var brainsweepings = recman.getAllRecipesFor(HexRecipeStuffRegistry.BRAINSWEEP_TYPE); - for (var poisonApples : brainsweepings) { - if (poisonApples.getId().equals(id)) { - this.recipe = poisonApples; + for (var holder : brainsweepings) { + if (holder.id().equals(id)) { + this.recipe = holder.value(); break; } } @@ -40,47 +39,50 @@ public void setup(Level level, IVariableProvider vars) { @Override public IVariable process(Level level, String key) { + var provider = level.registryAccess(); + // Always provide entity fallback so Patchouli never gets empty string (causes "Unknown entity id") + if ("entity".equals(key)) { + if (this.recipe != null && this.exampleEntityString == null) { + try { + var clientLevel = Minecraft.getInstance().level; + var entity = clientLevel != null + ? this.recipe.entityIn().exampleEntity(clientLevel) + : null; + if (entity != null) { + this.exampleEntityString = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString(); + } + } catch (Exception ignored) { + // Fall through + } + if (this.exampleEntityString == null) { + this.exampleEntityString = "minecraft:villager"; + } + } + return IVariable.wrap(this.exampleEntityString != null ? this.exampleEntityString : "minecraft:villager", provider); + } if (this.recipe == null) { return null; } switch (key) { case "header" -> { - return IVariable.from(this.recipe.result().getBlock().getName()); + return IVariable.from(this.recipe.result().getBlock().getName(), provider); } case "input" -> { var inputStacks = this.recipe.blockIn().getDisplayedStacks(); - return IVariable.from(inputStacks.toArray(new ItemStack[0])); + return IVariable.from(inputStacks.toArray(new ItemStack[0]), provider); } case "result" -> { - return IVariable.from(new ItemStack(this.recipe.result().getBlock())); + return IVariable.from(new ItemStack(this.recipe.result().getBlock()), provider); } - case "entity" -> { - if (this.exampleEntityString == null) { - var entity = this.recipe.entityIn().exampleEntity(Minecraft.getInstance().level); - if (entity == null) { - // oh dear - return null; - } - var bob = new StringBuilder(); - bob.append(BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType())); - - var tag = new CompoundTag(); - entity.save(tag); - bob.append(tag.toString()); - this.exampleEntityString = bob.toString(); - } - - return IVariable.wrap(this.exampleEntityString); - } case "entityTooltip" -> { Minecraft mc = Minecraft.getInstance(); return IVariable.wrapList(this.recipe.entityIn() .getTooltip(mc.options.advancedItemTooltips) .stream() - .map(IVariable::from) - .toList()); + .map(c -> IVariable.from(c, provider)) + .toList(), provider); } case "mediaCost" -> { record ItemCost(Item item, int cost) { @@ -94,18 +96,17 @@ public boolean dividesEvenly (int dividend) { new ItemCost(HexItems.CHARGED_AMETHYST, (int)MediaConstants.CRYSTAL_UNIT), }; - // get evenly divisible ItemStacks List validItemStacks = Arrays.stream(costs) .filter(itemCost -> itemCost.dividesEvenly((int)this.recipe.mediaCost())) .map(validItemCost -> new ItemStack(validItemCost.item, (int) this.recipe.mediaCost() / validItemCost.cost)) - .map(IVariable::from) + .map(stack -> IVariable.from(stack, provider)) .toList(); if (!validItemStacks.isEmpty()) { - return IVariable.wrapList(validItemStacks); + return IVariable.wrapList(validItemStacks, provider); } // fallback: display in terms of dust - return IVariable.from(new ItemStack(HexItems.AMETHYST_DUST, (int) (this.recipe.mediaCost() / MediaConstants.DUST_UNIT))); + return IVariable.from(new ItemStack(HexItems.AMETHYST_DUST, (int) (this.recipe.mediaCost() / MediaConstants.DUST_UNIT)), provider); } default -> { return null; diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/CustomComponentTooltip.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/CustomComponentTooltip.java index 13972ce372..8d70329df9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/CustomComponentTooltip.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/CustomComponentTooltip.java @@ -2,6 +2,7 @@ import com.google.gson.annotations.SerializedName; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.core.HolderLookup; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import vazkii.patchouli.api.IComponentRenderContext; @@ -20,15 +21,22 @@ public class CustomComponentTooltip implements ICustomComponent { transient IVariable tooltipVar; transient List tooltip; + transient HolderLookup.Provider registries; transient int x, y; + @Override + public void onVariablesAvailable(UnaryOperator lookup, HolderLookup.Provider registries) { + this.registries = registries; + tooltipVar = lookup.apply(tooltipReference); + } + @Override public void build(int componentX, int componentY, int pageNum) { x = componentX; y = componentY; tooltip = new ArrayList<>(); - for (IVariable s : tooltipVar.asListOrSingleton()) { + for (IVariable s : tooltipVar.asListOrSingleton(registries)) { tooltip.add(s.as(Component.class)); } } @@ -40,8 +48,4 @@ public void render(GuiGraphics graphics, IComponentRenderContext context, float } } - @Override - public void onVariablesAvailable(UnaryOperator lookup) { - tooltipVar = lookup.apply(tooltipReference); - } } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/LookupPatternComponent.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/LookupPatternComponent.java index 632c7abf79..45965d42f4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/LookupPatternComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/LookupPatternComponent.java @@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.mod.HexTags; import at.petrak.hexcasting.xplat.IXplatAbstractions; import com.google.gson.annotations.SerializedName; +import net.minecraft.core.HolderLookup; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import vazkii.patchouli.api.IVariable; @@ -22,7 +23,7 @@ public class LookupPatternComponent extends AbstractPatternComponent { protected boolean strokeOrder; @Override - public List getPatterns(UnaryOperator lookup) { + public List getPatterns(UnaryOperator lookup, HolderLookup.Provider registries) { var key = ResourceKey.create(IXplatAbstractions.INSTANCE.getActionRegistry().key(), this.opName); var entry = IXplatAbstractions.INSTANCE.getActionRegistry().get(key); @@ -37,10 +38,10 @@ public boolean showStrokeOrder() { } @Override - public void onVariablesAvailable(UnaryOperator lookup) { - var opName = lookup.apply(IVariable.wrap(this.opNameRaw)).asString(); + public void onVariablesAvailable(UnaryOperator lookup, HolderLookup.Provider registries) { + var opName = lookup.apply(IVariable.wrap(this.opNameRaw, registries)).asString(); this.opName = ResourceLocation.tryParse(opName); - super.onVariablesAvailable(lookup); + super.onVariablesAvailable(lookup, registries); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/ManualPatternComponent.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/ManualPatternComponent.java index f737701fc7..15ffcd5c3c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/ManualPatternComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/ManualPatternComponent.java @@ -5,6 +5,7 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.annotations.SerializedName; +import net.minecraft.core.HolderLookup; import vazkii.patchouli.api.IVariable; import java.util.ArrayList; @@ -23,9 +24,9 @@ public class ManualPatternComponent extends AbstractPatternComponent { protected transient boolean strokeOrder; @Override - public List getPatterns(UnaryOperator lookup) { - this.strokeOrder = lookup.apply(IVariable.wrap(this.strokeOrderRaw)).asBoolean(true); - var patsRaw = lookup.apply(IVariable.wrap(patternsRaw)).asListOrSingleton(); + public List getPatterns(UnaryOperator lookup, HolderLookup.Provider registries) { + this.strokeOrder = lookup.apply(IVariable.wrap(this.strokeOrderRaw, registries)).asBoolean(true); + var patsRaw = lookup.apply(IVariable.wrap(patternsRaw, registries)).asListOrSingleton(registries); var out = new ArrayList(); for (var ivar : patsRaw) { @@ -46,9 +47,9 @@ public boolean showStrokeOrder() { } @Override - public void onVariablesAvailable(UnaryOperator lookup) { - this.strokeOrder = IVariable.wrap(this.strokeOrderRaw).asBoolean(true); + public void onVariablesAvailable(UnaryOperator lookup, HolderLookup.Provider registries) { + this.strokeOrder = IVariable.wrap(this.strokeOrderRaw, registries).asBoolean(true); - super.onVariablesAvailable(lookup); + super.onVariablesAvailable(lookup, registries); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/MultiCraftingProcessor.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/MultiCraftingProcessor.java index 055128b7a5..39b8bb3bfd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/MultiCraftingProcessor.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/MultiCraftingProcessor.java @@ -32,10 +32,11 @@ public class MultiCraftingProcessor implements IComponentProcessor { @Override public void setup(Level level, IVariableProvider vars) { - List names = vars.get("recipes").asStream().map(IVariable::asString).collect(Collectors.toList()); + var provider = level.registryAccess(); + List names = vars.get("recipes", provider).asStream(provider).map(IVariable::asString).collect(Collectors.toList()); this.recipes = new ArrayList<>(); for (String name : names) { - CraftingRecipe recipe = PatchouliUtils.getRecipe(RecipeType.CRAFTING, new ResourceLocation(name)); + CraftingRecipe recipe = PatchouliUtils.getRecipe(RecipeType.CRAFTING, ResourceLocation.parse(name)); if (recipe != null) { recipes.add(recipe); if (shapeless) { @@ -59,9 +60,10 @@ public IVariable process(Level level, String key) { if (recipes.isEmpty()) { return null; } + var provider = level.registryAccess(); if (key.equals("heading")) { if (!hasCustomHeading) { - return IVariable.from(recipes.get(0).getResultItem(level.registryAccess()).getHoverName()); + return IVariable.from(recipes.get(0).getResultItem(provider).getHoverName(), provider); } return null; } @@ -85,14 +87,15 @@ public IVariable process(Level level, String key) { ingredients.add(list.size() > index ? list.get(index) : Ingredient.EMPTY); } } - return PatchouliUtils.interweaveIngredients(ingredients, longestIngredientSize); + return PatchouliUtils.interweaveIngredients(ingredients, longestIngredientSize, provider); } if (key.equals("output")) { return IVariable.wrapList( - recipes.stream().map(recipe -> recipe.getResultItem(level.registryAccess())).map(IVariable::from).collect(Collectors.toList())); + recipes.stream().map(recipe -> recipe.getResultItem(provider)).map(stack -> IVariable.from(stack, provider)).collect(Collectors.toList()), + provider); } if (key.equals("shapeless")) { - return IVariable.wrap(shapeless); + return IVariable.wrap(shapeless, provider); } return null; } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatchouliUtils.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatchouliUtils.java index 574b296e1b..23811f169c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatchouliUtils.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatchouliUtils.java @@ -1,8 +1,8 @@ package at.petrak.hexcasting.interop.patchouli; import net.minecraft.client.Minecraft; +import net.minecraft.core.HolderLookup; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Recipe; @@ -22,14 +22,16 @@ */ public class PatchouliUtils { @SuppressWarnings("unchecked") - public static , C extends Container> T getRecipe(RecipeType type, ResourceLocation id) { + public static > T getRecipe(RecipeType type, ResourceLocation id) { // PageDoubleRecipeRegistry if (Minecraft.getInstance().level == null) { return null; } else { var manager = Minecraft.getInstance().level.getRecipeManager(); return (T) manager.byKey(id) - .filter((recipe) -> recipe.getType() == type).orElse(null); + .filter((holder) -> holder.value().getType() == type) + .map(h -> (T) h.value()) + .orElse(null); } } @@ -40,12 +42,13 @@ public static , C extends Container> T getRecipe(RecipeType< * * @param ingredients List of ingredients in the specific slot * @param longestIngredientSize Longest ingredient in the entire recipe + * @param registries HolderLookup.Provider for serialization * @return Serialized Patchouli ingredient string */ - public static IVariable interweaveIngredients(List ingredients, int longestIngredientSize) { + public static IVariable interweaveIngredients(List ingredients, int longestIngredientSize, HolderLookup.Provider registries) { if (ingredients.size() == 1) { - return IVariable.wrapList(Arrays.stream(ingredients.get(0).getItems()).map(IVariable::from).collect( - Collectors.toList())); + return IVariable.wrapList(Arrays.stream(ingredients.get(0).getItems()).map(s -> IVariable.from(s, registries)).collect( + Collectors.toList()), registries); } ItemStack[] empty = {ItemStack.EMPTY}; @@ -60,17 +63,17 @@ public static IVariable interweaveIngredients(List ingredients, int List list = new ArrayList<>(stacks.size() * longestIngredientSize); for (int i = 0; i < longestIngredientSize; i++) { for (ItemStack[] stack : stacks) { - list.add(IVariable.from(stack[i % stack.length])); + list.add(IVariable.from(stack[i % stack.length], registries)); } } - return IVariable.wrapList(list); + return IVariable.wrapList(list, registries); } /** * Overload of the method above that uses the provided list's longest ingredient size. */ - public static IVariable interweaveIngredients(List ingredients) { + public static IVariable interweaveIngredients(List ingredients, HolderLookup.Provider registries) { return interweaveIngredients(ingredients, - ingredients.stream().mapToInt(ingr -> ingr.getItems().length).max().orElse(1)); + ingredients.stream().mapToInt(ingr -> ingr.getItems().length).max().orElse(1), registries); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatternProcessor.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatternProcessor.java index 94e9e258b8..a46f9a5e9a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatternProcessor.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatternProcessor.java @@ -11,10 +11,11 @@ public class PatternProcessor implements IComponentProcessor { @Override public void setup(Level level, IVariableProvider vars) { + var provider = level.registryAccess(); if (vars.has("header")) - translationKey = vars.get("header").asString(); + translationKey = vars.get("header", provider).asString(); else { - IVariable key = vars.get("op_id"); + IVariable key = vars.get("op_id", provider); String opName = key.asString(); String prefix = "hexcasting.action."; @@ -26,7 +27,7 @@ public void setup(Level level, IVariableProvider vars) { @Override public IVariable process(Level level, String key) { if (key.equals("translation_key")) { - return IVariable.wrap(translationKey); + return IVariable.wrap(translationKey, level.registryAccess()); } return null; diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinAbstractVillager.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinAbstractVillager.java index 344e60efcb..1d6db70287 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinAbstractVillager.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinAbstractVillager.java @@ -11,7 +11,7 @@ // Prevents the villager from having any offers if it's brainswept @Mixin(AbstractVillager.class) public class MixinAbstractVillager { - @Inject(method = "getOffers", at = @At("HEAD"), cancellable = true) + @Inject(method = "getOffers", at = @At("HEAD"), cancellable = true, remap = false) private void nixOffers(CallbackInfoReturnable cir) { var self = (AbstractVillager) (Object) this; if (IXplatAbstractions.INSTANCE.isBrainswept(self)) { diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinLivingEntity.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinLivingEntity.java index c3dbc47b81..daf0ec4bc0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinLivingEntity.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinLivingEntity.java @@ -12,7 +12,7 @@ // Nuke the brain at the source @Mixin(LivingEntity.class) public abstract class MixinLivingEntity { - @Inject(method = "getBrain", at = @At("RETURN")) + @Inject(method = "getBrain", at = @At("RETURN"), remap = false) private void removeBrain(CallbackInfoReturnable> cir) { var self = (LivingEntity) (Object) this; if (self instanceof Mob mob && IXplatAbstractions.INSTANCE.isBrainswept(mob)) { diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinMob.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinMob.java index 9404606e8c..3512879f6c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinMob.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinMob.java @@ -10,7 +10,7 @@ // Prevents brainswept mobs from having an AI tick @Mixin(Mob.class) public class MixinMob { - @Inject(method = "serverAiStep", at = @At("HEAD"), cancellable = true) + @Inject(method = "serverAiStep", at = @At("HEAD"), cancellable = true, remap = false) private void onRegisterBrainGoals(CallbackInfo ci) { var self = (Mob) (Object) this; if (IXplatAbstractions.INSTANCE.isBrainswept(self)) { @@ -18,7 +18,7 @@ private void onRegisterBrainGoals(CallbackInfo ci) { } } - @Inject(method = "playAmbientSound", at = @At("HEAD"), cancellable = true) + @Inject(method = "playAmbientSound", at = @At("HEAD"), cancellable = true, remap = false) protected void onPlayAmbientSound(CallbackInfo ci) { var self = (Mob) (Object) this; if (IXplatAbstractions.INSTANCE.isBrainswept(self)) { diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinRaider.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinRaider.java index cb1d92eda8..2bf3b308a9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinRaider.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinRaider.java @@ -9,8 +9,7 @@ // Prevents the witch from joining a raid @Mixin(Raider.class) public class MixinRaider { - @Redirect(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/raid/Raider;isAlive" + - "()Z")) + @Redirect(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;isAlive()Z"), remap = false) private boolean isAliveForAiPurposes(Raider instance) { var self = (Raider) (Object) this; return self.isAlive() && !IXplatAbstractions.INSTANCE.isBrainswept(self); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinVillager.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinVillager.java index 4f577f7246..fed6fc1d36 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinVillager.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinVillager.java @@ -11,7 +11,7 @@ // Prevents the villager from any of its brain goals @Mixin(Villager.class) public class MixinVillager { - @Inject(method = "canBreed", at = @At("HEAD"), cancellable = true) + @Inject(method = "canBreed", at = @At("HEAD"), cancellable = true, remap = false) private void preventBreeding(CallbackInfoReturnable cir) { var self = (Villager) (Object) this; if (IXplatAbstractions.INSTANCE.isBrainswept(self)) { @@ -19,7 +19,7 @@ private void preventBreeding(CallbackInfoReturnable cir) { } } - @Inject(method = "setUnhappy", at = @At("HEAD"), cancellable = true) + @Inject(method = "setUnhappy", at = @At("HEAD"), cancellable = true, remap = false) private void preventUnhappiness(CallbackInfo ci) { var self = (Villager) (Object) this; if (IXplatAbstractions.INSTANCE.isBrainswept(self)) { diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinWanderingTrader.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinWanderingTrader.java index 6ccfa837fc..83b7630852 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinWanderingTrader.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinWanderingTrader.java @@ -3,6 +3,7 @@ import net.minecraft.world.entity.npc.WanderingTrader; import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.ItemCost; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.util.RandomSource; @@ -20,7 +21,7 @@ // Adds ancient scrolls to the wandering trader by replacing the special trade in the last slot @Mixin(WanderingTrader.class) public class MixinWanderingTrader { - @Inject(method = "updateTrades", at = @At("RETURN")) + @Inject(method = "updateTrades", at = @At("RETURN"), remap = false) private void addNewTrades(CallbackInfo ci) { var self = (WanderingTrader) (Object) this; MerchantOffers offerList = self.getOffers(); @@ -31,7 +32,7 @@ private void addNewTrades(CallbackInfo ci) { ItemStack scroll = new ItemStack(HexItems.SCROLL_LARGE); AddPerWorldPatternToScrollFunc.doStatic(scroll, rand, self.getServer().overworld()); NBTHelper.putBoolean(scroll, ItemScroll.TAG_NEEDS_PURCHASE, true); - offerList.set(5, new MerchantOffer(new ItemStack(Items.EMERALD, 12), scroll, 1, 1, 1)); + offerList.set(5, new MerchantOffer(new ItemCost(Items.EMERALD, 12), scroll, 1, 1, 1.0F)); } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinWitch.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinWitch.java index fe23cebeb8..0b2fd31faa 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinWitch.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinWitch.java @@ -9,8 +9,7 @@ // Prevents the witch from drinking potions @Mixin(Witch.class) public class MixinWitch { - @Redirect(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/monster/Witch;" + - "isAlive()Z")) + @Redirect(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;isAlive()Z"), remap = false) private boolean isAliveForAiPurposes(Witch instance) { var self = (Witch) (Object) this; return self.isAlive() && !IXplatAbstractions.INSTANCE.isBrainswept(self); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorAbstractArrow.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorAbstractArrow.java index b956033d3b..3bbcc1ea4a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorAbstractArrow.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorAbstractArrow.java @@ -4,7 +4,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin(AbstractArrow.class) +@Mixin(value = AbstractArrow.class, remap = false) public interface AccessorAbstractArrow { @Accessor("inGround") boolean hex$isInGround(); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorEntity.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorEntity.java index 691669853b..14e9618de7 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorEntity.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorEntity.java @@ -4,7 +4,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(Entity.class) +@Mixin(value = Entity.class, remap = false) public interface AccessorEntity { @Invoker("markHurt") void hex$markHurt(); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorLivingEntity.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorLivingEntity.java index fde107fc87..873efb39ca 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorLivingEntity.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorLivingEntity.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(LivingEntity.class) +@Mixin(value = LivingEntity.class, remap = false) public interface AccessorLivingEntity { @Accessor("lastHurt") float hex$getLastHurt(); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorLootTable.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorLootTable.java index d2be3c734d..e3ba72cbfc 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorLootTable.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorLootTable.java @@ -8,16 +8,17 @@ import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.gen.Accessor; +import java.util.List; import java.util.function.BiFunction; -@Mixin(LootTable.class) +@Mixin(value = LootTable.class, remap = false) public interface AccessorLootTable { @Accessor("functions") - LootItemFunction[] hex$getFunctions(); + List hex$getFunctions(); @Accessor("functions") @Mutable - void hex$setFunctions(LootItemFunction[] lifs); + void hex$setFunctions(List lifs); @Accessor("compositeFunction") @Mutable diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorPotionBrewing.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorPotionBrewing.java deleted file mode 100644 index 88fe176a12..0000000000 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorPotionBrewing.java +++ /dev/null @@ -1,14 +0,0 @@ -package at.petrak.hexcasting.mixin.accessor; - -import net.minecraft.world.item.Item; -import net.minecraft.world.item.alchemy.Potion; -import net.minecraft.world.item.alchemy.PotionBrewing; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(PotionBrewing.class) -public interface AccessorPotionBrewing { - @Invoker("addMix") - static void addMix(Potion p_43514_, Item p_43515_, Potion p_43516_) { - } -} diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorUseOnContext.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorUseOnContext.java index 1cf59b94a9..9d7af61aa0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorUseOnContext.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorUseOnContext.java @@ -11,7 +11,7 @@ import javax.annotation.Nullable; -@Mixin(UseOnContext.class) +@Mixin(value = UseOnContext.class, remap = false) public interface AccessorUseOnContext { @Invoker("") static UseOnContext hex$new(Level $$0, @Nullable Player $$1, InteractionHand $$2, ItemStack $$3, diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorVillager.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorVillager.java index dc03602412..7b2f04b348 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorVillager.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/AccessorVillager.java @@ -5,7 +5,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(Villager.class) +@Mixin(value = Villager.class, remap = false) public interface AccessorVillager { @Invoker("tellWitnessesThatIWasMurdered") void hex$tellWitnessesThatIWasMurdered(Entity murderer); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/CriteriaTriggersAccessor.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/CriteriaTriggersAccessor.java index 5aaf071208..6c21b9941c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/CriteriaTriggersAccessor.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/CriteriaTriggersAccessor.java @@ -5,10 +5,10 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(CriteriaTriggers.class) +@Mixin(value = CriteriaTriggers.class, remap = false) public interface CriteriaTriggersAccessor { @Invoker("register") - static > T hex$register(T trigger) { + static > T hex$register(String id, T trigger) { throw new UnsupportedOperationException(); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorBlockEntityRenderDispatcher.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorBlockEntityRenderDispatcher.java index 52294d04f6..d31345cc8d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorBlockEntityRenderDispatcher.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorBlockEntityRenderDispatcher.java @@ -7,7 +7,7 @@ import java.util.function.Supplier; -@Mixin(BlockEntityRenderDispatcher.class) +@Mixin(value = BlockEntityRenderDispatcher.class, remap = false) public interface AccessorBlockEntityRenderDispatcher { @Accessor("blockRenderDispatcher") Supplier hex$getBlockRenderDispatcher(); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorCompositeRenderType.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorCompositeRenderType.java index c7965fd588..51750e6525 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorCompositeRenderType.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorCompositeRenderType.java @@ -4,7 +4,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(RenderType.CompositeRenderType.class) +@Mixin(value = RenderType.CompositeRenderType.class, remap = false) public interface AccessorCompositeRenderType { @Invoker("state") RenderType.CompositeState hex$state(); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorEmptyTextureStateShard.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorEmptyTextureStateShard.java index 2ee90b1593..e58ba23dbf 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorEmptyTextureStateShard.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorEmptyTextureStateShard.java @@ -7,7 +7,7 @@ import java.util.Optional; -@Mixin(RenderStateShard.EmptyTextureStateShard.class) +@Mixin(value = RenderStateShard.EmptyTextureStateShard.class, remap = false) public interface AccessorEmptyTextureStateShard { @Invoker("cutoutTexture") Optional hex$cutoutTexture(); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorMouseHandler.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorMouseHandler.java index 54343bb81c..26498e6fec 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorMouseHandler.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorMouseHandler.java @@ -4,11 +4,11 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin(MouseHandler.class) +@Mixin(value = MouseHandler.class, remap = false) public interface AccessorMouseHandler { - @Accessor("accumulatedScroll") + @Accessor("accumulatedScrollY") double hex$getAccumulatedScroll(); - @Accessor("accumulatedScroll") + @Accessor("accumulatedScrollY") void hex$setAccumulatedScroll(double scroll); } diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorRenderStateShard.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorRenderStateShard.java index 653ce5fb62..0bfc444e79 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorRenderStateShard.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorRenderStateShard.java @@ -4,7 +4,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin(RenderStateShard.class) +@Mixin(value = RenderStateShard.class, remap = false) public interface AccessorRenderStateShard { @Accessor("name") String hex$name(); diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorRenderType.java b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorRenderType.java index 5908725e0a..97b3954961 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorRenderType.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/accessor/client/AccessorRenderType.java @@ -6,7 +6,7 @@ import org.spongepowered.asm.mixin.gen.Invoker; // https://github.com/VazkiiMods/Botania/blob/13b7bcd9cbb6b1a418b0afe455662d29b46f1a7f/Xplat/src/main/java/vazkii/botania/mixin/client/AccessorRenderType.java -@Mixin(RenderType.class) +@Mixin(value = RenderType.class, remap = false) public interface AccessorRenderType { @Invoker("create") static RenderType.CompositeRenderType hex$create(String string, VertexFormat vertexFormat, diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinClientLevel.java b/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinClientLevel.java index 240232f2d4..44d334c284 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinClientLevel.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinClientLevel.java @@ -21,6 +21,7 @@ public abstract class MixinClientLevel { @Inject(method = "doAnimateTick", + remap = false, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Block;animateTick" + "(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;" + "Lnet/minecraft/core/BlockPos;Lnet/minecraft/util/RandomSource;)V"), diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinPlayerRenderer.java b/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinPlayerRenderer.java index eb46c8522d..b1a820f531 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinPlayerRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/client/MixinPlayerRenderer.java @@ -13,6 +13,7 @@ @Mixin(PlayerRenderer.class) public abstract class MixinPlayerRenderer { @Inject(method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", + remap = false, at = @At("HEAD")) public void hex$onRender(AbstractClientPlayer player, float $$1, float pticks, PoseStack ps, MultiBufferSource bufferSource, int $$5, CallbackInfo ci) { ClientRenderHelper.renderCastingStack(ps, player, pticks); diff --git a/Common/src/main/java/at/petrak/hexcasting/server/ScrungledPatternsSave.java b/Common/src/main/java/at/petrak/hexcasting/server/ScrungledPatternsSave.java index 2407d3571a..8ee5873d91 100644 --- a/Common/src/main/java/at/petrak/hexcasting/server/ScrungledPatternsSave.java +++ b/Common/src/main/java/at/petrak/hexcasting/server/ScrungledPatternsSave.java @@ -7,8 +7,10 @@ import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.xplat.IXplatAbstractions; import com.mojang.datafixers.util.Pair; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceKey; +import net.minecraft.util.datafix.DataFixTypes; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.saveddata.SavedData; @@ -61,7 +63,7 @@ public Pair lookupReverse(ResourceKey { var inner = new CompoundTag(); @@ -72,7 +74,7 @@ public CompoundTag save(CompoundTag tag) { return tag; } - private static ScrungledPatternsSave load(CompoundTag tag) { + private static ScrungledPatternsSave load(CompoundTag tag, HolderLookup.Provider registries) { var registryKey = IXplatAbstractions.INSTANCE.getActionRegistry().key(); var map = new HashMap(); @@ -83,7 +85,7 @@ private static ScrungledPatternsSave load(CompoundTag tag) { var rawKey = inner.getString(TAG_KEY); var dir = HexDir.values()[rawDir]; - var key = ResourceKey.create(registryKey, new ResourceLocation(rawKey)); + var key = ResourceKey.create(registryKey, ResourceLocation.parse(rawKey)); map.put(sig, new PerWorldEntry(key, dir)); } @@ -116,8 +118,10 @@ public static ScrungledPatternsSave createFromScratch(long seed) { public static ScrungledPatternsSave open(ServerLevel overworld) { return overworld.getDataStorage().computeIfAbsent( - ScrungledPatternsSave::load, - () -> ScrungledPatternsSave.createFromScratch(overworld.getSeed()), + new SavedData.Factory<>( + () -> ScrungledPatternsSave.createFromScratch(overworld.getSeed()), + ScrungledPatternsSave::load, + DataFixTypes.LEVEL), TAG_SAVED_DATA); } diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/ancient_cyphers.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/ancient_cyphers.json index 98b2fca094..3624479195 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/ancient_cyphers.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/ancient_cyphers.json @@ -12,7 +12,7 @@ { "type": "patchouli:spotlight", "text": "hexcasting.page.ancient_cyphers.2", - "item": "hexcasting:ancient_cypher{variant:0},hexcasting:ancient_cypher{variant:1},hexcasting:ancient_cypher{variant:2},hexcasting:ancient_cypher{variant:3},hexcasting:ancient_cypher{variant:4},hexcasting:ancient_cypher{variant:5},hexcasting:ancient_cypher{variant:6},hexcasting:ancient_cypher{variant:7}" + "item": "hexcasting:ancient_cypher" }, { "type": "patchouli:crafting", diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/creative_items.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/creative_items.json index 31ba2000c5..16ba82c2fb 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/creative_items.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/creative_items.json @@ -24,7 +24,7 @@ "type": "patchouli:spotlight", "title": "hexcasting.page.creative_items.debug_media.title", "text": "hexcasting.page.creative_items.debug_media.desc", - "item": "hexcasting:creative_unlocker{display:{Name:'{\\\"text\\\":\\\"debug media\\\"}'}}" + "item": "hexcasting:creative_unlocker" } ] } \ No newline at end of file diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/hexcasting.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/hexcasting.json index b28262d6b8..03e8990b3a 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/hexcasting.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/hexcasting.json @@ -1,7 +1,7 @@ { "name": "hexcasting.entry.hexcasting", "category": "hexcasting:items", - "icon": "hexcasting:artifact{patterns:[]}", + "icon": "hexcasting:artifact", "sortnum": 6, "advancement": "hexcasting:root", "pages": [ diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/phials.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/phials.json index 0f930d1ec8..c49fc9cdea 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/phials.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/phials.json @@ -21,7 +21,7 @@ { "type": "patchouli:spotlight", "text": "hexcasting.page.phials.desc", - "item": "hexcasting:battery{\"hexcasting:media\":640000,\"hexcasting:start_media\":640000}", + "item": "hexcasting:battery", "link_recipe": true } ] diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/potions.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/potions.json index a0db5dd70b..0a4ed16c7d 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/potions.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/items/potions.json @@ -1,7 +1,7 @@ { "name": "hexcasting.entry.potions", "category": "hexcasting:items", - "icon": "minecraft:potion{Potion:\"hexcasting:enlarge_grid\"}", + "icon": "minecraft:potion[potion_contents={potion:\"hexcasting:enlarge_grid\"}]", "sortnum": 8, "advancement": "hexcasting:root", "read_by_default": true, @@ -14,7 +14,7 @@ "type": "patchouli:spotlight", "title": "hexcasting.page.potions.effects.header", "text": "hexcasting.page.potions.2", - "item": "minecraft:potion{Potion:\"hexcasting:enlarge_grid\"},minecraft:potion{Potion:\"hexcasting:enlarge_grid_long\"},minecraft:potion{Potion:\"hexcasting:enlarge_grid_strong\"},minecraft:potion{Potion:\"hexcasting:shrink_grid\"},minecraft:potion{Potion:\"hexcasting:shrink_grid_long\"},minecraft:potion{Potion:\"hexcasting:shrink_grid_strong\"}" + "item": "minecraft:potion[potion_contents={potion:\"hexcasting:enlarge_grid\"}],minecraft:potion[potion_contents={potion:\"hexcasting:enlarge_grid_long\"}],minecraft:potion[potion_contents={potion:\"hexcasting:enlarge_grid_strong\"}],minecraft:potion[potion_contents={potion:\"hexcasting:shrink_grid\"}],minecraft:potion[potion_contents={potion:\"hexcasting:shrink_grid_long\"}],minecraft:potion[potion_contents={potion:\"hexcasting:shrink_grid_strong\"}]" } ] } diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/make_battery.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/make_battery.json index 2ffd387b21..72ca052f7d 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/make_battery.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/make_battery.json @@ -1,7 +1,7 @@ { "name": "hexcasting.action.hexcasting:craft/battery", "category": "hexcasting:patterns/great_spells", - "icon": "hexcasting:battery{media:10000,max_media:10000}", + "icon": "hexcasting:battery", "sortnum": 6, "advancement": "hexcasting:root", "read_by_default": true, diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/zeniths.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/zeniths.json index b5899a67c3..12244fb0db 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/zeniths.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/zeniths.json @@ -1,7 +1,7 @@ { "name": "hexcasting.entry.zeniths", "category": "hexcasting:patterns/great_spells", - "icon": "minecraft:potion{Potion:'minecraft:regeneration'}", + "icon": "minecraft:potion[potion_contents={potion:\"minecraft:regeneration\"}]", "advancement": "hexcasting:root", "sortnum": 4, "read_by_default": true, diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/hexcasting.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/hexcasting.json index 06cd64b47f..fbbdbc5d40 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/hexcasting.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/hexcasting.json @@ -1,7 +1,7 @@ { "name": "hexcasting.entry.hexcasting_spell", "category": "hexcasting:patterns/spells", - "icon": "hexcasting:artifact{patterns:[]}", + "icon": "hexcasting:artifact", "sortnum": 3, "advancement": "hexcasting:root", "read_by_default": true, diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/nadirs.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/nadirs.json index 8d7efd5c11..7c5c729461 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/nadirs.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/nadirs.json @@ -1,7 +1,7 @@ { "name": "hexcasting.entry.nadirs", "category": "hexcasting:patterns/spells", - "icon": "minecraft:potion{Potion:'minecraft:poison'}", + "icon": "minecraft:potion[potion_contents={potion:\"minecraft:poison\"}]", "advancement": "hexcasting:root", "sortnum": 2, "read_by_default": true, diff --git a/Common/src/main/resources/data/hexcasting/recipes/directrix/empty.json b/Common/src/main/resources/data/hexcasting/recipes/directrix/empty.json new file mode 100644 index 0000000000..648758e5a6 --- /dev/null +++ b/Common/src/main/resources/data/hexcasting/recipes/directrix/empty.json @@ -0,0 +1,27 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "redstone", + "key": { + "A": { + "item": "hexcasting:charged_amethyst" + }, + "C": { + "item": "minecraft:comparator" + }, + "O": { + "item": "minecraft:observer" + }, + "S": { + "item": "hexcasting:slate_block" + } + }, + "pattern": [ + "CSS", + "OAO", + "SSC" + ], + "result": { + "item": "hexcasting:directrix/empty" + }, + "show_notification": true +} diff --git a/Common/src/main/resources/hexplat.mixins.json b/Common/src/main/resources/hexplat.mixins.json index a70b99261b..34875c60ee 100644 --- a/Common/src/main/resources/hexplat.mixins.json +++ b/Common/src/main/resources/hexplat.mixins.json @@ -6,6 +6,7 @@ "package": "at.petrak.hexcasting.mixin", "mixins": [ "MixinAbstractVillager", + "MixinLivingEntity", "MixinMob", "MixinRaider", "MixinVillager", @@ -15,7 +16,6 @@ "accessor.AccessorEntity", "accessor.AccessorLivingEntity", "accessor.AccessorLootTable", - "accessor.AccessorPotionBrewing", "accessor.AccessorUseOnContext", "accessor.AccessorVillager", "accessor.CriteriaTriggersAccessor" diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/mixin/FabricMixinReloadableServerResources.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/mixin/FabricMixinReloadableServerResources.java index 70b6bc2113..05d1c7782e 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/mixin/FabricMixinReloadableServerResources.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/mixin/FabricMixinReloadableServerResources.java @@ -13,7 +13,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.Arrays; import java.util.concurrent.CompletableFuture; @Mixin(ReloadableServerResources.class) @@ -24,13 +23,12 @@ private static void onLoadResources(CallbackInfoReturnable { var amethystTable = rsr.getLootData().getLootTable(Blocks.AMETHYST_CLUSTER.getLootTable()); var theCoolerAmethystTable = (AccessorLootTable) amethystTable; - var oldFuncs = theCoolerAmethystTable.hex$getFunctions(); - var newFuncs = Arrays.copyOf(oldFuncs, oldFuncs.length + 1); + var oldFuncs = new java.util.ArrayList<>(theCoolerAmethystTable.hex$getFunctions()); var shardReducer = rsr.getLootData().getElement(new LootDataId<>(LootDataType.MODIFIER, FabricHexLootModJankery.FUNC_AMETHYST_SHARD_REDUCER)); if (shardReducer != null) { - newFuncs[newFuncs.length - 1] = shardReducer; - theCoolerAmethystTable.hex$setFunctions(newFuncs); - theCoolerAmethystTable.hex$setCompositeFunction(LootItemFunctions.compose(newFuncs)); + oldFuncs.add(shardReducer); + theCoolerAmethystTable.hex$setFunctions(oldFuncs); + theCoolerAmethystTable.hex$setCompositeFunction(LootItemFunctions.compose(oldFuncs)); } else { HexAPI.LOGGER.warn("{} was not found?", FabricHexLootModJankery.FUNC_AMETHYST_SHARD_REDUCER); } diff --git a/Forge/build.gradle b/Forge/build.gradle index 4ffb75e66e..74e5b70cb3 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -1,28 +1,10 @@ -buildscript { - repositories { - maven { url = 'https://maven.minecraftforge.net' } - maven { - url = 'https://repo.spongepowered.org/repository/maven-public/' - content { includeGroup "org.spongepowered" } - } - mavenCentral() - } - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '6.0.+', changing: true - classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' - } -} - plugins { id "java" id "maven-publish" - id "at.petra-k.pkpcpbp.PKSubprojPlugin" + id "net.neoforged.moddev" version "2.0.140" } -apply plugin: 'net.minecraftforge.gradle' -apply plugin: 'org.spongepowered.mixin' - pkSubproj { pkPublish = true curseforgeJar = jar.archiveFile @@ -30,168 +12,101 @@ pkSubproj { "paucal", "patchouli", "caelus", - "inline", ]) modrinthJar = jar.archiveFile modrinthDependencies([ - "paucal:HyBiJPtT", // 0.6.0-forge + "paucal:HyBiJPtT", "patchouli:1.20.1-80-forge", "caelus:3.1.0+1.20", - "inline:1.20.1-1.0.1-forge", ]) } repositories { + mavenLocal() mavenCentral() - - // If you have mod jar dependencies in ./libs, you can declare them as a repository like so: - flatDir { - dir 'libs' - } - - maven { - // location of the maven that hosts JEI files - name = "Progwml6 maven" - url = "https://dvs1.progwml6.com/files/maven/" - } - maven { - // location of a maven mirror for JEI files, as a fallback - name = "ModMaven" - url = "https://modmaven.dev" - } - // caelus elytra + maven { name = "JEI"; url = "https://maven.blamejared.com" } + flatDir { dir 'libs' } + maven { name = "Progwml6 maven"; url = "https://dvs1.progwml6.com/files/maven/" } + maven { name = "ModMaven"; url = "https://modmaven.dev" } maven { url = "https://maven.theillusivec4.top" } - // pehkui maven { url = "https://jitpack.io" } - maven { name = 'Kotlin for Forge' url = 'https://thedarkcolour.github.io/KotlinForForge/' content { includeGroup "thedarkcolour" } } - - maven { url "https://maven.shedaniel.me/" } + maven { url = "https://maven.shedaniel.me/" } + maven { url = 'https://maven.neoforged.net/releases' } + maven { url = 'https://api.modrinth.com/maven' } + maven { url = 'https://maven.modrinth.one' } } dependencies { - minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" compileOnly project(":Common") - - implementation "thedarkcolour:kotlinforforge:$kotlinForForgeVersion" - + implementation "thedarkcolour:kotlinforforge-neoforge:$kotlinForForgeVersion" annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' - compileOnly fg.deobf("at.petra-k.paucal:paucal-forge-$minecraftVersion:$paucalVersion") - runtimeOnly fg.deobf("at.petra-k.paucal:paucal-forge-$minecraftVersion:$paucalVersion") - compileOnly fg.deobf("vazkii.patchouli:Patchouli:$minecraftVersion-$patchouliVersion-FORGE-SNAPSHOT") - runtimeOnly fg.deobf("vazkii.patchouli:Patchouli:$minecraftVersion-$patchouliVersion-FORGE-SNAPSHOT") - - // aughh - testCompileOnly fg.deobf("at.petra-k.paucal:paucal-forge-$minecraftVersion:$paucalVersion") - testCompileOnly fg.deobf("vazkii.patchouli:Patchouli:$minecraftVersion-$patchouliVersion-FORGE-SNAPSHOT") - - implementation fg.deobf("top.theillusivec4.caelus:caelus-forge:$caelusVersion") + compileOnly "at.petrak:paucal-neoforge-${minecraftVersion}:${paucalVersion}" + runtimeOnly "at.petrak:paucal-neoforge-${minecraftVersion}:${paucalVersion}" + compileOnly files('libs/Patchouli-1.21.1-92-NEOFORGE.jar') + runtimeOnly files('libs/Patchouli-1.21.1-92-NEOFORGE.jar') + compileOnly files('libs/caelus-neoforge-7.0.1+1.21.1.jar') + runtimeOnly files('libs/caelus-neoforge-7.0.1+1.21.1.jar') - implementation fg.deobf("com.samsthenerd.inline:inline-forge:$minecraftVersion-$inlineVersion") + compileOnly "top.theillusivec4.curios:curios-neoforge:9.4.0+1.21.1" + // runtimeOnly "top.theillusivec4.curios:curios-neoforge:9.4.0+1.21.1" - // needed for inline to run - runtimeOnly fg.deobf("me.shedaniel.cloth:cloth-config-forge:$clothConfigVersion") + compileOnly "mezz.jei:jei-${minecraftVersion}-neoforge-api:${jeiVersion}" + runtimeOnly "mezz.jei:jei-${minecraftVersion}-neoforge:${jeiVersion}" - // Optional interop + // compileOnly "maven.modrinth:inline:${minecraftVersion}-${inlineVersion}-neoforge" - compileOnly fg.deobf("mezz.jei:jei-$minecraftVersion-common-api:$jeiVersion") - compileOnly fg.deobf("mezz.jei:jei-$minecraftVersion-forge-api:$jeiVersion") - runtimeOnly fg.deobf("mezz.jei:jei-$minecraftVersion-forge:$jeiVersion") - - compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:$curiosVersion+$minecraftVersion:api") - runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:$curiosVersion+$minecraftVersion") - - api fg.deobf("com.github.Virtuoel:Pehkui:${pehkuiVersion}-$minecraftVersion-forge") + testCompileOnly "at.petrak:paucal-neoforge-${minecraftVersion}:${paucalVersion}" + testCompileOnly "vazkii.patchouli:Patchouli:${minecraftVersion}-${patchouliVersion}-NEOFORGE-SNAPSHOT" } -minecraft { - mappings channel: 'official', version: minecraftVersion - accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') +def commonMain = project(":Common").sourceSets.main - if (project.hasProperty('forge_ats_enabled') && project.findProperty('forge_ats_enabled').toBoolean()) { - // This location is hardcoded in Forge and can not be changed. - // https://github.com/MinecraftForge/MinecraftForge/blob/be1698bb1554f9c8fa2f58e32b9ab70bc4385e60/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java#L123 - accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - project.logger.debug('Forge Access Transformers are enabled for this project.') - } +neoForge { + version = project.neoforgeVersion + accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg') runs { client { - workingDirectory project.file('run') - ideaModule "${rootProject.name}.${project.name}.main" - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - mods { - create(modID) { - source sourceSets.main - source project(":Common").sourceSets.main - } - } + client() + systemProperty 'neoforge.enabledGameTestNamespaces', modID } - server { - workingDirectory project.file('run') - ideaModule "${rootProject.name}.${project.name}.main" - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - mods { - create(modID) { - source sourceSets.main - source project(":Common").sourceSets.main - } - } + server() + programArgument '--nogui' + systemProperty 'neoforge.enabledGameTestNamespaces', modID + } + data { + data() + programArguments.addAll '--mod', modID, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() } - - // We have to have a dummy data run to be parented from - data {} - xplatDatagen { - parent minecraft.runs.data - - workingDirectory project.file('run') - ideaModule "${rootProject.name}.${project.name}.main" - args '--mod', modID, '--all', '--output', file('../Common/src/generated/resources/'), '--existing', file('../Common/src/main/resources/') - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - property 'hexcasting.xplat_datagen', 'true' - - mods { - create(modID) { - source sourceSets.main - source project(":Common").sourceSets.main - } - } + data() + programArguments.addAll '--mod', modID, '--all', '--output', file('../Common/src/generated/resources/').getAbsolutePath(), '--existing', file('../Common/src/main/resources/').getAbsolutePath() + systemProperty 'hexcasting.xplat_datagen', 'true' } - forgeDatagen { - parent minecraft.runs.data - - workingDirectory project.file('run') - ideaModule "${rootProject.name}.${project.name}.main" - args '--mod', modID, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - property 'hexcasting.forge_datagen', 'true' - mods { - create(modID) { - source sourceSets.main - source project(":Common").sourceSets.main - } - } + data() + programArguments.addAll '--mod', modID, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() + systemProperty 'hexcasting.forge_datagen', 'true' + } + configureEach { + systemProperty 'forge.logging.markers', 'REGISTRIES' + logLevel = org.slf4j.event.Level.DEBUG } } -} - -mixin { - add sourceSets.main, "hexcasting.mixins.refmap.json" - config "hexplat.mixins.json" - config "hexcasting_forge.mixins.json" + mods { + "${modID}" { + sourceSet sourceSets.main + sourceSet commonMain + } + } } compileJava { @@ -207,16 +122,18 @@ compileTestKotlin { sourceSets { main.resources.srcDirs += ['src/generated/resources', '../Common/src/generated/resources'] main.kotlin.srcDirs += 'src/main/java' + main.java.exclude 'at/petrak/hexcasting/forge/datagen/**' test.kotlin.srcDirs += 'src/main/java' } processResources { + duplicatesStrategy = DuplicatesStrategy.INCLUDE from project(":Common").sourceSets.main.resources inputs.property "version", project.version - filesMatching("mods.toml") { expand "version": project.version } + filesMatching("neoforge.mods.toml") { + expand "version": project.version + } } - -jar.finalizedBy('reobfJar') diff --git a/Forge/gradle.properties b/Forge/gradle.properties index 8b3c7f47f9..cd407bd2a3 100644 --- a/Forge/gradle.properties +++ b/Forge/gradle.properties @@ -1,8 +1,4 @@ -platform=forge +platform=neoforge -forgeVersion=47.1.47 - -kotlinForForgeVersion=4.3.0 - -curiosVersion=5.2.0-beta.3 -caelusVersion=3.1.0+1.20 +kotlinForForgeVersion=5.6.0 +caelusVersion=7.0.1+1.21.1 diff --git a/Forge/libs/Patchouli-1.21.1-92-NEOFORGE.jar b/Forge/libs/Patchouli-1.21.1-92-NEOFORGE.jar new file mode 100644 index 0000000000..3a1c67f451 Binary files /dev/null and b/Forge/libs/Patchouli-1.21.1-92-NEOFORGE.jar differ diff --git a/Forge/libs/caelus-neoforge-7.0.1+1.21.1.jar b/Forge/libs/caelus-neoforge-7.0.1+1.21.1.jar new file mode 100644 index 0000000000..f3df4ed4e1 Binary files /dev/null and b/Forge/libs/caelus-neoforge-7.0.1+1.21.1.jar differ diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexClientInitializer.java b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexClientInitializer.java index 30e0e2a53e..c73962664f 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexClientInitializer.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexClientInitializer.java @@ -2,6 +2,8 @@ import at.petrak.hexcasting.client.ClientTickCounter; import at.petrak.hexcasting.client.RegisterClientStuff; +import at.petrak.hexcasting.common.msgs.*; +import at.petrak.hexcasting.forge.network.*; import at.petrak.hexcasting.client.ShiftScrollListener; import at.petrak.hexcasting.client.gui.PatternTooltipComponent; import at.petrak.hexcasting.client.model.AltioraLayer; @@ -13,8 +15,8 @@ import at.petrak.hexcasting.common.misc.PatternTooltip; import at.petrak.hexcasting.interop.HexInterop; import net.minecraft.client.Minecraft; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.color.item.ItemColors; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.resources.ResourceLocation; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.PlayerModel; import net.minecraft.client.particle.ParticleProvider; @@ -23,68 +25,61 @@ import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleType; -import net.minecraftforge.client.event.*; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.neoforge.client.event.*; +import net.neoforged.neoforge.client.event.RegisterColorHandlersEvent; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import java.io.IOException; import java.util.function.Function; // This is Java because I can't kotlin-fu some of the consumers public class ForgeHexClientInitializer { - // We copy Fabric's example; it mixes in on the return of the initializer and sticks it in a global variable. - // So here's our global. - public static ItemColors GLOBAL_ITEM_COLORS; - public static BlockColors GLOBAL_BLOCK_COLORS; @SubscribeEvent public static void clientInit(FMLClientSetupEvent evt) { - evt.enqueueWork(() -> { - RegisterClientStuff.init(); - RegisterClientStuff.registerColorProviders( - (colorizer, item) -> GLOBAL_ITEM_COLORS.register(colorizer, item), - (colorizer, block) -> GLOBAL_BLOCK_COLORS.register(colorizer, block)); - }); + evt.enqueueWork(RegisterClientStuff::init); - var evBus = MinecraftForge.EVENT_BUS; + var evBus = NeoForge.EVENT_BUS; evBus.addListener((ClientPlayerNetworkEvent.LoggingIn e) -> PatternRegistryManifest.processRegistry(null)); evBus.addListener((RenderLevelStageEvent e) -> { if (e.getStage().equals(RenderLevelStageEvent.Stage.AFTER_PARTICLES)) { - HexAdditionalRenderers.overlayLevel(e.getPoseStack(), e.getPartialTick()); + HexAdditionalRenderers.overlayLevel(e.getPoseStack(), e.getPartialTick().getGameTimeDeltaPartialTick(true)); } }); evBus.addListener((RenderGuiEvent.Post e) -> { - HexAdditionalRenderers.overlayGui(e.getGuiGraphics(), e.getPartialTick()); + HexAdditionalRenderers.overlayGui(e.getGuiGraphics(), e.getPartialTick().getGameTimeDeltaPartialTick(true)); }); - evBus.addListener((TickEvent.RenderTickEvent e) -> { - if (e.phase == TickEvent.Phase.START) { - ClientTickCounter.renderTickStart(e.renderTickTime); - } - }); + evBus.addListener((RenderFrameEvent.Pre e) -> + ClientTickCounter.renderTickStart(e.getPartialTick().getGameTimeDeltaPartialTick(true))); - evBus.addListener((TickEvent.ClientTickEvent e) -> { - if (e.phase == TickEvent.Phase.END) { - ClientTickCounter.clientTickEnd(); - ShiftScrollListener.clientTickEnd(); - } + evBus.addListener((ClientTickEvent.Post e) -> { + ClientTickCounter.clientTickEnd(); + ShiftScrollListener.clientTickEnd(); }); evBus.addListener((InputEvent.MouseScrollingEvent e) -> { - var cancel = ShiftScrollListener.onScrollInGameplay(e.getScrollDelta()); + var cancel = ShiftScrollListener.onScrollInGameplay((float) e.getScrollDeltaY()); e.setCanceled(cancel); }); HexInterop.clientInit(); } + @SubscribeEvent + public static void registerColors(RegisterColorHandlersEvent.Item evt) { + RegisterClientStuff.registerColorProviders( + (colorizer, item) -> evt.getItemColors().register(colorizer, item), + (colorizer, block) -> evt.getBlockColors().register(colorizer, block)); + } + @SubscribeEvent public static void registerShaders(RegisterShadersEvent evt) throws IOException { HexShaders.init(evt.getResourceProvider(), p -> evt.registerShader(p.getFirst(), p.getSecond())); @@ -115,12 +110,19 @@ public static void registerTooltipComponents(RegisterClientTooltipComponentFacto @SubscribeEvent public static void onModelRegister(ModelEvent.RegisterAdditional evt) { var recMan = Minecraft.getInstance().getResourceManager(); - RegisterClientStuff.onModelRegister(recMan, evt::register); + RegisterClientStuff.onModelRegister(recMan, + loc -> evt.register(ModelResourceLocation.standalone(loc))); } @SubscribeEvent - public static void onModelBake(ModelEvent.BakingCompleted evt) { - RegisterClientStuff.onModelBake(evt.getModelBakery(), evt.getModels()); + public static void onModelBake(ModelEvent.ModifyBakingResult evt) { + var models = evt.getModels(); + var modelMap = new java.util.HashMap(); + for (var entry : models.entrySet()) { + var key = entry.getKey(); + modelMap.put(key.id(), entry.getValue()); + } + RegisterClientStuff.onModelBake(evt.getModelBakery(), modelMap); } @SubscribeEvent diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java index dd3eb257e3..6de79bca01 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java @@ -4,7 +4,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; -import net.minecraftforge.common.ForgeConfigSpec; +import net.neoforged.neoforge.common.ModConfigSpec; import net.minecraft.util.RandomSource; import java.util.List; @@ -12,16 +12,16 @@ import static at.petrak.hexcasting.api.mod.HexConfig.noneMatch; public class ForgeHexConfig implements HexConfig.CommonConfigAccess { - private static ForgeConfigSpec.LongValue dustMediaAmount; - private static ForgeConfigSpec.LongValue shardMediaAmount; - private static ForgeConfigSpec.LongValue chargedCrystalMediaAmount; - private static ForgeConfigSpec.DoubleValue mediaToHealthRate; + private static ModConfigSpec.LongValue dustMediaAmount; + private static ModConfigSpec.LongValue shardMediaAmount; + private static ModConfigSpec.LongValue chargedCrystalMediaAmount; + private static ModConfigSpec.DoubleValue mediaToHealthRate; - private static ForgeConfigSpec.IntValue cypherCooldown; - private static ForgeConfigSpec.IntValue trinketCooldown; - private static ForgeConfigSpec.IntValue artifactCooldown; + private static ModConfigSpec.IntValue cypherCooldown; + private static ModConfigSpec.IntValue trinketCooldown; + private static ModConfigSpec.IntValue artifactCooldown; - public ForgeHexConfig(ForgeConfigSpec.Builder builder) { + public ForgeHexConfig(ModConfigSpec.Builder builder) { builder.push("Media Amounts"); dustMediaAmount = builder.comment("How much media a single Amethyst Dust item is worth") .defineInRange("dustMediaAmount", DEFAULT_DUST_MEDIA_AMOUNT, 0, Integer.MAX_VALUE); @@ -79,14 +79,14 @@ public int artifactCooldown() { } public static class Client implements HexConfig.ClientConfigAccess { - private static ForgeConfigSpec.BooleanValue ctrlTogglesOffStrokeOrder; - private static ForgeConfigSpec.BooleanValue invertSpellbookScrollDirection; - private static ForgeConfigSpec.BooleanValue invertAbacusScrollDirection; - private static ForgeConfigSpec.DoubleValue gridSnapThreshold; - private static ForgeConfigSpec.BooleanValue clickingTogglesDrawing; - private static ForgeConfigSpec.BooleanValue alwaysShowListCommas; - - public Client(ForgeConfigSpec.Builder builder) { + private static ModConfigSpec.BooleanValue ctrlTogglesOffStrokeOrder; + private static ModConfigSpec.BooleanValue invertSpellbookScrollDirection; + private static ModConfigSpec.BooleanValue invertAbacusScrollDirection; + private static ModConfigSpec.DoubleValue gridSnapThreshold; + private static ModConfigSpec.BooleanValue clickingTogglesDrawing; + private static ModConfigSpec.BooleanValue alwaysShowListCommas; + + public Client(ModConfigSpec.Builder builder) { ctrlTogglesOffStrokeOrder = builder.comment( "Whether the ctrl key will instead turn *off* the color gradient on patterns") .define("ctrlTogglesOffStrokeOrder", DEFAULT_CTRL_TOGGLES_OFF_STROKE_ORDER); @@ -141,19 +141,19 @@ public boolean alwaysShowListCommas() { } public static class Server implements HexConfig.ServerConfigAccess { - private static ForgeConfigSpec.IntValue opBreakHarvestLevel; - private static ForgeConfigSpec.IntValue maxOpCount; - private static ForgeConfigSpec.IntValue maxSpellCircleLength; - private static ForgeConfigSpec.ConfigValue> actionDenyList; - private static ForgeConfigSpec.ConfigValue> circleActionDenyList; - - private static ForgeConfigSpec.BooleanValue greaterTeleportSplatsItems; - private static ForgeConfigSpec.BooleanValue villagersOffendedByMindMurder; - private static ForgeConfigSpec.ConfigValue> tpDimDenyList; - private static ForgeConfigSpec.BooleanValue doesTrueNameHaveAmbit; - private static ForgeConfigSpec.DoubleValue traderScrollChance; - - public Server(ForgeConfigSpec.Builder builder) { + private static ModConfigSpec.IntValue opBreakHarvestLevel; + private static ModConfigSpec.IntValue maxOpCount; + private static ModConfigSpec.IntValue maxSpellCircleLength; + private static ModConfigSpec.ConfigValue> actionDenyList; + private static ModConfigSpec.ConfigValue> circleActionDenyList; + + private static ModConfigSpec.BooleanValue greaterTeleportSplatsItems; + private static ModConfigSpec.BooleanValue villagersOffendedByMindMurder; + private static ModConfigSpec.ConfigValue> tpDimDenyList; + private static ModConfigSpec.BooleanValue doesTrueNameHaveAmbit; + private static ModConfigSpec.DoubleValue traderScrollChance; + + public Server(ModConfigSpec.Builder builder) { builder.push("Spells"); maxOpCount = builder.comment("The maximum number of actions that can be executed in one tick, to avoid " + "hanging the server.") @@ -251,7 +251,7 @@ public double traderScrollChance() { } private static boolean isValidReslocArg(Object o) { - return o instanceof String s && ResourceLocation.isValidResourceLocation(s); + return o instanceof String s && ResourceLocation.tryParse(s) != null; } } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java index 39bd896580..1cdb92c99d 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java @@ -21,15 +21,12 @@ import at.petrak.hexcasting.forge.cap.CapSyncers; import at.petrak.hexcasting.forge.cap.ForgeCapabilityHandler; import at.petrak.hexcasting.forge.cap.adimpl.CapClientCastingStack; -import at.petrak.hexcasting.forge.datagen.ForgeHexDataGenerators; import at.petrak.hexcasting.forge.interop.curios.CuriosApiInterop; import at.petrak.hexcasting.forge.interop.curios.CuriosRenderers; import at.petrak.hexcasting.forge.lib.ForgeHexArgumentTypeRegistry; import at.petrak.hexcasting.forge.lib.ForgeHexLootMods; -import at.petrak.hexcasting.forge.network.ForgePacketHandler; import at.petrak.hexcasting.forge.network.MsgBrainsweepAck; -import at.petrak.hexcasting.forge.recipe.ForgeModConditionalIngredient; -import at.petrak.hexcasting.forge.recipe.ForgeUnsealedIngredient; +import at.petrak.hexcasting.forge.lib.ForgeHexIngredientTypes; import at.petrak.hexcasting.interop.HexInterop; import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.core.MappedRegistry; @@ -47,55 +44,56 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BlockSetType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.ForgeConfigSpec; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.ToolActions; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; -import net.minecraftforge.event.RegisterCommandsEvent; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.event.entity.EntityAttributeModificationEvent; -import net.minecraftforge.event.entity.living.LivingConversionEvent; -import net.minecraftforge.event.entity.living.LivingEvent; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.event.level.BlockEvent; -import net.minecraftforge.event.server.ServerStartedEvent; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.config.ModConfig; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.network.PacketDistributor; -import net.minecraftforge.registries.RegisterEvent; -import thedarkcolour.kotlinforforge.KotlinModLoadingContext; - +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.ModList; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.config.ModConfig; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.common.ModConfigSpec; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.common.ItemAbilities; +import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; +import net.neoforged.neoforge.event.RegisterCommandsEvent; +import net.neoforged.neoforge.event.brewing.RegisterBrewingRecipesEvent; +import net.neoforged.neoforge.event.tick.LevelTickEvent; +import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; +import net.neoforged.neoforge.event.entity.living.LivingConversionEvent; +import net.neoforged.neoforge.event.tick.EntityTickEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; +import net.neoforged.neoforge.event.level.BlockEvent; +import net.neoforged.neoforge.event.server.ServerStartedEvent; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.registries.RegisterEvent; import java.util.function.BiConsumer; import java.util.function.Consumer; @Mod(HexAPI.MOD_ID) public class ForgeHexInitializer { - public ForgeHexInitializer() { + private static IEventBus MOD_BUS; + + public ForgeHexInitializer(IEventBus modBus) { + MOD_BUS = modBus; initConfig(); initRegistries(); initRegistry(); - initListeners(); + initListeners(modBus); } private static void initConfig() { - var config = new ForgeConfigSpec.Builder().configure(ForgeHexConfig::new); - var clientConfig = new ForgeConfigSpec.Builder().configure(ForgeHexConfig.Client::new); - var serverConfig = new ForgeConfigSpec.Builder().configure(ForgeHexConfig.Server::new); + var config = new ModConfigSpec.Builder().configure(ForgeHexConfig::new); + var clientConfig = new ModConfigSpec.Builder().configure(ForgeHexConfig.Client::new); + var serverConfig = new ModConfigSpec.Builder().configure(ForgeHexConfig.Server::new); HexConfig.setCommon(config.getLeft()); HexConfig.setClient(clientConfig.getLeft()); HexConfig.setServer(serverConfig.getLeft()); - var mlc = ModLoadingContext.get(); - mlc.registerConfig(ModConfig.Type.COMMON, config.getRight()); - mlc.registerConfig(ModConfig.Type.CLIENT, clientConfig.getRight()); - mlc.registerConfig(ModConfig.Type.SERVER, serverConfig.getRight()); + var modContainer = ModList.get().getModContainerById(HexAPI.MOD_ID).orElseThrow(); + modContainer.registerConfig(ModConfig.Type.COMMON, config.getRight()); + modContainer.registerConfig(ModConfig.Type.CLIENT, clientConfig.getRight()); + modContainer.registerConfig(ModConfig.Type.SERVER, serverConfig.getRight()); } public static void initRegistries() { @@ -134,6 +132,8 @@ private static void initRegistry() { bind(Registries.PARTICLE_TYPE, HexParticles::registerParticles); + bind(Registries.DATA_COMPONENT_TYPE, reg -> reg.accept(HexDataComponents.STACK_DATA, HexAPI.modLoc("stack_data"))); + bind(HexRegistries.IOTA_TYPE, HexIotaTypes::registerTypes); bind(HexRegistries.ACTION, HexActions::register); bind(HexRegistries.SPECIAL_HANDLER, HexSpecialHandlers::register); @@ -141,10 +141,15 @@ private static void initRegistry() { bind(HexRegistries.CONTINUATION_TYPE, HexContinuationTypes::registerContinuations); bind(HexRegistries.EVAL_SOUND, HexEvalSounds::register); - ForgeHexArgumentTypeRegistry.ARGUMENT_TYPES.register(getModEventBus()); - ForgeHexLootMods.REGISTRY.register(getModEventBus()); + ForgeHexArgumentTypeRegistry.ARGUMENT_TYPES.register(MOD_BUS); + ForgeHexLootMods.REGISTRY.register(MOD_BUS); - HexAdvancementTriggers.registerTriggers(); + // Advancement triggers must be registered via RegisterEvent (registry is frozen during mod init) + bind(Registries.TRIGGER_TYPE, reg -> { + reg.accept(HexAdvancementTriggers.OVERCAST_TRIGGER, HexAPI.modLoc("overcast")); + reg.accept(HexAdvancementTriggers.SPEND_MEDIA_TRIGGER, HexAPI.modLoc("spend_media")); + reg.accept(HexAdvancementTriggers.FAIL_GREAT_SPELL_TRIGGER, HexAPI.modLoc("fail_to_cast_great_spell")); + }); RegisterMisc.register(); } @@ -152,22 +157,22 @@ private static void initRegistry() { // https://github.com/VazkiiMods/Botania/blob/1.18.x/Forge/src/main/java/vazkii/botania/forge/ForgeCommonInitializer.java private static void bind(ResourceKey> registry, Consumer> source) { - getModEventBus().addListener((RegisterEvent event) -> { + MOD_BUS.addListener((RegisterEvent event) -> { if (registry.equals(event.getRegistryKey())) { source.accept((t, rl) -> event.register(registry, rl, () -> t)); } }); } - private static void initListeners() { - var modBus = getModEventBus(); - var evBus = MinecraftForge.EVENT_BUS; + private static void initListeners(IEventBus modBus) { + var evBus = NeoForge.EVENT_BUS; - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> modBus.register(ForgeHexClientInitializer.class)); + if (FMLEnvironment.dist == Dist.CLIENT) { + modBus.register(ForgeHexClientInitializer.class); // client init, colors, particles, etc. + } modBus.addListener((FMLCommonSetupEvent evt) -> evt.enqueueWork(() -> { - ForgePacketHandler.init(); HexComposting.setup(); HexStrippables.init(); // Forge does not strictly require TreeGrowers to initialize during early game stages, unlike Fabric @@ -186,13 +191,16 @@ private static void initListeners() { HexItems.registerItemCreativeTab(evt, evt.getTab()); }); + // RegisterBrewingRecipesEvent is on NeoForge bus, not mod bus + evBus.addListener((RegisterBrewingRecipesEvent evt) -> + HexPotions.addRecipes(evt.getBuilder())); + + + ForgeHexIngredientTypes.INGREDIENT_TYPES.register(modBus); // We have to do these at some point when the registries are still open modBus.addListener((RegisterEvent evt) -> { if (evt.getRegistryKey().equals(Registries.ITEM)) { - CraftingHelper.register(ForgeUnsealedIngredient.ID, ForgeUnsealedIngredient.Serializer.INSTANCE); - CraftingHelper.register(ForgeModConditionalIngredient.ID, - ForgeModConditionalIngredient.Serializer.INSTANCE); HexStatistics.register(); HexLootFunctions.registerSerializers((lift, id) -> Registry.register(BuiltInRegistries.LOOT_FUNCTION_TYPE, id, lift)); @@ -212,15 +220,15 @@ private static void initListeners() { evBus.addListener((LivingConversionEvent.Post evt) -> BrainsweepingEvents.copyBrainsweepPostTransformation(evt.getEntity(), evt.getOutcome())); - evBus.addListener((LivingEvent.LivingTickEvent evt) -> { + evBus.addListener((EntityTickEvent.Post evt) -> { if (evt.getEntity() instanceof ServerPlayer splayer) { OpFlight.tickDownFlight(splayer); OpAltiora.checkPlayerCollision(splayer); } }); - evBus.addListener((TickEvent.LevelTickEvent evt) -> { - if (evt.phase == TickEvent.Phase.END && evt.level instanceof ServerLevel world) { + evBus.addListener((LevelTickEvent.Post evt) -> { + if (evt.getLevel() instanceof ServerLevel world) { PlayerPositionRecorder.updateAllPlayers(world); } }); @@ -248,14 +256,13 @@ private static void initListeners() { Entity target = evt.getTarget(); if (evt.getTarget() instanceof ServerPlayer serverPlayer && target instanceof Mob mob && IXplatAbstractions.INSTANCE.isBrainswept(mob)) { - ForgePacketHandler.getNetwork() - .send(PacketDistributor.PLAYER.with(() -> serverPlayer), MsgBrainsweepAck.of(mob)); + PacketDistributor.sendToPlayer(serverPlayer, MsgBrainsweepAck.of(mob)); } }); // Implemented with a mixin on Farbc evBus.addListener((BlockEvent.BlockToolModificationEvent evt) -> { - if (!evt.isSimulated() && evt.getToolAction() == ToolActions.AXE_STRIP) { + if (!evt.isSimulated() && evt.getItemAbility() == ItemAbilities.AXE_STRIP) { BlockState bs = evt.getState(); var output = HexStrippables.STRIPPABLES.get(bs.getBlock()); if (output != null) { @@ -264,35 +271,33 @@ private static void initListeners() { } }); - // Caps are cardinal components on farbc - modBus.addListener(ForgeCapabilityHandler::registerCaps); - evBus.addGenericListener(ItemStack.class, ForgeCapabilityHandler::attachItemCaps); - evBus.addGenericListener(BlockEntity.class, ForgeCapabilityHandler::attachBlockEntityCaps); - evBus.addGenericListener(Entity.class, ForgeCapabilityHandler::attachEntityCaps); + // Capabilities - register providers via RegisterCapabilitiesEvent (replaces AttachCapabilitiesEvent) + modBus.addListener(ForgeCapabilityHandler::registerCapabilities); - modBus.register(ForgeHexDataGenerators.class); - modBus.register(ForgeCapabilityHandler.class); + try { + modBus.register(Class.forName("at.petrak.hexcasting.forge.datagen.ForgeHexDataGenerators")); + } catch (ClassNotFoundException ignored) { + // Datagen package excluded from build + } + // ForgeCapabilityHandler uses addListener(registerCapabilities), no @SubscribeEvent evBus.register(CapSyncers.class); modBus.addListener((EntityAttributeModificationEvent e) -> { - e.add(EntityType.PLAYER, HexAttributes.GRID_ZOOM); - e.add(EntityType.PLAYER, HexAttributes.SCRY_SIGHT); - e.add(EntityType.PLAYER, HexAttributes.FEEBLE_MIND); - e.add(EntityType.PLAYER, HexAttributes.MEDIA_CONSUMPTION_MODIFIER); - e.add(EntityType.PLAYER, HexAttributes.AMBIT_RADIUS); - e.add(EntityType.PLAYER, HexAttributes.SENTINEL_RADIUS); + var attrs = BuiltInRegistries.ATTRIBUTE; + e.add(EntityType.PLAYER, attrs.getHolderOrThrow(HexAttributes.GRID_ZOOM_KEY)); + e.add(EntityType.PLAYER, attrs.getHolderOrThrow(HexAttributes.SCRY_SIGHT_KEY)); + e.add(EntityType.PLAYER, attrs.getHolderOrThrow(HexAttributes.FEEBLE_MIND_KEY)); + e.add(EntityType.PLAYER, attrs.getHolderOrThrow(HexAttributes.MEDIA_CONSUMPTION_MODIFIER_KEY)); + e.add(EntityType.PLAYER, attrs.getHolderOrThrow(HexAttributes.AMBIT_RADIUS_KEY)); + e.add(EntityType.PLAYER, attrs.getHolderOrThrow(HexAttributes.SENTINEL_RADIUS_KEY)); }); if (ModList.get().isLoaded(HexInterop.Forge.CURIOS_API_ID)) { modBus.addListener(CuriosApiInterop::onInterModEnqueue); modBus.addListener(CuriosApiInterop::onClientSetup); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> modBus.addListener(CuriosRenderers::onLayerRegister)); + if (FMLEnvironment.dist == Dist.CLIENT) { + modBus.addListener(CuriosRenderers::onLayerRegister); + } } } - - // aaaauughhg - private static IEventBus getModEventBus() { - return KotlinModLoadingContext.Companion.get().getKEventBus(); - } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/CapSyncers.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/CapSyncers.java index 89e26d4474..c29c54e76a 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/CapSyncers.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/CapSyncers.java @@ -6,10 +6,17 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.event.tick.EntityTickEvent; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; public class CapSyncers { + private static final int LOGIN_SYNC_MAX_TICKS = 200; + private static final ConcurrentHashMap PENDING_LOGIN_SYNC = new ConcurrentHashMap<>(); + @SubscribeEvent public static void copyDataOnDeath(PlayerEvent.Clone evt) { var eitherSidePlayer = evt.getEntity(); @@ -38,21 +45,47 @@ public static void syncDataOnLogin(PlayerEvent.PlayerLoggedInEvent evt) { if (!(evt.getEntity() instanceof ServerPlayer player)) { return; } + // PlayerLoggedInEvent fires before the connection is always ready for play packets. + // Retry for a short window until NeoForge allows our payloads. + PENDING_LOGIN_SYNC.put(player.getUUID(), LOGIN_SYNC_MAX_TICKS); + } + @SubscribeEvent + public static void syncDataOnRejoin(PlayerEvent.PlayerRespawnEvent evt) { + if (!(evt.getEntity() instanceof ServerPlayer player)) { + return; + } + // Respawn is in play phase; sync immediately. syncSentinel(player); syncPigment(player); syncAltiora(player); } @SubscribeEvent - public static void syncDataOnRejoin(PlayerEvent.PlayerRespawnEvent evt) { + public static void retryLoginSync(EntityTickEvent.Post evt) { if (!(evt.getEntity() instanceof ServerPlayer player)) { return; } - syncSentinel(player); - syncPigment(player); - syncAltiora(player); + var uuid = player.getUUID(); + var remaining = PENDING_LOGIN_SYNC.get(uuid); + if (remaining == null) { + return; + } + if (remaining <= 0) { + PENDING_LOGIN_SYNC.remove(uuid); + return; + } + + try { + syncSentinel(player); + syncPigment(player); + syncAltiora(player); + PENDING_LOGIN_SYNC.remove(uuid); + } catch (UnsupportedOperationException e) { + // Still in configuration phase / channels not ready yet. + PENDING_LOGIN_SYNC.put(uuid, remaining - 1); + } } public static void syncSentinel(ServerPlayer player) { diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeCapabilityHandler.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeCapabilityHandler.java index 502357ab3a..ac2a068e8d 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeCapabilityHandler.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeCapabilityHandler.java @@ -8,209 +8,156 @@ import at.petrak.hexcasting.api.misc.MediaConstants; import at.petrak.hexcasting.api.mod.HexConfig; import at.petrak.hexcasting.common.entities.EntityWallScroll; -import at.petrak.hexcasting.common.items.HexBaubleItem; +import at.petrak.hexcasting.common.entities.HexEntities; import at.petrak.hexcasting.common.lib.HexBlocks; +import at.petrak.hexcasting.common.lib.HexBlockEntities; import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.forge.cap.adimpl.*; import at.petrak.hexcasting.forge.interop.curios.CuriosApiInterop; import at.petrak.hexcasting.interop.HexInterop; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.decoration.ItemFrame; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.common.util.NonNullSupplier; -import net.minecraftforge.event.AttachCapabilitiesEvent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BooleanSupplier; -import java.util.function.Function; +import net.minecraft.world.level.ItemLike; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.capabilities.ICapabilityProvider; +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; + +import java.util.ArrayList; +import java.util.List; import static at.petrak.hexcasting.api.HexAPI.modLoc; public class ForgeCapabilityHandler { - /** - * Items that store an iota to their tag. - */ - public static final ResourceLocation IOTA_STORAGE_CAP = modLoc("iota_holder"); - /** - * Items that intrinsically store an iota. - */ - public static final ResourceLocation IOTA_STATIC_CAP = modLoc("iota_item"); - /** - * Items that store a variable amount of media to their tag. - */ - public static final ResourceLocation MEDIA_STORAGE_CAP = modLoc("media_holder"); - /** - * Items that statically provide media. - */ - public static final ResourceLocation MEDIA_STATIC_CAP = modLoc("media_item"); - /** - * Items that store a packaged Hex. - */ - public static final ResourceLocation HEX_HOLDER_CAP = modLoc("hex_item"); - /** - * Items that have multiple visual variants. - */ - public static final ResourceLocation VARIANT_ITEM_CAP = modLoc("variant_item"); - /** - * Items that work as pigments. - */ - public static final ResourceLocation PIGMENT_CAP = modLoc("pigment"); - public static final ResourceLocation CURIO_CAP = modLoc("curio"); - - public static final ResourceLocation IMPETUS_HANDLER = modLoc("impetus_items"); - - /** - * Used to render the pattern spiral around players while casting. - */ - public static final ResourceLocation PATTERN_SPIRAL = modLoc("pattern_spiral"); - - public static void registerCaps(RegisterCapabilitiesEvent evt) { - evt.register(ADMediaHolder.class); - evt.register(ADIotaHolder.class); - evt.register(ADHexHolder.class); - evt.register(ADPigment.class); - } - - public static void attachItemCaps(AttachCapabilitiesEvent evt) { - ItemStack stack = evt.getObject(); - - if (stack.getItem() instanceof MediaHolderItem holder) { - evt.addCapability(MEDIA_STORAGE_CAP, - provide(stack, HexCapabilities.MEDIA, () -> new CapItemMediaHolder(holder, stack))); - } else if (stack.is(HexItems.AMETHYST_DUST)) { - evt.addCapability(MEDIA_STATIC_CAP, provide(stack, HexCapabilities.MEDIA, () -> - new CapStaticMediaHolder(HexConfig.common()::dustMediaAmount, ADMediaHolder.AMETHYST_DUST_PRIORITY, - stack))); - } else if (stack.is(Items.AMETHYST_SHARD)) { - evt.addCapability(MEDIA_STATIC_CAP, provide(stack, HexCapabilities.MEDIA, () -> new CapStaticMediaHolder( - HexConfig.common()::shardMediaAmount, ADMediaHolder.AMETHYST_SHARD_PRIORITY, stack))); - } else if (stack.is(HexItems.CHARGED_AMETHYST)) { - evt.addCapability(MEDIA_STATIC_CAP, - provide(stack, HexCapabilities.MEDIA, () -> new CapStaticMediaHolder( - HexConfig.common()::chargedCrystalMediaAmount, ADMediaHolder.CHARGED_AMETHYST_PRIORITY, stack))); - } else if (stack.is(HexItems.QUENCHED_SHARD)) { - // no one uses the config - evt.addCapability(MEDIA_STATIC_CAP, - provide(stack, HexCapabilities.MEDIA, () -> new CapStaticMediaHolder( - () -> MediaConstants.QUENCHED_SHARD_UNIT, ADMediaHolder.QUENCHED_SHARD_PRIORITY, stack))); - } else if (stack.is(HexBlocks.QUENCHED_ALLAY.asItem())) { - // no one uses the config - evt.addCapability(MEDIA_STATIC_CAP, - provide(stack, HexCapabilities.MEDIA, () -> new CapStaticMediaHolder( - () -> MediaConstants.QUENCHED_BLOCK_UNIT, ADMediaHolder.QUENCHED_ALLAY_PRIORITY, stack))); - } - - if (stack.getItem() instanceof IotaHolderItem holder) { - evt.addCapability(IOTA_STORAGE_CAP, - provide(stack, HexCapabilities.IOTA, () -> new CapItemIotaHolder(holder, stack))); - } else if (stack.is(Items.PUMPKIN_PIE)) { - // haha yes - evt.addCapability(IOTA_STATIC_CAP, provide(stack, HexCapabilities.IOTA, () -> - new CapStaticIotaHolder((s) -> new DoubleIota(Math.PI * s.getCount()), stack))); - } - - if (stack.getItem() instanceof HexHolderItem holder) { - evt.addCapability(HEX_HOLDER_CAP, - provide(stack, HexCapabilities.STORED_HEX, () -> new CapItemHexHolder(holder, stack))); - } - if (stack.getItem() instanceof VariantItem variantItem) { - evt.addCapability(VARIANT_ITEM_CAP, - provide(stack, HexCapabilities.VARIANT_ITEM, () -> new CapItemVariantItem(variantItem, stack))); - } - if (stack.getItem() instanceof PigmentItem pigment) { - evt.addCapability(PIGMENT_CAP, - provide(stack, HexCapabilities.COLOR, () -> new CapItemPigment(pigment, stack))); + public static void registerCapabilities(RegisterCapabilitiesEvent evt) { + // Media holder - items + // Register for ALL items (provider returns null for non-media) to avoid missing items + // from explicit list due to registration order, matching Fabric's predicate-based approach. + ICapabilityProvider mediaProvider = + (stack, ctx) -> { + if (stack.getItem() instanceof MediaHolderItem holder) { + return new CapItemMediaHolder(holder, stack); + } + if (stack.is(HexItems.AMETHYST_DUST)) { + return new CapStaticMediaHolder(HexConfig.common()::dustMediaAmount, ADMediaHolder.AMETHYST_DUST_PRIORITY, stack); + } + if (stack.is(Items.AMETHYST_SHARD)) { + return new CapStaticMediaHolder(HexConfig.common()::shardMediaAmount, ADMediaHolder.AMETHYST_SHARD_PRIORITY, stack); + } + if (stack.is(HexItems.CHARGED_AMETHYST)) { + return new CapStaticMediaHolder(HexConfig.common()::chargedCrystalMediaAmount, ADMediaHolder.CHARGED_AMETHYST_PRIORITY, stack); + } + if (stack.is(HexItems.QUENCHED_SHARD)) { + return new CapStaticMediaHolder(() -> MediaConstants.QUENCHED_SHARD_UNIT, ADMediaHolder.QUENCHED_SHARD_PRIORITY, stack); + } + if (stack.is(HexBlocks.QUENCHED_ALLAY.asItem())) { + return new CapStaticMediaHolder(() -> MediaConstants.QUENCHED_BLOCK_UNIT, ADMediaHolder.QUENCHED_ALLAY_PRIORITY, stack); + } + return null; + }; + for (Item item : BuiltInRegistries.ITEM) { + evt.registerItem(HexCapabilities.MEDIA, mediaProvider, item); } - if (IXplatAbstractions.INSTANCE.isModPresent(HexInterop.Forge.CURIOS_API_ID) - && stack.getItem() instanceof HexBaubleItem) { - evt.addCapability(CURIO_CAP, CuriosApiInterop.curioCap(stack)); + // Iota holder - items + evt.registerItem(HexCapabilities.IOTA, (stack, ctx) -> { + if (stack.getItem() instanceof IotaHolderItem holder) { + return new CapItemIotaHolder(holder, stack); + } + if (stack.is(Items.PUMPKIN_PIE)) { + return new CapStaticIotaHolder((s) -> new DoubleIota(Math.PI * s.getCount()), stack); + } + return null; + }, getIotaHolderItems()); + + // Hex holder - items + evt.registerItem(HexCapabilities.STORED_HEX, (stack, ctx) -> + stack.getItem() instanceof HexHolderItem holder ? new CapItemHexHolder(holder, stack) : null, + getHexHolderItems()); + + // Variant item + evt.registerItem(HexCapabilities.VARIANT_ITEM, (stack, ctx) -> + stack.getItem() instanceof VariantItem v ? new CapItemVariantItem(v, stack) : null, + getVariantItems()); + + // Pigment + evt.registerItem(HexCapabilities.COLOR, (stack, ctx) -> + stack.getItem() instanceof PigmentItem p ? new CapItemPigment(p, stack) : null, + getPigmentItems()); + + // Entity iota holders + evt.registerEntity(HexCapabilities.IOTA_ENTITY, EntityType.ITEM, (entity, ctx) -> + new CapEntityIotaHolder.Wrapper(new ItemDelegatingEntityIotaHolder.ToItemEntity((ItemEntity) entity))); + evt.registerEntity(HexCapabilities.IOTA_ENTITY, EntityType.GLOW_ITEM_FRAME, (entity, ctx) -> + new CapEntityIotaHolder.Wrapper(new ItemDelegatingEntityIotaHolder.ToItemFrame((ItemFrame) entity))); + evt.registerEntity(HexCapabilities.IOTA_ENTITY, EntityType.ITEM_FRAME, (entity, ctx) -> + new CapEntityIotaHolder.Wrapper(new ItemDelegatingEntityIotaHolder.ToItemFrame((ItemFrame) entity))); + evt.registerEntity(HexCapabilities.IOTA_ENTITY, HexEntities.WALL_SCROLL, (entity, ctx) -> + new CapEntityIotaHolder.Wrapper(new ItemDelegatingEntityIotaHolder.ToWallScroll((EntityWallScroll) entity))); + + // Client casting stack - players only (client-side rendering) + evt.registerEntity(HexCapabilities.CLIENT_CASTING_STACK, EntityType.PLAYER, (entity, ctx) -> + new CapClientCastingStack((Player) entity, new ClientCastingStack())); + + // Block entity - impetus item handler + evt.registerBlockEntity(Capabilities.ItemHandler.BLOCK, HexBlockEntities.IMPETUS_REDSTONE_TILE, + (be, ctx) -> new ForgeImpetusCapability((BlockEntityAbstractImpetus) be)); + evt.registerBlockEntity(Capabilities.ItemHandler.BLOCK, HexBlockEntities.IMPETUS_LOOK_TILE, + (be, ctx) -> new ForgeImpetusCapability((BlockEntityAbstractImpetus) be)); + evt.registerBlockEntity(Capabilities.ItemHandler.BLOCK, HexBlockEntities.IMPETUS_RIGHTCLICK_TILE, + (be, ctx) -> new ForgeImpetusCapability((BlockEntityAbstractImpetus) be)); + + // Curios - bauble items + if (IXplatAbstractions.INSTANCE.isModPresent(HexInterop.Forge.CURIOS_API_ID)) { + CuriosApiInterop.registerCurioCapability(evt); } } - public static void attachEntityCaps(AttachCapabilitiesEvent evt) { - var entity = evt.getObject(); - if (entity instanceof ItemEntity item) { - evt.addCapability(IOTA_STORAGE_CAP, wrapItemEntityDelegate(item, - ItemDelegatingEntityIotaHolder.ToItemEntity::new)); - } else if (entity instanceof ItemFrame frame) { - evt.addCapability(IOTA_STORAGE_CAP, wrapItemEntityDelegate(frame, - ItemDelegatingEntityIotaHolder.ToItemFrame::new)); - } else if (entity instanceof EntityWallScroll scroll) { - evt.addCapability(IOTA_STORAGE_CAP, wrapItemEntityDelegate(scroll, - ItemDelegatingEntityIotaHolder.ToWallScroll::new)); - } else if (entity instanceof Player player) { - evt.addCapability(PATTERN_SPIRAL, provide(player, HexCapabilities.CLIENT_CASTING_STACK, - () -> new CapClientCastingStack(player, new ClientCastingStack()))); + private static ItemLike[] getIotaHolderItems() { + List items = new ArrayList<>(); + items.add(Items.PUMPKIN_PIE); + for (Item item : BuiltInRegistries.ITEM) { + if (item instanceof IotaHolderItem) { + items.add(item); + } } + return items.toArray(ItemLike[]::new); } - public static void attachBlockEntityCaps(AttachCapabilitiesEvent evt) { - if (evt.getObject() instanceof BlockEntityAbstractImpetus impetus) { - evt.addCapability(IMPETUS_HANDLER, provide(impetus, ForgeCapabilities.ITEM_HANDLER, - () -> new ForgeImpetusCapability(impetus))); + private static ItemLike[] getHexHolderItems() { + List items = new ArrayList<>(); + for (Item item : BuiltInRegistries.ITEM) { + if (item instanceof HexHolderItem) { + items.add(item); + } } + return items.toArray(ItemLike[]::new); } - // i do not know why we need super here - private static SimpleProvider wrapItemEntityDelegate(E entity, - Function make) { - return provide(entity, HexCapabilities.IOTA, - () -> new CapEntityIotaHolder.Wrapper(make.apply(entity))); - } - - private static SimpleProvider provide(Entity entity, Capability capability, - NonNullSupplier supplier) { - return provide(entity::isRemoved, capability, supplier); - } - - private static SimpleProvider provide(BlockEntity be, Capability capability, - NonNullSupplier supplier) { - return provide(be::isRemoved, capability, supplier); - } - - public static SimpleProvider provide(ItemStack stack, Capability capability, - NonNullSupplier supplier) { - return provide(stack::isEmpty, capability, supplier); - } - - private static SimpleProvider provide(BooleanSupplier invalidated, Capability capability, - NonNullSupplier supplier) { - return new SimpleProvider<>(invalidated, capability, LazyOptional.of(supplier)); - } - - public static ICapabilityProvider makeProvider(Capability cap, U instance) { - LazyOptional lazyInstanceButNotReally = LazyOptional.of(() -> instance); - return new SimpleProvider<>(() -> false, cap, lazyInstanceButNotReally); + private static ItemLike[] getVariantItems() { + List items = new ArrayList<>(); + for (Item item : BuiltInRegistries.ITEM) { + if (item instanceof VariantItem) { + items.add(item); + } + } + return items.toArray(ItemLike[]::new); } - public record SimpleProvider(BooleanSupplier invalidated, - Capability capability, - LazyOptional instance) implements ICapabilityProvider { - - @NotNull - @Override - public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { - if (invalidated.getAsBoolean()) { - return LazyOptional.empty(); + private static ItemLike[] getPigmentItems() { + List items = new ArrayList<>(); + for (Item item : BuiltInRegistries.ITEM) { + if (item instanceof PigmentItem) { + items.add(item); } - - return cap == capability ? instance.cast() : LazyOptional.empty(); } + return items.toArray(ItemLike[]::new); } - } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeImpetusCapability.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeImpetusCapability.java index 9da53fa9a5..45d22e2eb8 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeImpetusCapability.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/ForgeImpetusCapability.java @@ -2,7 +2,7 @@ import at.petrak.hexcasting.api.casting.circles.BlockEntityAbstractImpetus; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; +import net.neoforged.neoforge.items.IItemHandler; import org.jetbrains.annotations.NotNull; public record ForgeImpetusCapability(BlockEntityAbstractImpetus impetus) implements IItemHandler { diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/HexCapabilities.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/HexCapabilities.java index 9db3e48d0a..88887ea76d 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/HexCapabilities.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/HexCapabilities.java @@ -2,24 +2,30 @@ import at.petrak.hexcasting.api.addldata.*; import at.petrak.hexcasting.api.client.ClientCastingStack; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.capabilities.EntityCapability; +import net.neoforged.neoforge.capabilities.ItemCapability; import java.util.function.Supplier; +import static at.petrak.hexcasting.api.HexAPI.modLoc; + public final class HexCapabilities { - public static final Capability MEDIA = CapabilityManager.get(new CapabilityToken<>() { - }); - public static final Capability IOTA = CapabilityManager.get(new CapabilityToken<>() { - }); - public static final Capability STORED_HEX = CapabilityManager.get(new CapabilityToken<>() { - }); - public static final Capability VARIANT_ITEM = CapabilityManager.get(new CapabilityToken<>() { - }); - public static final Capability COLOR = CapabilityManager.get(new CapabilityToken<>() { - }); - public static final Capability> CLIENT_CASTING_STACK = CapabilityManager.get(new CapabilityToken<>() { - }); + public static final ItemCapability MEDIA = + ItemCapability.createVoid(modLoc("media"), ADMediaHolder.class); + public static final ItemCapability IOTA = + ItemCapability.createVoid(modLoc("iota"), ADIotaHolder.class); + public static final EntityCapability IOTA_ENTITY = + EntityCapability.createVoid(modLoc("iota_entity"), ADIotaHolder.class); + public static final ItemCapability STORED_HEX = + ItemCapability.createVoid(modLoc("stored_hex"), ADHexHolder.class); + public static final ItemCapability VARIANT_ITEM = + ItemCapability.createVoid(modLoc("variant_item"), ADVariantItem.class); + public static final ItemCapability COLOR = + ItemCapability.createVoid(modLoc("pigment"), ADPigment.class); + @SuppressWarnings("unchecked") + public static final EntityCapability, Void> CLIENT_CASTING_STACK = + (EntityCapability, Void>) (Object) EntityCapability.createVoid( + modLoc("client_casting_stack"), Supplier.class); } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapClientCastingStack.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapClientCastingStack.java index bdba8678ca..ce21392850 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapClientCastingStack.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapClientCastingStack.java @@ -3,9 +3,8 @@ import at.petrak.hexcasting.api.client.ClientCastingStack; import at.petrak.hexcasting.forge.cap.HexCapabilities; import net.minecraft.world.entity.player.Player; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.LogicalSide; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.event.tick.PlayerTickEvent; import java.util.function.Supplier; @@ -16,9 +15,13 @@ public ClientCastingStack get() { } @SubscribeEvent - public static void tickClientPlayer(TickEvent.PlayerTickEvent evt) { - if (evt.side == LogicalSide.CLIENT && !evt.player.isDeadOrDying()) - evt.player.getCapability(HexCapabilities.CLIENT_CASTING_STACK).resolve() - .ifPresent(CastingStack -> CastingStack.get().tick()); + public static void tickClientPlayer(PlayerTickEvent.Post evt) { + var player = evt.getEntity(); + if (player.level().isClientSide() && !player.isDeadOrDying()) { + var cap = player.getCapability(HexCapabilities.CLIENT_CASTING_STACK); + if (cap != null) { + cap.get().tick(); + } + } } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexConditionsBuilder.java b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexConditionsBuilder.java index 93b1cfe529..af614bee93 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexConditionsBuilder.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexConditionsBuilder.java @@ -1,14 +1,14 @@ package at.petrak.hexcasting.forge.datagen; import at.petrak.hexcasting.datagen.IXplatConditionsBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import net.minecraft.advancements.CriterionTriggerInstance; import net.minecraft.data.recipes.FinishedRecipe; import net.minecraft.data.recipes.RecipeBuilder; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; -import net.minecraftforge.common.crafting.ConditionalRecipe; -import net.minecraftforge.common.crafting.conditions.ICondition; -import net.minecraftforge.common.crafting.conditions.IConditionBuilder; +import net.minecraft.world.item.crafting.RecipeSerializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,8 +16,12 @@ import java.util.List; import java.util.function.Consumer; -public class ForgeHexConditionsBuilder implements IXplatConditionsBuilder, IConditionBuilder { - private final List conditions = new ArrayList<>(); +/** + * Injects neoforge:conditions into recipe JSON, matching the NeoForge 1.21.1 + * data load conditions format. Replaces the removed ConditionalRecipe API. + */ +public class ForgeHexConditionsBuilder implements IXplatConditionsBuilder { + private final List conditionJsons = new ArrayList<>(); private final RecipeBuilder parent; public ForgeHexConditionsBuilder(RecipeBuilder parent) { @@ -26,13 +30,22 @@ public ForgeHexConditionsBuilder(RecipeBuilder parent) { @Override public IXplatConditionsBuilder whenModLoaded(String modid) { - conditions.add(modLoaded(modid)); + JsonObject json = new JsonObject(); + json.addProperty("type", "neoforge:mod_loaded"); + json.addProperty("modid", modid); + conditionJsons.add(json); return this; } @Override public IXplatConditionsBuilder whenModMissing(String modid) { - conditions.add(not(modLoaded(modid))); + JsonObject inner = new JsonObject(); + inner.addProperty("type", "neoforge:mod_loaded"); + inner.addProperty("modid", modid); + JsonObject json = new JsonObject(); + json.addProperty("type", "neoforge:not"); + json.add("value", inner); + conditionJsons.add(json); return this; } @@ -54,11 +67,42 @@ public IXplatConditionsBuilder whenModMissing(String modid) { @Override public void save(@NotNull Consumer consumer, @NotNull ResourceLocation resourceLocation) { - var conditionalBuilder = ConditionalRecipe.builder(); - for (ICondition condition : conditions) { - conditionalBuilder.addCondition(condition); - } - conditionalBuilder.addRecipe(recipeConsumer -> parent.save(recipeConsumer, resourceLocation)) - .build(consumer, resourceLocation); + Consumer withConditions = json -> consumer.accept(new FinishedRecipe() { + @Override + public void serializeRecipeData(@NotNull JsonObject jsonObject) { + json.serializeRecipeData(jsonObject); + if (!conditionJsons.isEmpty()) { + JsonArray conditions = new JsonArray(); + for (JsonObject cond : conditionJsons) { + conditions.add(cond); + } + jsonObject.add("neoforge:conditions", conditions); + } + } + + @Override + public ResourceLocation getId() { + return json.getId(); + } + + @Override + public RecipeSerializer getType() { + return json.getType(); + } + + @Nullable + @Override + public JsonObject serializeAdvancement() { + return json.serializeAdvancement(); + } + + @Nullable + @Override + public ResourceLocation getAdvancementId() { + return json.getAdvancementId(); + } + }); + + parent.save(withConditions, resourceLocation); } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexDataGenerators.java b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexDataGenerators.java index c5ed351ea7..0920246190 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexDataGenerators.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexDataGenerators.java @@ -28,12 +28,12 @@ import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; -import net.minecraftforge.common.Tags; -import net.minecraftforge.common.ToolActions; -import net.minecraftforge.common.data.DatapackBuiltinEntriesProvider; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.data.event.GatherDataEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.neoforged.neoforge.common.Tags; +import net.neoforged.neoforge.common.ItemAbilities; +import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.data.event.GatherDataEvent; +import net.neoforged.bus.api.SubscribeEvent; import java.util.EnumMap; import java.util.List; @@ -162,7 +162,7 @@ public Ingredient stick() { @Override public Ingredient whenModIngredient(Ingredient defaultIngredient, String modid, Ingredient modIngredient) { - return ForgeModConditionalIngredient.of(defaultIngredient, modid, modIngredient); + return ForgeModConditionalIngredient.of(defaultIngredient, modid, modIngredient).toVanilla(); } // https://github.com/vectorwing/FarmersDelight/blob/1.18.2/src/generated/resources/data/farmersdelight/recipes/cutting/amethyst_block.json @@ -171,7 +171,7 @@ public FarmersDelightToolIngredient axeStrip() { return () -> { JsonObject object = new JsonObject(); object.addProperty("type", "farmersdelight:tool_action"); - object.addProperty("action", ToolActions.AXE_STRIP.name()); + object.addProperty("action", ItemAbilities.AXE_STRIP.name()); return object; }; } @@ -181,7 +181,7 @@ public FarmersDelightToolIngredient axeDig() { return () -> { JsonObject object = new JsonObject(); object.addProperty("type", "farmersdelight:tool_action"); - object.addProperty("action", ToolActions.AXE_DIG.name()); + object.addProperty("action", ItemAbilities.AXE_DIG.name()); return object; }; } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexLootModGen.java b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexLootModGen.java index 521996ab29..b3cfd8a0f2 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexLootModGen.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/ForgeHexLootModGen.java @@ -10,8 +10,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.data.GlobalLootModifierProvider; -import net.minecraftforge.common.loot.LootTableIdCondition; +import net.neoforged.neoforge.common.data.GlobalLootModifierProvider; +import net.neoforged.neoforge.common.loot.LootTableIdCondition; import static at.petrak.hexcasting.api.HexAPI.modLoc; diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/TagsProviderEFHSetter.java b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/TagsProviderEFHSetter.java deleted file mode 100644 index ddda7d2966..0000000000 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/TagsProviderEFHSetter.java +++ /dev/null @@ -1,7 +0,0 @@ -package at.petrak.hexcasting.forge.datagen; - -import net.minecraftforge.common.data.ExistingFileHelper; - -public interface TagsProviderEFHSetter { - void setEFH(ExistingFileHelper efh); -} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexBlockStatesAndModels.java b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexBlockStatesAndModels.java index 1ed69ec340..a3c29ddb18 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexBlockStatesAndModels.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexBlockStatesAndModels.java @@ -14,12 +14,12 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraftforge.client.model.generators.BlockModelBuilder; -import net.minecraftforge.client.model.generators.ConfiguredModel; -import net.minecraftforge.client.model.generators.ModelBuilder; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.client.model.generators.BlockModelBuilder; +import net.neoforged.neoforge.client.model.generators.ConfiguredModel; +import net.neoforged.neoforge.client.model.generators.ModelBuilder; +import net.neoforged.neoforge.common.data.ExistingFileHelper; -import static net.minecraftforge.client.model.generators.ModelProvider.BLOCK_FOLDER; +import static net.neoforged.neoforge.client.model.generators.ModelProvider.BLOCK_FOLDER; public class HexBlockStatesAndModels extends PaucalBlockStateAndModelProvider { public HexBlockStatesAndModels(PackOutput output, ExistingFileHelper exFileHelper) { diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexItemModels.java b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexItemModels.java index 60985fb338..46e3a4ad6d 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexItemModels.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/datagen/xplat/HexItemModels.java @@ -22,9 +22,9 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.level.block.Block; -import net.minecraftforge.client.model.generators.ModelFile; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.registries.ForgeRegistries; +import net.minecraft.core.registries.BuiltInRegistries; +import net.neoforged.neoforge.client.model.generators.ModelFile; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import java.util.Arrays; import java.util.Objects; @@ -40,11 +40,11 @@ public HexItemModels(PackOutput output, ExistingFileHelper existingFileHelper) { private static final Integer[] PACKAGED_SPELL_HANDHELD_VARIANTS = {5}; private static String getPath(Item item) { - return Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(item)).getPath(); + return Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(item)).location().getPath(); } private static String getPath(Block block) { - return Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(block)).getPath(); + return Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(block)).location().getPath(); } @Override diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/CuriosApiInterop.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/CuriosApiInterop.java index dfb750c35a..00064c330a 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/CuriosApiInterop.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/CuriosApiInterop.java @@ -3,22 +3,25 @@ import at.petrak.hexcasting.api.misc.DiscoveryHandlers; import at.petrak.hexcasting.common.items.HexBaubleItem; import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker; -import at.petrak.hexcasting.forge.cap.ForgeCapabilityHandler; +import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.interop.HexInterop; -import com.google.common.collect.Multimap; -import net.minecraft.world.entity.ai.attributes.Attribute; -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.fml.InterModComms; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; +import net.neoforged.fml.InterModComms; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.fml.event.lifecycle.InterModEnqueueEvent; +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; import top.theillusivec4.curios.api.CuriosCapability; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.SlotTypeMessage; import top.theillusivec4.curios.api.SlotTypePreset; import top.theillusivec4.curios.api.type.capability.ICurio; +import com.google.common.collect.Multimap; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.item.ItemStack; + import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; @@ -42,33 +45,39 @@ public ItemStack getStack() { } @Override - public Multimap getAttributeModifiers(SlotContext slotContext, UUID uuid) { + public Multimap, AttributeModifier> getAttributeModifiers(SlotContext slotContext, UUID uuid) { var map = ICurio.super.getAttributeModifiers(slotContext, uuid); - map.putAll(this.bauble.getHexBaubleAttrs(this.stack)); + for (var entry : this.bauble.getHexBaubleAttrs(this.stack).entries()) { + var key = BuiltInRegistries.ATTRIBUTE.getResourceKey(entry.getKey()); + key.ifPresent(k -> map.put(BuiltInRegistries.ATTRIBUTE.getHolderOrThrow(k), entry.getValue())); + } return map; } } - public static ICapabilityProvider curioCap(ItemStack stack) { - return ForgeCapabilityHandler.makeProvider(CuriosCapability.ITEM, new Wrapper(stack)); + public static void registerCurioCapability(RegisterCapabilitiesEvent evt) { + evt.registerItem(CuriosCapability.ITEM, (stack, ctx) -> + stack.getItem() instanceof HexBaubleItem ? new Wrapper(stack) : null, + HexItems.SCRYING_LENS); } - public static void init() { DiscoveryHandlers.addDebugItemDiscoverer((player, type) -> { AtomicReference result = new AtomicReference<>(ItemStack.EMPTY); - player.getCapability(CuriosCapability.INVENTORY).ifPresent(handler -> { + var handler = player.getCapability(CuriosCapability.INVENTORY); + if (handler != null) { + search: for (var stacksHandler : handler.getCurios().values()) { var stacks = stacksHandler.getStacks(); for (int i = 0; i < stacks.getSlots(); i++) { var stack = stacks.getStackInSlot(i); if (ItemCreativeUnlocker.isDebug(stack, type)) { result.set(stack); - return; + break search; } } } - }); + } return result.get(); }); } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/CuriosRenderers.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/CuriosRenderers.java index 3ec7edd483..675520b67a 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/CuriosRenderers.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/CuriosRenderers.java @@ -8,9 +8,9 @@ import net.minecraft.client.model.geom.builders.CubeListBuilder; import net.minecraft.client.model.geom.builders.LayerDefinition; import net.minecraft.client.model.geom.builders.MeshDefinition; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.event.EntityRenderersEvent; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.client.event.EntityRenderersEvent; import top.theillusivec4.curios.api.client.CuriosRendererRegistry; @OnlyIn(Dist.CLIENT) diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/LensCurioRenderer.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/LensCurioRenderer.java index 38f5ff065f..a9f590d950 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/LensCurioRenderer.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/curios/LensCurioRenderer.java @@ -19,7 +19,7 @@ import top.theillusivec4.curios.api.client.ICurioRenderer; public class LensCurioRenderer implements ICurioRenderer { - public static final ModelLayerLocation LAYER = new ModelLayerLocation(new ResourceLocation(HexAPI.MOD_ID, "lens"), "lens"); + public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(HexAPI.MOD_ID, "lens"), "lens"); private final HumanoidModel model; diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/BrainsweepRecipeCategory.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/BrainsweepRecipeCategory.java index 6dddb8015a..7ac37293b6 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/BrainsweepRecipeCategory.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/BrainsweepRecipeCategory.java @@ -4,6 +4,7 @@ import at.petrak.hexcasting.common.recipe.BrainsweepRecipe; import com.mojang.blaze3d.systems.RenderSystem; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; +import mezz.jei.api.gui.builder.ITooltipBuilder; import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.drawable.IDrawableStatic; import mezz.jei.api.gui.ingredient.IRecipeSlotsView; @@ -18,13 +19,10 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.jetbrains.annotations.NotNull; -import java.util.Collections; -import java.util.List; - import static at.petrak.hexcasting.api.HexAPI.modLoc; import static at.petrak.hexcasting.client.render.RenderLib.renderEntity; @@ -63,15 +61,12 @@ IDrawable getIcon() { } @Override - public @NotNull - List getTooltipStrings(@NotNull BrainsweepRecipe recipe, + public void getTooltip(@NotNull ITooltipBuilder tooltip, @NotNull BrainsweepRecipe recipe, @NotNull IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) { if (37 <= mouseX && mouseX <= 37 + 26 && 19 <= mouseY && mouseY <= 19 + 48) { Minecraft mc = Minecraft.getInstance(); - return recipe.entityIn().getTooltip(mc.options.advancedItemTooltips); + tooltip.addAll(recipe.entityIn().getTooltip(mc.options.advancedItemTooltips)); } - - return Collections.emptyList(); } @Override diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/EdifyRecipeCategory.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/EdifyRecipeCategory.java index 84ab9bab31..14023a25a0 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/EdifyRecipeCategory.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/EdifyRecipeCategory.java @@ -15,8 +15,8 @@ import net.minecraft.tags.ItemTags; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.jetbrains.annotations.NotNull; import static at.petrak.hexcasting.api.HexAPI.modLoc; diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/HexJEIPlugin.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/HexJEIPlugin.java index 32572ba10c..f16ad99c72 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/HexJEIPlugin.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/HexJEIPlugin.java @@ -17,6 +17,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; @@ -56,8 +57,11 @@ public void registerCategories(IRecipeCategoryRegistration registration) { public void registerRecipes(@NotNull IRecipeRegistration registration) { Level level = Minecraft.getInstance().level; if (level != null) { - registration.addRecipes(BRAINSWEEPING, - level.getRecipeManager().getAllRecipesFor(HexRecipeStuffRegistry.BRAINSWEEP_TYPE)); + var brainsweepRecipes = level.getRecipeManager().getAllRecipesFor(HexRecipeStuffRegistry.BRAINSWEEP_TYPE) + .stream() + .map(RecipeHolder::value) + .toList(); + registration.addRecipes(BRAINSWEEPING, brainsweepRecipes); } if (PhialRecipeStackBuilder.shouldAddRecipe()) { diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PhialRecipeCategory.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PhialRecipeCategory.java index 23a4272a4e..552e4947a0 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PhialRecipeCategory.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PhialRecipeCategory.java @@ -14,8 +14,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.jetbrains.annotations.NotNull; import static at.petrak.hexcasting.api.HexAPI.modLoc; diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexArgumentTypeRegistry.java b/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexArgumentTypeRegistry.java index 4a3450372a..7aff9e1d6c 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexArgumentTypeRegistry.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexArgumentTypeRegistry.java @@ -3,33 +3,33 @@ import at.petrak.hexcasting.api.HexAPI; import at.petrak.hexcasting.common.command.PatternResLocArgument; import com.mojang.brigadier.arguments.ArgumentType; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.commands.synchronization.ArgumentTypeInfos; import net.minecraft.commands.synchronization.SingletonArgumentInfo; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; -// ArgumentTypeInfos.java public class ForgeHexArgumentTypeRegistry { public static final DeferredRegister> ARGUMENT_TYPES = DeferredRegister.create( - ForgeRegistries.COMMAND_ARGUMENT_TYPES, HexAPI.MOD_ID); + BuiltInRegistries.COMMAND_ARGUMENT_TYPE, HexAPI.MOD_ID); // how fucking ergonomic - public static final RegistryObject.Template>> + public static final DeferredHolder, + ArgumentTypeInfo.Template>> PATTERN_RESLOC = register(PatternResLocArgument.class, "pattern", SingletonArgumentInfo.contextFree(PatternResLocArgument::id) ); - private static , T extends ArgumentTypeInfo.Template, I extends ArgumentTypeInfo> - RegistryObject> register( + @SuppressWarnings("unchecked") + private static , T extends ArgumentTypeInfo.Template> + DeferredHolder, ArgumentTypeInfo> register( Class clazz, String name, ArgumentTypeInfo ati) { - var robj = ARGUMENT_TYPES.register(name, () -> ati); + var holder = ARGUMENT_TYPES.register(name, () -> ati); ArgumentTypeInfos.registerByClass(clazz, ati); - return robj; + return (DeferredHolder, ArgumentTypeInfo>) (Object) holder; } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexIngredientTypes.java b/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexIngredientTypes.java new file mode 100644 index 0000000000..74ab66518b --- /dev/null +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexIngredientTypes.java @@ -0,0 +1,27 @@ +package at.petrak.hexcasting.forge.lib; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.forge.recipe.ForgeModConditionalIngredient; +import at.petrak.hexcasting.forge.recipe.ForgeUnsealedIngredient; +import net.neoforged.neoforge.common.crafting.IngredientType; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; + +import java.util.function.Supplier; + +public class ForgeHexIngredientTypes { + public static final DeferredRegister> INGREDIENT_TYPES = + DeferredRegister.create(NeoForgeRegistries.Keys.INGREDIENT_TYPES, HexAPI.MOD_ID); + + public static final Supplier> UNSEALED = + INGREDIENT_TYPES.register("unsealed", () -> new IngredientType<>( + ForgeUnsealedIngredient.CODEC, + ForgeUnsealedIngredient.STREAM_CODEC + )); + + public static final Supplier> MOD_CONDITIONAL = + INGREDIENT_TYPES.register("mod_conditional", () -> new IngredientType<>( + ForgeModConditionalIngredient.CODEC, + ForgeModConditionalIngredient.STREAM_CODEC + )); +} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexLootMods.java b/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexLootMods.java index 7581f6aaab..6df9492d9b 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexLootMods.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/lib/ForgeHexLootMods.java @@ -5,22 +5,22 @@ import at.petrak.hexcasting.forge.loot.ForgeHexLoreLootMod; import at.petrak.hexcasting.forge.loot.ForgeHexScrollLootMod; import at.petrak.hexcasting.forge.loot.ForgeHexCypherLootMod; -import com.mojang.serialization.Codec; -import net.minecraftforge.common.loot.IGlobalLootModifier; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; +import com.mojang.serialization.MapCodec; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; public class ForgeHexLootMods { - public static final DeferredRegister> REGISTRY = DeferredRegister.create( - ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, HexAPI.MOD_ID); + public static final DeferredRegister> REGISTRY = DeferredRegister.create( + NeoForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, HexAPI.MOD_ID); - public static final RegistryObject> INJECT_SCROLLS = REGISTRY.register( - "inject_scrolls", ForgeHexScrollLootMod.CODEC); - public static final RegistryObject> INJECT_LORE = REGISTRY.register( - "inject_lore", ForgeHexLoreLootMod.CODEC); - public static final RegistryObject> INJECT_CYPHERS = REGISTRY.register( - "inject_cyphers", ForgeHexCypherLootMod.CODEC); - public static final RegistryObject> AMETHYST = REGISTRY.register( - "amethyst_cluster", ForgeHexAmethystLootMod.CODEC); + public static final DeferredHolder, MapCodec> INJECT_SCROLLS = REGISTRY.register( + "inject_scrolls", () -> ForgeHexScrollLootMod.CODEC.get()); + public static final DeferredHolder, MapCodec> INJECT_LORE = REGISTRY.register( + "inject_lore", () -> ForgeHexLoreLootMod.CODEC.get()); + public static final DeferredHolder, MapCodec> INJECT_CYPHERS = REGISTRY.register( + "inject_cyphers", () -> ForgeHexCypherLootMod.CODEC.get()); + public static final DeferredHolder, MapCodec> AMETHYST = REGISTRY.register( + "amethyst_cluster", () -> ForgeHexAmethystLootMod.CODEC.get()); } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexAmethystLootMod.java b/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexAmethystLootMod.java index 671e9cec5b..c15ffc7259 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexAmethystLootMod.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexAmethystLootMod.java @@ -1,23 +1,25 @@ package at.petrak.hexcasting.forge.loot; +import com.mojang.serialization.Codec; import at.petrak.hexcasting.common.loot.AmethystReducerFunc; import at.petrak.hexcasting.common.loot.HexLootHandler; import at.petrak.hexcasting.forge.lib.ForgeHexLootMods; import com.google.common.base.Suppliers; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.loot.LootModifier; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.common.loot.LootModifier; import org.jetbrains.annotations.NotNull; import java.util.function.Supplier; public class ForgeHexAmethystLootMod extends LootModifier { - public static final Supplier> CODEC = - Suppliers.memoize(() -> RecordCodecBuilder.create( + public static final Supplier> CODEC = + Suppliers.memoize(() -> RecordCodecBuilder.mapCodec( inst -> codecStart(inst).and( Codec.DOUBLE.fieldOf("shardDelta").forGetter(it -> it.shardDelta) ).apply(inst, ForgeHexAmethystLootMod::new) @@ -33,8 +35,15 @@ public ForgeHexAmethystLootMod(LootItemCondition[] conditionsIn, double shardDel @Override protected @NotNull ObjectArrayList doApply(ObjectArrayList generatedLoot, LootContext context) { - var injectPool = context.getResolver().getLootTable(HexLootHandler.TABLE_INJECT_AMETHYST_CLUSTER); - injectPool.getRandomItemsRaw(context, generatedLoot::add); + var injectPool = context.getResolver() + .lookup(net.minecraft.world.level.storage.loot.LootDataType.TABLE.registryKey()) + .orElseThrow() + .get(net.minecraft.resources.ResourceKey.create( + net.minecraft.world.level.storage.loot.LootDataType.TABLE.registryKey(), + HexLootHandler.TABLE_INJECT_AMETHYST_CLUSTER)) + .orElseThrow() + .value(); + injectPool.getRandomItems(context, generatedLoot::add); for (var stack : generatedLoot) { AmethystReducerFunc.doStatic(stack, context, this.shardDelta); @@ -44,7 +53,7 @@ public ForgeHexAmethystLootMod(LootItemCondition[] conditionsIn, double shardDel } @Override - public Codec codec() { + public MapCodec codec() { return ForgeHexLootMods.AMETHYST.get(); } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexCypherLootMod.java b/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexCypherLootMod.java index 385bf4a64e..50760140df 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexCypherLootMod.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexCypherLootMod.java @@ -1,23 +1,25 @@ package at.petrak.hexcasting.forge.loot; +import com.mojang.serialization.Codec; import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.loot.AddHexToAncientCypherFunc; import at.petrak.hexcasting.forge.lib.ForgeHexLootMods; import com.google.common.base.Suppliers; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.loot.LootModifier; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.common.loot.LootModifier; import org.jetbrains.annotations.NotNull; import java.util.function.Supplier; public class ForgeHexCypherLootMod extends LootModifier { - public static final Supplier> CODEC = - Suppliers.memoize(() -> RecordCodecBuilder.create( + public static final Supplier> CODEC = + Suppliers.memoize(() -> RecordCodecBuilder.mapCodec( inst -> codecStart(inst).and( Codec.DOUBLE.fieldOf("chance").forGetter(it -> it.chance) ).apply(inst, ForgeHexCypherLootMod::new) @@ -42,7 +44,7 @@ public ForgeHexCypherLootMod(LootItemCondition[] conditionsIn, double chance) { } @Override - public Codec codec() { + public MapCodec codec() { return ForgeHexLootMods.INJECT_CYPHERS.get(); } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexLoreLootMod.java b/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexLoreLootMod.java index e5de13a237..3d67585054 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexLoreLootMod.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexLoreLootMod.java @@ -1,22 +1,24 @@ package at.petrak.hexcasting.forge.loot; +import com.mojang.serialization.Codec; import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.forge.lib.ForgeHexLootMods; import com.google.common.base.Suppliers; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.loot.LootModifier; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.common.loot.LootModifier; import org.jetbrains.annotations.NotNull; import java.util.function.Supplier; public class ForgeHexLoreLootMod extends LootModifier { - public static final Supplier> CODEC = - Suppliers.memoize(() -> RecordCodecBuilder.create( + public static final Supplier> CODEC = + Suppliers.memoize(() -> RecordCodecBuilder.mapCodec( inst -> codecStart(inst).and( Codec.DOUBLE.fieldOf("chance").forGetter(it -> it.chance) ).apply(inst, ForgeHexLoreLootMod::new) @@ -39,7 +41,7 @@ public ForgeHexLoreLootMod(LootItemCondition[] conditionsIn, double chance) { } @Override - public Codec codec() { + public MapCodec codec() { return ForgeHexLootMods.INJECT_LORE.get(); } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexScrollLootMod.java b/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexScrollLootMod.java index 114a19b2b5..e0de62cbb1 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexScrollLootMod.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/loot/ForgeHexScrollLootMod.java @@ -1,25 +1,26 @@ package at.petrak.hexcasting.forge.loot; +import com.mojang.serialization.Codec; import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.loot.AddPerWorldPatternToScrollFunc; import at.petrak.hexcasting.common.loot.HexLootHandler; import at.petrak.hexcasting.forge.lib.ForgeHexLootMods; import com.google.common.base.Suppliers; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.loot.IGlobalLootModifier; -import net.minecraftforge.common.loot.LootModifier; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.common.loot.LootModifier; import org.jetbrains.annotations.NotNull; import java.util.function.Supplier; public class ForgeHexScrollLootMod extends LootModifier { - public static final Supplier> CODEC = - Suppliers.memoize(() -> RecordCodecBuilder.create( + public static final Supplier> CODEC = + Suppliers.memoize(() -> RecordCodecBuilder.mapCodec( inst -> codecStart(inst).and( Codec.INT.fieldOf("countRange").forGetter(it -> it.countRange) ).apply(inst, ForgeHexScrollLootMod::new) @@ -45,7 +46,7 @@ public ForgeHexScrollLootMod(LootItemCondition[] conditionsIn, int countRange) { } @Override - public Codec codec() { + public MapCodec codec() { return ForgeHexLootMods.INJECT_SCROLLS.get(); } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeAccessorBuiltInRegistries.java b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeAccessorBuiltInRegistries.java index b086d8714d..8b73c83eba 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeAccessorBuiltInRegistries.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeAccessorBuiltInRegistries.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(BuiltInRegistries.class) +@Mixin(value = BuiltInRegistries.class, remap = false) public interface ForgeAccessorBuiltInRegistries { @Invoker("registerDefaulted") static DefaultedRegistry hex$registerDefaulted(ResourceKey> registryName, diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinBlockColors.java b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinBlockColors.java deleted file mode 100644 index 04983c5019..0000000000 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinBlockColors.java +++ /dev/null @@ -1,16 +0,0 @@ -package at.petrak.hexcasting.forge.mixin; - -import at.petrak.hexcasting.forge.ForgeHexClientInitializer; -import net.minecraft.client.color.block.BlockColors; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(BlockColors.class) -public class ForgeMixinBlockColors { - @Inject(method = "createDefault", at = @At("RETURN")) - private static void hex$onCreateDefault(CallbackInfoReturnable info) { - ForgeHexClientInitializer.GLOBAL_BLOCK_COLORS = info.getReturnValue(); - } -} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinCustomPacketPayload.java b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinCustomPacketPayload.java new file mode 100644 index 0000000000..ab1f1327e5 --- /dev/null +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinCustomPacketPayload.java @@ -0,0 +1,60 @@ +package at.petrak.hexcasting.forge.mixin; + +import at.petrak.hexcasting.common.msgs.*; +import at.petrak.hexcasting.forge.network.*; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Map; + +import static at.petrak.hexcasting.api.HexAPI.modLoc; + +/** + * The encoder uses CustomPacketPayload$1.findCodec(id), which looks up id in a pre-built idToType map. + * When our hex payloads aren't in that map, it falls back to DiscardedPayload codec → ClassCastException. + * This mixin returns our real codecs for hexcasting payload IDs so encoding succeeds. + */ +@Mixin(targets = "net.minecraft.network.protocol.common.custom.CustomPacketPayload$1", remap = true) +public abstract class ForgeMixinCustomPacketPayload { + + private static final Map> HEX_CODECS = Map.ofEntries( + Map.entry(modLoc("pat_sc"), MsgNewSpellPatternS2C.STREAM_CODEC), + Map.entry(modLoc("pat_cs"), MsgNewSpellPatternC2S.STREAM_CODEC), + Map.entry(modLoc("scroll"), MsgShiftScrollC2S.STREAM_CODEC), + Map.entry(modLoc("sntnl"), MsgSentinelStatusUpdateAck.STREAM_CODEC), + Map.entry(modLoc("color"), MsgPigmentUpdateAck.STREAM_CODEC), + Map.entry(modLoc("altiora"), MsgAltioraUpdateAck.STREAM_CODEC), + Map.entry(modLoc("cprtcl"), MsgCastParticleS2C.STREAM_CODEC), + Map.entry(modLoc("cgui"), MsgOpenSpellGuiS2C.STREAM_CODEC), + Map.entry(modLoc("beep"), MsgBeepS2C.STREAM_CODEC), + Map.entry(modLoc("sweep"), MsgBrainsweepAck.STREAM_CODEC), + Map.entry(modLoc("wallscr"), MsgNewWallScrollS2C.STREAM_CODEC), + Map.entry(modLoc("redoscroll"), MsgRecalcWallScrollDisplayS2C.STREAM_CODEC), + Map.entry(modLoc("spi_pats_sc"), MsgNewSpiralPatternsS2C.STREAM_CODEC), + Map.entry(modLoc("clr_spi_pats_sc"), MsgClearSpiralPatternsS2C.STREAM_CODEC) + ); + + /** + * Injected at HEAD of findCodec(ResourceLocation). When the payload id is hexcasting and we have + * a codec, return it so the encoder uses our codec instead of falling back to DiscardedPayload. + */ + @Inject( + method = "findCodec(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/network/codec/StreamCodec;", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private void hexcasting$findCodec(ResourceLocation id, CallbackInfoReturnable cir) { + StreamCodec codec = HEX_CODECS.get(id); + if (codec != null) { + cir.setReturnValue(codec); + cir.cancel(); + } + } +} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinItemColors.java b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinItemColors.java deleted file mode 100644 index 2ef14ac4de..0000000000 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinItemColors.java +++ /dev/null @@ -1,17 +0,0 @@ -package at.petrak.hexcasting.forge.mixin; - -import at.petrak.hexcasting.forge.ForgeHexClientInitializer; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.color.item.ItemColors; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(ItemColors.class) -public class ForgeMixinItemColors { - @Inject(method = "createDefault", at = @At("RETURN")) - private static void hex$onCreateDefault(BlockColors blockColors, CallbackInfoReturnable info) { - ForgeHexClientInitializer.GLOBAL_ITEM_COLORS = info.getReturnValue(); - } -} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinNetworkRegistry.java b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinNetworkRegistry.java new file mode 100644 index 0000000000..a5047bfd3a --- /dev/null +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinNetworkRegistry.java @@ -0,0 +1,278 @@ +package at.petrak.hexcasting.forge.mixin; + +import at.petrak.hexcasting.common.msgs.*; +import at.petrak.hexcasting.forge.network.*; +import com.google.common.collect.ImmutableSet; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.ClientCommonPacketListener; +import net.minecraft.network.protocol.common.ServerCommonPacketListener; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.network.ConnectionProtocol; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.common.extensions.ICommonPacketListener; +import net.neoforged.neoforge.network.registration.NetworkPayloadSetup; +import net.neoforged.neoforge.network.registration.NetworkRegistry; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +import net.neoforged.neoforge.network.registration.PayloadRegistration; + +import static at.petrak.hexcasting.api.HexAPI.MOD_ID; +import static at.petrak.hexcasting.api.HexAPI.modLoc; + +/** + * Bypasses NeoForge 21.1.x payload direction checks for hex casting client-bound packets. + * Also ensures getCodec returns our codec when the encoder looks it up (avoids ClassCastException to DiscardedPayload). + * When handleModdedPayload's lookup returns null (client-side play setup lacks hex channels), we handle hex payloads directly. + */ +@Mixin(value = NetworkRegistry.class, remap = false) +public class ForgeMixinNetworkRegistry { + + private static final Set HEX_PLAY_PAYLOAD_IDS = Set.of( + modLoc("pat_sc"), modLoc("sntnl"), modLoc("color"), modLoc("altiora"), + modLoc("cprtcl"), modLoc("cgui"), modLoc("beep"), modLoc("sweep"), + modLoc("wallscr"), modLoc("redoscroll"), modLoc("spi_pats_sc"), modLoc("clr_spi_pats_sc") + ); + + /** Client-to-server payload IDs (must be allowed when client sends). */ + private static final Set HEX_C2S_PAYLOAD_IDS = Set.of( + modLoc("pat_cs"), modLoc("scroll") + ); + + /** Handlers for hex client-bound payloads when NeoForge lookup returns null (e.g. client play setup). */ + private static final Map> HEX_CLIENT_HANDLERS = Map.ofEntries( + Map.entry(modLoc("pat_sc"), p -> MsgNewSpellPatternS2C.handle((MsgNewSpellPatternS2C) p)), + Map.entry(modLoc("sntnl"), p -> MsgSentinelStatusUpdateAck.handle((MsgSentinelStatusUpdateAck) p)), + Map.entry(modLoc("color"), p -> MsgPigmentUpdateAck.handle((MsgPigmentUpdateAck) p)), + Map.entry(modLoc("altiora"), p -> MsgAltioraUpdateAck.handle((MsgAltioraUpdateAck) p)), + Map.entry(modLoc("cprtcl"), p -> MsgCastParticleS2C.handle((MsgCastParticleS2C) p)), + Map.entry(modLoc("cgui"), p -> MsgOpenSpellGuiS2C.handle((MsgOpenSpellGuiS2C) p)), + Map.entry(modLoc("beep"), p -> MsgBeepS2C.handle((MsgBeepS2C) p)), + Map.entry(modLoc("sweep"), p -> MsgBrainsweepAck.handle((MsgBrainsweepAck) p)), + Map.entry(modLoc("wallscr"), p -> MsgNewWallScrollS2C.handle((MsgNewWallScrollS2C) p)), + Map.entry(modLoc("redoscroll"), p -> MsgRecalcWallScrollDisplayS2C.handle((MsgRecalcWallScrollDisplayS2C) p)), + Map.entry(modLoc("spi_pats_sc"), p -> MsgNewSpiralPatternsS2C.handle((MsgNewSpiralPatternsS2C) p)), + Map.entry(modLoc("clr_spi_pats_sc"), p -> MsgClearSpiralPatternsS2C.handle((MsgClearSpiralPatternsS2C) p)) + ); + + @Inject( + method = "checkPacket(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/protocol/common/ServerCommonPacketListener;)V", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private static void hexcasting$bypassServerPacketCheck(Packet packet, ServerCommonPacketListener listener, CallbackInfo ci) { + if (packet instanceof ClientboundCustomPayloadPacket cp) { + if (MOD_ID.equals(cp.payload().type().id().getNamespace())) { + ci.cancel(); + } + } else if (packet instanceof ServerboundCustomPayloadPacket cp) { + if (HEX_C2S_PAYLOAD_IDS.contains(cp.payload().type().id())) { + ci.cancel(); + } + } + } + + @Inject( + method = "checkPacket(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/protocol/common/ClientCommonPacketListener;)V", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private static void hexcasting$bypassPacketCheck(Packet packet, ClientCommonPacketListener listener, CallbackInfo ci) { + if (packet instanceof ClientboundCustomPayloadPacket cp) { + if (MOD_ID.equals(cp.payload().type().id().getNamespace())) { + ci.cancel(); + } + } else if (packet instanceof ServerboundCustomPayloadPacket cp) { + if (HEX_C2S_PAYLOAD_IDS.contains(cp.payload().type().id())) { + ci.cancel(); + } + } + } + + @Inject( + method = "hasChannel(Lnet/neoforged/neoforge/common/extensions/ICommonPacketListener;Lnet/minecraft/resources/ResourceLocation;)Z", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private static void hexcasting$hasHexChannelListener(ICommonPacketListener listener, ResourceLocation id, CallbackInfoReturnable cir) { + if (HEX_PLAY_PAYLOAD_IDS.contains(id) || HEX_C2S_PAYLOAD_IDS.contains(id)) { + cir.setReturnValue(true); + cir.cancel(); + } + } + + @Inject( + method = "hasChannel(Lnet/minecraft/network/Connection;Lnet/minecraft/network/ConnectionProtocol;Lnet/minecraft/resources/ResourceLocation;)Z", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private static void hexcasting$hasHexChannelConnection(Connection connection, ConnectionProtocol protocol, ResourceLocation id, CallbackInfoReturnable cir) { + if (HEX_PLAY_PAYLOAD_IDS.contains(id) || HEX_C2S_PAYLOAD_IDS.contains(id)) { + cir.setReturnValue(true); + cir.cancel(); + } + } + + /** handleModdedPayload uses hasAdhocChannel (not hasChannel) when setup.getChannel returns null. */ + @Inject( + method = "hasAdhocChannel(Lnet/minecraft/network/ConnectionProtocol;Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/network/protocol/PacketFlow;)Z", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private static void hexcasting$hasAdhocHexChannel(ConnectionProtocol protocol, ResourceLocation id, PacketFlow flow, CallbackInfoReturnable cir) { + if (flow == PacketFlow.CLIENTBOUND && HEX_PLAY_PAYLOAD_IDS.contains(id)) { + cir.setReturnValue(true); + cir.cancel(); + } else if (flow == PacketFlow.SERVERBOUND && HEX_C2S_PAYLOAD_IDS.contains(id)) { + cir.setReturnValue(true); + cir.cancel(); + } + } + + /** + * When handleModdedPayload runs, the client's connection setup often lacks hex play channels (they're not + * negotiated). Dispatch hex payloads directly here so we never hit the "no registration" disconnect. + */ + @Inject( + method = "handleModdedPayload(Lnet/minecraft/network/protocol/common/ClientCommonPacketListener;Lnet/minecraft/network/protocol/common/ClientboundCustomPayloadPacket;)V", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private static void hexcasting$handleHexPayloadDirectly(ClientCommonPacketListener listener, ClientboundCustomPayloadPacket packet, CallbackInfo ci) { + var payload = packet.payload(); + var id = payload.type().id(); + var handler = HEX_CLIENT_HANDLERS.get(id); + if (handler != null) { + handler.accept(payload); + ci.cancel(); + } + } + + /** + * When handleModdedPayload runs on server, the registration lookup can return null for hex C2S payloads. + * Intercept and dispatch directly. + */ + @Inject( + method = "handleModdedPayload(Lnet/minecraft/network/protocol/common/ServerCommonPacketListener;Lnet/minecraft/network/protocol/common/ServerboundCustomPayloadPacket;)V", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private static void hexcasting$handleHexServerPayloadDirectly( + ServerCommonPacketListener listener, + ServerboundCustomPayloadPacket packet, + CallbackInfo ci + ) { + var payload = packet.payload(); + var id = payload.type().id(); + if (!HEX_C2S_PAYLOAD_IDS.contains(id)) return; + if (!(listener instanceof ServerGamePacketListenerImpl gameListener)) return; + var player = gameListener.player; + var server = player.getServer(); + if (server == null) return; + if (id.equals(modLoc("pat_cs"))) { + ((MsgNewSpellPatternC2S) payload).handle(server, player); + ci.cancel(); + } else if (id.equals(modLoc("scroll"))) { + ((MsgShiftScrollC2S) payload).handle(server, player); + ci.cancel(); + } + } + + /** When handleModdedPayload's registration Map.get returns null for hex payloads, fallback to play map. */ + @Redirect( + method = "handleModdedPayload(Lnet/minecraft/network/protocol/common/ClientCommonPacketListener;Lnet/minecraft/network/protocol/common/ClientboundCustomPayloadPacket;)V", + at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 1), + remap = false + ) + private static Object hexcasting$fallbackPayloadRegistration( + Map map, + Object key, + ClientCommonPacketListener listener, + ClientboundCustomPayloadPacket packet + ) { + Object result = map.get(key); + if (result != null) return result; + if (!(key instanceof ResourceLocation id) || !HEX_PLAY_PAYLOAD_IDS.contains(id)) return null; + try { + Field f = NetworkRegistry.class.getDeclaredField("PAYLOAD_REGISTRATIONS"); + f.setAccessible(true); + @SuppressWarnings("unchecked") + var regs = (Map>) f.get(null); + var playMap = regs.get(ConnectionProtocol.PLAY); + return playMap != null ? playMap.get(id) : null; + } catch (Exception e) { + return null; + } + } + + @Inject( + method = "onConfigurationFinished", + at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableSet$Builder;build()Lcom/google/common/collect/ImmutableSet;", ordinal = 1), + locals = LocalCapture.CAPTURE_FAILHARD, + remap = false + ) + private static void hexcasting$addPlayChannels( + ICommonPacketListener listener, + CallbackInfo ci, + NetworkPayloadSetup setup, + ImmutableSet.Builder notListeningAnymoreOn, + ImmutableSet.Builder nowListeningOn + ) { + nowListeningOn.addAll(HEX_PLAY_PAYLOAD_IDS); + } + + @ModifyVariable( + method = "getCodec", + ordinal = 0, + at = @At("STORE"), + remap = false + ) + private static Object hexcasting$fallbackPlayCodec( + Object registration, + ResourceLocation id, + ConnectionProtocol protocol, + PacketFlow flow + ) { + if (registration != null) return registration; + if (!MOD_ID.equals(id.getNamespace())) return null; + try { + Field f = NetworkRegistry.class.getDeclaredField("PAYLOAD_REGISTRATIONS"); + f.setAccessible(true); + @SuppressWarnings("unchecked") + Map> regs = + (Map>) f.get(null); + Map playMap = regs.get(ConnectionProtocol.PLAY); + if (playMap == null) return null; + PayloadRegistration playReg = playMap.get(id); + if (playReg == null) return null; + if (playReg.flow().isPresent() && playReg.flow().get() != flow) return null; + return playReg; + } catch (Exception e) { + return null; + } + } +} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinTagsProvider.java b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinTagsProvider.java index e815506337..d8720a71a2 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinTagsProvider.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/ForgeMixinTagsProvider.java @@ -1,8 +1,8 @@ package at.petrak.hexcasting.forge.mixin; -import at.petrak.hexcasting.forge.datagen.TagsProviderEFHSetter; +import at.petrak.hexcasting.forge.mixin.TagsProviderEFHSetter; import net.minecraft.data.tags.TagsProvider; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -25,7 +25,7 @@ public void setEFH(ExistingFileHelper efh) { @Redirect(method = "missing(Lnet/minecraft/tags/TagEntry;)Z", at = @At( value = "FIELD", - target = "Lnet/minecraft/data/tags/TagsProvider;existingFileHelper:Lnet/minecraftforge/common/data/ExistingFileHelper;", + target = "Lnet/minecraft/data/tags/TagsProvider;existingFileHelper:Lnet/neoforged/neoforge/common/data/ExistingFileHelper;", opcode = Opcodes.GETFIELD), remap = false) private ExistingFileHelper hex$missingRedirect(TagsProvider instance) { @@ -34,14 +34,7 @@ public void setEFH(ExistingFileHelper efh) { return actualFileHelper; } - @Redirect(method = "lambda$getOrCreateRawBuilder$9(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/tags/TagBuilder;", at = @At( - value = "FIELD", - target = "Lnet/minecraft/data/tags/TagsProvider;existingFileHelper:Lnet/minecraftforge/common/data/ExistingFileHelper;", - opcode = Opcodes.GETFIELD), - remap = false) - private ExistingFileHelper hex$getOrCreateRawBuilderRedirect(TagsProvider instance) { - if (actualFileHelper == null) - return existingFileHelper; - return actualFileHelper; - } + // 1.21: lambda$getOrCreateRawBuilder$9 no longer exists - method renamed to getOrCreateTagBuilder. + // Only redirect in missing() - tag()/getOrCreateTagBuilder path may need additional redirect + // if addOptionalTag validation fails. Try lambda$getOrCreateTagBuilder$0 if datagen breaks. } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/TagsProviderEFHSetter.java b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/TagsProviderEFHSetter.java new file mode 100644 index 0000000000..4df9d4f4d5 --- /dev/null +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/mixin/TagsProviderEFHSetter.java @@ -0,0 +1,11 @@ +package at.petrak.hexcasting.forge.mixin; + +import net.neoforged.neoforge.common.data.ExistingFileHelper; + +/** + * Interface for injecting ExistingFileHelper into TagsProvider subclasses that don't receive it + * via constructor (e.g. Paucal-based providers). Used by ForgeMixinTagsProvider. + */ +public interface TagsProviderEFHSetter { + void setEFH(ExistingFileHelper efh); +} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java b/Forge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java index abf74064e8..5ea823572b 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java @@ -1,80 +1,50 @@ package at.petrak.hexcasting.forge.network; import at.petrak.hexcasting.common.msgs.*; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkEvent; -import net.minecraftforge.network.NetworkRegistry; -import net.minecraftforge.network.simple.SimpleChannel; -import org.apache.logging.log4j.util.TriConsumer; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import static at.petrak.hexcasting.api.HexAPI.modLoc; +import static at.petrak.hexcasting.api.HexAPI.MOD_ID; +@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD, modid = MOD_ID) public class ForgePacketHandler { - private static final String PROTOCOL_VERSION = "1"; - private static final SimpleChannel NETWORK = NetworkRegistry.newSimpleChannel( - modLoc("main"), - () -> PROTOCOL_VERSION, - PROTOCOL_VERSION::equals, - PROTOCOL_VERSION::equals - ); - - public static SimpleChannel getNetwork() { - return NETWORK; - } - public static void init() { - int messageIdx = 0; + @SubscribeEvent + public static void registerPayloads(RegisterPayloadHandlersEvent event) { + final var registrar = event.registrar("1"); // Client -> server - NETWORK.registerMessage(messageIdx++, MsgNewSpellPatternC2S.class, MsgNewSpellPatternC2S::serialize, - MsgNewSpellPatternC2S::deserialize, makeServerBoundHandler(MsgNewSpellPatternC2S::handle)); - NETWORK.registerMessage(messageIdx++, MsgShiftScrollC2S.class, MsgShiftScrollC2S::serialize, - MsgShiftScrollC2S::deserialize, makeServerBoundHandler(MsgShiftScrollC2S::handle)); - - // Server -> client - NETWORK.registerMessage(messageIdx++, MsgNewSpellPatternS2C.class, MsgNewSpellPatternS2C::serialize, - MsgNewSpellPatternS2C::deserialize, makeClientBoundHandler(MsgNewSpellPatternS2C::handle)); - NETWORK.registerMessage(messageIdx++, MsgSentinelStatusUpdateAck.class, MsgSentinelStatusUpdateAck::serialize, - MsgSentinelStatusUpdateAck::deserialize, makeClientBoundHandler(MsgSentinelStatusUpdateAck::handle)); - NETWORK.registerMessage(messageIdx++, MsgPigmentUpdateAck.class, MsgPigmentUpdateAck::serialize, - MsgPigmentUpdateAck::deserialize, makeClientBoundHandler(MsgPigmentUpdateAck::handle)); - NETWORK.registerMessage(messageIdx++, MsgAltioraUpdateAck.class, MsgAltioraUpdateAck::serialize, - MsgAltioraUpdateAck::deserialize, makeClientBoundHandler(MsgAltioraUpdateAck::handle)); - NETWORK.registerMessage(messageIdx++, MsgCastParticleS2C.class, MsgCastParticleS2C::serialize, - MsgCastParticleS2C::deserialize, makeClientBoundHandler(MsgCastParticleS2C::handle)); - NETWORK.registerMessage(messageIdx++, MsgOpenSpellGuiS2C.class, MsgOpenSpellGuiS2C::serialize, - MsgOpenSpellGuiS2C::deserialize, makeClientBoundHandler(MsgOpenSpellGuiS2C::handle)); - NETWORK.registerMessage(messageIdx++, MsgBeepS2C.class, MsgBeepS2C::serialize, - MsgBeepS2C::deserialize, makeClientBoundHandler(MsgBeepS2C::handle)); - NETWORK.registerMessage(messageIdx++, MsgBrainsweepAck.class, MsgBrainsweepAck::serialize, - MsgBrainsweepAck::deserialize, makeClientBoundHandler(MsgBrainsweepAck::handle)); - NETWORK.registerMessage(messageIdx++, MsgNewWallScrollS2C.class, MsgNewWallScrollS2C::serialize, - MsgNewWallScrollS2C::deserialize, makeClientBoundHandler(MsgNewWallScrollS2C::handle)); - NETWORK.registerMessage(messageIdx++, MsgRecalcWallScrollDisplayS2C.class, MsgRecalcWallScrollDisplayS2C::serialize, - MsgRecalcWallScrollDisplayS2C::deserialize, makeClientBoundHandler(MsgRecalcWallScrollDisplayS2C::handle)); - NETWORK.registerMessage(messageIdx++, MsgNewSpiralPatternsS2C.class, MsgNewSpiralPatternsS2C::serialize, - MsgNewSpiralPatternsS2C::deserialize, makeClientBoundHandler(MsgNewSpiralPatternsS2C::handle)); - NETWORK.registerMessage(messageIdx++, MsgClearSpiralPatternsS2C.class, MsgClearSpiralPatternsS2C::serialize, - MsgClearSpiralPatternsS2C::deserialize, makeClientBoundHandler(MsgClearSpiralPatternsS2C::handle)); - } - - private static BiConsumer> makeServerBoundHandler( - TriConsumer handler) { - return (m, ctx) -> { - handler.accept(m, ctx.get().getSender().getServer(), ctx.get().getSender()); - ctx.get().setPacketHandled(true); - }; - } - - private static BiConsumer> makeClientBoundHandler(Consumer consumer) { - return (m, ctx) -> { - consumer.accept(m); - ctx.get().setPacketHandled(true); - }; + registrar.playToServer( + MsgNewSpellPatternC2S.TYPE, + MsgNewSpellPatternC2S.STREAM_CODEC, + (payload, context) -> payload.handle( + context.player().getServer(), + (net.minecraft.server.level.ServerPlayer) context.player() + ) + ); + registrar.playToServer( + MsgShiftScrollC2S.TYPE, + MsgShiftScrollC2S.STREAM_CODEC, + (payload, context) -> payload.handle( + context.player().getServer(), + (net.minecraft.server.level.ServerPlayer) context.player() + ) + ); + + // Server -> client: playToClient with mixin bypass for checkPacket (commonToClient registers + // for CONFIGURATION phase only, causing encoder ClassCastException during PLAY). + registrar.playToClient(MsgNewSpellPatternS2C.TYPE, MsgNewSpellPatternS2C.STREAM_CODEC, (payload, ctx) -> MsgNewSpellPatternS2C.handle(payload)); + registrar.playToClient(MsgSentinelStatusUpdateAck.TYPE, MsgSentinelStatusUpdateAck.STREAM_CODEC, (payload, ctx) -> MsgSentinelStatusUpdateAck.handle(payload)); + registrar.playToClient(MsgPigmentUpdateAck.TYPE, MsgPigmentUpdateAck.STREAM_CODEC, (payload, ctx) -> MsgPigmentUpdateAck.handle(payload)); + registrar.playToClient(MsgAltioraUpdateAck.TYPE, MsgAltioraUpdateAck.STREAM_CODEC, (payload, ctx) -> MsgAltioraUpdateAck.handle(payload)); + registrar.playToClient(MsgCastParticleS2C.TYPE, MsgCastParticleS2C.STREAM_CODEC, (payload, ctx) -> MsgCastParticleS2C.handle(payload)); + registrar.playToClient(MsgOpenSpellGuiS2C.TYPE, MsgOpenSpellGuiS2C.STREAM_CODEC, (payload, ctx) -> MsgOpenSpellGuiS2C.handle(payload)); + registrar.playToClient(MsgBeepS2C.TYPE, MsgBeepS2C.STREAM_CODEC, (payload, ctx) -> MsgBeepS2C.handle(payload)); + registrar.playToClient(MsgBrainsweepAck.TYPE, MsgBrainsweepAck.STREAM_CODEC, (payload, ctx) -> MsgBrainsweepAck.handle(payload)); + registrar.playToClient(MsgNewWallScrollS2C.TYPE, MsgNewWallScrollS2C.STREAM_CODEC, (payload, ctx) -> MsgNewWallScrollS2C.handle(payload)); + registrar.playToClient(MsgRecalcWallScrollDisplayS2C.TYPE, MsgRecalcWallScrollDisplayS2C.STREAM_CODEC, (payload, ctx) -> MsgRecalcWallScrollDisplayS2C.handle(payload)); + registrar.playToClient(MsgNewSpiralPatternsS2C.TYPE, MsgNewSpiralPatternsS2C.STREAM_CODEC, (payload, ctx) -> MsgNewSpiralPatternsS2C.handle(payload)); + registrar.playToClient(MsgClearSpiralPatternsS2C.TYPE, MsgClearSpiralPatternsS2C.STREAM_CODEC, (payload, ctx) -> MsgClearSpiralPatternsS2C.handle(payload)); } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgAltioraUpdateAck.java b/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgAltioraUpdateAck.java index 0e932b55ea..eae3a946ef 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgAltioraUpdateAck.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgAltioraUpdateAck.java @@ -3,9 +3,11 @@ import at.petrak.hexcasting.api.player.AltioraAbility; import at.petrak.hexcasting.common.msgs.IMessage; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; @@ -13,14 +15,21 @@ public record MsgAltioraUpdateAck(@Nullable AltioraAbility altiora) implements IMessage { public static final ResourceLocation ID = modLoc("altiora"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgAltioraUpdateAck::serialize, MsgAltioraUpdateAck::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgAltioraUpdateAck deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgAltioraUpdateAck deserialize(FriendlyByteBuf buf) { var extant = buf.readBoolean(); if (!extant) { diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgBrainsweepAck.java b/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgBrainsweepAck.java index c9d24606fc..39928cf6e4 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgBrainsweepAck.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgBrainsweepAck.java @@ -2,9 +2,11 @@ import at.petrak.hexcasting.common.msgs.IMessage; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; @@ -16,14 +18,21 @@ */ public record MsgBrainsweepAck(int target) implements IMessage { public static final ResourceLocation ID = modLoc("sweep"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgBrainsweepAck::serialize, MsgBrainsweepAck::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgBrainsweepAck deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgBrainsweepAck deserialize(FriendlyByteBuf buf) { var target = buf.readInt(); return new MsgBrainsweepAck(target); diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgPigmentUpdateAck.java b/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgPigmentUpdateAck.java index c38266b1ae..a7fc178c84 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgPigmentUpdateAck.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgPigmentUpdateAck.java @@ -3,9 +3,11 @@ import at.petrak.hexcasting.api.pigment.FrozenPigment; import at.petrak.hexcasting.common.msgs.IMessage; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import static at.petrak.hexcasting.api.HexAPI.modLoc; @@ -15,17 +17,23 @@ */ public record MsgPigmentUpdateAck(FrozenPigment update) implements IMessage { public static final ResourceLocation ID = modLoc("color"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgPigmentUpdateAck::serialize, MsgPigmentUpdateAck::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgPigmentUpdateAck deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); - - var tag = buf.readAnySizeNbt(); - var colorizer = FrozenPigment.fromNBT(tag); + public static MsgPigmentUpdateAck deserialize(FriendlyByteBuf buf) { + var tag = buf.readNbt(); + var colorizer = FrozenPigment.fromNBT(tag != null ? tag : new net.minecraft.nbt.CompoundTag()); return new MsgPigmentUpdateAck(colorizer); } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgSentinelStatusUpdateAck.java b/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgSentinelStatusUpdateAck.java index dc8f712d8e..9886bca904 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgSentinelStatusUpdateAck.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/network/MsgSentinelStatusUpdateAck.java @@ -3,10 +3,12 @@ import at.petrak.hexcasting.api.player.Sentinel; import at.petrak.hexcasting.common.msgs.IMessage; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.phys.Vec3; @@ -20,14 +22,21 @@ */ public record MsgSentinelStatusUpdateAck(@Nullable Sentinel update) implements IMessage { public static final ResourceLocation ID = modLoc("sntnl"); + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ID); + public static final StreamCodec STREAM_CODEC = + StreamCodec.ofMember(MsgSentinelStatusUpdateAck::serialize, MsgSentinelStatusUpdateAck::deserialize); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } @Override public ResourceLocation getFabricId() { return ID; } - public static MsgSentinelStatusUpdateAck deserialize(ByteBuf buffer) { - var buf = new FriendlyByteBuf(buffer); + public static MsgSentinelStatusUpdateAck deserialize(FriendlyByteBuf buf) { var exists = buf.readBoolean(); if (!exists) { diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/recipe/ForgeModConditionalIngredient.java b/Forge/src/main/java/at/petrak/hexcasting/forge/recipe/ForgeModConditionalIngredient.java index 0969291d47..ce7e3f37a6 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/recipe/ForgeModConditionalIngredient.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/recipe/ForgeModConditionalIngredient.java @@ -1,44 +1,49 @@ package at.petrak.hexcasting.forge.recipe; +import at.petrak.hexcasting.forge.lib.ForgeHexIngredientTypes; import at.petrak.hexcasting.xplat.IXplatAbstractions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import net.minecraft.network.FriendlyByteBuf; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Decoder; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.common.crafting.AbstractIngredient; -import net.minecraftforge.common.crafting.IIngredientSerializer; +import net.neoforged.neoforge.common.crafting.ICustomIngredient; +import net.neoforged.neoforge.common.crafting.IngredientType; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.util.Arrays; -import java.util.Objects; +import java.util.stream.Stream; import static at.petrak.hexcasting.api.HexAPI.modLoc; -public class ForgeModConditionalIngredient extends AbstractIngredient { +public class ForgeModConditionalIngredient implements ICustomIngredient { public static final ResourceLocation ID = modLoc("mod_conditional"); private final Ingredient main; private final String modid; private final Ingredient ifModLoaded; - private final Ingredient toUse; protected ForgeModConditionalIngredient(Ingredient main, String modid, Ingredient ifModLoaded) { - super(IXplatAbstractions.INSTANCE.isModPresent(modid) ? Arrays.stream(ifModLoaded.values) : Arrays.stream(main.values)); this.main = main; this.modid = modid; this.ifModLoaded = ifModLoaded; - this.toUse = IXplatAbstractions.INSTANCE.isModPresent(modid) ? ifModLoaded : main; } - /** - * Creates a new ingredient matching the given stack - */ public static ForgeModConditionalIngredient of(Ingredient main, String modid, Ingredient ifModLoaded) { return new ForgeModConditionalIngredient(main, modid, ifModLoaded); } @@ -54,61 +59,63 @@ public boolean isSimple() { } @Override - public @NotNull JsonElement toJson() { - JsonObject json = new JsonObject(); - json.addProperty("type", Objects.toString(ID)); - json.add("default", main.toJson()); - json.addProperty("modid", modid); - json.add("if_loaded", ifModLoaded.toJson()); - return json; + public @NotNull Stream getItems() { + return Arrays.stream(toUse.getItems()); } @Override - public @NotNull IIngredientSerializer getSerializer() { - return Serializer.INSTANCE; - } - - public static @NotNull Ingredient fromNetwork(FriendlyByteBuf friendlyByteBuf) { - return Ingredient.fromNetwork(friendlyByteBuf); // Just send the actual ingredient + public @NotNull IngredientType getType() { + return ForgeHexIngredientTypes.MOD_CONDITIONAL.get(); } - public static Ingredient fromJson(JsonObject object) { - if (object.has("type") && object.getAsJsonPrimitive("type").getAsString().equals(ID.toString())) { - if (object.has("modid") && IXplatAbstractions.INSTANCE.isModPresent(object.getAsJsonPrimitive("modid").getAsString())) { - try { - Ingredient ingredient = Ingredient.fromJson(object.get("if_loaded")); - if (!ingredient.isEmpty()) { - return ingredient; + private static final Codec INGREDIENT_CODEC = Codec.of( + new Encoder<>() { + @Override + public DataResult encode(Ingredient input, DynamicOps ops, T prefix) { + var custom = input.getCustomIngredient(); + JsonElement json; + if (custom != null) { + @SuppressWarnings("unchecked") + var codec = (com.mojang.serialization.Codec) custom.getType().codec().codec(); + var result = codec.encodeStart(JsonOps.INSTANCE, custom); + if (result.result().isPresent()) { + json = result.result().get(); + } else { + return DataResult.error(() -> "Failed to encode custom ingredient: " + result.error().get().message()); } - } catch (JsonParseException e) { - // NO-OP + } else { + json = serializeVanillaIngredient(input); } + return DataResult.success(new Dynamic<>(JsonOps.INSTANCE, json).convert(ops).getValue()); + } + }, + new Decoder<>() { + @Override + public DataResult> decode(DynamicOps ops, T input) { + return Ingredient.CODEC.parse(ops, input).map(ingr -> com.mojang.datafixers.util.Pair.of(ingr, input)); } - - return Ingredient.fromJson(object.get("default")); } + ); - return Ingredient.of(); - } - - public static class Serializer implements IIngredientSerializer { - public static final Serializer INSTANCE = new Serializer(); - - @Override - public @NotNull Ingredient parse(@NotNull FriendlyByteBuf buffer) { - return fromNetwork(buffer); + private static JsonElement serializeVanillaIngredient(Ingredient input) { + var items = Arrays.asList(input.getItems()); + if (items.isEmpty()) { + return new JsonObject(); } + var first = items.get(0); + JsonObject obj = new JsonObject(); + obj.addProperty("item", BuiltInRegistries.ITEM.getKey(first.getItem()).toString()); + return obj; + } - @Override - public @NotNull Ingredient parse(@NotNull JsonObject json) { - return fromJson(json); - } + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(inst -> + inst.group( + INGREDIENT_CODEC.fieldOf("default").forGetter(f -> f.main), + Codec.STRING.fieldOf("modid").forGetter(f -> f.modid), + INGREDIENT_CODEC.fieldOf("if_loaded").forGetter(f -> f.ifModLoaded) + ).apply(inst, ForgeModConditionalIngredient::new) + ); - @Override - public void write(@NotNull FriendlyByteBuf buffer, @NotNull Ingredient ingredient) { - if (ingredient instanceof ForgeModConditionalIngredient conditionalIngredient) - conditionalIngredient.toUse.toNetwork(buffer); - // It shouldn't be possible to not be a ForgeModConditionalIngredient here - } - } + public static final net.minecraft.network.codec.StreamCodec STREAM_CODEC = + ByteBufCodecs.fromCodecWithRegistries(CODEC.codec()); } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/recipe/ForgeUnsealedIngredient.java b/Forge/src/main/java/at/petrak/hexcasting/forge/recipe/ForgeUnsealedIngredient.java index 434104aa9b..a60f023607 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/recipe/ForgeUnsealedIngredient.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/recipe/ForgeUnsealedIngredient.java @@ -4,27 +4,26 @@ import at.petrak.hexcasting.api.casting.iota.NullIota; import at.petrak.hexcasting.api.item.IotaHolderItem; import at.petrak.hexcasting.api.utils.NBTHelper; +import at.petrak.hexcasting.forge.lib.ForgeHexIngredientTypes; import at.petrak.hexcasting.xplat.IXplatAbstractions; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import net.minecraft.network.FriendlyByteBuf; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.common.crafting.AbstractIngredient; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.crafting.IIngredientSerializer; -import net.minecraftforge.common.crafting.PartialNBTIngredient; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.crafting.ICustomIngredient; +import net.neoforged.neoforge.common.crafting.IngredientType; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; -import java.util.Objects; import java.util.stream.Stream; import static at.petrak.hexcasting.api.HexAPI.modLoc; -public class ForgeUnsealedIngredient extends AbstractIngredient { +public class ForgeUnsealedIngredient implements ICustomIngredient { public static final ResourceLocation ID = modLoc("unsealed"); private final ItemStack stack; @@ -36,7 +35,6 @@ private static ItemStack createStack(ItemStack base) { } protected ForgeUnsealedIngredient(ItemStack stack) { - super(Stream.of(new Ingredient.ItemValue(createStack(stack)))); this.stack = stack; } @@ -47,6 +45,10 @@ public static ForgeUnsealedIngredient of(ItemStack stack) { return new ForgeUnsealedIngredient(stack); } + public ItemStack getStack() { + return stack; + } + @Override public boolean test(@Nullable ItemStack input) { if (input == null) { @@ -58,7 +60,6 @@ public boolean test(@Nullable ItemStack input) { return holder.readIotaTag() != null && holder.writeIota(new NullIota(), true); } } - return false; } @@ -68,36 +69,24 @@ public boolean isSimple() { } @Override - public @NotNull IIngredientSerializer getSerializer() { - return ForgeUnsealedIngredient.Serializer.INSTANCE; + public @NotNull Stream getItems() { + return Stream.of(createStack(stack)); } @Override - public @NotNull JsonElement toJson() { - JsonObject json = new JsonObject(); - // TODO: should this be Partial or Strict - json.addProperty("type", Objects.toString(CraftingHelper.getID(PartialNBTIngredient.Serializer.INSTANCE))); - json.addProperty("item", Objects.toString(ForgeRegistries.ITEMS.getKey(stack.getItem()))); - return json; + public @NotNull IngredientType getType() { + return ForgeHexIngredientTypes.UNSEALED.get(); } - - public static class Serializer implements IIngredientSerializer { - public static final ForgeUnsealedIngredient.Serializer INSTANCE = new ForgeUnsealedIngredient.Serializer(); - - @Override - public @NotNull ForgeUnsealedIngredient parse(FriendlyByteBuf buffer) { - return new ForgeUnsealedIngredient(buffer.readItem()); - } - - @Override - public @NotNull ForgeUnsealedIngredient parse(@NotNull JsonObject json) { - return new ForgeUnsealedIngredient(CraftingHelper.getItemStack(json, true)); - } - - @Override - public void write(FriendlyByteBuf buffer, ForgeUnsealedIngredient ingredient) { - buffer.writeItem(ingredient.stack); - } - } + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(inst -> + inst.group( + ResourceLocation.CODEC.xmap( + rl -> new ItemStack(BuiltInRegistries.ITEM.get(rl)), + s -> BuiltInRegistries.ITEM.getKey(s.getItem()) + ).fieldOf("item").forGetter(ForgeUnsealedIngredient::getStack) + ).apply(inst, ForgeUnsealedIngredient::new) + ); + + public static final net.minecraft.network.codec.StreamCodec STREAM_CODEC = + ByteBufCodecs.fromCodecWithRegistries(CODEC.codec()); } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeClientXplatImpl.java b/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeClientXplatImpl.java index d33c2654b0..dcd272f8be 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeClientXplatImpl.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeClientXplatImpl.java @@ -3,8 +3,9 @@ import at.petrak.hexcasting.api.client.ClientCastingStack; import at.petrak.hexcasting.common.msgs.IMessage; import at.petrak.hexcasting.forge.cap.HexCapabilities; -import at.petrak.hexcasting.forge.network.ForgePacketHandler; import at.petrak.hexcasting.xplat.IClientXplatAbstractions; +import net.minecraft.client.Minecraft; +import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.client.renderer.entity.EntityRenderers; @@ -22,7 +23,10 @@ public class ForgeClientXplatImpl implements IClientXplatAbstractions { @Override public void sendPacketToServer(IMessage packet) { - ForgePacketHandler.getNetwork().sendToServer(packet); + var connection = Minecraft.getInstance().getConnection(); + if (connection != null) { + connection.send(new ServerboundCustomPayloadPacket(packet)); + } } @Override @@ -49,10 +53,10 @@ public void registerItemProperty(Item item, ResourceLocation id, ItemPropertyFun @Override public ClientCastingStack getClientCastingStack(Player player) { - var maybeCap = player.getCapability(HexCapabilities.CLIENT_CASTING_STACK).resolve(); - if (maybeCap.isEmpty()) + var cap = player.getCapability(HexCapabilities.CLIENT_CASTING_STACK); + if (cap == null) return new ClientCastingStack(); // lie - return maybeCap.get().get(); + return cap.get(); } @Override diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeOptionalMods.java b/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeOptionalMods.java new file mode 100644 index 0000000000..d74dfa3d4d --- /dev/null +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeOptionalMods.java @@ -0,0 +1,80 @@ +package at.petrak.hexcasting.forge.xplat; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.player.Player; + +import java.lang.reflect.Method; + +/** + * Reflection-based access to optional mods (Caelus, Pehkui) to avoid compile-time dependency + * when libs are not present. + */ +public final class ForgeOptionalMods { + + // Caelus: flight attribute for elytra + private static Class caelusApiClass; + private static Method caelusGetInstance; + private static Method caelusGetFlightAttribute; + + static { + try { + caelusApiClass = Class.forName("top.theillusivec4.caelus.api.CaelusApi"); + caelusGetInstance = caelusApiClass.getMethod("getInstance"); + caelusGetFlightAttribute = caelusApiClass.getMethod("getFlightAttribute"); + } catch (Exception ignored) { + } + } + + public static Attribute getCaelusFlightAttribute() { + if (caelusApiClass == null) return null; + try { + var instance = caelusGetInstance.invoke(null); + return (Attribute) caelusGetFlightAttribute.invoke(instance); + } catch (Exception e) { + return null; + } + } + + // Pehkui: scale get/set + private static Class scaleTypesClass; + private static Method getScaleData; + private static Method getScale; + private static Method setScale; + + static { + try { + scaleTypesClass = Class.forName("virtuoel.pehkui.api.ScaleTypes"); + var baseField = scaleTypesClass.getField("BASE"); + var base = baseField.get(null); + getScaleData = base.getClass().getMethod("getScaleData", Entity.class); + var scaleDataType = getScaleData.getReturnType(); + getScale = scaleDataType.getMethod("getScale"); + setScale = scaleDataType.getMethod("setScale", float.class); + } catch (Exception ignored) { + } + } + + public static float getPehkuiScale(Entity entity) { + if (scaleTypesClass == null) return 1f; + try { + var baseField = scaleTypesClass.getField("BASE"); + var base = baseField.get(null); + var scaleData = getScaleData.invoke(base, entity); + return (Float) getScale.invoke(scaleData); + } catch (Exception e) { + return 1f; + } + } + + public static void setPehkuiScale(Entity entity, float scale) { + if (scaleTypesClass == null) return; + try { + var baseField = scaleTypesClass.getField("BASE"); + var base = baseField.get(null); + var scaleData = getScaleData.invoke(base, entity); + setScale.invoke(scaleData, scale); + } catch (Exception ignored) { + } + } +} diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java b/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java index d39a71e857..cf5e5f2485 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/xplat/ForgeXplatImpl.java @@ -14,6 +14,7 @@ import at.petrak.hexcasting.api.casting.eval.vm.CastingVM; import at.petrak.hexcasting.api.casting.eval.vm.ContinuationFrame; import at.petrak.hexcasting.api.casting.iota.IotaType; +import at.petrak.hexcasting.api.mod.HexConfig; import at.petrak.hexcasting.api.mod.HexTags; import at.petrak.hexcasting.api.pigment.ColorProvider; import at.petrak.hexcasting.api.pigment.FrozenPigment; @@ -30,7 +31,6 @@ import at.petrak.hexcasting.forge.cap.HexCapabilities; import at.petrak.hexcasting.forge.interop.curios.CuriosApiInterop; import at.petrak.hexcasting.forge.mixin.ForgeAccessorBuiltInRegistries; -import at.petrak.hexcasting.forge.network.ForgePacketHandler; import at.petrak.hexcasting.forge.network.MsgBrainsweepAck; import at.petrak.hexcasting.forge.recipe.ForgeUnsealedIngredient; import at.petrak.hexcasting.interop.HexInterop; @@ -57,10 +57,13 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.Mob; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import net.minecraft.world.item.Tier; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; @@ -72,33 +75,32 @@ import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.*; -import net.minecraftforge.common.loot.CanToolPerformAction; -import net.minecraftforge.common.util.FakePlayerFactory; -import net.minecraftforge.event.level.BlockEvent; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.FluidType; -import net.minecraftforge.fluids.FluidUtil; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fml.ModContainer; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.loading.FMLLoader; -import net.minecraftforge.network.NetworkDirection; -import net.minecraftforge.network.PacketDistributor; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.common.ItemAbilities; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.common.loot.CanItemPerformAbility; +import net.neoforged.neoforge.common.util.FakePlayerFactory; +import net.neoforged.neoforge.event.level.BlockEvent; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidType; +import net.neoforged.neoforge.fluids.FluidUtil; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.ModList; +import net.neoforged.fml.loading.FMLEnvironment; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.neoforged.neoforge.network.PacketDistributor; import org.jetbrains.annotations.Nullable; -import top.theillusivec4.caelus.api.CaelusApi; -import virtuoel.pehkui.api.ScaleTypes; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.UUID; +import java.util.stream.Stream; import java.util.function.BiFunction; import java.util.function.Supplier; import static at.petrak.hexcasting.api.HexAPI.modLoc; -import static net.minecraftforge.fluids.capability.IFluidHandler.FluidAction.EXECUTE; +import static net.neoforged.neoforge.fluids.capability.IFluidHandler.FluidAction.EXECUTE; public class ForgeXplatImpl implements IXplatAbstractions { @Override @@ -108,7 +110,7 @@ public Platform platform() { @Override public boolean isPhysicalClient() { - return FMLLoader.getDist() == Dist.CLIENT; + return FMLEnvironment.dist == Dist.CLIENT; } @Override @@ -133,8 +135,7 @@ public void setBrainsweepAddlData(Mob mob) { mob.getPersistentData().putBoolean(TAG_BRAINSWEPT, true); if (mob.level() instanceof ServerLevel) { - ForgePacketHandler.getNetwork() - .send(PacketDistributor.TRACKING_ENTITY.with(() -> mob), MsgBrainsweepAck.of(mob)); + PacketDistributor.sendToPlayersTrackingEntity(mob, MsgBrainsweepAck.of(mob)); } } @@ -165,16 +166,23 @@ public void setAltiora(Player player, @Nullable AltioraAbility altiora) { tag.remove(TAG_ALTIORA_ALLOWED); } - // The elytra ability is done with an event on fabric - var elytraing = CaelusApi.getInstance().getFlightAttribute(); - var inst = player.getAttributes().getInstance(elytraing); - if (altiora != null) { - if (inst.getModifier(ALTIORA_ATTRIBUTE_ID) == null) { - inst.addTransientModifier(new AttributeModifier(ALTIORA_ATTRIBUTE_ID, "Altiora", 1.0, - AttributeModifier.Operation.ADDITION)); + // The elytra ability is done with an event on fabric (Caelus provides flight attribute) + var elytraing = ForgeOptionalMods.getCaelusFlightAttribute(); + if (elytraing != null) { + var holder = BuiltInRegistries.ATTRIBUTE.getResourceKey(elytraing) + .map(k -> BuiltInRegistries.ATTRIBUTE.getHolderOrThrow(k)) + .orElse(null); + if (holder != null) { + var inst = player.getAttributes().getInstance(holder); + if (altiora != null) { + if (inst.getModifier(ALTIORA_ATTRIBUTE_ID) == null) { + inst.addTransientModifier(new AttributeModifier(ALTIORA_ATTRIBUTE_ID, 1.0, + AttributeModifier.Operation.ADD_VALUE)); + } + } else { + inst.removeModifier(ALTIORA_ATTRIBUTE_ID); + } } - } else { - inst.removeModifier(ALTIORA_ATTRIBUTE_ID); } if (player instanceof ServerPlayer serverPlayer) { @@ -246,7 +254,7 @@ public FlightAbility getFlight(ServerPlayer player) { var origin = HexUtils.vecFromNBT(tag.getCompound(TAG_FLIGHT_ORIGIN)); var radius = tag.getDouble(TAG_FLIGHT_RADIUS); var dimension = ResourceKey.create(Registries.DIMENSION, - new ResourceLocation(tag.getString(TAG_FLIGHT_DIMENSION))); + ResourceLocation.parse(tag.getString(TAG_FLIGHT_DIMENSION))); return new FlightAbility(timeLeft, dimension, origin, radius); } return null; @@ -278,14 +286,13 @@ public Sentinel getSentinel(Player player) { var extendsRange = tag.getBoolean(TAG_SENTINEL_GREATER); var position = HexUtils.vecFromNBT(tag.getCompound(TAG_SENTINEL_POSITION)); var dimension = ResourceKey.create(Registries.DIMENSION, - new ResourceLocation(tag.getString(TAG_SENTINEL_DIMENSION))); + ResourceLocation.parse(tag.getString(TAG_SENTINEL_DIMENSION))); return new Sentinel(extendsRange, position, dimension); } @Override public CastingVM getStaffcastVM(ServerPlayer player, InteractionHand hand) { - // This is always from a staff because we don't need to load the VM when casting from item var ctx = new StaffCastEnv(player, hand); return new CastingVM(CastingImage.loadFromNbt(player.getPersistentData().getCompound(TAG_VM), player.serverLevel()), ctx); @@ -312,77 +319,71 @@ public void clearCastingData(ServerPlayer player) { @Override public @Nullable ADMediaHolder findMediaHolder(ItemStack stack) { - var maybeCap = stack.getCapability(HexCapabilities.MEDIA).resolve(); - return maybeCap.orElse(null); + return stack.getCapability(HexCapabilities.MEDIA); } @Override public @Nullable ADMediaHolder findMediaHolder(ServerPlayer player) { - var maybeCap = player.getCapability(HexCapabilities.MEDIA).resolve(); - return maybeCap.orElse(null); + // Media is only on item stacks; player aggregates from inventory via MediaHelper.scanPlayerForMediaStuff + return null; } @Override public @Nullable ADIotaHolder findDataHolder(ItemStack stack) { - var maybeCap = stack.getCapability(HexCapabilities.IOTA).resolve(); - return maybeCap.orElse(null); + return stack.getCapability(HexCapabilities.IOTA); } @Override public @Nullable ADIotaHolder findDataHolder(Entity entity) { - var maybeCap = entity.getCapability(HexCapabilities.IOTA).resolve(); - return maybeCap.orElse(null); + return entity.getCapability(HexCapabilities.IOTA_ENTITY); } @Override public @Nullable ADHexHolder findHexHolder(ItemStack stack) { - var maybeCap = stack.getCapability(HexCapabilities.STORED_HEX).resolve(); - return maybeCap.orElse(null); + return stack.getCapability(HexCapabilities.STORED_HEX); } @Override public @Nullable ADVariantItem findVariantHolder(ItemStack stack) { - var maybeCap = stack.getCapability(HexCapabilities.VARIANT_ITEM).resolve(); - return maybeCap.orElse(null); + return stack.getCapability(HexCapabilities.VARIANT_ITEM); } @Override public boolean isPigment(ItemStack stack) { - return stack.getCapability(HexCapabilities.COLOR).isPresent(); + return stack.getCapability(HexCapabilities.COLOR) != null; } @Override public ColorProvider getColorProvider(FrozenPigment pigment) { - var maybePigment = pigment.item().getCapability(HexCapabilities.COLOR).resolve(); - if (maybePigment.isPresent()) { - return maybePigment.get().provideColor(pigment.owner()); + var cap = pigment.item().getCapability(HexCapabilities.COLOR); + if (cap != null) { + return cap.provideColor(pigment.owner()); } return ColorProvider.MISSING; } @Override public void sendPacketToPlayer(ServerPlayer target, IMessage packet) { - ForgePacketHandler.getNetwork().send(PacketDistributor.PLAYER.with(() -> target), packet); + PacketDistributor.sendToPlayer(target, packet); } @Override public void sendPacketNear(Vec3 pos, double radius, ServerLevel dimension, IMessage packet) { - ForgePacketHandler.getNetwork().send(PacketDistributor.NEAR.with(() -> new PacketDistributor.TargetPoint( - pos.x, pos.y, pos.z, radius * radius, dimension.dimension() - )), packet); + PacketDistributor.sendToPlayersNear(dimension, null, pos.x, pos.y, pos.z, radius, packet); } @Override public void sendPacketTracking(Entity entity, IMessage packet) { - ForgePacketHandler.getNetwork().send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), packet); + PacketDistributor.sendToPlayersTrackingEntity(entity, packet); } @Override public Packet toVanillaClientboundPacket(IMessage message) { - //noinspection unchecked - return (Packet) ForgePacketHandler.getNetwork().toVanillaPacket(message, NetworkDirection.PLAY_TO_CLIENT); + // ClientboundCustomPayloadPacket implements Packet + // which extends ClientGamePacketListener for play phase + return (Packet) (Object) new ClientboundCustomPayloadPacket(message); } @Override @@ -393,17 +394,17 @@ public BlockEntityType createBlockEntityType(BiFuncti @Override public boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, Fluid fluid) { - Optional handler = FluidUtil.getFluidHandler(level, pos, Direction.UP).resolve(); - return handler.isPresent() && - handler.get().fill(new FluidStack(fluid, FluidType.BUCKET_VOLUME), EXECUTE) > 0; + var handler = FluidUtil.getFluidHandler(level, pos, Direction.UP).orElse(null); + return handler != null && + handler.fill(new FluidStack(fluid, FluidType.BUCKET_VOLUME), EXECUTE) > 0; } @Override public boolean drainAllFluid(Level level, BlockPos pos) { - Optional handler = FluidUtil.getFluidHandler(level, pos, Direction.UP).resolve(); - if (handler.isPresent()) { + var handler = FluidUtil.getFluidHandler(level, pos, Direction.UP).orElse(null); + if (handler != null) { boolean any = false; - IFluidHandler pool = handler.get(); + IFluidHandler pool = handler; for (int i = 0; i < pool.getTanks(); i++) { if (!pool.drain(pool.getFluidInTank(i), EXECUTE).isEmpty()) { any = true; @@ -416,12 +417,31 @@ public boolean drainAllFluid(Level level, BlockPos pos) { @Override public Ingredient getUnsealedIngredient(ItemStack stack) { - return ForgeUnsealedIngredient.of(stack); + return ForgeUnsealedIngredient.of(stack).toVanilla(); + } + + private static List harvestStacks(Item... items) { + return Stream.of(items).map(ItemStack::new).toList(); } + private static final List> HARVEST_TOOLS_BY_LEVEL = List.of( + harvestStacks(Items.WOODEN_PICKAXE, Items.WOODEN_AXE, Items.WOODEN_HOE, Items.WOODEN_SHOVEL), + harvestStacks(Items.STONE_PICKAXE, Items.STONE_AXE, Items.STONE_HOE, Items.STONE_SHOVEL), + harvestStacks(Items.IRON_PICKAXE, Items.IRON_AXE, Items.IRON_HOE, Items.IRON_SHOVEL), + harvestStacks(Items.DIAMOND_PICKAXE, Items.DIAMOND_AXE, Items.DIAMOND_HOE, Items.DIAMOND_SHOVEL), + harvestStacks(Items.NETHERITE_PICKAXE, Items.NETHERITE_AXE, Items.NETHERITE_HOE, Items.NETHERITE_SHOVEL) + ); + @Override public boolean isCorrectTierForDrops(Tier tier, BlockState bs) { - return !bs.requiresCorrectToolForDrops() || TierSortingRegistry.isCorrectTierForDrops(tier, bs); + if (!bs.requiresCorrectToolForDrops()) return true; + // TierSortingRegistry removed in NeoForge 21.1; use tool check like Fabric + int level = HexConfig.server().opBreakHarvestLevelBecauseForgeThoughtItWasAGoodIdeaToImplementHarvestTiersUsingAnHonestToGodTopoSort(); + int idx = Math.min(Math.max(level, 0), HARVEST_TOOLS_BY_LEVEL.size() - 1); + for (var tool : HARVEST_TOOLS_BY_LEVEL.get(idx)) { + if (tool.isCorrectToolForDrops(bs)) return true; + } + return false; } @Override @@ -432,12 +452,12 @@ public Item.Properties addEquipSlotFabric(EquipmentSlot slot) { private static final IXplatTags TAGS = new IXplatTags() { @Override public TagKey amethystDust() { - return HexTags.Items.create(new ResourceLocation("forge", "dusts/amethyst")); + return HexTags.Items.create(ResourceLocation.fromNamespaceAndPath("forge", "dusts/amethyst")); } @Override public TagKey gems() { - return HexTags.Items.create(new ResourceLocation("forge", "gems")); + return HexTags.Items.create(ResourceLocation.fromNamespaceAndPath("forge", "gems")); } }; @@ -448,7 +468,7 @@ public IXplatTags tags() { @Override public LootItemCondition.Builder isShearsCondition() { - return CanToolPerformAction.canToolPerformAction(ToolActions.SHEARS_DIG); + return CanItemPerformAbility.canItemPerformAbility(ItemAbilities.SHEARS_DIG); } @Override @@ -526,7 +546,9 @@ public Registry getEvalSoundRegistry() { public boolean isBreakingAllowed(ServerLevel world, BlockPos pos, BlockState state, @Nullable Player player) { if (player == null) player = FakePlayerFactory.get(world, HEXCASTING); - return !MinecraftForge.EVENT_BUS.post(new BlockEvent.BreakEvent(world, pos, state, player)); + var evt = new BlockEvent.BreakEvent(world, pos, state, player); + NeoForge.EVENT_BUS.post(evt); + return !evt.isCanceled(); } @Override @@ -535,8 +557,10 @@ public boolean isPlacingAllowed(ServerLevel world, BlockPos pos, ItemStack block player = FakePlayerFactory.get(world, HEXCASTING); ItemStack cached = player.getMainHandItem(); player.setItemInHand(InteractionHand.MAIN_HAND, blockStack.copy()); - var evt = ForgeHooks.onRightClickBlock(player, InteractionHand.MAIN_HAND, pos, - new BlockHitResult(Vec3.atCenterOf(pos), Direction.DOWN, pos, true)); + var hitVec = new BlockHitResult(Vec3.atCenterOf(pos), Direction.DOWN, pos, true); + var evt = new net.neoforged.neoforge.event.entity.player.PlayerInteractEvent.RightClickBlock( + player, InteractionHand.MAIN_HAND, pos, hitVec); + NeoForge.EVENT_BUS.post(evt); player.setItemInHand(InteractionHand.MAIN_HAND, cached); return !evt.isCanceled(); } @@ -554,12 +578,12 @@ public PehkuiInterop.ApiAbstraction getPehkuiApi() { PEHKUI_API = new PehkuiInterop.ApiAbstraction() { @Override public float getScale(Entity e) { - return ScaleTypes.BASE.getScaleData(e).getScale(); + return ForgeOptionalMods.getPehkuiScale(e); } @Override public void setScale(Entity e, float scale) { - ScaleTypes.BASE.getScaleData(e).setScale(scale); + ForgeOptionalMods.setPehkuiScale(e, scale); } }; } @@ -583,7 +607,8 @@ public void setScale(Entity e, float scale) { public static final String TAG_ALTIORA_ALLOWED = "hexcasting:altiora_allowed"; public static final String TAG_ALTIORA_GRACE = "hexcasting:altiora_grace_period"; - public static final UUID ALTIORA_ATTRIBUTE_ID = UUID.fromString("91897c79-3ebb-468c-a265-40418ed01c41"); + public static final net.minecraft.resources.ResourceLocation ALTIORA_ATTRIBUTE_ID = + modLoc("altiora"); public static final String TAG_VM = "hexcasting:spell_harness"; public static final String TAG_PATTERNS = "hexcasting:spell_patterns"; diff --git a/Forge/src/main/resources/META-INF/neoforge.mods.toml b/Forge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000000..511439bf2e --- /dev/null +++ b/Forge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,63 @@ +modLoader = "kotlinforforge" +loaderVersion = "[5,)" +license = "MIT" + +issueTrackerURL = "https://github.com/gamma-delta/HexMod/issues" + +[[mods]] +modId = "hexcasting" +version = "${file.jarVersion}" +displayName = "Hex Casting" +displayURL = "https://github.com/gamma-delta/HexMod" +logoFile = "logo.png" +credits = "Falkory for textures; Wiresegal for lots of polish; Alwinfy for visual effects, proofreading, and code help; Kra3tor for sound effects; naj77 for the nice logo; and all of my wonderful patrons for supporting me!" +authors = "petrak@ (aka gamma-delta)" +description = "Cast powerful Hexes on the fly by drawing patterns with a staff." + +[[dependencies.hexcasting]] +modId = "neoforge" +mandatory = true +versionRange = "[21,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.hexcasting]] +modId = "minecraft" +mandatory = true +versionRange = "[1.21.1,1.22)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.hexcasting]] +modId = "paucal" +mandatory = true +versionRange = "[0.7.0,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.hexcasting]] +modId = "patchouli" +mandatory = true +versionRange = "[1.21.1-92,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.hexcasting]] +modId = "caelus" +mandatory = true +versionRange = "[7.0.1,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.hexcasting]] +modId = "curios" +type = "optional" +versionRange = "[9.4.0,)" +ordering = "NONE" +side = "BOTH" + +[[mixins]] +config = "hexcasting_forge.mixins.json" + +[[mixins]] +config = "hexplat.mixins.json" diff --git a/Forge/src/main/resources/hexcasting_forge.mixins.json b/Forge/src/main/resources/hexcasting_forge.mixins.json index 3a50c75493..57daae6590 100644 --- a/Forge/src/main/resources/hexcasting_forge.mixins.json +++ b/Forge/src/main/resources/hexcasting_forge.mixins.json @@ -7,10 +7,9 @@ "mixins": [ "ForgeAccessorBuiltInRegistries", "ForgeMixinCursedRecipeSerializerBase", + "ForgeMixinCustomPacketPayload", + "ForgeMixinNetworkRegistry", "ForgeMixinTagsProvider" ], - "client": [ - "ForgeMixinBlockColors", - "ForgeMixinItemColors" - ] + "client": [] } diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index a2da4ee85f..0000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env groovy - -pipeline { - agent any - tools { - jdk "jdk-17.0.1" - } - environment { - discordWebhook = credentials('discordWebhook') - CURSEFORGE_TOKEN = credentials('curseforgeApiKey') - MODRINTH_TOKEN = credentials('modrinthApiKey') - } - stages { - stage('Clean') { - steps { - echo 'Cleaning Project' - sh 'chmod +x gradlew' - sh './gradlew clean' - } - } - stage('Build') { - steps { - echo 'Building' - sh './gradlew build' - } - } - stage('Run Datagen') { - steps { - echo 'Running datagen tasks' - sh './gradlew runAllDatagen' - } - } - stage('Check Datagen') { - steps { - echo 'Checking for modified files' - // also fail if there are new untracked files - sh 'git add --intent-to-add .' - // cache isn't reproducible, so ignore modifications to it - // https://stackoverflow.com/a/71878316 - sh 'git diff --name-only --exit-code -- ":!:*/src/generated/resources/.cache/*"' - } - } - stage('Publish') { - when { - allOf { - branch 'main' - not { changeRequest() } - } - } - stages { - stage('Deploy Previews') { - steps { - echo 'Deploying previews to various places' - sh './gradlew publish publishToDiscord' - } - } - stage('Deploy releases') { - steps { - echo 'Maybe deploy releases' - sh './gradlew publishCurseforge publishModrinth' - } - } - } - } - } - post { - always { - archiveArtifacts 'Common/build/libs/**.jar' - archiveArtifacts 'Forge/build/libs/**.jar' - archiveArtifacts 'Fabric/build/libs/**.jar' - } - } -} \ No newline at end of file diff --git a/Paucal b/Paucal new file mode 160000 index 0000000000..9d8060ab09 --- /dev/null +++ b/Paucal @@ -0,0 +1 @@ +Subproject commit 9d8060ab09dfe91dfde063968474824ac63c114b diff --git a/build.gradle b/build.gradle index 957b112bed..57b2f03a68 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,7 @@ pkpcpbp { doProjectMetadata = false setupJarMetadata = true setupMavenMetadata = true - javaVersion = 17 + javaVersion = 21 modInfo { modID = project.modID mcVersion = project.minecraftVersion @@ -83,30 +83,28 @@ subprojects { tasks.withType(JavaCompile).configureEach { it.options.encoding = 'UTF-8' - it.options.release = 17 + it.options.release = 21 } compileKotlin { kotlinOptions { - jvmTarget = "17" + jvmTarget = "21" } } compileTestKotlin { kotlinOptions { - jvmTarget = "17" + jvmTarget = "21" } } - // Disables Gradle's custom module metadata from being published to maven. The - // metadata includes mapped dependencies which are not reasonably consumable by - // other mod developers. + // Disable custom module metadata (mapped deps not consumable by others) tasks.withType(GenerateModuleMetadata) { enabled = false } sourceSets.main.kotlin.srcDirs += 'src/main/java' - java.toolchain.languageVersion = JavaLanguageVersion.of(17) + java.toolchain.languageVersion = JavaLanguageVersion.of(21) java.withSourcesJar() java.withJavadocJar() @@ -132,5 +130,5 @@ allprojects { tasks.register("runAllDatagen") { dependsOn ":Forge:runXplatDatagen" dependsOn ":Forge:runForgeDatagen" - dependsOn ":Fabric:runDatagen" + // dependsOn ":Fabric:runDatagen" // Re-enable when Fabric is included } diff --git a/compile-mixins.txt b/compile-mixins.txt new file mode 100644 index 0000000000..d57d8fed6d --- /dev/null +++ b/compile-mixins.txt @@ -0,0 +1,306 @@ +To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.8/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation. +Daemon will be stopped at the end of the build + +> Configure project :Paucal +Architect Plugin: 3.4.162 +Architectury Loom: 1.7.435 +You are using an outdated version of Architectury Loom! This version will not receive any support, please consider updating! + +> Configure project :Common +SpongePowered Vanilla 'GRADLE' Toolset Version '0.2.1-SNAPSHOT' +Targeting Minecraft '1.21.1' on a 'JOINED' platform + +> Task :Common:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :Common:compileKotlin UP-TO-DATE +> Task :Common:compileJava UP-TO-DATE +> Task :Common:processResources UP-TO-DATE +> Task :Common:classes +> Task :Common:jar +> Task :Forge:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :Forge:createMinecraftArtifacts UP-TO-DATE +> Task :Forge:compileKotlin + +> Task :Forge:compileJava +.\gradlew : Note: SpongePowered MIXIN Annotation Processor Version=0.8.5 +At C:\Users\KMService\AppData\Local\Temp\ps-script-a610a53e-070e-45c8-b000-e99144863737.ps1:105 char:69 ++ ... ing 1.21.1 neoforge draft"; .\gradlew :Forge:compileJava 2>&1 | Out-F ... ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + CategoryInfo : NotSpecified: (Note: SpongePow...r Version=0.8.5:String) [], RemoteException + + FullyQualifiedErrorId : NativeCommandError + +Note: Supported obfuscation types: ObfuscationServiceMCP supports [searge,notch] +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\mixin\ForgeMixinBlockColors.java:12: warning: Unable to determine +descriptor for @Inject target method + @Inject(method = "create", at = @At("RETURN")) + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\mixin\ForgeMixinItemColors.java:13: warning: Unable to determine +descriptor for @Inject target method + @Inject(method = "create", at = @At("RETURN")) + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\ForgeHexInitializer.java:24: error: package +at.petrak.hexcasting.forge.datagen does not exist +import at.petrak.hexcasting.forge.datagen.ForgeHexDataGenerators; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\ForgeHexInitializer.java:55: error: cannot find symbol +import net.neoforged.fml.DistExecutor; + ^ + symbol: class DistExecutor + location: package net.neoforged.fml +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\ForgeHexInitializer.java:58: error: cannot find symbol +import net.neoforged.neoforge.common.ToolActions; + ^ + symbol: class ToolActions + location: package net.neoforged.neoforge.common +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\ForgeHexInitializer.java:63: error: cannot find symbol +import net.neoforged.neoforge.event.TickEvent; + ^ + symbol: class TickEvent + location: package net.neoforged.neoforge.event +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\ForgeHexInitializer.java:71: error: package +net.neoforged.neoforge.eventbus.api does not exist +import net.neoforged.neoforge.eventbus.api.IEventBus; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\ForgeHexInitializer.java:79: error: cannot find symbol + private static IEventBus MOD_BUS; + ^ + symbol: class IEventBus + location: class ForgeHexInitializer +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\ForgeHexInitializer.java:81: error: cannot find symbol + public ForgeHexInitializer(IEventBus modBus) { + ^ + symbol: class IEventBus + location: class ForgeHexInitializer +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\ForgeHexInitializer.java:165: error: cannot find symbol + private static void initListeners(IEventBus modBus) { + ^ + symbol: class IEventBus + location: class ForgeHexInitializer +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\recipe\ForgeModConditionalIngredient.java:11: error: cannot find +symbol +import net.neoforged.neoforge.common.crafting.AbstractIngredient; + ^ + symbol: class AbstractIngredient + location: package net.neoforged.neoforge.common.crafting +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\recipe\ForgeModConditionalIngredient.java:12: error: cannot find +symbol +import net.neoforged.neoforge.common.crafting.IIngredientSerializer; + ^ + symbol: class IIngredientSerializer + location: package net.neoforged.neoforge.common.crafting +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\recipe\ForgeModConditionalIngredient.java:21: error: cannot find +symbol +public class ForgeModConditionalIngredient extends AbstractIngredient { + ^ + symbol: class AbstractIngredient +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\recipe\ForgeModConditionalIngredient.java:67: error: cannot find +symbol + public @NotNull IIngredientSerializer getSerializer() { + ^ + symbol: class IIngredientSerializer + location: class ForgeModConditionalIngredient +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\mixin\ForgeMixinTagsProvider.java:3: error: package +at.petrak.hexcasting.forge.datagen does not exist +import at.petrak.hexcasting.forge.datagen.TagsProviderEFHSetter; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\mixin\ForgeMixinTagsProvider.java:14: error: cannot find symbol +public abstract class ForgeMixinTagsProvider implements TagsProviderEFHSetter { + ^ + symbol: class TagsProviderEFHSetter +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\recipe\ForgeModConditionalIngredient.java:94: error: cannot find +symbol + public static class Serializer implements IIngredientSerializer { + ^ + symbol: class IIngredientSerializer + location: class ForgeModConditionalIngredient +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\xplat\ForgeXplatImpl.java:76: error: cannot find symbol +import net.neoforged.neoforge.common.ToolActions; + ^ + symbol: class ToolActions + location: package net.neoforged.neoforge.common +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\xplat\ForgeXplatImpl.java:77: error: cannot find symbol +import net.neoforged.neoforge.common.TierSortingRegistry; + ^ + symbol: class TierSortingRegistry + location: package net.neoforged.neoforge.common +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Forge\src\main\java\at\petrak\hexcasting\forge\xplat\ForgeXplatImpl.java:78: error: cannot find symbol +import net.neoforged.neoforge.common.loot.CanToolPerformAction; + ^ + symbol: class CanToolPerformAction + location: package net.neoforged.neoforge.common.loot +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\api\casting\iota\EntityIota.java:5: error: package +com.samsthenerd.inline.api does not exist +import com.samsthenerd.inline.api.InlineAPI; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\api\casting\iota\EntityIota.java:6: error: package +com.samsthenerd.inline.api.data does not exist +import com.samsthenerd.inline.api.data.EntityInlineData; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\api\casting\iota\EntityIota.java:7: error: package +com.samsthenerd.inline.api.data does not exist +import com.samsthenerd.inline.api.data.PlayerHeadData; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:6: error: package +com.samsthenerd.inline.api does not exist +import com.samsthenerd.inline.api.InlineAPI; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:7: error: package +com.samsthenerd.inline.api.matching does not exist +import com.samsthenerd.inline.api.matching.InlineMatch; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:8: error: package +com.samsthenerd.inline.api.matching does not exist +import com.samsthenerd.inline.api.matching.MatchContext; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:9: error: package +com.samsthenerd.inline.api.matching does not exist +import com.samsthenerd.inline.api.matching.MatcherInfo; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:10: error: package +com.samsthenerd.inline.api.matching does not exist +import com.samsthenerd.inline.api.matching.RegexMatcher; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:23: error: cannot find symbol +public class HexPatternMatcher implements RegexMatcher { + ^ + symbol: class RegexMatcher +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:26: error: cannot find symbol + private static final MatcherInfo patternMatcherInfo = MatcherInfo.fromId(patternMatcherID); + ^ + symbol: class MatcherInfo + location: class HexPatternMatcher +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:39: error: cannot find symbol + public Tuple getMatchAndGroup(MatchResult regexMatch, MatchContext ctx) { + ^ + symbol: class MatchContext + location: class HexPatternMatcher +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:39: error: cannot find symbol + public Tuple getMatchAndGroup(MatchResult regexMatch, MatchContext ctx) { + ^ + symbol: class InlineMatch + location: class HexPatternMatcher +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:72: error: cannot find symbol + public InlineMatch getMatch(MatchResult mr, MatchContext ctx){ + ^ + symbol: class MatchContext + location: class HexPatternMatcher +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:72: error: cannot find symbol + public InlineMatch getMatch(MatchResult mr, MatchContext ctx){ + ^ + symbol: class InlineMatch + location: class HexPatternMatcher +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\HexPatternMatcher.java:76: error: cannot find symbol + public MatcherInfo getInfo(){ + ^ + symbol: class MatcherInfo + location: class HexPatternMatcher +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlineHex.java:3: error: package +com.samsthenerd.inline.api does not exist +import com.samsthenerd.inline.api.InlineAPI; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlineHexClient.java:3: error: package +com.samsthenerd.inline.api.client does not exist +import com.samsthenerd.inline.api.client.InlineClientAPI; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternData.java:10: error: package +com.samsthenerd.inline.api does not exist +import com.samsthenerd.inline.api.InlineData; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternData.java:21: error: cannot find symbol +public class InlinePatternData implements InlineData{ + ^ + symbol: class InlineData +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternData.java:73: error: cannot find symbol + public static class InlinePatternDataType implements InlineDataType { + ^ + symbol: class InlineDataType + location: class InlinePatternData +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternRenderer.java:4: error: package +com.samsthenerd.inline.api.client does not exist +import com.samsthenerd.inline.api.client.GlowHandling; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternRenderer.java:5: error: package +com.samsthenerd.inline.api.client does not exist +import com.samsthenerd.inline.api.client.InlineRenderer; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternRenderer.java:6: error: package +com.samsthenerd.inline.impl does not exist +import com.samsthenerd.inline.impl.InlineStyle; + ^ +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternRenderer.java:11: error: cannot find symbol +public class InlinePatternRenderer implements InlineRenderer { + ^ + symbol: class InlineRenderer +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternRenderer.java:51: error: cannot find symbol + public GlowHandling getGlowPreference(InlinePatternData forData) { + ^ + symbol: class GlowHandling + location: class InlinePatternRenderer +C:\Users\KMService\Documents\hexcasting 1.21.1 neoforge +draft\Common\src\main\java\at\petrak\hexcasting\interop\inline\InlinePatternRenderer.java:57: error: cannot find symbol + public int render(InlinePatternData data, GuiGraphics drawContext, int index, Style style, int codepoint, +TextRenderingContext trContext){ + ^ + symbol: class TextRenderingContext + location: class InlinePatternRenderer +44 errors +2 warnings + +> Task :Forge:compileJava FAILED + +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':Forge:compileJava'. +> Compilation failed; see the compiler error output for details. + +* Try: +> Run with --info option to get more log output. +> Run with --scan to get full insights. + +BUILD FAILED in 17s +8 actionable tasks: 4 executed, 4 up-to-date diff --git a/compile-output.txt b/compile-output.txt new file mode 100644 index 0000000000..7445fb0f1f Binary files /dev/null and b/compile-output.txt differ diff --git a/gradle.properties b/gradle.properties index c6d41379ef..592aed1f36 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,16 +8,19 @@ modName=Hex Casting jetbrainsAnnotationsVersion=23.0.0 -minecraftVersion=1.20.1 -kotlinVersion=1.7.20 -modVersion=0.11.3 +minecraftVersion=1.21.1 +kotlinVersion=2.0.21 +modVersion=0.12.0 + +# NeoForge 1.21.1 (strict) +neoforgeVersion=21.1.219 # this is the version published to modrinth/cf i swear -paucalVersion=0.6.0-pre-118 -patchouliVersion=83 +paucalVersion=0.7.1 +patchouliVersion=1.21.1-92 -jeiVersion=15.0.0.12 +jeiVersion=19.27.0.340 pehkuiVersion=3.7.7 -inlineVersion=1.0.1 +inlineVersion=1.2.2 clothConfigVersion=11.1.106 \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 67a39ad9c4..9fe465d06f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,7 @@ pluginManagement { url = 'https://repo.spongepowered.org/repository/maven-public/' } maven { url 'https://maven.blamejared.com' } + maven { url = 'https://maven.neoforged.net/releases' } } plugins { @@ -18,4 +19,8 @@ pluginManagement { } rootProject.name = 'Hex Casting' -include("Common", "Fabric", "Forge") +include("Common", "Forge") +// include("Fabric") // Excluded during NeoForge port; re-enable for Fabric 1.21.1 port + +// Use local Paucal build to avoid mapped-jar mismatch +includeBuild('Paucal')