package hunternif.mc.atlas.ext; import hunternif.mc.atlas.network.PacketDispatcher; import hunternif.mc.atlas.network.client.TilesPacket; import hunternif.mc.atlas.util.Log; import hunternif.mc.atlas.util.ShortVec2; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.world.WorldSavedData; import net.minecraftforge.common.util.Constants; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; /** * This world-saved data contains all the custom pseudo-biome IDs in a world. * Atlases check with it when updating themselves. * @author Hunternif */ public class ExtBiomeData extends WorldSavedData { private static final int VERSION = 1; private static final String TAG_VERSION = "aaVersion"; private static final String TAG_DIMENSION_MAP_LIST = "dimMap"; private static final String TAG_DIMENSION_ID = "dimID"; private static final String TAG_BIOME_IDS = "biomeIDs"; public ExtBiomeData(String key) { super(key); } private final Map<Integer /*dimension ID*/, Map<ShortVec2, Integer /*biome ID*/>> dimensionMap = new ConcurrentHashMap<>(2, 0.75f, 2); private final ShortVec2 tempCoords = new ShortVec2(0, 0); @Override public void readFromNBT(NBTTagCompound compound) { int version = compound.getInteger(TAG_VERSION); if (version < VERSION) { Log.warn("Outdated atlas data format! Was %d but current is %d", version, VERSION); this.markDirty(); } NBTTagList dimensionMapList = compound.getTagList(TAG_DIMENSION_MAP_LIST, Constants.NBT.TAG_COMPOUND); for (int d = 0; d < dimensionMapList.tagCount(); d++) { NBTTagCompound tag = dimensionMapList.getCompoundTagAt(d); int dimensionID = tag.getInteger(TAG_DIMENSION_ID); Map<ShortVec2, Integer> biomeMap = getBiomesInDimension(dimensionID); int[] intArray = tag.getIntArray(TAG_BIOME_IDS); for (int i = 0; i < intArray.length; i += 3) { ShortVec2 coords = new ShortVec2(intArray[i], intArray[i+1]); biomeMap.put(coords, intArray[i + 2]); } } } @Override public NBTTagCompound writeToNBT(NBTTagCompound compound) { compound.setInteger(TAG_VERSION, VERSION); NBTTagList dimensionMapList = new NBTTagList(); for (Integer dimension : dimensionMap.keySet()) { NBTTagCompound tag = new NBTTagCompound(); tag.setInteger(TAG_DIMENSION_ID, dimension); Map<ShortVec2, Integer> biomeMap = getBiomesInDimension(dimension); int[] intArray = new int[biomeMap.size()*3]; int i = 0; for (Entry<ShortVec2, Integer> entry : biomeMap.entrySet()) { intArray[i++] = entry.getKey().x; intArray[i++] = entry.getKey().y; intArray[i++] = entry.getValue(); } tag.setIntArray(TAG_BIOME_IDS, intArray); dimensionMapList.appendTag(tag); } compound.setTag(TAG_DIMENSION_MAP_LIST, dimensionMapList); return compound; } private Map<ShortVec2, Integer> getBiomesInDimension(int dimension) { return dimensionMap.computeIfAbsent(dimension, k -> new ConcurrentHashMap<>(2, 0.75f, 2)); } /** If no custom tile is set at the specified coordinates, returns -1. */ public int getBiomeIdAt(int dimension, int x, int z) { Integer biomeID = getBiomesInDimension(dimension).get(tempCoords.set(x, z)); return biomeID == null ? -1 : biomeID; } /** If setting biome on the server, a packet should be sent to all players. */ public void setBiomeIdAt(int dimension, int x, int z, int biomeID) { getBiomesInDimension(dimension).put(new ShortVec2(x, z), biomeID); markDirty(); } public void removeBiomeAt(int dimension, int x, int z) { getBiomesInDimension(dimension).remove(tempCoords.set(x, z)); markDirty(); } /** Send all data to player in several zipped packets. */ public void syncOnPlayer(EntityPlayer player) { for (Integer dimension : dimensionMap.keySet()) { TilesPacket packet = new TilesPacket(dimension); Map<ShortVec2, Integer> biomes = getBiomesInDimension(dimension); for (Entry<ShortVec2, Integer> entry : biomes.entrySet()) { packet.addTile(entry.getKey().x, entry.getKey().y, entry.getValue()); } PacketDispatcher.sendTo(packet, (EntityPlayerMP) player); } Log.info("Sent custom biome data to player %s", player.getName()); } }