mirror of
				https://github.com/mcMMO-Dev/mcMMO.git
				synced 2025-11-03 18:43:43 +01:00 
			
		
		
		
	Prepare for negative Y values
This commit is contained in:
		@@ -148,10 +148,13 @@ public class BlockListener implements Listener {
 | 
				
			|||||||
        // Get opposite direction so we get correct block
 | 
					        // Get opposite direction so we get correct block
 | 
				
			||||||
        BlockFace direction = event.getDirection();
 | 
					        BlockFace direction = event.getDirection();
 | 
				
			||||||
        Block movedBlock = event.getBlock().getRelative(direction);
 | 
					        Block movedBlock = event.getBlock().getRelative(direction);
 | 
				
			||||||
        mcMMO.getPlaceStore().setTrue(movedBlock);
 | 
					        if (movedBlock.getY() >= Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist
 | 
				
			||||||
 | 
					            mcMMO.getPlaceStore().setTrue(movedBlock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (Block block : event.getBlocks()) {
 | 
					        for (Block block : event.getBlocks()) {
 | 
				
			||||||
            movedBlock = block.getRelative(direction);
 | 
					            movedBlock = block.getRelative(direction);
 | 
				
			||||||
 | 
					            if (movedBlock.getY() < Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
            mcMMO.getPlaceStore().setTrue(movedBlock);
 | 
					            mcMMO.getPlaceStore().setTrue(movedBlock);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import com.gmail.nossr50.util.player.UserManager;
 | 
				
			|||||||
import com.google.common.collect.ImmutableSet;
 | 
					import com.google.common.collect.ImmutableSet;
 | 
				
			||||||
import org.bukkit.Location;
 | 
					import org.bukkit.Location;
 | 
				
			||||||
import org.bukkit.Material;
 | 
					import org.bukkit.Material;
 | 
				
			||||||
 | 
					import org.bukkit.World;
 | 
				
			||||||
import org.bukkit.block.BlockState;
 | 
					import org.bukkit.block.BlockState;
 | 
				
			||||||
import org.bukkit.entity.*;
 | 
					import org.bukkit.entity.*;
 | 
				
			||||||
import org.bukkit.inventory.ItemStack;
 | 
					import org.bukkit.inventory.ItemStack;
 | 
				
			||||||
@@ -259,6 +260,12 @@ public final class Misc {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static int getWorldMinCompat(World world)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO this method should access the world min variable in a version safe manner so that we don't restrict usage to new versions of spigot only
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void printProgress(int convertedUsers, int progressInterval, long startMillis) {
 | 
					    public static void printProgress(int convertedUsers, int progressInterval, long startMillis) {
 | 
				
			||||||
        if ((convertedUsers % progressInterval) == 0) {
 | 
					        if ((convertedUsers % progressInterval) == 0) {
 | 
				
			||||||
            mcMMO.p.getLogger().info(String.format("Conversion progress: %d users at %.2f users/second", convertedUsers, convertedUsers / (double) ((System.currentTimeMillis() - startMillis) / TIME_CONVERSION_FACTOR)));
 | 
					            mcMMO.p.getLogger().info(String.format("Conversion progress: %d users at %.2f users/second", convertedUsers, convertedUsers / (double) ((System.currentTimeMillis() - startMillis) / TIME_CONVERSION_FACTOR)));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package com.gmail.nossr50.util.blockmeta;
 | 
					package com.gmail.nossr50.util.blockmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.Misc;
 | 
				
			||||||
import org.bukkit.Bukkit;
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
import org.bukkit.World;
 | 
					import org.bukkit.World;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
@@ -10,12 +11,13 @@ import java.util.BitSet;
 | 
				
			|||||||
import java.util.UUID;
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class BitSetChunkStore implements ChunkStore {
 | 
					public class BitSetChunkStore implements ChunkStore {
 | 
				
			||||||
    private static final int CURRENT_VERSION = 8;
 | 
					    private static final int CURRENT_VERSION = 9;
 | 
				
			||||||
    private static final int MAGIC_NUMBER = 0xEA5EDEBB;
 | 
					    private static final int MAGIC_NUMBER = 0xEA5EDEBB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final int cx;
 | 
					    private final int cx;
 | 
				
			||||||
    private final int cz;
 | 
					    private final int cz;
 | 
				
			||||||
    private final int worldHeight;
 | 
					    private final int worldMin;
 | 
				
			||||||
 | 
					    private final int worldMax;
 | 
				
			||||||
    private final @NotNull UUID worldUid;
 | 
					    private final @NotNull UUID worldUid;
 | 
				
			||||||
    // Bitset store conforms to a "bottom-up" bit ordering consisting of a stack of {worldHeight} Y planes, each Y plane consists of 16 Z rows of 16 X bits.
 | 
					    // Bitset store conforms to a "bottom-up" bit ordering consisting of a stack of {worldHeight} Y planes, each Y plane consists of 16 Z rows of 16 X bits.
 | 
				
			||||||
    private final @NotNull BitSet store;
 | 
					    private final @NotNull BitSet store;
 | 
				
			||||||
@@ -23,15 +25,16 @@ public class BitSetChunkStore implements ChunkStore {
 | 
				
			|||||||
    private transient boolean dirty = false;
 | 
					    private transient boolean dirty = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public BitSetChunkStore(@NotNull World world, int cx, int cz) {
 | 
					    public BitSetChunkStore(@NotNull World world, int cx, int cz) {
 | 
				
			||||||
        this(world.getUID(), world.getMaxHeight(), cx, cz);
 | 
					        this(world.getUID(), Misc.getWorldMinCompat(world), world.getMaxHeight(), cx, cz);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private BitSetChunkStore(@NotNull UUID worldUid, int worldHeight, int cx, int cz) {
 | 
					    private BitSetChunkStore(@NotNull UUID worldUid, int worldMin, int worldMax, int cx, int cz) {
 | 
				
			||||||
        this.cx = cx;
 | 
					        this.cx = cx;
 | 
				
			||||||
        this.cz = cz;
 | 
					        this.cz = cz;
 | 
				
			||||||
        this.worldUid = worldUid;
 | 
					        this.worldUid = worldUid;
 | 
				
			||||||
        this.worldHeight = worldHeight;
 | 
					        this.worldMin = worldMin;
 | 
				
			||||||
        this.store = new BitSet(16 * 16 * worldHeight);
 | 
					        this.worldMax = worldMax;
 | 
				
			||||||
 | 
					        this.store = new BitSet(16 * 16 * (worldMax - worldMin));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -54,6 +57,16 @@ public class BitSetChunkStore implements ChunkStore {
 | 
				
			|||||||
        return cz;
 | 
					        return cz;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int getChunkMin() {
 | 
				
			||||||
 | 
					        return worldMin;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int getChunkMax() {
 | 
				
			||||||
 | 
					        return worldMax;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public @NotNull UUID getWorldId() {
 | 
					    public @NotNull UUID getWorldId() {
 | 
				
			||||||
        return worldUid;
 | 
					        return worldUid;
 | 
				
			||||||
@@ -86,22 +99,34 @@ public class BitSetChunkStore implements ChunkStore {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private int coordToIndex(int x, int y, int z) {
 | 
					    private int coordToIndex(int x, int y, int z) {
 | 
				
			||||||
        return coordToIndex(x, y, z, worldHeight);
 | 
					        return coordToIndex(x, y, z, worldMin, worldMax);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static int coordToIndex(int x, int y, int z, int worldHeight) {
 | 
					    private static int coordToIndex(int x, int y, int z, int worldMin, int worldMax) {
 | 
				
			||||||
        if (x < 0 || x >= 16 || y < 0 || y >= worldHeight || z < 0 || z >= 16)
 | 
					        if (x < 0 || x >= 16 || y < worldMin || y >= worldMax || z < 0 || z >= 16)
 | 
				
			||||||
            throw new IndexOutOfBoundsException(String.format("x: %d y: %d z: %d World Height: %d", x, y, z, worldHeight));
 | 
					            throw new IndexOutOfBoundsException(String.format("x: %d y: %d z: %d World Min: %d World Max: %d", x, y, z, worldMin, worldMax));
 | 
				
			||||||
        return (z * 16 + x) + (256 * y);
 | 
					        int yOffset = -worldMin; // Ensures y multiplier remains positive
 | 
				
			||||||
 | 
					        return (z * 16 + x) + (256 * (y + yOffset));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static int getWorldHeight(@NotNull UUID worldUid, int storedWorldHeight)
 | 
					    private static int getWorldMin(@NotNull UUID worldUid, int storedWorldMin)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        World world = Bukkit.getWorld(worldUid);
 | 
					        World world = Bukkit.getWorld(worldUid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Not sure how this case could come up, but might as well handle it gracefully.  Loading a chunkstore for an unloaded world?
 | 
					        // Not sure how this case could come up, but might as well handle it gracefully.  Loading a chunkstore for an unloaded world?
 | 
				
			||||||
        if (world == null)
 | 
					        if (world == null)
 | 
				
			||||||
            return storedWorldHeight;
 | 
					            return storedWorldMin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Misc.getWorldMinCompat(world);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static int getWorldMax(@NotNull UUID worldUid, int storedWorldMax)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        World world = Bukkit.getWorld(worldUid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Not sure how this case could come up, but might as well handle it gracefully.  Loading a chunkstore for an unloaded world?
 | 
				
			||||||
 | 
					        if (world == null)
 | 
				
			||||||
 | 
					            return storedWorldMax;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return world.getMaxHeight();
 | 
					        return world.getMaxHeight();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -114,7 +139,8 @@ public class BitSetChunkStore implements ChunkStore {
 | 
				
			|||||||
        out.writeLong(worldUid.getMostSignificantBits());
 | 
					        out.writeLong(worldUid.getMostSignificantBits());
 | 
				
			||||||
        out.writeInt(cx);
 | 
					        out.writeInt(cx);
 | 
				
			||||||
        out.writeInt(cz);
 | 
					        out.writeInt(cz);
 | 
				
			||||||
        out.writeInt(worldHeight);
 | 
					        out.writeInt(worldMin);
 | 
				
			||||||
 | 
					        out.writeInt(worldMax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Store the byte array directly so we don't have the object type info overhead
 | 
					        // Store the byte array directly so we don't have the object type info overhead
 | 
				
			||||||
        byte[] storeData = store.toByteArray();
 | 
					        byte[] storeData = store.toByteArray();
 | 
				
			||||||
@@ -129,7 +155,7 @@ public class BitSetChunkStore implements ChunkStore {
 | 
				
			|||||||
        // Can be used to determine the format of the file
 | 
					        // Can be used to determine the format of the file
 | 
				
			||||||
        int fileVersionNumber = in.readInt();
 | 
					        int fileVersionNumber = in.readInt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (magic != MAGIC_NUMBER || fileVersionNumber != CURRENT_VERSION)
 | 
					        if (magic != MAGIC_NUMBER || fileVersionNumber < 8)
 | 
				
			||||||
            throw new IOException();
 | 
					            throw new IOException();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        long lsb = in.readLong();
 | 
					        long lsb = in.readLong();
 | 
				
			||||||
@@ -138,21 +164,38 @@ public class BitSetChunkStore implements ChunkStore {
 | 
				
			|||||||
        int cx = in.readInt();
 | 
					        int cx = in.readInt();
 | 
				
			||||||
        int cz = in.readInt();
 | 
					        int cz = in.readInt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int worldHeight = in.readInt();
 | 
					        int worldMin = 0;
 | 
				
			||||||
 | 
					        if (fileVersionNumber >= 9)
 | 
				
			||||||
 | 
					            worldMin = in.readInt();
 | 
				
			||||||
 | 
					        int worldMax = in.readInt();
 | 
				
			||||||
        byte[] temp = new byte[in.readInt()];
 | 
					        byte[] temp = new byte[in.readInt()];
 | 
				
			||||||
        in.readFully(temp);
 | 
					        in.readFully(temp);
 | 
				
			||||||
        BitSet stored = BitSet.valueOf(temp);
 | 
					        BitSet stored = BitSet.valueOf(temp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int currentWorldHeight = getWorldHeight(worldUid, worldHeight);
 | 
					        int currentWorldMin = getWorldMin(worldUid, worldMin);
 | 
				
			||||||
 | 
					        int currentWorldMax = getWorldMax(worldUid, worldMax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        boolean worldHeightShrunk = currentWorldHeight < worldHeight;
 | 
					        // The order in which the world height update code occurs here is important, the world max truncate math only holds up if done before adjusting for min changes
 | 
				
			||||||
        // Lop off extra data if world height has shrunk
 | 
					        // Lop off extra data if world max has shrunk
 | 
				
			||||||
        if (worldHeightShrunk)
 | 
					        if (currentWorldMax < worldMax)
 | 
				
			||||||
            stored.clear(coordToIndex(16, currentWorldHeight, 16, worldHeight), stored.length());
 | 
					            stored.clear(coordToIndex(16, currentWorldMax, 16, worldMin, worldMax), stored.length());
 | 
				
			||||||
 | 
					        // Left shift store if world min has shrunk
 | 
				
			||||||
 | 
					        if (currentWorldMin > worldMin)
 | 
				
			||||||
 | 
					            stored = stored.get(currentWorldMin, stored.length()); // Because BitSet's aren't fixed size, a "substring" operation is equivalent to a left shift
 | 
				
			||||||
 | 
					        // Right shift store if world min has expanded
 | 
				
			||||||
 | 
					        if (currentWorldMin < worldMin)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int offset = (worldMin - currentWorldMin) * 16 * 16; // We are adding this many bits to the front
 | 
				
			||||||
 | 
					            // This isn't the most efficient way to do this, however, its a rare case to occur, and in the grand scheme of things, the small performance we could gain would cost us significant reduced readability of the code
 | 
				
			||||||
 | 
					            BitSet shifted = new BitSet();
 | 
				
			||||||
 | 
					            for (int i = 0; i < stored.length(); i++)
 | 
				
			||||||
 | 
					                shifted.set(i + offset, stored.get(i));
 | 
				
			||||||
 | 
					            stored = shifted;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        BitSetChunkStore chunkStore = new BitSetChunkStore(worldUid, currentWorldHeight, cx, cz);
 | 
					        BitSetChunkStore chunkStore = new BitSetChunkStore(worldUid, currentWorldMin, currentWorldMax, cx, cz);
 | 
				
			||||||
        chunkStore.store.or(stored);
 | 
					        chunkStore.store.or(stored);
 | 
				
			||||||
        chunkStore.dirty = worldHeightShrunk; // In the expanded case there is no reason to re-write it unless the data changes
 | 
					        chunkStore.dirty = currentWorldMin != worldMin || currentWorldMax != worldMax;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return chunkStore;
 | 
					        return chunkStore;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -203,7 +246,7 @@ public class BitSetChunkStore implements ChunkStore {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                private int cx;
 | 
					                private int cx;
 | 
				
			||||||
                private int cz;
 | 
					                private int cz;
 | 
				
			||||||
                private int worldHeight;
 | 
					                private int worldMax;
 | 
				
			||||||
                private UUID worldUid;
 | 
					                private UUID worldUid;
 | 
				
			||||||
                private boolean[][][] store;
 | 
					                private boolean[][][] store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -226,19 +269,20 @@ public class BitSetChunkStore implements ChunkStore {
 | 
				
			|||||||
                    cz = in.readInt();
 | 
					                    cz = in.readInt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    store = (boolean[][][]) in.readObject();
 | 
					                    store = (boolean[][][]) in.readObject();
 | 
				
			||||||
                    worldHeight = store[0][0].length;
 | 
					                    worldMax = store[0][0].length;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                public @NotNull BitSetChunkStore convert()
 | 
					                public @NotNull BitSetChunkStore convert()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    int currentWorldHeight = getWorldHeight(worldUid, worldHeight);
 | 
					                    int currentWorldMin = getWorldMin(worldUid, 0);
 | 
				
			||||||
 | 
					                    int currentWorldMax = getWorldMax(worldUid, worldMax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    BitSetChunkStore converted = new BitSetChunkStore(worldUid, currentWorldHeight, cx, cz);
 | 
					                    BitSetChunkStore converted = new BitSetChunkStore(worldUid, currentWorldMin, currentWorldMax, cx, cz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Read old data into new chunkstore
 | 
					                    // Read old data into new chunkstore
 | 
				
			||||||
                    for (int x = 0; x < 16; x++) {
 | 
					                    for (int x = 0; x < 16; x++) {
 | 
				
			||||||
                        for (int z = 0; z < 16; z++) {
 | 
					                        for (int z = 0; z < 16; z++) {
 | 
				
			||||||
                            for (int y = 0; y < worldHeight && y < currentWorldHeight; y++) {
 | 
					                            for (int y = 0; y < worldMax && y < currentWorldMax; y++) {
 | 
				
			||||||
                                converted.store.set(converted.coordToIndex(x, y, z), store[x][z][y]);
 | 
					                                converted.store.set(converted.coordToIndex(x, y, z), store[x][z][y]);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,9 @@ public interface ChunkStore {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    int getChunkZ();
 | 
					    int getChunkZ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int getChunkMin();
 | 
				
			||||||
 | 
					    int getChunkMax();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @NotNull UUID getWorldId();
 | 
					    @NotNull UUID getWorldId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package com.gmail.nossr50.util.blockmeta;
 | 
					package com.gmail.nossr50.util.blockmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.gmail.nossr50.TestUtil;
 | 
					import com.gmail.nossr50.TestUtil;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.Misc;
 | 
				
			||||||
import com.google.common.io.Files;
 | 
					import com.google.common.io.Files;
 | 
				
			||||||
import org.bukkit.Bukkit;
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
import org.bukkit.World;
 | 
					import org.bukkit.World;
 | 
				
			||||||
@@ -22,7 +23,7 @@ import static org.mockito.Mockito.mock;
 | 
				
			|||||||
 * Could be a lot better.  But some tests are better than none!  Tests the major things, still kinda unit-testy.  Verifies that the serialization isn't completely broken.
 | 
					 * Could be a lot better.  But some tests are better than none!  Tests the major things, still kinda unit-testy.  Verifies that the serialization isn't completely broken.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@RunWith(PowerMockRunner.class)
 | 
					@RunWith(PowerMockRunner.class)
 | 
				
			||||||
@PrepareForTest(Bukkit.class)
 | 
					@PrepareForTest({ Bukkit.class, Misc.class })
 | 
				
			||||||
public class ChunkStoreTest {
 | 
					public class ChunkStoreTest {
 | 
				
			||||||
    private static File tempDir;
 | 
					    private static File tempDir;
 | 
				
			||||||
    @BeforeClass
 | 
					    @BeforeClass
 | 
				
			||||||
@@ -76,6 +77,34 @@ public class ChunkStoreTest {
 | 
				
			|||||||
        assertEqual(original, deserialized);
 | 
					        assertEqual(original, deserialized);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testNegativeWorldMin() throws IOException {
 | 
				
			||||||
 | 
					        PowerMockito.mockStatic(Misc.class);
 | 
				
			||||||
 | 
					        Mockito.when(Misc.getWorldMinCompat(mockWorld)).thenReturn(-64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2);
 | 
				
			||||||
 | 
					        original.setTrue(14, -32, 12);
 | 
				
			||||||
 | 
					        original.setTrue(14, -64, 12);
 | 
				
			||||||
 | 
					        original.setTrue(13, -63, 12);
 | 
				
			||||||
 | 
					        byte[] serializedBytes = serializeChunkstore(original);
 | 
				
			||||||
 | 
					        ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
 | 
				
			||||||
 | 
					        assertEqual(original, deserialized);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testNegativeWorldMinUpgrade() throws IOException {
 | 
				
			||||||
 | 
					        BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2);
 | 
				
			||||||
 | 
					        original.setTrue(14, 1, 12);
 | 
				
			||||||
 | 
					        original.setTrue(14, 2, 12);
 | 
				
			||||||
 | 
					        original.setTrue(13, 3, 12);
 | 
				
			||||||
 | 
					        byte[] serializedBytes = serializeChunkstore(original);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PowerMockito.mockStatic(Misc.class);
 | 
				
			||||||
 | 
					        Mockito.when(Misc.getWorldMinCompat(mockWorld)).thenReturn(-64);
 | 
				
			||||||
 | 
					        ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes)));
 | 
				
			||||||
 | 
					        assertEqualIgnoreMinMax(original, deserialized);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    public void testChunkCoords() throws IOException {
 | 
					    public void testChunkCoords() throws IOException {
 | 
				
			||||||
        for (int x = -96; x < 0; x++) {
 | 
					        for (int x = -96; x < 0; x++) {
 | 
				
			||||||
@@ -175,14 +204,25 @@ public class ChunkStoreTest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void assertEqual(ChunkStore expected, ChunkStore actual)
 | 
					    private void assertEqual(ChunkStore expected, ChunkStore actual)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Assert.assertEquals(expected.getChunkMin(), actual.getChunkMin());
 | 
				
			||||||
 | 
					        Assert.assertEquals(expected.getChunkMax(), actual.getChunkMax());
 | 
				
			||||||
 | 
					        assertEqualIgnoreMinMax(expected, actual);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void assertEqualIgnoreMinMax(ChunkStore expected, ChunkStore actual)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Assert.assertEquals(expected.getChunkX(), actual.getChunkX());
 | 
					        Assert.assertEquals(expected.getChunkX(), actual.getChunkX());
 | 
				
			||||||
        Assert.assertEquals(expected.getChunkZ(), actual.getChunkZ());
 | 
					        Assert.assertEquals(expected.getChunkZ(), actual.getChunkZ());
 | 
				
			||||||
        Assert.assertEquals(expected.getWorldId(), actual.getWorldId());
 | 
					        Assert.assertEquals(expected.getWorldId(), actual.getWorldId());
 | 
				
			||||||
        for (int y = 0; y < 256; y++)
 | 
					        for (int y = Math.min(actual.getChunkMin(), expected.getChunkMin()); y < Math.max(actual.getChunkMax(), expected.getChunkMax()); y++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (expected.getChunkMin() > y || actual.getChunkMin() > y || expected.getChunkMax() <= y || actual.getChunkMax() <= y)
 | 
				
			||||||
 | 
					                continue; // Ignore
 | 
				
			||||||
            for (int x = 0; x < 16; x++)
 | 
					            for (int x = 0; x < 16; x++)
 | 
				
			||||||
                for (int z = 0; z < 16; z++)
 | 
					                for (int z = 0; z < 16; z++)
 | 
				
			||||||
                    Assert.assertTrue(expected.isTrue(x, y, z) == actual.isTrue(x, y, z));
 | 
					                    Assert.assertTrue(expected.isTrue(x, y, z) == actual.isTrue(x, y, z));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static byte[] serializeChunkstore(@NotNull ChunkStore chunkStore) throws IOException {
 | 
					    private static byte[] serializeChunkstore(@NotNull ChunkStore chunkStore) throws IOException {
 | 
				
			||||||
@@ -231,6 +271,16 @@ public class ChunkStoreTest {
 | 
				
			|||||||
            return cz;
 | 
					            return cz;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public int getChunkMin() {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public int getChunkMax() {
 | 
				
			||||||
 | 
					            return store[0][0].length;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @Override
 | 
					        @Override
 | 
				
			||||||
        public @NotNull UUID getWorldId() {
 | 
					        public @NotNull UUID getWorldId() {
 | 
				
			||||||
            return worldUid;
 | 
					            return worldUid;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user