Bug fix: don't change the relPos of existing WPObjects during object exporting and manipulation
Bug fix: correctly import exporting, rotation and mirroring of entities from custom objectsmaster
parent
5d194dadd6
commit
0bb514a5f8
|
@ -729,6 +729,8 @@ public final class Constants {
|
|||
public static final String TAG_LARGE_BIOMES_ = "large_biomes";
|
||||
public static final String TAG_SPAWN_FORCED = "SpawnForced";
|
||||
public static final String TAG_SPAWN_DIMENSION = "SpawnDimension";
|
||||
public static final String TAG_FACING = "Facing";
|
||||
public static final String TAG_FACING_ = "facing";
|
||||
|
||||
/**
|
||||
* Possibly unofficial, SpoutCraft-specific
|
||||
|
|
|
@ -7,11 +7,13 @@ package org.pepsoft.minecraft;
|
|||
|
||||
import org.jnbt.CompoundTag;
|
||||
import org.jnbt.StringTag;
|
||||
import org.pepsoft.util.MathUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.pepsoft.minecraft.Constants.*;
|
||||
import static org.pepsoft.util.ArrayUtils.indexOf;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -71,6 +73,11 @@ public class Entity extends AbstractNBTItem {
|
|||
throw new IllegalArgumentException();
|
||||
}
|
||||
setDoubleList(TAG_POS, pos);
|
||||
if (containsTag(TAG_TILE_X)) {
|
||||
setInt(TAG_TILE_X, (int) Math.floor(pos[0]));
|
||||
setInt(TAG_TILE_Y, (int) Math.floor(pos[1]));
|
||||
setInt(TAG_TILE_Z, (int) Math.floor(pos[2]));
|
||||
}
|
||||
}
|
||||
|
||||
public final float[] getRot() {
|
||||
|
@ -112,6 +119,97 @@ public class Entity extends AbstractNBTItem {
|
|||
setString(TAG_UUID, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a clone of this entity that has been rotated clockwise by {@code steps} times 90 degrees.
|
||||
*/
|
||||
public Entity rotate(int steps) {
|
||||
final Entity rotEntity = clone();
|
||||
if (steps != 0) {
|
||||
final float[] rot = rotEntity.getRot();
|
||||
rot[0] = MathUtils.mod(rot[0] + steps * 90.0f, 360.0f);
|
||||
rotEntity.setRot(rot);
|
||||
if (containsTag(TAG_FACING_)) {
|
||||
int facing = getByte(TAG_FACING_);
|
||||
if ((facing >= 0) && (facing <= 3)) {
|
||||
facing = (facing + steps) & 0x3;
|
||||
rotEntity.setByte(TAG_FACING_, (byte) facing);
|
||||
}
|
||||
}
|
||||
if (containsTag(TAG_FACING)) {
|
||||
int facing = getByte(TAG_FACING);
|
||||
if ((facing >= 2) && (facing <= 5)) {
|
||||
facing = FACING_VALUES[(indexOf(FACING_VALUES, facing) + steps) & 0x3];
|
||||
rotEntity.setByte(TAG_FACING, (byte) facing);
|
||||
}
|
||||
}
|
||||
// TODO are there other properties to adjust?
|
||||
// TODO adjust velocity
|
||||
}
|
||||
return rotEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a clone of this entity that has been mirrored in the indicated axis.
|
||||
*/
|
||||
public Entity mirror(boolean mirrorYAxis) {
|
||||
final Entity mirEntity = clone();
|
||||
final double[] vel = mirEntity.getVel();
|
||||
if (mirrorYAxis) {
|
||||
vel[2] = -vel[2];
|
||||
} else {
|
||||
vel[0] = -vel[0];
|
||||
}
|
||||
mirEntity.setVel(vel);
|
||||
final float[] rot = mirEntity.getRot();
|
||||
if (mirrorYAxis) {
|
||||
rot[0] = MathUtils.mod(180.0f - rot[0], 360.0f);
|
||||
} else {
|
||||
rot[0] = MathUtils.mod(-rot[0], 360.0f);
|
||||
}
|
||||
mirEntity.setRot(rot);
|
||||
if (containsTag(TAG_FACING_)) {
|
||||
int facing = getByte(TAG_FACING_);
|
||||
if (mirrorYAxis) {
|
||||
switch (facing) {
|
||||
case 0: facing = 2; break;
|
||||
case 2: facing = 0; break;
|
||||
}
|
||||
} else {
|
||||
switch (facing) {
|
||||
case 1: facing = 3; break;
|
||||
case 3: facing = 1; break;
|
||||
}
|
||||
}
|
||||
mirEntity.setByte(TAG_FACING_, (byte) facing);
|
||||
}
|
||||
if (containsTag(TAG_FACING)) {
|
||||
int facing = getByte(TAG_FACING);
|
||||
if (mirrorYAxis) {
|
||||
switch (facing) {
|
||||
case 2: facing = 3; break;
|
||||
case 3: facing = 2; break;
|
||||
}
|
||||
} else {
|
||||
switch (facing) {
|
||||
case 4: facing = 5; break;
|
||||
case 5: facing = 4; break;
|
||||
}
|
||||
}
|
||||
mirEntity.setByte(TAG_FACING, (byte) facing);
|
||||
}
|
||||
// TODO are there other properties to adjust?
|
||||
return mirEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity clone() {
|
||||
final Entity clone = (Entity) super.clone();
|
||||
if (relPos != null) {
|
||||
clone.relPos = relPos.clone();
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
public static Entity fromNBT(CompoundTag entityTag) {
|
||||
return fromNBT(entityTag, null);
|
||||
}
|
||||
|
@ -132,5 +230,6 @@ public class Entity extends AbstractNBTItem {
|
|||
|
||||
private double[] relPos;
|
||||
|
||||
private static final int[] FACING_VALUES = { 3, 4, 2, 5 };
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -637,16 +637,9 @@ public final class MC115AnvilChunk extends MCNamedBlocksChunk implements Section
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int x, int y, int height, Entity entity) {
|
||||
entity = (Entity) entity.clone();
|
||||
entity.setPos(new double[] {x, height, y});
|
||||
getEntities().add(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(double x, double y, double height, Entity entity) {
|
||||
entity = (Entity) entity.clone();
|
||||
entity = entity.clone();
|
||||
entity.setPos(new double[] {x, height, y});
|
||||
getEntities().add(entity);
|
||||
}
|
||||
|
|
|
@ -647,16 +647,9 @@ public final class MC118AnvilChunk extends MCNamedBlocksChunk implements Section
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int x, int y, int height, Entity entity) {
|
||||
entity = (Entity) entity.clone();
|
||||
entity.setPos(new double[] {x, height, y});
|
||||
getEntities().add(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(double x, double y, double height, Entity entity) {
|
||||
entity = (Entity) entity.clone();
|
||||
entity = entity.clone();
|
||||
entity.setPos(new double[] {x, height, y});
|
||||
getEntities().add(entity);
|
||||
}
|
||||
|
|
|
@ -504,16 +504,9 @@ public final class MC12AnvilChunk extends MCNumberedBlocksChunk implements Minec
|
|||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int x, int y, int height, Entity entity) {
|
||||
entity = (Entity) entity.clone();
|
||||
entity.setPos(new double[] {x, height, y});
|
||||
getEntities().add(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(double x, double y, double height, Entity entity) {
|
||||
entity = (Entity) entity.clone();
|
||||
entity = entity.clone();
|
||||
entity.setPos(new double[] {x, height, y});
|
||||
getEntities().add(entity);
|
||||
}
|
||||
|
|
|
@ -376,16 +376,9 @@ public class MemoryChunk implements Chunk, MinecraftWorld, Serializable {
|
|||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int x, int y, int height, Entity entity) {
|
||||
entity = (Entity) entity.clone();
|
||||
entity.setPos(new double[] {x, height, y});
|
||||
getEntities().add(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(double x, double y, double height, Entity entity) {
|
||||
entity = (Entity) entity.clone();
|
||||
entity = entity.clone();
|
||||
entity.setPos(new double[] {x, height, y});
|
||||
getEntities().add(entity);
|
||||
}
|
||||
|
|
|
@ -269,11 +269,6 @@ public class CachingMinecraftWorld implements MinecraftWorld {
|
|||
chunkStore.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int x, int y, int height, Entity entity) {
|
||||
addEntity(x + 0.5, y + 0.5, height + 1.5, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(double x, double y, double height, Entity entity) {
|
||||
if (readOnly) {
|
||||
|
@ -281,7 +276,7 @@ public class CachingMinecraftWorld implements MinecraftWorld {
|
|||
}
|
||||
Chunk chunk = getChunkForEditing(((int) x) >> 4, ((int) y) >> 4);
|
||||
if ((chunk != null) && (! chunk.isReadOnly())) {
|
||||
Entity clone = (Entity) entity.clone();
|
||||
Entity clone = entity.clone();
|
||||
clone.setPos(new double[] {x, height, y});
|
||||
chunk.getEntities().add(clone);
|
||||
}
|
||||
|
|
|
@ -95,18 +95,9 @@ public class InvertedWorld implements MinecraftWorld {
|
|||
return maxHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int x, int y, int height, Entity entity) {
|
||||
Entity worldEntity = (Entity) entity.clone();
|
||||
double[] pos = worldEntity.getPos();
|
||||
pos[1] = maxZ - pos[1];
|
||||
worldEntity.setPos(pos);
|
||||
world.addEntity(x, y, maxZ - height, worldEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(double x, double y, double height, Entity entity) {
|
||||
Entity worldEntity = (Entity) entity.clone();
|
||||
Entity worldEntity = entity.clone();
|
||||
double[] pos = worldEntity.getPos();
|
||||
pos[1] = maxZ - pos[1];
|
||||
worldEntity.setPos(pos);
|
||||
|
|
|
@ -67,8 +67,6 @@ public interface MinecraftWorld extends ChunkProvider {
|
|||
|
||||
int getMaxHeight();
|
||||
|
||||
void addEntity(int x, int y, int height, Entity entity);
|
||||
|
||||
void addEntity(double x, double y, double height, Entity entity);
|
||||
|
||||
void addTileEntity(int x, int y, int height, TileEntity tileEntity);
|
||||
|
|
|
@ -131,16 +131,11 @@ public class WorldRegion implements MinecraftWorld {
|
|||
return maxHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int x, int y, int height, Entity entity) {
|
||||
addEntity(x + 0.5, y + 0.5, height + 1.5, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(double x, double y, double height, Entity entity) {
|
||||
Chunk chunk = getChunkForEditing(((int) x) >> 4, ((int) y) >> 4);
|
||||
Chunk chunk = getChunkForEditing((int) Math.floor(x) >> 4, (int) Math.floor(y) >> 4);
|
||||
if (chunk != null) {
|
||||
Entity clone = (Entity) entity.clone();
|
||||
Entity clone = entity.clone();
|
||||
clone.setPos(new double[] {x, height, y});
|
||||
chunk.getEntities().add(clone);
|
||||
}
|
||||
|
|
|
@ -181,11 +181,6 @@ public final class MinecraftWorldObject implements MinecraftWorld, WPObject {
|
|||
return maxHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(int x, int y, int height, Entity entity) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(double x, double y, double height, Entity entity) {
|
||||
// Do nothing
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.pepsoft.minecraft.Entity;
|
|||
import org.pepsoft.minecraft.Material;
|
||||
import org.pepsoft.minecraft.TileEntity;
|
||||
import org.pepsoft.util.AttributeKey;
|
||||
import org.pepsoft.util.MathUtils;
|
||||
import org.pepsoft.worldpainter.Platform;
|
||||
|
||||
import javax.vecmath.Point3i;
|
||||
|
@ -71,21 +70,14 @@ public class MirroredObject extends AbstractObject {
|
|||
if (objectEntities != null) {
|
||||
List<Entity> entities = new ArrayList<>(objectEntities.size());
|
||||
for (Entity objectEntity: objectEntities) {
|
||||
Entity entity = (Entity) objectEntity.clone();
|
||||
Entity entity = objectEntity.mirror(mirrorYAxis);
|
||||
double[] relPos = entity.getRelPos();
|
||||
double[] vel = entity.getVel();
|
||||
if (mirrorYAxis) {
|
||||
relPos[2] = dimensions.y - relPos[2];
|
||||
vel[2] = -vel[2];
|
||||
} else {
|
||||
relPos[0] = dimensions.x - relPos[0];
|
||||
vel[0] = -vel[0];
|
||||
}
|
||||
entity.setRelPos(relPos);
|
||||
entity.setVel(vel);
|
||||
float[] rot = entity.getRot();
|
||||
rot[0] = MathUtils.mod(rot[0] + 180.0f, 360.0f);
|
||||
entity.setRot(rot);
|
||||
entities.add(entity);
|
||||
}
|
||||
return entities;
|
||||
|
|
|
@ -8,7 +8,6 @@ import org.pepsoft.minecraft.Entity;
|
|||
import org.pepsoft.minecraft.Material;
|
||||
import org.pepsoft.minecraft.TileEntity;
|
||||
import org.pepsoft.util.AttributeKey;
|
||||
import org.pepsoft.util.MathUtils;
|
||||
import org.pepsoft.worldpainter.Platform;
|
||||
|
||||
import javax.vecmath.Point3i;
|
||||
|
@ -110,36 +109,33 @@ public class RotatedObject extends AbstractObject {
|
|||
|
||||
@Override
|
||||
public List<Entity> getEntities() {
|
||||
if (steps == 0) {
|
||||
return object.getEntities();
|
||||
}
|
||||
List<Entity> objectEntities = object.getEntities();
|
||||
if (objectEntities != null) {
|
||||
List<Entity> entities = new ArrayList<>(objectEntities.size());
|
||||
for (Entity origEntity: objectEntities) {
|
||||
Entity rotEntity = (Entity) origEntity.clone();
|
||||
if (steps != 0) {
|
||||
double[] origRelPos = origEntity.getRelPos();
|
||||
double[] rotRelPos = rotEntity.getRelPos();
|
||||
switch (steps) {
|
||||
case 1:
|
||||
rotRelPos[0] = dimensions.x - origRelPos[2];
|
||||
rotRelPos[2] = origRelPos[0];
|
||||
break;
|
||||
case 2:
|
||||
rotRelPos[0] = dimensions.x - origRelPos[0];
|
||||
rotRelPos[2] = dimensions.y - origRelPos[2];
|
||||
break;
|
||||
case 3:
|
||||
rotRelPos[0] = origRelPos[2];
|
||||
rotRelPos[2] = dimensions.y - origRelPos[0];
|
||||
break;
|
||||
default:
|
||||
throw new InternalError();
|
||||
}
|
||||
rotEntity.setRelPos(rotRelPos);
|
||||
float[] rot = origEntity.getRot();
|
||||
rot[0] = MathUtils.mod(rot[0] + steps * 90.0f, 360.0f);
|
||||
rotEntity.setRot(rot);
|
||||
// TODO: adjust velocity
|
||||
Entity rotEntity = origEntity.rotate(steps);
|
||||
double[] origRelPos = origEntity.getRelPos();
|
||||
double[] rotRelPos = rotEntity.getRelPos();
|
||||
switch (steps) {
|
||||
case 1:
|
||||
rotRelPos[0] = dimensions.x - origRelPos[2];
|
||||
rotRelPos[2] = origRelPos[0];
|
||||
break;
|
||||
case 2:
|
||||
rotRelPos[0] = dimensions.x - origRelPos[0];
|
||||
rotRelPos[2] = dimensions.y - origRelPos[2];
|
||||
break;
|
||||
case 3:
|
||||
rotRelPos[0] = origRelPos[2];
|
||||
rotRelPos[2] = dimensions.y - origRelPos[0];
|
||||
break;
|
||||
default:
|
||||
throw new InternalError();
|
||||
}
|
||||
rotEntity.setRelPos(rotRelPos);
|
||||
entities.add(rotEntity);
|
||||
}
|
||||
return entities;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
*/
|
||||
package org.pepsoft.worldpainter.objects;
|
||||
|
||||
import org.jnbt.ByteTag;
|
||||
import org.jnbt.CompoundTag;
|
||||
import org.pepsoft.minecraft.Entity;
|
||||
import org.pepsoft.minecraft.Material;
|
||||
import org.pepsoft.minecraft.TileEntity;
|
||||
|
@ -13,10 +15,10 @@ import org.pepsoft.worldpainter.Dimension;
|
|||
import javax.vecmath.Point3i;
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static org.pepsoft.minecraft.Constants.TAG_FACING;
|
||||
import static org.pepsoft.minecraft.Constants.TAG_FACING_;
|
||||
|
||||
/**
|
||||
* A three dimensional object, consisting of Minecraft blocks, which can be
|
||||
|
@ -243,6 +245,108 @@ public interface WPObject extends Serializable, Cloneable {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the object to the console.
|
||||
*/
|
||||
default void dump() {
|
||||
final Point3i dim = getDimensions();
|
||||
final Map<Point3i, List<Entity>> entities = new HashMap<>();
|
||||
if (getEntities() != null) {
|
||||
for (Entity entity : getEntities()) {
|
||||
final Point3i pos = new Point3i(
|
||||
(int) Math.floor(entity.getRelPos()[0]),
|
||||
(int) Math.floor(entity.getRelPos()[2]),
|
||||
(int) Math.floor(entity.getRelPos()[1])
|
||||
);
|
||||
entities.computeIfAbsent(pos, k -> new ArrayList<>()).add(entity);
|
||||
}
|
||||
}
|
||||
for (int z = 0; z < dim.z; z++) {
|
||||
final List<Entity> entitiesEncountered = new ArrayList<>(entities.size());
|
||||
System.out.println("X-->");
|
||||
for (int y = 0; y < dim.y; y++) {
|
||||
for (int row = 0; row < 4; row++) {
|
||||
switch (row) {
|
||||
case 0:
|
||||
for (int x = 0; x < dim.x; x++) {
|
||||
System.out.print("+------");
|
||||
}
|
||||
System.out.print('+');
|
||||
break;
|
||||
case 1:
|
||||
for (int x = 0; x < dim.x; x++) {
|
||||
if (getMask(x, y, z)) {
|
||||
System.out.printf("|%6.6s", getMaterial(x, y, z).simpleName);
|
||||
} else {
|
||||
System.out.print("| ");
|
||||
}
|
||||
}
|
||||
System.out.print('|');
|
||||
break;
|
||||
case 2:
|
||||
for (int x = 0; x < dim.x; x++) {
|
||||
final Point3i pos = new Point3i(x, y, z);
|
||||
if (entities.containsKey(pos)) {
|
||||
final Entity entity = entities.get(pos).get(0);
|
||||
entitiesEncountered.add(entity);
|
||||
final String id = entity.getId();
|
||||
System.out.printf("|%d:%4.4s", entitiesEncountered.size(), id.substring(id.indexOf(':') + 1));
|
||||
} else {
|
||||
System.out.print("| ");
|
||||
}
|
||||
}
|
||||
System.out.print('|');
|
||||
break;
|
||||
case 3:
|
||||
for (int x = 0; x < dim.x; x++) {
|
||||
final Point3i pos = new Point3i(x, y, z);
|
||||
if (entities.containsKey(pos) && (entities.get(pos).size() > 1)) {
|
||||
final Entity entity = entities.get(pos).get(1);
|
||||
entitiesEncountered.add(entity);
|
||||
final String id = entity.getId();
|
||||
System.out.printf("|%d:%4.4s", entitiesEncountered.size(), id.substring(id.indexOf(':') + 1));
|
||||
} else {
|
||||
System.out.print("| ");
|
||||
}
|
||||
}
|
||||
System.out.print('|');
|
||||
break;
|
||||
}
|
||||
if ((y * 4 + row) == 0) {
|
||||
System.out.print(" Y");
|
||||
} else if ((y * 4 + row) == 1) {
|
||||
System.out.print(" |");
|
||||
} else if ((y * 4 + row) == 2) {
|
||||
System.out.print(" v");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < dim.x; x++) {
|
||||
System.out.print("+------");
|
||||
}
|
||||
System.out.println("+ Z: " + z);
|
||||
for (int i = 0; i < entitiesEncountered.size(); i++) {
|
||||
final Entity entity = entitiesEncountered.get(i);
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(entity.getId());
|
||||
sb.append(", relPos: ");
|
||||
sb.append(Arrays.toString(entity.getRelPos()));
|
||||
CompoundTag nbt = entity.toNBT();
|
||||
if (nbt.containsTag(TAG_FACING_)) {
|
||||
sb.append(", facing: ");
|
||||
sb.append(((ByteTag) nbt.getTag(TAG_FACING_)).getValue());
|
||||
}
|
||||
if (nbt.containsTag(TAG_FACING)) {
|
||||
sb.append(", Facing: ");
|
||||
sb.append(((ByteTag) nbt.getTag(TAG_FACING)).getValue());
|
||||
}
|
||||
System.out.println("*" + (i + 1) + ": " + sb);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
// Standard attribute values
|
||||
int COLLISION_MODE_ALL = 1;
|
||||
int COLLISION_MODE_SOLID = 2;
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package org.pepsoft.util;
|
||||
|
||||
/**
|
||||
* Utility methods for working with arrays.
|
||||
*/
|
||||
public final class ArrayUtils {
|
||||
private ArrayUtils() {
|
||||
// Prevent instantiation
|
||||
}
|
||||
|
||||
public static int indexOf(int[] array, int value) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (array[i] == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue