cubicchunks.world.column.CubeMap.java Source code

Java tutorial

Introduction

Here is the source code for cubicchunks.world.column.CubeMap.java

Source

/*
 *  This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT).
 *
 *  Copyright (c) 2015 contributors
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */
package cubicchunks.world.column;

import com.google.common.collect.Lists;

import net.minecraft.world.chunk.storage.ExtendedBlockStorage;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import cubicchunks.world.cube.Cube;

class CubeMap implements Iterable<Cube> {

    private static final Comparator<Cube> ORDER = (one, two) -> one.getY() - two.getY();

    private final List<Cube> cubes = new ArrayList<>();

    private ExtendedBlockStorage[] toBlockTick = new ExtendedBlockStorage[0];

    Cube remove(int cubeY) {
        int index = binarySearch(cubeY);
        return index < cubes.size() && cubes.get(index).getY() == cubeY ? cubes.remove(index) : null;
    }

    void put(Cube cube) {
        if (cube == null) {
            throw new NullPointerException();
        }
        if (this.contains(cube.getY())) {
            throw new IllegalArgumentException("Cube at " + cube.getY() + " already exists!");
        }
        cubes.add(cube);
        cubes.sort(ORDER); // kind of expensive... but puts don't happen much (wish there was a SortedArrayList)
    }

    Iterable<Cube> cubes(int startY, int endY) {
        boolean reverse = false;
        if (startY > endY) {
            int i = startY;
            startY = endY;
            endY = i;
            reverse = true;
        }

        int bottom = binarySearch(startY);
        int top = binarySearch(endY + 1); // subList()'s second arg is exclusive so we need to add 1

        if (bottom < cubes.size() && top <= cubes.size()) {
            return reverse ? Lists.reverse(cubes.subList(bottom, top)) : cubes.subList(bottom, top);
        } else {
            return Collections.emptyList();
        }
    }

    private boolean contains(int cubeY) {
        int index = binarySearch(cubeY);
        return index < cubes.size() && cubes.get(index).getY() == cubeY;
    }

    @Override
    public Iterator<Cube> iterator() {
        return cubes.iterator();
    }

    public Collection<Cube> all() {
        return Collections.unmodifiableCollection(cubes);
    }

    public boolean isEmpty() {
        return cubes.isEmpty();
    }

    /**
     * @return An array of EBS's form Cubes that need ticking... kind of a hack but vanilla needs it
     */
    ExtendedBlockStorage[] getStoragesToTick() {
        if (!isToTickValid()) {
            int count = 0;
            for (Cube cube : cubes) {
                if (cube.getStorage() != null && cube.getTickets().shouldTick()) {
                    count++;
                }
            }

            toBlockTick = new ExtendedBlockStorage[count];
            count = 0;
            for (Cube cube : cubes) {
                if (cube.getStorage() != null && cube.getTickets().shouldTick()) {
                    toBlockTick[count++] = cube.getStorage();
                }
            }
        }

        return toBlockTick;
    }

    private boolean isToTickValid() {
        int index = 0;
        for (Cube cube : cubes) {
            if (cube.getStorage() != null && cube.getTickets().shouldTick()) {
                if (index >= toBlockTick.length) {
                    return false;
                }
                if (toBlockTick[index++] != cube.getStorage()) {
                    return false;
                }
            }
        }
        return index == toBlockTick.length; // did we check everything there was in toBlockTick?
    }

    private int binarySearch(int cubeY) {
        int start = 0;
        int end = cubes.size() - 1;
        int mid = 0;

        while (start <= end) {
            mid = start + end >>> 1;

            int at = cubes.get(mid).getY();
            if (at < cubeY) { // we are below the target;
                start = mid + 1;
            } else if (at > cubeY) {
                end = mid - 1; // we are above the target
            } else {
                return mid;// found target!
            }
        }

        return mid; // not found :(
    }
}