LZ-#17 - Finish initial implementation

This commit is contained in:
zontreck 2024-04-12 07:52:00 -07:00
parent 059055044d
commit 7d924f7740
13 changed files with 336 additions and 31 deletions

View file

@ -5,7 +5,7 @@ import dev.zontreck.libzontreck.vectors.Vector2i;
import net.minecraft.nbt.CompoundTag;
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

View file

@ -7,7 +7,7 @@ import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
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

View file

@ -11,7 +11,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.Random;
public class BlockRestoreRunner implements Runnable
class BlockRestoreRunner implements Runnable
{
public BlockRestoreRunner(BlockRestoreQueue queue)
{

View file

@ -25,6 +25,7 @@ public class PrimitiveBlock
this.level = level;
this.blockState = blockState;
}
/**
* Alias method
* @see SavedBlock#serialize()
@ -67,4 +68,13 @@ public class PrimitiveBlock
} else return false;
}else return false;
}
/**
* Clones the PrimitiveBlock into a new instance
* @return
*/
public PrimitiveBlock copy()
{
return savedBlock.clone().getBlockPrimitive();
}
}

View file

@ -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";
}
}

View file

@ -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;
}
}
}

View file

@ -12,7 +12,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
public class SavedBlock
public class SavedBlock implements Cloneable
{
private CompoundTag blockState;
private CompoundTag blockEntity;
@ -93,4 +93,20 @@ public class SavedBlock
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();
}
}
}

View file

@ -5,6 +5,7 @@ import dev.zontreck.libzontreck.util.PositionUtil;
import dev.zontreck.libzontreck.vectors.Vector3i;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@ -14,41 +15,22 @@ public class SortedBlockQueue extends BlockRestoreQueue
public String getRestoreQueueName() {
return "SortedBlockQueue";
}
@Override
public void notifyDirtyQueue(boolean blockAdded) {
if(blockAdded) {
// Perform sorting
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()) {
PrimitiveBlock blk = it.next();
positions.add(new Vector3i(blk.position));
}
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;
}
}
// Add blocks in sorted order to the new queue
for (PrimitiveBlock blk : queue) {
retQueue.add(blk.copy()); // Copy block if necessary
}
setQueueNoNotify(retQueue);
}
}
}

View file

@ -3,6 +3,7 @@ package dev.zontreck.libzontreck.vectors;
import dev.zontreck.libzontreck.api.Vector2;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.phys.Vec2;
import org.jetbrains.annotations.NotNull;
public class Vector2f implements Vector2<Float>
{
@ -182,4 +183,18 @@ public class Vector2f implements Vector2<Float>
public Float getY() {
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;
}
}

View file

@ -3,6 +3,7 @@ package dev.zontreck.libzontreck.vectors;
import dev.zontreck.libzontreck.api.Vector2;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.phys.Vec2;
import org.jetbrains.annotations.NotNull;
public class Vector2i implements Vector2<Integer>
{
@ -195,4 +196,18 @@ public class Vector2i implements Vector2<Integer>
public Integer getY() {
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;
}
}

View file

@ -9,6 +9,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
public class Vector3d implements Vector3<Double>
{
@ -234,4 +235,19 @@ public class Vector3d implements Vector3<Double>
public Double getZ() {
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;
}
}

View file

@ -6,6 +6,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@ -227,4 +228,19 @@ public class Vector3i implements Vector3<Integer>
public Integer getZ() {
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;
}
}

View file

@ -4,12 +4,14 @@ import dev.zontreck.libzontreck.LibZontreck;
import dev.zontreck.libzontreck.exceptions.InvalidDeserialization;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.server.ServerLifecycleHooks;
public class WorldPosition {
public class WorldPosition implements Cloneable
{
public Vector3d Position;
public String Dimension;
@ -125,4 +127,16 @@ public class WorldPosition {
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();
}
}
}