mirror of
https://github.com/LegacyModdingMC/ChunkAPI.git
synced 2026-11-15 01:35:07 +00:00
Implement AnvilChunkLoader coupling
This commit is contained in:
13 files changed
+477
-92
No files matched your search
@@ -1,62 +1,122 @@
|
||||
package com.falsepattern.chunk.api;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Singleton instances that can manage custom in chunks.
|
||||
* <p>
|
||||
* Implementations should be stateless and thread-safe.
|
||||
* @implNote For performance reasons, you should store any data in the chunk itself using a mixin. The type T is the type
|
||||
* of the interface that you are mixing into the chunk.
|
||||
* Singleton instances that can manage custom in chunks. This class only manages the registration of
|
||||
* managers. For the actual networking and data storage, see the internal interfaces of this interface.
|
||||
* Note: This interface does nothing by itself, you also need to implement one or more of the internal interfaces.
|
||||
* One class can have multiple
|
||||
*/
|
||||
public interface ChunkDataManager<T> {
|
||||
public interface ChunkDataManager {
|
||||
|
||||
/**
|
||||
* @return The domain of this manager. Usually the modid of the mod that owns this manager.
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
String domain();
|
||||
|
||||
/**
|
||||
* @return The id of this manager. Usually the name of the manager. Unique per domain.
|
||||
*/
|
||||
|
||||
@Contract(pure = true)
|
||||
String id();
|
||||
|
||||
/**
|
||||
* @implNote This is used to determine the size of the packet compression/decompression buffer.
|
||||
* @return The maximum amount of bytes your data can take up in a packet.
|
||||
* Implement this interface if you want to synchronize your data with the client.
|
||||
*/
|
||||
int maxPacketSize();
|
||||
interface PacketDataManager extends ChunkDataManager {
|
||||
/**
|
||||
* @implNote This is used to determine the size of the packet compression/decompression buffer.
|
||||
* @return The maximum amount of bytes your data can take up in a packet.
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
int maxPacketSize();
|
||||
|
||||
/**
|
||||
* Serializes your data into a packet.
|
||||
*
|
||||
* @param chunk The chunk to serialize.
|
||||
*/
|
||||
void writeToBuffer(Chunk chunk, int ebsMask, boolean forceUpdate, ByteBuffer data);
|
||||
|
||||
/**
|
||||
* Deserializes your data from a packet.
|
||||
* Mutates this object.
|
||||
*
|
||||
* @param chunk The chunk to deserialize.
|
||||
* @param buffer The packet buffer to read from.
|
||||
*/
|
||||
void readFromBuffer(Chunk chunk, int ebsMask, boolean forceUpdate, ByteBuffer buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes your data into a packet.
|
||||
*
|
||||
* @param chunk The chunk to serialize.
|
||||
* Implement this interface if you want to save your data to disk. This is called once per chunk.
|
||||
*/
|
||||
void writeToBuffer(T chunk, int ebsMask, boolean forceUpdate, ByteBuffer data);
|
||||
interface ChunkNBTDataManager extends ChunkDataManager {
|
||||
/**
|
||||
* If false, the given nbt compound will be a freshly created object that gets inserted into the actual
|
||||
* level NBT tag under the `domain:id` name.
|
||||
* <p>
|
||||
* If true, the nbt tag passed in into the write/read methods will be the raw Level NBT tag without filtering.
|
||||
*
|
||||
* @implNote This is used internally for reimplementing the vanilla logic. Only change this if you know what you're doing.
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
default boolean chunkPrivilegedAccess() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes your data into an NBT tag. This is used when saving the chunk to disk.
|
||||
*/
|
||||
void writeChunkToNBT(Chunk chunk, NBTTagCompound nbt);
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes your data from an NBT tag. This is used when loading the chunk from disk.
|
||||
* The NBT *may* be null if the chunk was saved before this manager was registered
|
||||
* (e.g., loading save before the mod was added), and the manager is not {@link #chunkPrivilegedAccess() privileged}.
|
||||
* In this case, you should initialize the data to a sane default.
|
||||
*/
|
||||
void readChunkFromNBT(Chunk chunk, NBTTagCompound nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes your data from a packet.
|
||||
* Mutates this object.
|
||||
*
|
||||
* @param chunk The chunk to deserialize.
|
||||
* @param buffer The packet buffer to read from.
|
||||
* Implement this interface if you want to save your ExtendedBlockStorage data to disk. This is called once per
|
||||
* ExtendedBlockStorage per chunk. (16 times per chunk)
|
||||
*/
|
||||
void readFromBuffer(T chunk, int ebsMask, boolean forceUpdate, ByteBuffer buffer);
|
||||
interface SectionNBTDataManager extends ChunkDataManager {
|
||||
/**
|
||||
* If false, the given nbt compound will be a freshly created object that gets inserted into the actual
|
||||
* segment NBT tag under the `domain:id` name.
|
||||
* <p>
|
||||
* If true, the nbt tag passed in into the write/read methods will be the raw segment NBT tag without filtering.
|
||||
*
|
||||
* @implNote This is used internally for reimplementing the vanilla logic. Only change this if you know what you're doing.
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
default boolean sectionPrivilegedAccess() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Serializes your data into an NBT tag. This is used when saving the chunk to disk.
|
||||
*/
|
||||
void writeSectionToNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section);
|
||||
|
||||
/**
|
||||
* Serializes your data into an NBT tag. This is used when saving the chunk to disk.
|
||||
* @param tag The tag to write to.
|
||||
*/
|
||||
void writeToNBT(T chunk, @NotNull NBTTagCompound tag);
|
||||
|
||||
/**
|
||||
* Deserializes your data from an NBT tag. This is used when loading the chunk from disk.
|
||||
* Mutates this object.
|
||||
* @param tag The tag to read from.
|
||||
*/
|
||||
void readFromNBT(T chunk, @NotNull NBTTagCompound tag);
|
||||
/**
|
||||
* Deserializes your data from an NBT tag. This is used when loading the chunk from disk.
|
||||
* The NBT *may* be null if the chunk was saved before this manager was registered
|
||||
* (e.g., loading save before the mod was added), and the manager is not {@link #sectionPrivilegedAccess() privileged}.
|
||||
* In this case, you should initialize the data to a sane default.
|
||||
*/
|
||||
void readSectionFromNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class ChunkDataRegistry {
|
||||
* @throws IllegalStateException If the registration stage is over.
|
||||
* @throws IllegalArgumentException If the manager has a duplicate id.
|
||||
*/
|
||||
public static void registerDataManager(ChunkDataManager<?> manager) throws IllegalStateException, IllegalArgumentException {
|
||||
public static void registerDataManager(ChunkDataManager manager) throws IllegalStateException, IllegalArgumentException {
|
||||
ChunkDataRegistryImpl.registerDataManager(manager);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,28 +4,35 @@ import com.falsepattern.chunk.api.ChunkDataManager;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ChunkDataRegistryImpl {
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final Map<String, ChunkDataManager> managers = new HashMap<>();
|
||||
private static final Set<String> managers = new HashSet<>();
|
||||
private static final Map<String, ChunkDataManager.PacketDataManager> packetManagers = new HashMap<>();
|
||||
private static final Map<String, ChunkDataManager.ChunkNBTDataManager> chunkNBTManagers = new HashMap<>();
|
||||
private static final Map<String, ChunkDataManager.SectionNBTDataManager> sectionNBTManagers = new HashMap<>();
|
||||
private static final Set<String> disabledManagers = new HashSet<>();
|
||||
private static int maxPacketSize = 0;
|
||||
public static void registerDataManager(ChunkDataManager<?> manager) throws IllegalStateException, IllegalArgumentException {
|
||||
private static int maxPacketSize = 4;
|
||||
public static void registerDataManager(ChunkDataManager manager) throws IllegalStateException, IllegalArgumentException {
|
||||
if (!ChunkAPI.isRegistrationStage()) {
|
||||
throw new IllegalStateException("ChunkDataManager registration is not allowed at this time! " +
|
||||
"Please register your ChunkDataManager in the preInit phase of your mod.");
|
||||
}
|
||||
var id = manager.domain() + ":" + manager.id();
|
||||
if (managers.containsKey(id)) {
|
||||
if (managers.contains(id)) {
|
||||
throw new IllegalArgumentException("ChunkDataManager " + manager + " has a duplicate id!");
|
||||
}
|
||||
|
||||
@@ -34,9 +41,19 @@ public class ChunkDataRegistryImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
managers.put(id, manager);
|
||||
maxPacketSize += 4 + id.getBytes(StandardCharsets.UTF_8).length;
|
||||
maxPacketSize += manager.maxPacketSize();
|
||||
managers.add(id);
|
||||
if (manager instanceof ChunkDataManager.PacketDataManager) {
|
||||
val packetManager = (ChunkDataManager.PacketDataManager) manager;
|
||||
maxPacketSize += 4 + id.getBytes(StandardCharsets.UTF_8).length;
|
||||
maxPacketSize += packetManager.maxPacketSize();
|
||||
packetManagers.put(id, packetManager);
|
||||
}
|
||||
if (manager instanceof ChunkDataManager.ChunkNBTDataManager) {
|
||||
chunkNBTManagers.put(id, (ChunkDataManager.ChunkNBTDataManager) manager);
|
||||
}
|
||||
if (manager instanceof ChunkDataManager.SectionNBTDataManager) {
|
||||
sectionNBTManagers.put(id, (ChunkDataManager.SectionNBTDataManager) manager);
|
||||
}
|
||||
}
|
||||
|
||||
public static void disableDataManager(String domain, String id) {
|
||||
@@ -44,17 +61,22 @@ public class ChunkDataRegistryImpl {
|
||||
throw new IllegalStateException("ChunkDataManager disabling is not allowed at this time! " +
|
||||
"Please disable any ChunkDataManagers in the preInit/init phases.");
|
||||
}
|
||||
id = domain + ":" + id;
|
||||
Common.LOG.warn("Disabling ChunkDataManager " + id + ". See the stacktrace for the source of this event.", new Throwable());
|
||||
Common.LOG.warn("Disabling ChunkDataManager " + id + " in domain " + domain + ". See the stacktrace for the source of this event.", new Throwable());
|
||||
val manager = domain + ":" + id;
|
||||
//Remove the manager from the list of managers, if it exists
|
||||
val removed = managers.remove(id);
|
||||
if (removed != null) {
|
||||
maxPacketSize -= 4 + id.getBytes(StandardCharsets.UTF_8).length;
|
||||
maxPacketSize -= removed.maxPacketSize();
|
||||
if (managers.remove(manager)) {
|
||||
//Clear the maps
|
||||
if (packetManagers.containsKey(id)) {
|
||||
val removed = packetManagers.remove(id);
|
||||
maxPacketSize -= 4 + id.getBytes(StandardCharsets.UTF_8).length;
|
||||
maxPacketSize -= removed.maxPacketSize();
|
||||
}
|
||||
chunkNBTManagers.remove(id);
|
||||
sectionNBTManagers.remove(id);
|
||||
}
|
||||
|
||||
//Add the manager to the list of disabled managers, in case it gets registered after this disable call.
|
||||
disabledManagers.add(id);
|
||||
disabledManagers.add(manager);
|
||||
}
|
||||
|
||||
public static int maxPacketSize() {
|
||||
@@ -74,7 +96,6 @@ public class ChunkDataRegistryImpl {
|
||||
return new String(bytes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void readFromBuffer(Chunk chunk, int ebsMask, boolean forceUpdate, byte[] data) {
|
||||
val buf = ByteBuffer.wrap(data);
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
@@ -82,9 +103,9 @@ public class ChunkDataRegistryImpl {
|
||||
for (int i = 0; i < count; i++) {
|
||||
val id = readString(buf);
|
||||
val length = buf.getInt();
|
||||
val manager = managers.get(id);
|
||||
val manager = packetManagers.get(id);
|
||||
if (manager == null) {
|
||||
Common.LOG.error("Received data for unknown ChunkDataManager " + id + ". Skipping.");
|
||||
Common.LOG.error("Received data for unknown PacketDataManager " + id + ". Skipping.");
|
||||
buf.position(buf.position() + length);
|
||||
continue;
|
||||
}
|
||||
@@ -95,14 +116,14 @@ public class ChunkDataRegistryImpl {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static int writeToBuffer(Chunk chunk, int ebsMask, boolean forceUpdate, byte[] data) {
|
||||
val buf = ByteBuffer.wrap(data);
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.putInt(managers.size());
|
||||
for (val pair: managers.entrySet()) {
|
||||
buf.putInt(packetManagers.size());
|
||||
for (val pair: packetManagers.entrySet()) {
|
||||
val id = pair.getKey();
|
||||
val manager = pair.getValue();
|
||||
writeString(buf, pair.getKey());
|
||||
writeString(buf, id);
|
||||
int start = buf.position() + 4;
|
||||
val slice = createSlice(buf, start, manager.maxPacketSize());
|
||||
manager.writeToBuffer(chunk, ebsMask, forceUpdate, slice);
|
||||
@@ -123,4 +144,60 @@ public class ChunkDataRegistryImpl {
|
||||
buffer.position(oldPosition);
|
||||
return slice;
|
||||
}
|
||||
|
||||
private static NBTTagCompound createManagerNBT(boolean privileged, NBTTagCompound root, ChunkDataManager manager) {
|
||||
if (privileged) {
|
||||
return root;
|
||||
}
|
||||
val domain = manager.domain();
|
||||
NBTTagCompound domainNBT;
|
||||
if (root.hasKey(domain)) {
|
||||
domainNBT = new NBTTagCompound();
|
||||
root.setTag(domain, domainNBT);
|
||||
} else {
|
||||
domainNBT = root.getCompoundTag(domain);
|
||||
}
|
||||
val subNBT = new NBTTagCompound();
|
||||
domainNBT.setTag(manager.id(), subNBT);
|
||||
return subNBT;
|
||||
}
|
||||
|
||||
private static NBTTagCompound getManagerNBT(boolean privileged, NBTTagCompound root, ChunkDataManager manager) {
|
||||
if (privileged) {
|
||||
return root;
|
||||
}
|
||||
val domain = manager.domain();
|
||||
if (!root.hasKey(domain)) {
|
||||
return null;
|
||||
}
|
||||
val domainNBT = root.getCompoundTag(domain);
|
||||
if (!domainNBT.hasKey(manager.id())) {
|
||||
return null;
|
||||
}
|
||||
return domainNBT.getCompoundTag(manager.id());
|
||||
}
|
||||
|
||||
public static void writeSectionToNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound sectionNBT) {
|
||||
for (val manager: sectionNBTManagers.values()) {
|
||||
manager.writeSectionToNBT(chunk, ebs, createManagerNBT(manager.sectionPrivilegedAccess(), sectionNBT, manager));
|
||||
}
|
||||
}
|
||||
|
||||
public static void readSectionFromNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound sectionNBT) {
|
||||
for (val manager: sectionNBTManagers.values()) {
|
||||
manager.readSectionFromNBT(chunk, ebs, getManagerNBT(manager.sectionPrivilegedAccess(), sectionNBT, manager));
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeChunkToNBT(Chunk chunk, NBTTagCompound chunkNBT) {
|
||||
for (val manager: chunkNBTManagers.values()) {
|
||||
manager.writeChunkToNBT(chunk, createManagerNBT(manager.chunkPrivilegedAccess(), chunkNBT, manager));
|
||||
}
|
||||
}
|
||||
|
||||
public static void readChunkFromNBT(Chunk chunk, NBTTagCompound chunkNBT) {
|
||||
for (val manager: chunkNBTManagers.values()) {
|
||||
manager.readChunkFromNBT(chunk, getManagerNBT(manager.chunkPrivilegedAccess(), chunkNBT, manager));
|
||||
}
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package com.falsepattern.chunk.internal.mixin.mixins.common.vanilla;
|
||||
|
||||
import com.falsepattern.chunk.internal.ChunkDataRegistryImpl;
|
||||
import lombok.val;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.NextTickListEntry;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(AnvilChunkLoader.class)
|
||||
public abstract class AnvilChunkLoaderMixin {
|
||||
/**
|
||||
* Writes the Chunk passed as an argument to the NBTTagCompound also passed, using the World argument to retrieve
|
||||
* the Chunk's last update time.
|
||||
* @author FalsePattern
|
||||
* @reason Replace functionality
|
||||
*/
|
||||
@Overwrite
|
||||
private void writeChunkToNBT(Chunk chunk, World world, NBTTagCompound nbt) {
|
||||
nbt.setByte("V", (byte)1);
|
||||
nbt.setInteger("xPos", chunk.xPosition);
|
||||
nbt.setInteger("zPos", chunk.zPosition);
|
||||
System.out.println("Saving chunk " + chunk.xPosition + ", " + chunk.zPosition);
|
||||
nbt.setLong("LastUpdate", world.getTotalWorldTime());
|
||||
nbt.setIntArray("HeightMap", chunk.heightMap);
|
||||
nbt.setBoolean("TerrainPopulated", chunk.isTerrainPopulated);
|
||||
nbt.setBoolean("LightPopulated", chunk.isLightPopulated);
|
||||
nbt.setLong("InhabitedTime", chunk.inhabitedTime);
|
||||
writeSections(chunk, nbt);
|
||||
writeCustomData(chunk, nbt);
|
||||
writeEntities(chunk, world, nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the data stored in the given NBTTagCompound and creates a Chunk with that data in the given World.
|
||||
* Returns the created Chunk.
|
||||
* @author FalsePattern
|
||||
* @reason Replace functionality
|
||||
*/
|
||||
@Overwrite
|
||||
private Chunk readChunkFromNBT(World world, NBTTagCompound nbt) {
|
||||
int x = nbt.getInteger("xPos");
|
||||
int z = nbt.getInteger("zPos");
|
||||
System.out.println("Loading chunk " + x + ", " + z );
|
||||
Chunk chunk = new Chunk(world, x, z);
|
||||
chunk.heightMap = nbt.getIntArray("HeightMap");
|
||||
chunk.isTerrainPopulated = nbt.getBoolean("TerrainPopulated");
|
||||
chunk.isLightPopulated = nbt.getBoolean("LightPopulated");
|
||||
chunk.inhabitedTime = nbt.getLong("InhabitedTime");
|
||||
readSections(chunk, nbt);
|
||||
readCustomData(chunk, nbt);
|
||||
|
||||
// End this method here and split off entity loading to another method
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private void readCustomData(Chunk chunk, NBTTagCompound nbt) {
|
||||
ChunkDataRegistryImpl.readChunkFromNBT(chunk, nbt);
|
||||
}
|
||||
|
||||
private void readSections(Chunk chunk, NBTTagCompound nbt) {
|
||||
NBTTagList sections = nbt.getTagList("Sections", 10);
|
||||
byte segments = 16;
|
||||
ExtendedBlockStorage[] ebsList = new ExtendedBlockStorage[segments];
|
||||
|
||||
for (int k = 0; k < sections.tagCount(); ++k) {
|
||||
NBTTagCompound section = sections.getCompoundTagAt(k);
|
||||
byte yLevel = section.getByte("Y");
|
||||
ExtendedBlockStorage ebs = new ExtendedBlockStorage(yLevel << 4, !chunk.worldObj.provider.hasNoSky);
|
||||
ChunkDataRegistryImpl.readSectionFromNBT(chunk, ebs, section);
|
||||
|
||||
ebs.removeInvalidBlocks();
|
||||
ebsList[yLevel] = ebs;
|
||||
}
|
||||
|
||||
chunk.setStorageArrays(ebsList);
|
||||
}
|
||||
|
||||
private void writeCustomData(Chunk chunk, NBTTagCompound nbt) {
|
||||
ChunkDataRegistryImpl.writeChunkToNBT(chunk, nbt);
|
||||
}
|
||||
|
||||
private void writeSections(Chunk chunk, NBTTagCompound nbt) {
|
||||
ExtendedBlockStorage[] ebsList = chunk.getBlockStorageArray();
|
||||
NBTTagList sections = new NBTTagList();
|
||||
NBTTagCompound section;
|
||||
|
||||
for (ExtendedBlockStorage ebs: ebsList) {
|
||||
if (ebs != null) {
|
||||
section = new NBTTagCompound();
|
||||
section.setByte("Y", (byte) (ebs.getYLocation() >> 4 & 255));
|
||||
ChunkDataRegistryImpl.writeSectionToNBT(chunk, ebs, section);
|
||||
sections.appendTag(section);
|
||||
}
|
||||
}
|
||||
|
||||
nbt.setTag("Sections", sections);
|
||||
}
|
||||
|
||||
private void writeEntities(Chunk chunk, World world, NBTTagCompound nbt) {
|
||||
chunk.hasEntities = false;
|
||||
NBTTagList entities = new NBTTagList();
|
||||
|
||||
for (int i = 0; i < chunk.entityLists.length; ++i) {
|
||||
for (Object o: chunk.entityLists[i]) {
|
||||
Entity entity = (Entity) o;
|
||||
val entityNBT = new NBTTagCompound();
|
||||
|
||||
try {
|
||||
if (entity.writeToNBTOptional(entityNBT)) {
|
||||
chunk.hasEntities = true;
|
||||
entities.appendTag(entityNBT);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FMLLog.log(Level.ERROR, e,
|
||||
"An Entity type %s has thrown an exception trying to write state. It will not persist. Report this to the mod author",
|
||||
entity.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nbt.setTag("Entities", entities);
|
||||
NBTTagList tileEntities = new NBTTagList();
|
||||
|
||||
for (Object o: chunk.chunkTileEntityMap.values()) {
|
||||
TileEntity tileentity = (TileEntity) o;
|
||||
val tileEntityNBT = new NBTTagCompound();
|
||||
try {
|
||||
tileentity.writeToNBT(tileEntityNBT);
|
||||
tileEntities.appendTag(tileEntityNBT);
|
||||
} catch (Exception e) {
|
||||
FMLLog.log(Level.ERROR, e,
|
||||
"A TileEntity type %s has throw an exception trying to write state. It will not persist. Report this to the mod author",
|
||||
tileentity.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
nbt.setTag("TileEntities", tileEntities);
|
||||
List<?> pendingUpdates = world.getPendingBlockUpdates(chunk, false);
|
||||
|
||||
if (pendingUpdates != null) {
|
||||
long k = world.getTotalWorldTime();
|
||||
NBTTagList tileTicks = new NBTTagList();
|
||||
|
||||
for (Object o : pendingUpdates) {
|
||||
NextTickListEntry update = (NextTickListEntry) o;
|
||||
NBTTagCompound updateNBT = new NBTTagCompound();
|
||||
updateNBT.setInteger("i", Block.getIdFromBlock(update.func_151351_a()));
|
||||
updateNBT.setInteger("x", update.xCoord);
|
||||
updateNBT.setInteger("y", update.yCoord);
|
||||
updateNBT.setInteger("z", update.zCoord);
|
||||
updateNBT.setInteger("t", (int) (update.scheduledTime - k));
|
||||
updateNBT.setInteger("p", update.priority);
|
||||
tileTicks.appendTag(updateNBT);
|
||||
}
|
||||
|
||||
nbt.setTag("TileTicks", tileTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -53,7 +53,6 @@ public abstract class S21PacketChunkDataMixin {
|
||||
if (buffer.length < ChunkDataRegistryImpl.maxPacketSize()) {
|
||||
buffer = new byte[ChunkDataRegistryImpl.maxPacketSize()];
|
||||
}
|
||||
val data = buffer;
|
||||
|
||||
if (forceUpdate) {
|
||||
chunk.sendUpdates = true;
|
||||
@@ -65,10 +64,10 @@ public abstract class S21PacketChunkDataMixin {
|
||||
}
|
||||
}
|
||||
|
||||
int length = ChunkDataRegistryImpl.writeToBuffer(chunk, extracted.field_150280_b, forceUpdate, data);
|
||||
int length = ChunkDataRegistryImpl.writeToBuffer(chunk, extracted.field_150280_b, forceUpdate, buffer);
|
||||
|
||||
extracted.field_150282_a = new byte[length];
|
||||
System.arraycopy(data, 0, extracted.field_150282_a, 0, length);
|
||||
System.arraycopy(buffer, 0, extracted.field_150282_a, 0, length);
|
||||
return extracted;
|
||||
}
|
||||
|
||||
@@ -90,6 +89,7 @@ public abstract class S21PacketChunkDataMixin {
|
||||
}
|
||||
data.writeInt(xPosition);
|
||||
data.writeInt(zPosition);
|
||||
System.out.println("Writing chunk packet (" + xPosition + ", " + zPosition + ")");
|
||||
data.writeBoolean(forceUpdate);
|
||||
data.writeShort((short)(ebsMask & 0xFFFF));
|
||||
data.writeInt(this.data.length);
|
||||
@@ -105,6 +105,7 @@ public abstract class S21PacketChunkDataMixin {
|
||||
public void readPacketData(PacketBuffer data) throws IOException {
|
||||
xPosition = data.readInt();
|
||||
zPosition = data.readInt();
|
||||
System.out.println("Reading chunk packet (" + xPosition + ", " + zPosition + ")");
|
||||
forceUpdate = data.readBoolean();
|
||||
ebsMask = data.readShort() & 0xFFFF;
|
||||
this.data = new byte[data.readInt()];
|
||||
|
||||
@@ -36,6 +36,7 @@ import static com.falsepattern.lib.mixin.IMixin.PredicateHelpers.always;
|
||||
@RequiredArgsConstructor
|
||||
public enum Mixin implements IMixin {
|
||||
// @formatter:off
|
||||
AnvilChunkLoaderMixin(Side.COMMON, always(), "vanilla.AnvilChunkLoaderMixin"),
|
||||
S21PacketChunkDataMixin(Side.COMMON, always(), "vanilla.S21PacketChunkDataMixin"),
|
||||
S26PacketMapChunkBulkMixin(Side.COMMON, always(), "vanilla.S26PacketMapChunkBulkMixin"),
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package com.falsepattern.chunk.internal.vanilla;
|
||||
|
||||
import com.falsepattern.chunk.api.ChunkDataManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BiomeManager extends VanillaManager {
|
||||
public class BiomeManager extends VanillaManager implements ChunkDataManager.PacketDataManager, ChunkDataManager.ChunkNBTDataManager {
|
||||
public static final int BYTES_PER_CHUNK = 256;
|
||||
|
||||
@Override
|
||||
@@ -21,26 +24,34 @@ public class BiomeManager extends VanillaManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToBuffer(Chunk chunk, int ebsMask, boolean forceUpdate, ByteBuffer data) {
|
||||
public void writeToBuffer(@NotNull Chunk chunk, int ebsMask, boolean forceUpdate, @NotNull ByteBuffer data) {
|
||||
if (forceUpdate) {
|
||||
data.put(chunk.getBiomeArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromBuffer(Chunk chunk, int ebsMask, boolean forceUpdate, ByteBuffer buffer) {
|
||||
public void readFromBuffer(@NotNull Chunk chunk, int ebsMask, boolean forceUpdate, @NotNull ByteBuffer buffer) {
|
||||
if (forceUpdate) {
|
||||
buffer.get(chunk.getBiomeArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(Chunk chunk, @NotNull NBTTagCompound tag) {
|
||||
public boolean chunkPrivilegedAccess() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void writeChunkToNBT(@NotNull Chunk chunk, @NotNull NBTTagCompound nbt) {
|
||||
nbt.setByteArray("Biomes", chunk.getBiomeArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(Chunk chunk, @NotNull NBTTagCompound tag) {
|
||||
|
||||
public void readChunkFromNBT(@NotNull Chunk chunk, @NotNull NBTTagCompound nbt) {
|
||||
if (nbt.hasKey("Biomes", 7)) {
|
||||
chunk.setBiomeArray(nbt.getByteArray("Biomes"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,21 @@
|
||||
package com.falsepattern.chunk.internal.vanilla;
|
||||
|
||||
import com.falsepattern.chunk.api.ChunkDataManager;
|
||||
import lombok.val;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.falsepattern.chunk.internal.Common.BLOCKS_PER_EBS;
|
||||
import static com.falsepattern.chunk.internal.Common.EBS_PER_CHUNK;
|
||||
|
||||
public class BlockIDManager extends VanillaManager {
|
||||
public class BlockIDManager extends VanillaManager implements ChunkDataManager.PacketDataManager, ChunkDataManager.SectionNBTDataManager {
|
||||
private static final int LSB_BYTES_PER_EBS = BLOCKS_PER_EBS;
|
||||
private static final int MSB_BYTES_PER_EBS = BLOCKS_PER_EBS / 2;
|
||||
private static final int HEADER_SIZE = 2;
|
||||
@@ -72,12 +76,25 @@ public class BlockIDManager extends VanillaManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(Chunk chunk, @NotNull NBTTagCompound tag) {
|
||||
|
||||
public boolean sectionPrivilegedAccess() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(Chunk chunk, @NotNull NBTTagCompound tag) {
|
||||
public void writeSectionToNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section) {
|
||||
section.setByteArray("Blocks", ebs.getBlockLSBArray());
|
||||
|
||||
if (ebs.getBlockMSBArray() != null) {
|
||||
section.setByteArray("Add", ebs.getBlockMSBArray().data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSectionFromNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section) {
|
||||
ebs.setBlockLSBArray(section.getByteArray("Blocks"));
|
||||
|
||||
if (section.hasKey("Add", 7)) {
|
||||
ebs.setBlockMSBArray(new NibbleArray(section.getByteArray("Add"), 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.falsepattern.chunk.internal.vanilla;
|
||||
|
||||
import com.falsepattern.chunk.api.ChunkDataManager;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
public class BlocklightManager extends NibbleManager {
|
||||
public class BlocklightManager extends NibbleManager implements ChunkDataManager.SectionNBTDataManager {
|
||||
@Override
|
||||
protected NibbleArray getNibbleArray(ExtendedBlockStorage ebs) {
|
||||
return ebs.getBlocklightArray();
|
||||
@@ -13,4 +17,19 @@ public class BlocklightManager extends NibbleManager {
|
||||
public String id() {
|
||||
return "blocklight";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sectionPrivilegedAccess() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSectionToNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section) {
|
||||
section.setByteArray("BlockLight", ebs.getBlocklightArray().data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSectionFromNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section) {
|
||||
ebs.setBlocklightArray(new NibbleArray(section.getByteArray("BlockLight"), 4));
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.falsepattern.chunk.internal.vanilla;
|
||||
|
||||
import com.falsepattern.chunk.api.ChunkDataManager;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
public class MetadataManager extends NibbleManager {
|
||||
public class MetadataManager extends NibbleManager implements ChunkDataManager.SectionNBTDataManager {
|
||||
@Override
|
||||
protected NibbleArray getNibbleArray(ExtendedBlockStorage ebs) {
|
||||
return ebs.getMetadataArray();
|
||||
@@ -13,4 +17,19 @@ public class MetadataManager extends NibbleManager {
|
||||
public String id() {
|
||||
return "metadata";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sectionPrivilegedAccess() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSectionToNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section) {
|
||||
section.setByteArray("Data", ebs.getMetadataArray().data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSectionFromNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section) {
|
||||
ebs.setBlockMetadataArray(new NibbleArray(section.getByteArray("Data"), 4));
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
package com.falsepattern.chunk.internal.vanilla;
|
||||
|
||||
import com.falsepattern.chunk.api.ChunkDataManager;
|
||||
import com.falsepattern.chunk.internal.Common;
|
||||
import lombok.val;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public abstract class NibbleManager extends VanillaManager {
|
||||
public abstract class NibbleManager extends VanillaManager implements ChunkDataManager.PacketDataManager {
|
||||
public static final int BYTES_PER_EBS = Common.BLOCKS_PER_EBS / 2;
|
||||
|
||||
protected abstract NibbleArray getNibbleArray(ExtendedBlockStorage ebs);
|
||||
@@ -46,14 +45,4 @@ public abstract class NibbleManager extends VanillaManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(Chunk chunk, @NotNull NBTTagCompound tag) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(Chunk chunk, @NotNull NBTTagCompound tag) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
package com.falsepattern.chunk.internal.vanilla;
|
||||
|
||||
import com.falsepattern.chunk.api.ChunkDataManager;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class SkylightManager extends NibbleManager {
|
||||
public class SkylightManager extends NibbleManager implements ChunkDataManager.SectionNBTDataManager {
|
||||
@Override
|
||||
public String id() {
|
||||
return "skylight";
|
||||
@@ -30,4 +33,25 @@ public class SkylightManager extends NibbleManager {
|
||||
super.readFromBuffer(chunk, ebsMask, forceUpdate, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sectionPrivilegedAccess() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSectionToNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section) {
|
||||
if (!chunk.worldObj.provider.hasNoSky) {
|
||||
section.setByteArray("SkyLight", ebs.getSkylightArray().data);
|
||||
} else {
|
||||
section.setByteArray("SkyLight", new byte[ebs.getBlocklightArray().data.length]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSectionFromNBT(Chunk chunk, ExtendedBlockStorage ebs, NBTTagCompound section) {
|
||||
if (!chunk.worldObj.provider.hasNoSky) {
|
||||
ebs.setSkylightArray(new NibbleArray(section.getByteArray("SkyLight"), 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,9 @@ package com.falsepattern.chunk.internal.vanilla;
|
||||
|
||||
import com.falsepattern.chunk.api.ChunkDataManager;
|
||||
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
public abstract class VanillaManager implements ChunkDataManager<Chunk> {
|
||||
public abstract class VanillaManager implements ChunkDataManager {
|
||||
@Override
|
||||
public String domain() {
|
||||
return "minecraft";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Chunk chunk) {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user