LZ-#17 - Finish initial implementation
This commit is contained in:
parent
059055044d
commit
7d924f7740
13 changed files with 336 additions and 31 deletions
|
@ -5,7 +5,7 @@ import dev.zontreck.libzontreck.vectors.Vector2i;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec2;
|
import net.minecraft.world.phys.Vec2;
|
||||||
|
|
||||||
public interface Vector2<T>
|
public interface Vector2<T> extends Cloneable, Comparable<Vector2<T>>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Converts the current Vector2 representation into a minecraft Vec2
|
* Converts the current Vector2 representation into a minecraft Vec2
|
||||||
|
|
|
@ -7,7 +7,7 @@ import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public interface Vector3<T>
|
public interface Vector3<T> extends Cloneable, Comparable<Vector3<T>>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Converts the current Vector3 representation into a minecraft Vec3
|
* Converts the current Vector3 representation into a minecraft Vec3
|
||||||
|
|
|
@ -11,7 +11,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public class BlockRestoreRunner implements Runnable
|
class BlockRestoreRunner implements Runnable
|
||||||
{
|
{
|
||||||
public BlockRestoreRunner(BlockRestoreQueue queue)
|
public BlockRestoreRunner(BlockRestoreQueue queue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,7 @@ public class PrimitiveBlock
|
||||||
this.level = level;
|
this.level = level;
|
||||||
this.blockState = blockState;
|
this.blockState = blockState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias method
|
* Alias method
|
||||||
* @see SavedBlock#serialize()
|
* @see SavedBlock#serialize()
|
||||||
|
@ -67,4 +68,13 @@ public class PrimitiveBlock
|
||||||
} else return false;
|
} else return false;
|
||||||
}else return false;
|
}else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the PrimitiveBlock into a new instance
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public PrimitiveBlock copy()
|
||||||
|
{
|
||||||
|
return savedBlock.clone().getBlockPrimitive();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package dev.zontreck.libzontreck.memory.world;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
|
||||||
|
public class SaveDataCoordinates
|
||||||
|
{
|
||||||
|
public int X;
|
||||||
|
public int Z;
|
||||||
|
|
||||||
|
public SaveDataCoordinates(BlockPos pos)
|
||||||
|
{
|
||||||
|
int X = pos.getX() >> 4 >> 5;
|
||||||
|
int Z = pos.getZ() >> 4 >> 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName()
|
||||||
|
{
|
||||||
|
return "r." + X + "." + Z + ".dat";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
package dev.zontreck.libzontreck.memory.world;
|
||||||
|
|
||||||
|
import dev.zontreck.libzontreck.LibZontreck;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.nbt.NbtIo;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SaveDataFactory
|
||||||
|
{
|
||||||
|
static Map<String, SaveData> datas = new HashMap<>();
|
||||||
|
|
||||||
|
protected static boolean hasSaveDataInstance(SaveDataFile file)
|
||||||
|
{
|
||||||
|
return datas.containsKey(file.getSaveDataPath().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static SaveData getSaveDataInstance(SaveDataFile file)
|
||||||
|
{
|
||||||
|
return datas.get(file.getSaveDataPath().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder()
|
||||||
|
{
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
static class Builder
|
||||||
|
{
|
||||||
|
private String modID = "minecraft";
|
||||||
|
private String levelName;
|
||||||
|
private String queueID;
|
||||||
|
private boolean DBMode;
|
||||||
|
private BlockPos position;
|
||||||
|
|
||||||
|
public Builder withDimension(Level level)
|
||||||
|
{
|
||||||
|
ResourceLocation lv = level.dimension().location();
|
||||||
|
this.modID = lv.getNamespace();
|
||||||
|
this.levelName = lv.getPath();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withQueueID(BlockRestoreQueue queue)
|
||||||
|
{
|
||||||
|
queueID = queue.getRestoreQueueName();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withDatabaseMode()
|
||||||
|
{
|
||||||
|
DBMode=true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withPosition(BlockPos pos)
|
||||||
|
{
|
||||||
|
position = pos;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveDataFile build()
|
||||||
|
{
|
||||||
|
return new SaveDataFile(modID, levelName, queueID, DBMode, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SaveDataFile
|
||||||
|
{
|
||||||
|
String mod;
|
||||||
|
String dimension;
|
||||||
|
String queue;
|
||||||
|
boolean database;
|
||||||
|
BlockPos position;
|
||||||
|
|
||||||
|
public SaveDataFile(String modID, String levelName, String queueID, boolean DBMode, BlockPos pos)
|
||||||
|
{
|
||||||
|
mod = modID;
|
||||||
|
dimension = levelName;
|
||||||
|
queue = queueID;
|
||||||
|
database = DBMode;
|
||||||
|
position = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getSaveDataPath()
|
||||||
|
{
|
||||||
|
Path path = LibZontreck.BASE_CONFIG.resolve("block_snapshots");
|
||||||
|
if(mod != null) path = path.resolve(mod);
|
||||||
|
if(dimension != null) path = path.resolve(dimension);
|
||||||
|
if(queue != null) path = path.resolve(queue);
|
||||||
|
|
||||||
|
path.toFile().mkdirs();
|
||||||
|
|
||||||
|
SaveDataCoordinates coordinates = new SaveDataCoordinates(position);
|
||||||
|
path = path.resolve(coordinates.getFileName());
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the save data, or initializes a new instance.
|
||||||
|
* <p></p>
|
||||||
|
* Additionally, this will check for a pre-existing POJO instance and return if it exists.
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public SaveData getInstance() throws IOException {
|
||||||
|
if(SaveDataFactory.hasSaveDataInstance(this)) return SaveDataFactory.getSaveDataInstance(this);
|
||||||
|
Path data = getSaveDataPath();
|
||||||
|
if(data.toFile().exists())
|
||||||
|
{
|
||||||
|
CompoundTag tag = NbtIo.read(data.toFile());
|
||||||
|
|
||||||
|
return SaveData.deserialize(tag, this);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return new SaveData(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SaveData {
|
||||||
|
SaveDataFile myFile;
|
||||||
|
public static final String TAG_SAVED_BLOCKS = "sb";
|
||||||
|
|
||||||
|
public List<SavedBlock> blocks = new ArrayList<>();
|
||||||
|
|
||||||
|
public SaveData(SaveDataFile file)
|
||||||
|
{
|
||||||
|
myFile = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a NBT Tag and reconstruct the SaveData POJO
|
||||||
|
* @param tag
|
||||||
|
* @param file
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static SaveData deserialize(CompoundTag tag, SaveDataFile file) {
|
||||||
|
SaveData data = new SaveData(file);
|
||||||
|
ListTag lst = tag.getList(TAG_SAVED_BLOCKS, ListTag.TAG_COMPOUND);
|
||||||
|
for(Tag xTag : lst)
|
||||||
|
{
|
||||||
|
if(xTag instanceof CompoundTag ct)
|
||||||
|
{
|
||||||
|
SavedBlock sb = SavedBlock.deserialize(ct);
|
||||||
|
data.blocks.add(sb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the current save data to NBT
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CompoundTag serialize()
|
||||||
|
{
|
||||||
|
CompoundTag tag = new CompoundTag();
|
||||||
|
ListTag lst = new ListTag();
|
||||||
|
for(SavedBlock block : blocks)
|
||||||
|
{
|
||||||
|
lst.add(block.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.put(TAG_SAVED_BLOCKS, lst);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports a full queue to the save data file.
|
||||||
|
* ! WARNING ! This method will overwrite the SaveDataFile's Queue ID
|
||||||
|
* @param queue Queue to import
|
||||||
|
* @return The current SaveData instance
|
||||||
|
*/
|
||||||
|
public SaveData importQueue(BlockRestoreQueue queue)
|
||||||
|
{
|
||||||
|
for(PrimitiveBlock blk : queue.getQueue())
|
||||||
|
{
|
||||||
|
blocks.add(blk.savedBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
myFile.queue = queue.getRestoreQueueName();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
public class SavedBlock
|
public class SavedBlock implements Cloneable
|
||||||
{
|
{
|
||||||
private CompoundTag blockState;
|
private CompoundTag blockState;
|
||||||
private CompoundTag blockEntity;
|
private CompoundTag blockEntity;
|
||||||
|
@ -93,4 +93,20 @@ public class SavedBlock
|
||||||
return new PrimitiveBlock(this, state.getBlock(), state, blockEntity, position.Position.asBlockPos(), level);
|
return new PrimitiveBlock(this, state.getBlock(), state, blockEntity, position.Position.asBlockPos(), level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SavedBlock clone() {
|
||||||
|
try {
|
||||||
|
SavedBlock clone = (SavedBlock) super.clone();
|
||||||
|
if(blockEntity != null)
|
||||||
|
clone.blockEntity = blockEntity.copy();
|
||||||
|
if(blockState != null)
|
||||||
|
clone.blockState = blockState.copy();
|
||||||
|
if(position != null)
|
||||||
|
clone.position = position.clone();
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import dev.zontreck.libzontreck.util.PositionUtil;
|
||||||
import dev.zontreck.libzontreck.vectors.Vector3i;
|
import dev.zontreck.libzontreck.vectors.Vector3i;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -14,41 +15,22 @@ public class SortedBlockQueue extends BlockRestoreQueue
|
||||||
public String getRestoreQueueName() {
|
public String getRestoreQueueName() {
|
||||||
return "SortedBlockQueue";
|
return "SortedBlockQueue";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyDirtyQueue(boolean blockAdded) {
|
public void notifyDirtyQueue(boolean blockAdded) {
|
||||||
if(blockAdded) {
|
if(blockAdded) {
|
||||||
// Perform sorting
|
|
||||||
|
|
||||||
List<PrimitiveBlock> queue = getQueue();
|
List<PrimitiveBlock> queue = getQueue();
|
||||||
List<Vector3> positions = new ArrayList<>();
|
List<PrimitiveBlock> retQueue = new ArrayList<>(queue.size());
|
||||||
|
|
||||||
Iterator<PrimitiveBlock> it = queue.iterator();
|
// Sort the queue based on block positions
|
||||||
|
queue.sort(Comparator.comparing(block -> new Vector3i(block.position)));
|
||||||
|
|
||||||
while(it.hasNext()) {
|
// Add blocks in sorted order to the new queue
|
||||||
PrimitiveBlock blk = it.next();
|
for (PrimitiveBlock blk : queue) {
|
||||||
positions.add(new Vector3i(blk.position));
|
retQueue.add(blk.copy()); // Copy block if necessary
|
||||||
}
|
|
||||||
|
|
||||||
positions = PositionUtil.sortAscending(positions);
|
|
||||||
|
|
||||||
List<PrimitiveBlock> retQueue = new ArrayList<>();
|
|
||||||
|
|
||||||
it = queue.iterator();
|
|
||||||
for(Vector3 pos : positions) {
|
|
||||||
it = queue.iterator();
|
|
||||||
while(it.hasNext()) {
|
|
||||||
PrimitiveBlock blk = it.next();
|
|
||||||
if(blk.position.equals(pos.asBlockPos())) {
|
|
||||||
retQueue.add(blk);
|
|
||||||
it.remove();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setQueueNoNotify(retQueue);
|
setQueueNoNotify(retQueue);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package dev.zontreck.libzontreck.vectors;
|
||||||
import dev.zontreck.libzontreck.api.Vector2;
|
import dev.zontreck.libzontreck.api.Vector2;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec2;
|
import net.minecraft.world.phys.Vec2;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class Vector2f implements Vector2<Float>
|
public class Vector2f implements Vector2<Float>
|
||||||
{
|
{
|
||||||
|
@ -182,4 +183,18 @@ public class Vector2f implements Vector2<Float>
|
||||||
public Float getY() {
|
public Float getY() {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull Vector2<Float> other) {
|
||||||
|
if(other instanceof Vector2f v2f){
|
||||||
|
|
||||||
|
// Compare x coordinates first
|
||||||
|
int cmp = Float.compare(this.x, v2f.x);
|
||||||
|
if (cmp != 0) {
|
||||||
|
return cmp;
|
||||||
|
}
|
||||||
|
// If x coordinates are equal, compare y coordinates
|
||||||
|
return Float.compare(this.y, v2f.y);
|
||||||
|
} else return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package dev.zontreck.libzontreck.vectors;
|
||||||
import dev.zontreck.libzontreck.api.Vector2;
|
import dev.zontreck.libzontreck.api.Vector2;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec2;
|
import net.minecraft.world.phys.Vec2;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class Vector2i implements Vector2<Integer>
|
public class Vector2i implements Vector2<Integer>
|
||||||
{
|
{
|
||||||
|
@ -195,4 +196,18 @@ public class Vector2i implements Vector2<Integer>
|
||||||
public Integer getY() {
|
public Integer getY() {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull Vector2<Integer> other) {
|
||||||
|
if(other instanceof Vector2i v2i){
|
||||||
|
|
||||||
|
// Compare x coordinates first
|
||||||
|
int cmp = Integer.compare(this.x, v2i.x);
|
||||||
|
if (cmp != 0) {
|
||||||
|
return cmp;
|
||||||
|
}
|
||||||
|
// If x coordinates are equal, compare y coordinates
|
||||||
|
return Integer.compare(this.y, v2i.y);
|
||||||
|
} else return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class Vector3d implements Vector3<Double>
|
public class Vector3d implements Vector3<Double>
|
||||||
{
|
{
|
||||||
|
@ -234,4 +235,19 @@ public class Vector3d implements Vector3<Double>
|
||||||
public Double getZ() {
|
public Double getZ() {
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull Vector3<Double> doubleVector3) {
|
||||||
|
if(doubleVector3 instanceof Vector3d v3d)
|
||||||
|
{
|
||||||
|
int Ycomp = Double.compare(y, v3d.y);
|
||||||
|
if(Ycomp!=0)return Ycomp;
|
||||||
|
int Zcomp = Double.compare(z, v3d.z);
|
||||||
|
if(Zcomp!=0)return Zcomp;
|
||||||
|
int Xcomp = Double.compare(x, v3d.x);
|
||||||
|
if(Xcomp!=0)return Xcomp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -227,4 +228,19 @@ public class Vector3i implements Vector3<Integer>
|
||||||
public Integer getZ() {
|
public Integer getZ() {
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull Vector3<Integer> integerVector3) {
|
||||||
|
if(integerVector3 instanceof Vector3i v3i)
|
||||||
|
{
|
||||||
|
int Ycomp = Integer.compare(y, v3i.y);
|
||||||
|
if(Ycomp!=0)return Ycomp;
|
||||||
|
int Zcomp = Integer.compare(z, v3i.z);
|
||||||
|
if(Zcomp!=0)return Zcomp;
|
||||||
|
int Xcomp = Integer.compare(x, v3i.x);
|
||||||
|
if(Xcomp!=0)return Xcomp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,14 @@ import dev.zontreck.libzontreck.LibZontreck;
|
||||||
import dev.zontreck.libzontreck.exceptions.InvalidDeserialization;
|
import dev.zontreck.libzontreck.exceptions.InvalidDeserialization;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtUtils;
|
import net.minecraft.nbt.NbtUtils;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraftforge.server.ServerLifecycleHooks;
|
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||||
|
|
||||||
public class WorldPosition {
|
public class WorldPosition implements Cloneable
|
||||||
|
{
|
||||||
|
|
||||||
public Vector3d Position;
|
public Vector3d Position;
|
||||||
public String Dimension;
|
public String Dimension;
|
||||||
|
@ -125,4 +127,16 @@ public class WorldPosition {
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorldPosition clone() {
|
||||||
|
try {
|
||||||
|
WorldPosition clone = (WorldPosition) super.clone();
|
||||||
|
if(Position != null)
|
||||||
|
clone.Position = Position.Clone();
|
||||||
|
return clone;
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue