diff --git a/Scenamatica/NMSBridge/NMSTypes/src/main/java/org/kunlab/scenamatica/nms/types/world/NMSWorldServer.java b/Scenamatica/NMSBridge/NMSTypes/src/main/java/org/kunlab/scenamatica/nms/types/world/NMSWorldServer.java index 02444027f..91af78aea 100644 --- a/Scenamatica/NMSBridge/NMSTypes/src/main/java/org/kunlab/scenamatica/nms/types/world/NMSWorldServer.java +++ b/Scenamatica/NMSBridge/NMSTypes/src/main/java/org/kunlab/scenamatica/nms/types/world/NMSWorldServer.java @@ -1,6 +1,7 @@ package org.kunlab.scenamatica.nms.types.world; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.NMSWrapped; @@ -38,4 +39,14 @@ public interface NMSWorldServer extends NMSWrapped @NotNull @Versioned(from = "1.17") NMSPersistentEntitySectionManager getEntityManager(); + + /** + * ブロックのアクションを再生します。 + * e.g. 音ブロックの再生 + * + * @param block ブロック + * @param param1 ブロック固有パラメータ1 + * @param param2 ブロック固有パラメータ2 + */ + void playBlockAction(Block block, int param1, int param2); } diff --git a/Scenamatica/NMSBridge/v1_13_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_13_R1/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_13_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_13_R1/world/NMSWorldServerImpl.java index 707fb691c..9d7b75d32 100644 --- a/Scenamatica/NMSBridge/v1_13_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_13_R1/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_13_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_13_R1/world/NMSWorldServerImpl.java @@ -1,7 +1,10 @@ package org.kunlab.scenamatica.nms.impl.v1_13_R1.world; +import net.minecraft.server.v1_13_R1.BlockPosition; import net.minecraft.server.v1_13_R1.WorldServer; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_13_R1.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.exceptions.UnsupportedNMSOperationException; @@ -58,4 +61,12 @@ public World getBukkit() NMSPersistentEntitySectionManager.class ); } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); + net.minecraft.server.v1_13_R1.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.playBlockAction(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/NMSBridge/v1_13_R2/src/main/java/org/kunlab/scenamatica/nms/impl/v1_13_R2/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_13_R2/src/main/java/org/kunlab/scenamatica/nms/impl/v1_13_R2/world/NMSWorldServerImpl.java index be6a4fcc6..0044418fc 100644 --- a/Scenamatica/NMSBridge/v1_13_R2/src/main/java/org/kunlab/scenamatica/nms/impl/v1_13_R2/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_13_R2/src/main/java/org/kunlab/scenamatica/nms/impl/v1_13_R2/world/NMSWorldServerImpl.java @@ -1,7 +1,10 @@ package org.kunlab.scenamatica.nms.impl.v1_13_R2.world; +import net.minecraft.server.v1_13_R2.BlockPosition; import net.minecraft.server.v1_13_R2.WorldServer; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_13_R2.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.exceptions.UnsupportedNMSOperationException; @@ -59,4 +62,12 @@ public NMSChunkProvider getChunkProvider() NMSPersistentEntitySectionManager.class ); } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); + net.minecraft.server.v1_13_R2.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.playBlockAction(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/NMSBridge/v1_14_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_14_R1/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_14_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_14_R1/world/NMSWorldServerImpl.java index 98ab0e1cf..0f57b9234 100644 --- a/Scenamatica/NMSBridge/v1_14_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_14_R1/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_14_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_14_R1/world/NMSWorldServerImpl.java @@ -1,7 +1,10 @@ package org.kunlab.scenamatica.nms.impl.v1_14_R1.world; +import net.minecraft.server.v1_14_R1.BlockPosition; import net.minecraft.server.v1_14_R1.WorldServer; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.exceptions.UnsupportedNMSOperationException; @@ -59,4 +62,12 @@ public NMSChunkProvider getChunkProvider() NMSPersistentEntitySectionManager.class ); } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); + net.minecraft.server.v1_14_R1.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.playBlockAction(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/NMSBridge/v1_15_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_15_R1/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_15_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_15_R1/world/NMSWorldServerImpl.java index 7546c30e4..57054e8ac 100644 --- a/Scenamatica/NMSBridge/v1_15_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_15_R1/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_15_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_15_R1/world/NMSWorldServerImpl.java @@ -1,7 +1,10 @@ package org.kunlab.scenamatica.nms.impl.v1_15_R1.world; +import net.minecraft.server.v1_15_R1.BlockPosition; import net.minecraft.server.v1_15_R1.WorldServer; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_15_R1.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.exceptions.UnsupportedNMSOperationException; @@ -58,4 +61,12 @@ public World getBukkit() NMSPersistentEntitySectionManager.class ); } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); + net.minecraft.server.v1_15_R1.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.playBlockAction(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/NMSBridge/v1_16_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R1/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_16_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R1/world/NMSWorldServerImpl.java index bb9b53c74..945f37791 100644 --- a/Scenamatica/NMSBridge/v1_16_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R1/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_16_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R1/world/NMSWorldServerImpl.java @@ -1,7 +1,10 @@ package org.kunlab.scenamatica.nms.impl.v1_16_R1.world; +import net.minecraft.server.v1_16_R1.BlockPosition; import net.minecraft.server.v1_16_R1.WorldServer; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_16_R1.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.exceptions.UnsupportedNMSOperationException; @@ -58,4 +61,12 @@ public World getBukkit() NMSPersistentEntitySectionManager.class ); } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); + net.minecraft.server.v1_16_R1.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.playBlockAction(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/NMSBridge/v1_16_R2/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R2/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_16_R2/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R2/world/NMSWorldServerImpl.java index 2f41793ab..dbc051757 100644 --- a/Scenamatica/NMSBridge/v1_16_R2/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R2/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_16_R2/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R2/world/NMSWorldServerImpl.java @@ -1,7 +1,10 @@ package org.kunlab.scenamatica.nms.impl.v1_16_R2.world; +import net.minecraft.server.v1_16_R2.BlockPosition; import net.minecraft.server.v1_16_R2.WorldServer; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_16_R2.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.exceptions.UnsupportedNMSOperationException; @@ -58,4 +61,12 @@ public World getBukkit() NMSPersistentEntitySectionManager.class ); } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); + net.minecraft.server.v1_16_R2.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.playBlockAction(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/NMSBridge/v1_16_R3/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R3/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_16_R3/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R3/world/NMSWorldServerImpl.java index a72696750..3d64709f2 100644 --- a/Scenamatica/NMSBridge/v1_16_R3/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R3/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_16_R3/src/main/java/org/kunlab/scenamatica/nms/impl/v1_16_R3/world/NMSWorldServerImpl.java @@ -1,7 +1,10 @@ package org.kunlab.scenamatica.nms.impl.v1_16_R3.world; +import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.exceptions.UnsupportedNMSOperationException; @@ -58,4 +61,12 @@ public World getBukkit() NMSPersistentEntitySectionManager.class ); } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); + net.minecraft.server.v1_16_R3.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.playBlockAction(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/NMSBridge/v1_17_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_17_R1/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_17_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_17_R1/world/NMSWorldServerImpl.java index c2ad6c508..81e27a495 100644 --- a/Scenamatica/NMSBridge/v1_17_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_17_R1/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_17_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_17_R1/world/NMSWorldServerImpl.java @@ -1,7 +1,10 @@ package org.kunlab.scenamatica.nms.impl.v1_17_R1.world; +import net.minecraft.core.BlockPosition; import net.minecraft.server.level.WorldServer; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.types.world.NMSChunkProvider; @@ -55,4 +58,12 @@ public World getBukkit() { return this.entityManager; } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); + net.minecraft.world.level.block.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.playBlockAction(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/NMSBridge/v1_18_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_18_R1/world/NMSWorldServerImpl.java b/Scenamatica/NMSBridge/v1_18_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_18_R1/world/NMSWorldServerImpl.java index 5086b7c7a..c624c787b 100644 --- a/Scenamatica/NMSBridge/v1_18_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_18_R1/world/NMSWorldServerImpl.java +++ b/Scenamatica/NMSBridge/v1_18_R1/src/main/java/org/kunlab/scenamatica/nms/impl/v1_18_R1/world/NMSWorldServerImpl.java @@ -1,8 +1,11 @@ package org.kunlab.scenamatica.nms.impl.v1_18_R1.world; +import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.kunlab.scenamatica.nms.types.world.NMSChunkProvider; @@ -56,4 +59,12 @@ public World getBukkit() { return this.entityManager; } + + @Override + public void playBlockAction(Block block, int param1, int param2) + { + BlockPos blockPosition = new BlockPos(block.getX(), block.getY(), block.getZ()); + net.minecraft.world.level.block.Block nmsBlock = CraftMagicNumbers.getBlock(block.getBlockData().getMaterial()); + this.nmsWorld.blockEvent(blockPosition, nmsBlock, param1, param2); + } } diff --git a/Scenamatica/ScenamaticaActionEngine/src/main/java/org/kunlab/scenamatica/action/input/SmartCaster.java b/Scenamatica/ScenamaticaActionEngine/src/main/java/org/kunlab/scenamatica/action/input/SmartCaster.java index 0f2de87a2..52a5367dd 100644 --- a/Scenamatica/ScenamaticaActionEngine/src/main/java/org/kunlab/scenamatica/action/input/SmartCaster.java +++ b/Scenamatica/ScenamaticaActionEngine/src/main/java/org/kunlab/scenamatica/action/input/SmartCaster.java @@ -5,8 +5,11 @@ import org.kunlab.scenamatica.enums.YAMLNodeType; import org.kunlab.scenamatica.exceptions.scenariofile.InvalidScenarioFileException; import org.kunlab.scenamatica.exceptions.scenariofile.YamlParsingException; +import org.kunlab.scenamatica.interfaces.action.ActionContext; import org.kunlab.scenamatica.interfaces.action.input.InputToken; import org.kunlab.scenamatica.interfaces.action.input.Traverser; +import org.kunlab.scenamatica.interfaces.action.types.Requireable; +import org.kunlab.scenamatica.interfaces.scenariofile.Structure; import org.kunlab.scenamatica.interfaces.scenariofile.StructureSerializer; import org.kunlab.scenamatica.interfaces.scenariofile.StructuredYamlNode; import org.kunlab.scenamatica.scenariofile.StructuredYamlNodeImpl; @@ -28,6 +31,12 @@ else if (clazz == Double.class || clazz == double.class) return clazz.cast(num.doubleValue()); else if (clazz == Float.class || clazz == float.class) return clazz.cast(num.floatValue()); + else if (clazz == Short.class || clazz == short.class) + return clazz.cast(num.shortValue()); + else if (clazz == Byte.class || clazz == byte.class) + return clazz.cast(num.byteValue()); + else if (clazz == Number.class) + return clazz.cast(num); else throw new IllegalArgumentException("Unknown number type: " + clazz); } @@ -151,16 +160,23 @@ else if (StructuredYamlNode.class.isAssignableFrom(toClass)) private static boolean canSmartCast(Class clazz, Object obj) { - boolean isStrNodeClass = StructuredYamlNode.class.isAssignableFrom(clazz); - - return obj == null - || clazz.isInstance(obj) - || clazz == String.class - || (Number.class.isAssignableFrom(clazz) && obj instanceof Number) - || ((isStrNodeClass || List.class.isAssignableFrom(clazz)) && obj instanceof List) - || ((isStrNodeClass || Map.class.isAssignableFrom(clazz)) && obj instanceof Map) - || (Boolean.class.isAssignableFrom(clazz) && obj instanceof Boolean) - || (obj instanceof StructuredYamlNode); + if (obj == null || clazz.isInstance(obj) || clazz == String.class + // Requireable のためのパッチ + || Requireable.class.isAssignableFrom(clazz) || ActionContext.class.isAssignableFrom(clazz)) + return true; + + return isMatchingType(Number.class, obj, YAMLNodeType.NUMBER) + || isMatchingType(Boolean.class, obj, YAMLNodeType.BOOLEAN) + || isMatchingType(List.class, obj, YAMLNodeType.LIST) + || ((Map.class.isAssignableFrom(clazz) || StructuredYamlNode.class.isAssignableFrom(clazz)) && + (obj instanceof Map || obj instanceof StructuredYamlNode && ((StructuredYamlNode) obj).isType(YAMLNodeType.MAPPING))) + || (Structure.class.isAssignableFrom(clazz) && obj instanceof StructuredYamlNode && ((StructuredYamlNode) obj).isType(YAMLNodeType.MAPPING)); + } + + private static boolean isMatchingType(Class clazz, Object obj, YAMLNodeType nodeType) + { + return clazz.isAssignableFrom(obj.getClass()) + || (obj instanceof StructuredYamlNode && ((StructuredYamlNode) obj).isType(nodeType)); } /* non-public */ diff --git a/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/java/org/kunlab/scenamatica/action/actions/base/block/BlockPlayNoteAction.java b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/java/org/kunlab/scenamatica/action/actions/base/block/BlockPlayNoteAction.java new file mode 100644 index 000000000..12ad0b504 --- /dev/null +++ b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/java/org/kunlab/scenamatica/action/actions/base/block/BlockPlayNoteAction.java @@ -0,0 +1,327 @@ +package org.kunlab.scenamatica.action.actions.base.block; + +import org.bukkit.Bukkit; +import org.bukkit.Instrument; +import org.bukkit.Note; +import org.bukkit.block.Block; +import org.bukkit.block.data.type.NoteBlock; +import org.bukkit.event.Event; +import org.bukkit.event.block.NotePlayEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.kunlab.scenamatica.annotations.action.Action; +import org.kunlab.scenamatica.bookkeeper.annotations.ActionDoc; +import org.kunlab.scenamatica.bookkeeper.annotations.Admonition; +import org.kunlab.scenamatica.bookkeeper.annotations.InputDoc; +import org.kunlab.scenamatica.bookkeeper.annotations.OutputDoc; +import org.kunlab.scenamatica.bookkeeper.annotations.TypeDoc; +import org.kunlab.scenamatica.bookkeeper.annotations.TypeProperty; +import org.kunlab.scenamatica.bookkeeper.enums.ActionMethod; +import org.kunlab.scenamatica.bookkeeper.enums.AdmonitionType; +import org.kunlab.scenamatica.enums.ScenarioType; +import org.kunlab.scenamatica.exceptions.scenario.IllegalActionInputException; +import org.kunlab.scenamatica.exceptions.scenariofile.YamlParsingException; +import org.kunlab.scenamatica.interfaces.action.ActionContext; +import org.kunlab.scenamatica.interfaces.action.input.InputBoard; +import org.kunlab.scenamatica.interfaces.action.input.InputToken; +import org.kunlab.scenamatica.interfaces.action.types.Executable; +import org.kunlab.scenamatica.interfaces.action.types.Expectable; +import org.kunlab.scenamatica.interfaces.scenariofile.Mapped; +import org.kunlab.scenamatica.interfaces.scenariofile.Structure; +import org.kunlab.scenamatica.interfaces.scenariofile.StructureSerializer; +import org.kunlab.scenamatica.interfaces.scenariofile.StructuredYamlNode; +import org.kunlab.scenamatica.nms.NMSProvider; +import org.kunlab.scenamatica.nms.types.world.NMSWorldServer; +import org.kunlab.scenamatica.structures.StructureMappers; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Action("block_play_note") +@ActionDoc( + name = "音ブロックの再生", + description = "音ブロックを指定した音で再生します。", + events = NotePlayEvent.class, + + executable = "指定された音ブロックを再生します。", + requireable = "音ブロックが再生されることを期待します。", + + outputs = { + @OutputDoc( + name = BlockPlayNoteAction.OUT_INSTRUMENT, + description = "再生された音の種類です。", + type = Instrument.class + ), + @OutputDoc( + name = BlockPlayNoteAction.OUT_NOTE, + description = "再生された音です。", + type = BlockPlayNoteAction.NoteInput.class + ) + } +) +public class BlockPlayNoteAction extends AbstractBlockAction + implements Executable, Expectable +{ + public static final String OUT_INSTRUMENT = "instrument"; + public static final String OUT_NOTE = "note"; + + @InputDoc( + name = "instrument", + description = "再生する音の種類です。", + type = Instrument.class, + + admonitions = { + @Admonition( + type = AdmonitionType.WARNING, + on = ActionMethod.EXECUTE, + content = "この入力を指定すると, 音の再生前に, 音ブロックの関連する属性を変更します。" + ) + } + ) + public static final InputToken IN_INSTRUMENT = ofEnumInput( + "instrument", + Instrument.class + ); + @InputDoc( + name = "note", + description = "再生する音の高さです。", + type = NoteInput.class, + + admonitions = { + @Admonition( + type = AdmonitionType.WARNING, + on = ActionMethod.EXECUTE, + content = "この入力を指定すると, 音の再生前に, 音ブロックの関連する属性を変更します。" + ) + } + ) + public static final InputToken IN_NOTE = ofInput( + "note", + NoteInput.class, + ofTraverser( + Number.class, + (ser, num) -> { + int value = num.intValue(); + return new NoteInput(value); + } + ), + ofTraverser( + StructuredYamlNode.class, + NoteInput::deserialize + ) + ); + + @Override + public void execute(@NotNull ActionContext ctxt) + { + Block block = super.getBlockLocationWithWorld(ctxt.input(IN_BLOCK), ctxt).getBlock(); + NoteBlock noteBlock = (NoteBlock) block.getBlockData(); + + Instrument instrument = noteBlock.getInstrument(); + Note note = noteBlock.getNote(); + if (ctxt.hasInput(IN_INSTRUMENT)) + noteBlock.setInstrument(instrument = ctxt.input(IN_INSTRUMENT)); + if (ctxt.hasInput(IN_NOTE)) + { + NoteInput noteInput = ctxt.input(IN_NOTE); + note = noteInput.getNote(); + noteBlock.setNote(note); + } + + block.setBlockData(noteBlock); + this.makeOutputs(ctxt, instrument, note); + + // 音を再生するメソッドはないので, イベントの発火 => 音の再生をシミュレートする。 + NotePlayEvent event = new NotePlayEvent(block, instrument, note); + Bukkit.getPluginManager().callEvent(event); + if (!event.isCancelled()) + this.simulateNoteBlockPlay(block, instrument, note); + } + + @SuppressWarnings("deprecation") + private void simulateNoteBlockPlay(Block block, Instrument instrument, Note note) + { + NMSWorldServer nmsWorld = NMSProvider.getProvider().wrap(block.getWorld()); + nmsWorld.playBlockAction(block, instrument.getType(), note.getId()); + } + + @Override + public boolean checkFired(@NotNull ActionContext ctxt, @NotNull Event event) + { + if (!super.checkMatchedBlockEvent(ctxt, event)) + return false; + + assert event instanceof NotePlayEvent; + NotePlayEvent notePlayEvent = (NotePlayEvent) event; + + Instrument inst = notePlayEvent.getInstrument(); + Note note = notePlayEvent.getNote(); + + boolean result = ctxt.ifHasInput(IN_INSTRUMENT, in -> in == inst) + && ctxt.ifHasInput(IN_NOTE, in -> in.isAdequate(note, false)); + if (result) + this.makeOutputs(ctxt, inst, note); + + return result; + } + + private void makeOutputs(@NotNull ActionContext ctxt, Instrument instrument, Note note) + { + ctxt.output(OUT_INSTRUMENT, instrument); + ctxt.output(OUT_NOTE, NoteInput.fromNote(note)); + } + + @Override + public List> getAttachingEvents() + { + return Collections.singletonList(NotePlayEvent.class); + } + + @Override + public InputBoard getInputBoard(@NotNull ScenarioType type) + { + return super.getInputBoard(type) + .registerAll(IN_INSTRUMENT, IN_NOTE); + } + + @TypeDoc( + name = "音", + description = "音の種類とピッチを指定します。", + mappingOf = Note.class, + properties = { + @TypeProperty( + name = NoteInput.TONE, + description = "C, D, E, F, G, A, B などの, 音名です。", + type = Note.Tone.class + ), + @TypeProperty( + name = NoteInput.OCTAVE, + description = "音のオクターブです。", + type = int.class, + defaultValue = "0", + min = 0, + max = 2 + ), + @TypeProperty( + name = NoteInput.SHARP, + description = "半音上がっているかどうかです。", + type = boolean.class, + defaultValue = "false" + ), + @TypeProperty( + name = NoteInput.FLAT, + description = "半音下がっているかどうかです。", + type = boolean.class, + defaultValue = "false" + ) + } + ) + public static class NoteInput implements Structure, Mapped + { + public static final String TONE = "tone"; + public static final String OCTAVE = "octave"; + public static final String SHARP = "sharp"; + public static final String FLAT = "flat"; + + private final int toneValue; + + private final Note.Tone tone; + private final int octave; + private final boolean sharp; + private final boolean flat; + + public NoteInput(Note.Tone tone, int octave, boolean sharp, boolean flat) + { + this.toneValue = -1; + this.tone = tone; + this.octave = octave; + if (sharp && flat) + this.sharp = this.flat = false; + else + { + this.sharp = sharp; + this.flat = flat; + } + } + + public NoteInput(int toneValue) + { + if (toneValue < 0 || toneValue > 24) + throw new IllegalActionInputException(BlockPlayNoteAction.IN_NOTE, "Tone value has to be between 0 and 24"); + this.toneValue = toneValue; + this.tone = null; + this.octave = 0; + this.sharp = false; + this.flat = false; + } + + public static NoteInput fromNote(Note note) + { + return new NoteInput(note.getTone(), note.getOctave(), note.isSharped(), false); + } + + public static NoteInput deserialize(StructureSerializer ser, StructuredYamlNode node) throws YamlParsingException + { + Note.Tone tone = node.get(TONE).getAs(StructureMappers.enumName(Note.Tone.class)); + int octave = node.get(OCTAVE).asInteger(0); + boolean sharp = node.get(SHARP).asBoolean(false); + boolean flat = node.get(FLAT).asBoolean(false); + + return new NoteInput(tone, octave, sharp, flat); + } + + public Note getNote() + { + if (this.toneValue != -1) + return new Note(this.toneValue); + assert this.tone != null; + + if (this.octave < 0 || this.octave > 2 || (this.octave == 2 && !(this.tone == Note.Tone.F && this.sharp))) + throw new IllegalActionInputException(BlockPlayNoteAction.IN_NOTE, "Tone and octave have to be between F#0 and F#2"); + + if (this.sharp) + return Note.sharp(this.octave, this.tone); + else if (this.flat) + return Note.flat(this.octave, this.tone); + else + return Note.natural(this.octave, this.tone); + } + + @Override + public void applyTo(@NotNull Note object) + { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("deprecation") + public boolean isAdequate(@Nullable Note object, boolean isStrict) + { + if (object == null) + return false; + byte thisNote = this.getNote().getId(); + byte thatNote = object.getId(); + + return thisNote == thatNote; + } + + @Override + public boolean canApplyTo(@Nullable Object target) + { + return target instanceof Note; + } + + public Map serialize() + { + Map map = new HashMap<>(); + Note note = this.getNote(); + map.put(TONE, note.getTone()); + map.put(OCTAVE, note.getOctave()); + map.put(SHARP, note.isSharped()); + map.put(FLAT, this.flat); + return map; + } + } +} diff --git a/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-2.yml b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-2.yml new file mode 100644 index 000000000..1a7334692 --- /dev/null +++ b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-2.yml @@ -0,0 +1,51 @@ +# noinspection YAMLSchemaValidation +scenamatica: ${project.version} + +name: actions_block_play_note_2 +description: Testing block_place action without note and instrument works or not +on: + - type: on_load + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + - type: manual_dispatch + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + +context: + stage: + type: flat + + +scenario: + - type: execute + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + - type: expect + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 diff --git a/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-3.yml b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-3.yml new file mode 100644 index 000000000..7cb65fad5 --- /dev/null +++ b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-3.yml @@ -0,0 +1,60 @@ +# noinspection YAMLSchemaValidation +scenamatica: ${project.version} + +name: actions_block_play_note_3 +description: Testing block_place action with note structure works or not +on: + - type: on_load + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + - type: manual_dispatch + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + +context: + stage: + type: flat + +scenario: + - type: execute + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + note: + tone: C + octave: 1 + sharp: true + instrument: PIANO + - type: expect + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + note: + tone: C + octave: 1 + sharp: true + instrument: PIANO diff --git a/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-4.yml b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-4.yml new file mode 100644 index 000000000..e317ee425 --- /dev/null +++ b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-4.yml @@ -0,0 +1,52 @@ +# noinspection YAMLSchemaValidation +scenamatica: ${project.version} + +name: actions_block_play_note_4 +description: Testing block_place action with different note works or not +on: + - type: on_load + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + - type: manual_dispatch + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + +context: + stage: + type: flat + +scenario: + - type: execute + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + instrument: FLUTE + - type: expect + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + instrument: FLUTE diff --git a/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-5.yml b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-5.yml new file mode 100644 index 000000000..f408bc7b0 --- /dev/null +++ b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote-5.yml @@ -0,0 +1,69 @@ +# noinspection YAMLSchemaValidation +scenamatica: ${project.version} + +name: actions_block_play_note_5 +description: Testing block_place action with pre-defined instrument works or not +on: + - type: on_load + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + - type: execute + action: block_place + with: + block: + location: + x: 0 + y: 3 + z: 0 + type: GOLD_BLOCK + - type: manual_dispatch + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + - type: execute + action: block_place + with: + block: + location: + x: 0 + y: 3 + z: 0 + type: GOLD_BLOCK + +context: + stage: + type: flat + +scenario: + - type: execute + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + - type: expect + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + instrument: BELL diff --git a/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote.yml b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote.yml new file mode 100644 index 000000000..dc6947679 --- /dev/null +++ b/Scenamatica/ScenamaticaActions/Base_v1_13_2/src/main/resources/scenarios/actions/block/PlayNote.yml @@ -0,0 +1,55 @@ +# noinspection YAMLSchemaValidation +scenamatica: ${project.version} + +name: actions_block_play_note +description: Testing block_place action works or not +on: + - type: on_load + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + - type: manual_dispatch + before: + - type: execute + action: block_place + with: + block: + type: NOTE_BLOCK + location: + x: 0 + y: 4 + z: 0 + +context: + stage: + type: flat + + +scenario: + - type: execute + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + note: 1 + instrument: PIANO + - type: expect + action: block_play_note + with: + block: + location: + x: 0 + y: 4 + z: 0 + note: 1 + instrument: PIANO