diff --git a/src/main/java/com/github/skriptdev/skript/api/hytale/utils/EntityReferenceUtils.java b/src/main/java/com/github/skriptdev/skript/api/hytale/utils/EntityReferenceUtils.java index ec790cdf..2be77233 100644 --- a/src/main/java/com/github/skriptdev/skript/api/hytale/utils/EntityReferenceUtils.java +++ b/src/main/java/com/github/skriptdev/skript/api/hytale/utils/EntityReferenceUtils.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.spatial.SpatialResource; import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.server.core.entity.Entity; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.item.ItemComponent; @@ -44,6 +45,16 @@ public static ReferenceType getType(Class> componentCl return TYPES_MAP.get(componentClass); } + @SuppressWarnings("unchecked") + public static @Nullable Ref getRef(Object o) { + if (o instanceof Ref ref) { + return (Ref) ref; + } else if (o instanceof Entity entity) { + return entity.getReference(); + } + return null; + } + public static List> getRefsInSphere(@Nonnull Vector3d pos, double radius, @Nonnull Store store) { ObjectList> results = SpatialResource.getThreadLocalReferenceList(); EntityModule entityModule = EntityModule.get(); diff --git a/src/main/java/com/github/skriptdev/skript/api/hytale/utils/EntityUtils.java b/src/main/java/com/github/skriptdev/skript/api/hytale/utils/EntityUtils.java index d0518e4f..04ef05e6 100644 --- a/src/main/java/com/github/skriptdev/skript/api/hytale/utils/EntityUtils.java +++ b/src/main/java/com/github/skriptdev/skript/api/hytale/utils/EntityUtils.java @@ -10,15 +10,30 @@ import com.hypixel.hytale.math.vector.Location; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3f; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +import com.hypixel.hytale.server.core.asset.type.item.config.Item; +import com.hypixel.hytale.server.core.asset.type.model.config.Model; +import com.hypixel.hytale.server.core.asset.type.model.config.ModelAsset; import com.hypixel.hytale.server.core.entity.Entity; import com.hypixel.hytale.server.core.entity.LivingEntity; import com.hypixel.hytale.server.core.entity.UUIDComponent; +import com.hypixel.hytale.server.core.entity.entities.BlockEntity; import com.hypixel.hytale.server.core.entity.movement.MovementStatesComponent; import com.hypixel.hytale.server.core.entity.nameplate.Nameplate; import com.hypixel.hytale.server.core.inventory.ItemStack; +import com.hypixel.hytale.server.core.modules.entity.component.EntityScaleComponent; +import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; +import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; +import com.hypixel.hytale.server.core.modules.entity.component.PersistentModel; +import com.hypixel.hytale.server.core.modules.entity.component.PropComponent; +import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entity.item.ItemComponent; +import com.hypixel.hytale.server.core.modules.entity.item.PreventItemMerging; +import com.hypixel.hytale.server.core.modules.entity.item.PreventPickup; +import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId; import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap; import com.hypixel.hytale.server.core.modules.entitystats.EntityStatsModule; +import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.entities.NPCEntity; @@ -29,6 +44,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.annotation.Nonnull; import java.util.UUID; /** @@ -227,7 +243,7 @@ public static > void tryRemoveComponent(Entity ent @SuppressWarnings({"DataFlowIssue"}) public static @NotNull Pair, ItemComponent> dropItem(Store store, ItemStack itemStack, - Location location, Vector3f velocity, float pickupDelay) { + Location location, Vector3f velocity, float pickupDelay) { if (itemStack.isEmpty() || !itemStack.isValid()) { return new Pair<>(null, null); } @@ -324,4 +340,119 @@ public static void clearMarkedEntity(NPCEntity npcEntity, @Nullable Entity targe } } + private static String getItemModelId(@Nonnull Item item) { + String modelId = item.getModel(); + + if (modelId == null && item.hasBlockType()) { + BlockType blockType = BlockType.getAssetMap().getAsset(item.getId()); + + if (blockType != null && blockType.getCustomModel() != null) { + modelId = blockType.getCustomModel(); + } + } + + return modelId; + } + + private static Model getItemModel(@Nonnull Item item) { + String modelId = getItemModelId(item); + + if (modelId == null) { + return null; + } else { + ModelAsset modelAsset = ModelAsset.getAssetMap().getAsset(modelId); + + return modelAsset != null ? Model.createStaticScaledModel(modelAsset, 1.0f) : null; + } + } + + public static Ref spawnModel(@NotNull Object object, @NotNull Location location) { + return switch (object) { + case Item item -> spawnItem(item, location); + case BlockType blockType -> spawnBlock(null, blockType, location); + case ModelAsset modelAsset -> spawnModel(null, Model.createStaticScaledModel(modelAsset, 1.0f), location); + default -> null; + }; + } + + public static Ref spawnModel(@Nullable Item item, @NotNull Model model, @NotNull Location location) { + World world = Universe.get().getWorld(location.getWorld()); + if (world == null) return null; + + Store store = world.getEntityStore().getStore(); + Holder holder = store.getRegistry().newHolder(); + + holder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId())); + holder.addComponent(TransformComponent.getComponentType(), new TransformComponent(location.getPosition(), location.getRotation())); + holder.addComponent(ModelComponent.getComponentType(), new ModelComponent(model)); + holder.addComponent(PersistentModel.getComponentType(), + new PersistentModel( + new Model.ModelReference(model.getModelAssetId(), 1.0f, null, true))); + if (item != null) { + ItemStack itemStack = new ItemStack(item.getId(), 1); + itemStack.setOverrideDroppedItemAnimation(true); + holder.addComponent(ItemComponent.getComponentType(), new ItemComponent(itemStack)); + } + holder.addComponent(EntityScaleComponent.getComponentType(), new EntityScaleComponent(1.0f)); + holder.addComponent(PreventPickup.getComponentType(), PreventPickup.INSTANCE); + holder.addComponent(PreventItemMerging.getComponentType(), PreventItemMerging.INSTANCE); + holder.addComponent(HeadRotation.getComponentType(), new HeadRotation(location.getRotation())); + holder.addComponent(PropComponent.getComponentType(), PropComponent.get()); + holder.ensureComponent(UUIDComponent.getComponentType()); + return store.addEntity(holder, AddReason.SPAWN); + } + + public static Ref spawnItem(@NotNull Item item, @NotNull Location location) { + Model model = getItemModel(item); + if (model != null) { + return spawnModel(item, model, location); + } + if (item.hasBlockType()) { + BlockType blockType = BlockType.getAssetMap().getAsset(item.getId()); + if (blockType != null) { + return spawnBlock(item, blockType, location); + } + } + World world = Universe.get().getWorld(location.getWorld()); + if (world == null) return null; + + Store store = world.getEntityStore().getStore(); + Holder holder = store.getRegistry().newHolder(); + + holder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId())); + holder.addComponent(TransformComponent.getComponentType(), new TransformComponent(location.getPosition(), location.getRotation())); + ItemStack itemStack = new ItemStack(item.getId(), 1); + itemStack.setOverrideDroppedItemAnimation(true); + holder.addComponent(ItemComponent.getComponentType(), new ItemComponent(itemStack)); + holder.addComponent(EntityScaleComponent.getComponentType(), new EntityScaleComponent(1.0f)); + holder.addComponent(PreventPickup.getComponentType(), PreventPickup.INSTANCE); + holder.addComponent(PreventItemMerging.getComponentType(), PreventItemMerging.INSTANCE); + holder.addComponent(HeadRotation.getComponentType(), new HeadRotation(location.getRotation())); + holder.addComponent(PropComponent.getComponentType(), PropComponent.get()); + return store.addEntity(holder, AddReason.SPAWN); + } + + public static Ref spawnBlock(@Nullable Item item, @NotNull BlockType blockType, @NotNull Location location) { + World world = Universe.get().getWorld(location.getWorld()); + if (world == null) return null; + + Store store = world.getEntityStore().getStore(); + Holder holder = store.getRegistry().newHolder(); + + holder.addComponent(BlockEntity.getComponentType(), new BlockEntity(blockType.getId())); + holder.addComponent(TransformComponent.getComponentType(), new TransformComponent(location.getPosition(), location.getRotation())); + holder.addComponent(EntityScaleComponent.getComponentType(), new EntityScaleComponent(1.0F)); + if (item != null) { + ItemStack itemStack = new ItemStack(item.getId(), 1); + itemStack.setOverrideDroppedItemAnimation(true); + holder.addComponent(ItemComponent.getComponentType(), new ItemComponent(itemStack)); + } + holder.addComponent(PreventPickup.getComponentType(), PreventPickup.INSTANCE); + holder.addComponent(PreventItemMerging.getComponentType(), PreventItemMerging.INSTANCE); + holder.addComponent(HeadRotation.getComponentType(), new HeadRotation(location.getRotation())); + holder.addComponent(PropComponent.getComponentType(), PropComponent.get()); + holder.ensureComponent(UUIDComponent.getComponentType()); + return store.addEntity(holder, AddReason.SPAWN); + } + } diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/docs/JsonDocPrinter.java b/src/main/java/com/github/skriptdev/skript/api/skript/docs/JsonDocPrinter.java index c6a88b1a..73bce174 100644 --- a/src/main/java/com/github/skriptdev/skript/api/skript/docs/JsonDocPrinter.java +++ b/src/main/java/com/github/skriptdev/skript/api/skript/docs/JsonDocPrinter.java @@ -50,6 +50,7 @@ public class JsonDocPrinter { private final SkriptAddon addon; private final String addonKey; private final boolean includeSkriptParser; + private final List ids = new ArrayList<>(); public JsonDocPrinter(CommandSender sender, SkriptAddon addon) { this.sender = sender; @@ -593,7 +594,12 @@ private BsonString getId(String type, String syntaxId) { addonName = "HySkript"; } String s = type + ":" + addonName + ":" + syntaxId; - return new BsonString(s.toLowerCase(Locale.ROOT).replace(" ", "_")); + String id = s.toLowerCase(Locale.ROOT).replace(" ", "_"); + if (this.ids.contains(id)) { + Utils.error("Duplicate ID: " + id); + } + this.ids.add(id); + return new BsonString(id); } diff --git a/src/main/java/com/github/skriptdev/skript/api/utils/ReflectionUtils.java b/src/main/java/com/github/skriptdev/skript/api/utils/ReflectionUtils.java index 20cae7be..7d04b03b 100644 --- a/src/main/java/com/github/skriptdev/skript/api/utils/ReflectionUtils.java +++ b/src/main/java/com/github/skriptdev/skript/api/utils/ReflectionUtils.java @@ -2,6 +2,9 @@ import com.hypixel.hytale.server.core.modules.accesscontrol.AccessControlModule; import com.hypixel.hytale.server.core.modules.accesscontrol.provider.HytaleBanProvider; +import com.hypixel.hytale.server.core.universe.world.World; +import com.hypixel.hytale.server.core.universe.world.WorldConfig; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; @@ -37,4 +40,28 @@ public static void init() { return BAN_PROVIDER; } + /** + * Set world override time durations of a world. + *
I didn't want to do this, but Hytale doesn't have a setter and this is private. + * + * @param world World to change times for + * @param seconds Seconds to override + * @param day Whether to override daytime or nighttime duration + */ + public static void setWorldTimeOverrides(@NotNull World world, @Nullable Integer seconds, boolean day) { + WorldConfig worldConfig = world.getWorldConfig(); + try { + Field field; + if (day) { + field = worldConfig.getClass().getDeclaredField("daytimeDurationSecondsOverride"); + } else { + field = worldConfig.getClass().getDeclaredField("nighttimeDurationSecondsOverride"); + } + field.setAccessible(true); + field.set(worldConfig, seconds); + } catch (NoSuchFieldException | IllegalAccessException ignore) { + + } + } + } diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/conditions/ConditionHandler.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/conditions/ConditionHandler.java index 6599cc6d..e351fc4a 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/conditions/ConditionHandler.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/conditions/ConditionHandler.java @@ -25,6 +25,7 @@ import com.github.skriptdev.skript.plugin.elements.conditions.player.CondPlayerMovementSprinting; import com.github.skriptdev.skript.plugin.elements.conditions.player.CondPlayerMovementSwimming; import com.github.skriptdev.skript.plugin.elements.conditions.player.CondPlayerMovementWalking; +import com.github.skriptdev.skript.plugin.elements.conditions.ref.CondCanBePickedUp; import com.github.skriptdev.skript.plugin.elements.conditions.world.CondChunkIsLoaded; import com.github.skriptdev.skript.plugin.elements.conditions.world.CondWorldTimePaused; @@ -66,6 +67,9 @@ public static void register(SkriptRegistration registration) { CondPlayerMovementSwimming.register(registration); CondPlayerMovementWalking.register(registration); + // REF + CondCanBePickedUp.register(registration); + // WORLD CondChunkIsLoaded.register(registration); CondWorldTimePaused.register(registration); diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/conditions/ref/CondCanBePickedUp.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/conditions/ref/CondCanBePickedUp.java new file mode 100644 index 00000000..5fd4bc02 --- /dev/null +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/conditions/ref/CondCanBePickedUp.java @@ -0,0 +1,67 @@ +package com.github.skriptdev.skript.plugin.elements.conditions.ref; + +import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.server.core.modules.entity.item.PreventPickup; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import io.github.syst3ms.skriptparser.lang.TriggerContext; +import io.github.syst3ms.skriptparser.lang.properties.ConditionalType; +import io.github.syst3ms.skriptparser.lang.properties.PropertyConditional; +import io.github.syst3ms.skriptparser.types.changers.ChangeMode; +import io.github.syst3ms.skriptparser.util.CollectionUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public class CondCanBePickedUp extends PropertyConditional> { + + public static void register(SkriptRegistration reg) { + reg.newPropertyConditional(CondCanBePickedUp.class, + "refs", ConditionalType.CAN, "be picked up") + .name("Ref - Can Be Picked Up") + .description("Check if a ref can be picked up.", + "This generally refers to dropped items.", + "This can be set, preventing items from being picked up.") + .since("INSERT VERSION") + .register(); + } + + @Override + public boolean check(@NotNull TriggerContext ctx) { + return getPerformer().check(ctx, ref -> { + Store store = ref.getStore(); + return store.getComponent(ref, PreventPickup.getComponentType()) == null; + }, isNegated()); + } + + @Override + public Optional[]> acceptsChange(@NotNull ChangeMode mode) { + if (mode == ChangeMode.SET) { + return CollectionUtils.optionalArrayOf(Boolean.class); + } + return Optional.empty(); + } + + @SuppressWarnings("ConstantValue") + @Override + public void change(@NotNull TriggerContext ctx, @NotNull ChangeMode changeMode, Object @NotNull [] changeWith) { + if (changeWith == null || changeWith.length == 0 || !(changeWith[0] instanceof Boolean bool)) { + return; + } + for (Ref ref : getPerformer().getArray(ctx)) { + Store store = ref.getStore(); + if (bool) { + store.removeComponentIfExists(ref, PreventPickup.getComponentType()); + } else { + store.ensureComponent(ref, PreventPickup.getComponentType()); + } + } + } + + @Override + public String toString(@NotNull TriggerContext ctx, boolean debug) { + return getPerformer().toString(ctx, debug) + " can be picked up"; + } + +} diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/EffectHandler.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/EffectHandler.java index ab5928c0..8b95e43c 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/EffectHandler.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/EffectHandler.java @@ -12,6 +12,7 @@ import com.github.skriptdev.skript.plugin.elements.effects.entity.EffFreeze; import com.github.skriptdev.skript.plugin.elements.effects.entity.EffInteraction; import com.github.skriptdev.skript.plugin.elements.effects.entity.EffKill; +import com.github.skriptdev.skript.plugin.elements.effects.entity.EffPlayAnimation; import com.github.skriptdev.skript.plugin.elements.effects.entity.EffRemoveStatModifier; import com.github.skriptdev.skript.plugin.elements.effects.entity.EffRide; import com.github.skriptdev.skript.plugin.elements.effects.entity.EffShoot; @@ -56,6 +57,7 @@ public static void register(SkriptRegistration registration) { EffFreeze.register(registration); EffInteraction.register(registration); EffKill.register(registration); + EffPlayAnimation.register(registration); EffRemoveStatModifier.register(registration); EffRide.register(registration); EffShoot.register(registration); diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/entity/EffPlayAnimation.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/entity/EffPlayAnimation.java new file mode 100644 index 00000000..4ef6f7b1 --- /dev/null +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/entity/EffPlayAnimation.java @@ -0,0 +1,84 @@ +package com.github.skriptdev.skript.plugin.elements.effects.entity; + +import com.github.skriptdev.skript.api.hytale.utils.EntityReferenceUtils; +import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.protocol.AnimationSlot; +import com.hypixel.hytale.server.core.entity.AnimationUtils; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import io.github.syst3ms.skriptparser.lang.Effect; +import io.github.syst3ms.skriptparser.lang.Expression; +import io.github.syst3ms.skriptparser.lang.TriggerContext; +import io.github.syst3ms.skriptparser.parsing.ParseContext; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public class EffPlayAnimation extends Effect { + + public static void register(SkriptRegistration reg) { + reg.newEffect(EffPlayAnimation.class, + "play animation %string% on %entities/refs%", + "play %animationslot% animation %string% on %entities/refs%") + .name("Play Animation") + .description("Plays an animation on the specified entity.", + "If the animation slot is not specified, the action slot will be used.") + // TODO add note about emotes when they're available in update 4 + .examples("play animation \"Death\" on player", + "play action animation \"Eat\" on target entity of player", + "play movement animation \"Jump\" on player") + .since("INSERT VERSION") + .register(); + } + + private Expression animation; + private Expression slot; + private Expression owners; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression @NotNull [] expressions, int matchedPattern, @NotNull ParseContext parseContext) { + if (matchedPattern == 0) { + this.animation = (Expression) expressions[0]; + this.owners = expressions[1]; + } else { + this.slot = (Expression) expressions[0]; + this.animation = (Expression) expressions[1]; + this.owners = expressions[2]; + } + return true; + } + + @Override + protected void execute(@NotNull TriggerContext ctx) { + String animation = this.animation.getSingle(ctx).orElse(null); + if (animation == null) return; + + AnimationSlot slot = AnimationSlot.Action; + if (this.slot != null) { + Optional single = this.slot.getSingle(ctx); + if (single.isPresent()) slot = single.get(); + } + + for (Object o : this.owners.getArray(ctx)) { + Ref ref = EntityReferenceUtils.getRef(o); + if (ref == null) continue; + + Store store = ref.getStore(); + + AnimationUtils.playAnimation(ref, slot, animation, true, store); + } + } + + @Override + public String toString(@NotNull TriggerContext ctx, boolean debug) { + if (this.slot != null) { + return "play animation " + this.animation.toString(ctx, debug) + + " in " + this.slot.toString(ctx, debug) + " slot on " + this.owners.toString(ctx, debug); + } + return "play animation " + this.animation.toString(ctx, debug) + + " on " + this.owners.toString(ctx, debug); + } + +} diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/inventory/EvtItemStackSlotTransaction.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/inventory/EvtItemStackSlotTransaction.java index 1e26a281..0337ee65 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/inventory/EvtItemStackSlotTransaction.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/inventory/EvtItemStackSlotTransaction.java @@ -17,7 +17,7 @@ public class EvtItemStackSlotTransaction extends SkriptEvent { public static void register(SkriptRegistration reg) { reg.newEvent(EvtItemStackSlotTransaction.class, "inventory item[stack] slot transaction") - .name("Inventory Item Slot Transaction") + .name("Inventory ItemStack Slot Transaction") .description("Called when there is an inventory transaction involving an ItemStack in a slot.") .since("1.3.0") .setHandledContexts(ItemStackSlotContext.class) diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/inventory/EvtSlotTransaction.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/inventory/EvtSlotTransaction.java index cfd36c8e..e637002c 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/inventory/EvtSlotTransaction.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/inventory/EvtSlotTransaction.java @@ -14,8 +14,8 @@ public class EvtSlotTransaction extends SkriptEvent { public static void register(SkriptRegistration reg) { reg.newEvent(EvtSlotTransaction.class, - "inventory item[stack] slot transaction") - .name("Inventory Item Slot Transaction") + "inventory slot transaction") + .name("Inventory Slot Transaction") .description("Called when there is an inventory transaction involving a slot.") .since("1.3.0") .setHandledContexts(SlotTransactionContext.class) diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/skript/EvtLoad.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/skript/EvtLoad.java index f08a9955..d79f3fbb 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/skript/EvtLoad.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/skript/EvtLoad.java @@ -1,13 +1,14 @@ package com.github.skriptdev.skript.plugin.elements.events.skript; import io.github.syst3ms.skriptparser.lang.Expression; +import io.github.syst3ms.skriptparser.lang.Statement; import io.github.syst3ms.skriptparser.lang.Trigger; import io.github.syst3ms.skriptparser.lang.TriggerContext; -import io.github.syst3ms.skriptparser.lang.TriggerMap; import io.github.syst3ms.skriptparser.lang.event.SkriptEvent; import io.github.syst3ms.skriptparser.lang.event.StartOnLoadEvent; import io.github.syst3ms.skriptparser.parsing.ParseContext; import io.github.syst3ms.skriptparser.registration.SkriptRegistration; +import io.github.syst3ms.skriptparser.variables.Variables; import org.jetbrains.annotations.Nullable; public class EvtLoad extends SkriptEvent implements StartOnLoadEvent { @@ -38,7 +39,9 @@ public String toString(@Nullable TriggerContext ctx, boolean debug) { @Override public void onInitialLoad(Trigger trigger) { - TriggerMap.callTriggersByContext(new ScriptLoadContext()); + ScriptLoadContext scriptLoadContext = new ScriptLoadContext(); + Statement.runAll(trigger, scriptLoadContext); + Variables.clearLocalVariables(scriptLoadContext); } private static class ScriptLoadContext implements TriggerContext { diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/skript/EvtPeriodical.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/skript/EvtPeriodical.java index 30096ad8..9b884d98 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/skript/EvtPeriodical.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/skript/EvtPeriodical.java @@ -7,14 +7,15 @@ import com.hypixel.hytale.server.core.universe.world.World; import io.github.syst3ms.skriptparser.lang.Expression; import io.github.syst3ms.skriptparser.lang.Literal; +import io.github.syst3ms.skriptparser.lang.Statement; import io.github.syst3ms.skriptparser.lang.Trigger; import io.github.syst3ms.skriptparser.lang.TriggerContext; -import io.github.syst3ms.skriptparser.lang.TriggerMap; import io.github.syst3ms.skriptparser.lang.VariableString; import io.github.syst3ms.skriptparser.lang.event.SkriptEvent; import io.github.syst3ms.skriptparser.lang.event.StartOnLoadEvent; import io.github.syst3ms.skriptparser.log.ErrorType; import io.github.syst3ms.skriptparser.parsing.ParseContext; +import io.github.syst3ms.skriptparser.variables.Variables; import java.time.Duration; import java.util.concurrent.ScheduledFuture; @@ -73,7 +74,11 @@ public void onInitialLoad(Trigger trigger) { Duration dur = this.duration.getSingle().orElseThrow(AssertionError::new); long durationMillis = dur.toMillis(); - Runnable runTrigger = () -> TriggerMap.callTriggersByContext(new PeriodicalContext(this.world)); + Runnable runTrigger = () -> { + PeriodicalContext periodicalContext = new PeriodicalContext(this.world); + Statement.runAll(trigger, periodicalContext); + Variables.clearLocalVariables(periodicalContext); + }; this.scheduledFuture = HytaleServer.SCHEDULED_EXECUTOR.scheduleAtFixedRate(() -> { if (this.world != null) { diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/world/EvtAtWorldTime.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/world/EvtAtWorldTime.java index 07af6ff4..fccab489 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/events/world/EvtAtWorldTime.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/events/world/EvtAtWorldTime.java @@ -10,15 +10,16 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import io.github.syst3ms.skriptparser.lang.Expression; import io.github.syst3ms.skriptparser.lang.Literal; +import io.github.syst3ms.skriptparser.lang.Statement; import io.github.syst3ms.skriptparser.lang.Trigger; import io.github.syst3ms.skriptparser.lang.TriggerContext; -import io.github.syst3ms.skriptparser.lang.TriggerMap; import io.github.syst3ms.skriptparser.lang.VariableString; import io.github.syst3ms.skriptparser.lang.event.SkriptEvent; import io.github.syst3ms.skriptparser.lang.event.StartOnLoadEvent; import io.github.syst3ms.skriptparser.log.ErrorType; import io.github.syst3ms.skriptparser.parsing.ParseContext; import io.github.syst3ms.skriptparser.util.Time; +import io.github.syst3ms.skriptparser.variables.Variables; import org.jetbrains.annotations.NotNull; import java.util.Optional; @@ -85,7 +86,9 @@ public void onInitialLoad(Trigger trigger) { // Check every in-world minute for a match if (time.getHour() != worldTime.getHour() || time.getMinute() != worldTime.getMinute()) return; - TriggerMap.callTriggersByContext(new WorldTimeContext(this.world)); + WorldTimeContext worldTimeContext = new WorldTimeContext(this.world); + Statement.runAll(trigger, worldTimeContext); + Variables.clearLocalVariables(worldTimeContext); }), 0, duration, TimeUnit.MILLISECONDS); } diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/ExpressionHandler.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/ExpressionHandler.java index daaca6d9..8a905ada 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/ExpressionHandler.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/ExpressionHandler.java @@ -15,8 +15,10 @@ import com.github.skriptdev.skript.plugin.elements.expressions.block.ExprTargetBlockOfPlayer; import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprActiveSlot; import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprEntitiesInRadius; +import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprEntityAnimations; import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprEntityAttitude; import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprEntityComponents; +import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprEntityFallDistance; import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprEntityHeadRotation; import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprEntityHealth; import com.github.skriptdev.skript.plugin.elements.expressions.entity.ExprEntityModel; @@ -117,8 +119,10 @@ public static void register(SkriptRegistration registration) { // ENTITY ExprActiveSlot.register(registration); ExprEntitiesInRadius.register(registration); + ExprEntityAnimations.register(registration); ExprEntityAttitude.register(registration); ExprEntityComponents.register(registration); + ExprEntityFallDistance.register(registration); ExprEntityHeadRotation.register(registration); ExprEntityHealth.register(registration); ExprEntityModel.register(registration); diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityAnimations.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityAnimations.java new file mode 100644 index 00000000..f395b2bb --- /dev/null +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityAnimations.java @@ -0,0 +1,68 @@ +package com.github.skriptdev.skript.plugin.elements.expressions.entity; + +import com.github.skriptdev.skript.api.hytale.utils.EntityReferenceUtils; +import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.server.core.asset.type.model.config.Model; +import com.hypixel.hytale.server.core.asset.type.model.config.ModelAsset; +import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import io.github.syst3ms.skriptparser.lang.Expression; +import io.github.syst3ms.skriptparser.lang.TriggerContext; +import io.github.syst3ms.skriptparser.parsing.ParseContext; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class ExprEntityAnimations implements Expression { + + public static void register(SkriptRegistration reg) { + reg.newExpression(ExprEntityAnimations.class, String.class, + false, "animations of %entities/refs/modelassets%") + .name("Entity Animations") + .description("Get the animations of an Entity/Ref.", + "If using Entity/Ref this will return the possible animations of their current model component.") + .since("INSERT VERSION") + .register(); + } + + private Expression owners; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, @NotNull ParseContext parseContext) { + this.owners = expressions[0]; + return true; + } + + @Override + public String[] getValues(@NotNull TriggerContext ctx) { + List animations = new ArrayList<>(); + for (Object owner : this.owners.getArray(ctx)) { + if (owner instanceof ModelAsset modelAsset) { + Model model = Model.createRandomScaleModel(modelAsset); + animations.addAll(model.getAnimationSetMap().keySet()); + } else { + Ref ref = EntityReferenceUtils.getRef(owner); + if (ref == null) { + return null; + } else { + Store store = ref.getStore(); + ModelComponent component = store.getComponent(ref, ModelComponent.getComponentType()); + if (component == null) return null; + + animations.addAll(component.getModel().getAnimationSetMap().keySet()); + } + } + } + + return animations.stream().sorted().toArray(String[]::new); + } + + @Override + public String toString(@NotNull TriggerContext ctx, boolean debug) { + return "animations of " + this.owners.toString(ctx, debug); + } + +} diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityFallDistance.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityFallDistance.java new file mode 100644 index 00000000..ad649c69 --- /dev/null +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityFallDistance.java @@ -0,0 +1,61 @@ +package com.github.skriptdev.skript.plugin.elements.expressions.entity; + +import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; +import com.hypixel.hytale.server.core.entity.LivingEntity; +import io.github.syst3ms.skriptparser.lang.TriggerContext; +import io.github.syst3ms.skriptparser.lang.properties.PropertyExpression; +import io.github.syst3ms.skriptparser.types.changers.ChangeMode; +import io.github.syst3ms.skriptparser.util.CollectionUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class ExprEntityFallDistance extends PropertyExpression { + + public static void register(SkriptRegistration reg) { + reg.newPropertyExpression(ExprEntityFallDistance.class, Number.class, + "fall distance", "livingentities") + .name("Entity Fall Distance") + .description("Get/set the fall distance of an entity.") + .examples("if fall distance of player > 10:", + "set fall distance of player to 10", + "add 1 to fall distance of player", + "remove 10 from fall distance of {_e}", + "clear fall distance of player") + .register(); + } + + @Override + public @Nullable Number getProperty(LivingEntity owner) { + return owner.getCurrentFallDistance(); + } + + @Override + public Optional[]> acceptsChange(@NotNull ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.ADD || mode == ChangeMode.REMOVE || mode == ChangeMode.DELETE) { + return CollectionUtils.optionalArrayOf(Number.class); + } + return Optional.empty(); + } + + @SuppressWarnings("ConstantValue") + @Override + public void change(@NotNull TriggerContext ctx, @NotNull ChangeMode changeMode, Object @NotNull [] changeWith) { + double changeValue = 0; + if (changeWith != null && changeWith.length > 0 && changeWith[0] instanceof Number num) { + changeValue = num.doubleValue(); + } + + for (LivingEntity livingEntity : getOwner().getArray(ctx)) { + double current = livingEntity.getCurrentFallDistance(); + + double newValue = switch (changeMode) { + case ADD -> current + changeValue; + case REMOVE -> current - changeValue; + default -> changeValue; + }; + livingEntity.setCurrentFallDistance(Math.max(newValue, 0)); + } + } +} diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityScale.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityScale.java index 38eacd1b..06a9b188 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityScale.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/entity/ExprEntityScale.java @@ -2,8 +2,10 @@ import com.github.skriptdev.skript.api.hytale.utils.EntityUtils; import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; +import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.server.core.entity.Entity; import com.hypixel.hytale.server.core.modules.entity.component.EntityScaleComponent; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import io.github.syst3ms.skriptparser.lang.TriggerContext; import io.github.syst3ms.skriptparser.lang.properties.PropertyExpression; import io.github.syst3ms.skriptparser.types.changers.ChangeMode; @@ -12,13 +14,13 @@ import java.util.Optional; -public class ExprEntityScale extends PropertyExpression { +public class ExprEntityScale extends PropertyExpression { public static void register(SkriptRegistration reg) { reg.newPropertyExpression(ExprEntityScale.class, Number.class, - "scale", "entities") + "scale", "entities/refs") .name("Entity Scale") - .description("Get/set the scale of an entity.", + .description("Get/set the scale of an Entity/Ref.", "**Note**: Changing the scale of a player does not affect their camera.") .examples("if scale of target entity of player > 1:", "set scale of {_e} to 10", @@ -29,11 +31,20 @@ public static void register(SkriptRegistration reg) { .register(); } + @SuppressWarnings("unchecked") @Override - public @Nullable Number getProperty(@NotNull Entity entity) { - EntityScaleComponent component = EntityUtils.getComponent(entity, EntityScaleComponent.getComponentType()); - if (component == null) return 1.0f; + public @Nullable Number getProperty(@NotNull Object o) { + EntityScaleComponent component; + if (o instanceof Entity entity) { + component = EntityUtils.getComponent(entity, EntityScaleComponent.getComponentType()); + } else if (o instanceof Ref r) { + Ref ref = (Ref) r; + component = ref.getStore().getComponent(ref, EntityScaleComponent.getComponentType()); + } else { + return null; + } + if (component == null) return 1.0f; return component.getScale(); } @@ -45,15 +56,23 @@ public Optional[]> acceptsChange(@NotNull ChangeMode mode) { return Optional.empty(); } - @SuppressWarnings("ConstantValue") + @SuppressWarnings({"ConstantValue", "unchecked"}) @Override public void change(@NotNull TriggerContext ctx, @NotNull ChangeMode changeMode, Object @NotNull [] changeWith) { if (changeWith == null || changeWith.length == 0 || !(changeWith[0] instanceof Number number)) { return; } - for (Entity entity : getOwner().getArray(ctx)) { - EntityScaleComponent component = EntityUtils.ensureAndGetComponent(entity, EntityScaleComponent.getComponentType()); + for (Object o : getOwner().getArray(ctx)) { + EntityScaleComponent component; + if (o instanceof Entity entity) { + component = EntityUtils.ensureAndGetComponent(entity, EntityScaleComponent.getComponentType()); + } else if (o instanceof Ref r) { + Ref ref = (Ref) r; + component = ref.getStore().ensureAndGetComponent(ref, EntityScaleComponent.getComponentType()); + } else { + continue; + } float oldValue = component.getScale(); float changeValue = number.floatValue(); diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/other/ExprCast.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/other/ExprCast.java index aaf6b9eb..4d83be39 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/other/ExprCast.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/other/ExprCast.java @@ -5,6 +5,7 @@ import io.github.syst3ms.skriptparser.lang.Literal; import io.github.syst3ms.skriptparser.lang.TriggerContext; import io.github.syst3ms.skriptparser.log.ErrorType; +import io.github.syst3ms.skriptparser.log.SkriptLogger; import io.github.syst3ms.skriptparser.parsing.ParseContext; import io.github.syst3ms.skriptparser.types.Type; import org.jetbrains.annotations.NotNull; @@ -27,33 +28,40 @@ public static void register(SkriptRegistration reg) { private String castable; private Type type; - private Function parser; + private Object parsedObject; @SuppressWarnings("unchecked") @Override public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { + SkriptLogger logger = parseContext.getLogger(); this.castable = parseContext.getMatches().getFirst().group(); Literal> expression = (Literal>) expressions[0]; this.type = expression.getSingle().orElse(null); if (this.type == null) { // This shouldn't happen, but let's be safe; - parseContext.getLogger().error("Type cannot be null for cast expression initialization.", ErrorType.SEMANTIC_ERROR); + logger.error("Type cannot be null for cast expression initialization.", ErrorType.SEMANTIC_ERROR); return false; } if (this.type.getLiteralParser().isEmpty()) { String baseName = this.type.getBaseName(); - parseContext.getLogger().error("The type '" + baseName + "' cannot be casted.", ErrorType.SEMANTIC_ERROR); + logger.error("The type '" + baseName + "' cannot be cast.", ErrorType.SEMANTIC_ERROR); + return false; + } + Function parser = this.type.getLiteralParser().get(); + // Let's parse at parse time so we don't have to worry about it during runtime + this.parsedObject = parser.apply(this.castable); + if (this.parsedObject == null) { + String baseName = this.type.getBaseName(); + logger.error("'" + this.castable + "' cannot be cast to " + baseName + ".", ErrorType.SEMANTIC_ERROR); return false; } - this.parser = this.type.getLiteralParser().get(); return true; } @Override public Object[] getValues(@NotNull TriggerContext ctx) { - Object apply = this.parser.apply(castable); - return new Object[]{apply}; + return new Object[]{this.parsedObject}; } @Override diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/world/ExprWorldTimeDurations.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/world/ExprWorldTimeDurations.java index b2409139..a060ec8d 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/world/ExprWorldTimeDurations.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/world/ExprWorldTimeDurations.java @@ -1,14 +1,19 @@ package com.github.skriptdev.skript.plugin.elements.expressions.world; import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; +import com.github.skriptdev.skript.api.utils.ReflectionUtils; import com.hypixel.hytale.server.core.universe.world.World; import io.github.syst3ms.skriptparser.lang.Expression; +import io.github.syst3ms.skriptparser.lang.TriggerContext; import io.github.syst3ms.skriptparser.lang.properties.PropertyExpression; import io.github.syst3ms.skriptparser.parsing.ParseContext; +import io.github.syst3ms.skriptparser.types.changers.ChangeMode; +import io.github.syst3ms.skriptparser.util.CollectionUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.time.Duration; +import java.util.Optional; public class ExprWorldTimeDurations extends PropertyExpression { @@ -18,8 +23,11 @@ public static void register(SkriptRegistration reg) { .name("World Time Durations") .description("Represents the daytime/nighttime durations of a world.", "These values are from a GamePlayConfig but can be overridden in your World config.", - "**Note**: Currently these cannot be set via code.") - .examples("set {_Day} to world daytime duration of world of player") + "Set/add/remove/reset will update your world config with these values.") + .examples("set {_Day} to world daytime duration of world of player", + "set world daytime duration of {_world} to 1 hour", + "add 10 minutes to world daytime duration of {_world}", + "reset world daytime duration of {_world}") .since("1.1.0") .register(); } @@ -43,4 +51,53 @@ public boolean init(Expression @NotNull [] expressions, int matchedPattern, P return Duration.ofSeconds(seconds); } + @Override + public Optional[]> acceptsChange(ChangeMode mode) { + return switch (mode) { + case ADD, REMOVE, SET, RESET -> { + if (this.pattern == 2) { + // LOG + yield Optional.empty(); + } + yield CollectionUtils.optionalArrayOf(Duration.class); + } + default -> Optional.empty(); + }; + } + + @SuppressWarnings("ConstantValue") + @Override + public void change(@NotNull TriggerContext ctx, @NotNull ChangeMode changeMode, Object @NotNull [] changeWith) { + Duration duration = null; + if (changeWith != null && changeWith.length > 0 && changeWith[0] instanceof Duration d) { + duration = d; + } + + int durationSeconds; + if (duration == null) { + durationSeconds = 0; + } else { + durationSeconds = (int) duration.toMillis() / 1000; + } + + boolean daytime = this.pattern == 0; + for (World world : getOwner().getArray(ctx)) { + int previons; + if (daytime) { + previons = world.getDaytimeDurationSeconds(); + } else { + previons = world.getNighttimeDurationSeconds(); + } + + Integer seconds = switch (changeMode) { + case ADD -> previons + durationSeconds; + case REMOVE -> previons - durationSeconds; + case SET -> durationSeconds; + default -> null; + }; + + ReflectionUtils.setWorldTimeOverrides(world, seconds, daytime); + } + } + } diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/sections/SectionHandler.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/sections/SectionHandler.java index 53faa6fc..df008312 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/sections/SectionHandler.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/sections/SectionHandler.java @@ -3,6 +3,7 @@ import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; import com.github.skriptdev.skript.plugin.elements.sections.entity.SecApplyStatModifier; import com.github.skriptdev.skript.plugin.elements.sections.entity.SecDropItem; +import com.github.skriptdev.skript.plugin.elements.sections.entity.SecSpawnDisplay; import com.github.skriptdev.skript.plugin.elements.sections.entity.SecSpawnNPC; import com.github.skriptdev.skript.plugin.elements.sections.player.SecPlaySound; import com.github.skriptdev.skript.plugin.elements.sections.player.SecSendNotification; @@ -18,6 +19,7 @@ public static void register(SkriptRegistration registration) { // ENTITY SecApplyStatModifier.register(registration); SecDropItem.register(registration); + SecSpawnDisplay.register(registration); SecSpawnNPC.register(registration); // PLAYER diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/sections/entity/SecSpawnDisplay.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/sections/entity/SecSpawnDisplay.java new file mode 100644 index 00000000..35191149 --- /dev/null +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/sections/entity/SecSpawnDisplay.java @@ -0,0 +1,106 @@ +package com.github.skriptdev.skript.plugin.elements.sections.entity; + +import com.github.skriptdev.skript.api.hytale.utils.EntityUtils; +import com.github.skriptdev.skript.api.skript.event.RefContext; +import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.math.vector.Location; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import io.github.syst3ms.skriptparser.lang.CodeSection; +import io.github.syst3ms.skriptparser.lang.Expression; +import io.github.syst3ms.skriptparser.lang.Statement; +import io.github.syst3ms.skriptparser.lang.TriggerContext; +import io.github.syst3ms.skriptparser.parsing.ParseContext; +import io.github.syst3ms.skriptparser.parsing.ParserState; +import io.github.syst3ms.skriptparser.variables.Variables; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; + +public class SecSpawnDisplay extends CodeSection { + + public static void register(SkriptRegistration reg) { + reg.newSection(SecSpawnDisplay.class, + "spawn display item %item% at %location%", + "spawn display block %blocktype% at %location%", + "spawn display model %modelasset% at %location%") + .name("Spawn Display") + .description("Spawn an item at a location.") + .examples("spawn display item ingredient_poop at {_loc}:", + "\tset {_e} to event-ref", + "\tset scale of {_e} to 10") + .since("INSERT VERSION") + .register(); + } + + int pattern; + private Expression model; + private Expression location; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, @NotNull ParseContext parseContext) { + this.pattern = matchedPattern; + this.model = expressions[0]; + this.location = (Expression) expressions[1]; + + ParserState parserState = parseContext.getParserState(); + List> triggerContexts = new ArrayList<>(parserState.getCurrentContexts().stream().toList()); + triggerContexts.add(ModelContext.class); + parserState.setCurrentContexts(new HashSet<>(triggerContexts)); + + return true; + } + + @Override + public Optional walk(@NotNull TriggerContext ctx) { + Optional nextStatement = getNext(); + + Object o = this.model.getSingle(ctx).orElse(null); + Location location = this.location.getSingle(ctx).orElse(null); + if (o == null || location == null) return nextStatement; + + Ref ref = EntityUtils.spawnModel(o, location); + Optional first = getFirst(); + + if (ref != null && first.isPresent()) { + ModelContext modelContext = new ModelContext(ref); + Variables.copyLocalVariables(ctx, modelContext); + Statement.runAll(first.get(), modelContext); + Variables.copyLocalVariables(modelContext, ctx); + Variables.clearLocalVariables(modelContext); + } + return nextStatement; + } + + @Override + public String toString(@NotNull TriggerContext ctx, boolean debug) { + String type = switch (this.pattern) { + case 1 -> "block"; + case 2 -> "model"; + default -> "item"; + }; + return "spawn display " + type + " " + this.model.toString(ctx, debug) + " at " + this.location.toString(ctx, debug); + } + + public static class ModelContext implements RefContext { + private final Ref ref; + + public ModelContext(Ref ref) { + this.ref = ref; + } + + public Ref getRef() { + return this.ref; + } + + @Override + public String getName() { + return "model context"; + } + } + +} diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/types/TypesEntity.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/types/TypesEntity.java index bce3364d..785593ed 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/types/TypesEntity.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/types/TypesEntity.java @@ -5,6 +5,7 @@ import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.RemoveReason; +import com.hypixel.hytale.protocol.AnimationSlot; import com.hypixel.hytale.server.core.asset.type.attitude.Attitude; import com.hypixel.hytale.server.core.entity.Entity; import com.hypixel.hytale.server.core.entity.LivingEntity; @@ -57,6 +58,11 @@ static void register(SkriptRegistration reg) { .since("1.0.0") .toStringFunction(ActiveEntityEffect::toString) .register(); + reg.newEnumType(AnimationSlot.class, "animationslot", "animationSlot@s") + .name("Animation Slot") + .description("Represents the slot for an animation to be played on an entity.") + .since("INSERT VERSION") + .register(); reg.newEnumType(Attitude.class, "attitude", "attitude@s") .name("Attitude") .description("Represents the attitude of an NPC Entity towards another entity.") @@ -89,7 +95,6 @@ static void register(SkriptRegistration reg) { reg.newType(NPCRegistry.NPCRole.class, "npcrole", "npcrole@s") .name("NPC Role") .description("Represents the type of NPCs in the game.") - .examples("coming soon") // TODO .usage(NPCRegistry.getTypeUsage()) .since("1.0.0") .toStringFunction(NPCRegistry.NPCRole::name) diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/types/TypesWorld.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/types/TypesWorld.java index 8f7357d8..d101fd17 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/types/TypesWorld.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/types/TypesWorld.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.protocol.SoundCategory; import com.hypixel.hytale.server.core.command.system.arguments.types.RelativeDoublePosition; import com.hypixel.hytale.server.core.command.system.arguments.types.RelativeIntPosition; +import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.worldgen.zone.Zone; @@ -50,6 +51,10 @@ public Class[] acceptsChange(@NotNull ChangeMode mode) { public void change(Ref @NotNull [] toChange, Object @NotNull [] changeWith, @NotNull ChangeMode mode) { for (Ref ref : toChange) { Store store = ref.getStore(); + if (store.getComponent(ref, Player.getComponentType()) != null) { + // Don't allow deleting players + continue; + } store.removeEntity(ref, RemoveReason.REMOVE); } }