Skip to content

Commit

Permalink
schematic entities
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmonkey4eva committed Apr 23, 2021
1 parent 8264a6b commit 502a231
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public class SchematicCommand extends AbstractCommand implements Holdable, Liste

public SchematicCommand() {
setName("schematic");
setSyntax("schematic [create/load/unload/rotate (angle:<#>)/paste (fake_to:<player>|... fake_duration:<duration>)/save/flip_x/flip_y/flip_z) (noair) (mask:<material>|...)] [name:<name>] (filename:<name>) (<location>) (<cuboid>) (delayed) (max_delay_ms:<#>)");
setRequiredArguments(2, 11);
setSyntax("schematic [create/load/unload/rotate (angle:<#>)/paste (fake_to:<player>|... fake_duration:<duration>)/save/flip_x/flip_y/flip_z) (noair) (mask:<material>|...)] [name:<name>] (filename:<name>) (<location>) (<cuboid>) (delayed) (max_delay_ms:<#>) (entities)");
setRequiredArguments(2, 12);
TagManager.registerTagHandler(new TagRunnable.RootForm() {
@Override
public void run(ReplaceableTagEvent event) {
Expand All @@ -56,10 +56,10 @@ public void run(ReplaceableTagEvent event) {

// <--[command]
// @Name Schematic
// @Syntax schematic [create/load/unload/rotate (angle:<#>)/paste (fake_to:<player>|... fake_duration:<duration>)/save/flip_x/flip_y/flip_z) (noair) (mask:<material>|...)] [name:<name>] (filename:<name>) (<location>) (<cuboid>) (delayed) (max_delay_ms:<#>)
// @Syntax schematic [create/load/unload/rotate (angle:<#>)/paste (fake_to:<player>|... fake_duration:<duration>)/save/flip_x/flip_y/flip_z) (noair) (mask:<material>|...)] [name:<name>] (filename:<name>) (<location>) (<cuboid>) (delayed) (max_delay_ms:<#>) (entities)
// @Group world
// @Required 2
// @Maximum 11
// @Maximum 12
// @Short Creates, loads, pastes, and saves schematics (Sets of blocks).
//
// @Description
Expand Down Expand Up @@ -94,6 +94,9 @@ public void run(ReplaceableTagEvent event) {
// block set, instead of actually modifying the blocks in the world.
// This takes an optional duration as "fake_duration" for how long the fake blocks should remain.
//
// The "create" and "paste" options allow the "entities" argument to be specified - when used, entities will be copied or pasted.
// At current time, entity types included will be: Paintings, ItemFrames.
//
// The schematic command is ~waitable as an alternative to 'delayed' argument. Refer to <@link language ~waitable>.
//
// @Tags
Expand Down Expand Up @@ -183,6 +186,10 @@ else if (!scriptEntry.hasObject("noair")
&& arg.matches("noair")) {
scriptEntry.addObject("noair", new ElementTag("true"));
}
else if (!scriptEntry.hasObject("entities")
&& arg.matches("entities")) {
scriptEntry.addObject("entities", new ElementTag("true"));
}
else if (!scriptEntry.hasObject("mask")
&& arg.matchesPrefix("mask")
&& arg.matchesArgumentList(MaterialTag.class)) {
Expand All @@ -200,7 +207,7 @@ else if (!scriptEntry.hasObject("fake_duration")
}
else if (!scriptEntry.hasObject("location")
&& arg.matchesArgumentType(LocationTag.class)) {
scriptEntry.addObject("location", arg.asType(LocationTag.class));
scriptEntry.addObject("location", arg.asType(LocationTag.class).getBlockLocation());
}
else if (!scriptEntry.hasObject("cuboid")
&& arg.matchesArgumentType(CuboidTag.class)) {
Expand Down Expand Up @@ -231,23 +238,15 @@ public void execute(final ScriptEntry scriptEntry) {
ElementTag noair = scriptEntry.getElement("noair");
ElementTag delayed = scriptEntry.getElement("delayed");
ElementTag maxDelayMs = scriptEntry.getElement("max_delay_ms");
ElementTag copyEntities = scriptEntry.getElement("entities");
LocationTag location = scriptEntry.getObjectTag("location");
List<MaterialTag> mask = (List<MaterialTag>) scriptEntry.getObject("mask");
List<PlayerTag> fakeTo = (List<PlayerTag>) scriptEntry.getObject("fake_to");
DurationTag fakeDuration = scriptEntry.getObjectTag("fake_duration");
CuboidTag cuboid = scriptEntry.getObjectTag("cuboid");
if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, getName(), type.debug()
+ name.debug()
+ (location != null ? location.debug() : "")
+ (filename != null ? filename.debug() : "")
+ (cuboid != null ? cuboid.debug() : "")
+ (angle != null ? angle.debug() : "")
+ (noair != null ? noair.debug() : "")
+ (delayed != null ? delayed.debug() + maxDelayMs.debug() : "")
+ (mask != null ? ArgumentHelper.debugList("mask", mask) : "")
+ (fakeTo != null ? ArgumentHelper.debugList("fake_to", fakeTo) : "")
+ (fakeDuration != null ? fakeDuration.debug() : ""));
Debug.report(scriptEntry, getName(), type, name, location, filename, cuboid, angle, noair, delayed, maxDelayMs, fakeDuration,
(mask != null ? ArgumentHelper.debugList("mask", mask) : ""), (fakeTo != null ? ArgumentHelper.debugList("fake_to", fakeTo) : ""));
}
CuboidBlockSet set;
Type ttype = Type.valueOf(type.asString());
Expand All @@ -273,13 +272,19 @@ public void execute(final ScriptEntry scriptEntry) {
if (delayed != null && delayed.asBoolean()) {
set = new CuboidBlockSet();
set.buildDelayed(cuboid, location, () -> {
if (copyEntities != null && copyEntities.asBoolean()) {
set.buildEntities(cuboid, location);
}
schematics.put(name.asString().toUpperCase(), set);
scriptEntry.setFinished(true);
}, maxDelayMs.asLong());
}
else {
scriptEntry.setFinished(true);
set = new CuboidBlockSet(cuboid, location);
if (copyEntities != null && copyEntities.asBoolean()) {
set.buildEntities(cuboid, location);
}
schematics.put(name.asString().toUpperCase(), set);
}
}
Expand Down Expand Up @@ -445,6 +450,11 @@ public void execute(final ScriptEntry scriptEntry) {
input.centerLocation = location;
input.noAir = noair != null && noair.asBoolean();
input.fakeTo = fakeTo;
if (fakeTo != null && copyEntities != null && copyEntities.asBoolean()) {
Debug.echoError(scriptEntry.getResidingQueue(), "Cannot fake paste entities currently.");
scriptEntry.setFinished(true);
return;
}
if (fakeDuration == null) {
fakeDuration = new DurationTag(0);
}
Expand All @@ -455,12 +465,21 @@ public void execute(final ScriptEntry scriptEntry) {
input.mask.add(material.getMaterial());
}
}
set = schematics.get(name.asString().toUpperCase());
if (delayed != null && delayed.asBoolean()) {
schematics.get(name.asString().toUpperCase()).setBlocksDelayed(() -> scriptEntry.setFinished(true), input, maxDelayMs.asLong());
set.setBlocksDelayed(() -> {
if (copyEntities != null && copyEntities.asBoolean()) {
set.pasteEntities(location);
}
scriptEntry.setFinished(true);
}, input, maxDelayMs.asLong());
}
else {
set.setBlocks(input);
if (copyEntities != null && copyEntities.asBoolean()) {
set.pasteEntities(location);
}
scriptEntry.setFinished(true);
schematics.get(name.asString().toUpperCase()).setBlocks(input);
}
}
catch (Exception ex) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package com.denizenscript.denizen.utilities.blocks;

import com.denizenscript.denizen.Denizen;
import com.denizenscript.denizen.objects.CuboidTag;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizen.objects.MaterialTag;
import com.denizenscript.denizen.objects.*;
import com.denizenscript.denizen.scripts.commands.world.SchematicCommand;
import com.denizenscript.denizencore.objects.Mechanism;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.objects.core.MapTag;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Painting;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;

import java.util.ArrayList;

public class CuboidBlockSet implements BlockSet {

Expand Down Expand Up @@ -85,6 +95,8 @@ public void run() {

public int center_z;

public ListTag entities = null;

@Override
public FullBlockData[] getBlocks() {
return blocks;
Expand All @@ -96,6 +108,97 @@ public CuboidTag getCuboid(Location loc) {
return new CuboidTag(low, high);
}

public static BlockFace rotateFaceOneBackwards(BlockFace face) {
switch (face) {
case NORTH:
return BlockFace.EAST;
case EAST:
return BlockFace.SOUTH;
case SOUTH:
return BlockFace.WEST;
case WEST:
return BlockFace.NORTH;
default:
return BlockFace.SELF;
}
}

public static BlockFace rotateFaceOne(BlockFace face) {
switch (face) {
case NORTH:
return BlockFace.WEST;
case EAST:
return BlockFace.NORTH;
case SOUTH:
return BlockFace.EAST;
case WEST:
return BlockFace.SOUTH;
default:
return BlockFace.SELF;
}
}

public void buildEntities(CuboidTag cuboid, Location center) {
entities = new ListTag();
for (Entity ent : cuboid.getWorld().getEntities()) {
if (cuboid.isInsideCuboid(ent.getLocation())) {
EntityType type = ent.getType();
if (type == EntityType.PAINTING || type == EntityType.ITEM_FRAME) {
MapTag data = new MapTag();
data.putObject("entity", new EntityTag(ent).describe());
data.putObject("rotation", new ElementTag(0));
Vector offset = ent.getLocation().toVector().subtract(center.toVector());
if (ent instanceof Painting) { // Compensate for painting locations being very stupid
//offset.setY(offset.getY() - 0.1);
//offset.add(rotateFaceOneBackwards(ent.getFacing()).getDirection().multiply(0.1));
}
data.putObject("offset", new LocationTag(offset));
entities.addObject(data);
}
}
}
}

public void pasteEntities(LocationTag relative) {
if (entities == null) {
return;
}
for (MapTag data : entities.filter(MapTag.class, CoreUtilities.noDebugContext)) {
LocationTag offset = data.getObject("offset").asType(LocationTag.class, CoreUtilities.noDebugContext);
int rotation = data.getObject("rotation").asType(ElementTag.class, CoreUtilities.noDebugContext).asInt();
EntityTag entity = data.getObject("entity").asType(EntityTag.class, CoreUtilities.noDebugContext);
if (entity == null || offset == null) {
continue;
}
entity = entity.duplicate();
offset = offset.clone();
if (rotation != 0) {
ArrayList<Mechanism> mechs = new ArrayList<>(entity.getWaitingMechanisms().size());
for (Mechanism mech : entity.getWaitingMechanisms()) {
if (mech.getName().equals("rotation")) {
String rotationName = mech.getValue().asString();
BlockFace face = BlockFace.valueOf(rotationName.toUpperCase());
for (int i = 0; i < rotation; i += 90) {
face = rotateFaceOne(face);
}
offset.add(face.getDirection().multiply(0.1)); // Compensate for hanging locations being very stupid
mechs.add(new Mechanism(new ElementTag("rotation"), new ElementTag(face.name()), CoreUtilities.noDebugContext));
}
else {
mechs.add(new Mechanism(mech.getName(), mech.value, CoreUtilities.noDebugContext));
}
}
entity.mechanisms = mechs;
}
else {
for (Mechanism mechanism : entity.mechanisms) {
mechanism.context = CoreUtilities.noDebugContext;
}
}
entity.spawnAt(relative.clone().add(offset));
}
}

public void setBlockSingle(FullBlockData block, int x, int y, int z, InputParams input) {
if (input.noAir && block.data.getMaterial() == Material.AIR) {
return;
Expand Down Expand Up @@ -164,7 +267,29 @@ public void setBlocks(InputParams input) {
SchematicCommand.noPhys = false;
}

public void rotateEntitiesOne() {
if (entities == null) {
return;
}
ListTag outEntities = new ListTag();
for (MapTag data : entities.filter(MapTag.class, CoreUtilities.noDebugContext)) {
LocationTag offset = data.getObject("offset").asType(LocationTag.class, CoreUtilities.noDebugContext);
int rotation = data.getObject("rotation").asType(ElementTag.class, CoreUtilities.noDebugContext).asInt();
offset = new LocationTag(null, offset.getZ(), offset.getY(), -offset.getX() + 1);
rotation += 90;
while (rotation >= 360) {
rotation -= 360;
}
data = data.duplicate();
data.putObject("offset", offset);
data.putObject("rotation", new ElementTag(rotation));
outEntities.addObject(data);
}
entities = outEntities;
}

public void rotateOne() {
rotateEntitiesOne();
FullBlockData[] bd = new FullBlockData[blocks.length];
int index = 0;
int cx = center_x;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.denizenscript.denizen.nms.util.jnbt.*;
import com.denizenscript.denizen.objects.MaterialTag;
import com.denizenscript.denizen.utilities.debugging.Debug;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
Expand All @@ -23,6 +24,7 @@
public class SpongeSchematicHelper {

// Referenced from WorldEdit source and Sponge schematic format v2 documentation
// Some values are custom and specific to Denizen
public static CuboidBlockSet fromSpongeStream(InputStream is) {
CuboidBlockSet cbs = new CuboidBlockSet();
try {
Expand All @@ -34,6 +36,10 @@ public static CuboidBlockSet fromSpongeStream(InputStream is) {
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
Map<String, Tag> schematic = schematicTag.getValue();
if (schematic.containsKey("DenizenEntities")) {
String entities = getChildTag(schematic, "DenizenEntities", StringTag.class).getValue();
cbs.entities = ListTag.valueOf(entities, CoreUtilities.errorButNoDebugContext);
}
short width = getChildTag(schematic, "Width", ShortTag.class).getValue();
short length = getChildTag(schematic, "Length", ShortTag.class).getValue();
short height = getChildTag(schematic, "Height", ShortTag.class).getValue();
Expand Down Expand Up @@ -143,6 +149,9 @@ public static void saveToSpongeStream(CuboidBlockSet blockSet, OutputStream os)
schematic.put("Length", new ShortTag((short) (blockSet.z_height)));
schematic.put("Height", new ShortTag((short) (blockSet.y_length)));
schematic.put("DenizenOffset", new IntArrayTag(new int[] {blockSet.center_x, blockSet.center_y, blockSet.center_z}));
if (blockSet.entities != null) {
schematic.put("DenizenEntities", new StringTag(blockSet.entities.toString()));
}
Map<String, Tag> palette = new HashMap<>();
ByteArrayOutputStream blocksBuffer = new ByteArrayOutputStream((blockSet.x_width) * (blockSet.y_length) * (blockSet.z_height));
ArrayList<Tag> tileEntities = new ArrayList<>();
Expand Down

0 comments on commit 502a231

Please sign in to comment.