mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-18 10:32:30 +00:00
Partially working structure rotation
This commit is contained in:
parent
080a6d98f9
commit
e3a8a3386e
@ -26,6 +26,30 @@ public class Range implements Iterable<Integer> {
|
|||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Range setMax(int max) {
|
||||||
|
this.max = max;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRange() {
|
||||||
|
return max-min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Range multiply(int mult) {
|
||||||
|
min*=mult;
|
||||||
|
max*=mult;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Range reflect(int pt) {
|
||||||
|
return new Range(2*pt-this.getMax(), 2*pt-this.getMin());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Range setMin(int min) {
|
||||||
|
this.min = min;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public int get(Random r) {
|
public int get(Random r) {
|
||||||
return r.nextInt((max-min)+1)+min;
|
return r.nextInt((max-min)+1)+min;
|
||||||
}
|
}
|
||||||
|
@ -179,9 +179,10 @@ public class TerraCommand implements CommandExecutor, TabExecutor {
|
|||||||
return true;
|
return true;
|
||||||
} else if("load".equals(args[1])) {
|
} else if("load".equals(args[1])) {
|
||||||
try {
|
try {
|
||||||
|
GaeaStructure.Rotation r = GaeaStructure.Rotation.fromDegrees(Integer.parseInt(args[3]));
|
||||||
GaeaStructure struc = GaeaStructure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[2] + ".tstructure"));
|
GaeaStructure struc = GaeaStructure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[2] + ".tstructure"));
|
||||||
if("true".equals(args[3])) struc.paste(pl.getLocation());
|
if("true".equals(args[4])) struc.paste(pl.getLocation(), r, Collections.emptyList());
|
||||||
else struc.paste(pl.getLocation(), pl.getLocation().getChunk());
|
else struc.paste(pl.getLocation(), pl.getLocation().getChunk(), r, Collections.emptyList());
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
sender.sendMessage("Structure not found.");
|
sender.sendMessage("Structure not found.");
|
||||||
|
@ -15,13 +15,15 @@ import org.polydev.gaea.profiler.ProfileFuture;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class StructurePopulator extends BlockPopulator {
|
public class StructurePopulator extends BlockPopulator {
|
||||||
StructureSpawn spawnTest = new StructureSpawn(250, 250);
|
StructureSpawn spawnTest = new StructureSpawn(75, 25);
|
||||||
GaeaStructure struc = GaeaStructure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", "demo2.tstructure"));
|
GaeaStructure struc = GaeaStructure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", "desert.tstructure"));
|
||||||
double horizontal = struc.getStructureInfo().getMaxHorizontal();
|
double horizontal = struc.getStructureInfo().getMaxHorizontal();
|
||||||
|
|
||||||
public StructurePopulator() throws IOException {
|
public StructurePopulator() throws IOException {
|
||||||
@ -36,9 +38,8 @@ public class StructurePopulator extends BlockPopulator {
|
|||||||
spawn.setY(72);
|
spawn.setY(72);
|
||||||
if(Math.abs((cx+8)-spawn.getBlockX()) <= horizontal && Math.abs((cz+8)-spawn.getBlockZ()) <= horizontal) {
|
if(Math.abs((cx+8)-spawn.getBlockX()) <= horizontal && Math.abs((cz+8)-spawn.getBlockZ()) <= horizontal) {
|
||||||
try(ProfileFuture ignore = TerraProfiler.fromWorld(world).measure("StructurePasteTime")) {
|
try(ProfileFuture ignore = TerraProfiler.fromWorld(world).measure("StructurePasteTime")) {
|
||||||
struc.paste(spawn, chunk);
|
struc.paste(spawn, chunk, GaeaStructure.Rotation.fromDegrees(random.nextInt(4)*90), Collections.emptyList());
|
||||||
}
|
}
|
||||||
Bukkit.getLogger().info("Pasted at " + spawn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,14 @@ import org.bukkit.Chunk;
|
|||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
import org.bukkit.block.Sign;
|
import org.bukkit.block.Sign;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.block.data.Directional;
|
||||||
|
import org.bukkit.block.data.Rotatable;
|
||||||
|
import org.bukkit.block.data.type.Chest;
|
||||||
|
import org.bukkit.block.data.type.Stairs;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -19,6 +24,8 @@ import java.io.InputStream;
|
|||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@ -44,10 +51,10 @@ public class GaeaStructure implements Serializable {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.uuid = UUID.randomUUID();
|
this.uuid = UUID.randomUUID();
|
||||||
if(l1.getX() > l2.getX() || l1.getY() > l2.getY() || l1.getZ() > l2.getZ()) throw new IllegalArgumentException("Invalid locations provided!");
|
if(l1.getX() > l2.getX() || l1.getY() > l2.getY() || l1.getZ() > l2.getZ()) throw new IllegalArgumentException("Invalid locations provided!");
|
||||||
structure = new StructureContainedBlock[l2.getBlockX()-l1.getBlockX()+1][l2.getBlockY()-l1.getBlockY()+1][l2.getBlockZ()-l1.getBlockZ()+1];
|
structure = new StructureContainedBlock[l2.getBlockX()-l1.getBlockX()+1][l2.getBlockZ()-l1.getBlockZ()+1][l2.getBlockY()-l1.getBlockY()+1];
|
||||||
for(int x = 0; x <= l2.getBlockX()-l1.getBlockX(); x++) {
|
for(int x = 0; x <= l2.getBlockX()-l1.getBlockX(); x++) {
|
||||||
for(int y = 0; y <= l2.getBlockY()-l1.getBlockY(); y++) {
|
for(int z = 0; z <= l2.getBlockZ()-l1.getBlockZ(); z++) {
|
||||||
for(int z = 0; z <= l2.getBlockZ()-l1.getBlockZ(); z++) {
|
for(int y = 0; y <= l2.getBlockY()-l1.getBlockY(); y++) {
|
||||||
Block b = Objects.requireNonNull(l1.getWorld()).getBlockAt(l1.clone().add(x, y, z));
|
Block b = Objects.requireNonNull(l1.getWorld()).getBlockAt(l1.clone().add(x, y, z));
|
||||||
BlockState state = b.getState();
|
BlockState state = b.getState();
|
||||||
BlockData d = b.getBlockData();
|
BlockData d = b.getBlockData();
|
||||||
@ -67,7 +74,7 @@ public class GaeaStructure implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
structure[x][y][z] = new StructureContainedBlock(x, y, z, useState ? state : null, d);
|
structure[x][z][y] = new StructureContainedBlock(x, y, z, useState ? state : null, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,46 +87,229 @@ public class GaeaStructure implements Serializable {
|
|||||||
return structureInfo;
|
return structureInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void paste(@NotNull Location origin) {
|
public void paste(@NotNull Location origin, Rotation r, List<Mirror> m) {
|
||||||
this.executeForBlocksInRange(getRange(Axis.X), getRange(Axis.Y), getRange(Axis.Z), block -> pasteBlock(block, origin));
|
this.executeForBlocksInRange(getRange(Axis.X), getRange(Axis.Y), getRange(Axis.Z), block -> pasteBlock(block, origin, r, m), r, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void paste(Location origin, Chunk chunk) {
|
private int[] getRotatedCoords(int[] arr, Rotation r, List<Mirror> m) {
|
||||||
int xOr = (chunk.getX() << 4);
|
int[] cp = Arrays.copyOf(arr, 2);
|
||||||
int zOr = (chunk.getZ() << 4);
|
switch(r) {
|
||||||
Range intersectX = new Range(xOr, xOr+16).sub(origin.getBlockX() - structureInfo.getCenterX());
|
case CW_90:
|
||||||
Range intersectZ = new Range(zOr, zOr+16).sub(origin.getBlockZ() - structureInfo.getCenterZ());
|
arr[0] = cp[1];
|
||||||
if(intersectX == null || intersectZ == null) return;
|
arr[1] = - cp[0];
|
||||||
executeForBlocksInRange(intersectX, getRange(Axis.Y), intersectZ, block -> pasteBlock(block, origin));
|
break;
|
||||||
|
case CCW_90:
|
||||||
|
arr[0] = - cp[1];
|
||||||
|
arr[1] = cp[0];
|
||||||
|
break;
|
||||||
|
case CW_180:
|
||||||
|
arr[0] = - cp[0];
|
||||||
|
arr[1] = - cp[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(m.contains(Mirror.X)) arr[0] = - arr[0];
|
||||||
|
if(m.contains(Mirror.Z)) arr[1] = - arr[1];
|
||||||
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pasteBlock(StructureContainedBlock block, Location origin) {
|
/**
|
||||||
BlockData data = block.getBlockData();
|
* Inverse of {@link GaeaStructure#getRotatedCoords(int[], Rotation, List)}, gets the coordinates <i>before</i> rotation
|
||||||
Block worldBlock = origin.clone().add(block.getX()-structureInfo.getCenterX(), block.getY(), block.getZ()-structureInfo.getCenterZ()).getBlock();
|
* @param arr 2-integer array holding X and Z coordinates
|
||||||
if(!data.getMaterial().equals(Material.STRUCTURE_VOID)) worldBlock.setBlockData(data, false);
|
* @param r Rotation
|
||||||
if(block.getState() != null) {
|
* @param m Mirror
|
||||||
block.getState().getState(worldBlock.getState()).update();
|
* @return New coordinates
|
||||||
|
*/
|
||||||
|
private int[] getOriginalCoords(int[] arr, Rotation r, List<Mirror> m) {
|
||||||
|
int[] cp = Arrays.copyOf(arr, 2);
|
||||||
|
switch(r) {
|
||||||
|
case CW_90:
|
||||||
|
arr[1] = cp[0];
|
||||||
|
arr[0] = - cp[1];
|
||||||
|
break;
|
||||||
|
case CCW_90:
|
||||||
|
arr[1] = - cp[0];
|
||||||
|
arr[0] = cp[1];
|
||||||
|
break;
|
||||||
|
case CW_180:
|
||||||
|
arr[1] = - cp[1];
|
||||||
|
arr[0] = - cp[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(m.contains(Mirror.X)) arr[0] = - arr[0];
|
||||||
|
if(m.contains(Mirror.Z)) arr[1] = - arr[1];
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the BlockFace with rotation and mirrors applied to it
|
||||||
|
* @param f BlockFace to apply rotation to
|
||||||
|
* @param r Rotation
|
||||||
|
* @param m Mirror
|
||||||
|
* @return Rotated BlockFace
|
||||||
|
*/
|
||||||
|
private BlockFace getRotatedFace(BlockFace f, Rotation r, List<Mirror> m) {
|
||||||
|
BlockFace n = f;
|
||||||
|
int rotateNum = r.getDegrees()/90;
|
||||||
|
int rn = faceRotation(f);
|
||||||
|
if(rn >= 0) {
|
||||||
|
n = fromRotation(faceRotation(n) - 4*rotateNum);
|
||||||
|
}
|
||||||
|
if(f.getModX()!=0 && m.contains(Mirror.X)) n = n.getOppositeFace();
|
||||||
|
if(f.getModZ()!=0 && m.contains(Mirror.Z)) n = n.getOppositeFace();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an integer representation of a BlockFace, to perform math on.
|
||||||
|
* @param f BlockFace to get integer for
|
||||||
|
* @return integer representation of BlockFace
|
||||||
|
*/
|
||||||
|
private static int faceRotation(BlockFace f) {
|
||||||
|
switch(f) {
|
||||||
|
case NORTH: return 0;
|
||||||
|
case NORTH_NORTH_EAST: return 1;
|
||||||
|
case NORTH_EAST: return 2;
|
||||||
|
case EAST_NORTH_EAST: return 3;
|
||||||
|
case EAST: return 4;
|
||||||
|
case EAST_SOUTH_EAST: return 5;
|
||||||
|
case SOUTH_EAST: return 6;
|
||||||
|
case SOUTH_SOUTH_EAST: return 7;
|
||||||
|
case SOUTH: return 8;
|
||||||
|
case SOUTH_SOUTH_WEST: return 9;
|
||||||
|
case SOUTH_WEST: return 10;
|
||||||
|
case WEST_SOUTH_WEST: return 11;
|
||||||
|
case WEST: return 12;
|
||||||
|
case WEST_NORTH_WEST: return 13;
|
||||||
|
case NORTH_WEST: return 14;
|
||||||
|
case NORTH_NORTH_WEST: return 15;
|
||||||
|
default: return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeForBlocksInRange(Range xM, Range yM, Range zM, Consumer<StructureContainedBlock> exec) {
|
/**
|
||||||
|
* Convert integer to BlockFace representation
|
||||||
|
* @param r integer to get BlockFace for
|
||||||
|
* @return BlockFace represented by integer.
|
||||||
|
*/
|
||||||
|
private static BlockFace fromRotation(int r) {
|
||||||
|
switch(Math.floorMod(r, 16)) {
|
||||||
|
case 0: return BlockFace.NORTH;
|
||||||
|
case 1: return BlockFace.NORTH_NORTH_EAST;
|
||||||
|
case 2: return BlockFace.NORTH_EAST;
|
||||||
|
case 3: return BlockFace.EAST_NORTH_EAST;
|
||||||
|
case 4: return BlockFace.EAST;
|
||||||
|
case 5: return BlockFace.EAST_SOUTH_EAST;
|
||||||
|
case 6: return BlockFace.SOUTH_EAST;
|
||||||
|
case 7: return BlockFace.SOUTH_SOUTH_EAST;
|
||||||
|
case 8: return BlockFace.SOUTH;
|
||||||
|
case 9: return BlockFace.SOUTH_SOUTH_WEST;
|
||||||
|
case 10: return BlockFace.SOUTH_WEST;
|
||||||
|
case 11: return BlockFace.WEST_SOUTH_WEST;
|
||||||
|
case 12: return BlockFace.WEST;
|
||||||
|
case 13: return BlockFace.WEST_NORTH_WEST;
|
||||||
|
case 14: return BlockFace.NORTH_WEST;
|
||||||
|
case 15: return BlockFace.NORTH_NORTH_WEST;
|
||||||
|
default: throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paste structure at an origin location, confined to a single chunk.
|
||||||
|
* @param origin Origin location
|
||||||
|
* @param chunk Chunk to confine pasting to
|
||||||
|
* @param r Rotation
|
||||||
|
* @param m Mirror
|
||||||
|
*/
|
||||||
|
public void paste(Location origin, Chunk chunk, Rotation r, List<Mirror> m) {
|
||||||
|
int xOr = (chunk.getX() << 4);
|
||||||
|
int zOr = (chunk.getZ() << 4);
|
||||||
|
Range intersectX;
|
||||||
|
Range intersectZ;
|
||||||
|
intersectX = new Range(xOr, xOr+16).sub(origin.getBlockX() - structureInfo.getCenterX());
|
||||||
|
intersectZ = new Range(zOr, zOr+16).sub(origin.getBlockZ() - structureInfo.getCenterZ());
|
||||||
|
if(intersectX == null || intersectZ == null) return;
|
||||||
|
executeForBlocksInRange(intersectX, getRange(Axis.Y), intersectZ, block -> pasteBlock(block, origin, r, m), r, m);
|
||||||
|
Bukkit.getLogger().info(intersectX.toString() + " : " + intersectZ.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paste a single StructureDefinedBlock at an origin location, offset by its coordinates.
|
||||||
|
* @param block The block to paste
|
||||||
|
* @param origin The origin location
|
||||||
|
* @param r The rotation of the structure
|
||||||
|
* @param m The mirror type of the structure
|
||||||
|
*/
|
||||||
|
private void pasteBlock(StructureContainedBlock block, Location origin, Rotation r, List<Mirror> m) {
|
||||||
|
BlockData data = block.getBlockData().clone();
|
||||||
|
Block worldBlock = origin.clone().add(block.getX(), block.getY(), block.getZ()).getBlock();
|
||||||
|
if(!data.getMaterial().equals(Material.STRUCTURE_VOID)) {
|
||||||
|
if(data instanceof Rotatable) {
|
||||||
|
BlockFace rt = getRotatedFace(((Rotatable) data).getRotation(), r, m);
|
||||||
|
Bukkit.getLogger().info("Previous: " + ((Rotatable) data).getRotation() + ", New: " + rt);
|
||||||
|
((Rotatable) data).setRotation(rt);
|
||||||
|
} else if(data instanceof Directional) {
|
||||||
|
BlockFace rt = getRotatedFace(((Directional) data).getFacing(), r, m);
|
||||||
|
Bukkit.getLogger().info("Previous: " + ((Directional) data).getFacing() + ", New: " + rt);
|
||||||
|
((Directional) data).setFacing(rt);
|
||||||
|
}
|
||||||
|
worldBlock.setBlockData(data, false);
|
||||||
|
if(block.getState() != null) {
|
||||||
|
block.getState().getState(worldBlock.getState()).update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a Consumer for all blocks in a cuboid region defined by 3 Ranges, accounting for rotation.
|
||||||
|
* @param xM X Range
|
||||||
|
* @param yM Y Range
|
||||||
|
* @param zM Z Range
|
||||||
|
* @param exec Consumer to execute for each block.
|
||||||
|
* @param r Rotation
|
||||||
|
* @param m Mirror
|
||||||
|
*/
|
||||||
|
private void executeForBlocksInRange(Range xM, Range yM, Range zM, Consumer<StructureContainedBlock> exec, Rotation r, List<Mirror> m) {
|
||||||
for(int x : xM) {
|
for(int x : xM) {
|
||||||
for(int y : yM) {
|
for(int y : yM) {
|
||||||
for(int z : zM) {
|
for(int z : zM) {
|
||||||
if(isInStructure(x, y, z)) exec.accept(structure[x][y][z]);
|
int[] c = getOriginalCoords(new int[] {structure[x][z][y].getX()-structureInfo.getCenterX(), structure[x][z][y].getZ()-structureInfo.getCenterZ()}, r, m);
|
||||||
|
if(isInStructure(c[0], y, c[1])) {
|
||||||
|
StructureContainedBlock b = structure[c[0]][c[1]][y];
|
||||||
|
exec.accept(new StructureContainedBlock(x, y, z, b.getState(), b.getBlockData()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether a set of coordinates is within the current structure
|
||||||
|
* @param x X coordinate
|
||||||
|
* @param y Y coordinate
|
||||||
|
* @param z Z coordinate
|
||||||
|
* @return True if coordinate set is in structure, false if it is not.
|
||||||
|
*/
|
||||||
private boolean isInStructure(int x, int y, int z) {
|
private boolean isInStructure(int x, int y, int z) {
|
||||||
return x < structureInfo.getSizeX() && y < structureInfo.getSizeY() && z < structureInfo.getSizeZ() && x >= 0 && y >= 0 && z >= 0;
|
return x < structureInfo.getSizeX() && y < structureInfo.getSizeY() && z < structureInfo.getSizeZ() && x >= 0 && y >= 0 && z >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the structure to a file
|
||||||
|
* @param f File to save to
|
||||||
|
* @throws IOException If file access error occurs
|
||||||
|
*/
|
||||||
public void save(@NotNull File f) throws IOException {
|
public void save(@NotNull File f) throws IOException {
|
||||||
toFile(this, f);
|
toFile(this, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a structure from a file.
|
||||||
|
* @param f File to load from
|
||||||
|
* @return The structure loaded
|
||||||
|
* @throws IOException If file access error occurs
|
||||||
|
* @throws ClassNotFoundException If structure data is invalid.
|
||||||
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
private static GaeaStructure fromFile(@NotNull File f) throws IOException, ClassNotFoundException {
|
private static GaeaStructure fromFile(@NotNull File f) throws IOException, ClassNotFoundException {
|
||||||
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
|
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
|
||||||
@ -164,7 +354,30 @@ public class GaeaStructure implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Axis {
|
public enum Axis {
|
||||||
X, Y, Z
|
X, Y, Z
|
||||||
}
|
}
|
||||||
|
public enum Rotation {
|
||||||
|
CW_90(90), CW_180(180), CCW_90(270), NONE(0);
|
||||||
|
private final int degrees;
|
||||||
|
Rotation(int degrees) {
|
||||||
|
this.degrees = degrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDegrees() {
|
||||||
|
return degrees;
|
||||||
|
}
|
||||||
|
public static Rotation fromDegrees(int deg) {
|
||||||
|
switch(Math.floorMod(deg, 360)) {
|
||||||
|
case 0: return Rotation.NONE;
|
||||||
|
case 90: return Rotation.CW_90;
|
||||||
|
case 180: return Rotation.CW_180;
|
||||||
|
case 270: return Rotation.CCW_90;
|
||||||
|
default: throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public enum Mirror {
|
||||||
|
NONE, X, Z
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,15 @@ public class StructureContainedBlock implements Serializable {
|
|||||||
this.z = z;
|
this.z = z;
|
||||||
this.bl = new SerializableBlockData(d);
|
this.bl = new SerializableBlockData(d);
|
||||||
}
|
}
|
||||||
|
public StructureContainedBlock(int x, int y, int z, SerializableBlockState state, BlockData d) {
|
||||||
|
if(state instanceof SerializableSign) {
|
||||||
|
this.state = state;
|
||||||
|
} else this.state = null;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.bl = new SerializableBlockData(d);
|
||||||
|
}
|
||||||
|
|
||||||
public int getX() {
|
public int getX() {
|
||||||
return x;
|
return x;
|
||||||
|
@ -30,7 +30,9 @@ terra {
|
|||||||
}
|
}
|
||||||
load {
|
load {
|
||||||
structure brigadier:string single_word {
|
structure brigadier:string single_word {
|
||||||
respect_chunk brigadier:bool;
|
rotation brigadier:integer {
|
||||||
|
respect_chunk brigadier:bool;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getspawn;
|
getspawn;
|
||||||
|
@ -26,4 +26,11 @@ public class RangeTest {
|
|||||||
one = new Range(25, 50);
|
one = new Range(25, 50);
|
||||||
assertNull(one.intersects(two));
|
assertNull(one.intersects(two));
|
||||||
}
|
}
|
||||||
|
@Test
|
||||||
|
public void reflect() {
|
||||||
|
Range t = new Range(3, 10);
|
||||||
|
Range other = t.reflect(5);
|
||||||
|
assertEquals(7, other.getMax());
|
||||||
|
assertEquals(0, other.getMin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user