Skip to content

Commit

Permalink
feat(actions): Explode action
Browse files Browse the repository at this point in the history
# feat(actions): Explode action

## + Action: EX/EP `block_explode`

Burns specified block.

+ Category: `block`
+ Attaching events:
  - [`BlockExplodeEvent`](https://jd.papermc.io/paper/1.13/org/bukkit/event/block/BlockExplodeEvent.html)

### Differences via versions

#### 1.13.2: Base implemention
  • Loading branch information
PeyaPeyaPeyang authored Mar 9, 2025
2 parents 888680d + 0309cae commit 6e7fa39
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package org.kunlab.scenamatica.action.actions.base.block;

import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.block.BlockExplodeEvent;
import org.jetbrains.annotations.NotNull;
import org.kunlab.scenamatica.action.utils.InputTypeToken;
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.enums.ActionMethod;
import org.kunlab.scenamatica.bookkeeper.enums.AdmonitionType;
import org.kunlab.scenamatica.enums.ScenarioType;
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.structures.minecraft.misc.BlockStructure;

import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

@Action("block_explode")
@ActionDoc(
name = "ブロックの爆発",
description = "ブロックを爆発させます。",
events = BlockExplodeEvent.class,

executable = "ブロックを爆発させます。",
expectable = "ブロックが爆発するまで待機します。",
requireable = ActionDoc.UNALLOWED,

admonitions = {
@Admonition(
type = AdmonitionType.INFORMATION,
content = "このアクションは, TNT 等の起爆や, それの爆発についてのアクションではありません。\n " +
"これは, 何らかの理由で爆風が発生し, 周囲のブロックが破壊されることについてのアクションです。"
),
@Admonition(
type = AdmonitionType.INFORMATION,
content = "このアクションでは, TNT の爆発を検知・作成できません。\n " +
"それを行うためには, 代わりに `entity_explode` アクションを使用してください。"
)
}
)
public class BlockExplodeAction extends AbstractBlockAction
implements Executable, Expectable
{
@InputDoc(
name = "爆発の大きさ",
description = "爆発の大きさ(周囲のブロックに影響する範囲)を半径で指定します。",
type = float.class,
requiredOn = ActionMethod.EXECUTE,

admonitions = {
@Admonition(
type = AdmonitionType.TIP,
content = "ベッド爆発の大きさは `5.0f`, ウィザーの頭蓋骨爆発の大きさは `1.0f` です。"
)
}
)
public static final InputToken<Float> IN_YIELD = ofInput("yield", Float.class);

@InputDoc(
name = "周囲の着火",
description = "爆発によって周囲のブロックに火が付くかどうかを指定します。",
type = boolean.class,

availableFor = ActionMethod.EXECUTE
)
public static final InputToken<Boolean> IN_FIRE = ofInput("fire", Boolean.class);

@InputDoc(
name = "ブロックの破壊",
description = "爆発によって周囲のブロックが破壊されるかどうかを指定します。",
type = boolean.class,

availableFor = ActionMethod.EXECUTE,

admonitions = {
@Admonition(
type = AdmonitionType.INFORMATION,
content = "この値はデフォルトで `true` です。"
)
}
)
public static final InputToken<Boolean> IN_BREAK_BLOCKS = ofInput("breakBlocks", Boolean.class);

@InputDoc(
name = "影響を受けるブロック",
description = "爆発によって影響を受ける(破壊される)周囲のブロックの一覧を指定します。",
type = BlockStructure.class,

availableFor = ActionMethod.EXPECT
)
public static final InputToken<List<BlockStructure>> IN_BLOCKS = ofInput(
"blocks",
InputTypeToken.ofList(BlockStructure.class),
ofListDeserializer(ofDeserializer(BlockStructure.class))
);

private static boolean isBrokenBlocksMatches(@NotNull ActionContext ctxt, List<Block> blocks)
{
List<BlockStructure> blockDefs = ctxt.input(IN_BLOCKS);
Predicate<BlockStructure> blockDefPredicate = blockDef -> blocks.stream().anyMatch(blockDef::isAdequate);

return blockDefs.stream().allMatch(blockDefPredicate);
}

@Override
public void execute(@NotNull ActionContext ctxt)
{
BlockStructure blockDef = ctxt.input(IN_BLOCK);
Location location = this.getBlockLocationWithWorld(blockDef, ctxt);
Block block = location.getBlock();

Float yield = ctxt.input(IN_YIELD);

boolean setFire = ctxt.orElseInput(IN_FIRE, () -> false);
boolean breakBlocks = ctxt.orElseInput(IN_BREAK_BLOCKS, () -> true);

block.getWorld().createExplosion(location, yield, setFire, breakBlocks);
}

@Override
public boolean checkFired(@NotNull ActionContext ctxt, @NotNull Event event)
{
if (!super.checkMatchedBlockEvent(ctxt, event))
return false;

assert event instanceof BlockExplodeEvent;
BlockExplodeEvent explodeEvent = (BlockExplodeEvent) event;

return ctxt.ifHasInput(IN_YIELD, yield -> explodeEvent.getYield() == yield)
|| ctxt.ifHasInput(IN_BLOCKS, blocks -> isBrokenBlocksMatches(ctxt, explodeEvent.blockList()));
}

@Override
public InputBoard getInputBoard(@NotNull ScenarioType type)
{
InputBoard board = super.getInputBoard(type)
.register(IN_YIELD);

if (type == ScenarioType.ACTION_EXECUTE)
board.registerAll(IN_FIRE, IN_BREAK_BLOCKS)
.requirePresent(IN_YIELD);
else
board.register(IN_BLOCKS);

return board;
}

@Override
public List<Class<? extends Event>> getAttachingEvents()
{
return Collections.singletonList(BlockExplodeEvent.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# noinspection YAMLSchemaValidation
scenamatica: ${project.version}

name: actions_block_explode_2
description: Testing block_explode action with breaking blocks works or not
on:
- type: on_load
- type: manual_dispatch

context:
stage:
type: flat

scenario:
- type: execute
action: block_explode
with:
block:
location:
x: 0
y: 4
z: 0
yield: 50
breakBlocks: true
- type: expect
action: block_explode
with:
blocks:
- location:
x: 10
y: 3
z: 0
- location:
x: 0
y: 3
z: 10
- location:
x: 5
y: 3
z: -5
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# noinspection YAMLSchemaValidation
scenamatica: ${project.version}

name: actions_block_explode
description: Testing block_explode action works or not
on:
- type: on_load
- type: manual_dispatch

context:
stage:
type: flat

scenario:
- type: execute
action: block_explode
with:
block:
location:
x: 0
y: 4
z: 0
yield: 4
- type: expect
action: block_explode
with:
block:
location:
x: 0
y: 4
z: 0

0 comments on commit 6e7fa39

Please sign in to comment.