From f4183e8230d63ede5bb23b27cce9230d2028ca8c Mon Sep 17 00:00:00 2001 From: eggohito <66972816+eggohito@users.noreply.github.com> Date: Sun, 5 Nov 2023 23:19:52 +0800 Subject: [PATCH] Added stuff related to command tags + Added a CCA synced component for command tags; allows for checking for command tags in the client + Added `has_command_tag` entity condition type --- .../java/io/github/apace100/apoli/Apoli.java | 7 ++ .../apoli/component/CommandTagComponent.java | 27 +++++++ .../component/CommandTagComponentImpl.java | 80 +++++++++++++++++++ .../apace100/apoli/mixin/EntityAccessor.java | 7 ++ .../apace100/apoli/mixin/EntityMixin.java | 49 ++++++++++++ .../factory/condition/EntityConditions.java | 1 + .../entity/HasCommandTagCondition.java | 42 ++++++++++ src/main/resources/fabric.mod.json | 3 +- 8 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/github/apace100/apoli/component/CommandTagComponent.java create mode 100644 src/main/java/io/github/apace100/apoli/component/CommandTagComponentImpl.java create mode 100644 src/main/java/io/github/apace100/apoli/power/factory/condition/entity/HasCommandTagCondition.java diff --git a/src/main/java/io/github/apace100/apoli/Apoli.java b/src/main/java/io/github/apace100/apoli/Apoli.java index 9917bec62..4943d19df 100644 --- a/src/main/java/io/github/apace100/apoli/Apoli.java +++ b/src/main/java/io/github/apace100/apoli/Apoli.java @@ -5,6 +5,8 @@ import dev.onyxstudios.cca.api.v3.entity.RespawnCopyStrategy; import io.github.apace100.apoli.command.PowerCommand; import io.github.apace100.apoli.command.ResourceCommand; +import io.github.apace100.apoli.component.CommandTagComponent; +import io.github.apace100.apoli.component.CommandTagComponentImpl; import io.github.apace100.apoli.component.PowerHolderComponent; import io.github.apace100.apoli.component.PowerHolderComponentImpl; import io.github.apace100.apoli.global.GlobalPowerSetLoader; @@ -30,6 +32,7 @@ import net.fabricmc.fabric.api.resource.conditions.v1.ResourceConditions; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.advancement.criterion.Criteria; +import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.registry.Registries; import net.minecraft.resource.ResourceType; @@ -128,6 +131,10 @@ public void registerEntityComponentFactories(EntityComponentFactoryRegistry regi .impl(PowerHolderComponentImpl.class) .respawnStrategy(RespawnCopyStrategy.ALWAYS_COPY) .end(PowerHolderComponentImpl::new); + registry.beginRegistration(Entity.class, CommandTagComponent.KEY) + .impl(CommandTagComponentImpl.class) + .respawnStrategy(RespawnCopyStrategy.ALWAYS_COPY) + .end(CommandTagComponentImpl::new); } @Override diff --git a/src/main/java/io/github/apace100/apoli/component/CommandTagComponent.java b/src/main/java/io/github/apace100/apoli/component/CommandTagComponent.java new file mode 100644 index 000000000..30e52c4b6 --- /dev/null +++ b/src/main/java/io/github/apace100/apoli/component/CommandTagComponent.java @@ -0,0 +1,27 @@ +package io.github.apace100.apoli.component; + +import dev.onyxstudios.cca.api.v3.component.ComponentKey; +import dev.onyxstudios.cca.api.v3.component.ComponentRegistry; +import dev.onyxstudios.cca.api.v3.component.load.ServerLoadAwareComponent; +import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent; +import io.github.apace100.apoli.Apoli; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Set; + +public interface CommandTagComponent extends AutoSyncedComponent, ServerLoadAwareComponent { + + ComponentKey KEY = ComponentRegistry.getOrCreate(Apoli.identifier("command_tags"), CommandTagComponent.class); + + Set getTags(); + + @ApiStatus.Internal + void setTags(Set commandTags); + + @ApiStatus.Internal + boolean addTag(String commandTag); + + @ApiStatus.Internal + boolean removeTag(String commandTag); + +} diff --git a/src/main/java/io/github/apace100/apoli/component/CommandTagComponentImpl.java b/src/main/java/io/github/apace100/apoli/component/CommandTagComponentImpl.java new file mode 100644 index 000000000..a16b5b8bc --- /dev/null +++ b/src/main/java/io/github/apace100/apoli/component/CommandTagComponentImpl.java @@ -0,0 +1,80 @@ +package io.github.apace100.apoli.component; + +import io.github.apace100.apoli.mixin.EntityAccessor; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtList; +import net.minecraft.nbt.NbtString; + +import java.util.HashSet; +import java.util.Set; + +public class CommandTagComponentImpl implements CommandTagComponent { + + private final Set commandTags; + private final Entity provider; + + public CommandTagComponentImpl(Entity provider) { + this.commandTags = new HashSet<>(); + this.provider = provider; + } + + @Override + public Set getTags() { + return commandTags; + } + + @Override + public void setTags(Set commandTags) { + this.commandTags.clear(); + this.commandTags.addAll(commandTags); + } + + @Override + public boolean addTag(String commandTag) { + return this.commandTags.add(commandTag); + } + + @Override + public boolean removeTag(String commandTag) { + return this.commandTags.remove(commandTag); + } + + @Override + public void loadServerside() { + + Set originalCommandTags = ((EntityAccessor) provider).getOriginalCommandTags(); + + if (!commandTags.equals(originalCommandTags)) { + this.setTags(originalCommandTags); + CommandTagComponent.KEY.sync(provider); + } + + } + + @Override + public void readFromNbt(NbtCompound tag) { + + NbtList commandTagsNbt = tag.getList("Tags", NbtElement.STRING_TYPE); + this.commandTags.clear(); + + for (int i = 0; i < commandTagsNbt.size(); ++i) { + this.commandTags.add(commandTagsNbt.getString(i)); + } + + } + + @Override + public void writeToNbt(NbtCompound tag) { + + NbtList commandTagsNbt = new NbtList(); + this.commandTags.stream() + .map(NbtString::of) + .forEach(commandTagsNbt::add); + + tag.put("Tags", commandTagsNbt); + + } + +} diff --git a/src/main/java/io/github/apace100/apoli/mixin/EntityAccessor.java b/src/main/java/io/github/apace100/apoli/mixin/EntityAccessor.java index fc3c0735d..845515196 100644 --- a/src/main/java/io/github/apace100/apoli/mixin/EntityAccessor.java +++ b/src/main/java/io/github/apace100/apoli/mixin/EntityAccessor.java @@ -2,11 +2,18 @@ import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; +import java.util.Set; + @Mixin(Entity.class) public interface EntityAccessor { @Invoker boolean callIsBeingRainedOn(); + + @Accessor("commandTags") + Set getOriginalCommandTags(); + } diff --git a/src/main/java/io/github/apace100/apoli/mixin/EntityMixin.java b/src/main/java/io/github/apace100/apoli/mixin/EntityMixin.java index c6a5f8a98..4d909932f 100644 --- a/src/main/java/io/github/apace100/apoli/mixin/EntityMixin.java +++ b/src/main/java/io/github/apace100/apoli/mixin/EntityMixin.java @@ -5,6 +5,7 @@ import io.github.apace100.apoli.access.MovingEntity; import io.github.apace100.apoli.access.SubmergableEntity; import io.github.apace100.apoli.access.WaterMovingEntity; +import io.github.apace100.apoli.component.CommandTagComponent; import io.github.apace100.apoli.component.PowerHolderComponent; import io.github.apace100.apoli.power.*; import io.github.apace100.calio.Calio; @@ -81,6 +82,10 @@ private void makeFullyFireImmune(CallbackInfoReturnable cir) { @Shadow protected Object2DoubleMap> fluidHeight; + @Shadow public abstract World getWorld(); + + @Shadow public abstract Set getCommandTags(); + @Inject(method = "isTouchingWater", at = @At("HEAD"), cancellable = true) private void makeEntitiesIgnoreWater(CallbackInfoReturnable cir) { if(PowerHolderComponent.hasPower((Entity)(Object)this, IgnoreWaterPower.class)) { @@ -281,4 +286,48 @@ private void modifyGlowingColorFromPower(CallbackInfoReturnable cir) { return !PreventEntityCollisionPower.doesApply((Entity) (Object) this, other) && original; } + @Unique + private boolean apoli$shouldSyncCommandTags = false; + + @Inject(method = "addCommandTag", at = @At("TAIL")) + private void apoli$addCommandTagToComponent(String tag, CallbackInfoReturnable cir) { + + boolean result = CommandTagComponent.KEY.get(this).addTag(tag); + + if (result) { + apoli$shouldSyncCommandTags = true; + } + + } + + @Inject(method = "removeScoreboardTag", at = @At("TAIL")) + private void apoli$removeCommandTagFromComponent(String tag, CallbackInfoReturnable cir) { + + boolean result = CommandTagComponent.KEY.get(this).removeTag(tag); + + if (result) { + apoli$shouldSyncCommandTags = true; + } + + } + + @ModifyReturnValue(method = "getCommandTags", at = @At("RETURN")) + private Set apoli$overrideCommandTags(Set original) { + return CommandTagComponent.KEY.get(this).getTags(); + } + + @Inject(method = "baseTick", at = @At("TAIL")) + private void apoli$syncCommandTags(CallbackInfo ci) { + + if (!apoli$shouldSyncCommandTags || this.getWorld().isClient) { + return; + } + + CommandTagComponent.KEY.get(this).setTags(((EntityAccessor) this).getOriginalCommandTags()); + CommandTagComponent.KEY.sync(this); + + apoli$shouldSyncCommandTags = false; + + } + } diff --git a/src/main/java/io/github/apace100/apoli/power/factory/condition/EntityConditions.java b/src/main/java/io/github/apace100/apoli/power/factory/condition/EntityConditions.java index cfce0fc92..55057b823 100644 --- a/src/main/java/io/github/apace100/apoli/power/factory/condition/EntityConditions.java +++ b/src/main/java/io/github/apace100/apoli/power/factory/condition/EntityConditions.java @@ -444,6 +444,7 @@ public static void register() { register(InThunderstormCondition.getFactory()); register(AdvancementCondition.getFactory()); register(SetSizeCondition.getFactory()); + register(HasCommandTagCondition.getFactory()); } private static void register(ConditionFactory conditionFactory) { diff --git a/src/main/java/io/github/apace100/apoli/power/factory/condition/entity/HasCommandTagCondition.java b/src/main/java/io/github/apace100/apoli/power/factory/condition/entity/HasCommandTagCondition.java new file mode 100644 index 000000000..911da2e07 --- /dev/null +++ b/src/main/java/io/github/apace100/apoli/power/factory/condition/entity/HasCommandTagCondition.java @@ -0,0 +1,42 @@ +package io.github.apace100.apoli.power.factory.condition.entity; + +import io.github.apace100.apoli.Apoli; +import io.github.apace100.apoli.power.factory.condition.ConditionFactory; +import io.github.apace100.apoli.util.IdentifierAlias; +import io.github.apace100.calio.data.SerializableData; +import io.github.apace100.calio.data.SerializableDataTypes; +import net.minecraft.entity.Entity; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class HasCommandTagCondition { + + public static boolean condition(SerializableData.Instance data, Entity entity) { + + Set specifiedCommandTags = new HashSet<>(); + Set commandTags = entity.getCommandTags(); + + data.ifPresent("command_tag", specifiedCommandTags::add); + data.ifPresent("command_tags", specifiedCommandTags::addAll); + + return specifiedCommandTags.isEmpty() ? !commandTags.isEmpty() + : !Collections.disjoint(commandTags, specifiedCommandTags); + + } + + public static ConditionFactory getFactory() { + IdentifierAlias.addPathAlias("has_tag", "has_command_tag"); + return new ConditionFactory<>( + Apoli.identifier("has_command_tag"), + new SerializableData() + .add("tag", SerializableDataTypes.STRING, null) + .addFunctionedDefault("command_tag", SerializableDataTypes.STRING, data -> data.get("tag")) + .add("tags", SerializableDataTypes.STRINGS, null) + .addFunctionedDefault("command_tags", SerializableDataTypes.STRINGS, data -> data.get("tags")), + HasCommandTagCondition::condition + ); + } + +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 1d17f0354..6c2afedb9 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -45,7 +45,8 @@ ], "custom": { "cardinal-components": [ - "apoli:powers" + "apoli:powers", + "apoli:command_tags" ], "modmenu": { "badges": ["library"]