/*
* 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.server;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldSavedData;
import net.minecraft.world.storage.MapStorage;
import cubicchunks.CubicChunks;
import cubicchunks.util.Coords;
import cubicchunks.util.ticket.ITicket;
import cubicchunks.world.ICubeProvider;
import cubicchunks.world.ICubicWorld;
import cubicchunks.world.IProviderExtras;
public class SpawnCubes {
private static final int DEFAULT_SPAWN_RADIUS = 12; // highest render distance is 32
public static void update(ICubicWorld world) {
if (world.getProvider().canRespawnHere()) {
SpawnArea.get(world).update(world);
}
}
public static class SpawnArea extends WorldSavedData implements ITicket {
private static final String STORAGE = CubicChunks.MODID + "_spawncubes";
private BlockPos spawnPoint = null;
private int radius = DEFAULT_SPAWN_RADIUS;
public SpawnArea() {
this(STORAGE);
}
public SpawnArea(String storage) {
super(storage);
}
public void update(ICubicWorld world) {
update(world, radius); // radius did not change
}
public void update(ICubicWorld world, int newRadius) {
if (!world.getSpawnPoint().equals(spawnPoint) || radius != newRadius) { // check if something changed
removeTickets(world);
radius = newRadius;
addTickets(world); // addTickets will update the spawn location if need be
markDirty();
}
}
private void removeTickets(ICubicWorld world) {
if (radius < 0 || spawnPoint == null) {
return; // no spawn chunks OR nothing to remove
}
ICubeProvider serverCubeCache = world.getCubeCache();
int spawnCubeX = Coords.blockToCube(spawnPoint.getX());
int spawnCubeY = Coords.blockToCube(spawnPoint.getY());
int spawnCubeZ = Coords.blockToCube(spawnPoint.getZ());
for (int cubeX = spawnCubeX - radius; cubeX <= spawnCubeX + radius; cubeX++) {
for (int cubeZ = spawnCubeZ - radius; cubeZ <= spawnCubeZ + radius; cubeZ++) {
for (int cubeY = spawnCubeY + radius; cubeY >= spawnCubeY - radius; cubeY--) {
serverCubeCache.getCube(cubeX, cubeY, cubeZ).getTickets().remove(this);
}
}
}
}
private void addTickets(ICubicWorld world) {
if (radius < 0) {
return; // no spawn cubes
}
IProviderExtras serverCubeCache = (IProviderExtras) world.getCubeCache();
// load the cubes around the spawn point
CubicChunks.LOGGER.info("Loading cubes for spawn...");
spawnPoint = world.getSpawnPoint();
int spawnCubeX = Coords.blockToCube(spawnPoint.getX());
int spawnCubeY = Coords.blockToCube(spawnPoint.getY());
int spawnCubeZ = Coords.blockToCube(spawnPoint.getZ());
long lastTime = System.currentTimeMillis();
final int progressReportInterval = 1000;//ms
int totalToGenerate = (radius*2 + 1)*(radius*2 + 1)*(radius*2 + 1);
int generated = 0;
for (int cubeX = spawnCubeX - radius; cubeX <= spawnCubeX + radius; cubeX++) {
for (int cubeZ = spawnCubeZ - radius; cubeZ <= spawnCubeZ + radius; cubeZ++) {
for (int cubeY = spawnCubeY + radius; cubeY >= spawnCubeY - radius; cubeY--) {
serverCubeCache.getCube(cubeX, cubeY, cubeZ, IProviderExtras.Requirement.LIGHT).getTickets().add(this);
generated++;
if (System.currentTimeMillis() >= lastTime + progressReportInterval) {
lastTime = System.currentTimeMillis();
CubicChunks.LOGGER.info("Preparing spawn area: {}%", generated*100/totalToGenerate);
}
}
}
}
}
public boolean shouldTick() {
return true;
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
this.radius = nbt.getInteger("spawnRadius");
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
nbt.setInteger("spawnRadius", this.radius);
return nbt;
}
public static SpawnArea get(ICubicWorld world) {
MapStorage storage = ((World) world).getPerWorldStorage();
SpawnArea area = (SpawnArea) storage.getOrLoadData(SpawnArea.class, STORAGE);
if (area == null) {
area = new SpawnArea();
storage.setData(STORAGE, area);
}
return area;
}
}
}