javaalgorithmdata-structures3dminecraft

Data Structure and Algorithm for a 3D Volume?


I've been tinkering with some Minecraft Bukkit plugin development, and am currently working on something where I need to be able to define a "volume" of space and determine when an entity (player) moves from outside that volume to inside (or vice versa).

If I restrict the "volume" to boxes, it should be simple. The data structure can just maintain the X/Y/Z bounding integers (so 6 total integers) and calculating entry/exit given two points (movement from and movement to) should just be a matter of determining if A) all three To values are within all three ranges and B) at least one From value is outside its corresponding range.

(Though if there's a better, more performant way of storing and calculating this, I'm all ears.)

However, what if the "volume" isn't a simple box? Suppose I have an oddly-shaped room and want to enclose the volume of that room. I could arrange multiple "volumes" individually to fill the overall space, however that would result in false positives when an entity moves from one to another.

Not having worked in gaming or 3D engines before, I'm drawing a blank on how I might be able to structure something like this. But it occurs to me that this is likely a problem which has been solved and has known established patterns. Essentially, I'm trying to:

  1. Define a data structure which can represent an oddly-shaped volume of space (albeit at least based on block coordinates).
  2. Define an algorithm which, given a source and destination of movement, can determine if the movement crossed a boundary of the defined space.

Are there established patterns and practices for this?


Solution

  • I don't know if this has been used in any kind of video game before, but the first thing that came to mind is the classic Sieve of Eratosthenes implementation, the only change would be to make the boolean array 3D, and use the keys as coordinates. Obviously though as x and y values can be huge in Minecraft, you'd probably want to save space by saving an offset between the world 0,0 position and your selection, something like this:

    class OddArea
    {
        static final int MAX_SELECTION_SIZE = 64; //Or whatever
    
        public final int xOffset, yOffset;
    
        // 256 = Chunk height
        public final boolean[][][] squares = new boolean[MAX_SELECTION_SIZE][MAX_SELECTION_SIZE][256];
    
        OddArea()
        {
            this(0, 0);
        }
    
        OddArea(final int xOffset, final int yOffset)
        {
            this.xOffset = xOffset;
            this.yOffset = yOffset;
        }
    
        void addBlock(final int x, final int y, final int z)
        {
            this.squares[x - this.xOffset][y - this.yOffset][z] = true;
        }
    
        boolean isInsideArea(final int x, final int y, final int z)
        {
            return this.squares[x - this.xOffset][y - this.yOffset][z];
        }
    }
    

    z doesn't require an offset as the Minecraft world is only 256 blocks high.

    The only issue I can think of with this setup is you'd have to know the lowest x,y coordinates before you start filling up your object