From c183c7ac48e3d3d30e03a9d8de50b5f8ca96d68c Mon Sep 17 00:00:00 2001 From: Westernat Date: Wed, 14 Feb 2024 20:15:18 +0800 Subject: [PATCH] 2.8.0 --- gradle.properties | 2 +- .../java/org/mesdag/advjs/AdvJSPlugin.java | 3 +- .../advancement/AdvConfigureEventJS.java | 8 +-- .../advjs/advancement/AdvLockEventJS.java | 43 ++++++++----- .../advjs/advancement/CriteriaBuilder.java | 4 +- .../org/mesdag/advjs/command/AdvCommand.java | 4 +- ...AbstractBlock$AbstractBlockStateMixin.java | 29 +++++++++ .../mesdag/advjs/mixin/ItemStackMixin.java | 47 +++++++++++++++ .../mixin/PlayerAdvancementTrackerMixin.java | 13 ++-- .../mesdag/advjs/mixin/PlayerEntityMixin.java | 14 +++++ .../advjs/mixin/ScreenHandlerMixin.java | 25 +++++--- .../mixin/ServerAdvancementLoaderMixin.java | 13 ++-- .../client/ClientAdvancementsAccessor.java | 15 +++++ .../org/mesdag/advjs/trigger/Trigger.java | 23 +++---- .../trigger/registry/CustomTriggers.java | 9 +-- .../java/org/mesdag/advjs/util/AdvHelper.java | 45 ++++++++++++-- .../mesdag/advjs/util/AdvancementFilter.java | 60 +++++++++---------- .../java/org/mesdag/advjs/util/Bounds.java | 2 +- src/main/java/org/mesdag/advjs/util/Data.java | 9 +++ src/main/resources/advjs.mixins.json | 3 + 20 files changed, 274 insertions(+), 97 deletions(-) create mode 100644 src/main/java/org/mesdag/advjs/mixin/AbstractBlock$AbstractBlockStateMixin.java create mode 100644 src/main/java/org/mesdag/advjs/mixin/ItemStackMixin.java create mode 100644 src/main/java/org/mesdag/advjs/mixin/client/ClientAdvancementsAccessor.java diff --git a/gradle.properties b/gradle.properties index 08c479c..bcbf307 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ yarn_mappings=1.20.1+build.10 loader_version=0.15.3 # Mod Properties -mod_version=2001fabric-2.7.0 +mod_version=2001fabric-2.8.0 maven_group=org.mesdag.advjs archives_base_name=AdvJS diff --git a/src/main/java/org/mesdag/advjs/AdvJSPlugin.java b/src/main/java/org/mesdag/advjs/AdvJSPlugin.java index d26c53e..4c85ede 100644 --- a/src/main/java/org/mesdag/advjs/AdvJSPlugin.java +++ b/src/main/java/org/mesdag/advjs/AdvJSPlugin.java @@ -15,7 +15,7 @@ import java.nio.file.Files; public class AdvJSPlugin extends KubeJSPlugin { - static boolean DEBUG; + static boolean DEBUG = false; @Override public void registerBindings(BindingsEvent event) { @@ -24,6 +24,7 @@ public void registerBindings(BindingsEvent event) { event.add("GameMode", GameTypeWrapper.class); event.add("Bounds", Bounds.class); event.add("CustomTriggers", CustomTriggers.class); + event.add("AdvHelper", AdvHelper.class); } @Override diff --git a/src/main/java/org/mesdag/advjs/advancement/AdvConfigureEventJS.java b/src/main/java/org/mesdag/advjs/advancement/AdvConfigureEventJS.java index e554c30..7cf8749 100644 --- a/src/main/java/org/mesdag/advjs/advancement/AdvConfigureEventJS.java +++ b/src/main/java/org/mesdag/advjs/advancement/AdvConfigureEventJS.java @@ -43,10 +43,10 @@ public AdvBuilder create(Identifier rootPath) { Else if you put in a json object, it will remove advancement by filter: - modid: the mod id of advancement. - icon: the id of icon item/block. - frame: type of frame for the icon. Available value is 'challenge', 'goal' or 'task'. - parent: the parent advancement path of this advancement. + @param mod: the mod id of advancement. + @param icon: the icon of advancement widget. + @param frame: type of frame for the icon. Available value is 'challenge', 'goal' or 'task'. + @param parent: the parent advancement id of this advancement. """) public void remove(AdvancementFilter filter) { if (filter.fail()) { diff --git a/src/main/java/org/mesdag/advjs/advancement/AdvLockEventJS.java b/src/main/java/org/mesdag/advjs/advancement/AdvLockEventJS.java index 6f9d374..60d2ea0 100644 --- a/src/main/java/org/mesdag/advjs/advancement/AdvLockEventJS.java +++ b/src/main/java/org/mesdag/advjs/advancement/AdvLockEventJS.java @@ -2,30 +2,43 @@ import dev.latvian.mods.kubejs.event.EventJS; import dev.latvian.mods.kubejs.typings.Info; -import dev.latvian.mods.kubejs.typings.Param; -import net.minecraft.predicate.item.ItemPredicate; +import net.minecraft.block.Block; +import net.minecraft.entity.EntityType; +import net.minecraft.item.Item; import net.minecraft.recipe.Ingredient; import net.minecraft.util.Identifier; +import org.mesdag.advjs.predicate.ItemPredicateBuilder; import org.mesdag.advjs.util.ItemSetter; -import static org.mesdag.advjs.util.Data.LOCK_RESULT; +import java.util.function.Consumer; + +import static org.mesdag.advjs.util.Data.*; public class AdvLockEventJS extends EventJS implements ItemSetter { - @Info(value = "Lock recipe by advancement. It will only deny player take the result from GUI.", - params = { - @Param(name = "toLock"), - @Param(name = "lockBy") - }) + @Info("Deny player take specific result. It only available in GUI.") public void result(Ingredient toLock, Identifier lockBy) { LOCK_RESULT.put(wrapItem(toLock), lockBy); } - @Info(value = "Lock recipe by advancement. It will only deny player take the result from GUI.", - params = { - @Param(name = "toLock"), - @Param(name = "lockBy") - }) - public void result(ItemPredicate toLock, Identifier lockBy) { - LOCK_RESULT.put(toLock, lockBy); + @Info("Deny player take specific result. It only available in GUI.") + public void result(Consumer consumer, Identifier lockBy) { + ItemPredicateBuilder builder = new ItemPredicateBuilder(); + consumer.accept(builder); + LOCK_RESULT.put(builder.build(), lockBy); + } + + @Info("Pass item use or use on block.") + public void itemUse(Item toLock, Identifier lockBy) { + LOCK_ITEM_USE.put(toLock, lockBy); + } + + @Info("Deny player interact with specific block.") + public void blockInteract(Block toLock, Identifier lockBy) { + LOCK_BLOCK_INTERACT.put(toLock, lockBy); + } + + @Info("pass player interact with specific type of entities.") + public void entityInteract(EntityType toLock, Identifier lockBy) { + LOCK_ENTITY_INTERACT.put(toLock, lockBy); } } diff --git a/src/main/java/org/mesdag/advjs/advancement/CriteriaBuilder.java b/src/main/java/org/mesdag/advjs/advancement/CriteriaBuilder.java index caff167..5c12b0b 100644 --- a/src/main/java/org/mesdag/advjs/advancement/CriteriaBuilder.java +++ b/src/main/java/org/mesdag/advjs/advancement/CriteriaBuilder.java @@ -34,12 +34,12 @@ public CriteriaBuilder(Map criteria) { @Param(name = "name", value = "The name of this trigger."), @Param(name = "trigger", value = "The trigger itself.") }) - public void add(String name, Trigger instance) { + public void add(String name, CriterionConditions instance) { criteria.put(name, new AdvancementCriterion(instance)); } @Info("Add a nameless trigger for this advancement.") - public void add(Trigger instance) { + public void add(CriterionConditions instance) { criteria.put(UUID.randomUUID().toString(), new AdvancementCriterion(instance)); } diff --git a/src/main/java/org/mesdag/advjs/command/AdvCommand.java b/src/main/java/org/mesdag/advjs/command/AdvCommand.java index 5e893d7..c32fbe8 100644 --- a/src/main/java/org/mesdag/advjs/command/AdvCommand.java +++ b/src/main/java/org/mesdag/advjs/command/AdvCommand.java @@ -2186,8 +2186,10 @@ function lookAtThroughSpyglass(entityType) { }) AdvJSEvents.lock(event => { - // Lock recipe by advancement event.result("stone_slab", "minecraft:story/smelt_iron"); + event.itemUse("spyglass", "minecraft:story/smelt_iron"); + event.blockInteract("chest", "minecraft:story/smelt_iron"); + event.entityInteract("villager", "minecraft:story/smelt_iron"); }) PlayerEvents.advancement(event => { diff --git a/src/main/java/org/mesdag/advjs/mixin/AbstractBlock$AbstractBlockStateMixin.java b/src/main/java/org/mesdag/advjs/mixin/AbstractBlock$AbstractBlockStateMixin.java new file mode 100644 index 0000000..606073d --- /dev/null +++ b/src/main/java/org/mesdag/advjs/mixin/AbstractBlock$AbstractBlockStateMixin.java @@ -0,0 +1,29 @@ +package org.mesdag.advjs.mixin; + +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.world.World; +import org.mesdag.advjs.util.AdvHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import static org.mesdag.advjs.util.Data.LOCK_BLOCK_INTERACT; + +@Mixin(AbstractBlock.AbstractBlockState.class) +public abstract class AbstractBlock$AbstractBlockStateMixin { + @Shadow public abstract Block getBlock(); + + @Inject(method = "onUse", at = @At("HEAD"), cancellable = true) + private void advJS$pass(World world, PlayerEntity player, Hand hand, BlockHitResult hit, CallbackInfoReturnable cir) { + if (world.isClient) return; + if (!AdvHelper.advDone((ServerPlayerEntity) player, LOCK_BLOCK_INTERACT.get(getBlock()))) cir.setReturnValue(ActionResult.PASS); + } +} diff --git a/src/main/java/org/mesdag/advjs/mixin/ItemStackMixin.java b/src/main/java/org/mesdag/advjs/mixin/ItemStackMixin.java new file mode 100644 index 0000000..5e558e5 --- /dev/null +++ b/src/main/java/org/mesdag/advjs/mixin/ItemStackMixin.java @@ -0,0 +1,47 @@ +package org.mesdag.advjs.mixin; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; +import org.mesdag.advjs.util.AdvHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import static org.mesdag.advjs.util.Data.LOCK_ITEM_USE; + +@Mixin(ItemStack.class) +public abstract class ItemStackMixin { + @Shadow + public abstract Item getItem(); + + @Inject( + method = "useOnBlock", + at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemUsageContext;getBlockPos()Lnet/minecraft/util/math/BlockPos;"), + locals = LocalCapture.CAPTURE_FAILSOFT, + cancellable = true) + private void advJS$useOn(ItemUsageContext context, CallbackInfoReturnable cir, PlayerEntity player) { + if (player instanceof ServerPlayerEntity serverPlayer && !AdvHelper.advDone(serverPlayer, LOCK_ITEM_USE.get(getItem()))) { + cir.setReturnValue(ActionResult.PASS); + } + } + + @Inject(method = "use", at = @At("HEAD"), cancellable = true) + private void advJS$use(World world, PlayerEntity user, Hand hand, CallbackInfoReturnable> cir) { + if (world.isClient) { + if (AdvHelper.clientAdvDone(LOCK_ITEM_USE.get(getItem()))) return; + } else if (AdvHelper.advDone((ServerPlayerEntity) user, LOCK_ITEM_USE.get(getItem()))) { + return; + } + cir.setReturnValue(TypedActionResult.pass((ItemStack) (Object) this)); + } +} diff --git a/src/main/java/org/mesdag/advjs/mixin/PlayerAdvancementTrackerMixin.java b/src/main/java/org/mesdag/advjs/mixin/PlayerAdvancementTrackerMixin.java index 865a345..5a3b697 100644 --- a/src/main/java/org/mesdag/advjs/mixin/PlayerAdvancementTrackerMixin.java +++ b/src/main/java/org/mesdag/advjs/mixin/PlayerAdvancementTrackerMixin.java @@ -8,6 +8,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Identifier; import org.mesdag.advjs.AdvJS; +import org.mesdag.advjs.util.AdvHelper; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -28,10 +29,10 @@ public abstract class PlayerAdvancementTrackerMixin { @Shadow public abstract boolean revokeCriterion(Advancement advancement, String criterionName); @Inject(method = "grantCriterion", at = @At("HEAD"), cancellable = true) - private void advJS$checkParentDone(Advancement advancement, String criterionName, CallbackInfoReturnable cir) { + private void advJS$checkDone(Advancement advancement, String criterionName, CallbackInfoReturnable cir) { Identifier id = advancement.getId(); - if (!REQUIRE_DONE.containsKey(id)) return; Identifier[] requires = REQUIRE_DONE.get(id); + if (requires==null) return; if (requires.length == 0) { ConsoleJS.SERVER.error("AdvJS/requireDone: Invalid requires[] of '%s', which length is 0".formatted(id)); return; @@ -40,12 +41,8 @@ public abstract class PlayerAdvancementTrackerMixin { ServerAdvancementLoader loader = owner.server.getAdvancementLoader(); for (Identifier requireId : requires) { Advancement required = requireId == AdvJS.PARENT ? advancement.getParent() : loader.get(requireId); - if (required == null) { - ConsoleJS.SERVER.warn("AdvJS/requireDone: Advancement '%s' is not exist, so '%s' will not check it".formatted(requireId, id)); - continue; - } - - if (!getProgress(required).isDone()) { + String nullMsg = "AdvJS/requireDone: Advancement '%s' is not exist, so '%s' will not check it".formatted(requireId, id); + if (!AdvHelper.advDone(owner, required, nullMsg)) { cir.setReturnValue(false); return; } diff --git a/src/main/java/org/mesdag/advjs/mixin/PlayerEntityMixin.java b/src/main/java/org/mesdag/advjs/mixin/PlayerEntityMixin.java index b6a92e2..6645d2e 100644 --- a/src/main/java/org/mesdag/advjs/mixin/PlayerEntityMixin.java +++ b/src/main/java/org/mesdag/advjs/mixin/PlayerEntityMixin.java @@ -3,11 +3,17 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; import org.mesdag.advjs.trigger.custom.CriteriaTriggers; +import org.mesdag.advjs.util.AdvHelper; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import static org.mesdag.advjs.util.Data.LOCK_ENTITY_INTERACT; @Mixin(PlayerEntity.class) public abstract class PlayerEntityMixin { @@ -18,4 +24,12 @@ public abstract class PlayerEntityMixin { CriteriaTriggers.PLAYER_TOUCH.trigger(serverPlayer, entity); } } + + @Inject(method = "interact", at = @At("HEAD"), cancellable = true) + private void advJS$interact(Entity entity, Hand hand, CallbackInfoReturnable cir) { + PlayerEntity self = (PlayerEntity) (Object) this; + if (self instanceof ServerPlayerEntity serverPlayer && !AdvHelper.advDone(serverPlayer, LOCK_ENTITY_INTERACT.get(entity.getType()))) { + cir.setReturnValue(ActionResult.PASS); + } + } } diff --git a/src/main/java/org/mesdag/advjs/mixin/ScreenHandlerMixin.java b/src/main/java/org/mesdag/advjs/mixin/ScreenHandlerMixin.java index 8652528..6288611 100644 --- a/src/main/java/org/mesdag/advjs/mixin/ScreenHandlerMixin.java +++ b/src/main/java/org/mesdag/advjs/mixin/ScreenHandlerMixin.java @@ -10,6 +10,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Identifier; import net.minecraft.util.collection.DefaultedList; +import org.mesdag.advjs.AdvJS; import org.mesdag.advjs.util.AdvHelper; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -30,17 +31,25 @@ public abstract class ScreenHandlerMixin { @Inject(method = "internalOnSlotClick", at = @At("HEAD"), cancellable = true) private void advJS$checkAdvancement(int slotIndex, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) { - if (slotIndex < 0) return; + if (slotIndex < 0 || !(player instanceof ServerPlayerEntity serverPlayer)) return; + +// ResourceLocation slot_lock_by = LOCK_SLOT.get(index); +// if (LOCK_SLOT.containsKey(index) && AdvHelper.advNotDone(serverPlayer, slot_lock_by)) { +// ci.cancel(); +// AdvJS.debugInfo("AdvJS/lockSlot: slot index '%s' has locked by '%s'".formatted(index, slot_lock_by)); +// return; +// } + Slot slot = slots.get(slotIndex); if (!(slot.inventory instanceof CraftingResultInventory)) return; - if (actionType == SlotActionType.PICKUP && player instanceof ServerPlayerEntity serverPlayer) { - ItemStack result = slot.getStack(); - for (Map.Entry entry : LOCK_RESULT.entrySet()){ - if(entry.getKey().test(result) && AdvHelper.advNotDone(serverPlayer, entry.getValue())){ - ci.cancel(); - return; - } + ItemStack result = slot.getStack(); + for (Map.Entry entry : LOCK_RESULT.entrySet()) { + Identifier result_lock_by = entry.getValue(); + if (entry.getKey().test(result) && !AdvHelper.advDone(serverPlayer, result_lock_by)) { + ci.cancel(); + AdvJS.debugInfo("AdvJS/lockResult: result '%s' has locked by '%s'".formatted(result.getItem().kjs$getId(), result_lock_by)); + return; } } } diff --git a/src/main/java/org/mesdag/advjs/mixin/ServerAdvancementLoaderMixin.java b/src/main/java/org/mesdag/advjs/mixin/ServerAdvancementLoaderMixin.java index 39b0d28..fdaddad 100644 --- a/src/main/java/org/mesdag/advjs/mixin/ServerAdvancementLoaderMixin.java +++ b/src/main/java/org/mesdag/advjs/mixin/ServerAdvancementLoaderMixin.java @@ -5,7 +5,6 @@ import com.google.gson.JsonObject; import dev.latvian.mods.kubejs.util.ConsoleJS; import net.minecraft.advancement.*; -import net.minecraft.item.Item; import net.minecraft.loot.LootManager; import net.minecraft.predicate.entity.AdvancementEntityPredicateDeserializer; import net.minecraft.resource.ResourceManager; @@ -57,12 +56,10 @@ public abstract class ServerAdvancementLoaderMixin { for (AdvancementFilter filter : FILTERS) { if (filter.isResolved()) continue; - String parent = advJson.has("parent") ? advJson.get("parent").getAsString() : null; + Identifier parent = advJson.has("parent") ? new Identifier(advJson.get("parent").getAsString()) : null; if (advJson.has("display")) { - JsonObject display = advJson.get("display").getAsJsonObject(); - Item item = display.has("icon") ? JsonHelper.getItem(display.get("icon").getAsJsonObject(), "item", null) : null; - String frame = display.has("frame") ? display.get("frame").getAsString() : null; - if (filter.matches(key, item, frame, parent)) { + AdvancementDisplay displayInfo = AdvancementDisplay.fromJson(JsonHelper.getObject(advJson, "display")); + if (filter.matches(key, displayInfo.getIcon(), displayInfo.getFrame(), parent)) { builder.add(key); } } else if (filter.matches(key, null, null, parent)) { @@ -76,13 +73,13 @@ public abstract class ServerAdvancementLoaderMixin { counter++; } - ConsoleJS.SERVER.info("AdvJS: Removed '%s' advancements".formatted(counter)); + ConsoleJS.SERVER.info("AdvJS: Removed %s advancements".formatted(counter)); } @Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/profiler/Profiler;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/advancement/AdvancementManager;load(Ljava/util/Map;)V", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILSOFT) - private void advjs$modify_add(Map map, ResourceManager resourceManager, Profiler profiler, CallbackInfo ci, Map map2, AdvancementManager advancementManager) { + private void advJS$modify_add(Map map, ResourceManager resourceManager, Profiler profiler, CallbackInfo ci, Map map2, AdvancementManager advancementManager) { advJS$modify(map2, conditionManager); advJS$add(map2); ConsoleJS.SERVER.info("AdvJS: Completely loaded!"); diff --git a/src/main/java/org/mesdag/advjs/mixin/client/ClientAdvancementsAccessor.java b/src/main/java/org/mesdag/advjs/mixin/client/ClientAdvancementsAccessor.java new file mode 100644 index 0000000..955da54 --- /dev/null +++ b/src/main/java/org/mesdag/advjs/mixin/client/ClientAdvancementsAccessor.java @@ -0,0 +1,15 @@ +package org.mesdag.advjs.mixin.client; + +import net.minecraft.advancement.Advancement; +import net.minecraft.advancement.AdvancementProgress; +import net.minecraft.client.network.ClientAdvancementManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(ClientAdvancementManager.class) +public interface ClientAdvancementsAccessor { + @Accessor + Map getAdvancementProgresses(); +} diff --git a/src/main/java/org/mesdag/advjs/trigger/Trigger.java b/src/main/java/org/mesdag/advjs/trigger/Trigger.java index f687258..9fb0978 100644 --- a/src/main/java/org/mesdag/advjs/trigger/Trigger.java +++ b/src/main/java/org/mesdag/advjs/trigger/Trigger.java @@ -20,6 +20,7 @@ import org.mesdag.advjs.trigger.custom.BossEventCriterion; import org.mesdag.advjs.trigger.custom.IncreasedKillScoreCriterion; import org.mesdag.advjs.trigger.custom.PlayerTouchCriterion; +import org.mesdag.advjs.trigger.registry.CustomTrigger; import org.mesdag.advjs.trigger.registry.CustomTriggerInstance; import org.mesdag.advjs.trigger.registry.CustomTriggers; import org.mesdag.advjs.util.ItemSetter; @@ -37,22 +38,24 @@ public Trigger(LootManager conditionManager) { @Info("Your custom trigger, which not match player.") public CustomTriggerInstance custom(Identifier id) { - if(CustomTriggers.TRIGGERS.containsKey(id)) { - return CustomTriggers.TRIGGERS.get(id).create(); + CustomTrigger trigger = CustomTriggers.TRIGGERS.get(id); + if (trigger == null) { + ConsoleJS.SERVER.error("No such trigger: '%s'".formatted(id)); + return CustomTriggers.IMPOSSIBLE; } - ConsoleJS.SERVER.error("No such trigger: '%s'".formatted(id)); - return CustomTriggers.IMPOSSIBLE; + return trigger.create(); } @Info("Your custom trigger, which will match player.") public CustomTriggerInstance custom(Identifier id, Consumer consumer) { - if(CustomTriggers.TRIGGERS.containsKey(id)) { - BaseTriggerInstanceBuilder builder = new BaseTriggerInstanceBuilder(); - consumer.accept(builder); - return CustomTriggers.TRIGGERS.get(id).create(builder.player); + CustomTrigger trigger = CustomTriggers.TRIGGERS.get(id); + if (trigger == null) { + ConsoleJS.SERVER.error("No such trigger: '%s'".formatted(id)); + return CustomTriggers.IMPOSSIBLE; } - ConsoleJS.SERVER.error("No such trigger: '%s'".formatted(id)); - return CustomTriggers.IMPOSSIBLE; + BaseTriggerInstanceBuilder builder = new BaseTriggerInstanceBuilder(); + consumer.accept(builder); + return trigger.create(builder.player); } @Info("Create new trigger by json.") diff --git a/src/main/java/org/mesdag/advjs/trigger/registry/CustomTriggers.java b/src/main/java/org/mesdag/advjs/trigger/registry/CustomTriggers.java index ad521c9..9aa2bb0 100644 --- a/src/main/java/org/mesdag/advjs/trigger/registry/CustomTriggers.java +++ b/src/main/java/org/mesdag/advjs/trigger/registry/CustomTriggers.java @@ -27,10 +27,11 @@ public static void registerAll() { } public static CustomTrigger of(Identifier id) { - if(TRIGGERS.containsKey(id)) { - return TRIGGERS.get(id); + CustomTrigger trigger = TRIGGERS.get(id); + if (trigger == null) { + ConsoleJS.SERVER.error("No such trigger: '%s'".formatted(id)); + return IMPOSSIBLE_TRIGGER; } - ConsoleJS.SERVER.error("No such trigger: '%s'".formatted(id)); - return IMPOSSIBLE_TRIGGER; + return trigger; } } diff --git a/src/main/java/org/mesdag/advjs/util/AdvHelper.java b/src/main/java/org/mesdag/advjs/util/AdvHelper.java index 407d8af..0dbe63f 100644 --- a/src/main/java/org/mesdag/advjs/util/AdvHelper.java +++ b/src/main/java/org/mesdag/advjs/util/AdvHelper.java @@ -1,22 +1,59 @@ package org.mesdag.advjs.util; +import dev.latvian.mods.kubejs.typings.Info; +import dev.latvian.mods.kubejs.typings.Param; import dev.latvian.mods.kubejs.util.ConsoleJS; +import dev.latvian.mods.rhino.util.HideFromJS; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.minecraft.advancement.Advancement; +import net.minecraft.advancement.AdvancementProgress; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientAdvancementManager; +import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; +import org.mesdag.advjs.mixin.client.ClientAdvancementsAccessor; + +import java.util.Map; public class AdvHelper { - public static boolean advNotDone(ServerPlayerEntity serverPlayer, Identifier id) { - return !advDone(serverPlayer, id, null); + public static boolean advDone(ServerPlayerEntity serverPlayer, Identifier id) { + return advDone(serverPlayer, id, null); + } + + @Info(params = { + @Param(name = "serverPlayer"), + @Param(name = "id"), + @Param(name = "nullMsg", value = "The message to send if advancement failed to get.") + }) + public static boolean advDone(ServerPlayerEntity serverPlayer, @Nullable Identifier id, @Nullable String nullMsg) { + if (id == null) return true; // if failed to get advancement id, return true + return advDone(serverPlayer, serverPlayer.server.getAdvancementLoader().get(id), nullMsg); } - public static boolean advDone(ServerPlayerEntity serverPlayer, Identifier id, @Nullable String nullMsg) { - Advancement advancement = serverPlayer.server.getAdvancementLoader().get(id); + public static boolean advDone(ServerPlayerEntity serverPlayer, @Nullable Advancement advancement, @Nullable String nullMsg) { if (advancement == null) { if (nullMsg != null) ConsoleJS.SERVER.error(nullMsg); return false; } return serverPlayer.getAdvancementTracker().getProgress(advancement).isDone(); } + + @HideFromJS + @Environment(EnvType.CLIENT) + public static boolean clientAdvDone(@Nullable Identifier id) { + if (id == null) return true; // if failed to get advancement id, return true + ClientPlayNetworkHandler connection = MinecraftClient.getInstance().getNetworkHandler(); + if (connection == null) return false; + + ClientAdvancementManager manager = connection.getAdvancementHandler(); + Advancement advancement = manager.getManager().get(id); + if (advancement == null) return false; + + Map progresses = ((ClientAdvancementsAccessor) manager).getAdvancementProgresses(); + AdvancementProgress progress = progresses.get(advancement); + return progress != null && progress.isDone(); + } } diff --git a/src/main/java/org/mesdag/advjs/util/AdvancementFilter.java b/src/main/java/org/mesdag/advjs/util/AdvancementFilter.java index bb0ccbd..4302c50 100644 --- a/src/main/java/org/mesdag/advjs/util/AdvancementFilter.java +++ b/src/main/java/org/mesdag/advjs/util/AdvancementFilter.java @@ -1,12 +1,11 @@ package org.mesdag.advjs.util; -import com.google.gson.JsonObject; +import dev.latvian.mods.kubejs.item.ItemStackJS; import dev.latvian.mods.kubejs.util.ConsoleJS; -import dev.latvian.mods.kubejs.util.MapJS; +import dev.latvian.mods.kubejs.util.UtilsJS; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.item.Item; -import net.minecraft.item.Items; -import net.minecraft.registry.Registries; +import net.minecraft.advancement.AdvancementFrame; +import net.minecraft.item.ItemStack; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; @@ -16,46 +15,47 @@ public class AdvancementFilter { @Nullable Identifier path; @Nullable String modid; - @Nullable Item icon; - @Nullable String frame; - @Nullable String parent; + @Nullable ItemStack icon; + @Nullable AdvancementFrame frame; + @Nullable Identifier parent; private boolean resolved = false; public static AdvancementFilter of(Object o) { AdvancementFilter filter = new AdvancementFilter(); if (o instanceof CharSequence charSequence) { filter.path = new Identifier(charSequence.toString()); - } else if (o instanceof Map) { - JsonObject jsonObject = MapJS.json(o); - if (jsonObject == null) { - return filter; - } - - if (jsonObject.has("mod")) { - String modid = jsonObject.get("mod").getAsString(); - if (FabricLoader.getInstance().isModLoaded(modid)) { - filter.modid = modid; + } else if (o instanceof Map map) { + Object mod = map.get("mod"); + if (mod instanceof CharSequence modid) { + String modidStr = modid.toString(); + if (FabricLoader.getInstance().isModLoaded(modidStr)) { + filter.modid = modidStr; } else { - ConsoleJS.SERVER.warn("AdvJS/RemoveFilter: Mod '%s' not found".formatted(modid)); + ConsoleJS.SERVER.warn("AdvJS/RemoveFilter: mod '%s' not found".formatted(modid)); } } - if (jsonObject.has("icon")) { - Identifier id = new Identifier(jsonObject.get("icon").getAsString()); - Item item = Registries.ITEM.containsId(id) ? Registries.ITEM.get(id) : Items.AIR; - if (item != Items.AIR) { - filter.icon = item; + Object icon = map.get("icon"); + if (icon != null) { + ItemStack iconStack = ItemStackJS.of(icon); + if (iconStack == ItemStack.EMPTY) { + ConsoleJS.SERVER.warn("AdvJS/RemoveFilter: icon '%s' not found".formatted(icon)); } else { - ConsoleJS.SERVER.warn("AdvJS/RemoveFilter: Icon '%s' not found".formatted(id)); + filter.icon = iconStack; } } - if (jsonObject.has("frame")) { - filter.frame = jsonObject.get("frame").getAsString(); + Object frame = map.get("frame"); + if (frame instanceof CharSequence frameStr) { + filter.frame = AdvancementFrame.forName(frameStr.toString()); + } else if (frame instanceof AdvancementFrame frameType) { + filter.frame = frameType; } - if (jsonObject.has("parent")) { - filter.parent = jsonObject.get("parent").getAsString(); + Object parent = map.get("parent"); + Identifier parentId = UtilsJS.getMCID(null, parent); + if (parentId != null) { + filter.parent = parentId; } } return filter; @@ -69,7 +69,7 @@ public boolean fail() { return path == null && modid == null && icon == null && frame == null && parent == null; } - public boolean matches(Identifier path, Item icon, String frame, String parent) { + public boolean matches(Identifier path, ItemStack icon, AdvancementFrame frame, Identifier parent) { if (this.path != null) { if (this.path.equals(path)) { resolved = true; diff --git a/src/main/java/org/mesdag/advjs/util/Bounds.java b/src/main/java/org/mesdag/advjs/util/Bounds.java index 2c2d084..7b72df8 100644 --- a/src/main/java/org/mesdag/advjs/util/Bounds.java +++ b/src/main/java/org/mesdag/advjs/util/Bounds.java @@ -73,7 +73,7 @@ public static Bounds of(Object o) { return new Bounds(min.doubleValue(), max.doubleValue()); } else if (o instanceof Map) { Map m = (Map) o; - return new Bounds(m.containsKey("min") ? (Number) m.get("min") : null, m.containsKey("max") ? (Number) m.get("max") : null); + return new Bounds((Number) m.get("min"), (Number) m.get("max")); } return ANY; diff --git a/src/main/java/org/mesdag/advjs/util/Data.java b/src/main/java/org/mesdag/advjs/util/Data.java index d2638e1..661f487 100644 --- a/src/main/java/org/mesdag/advjs/util/Data.java +++ b/src/main/java/org/mesdag/advjs/util/Data.java @@ -1,5 +1,8 @@ package org.mesdag.advjs.util; +import net.minecraft.block.Block; +import net.minecraft.entity.EntityType; +import net.minecraft.item.Item; import net.minecraft.predicate.item.ItemPredicate; import net.minecraft.util.Identifier; import org.mesdag.advjs.advancement.AdvBuilder; @@ -14,6 +17,9 @@ public class Data { public static final Hashtable GETTERS = new Hashtable<>(); public static final Hashtable BUILDERS = new Hashtable<>(); public static final Hashtable LOCK_RESULT = new Hashtable<>(); + public static final Hashtable LOCK_ITEM_USE = new Hashtable<>(); + public static final Hashtable LOCK_BLOCK_INTERACT = new Hashtable<>(); + public static final Hashtable, Identifier> LOCK_ENTITY_INTERACT = new Hashtable<>(); public static final Hashtable REQUIRE_DONE = new Hashtable<>(); public static final Hashtable DISPLAY_OFFSET = new Hashtable<>(); @@ -23,6 +29,9 @@ public static void clear() { GETTERS.clear(); BUILDERS.clear(); LOCK_RESULT.clear(); + LOCK_ITEM_USE.clear(); + LOCK_BLOCK_INTERACT.clear(); + LOCK_ENTITY_INTERACT.clear(); REQUIRE_DONE.clear(); DISPLAY_OFFSET.clear(); } diff --git a/src/main/resources/advjs.mixins.json b/src/main/resources/advjs.mixins.json index f298ebf..9ac3370 100644 --- a/src/main/resources/advjs.mixins.json +++ b/src/main/resources/advjs.mixins.json @@ -3,8 +3,10 @@ "package": "org.mesdag.advjs.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ + "AbstractBlock$AbstractBlockStateMixin", "AdvancementRewardsMixin", "BlockMixin", + "ItemStackMixin", "PlayerAdvancementTrackerMixin", "PlayerEntityMixin", "ScreenHandlerMixin", @@ -16,6 +18,7 @@ "defaultRequire": 1 }, "client": [ + "client.ClientAdvancementsAccessor", "revelationary.ClientAdvancementsMixin" ] } \ No newline at end of file