Speed up generation
This commit is contained in:
parent
f8dbbce106
commit
b782f5ced9
@ -1,10 +1,7 @@
|
|||||||
package nautilus.game.arcade.uhc;
|
package nautilus.game.arcade.uhc;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -13,7 +10,6 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_8_R3.BiomeBase;
|
import net.minecraft.server.v1_8_R3.BiomeBase;
|
||||||
|
|
||||||
@ -27,26 +23,35 @@ import org.apache.http.impl.client.HttpClientBuilder;
|
|||||||
import org.apache.http.message.BasicHeader;
|
import org.apache.http.message.BasicHeader;
|
||||||
import org.apache.http.protocol.HTTP;
|
import org.apache.http.protocol.HTTP;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Difficulty;
|
import org.bukkit.Difficulty;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.WorldBorder;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||||
|
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||||
|
import org.bukkit.event.world.WorldInitEvent;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.spigotmc.WatchdogThread;
|
import org.spigotmc.WatchdogThread;
|
||||||
|
import org.zeroturnaround.zip.ByteSource;
|
||||||
|
import org.zeroturnaround.zip.FileSource;
|
||||||
import org.zeroturnaround.zip.ZipEntrySource;
|
import org.zeroturnaround.zip.ZipEntrySource;
|
||||||
import org.zeroturnaround.zip.ZipUtil;
|
import org.zeroturnaround.zip.ZipUtil;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
public class WorldGen extends JavaPlugin
|
public class WorldGen extends JavaPlugin implements Listener
|
||||||
{
|
{
|
||||||
private static final int TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
|
private static final int TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
|
||||||
|
|
||||||
private static final int MIN_X = -1000;
|
// The world will be -MAP_SIZE to MAP_SIZE large
|
||||||
private static final int MIN_Z = -1000;
|
private static final int MAP_SIZE = 1000;
|
||||||
private static final int MAX_X = 1000;
|
|
||||||
private static final int MAX_Z = 1000;
|
|
||||||
private static final int VIEW_DISTANCE = 5;
|
private static final int VIEW_DISTANCE = 5;
|
||||||
|
|
||||||
private static final String API_HOST_FILE = "api-config.dat";
|
private static final String API_HOST_FILE = "api-config.dat";
|
||||||
@ -78,19 +83,60 @@ public class WorldGen extends JavaPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void login(AsyncPlayerPreLoginEvent event)
|
||||||
|
{
|
||||||
|
event.setKickMessage("get out");
|
||||||
|
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void unload(ChunkUnloadEvent event)
|
||||||
|
{
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void init(WorldInitEvent event)
|
||||||
|
{
|
||||||
|
// Prevent any eager generation
|
||||||
|
event.getWorld().setKeepSpawnInMemory(false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable()
|
public void onEnable()
|
||||||
{
|
{
|
||||||
|
getLogger().info("Cleaning up other worlds");
|
||||||
|
for (World world : getServer().getWorlds())
|
||||||
|
{
|
||||||
|
world.setKeepSpawnInMemory(false);
|
||||||
|
world.setSpawnFlags(false, false);
|
||||||
|
world.setAmbientSpawnLimit(0);
|
||||||
|
world.setAnimalSpawnLimit(0);
|
||||||
|
world.setMonsterSpawnLimit(0);
|
||||||
|
world.setWaterAnimalSpawnLimit(0);
|
||||||
|
world.getEntities().forEach(Entity::remove);
|
||||||
|
for (Chunk chunk : world.getLoadedChunks())
|
||||||
|
{
|
||||||
|
chunk.unload(false, false);
|
||||||
|
}
|
||||||
|
getServer().unloadWorld(world, false);
|
||||||
|
getLogger().info("Unloaded " + world.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogger().info("Replacing biomes");
|
||||||
BiomeBase.getBiomes()[BiomeBase.OCEAN.id] = BiomeBase.PLAINS;
|
BiomeBase.getBiomes()[BiomeBase.OCEAN.id] = BiomeBase.PLAINS;
|
||||||
BiomeBase.getBiomes()[BiomeBase.DEEP_OCEAN.id] = BiomeBase.PLAINS;
|
BiomeBase.getBiomes()[BiomeBase.DEEP_OCEAN.id] = BiomeBase.PLAINS;
|
||||||
BiomeBase.getBiomes()[BiomeBase.SWAMPLAND.id] = BiomeBase.PLAINS;
|
BiomeBase.getBiomes()[BiomeBase.SWAMPLAND.id] = BiomeBase.PLAINS;
|
||||||
BiomeBase.getBiomes()[BiomeBase.RIVER.id] = BiomeBase.PLAINS;
|
BiomeBase.getBiomes()[BiomeBase.RIVER.id] = BiomeBase.PLAINS;
|
||||||
|
|
||||||
|
getLogger().info("Forcing system GC");
|
||||||
|
System.gc();
|
||||||
|
|
||||||
WatchdogThread.doStop();
|
WatchdogThread.doStop();
|
||||||
|
|
||||||
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File root = new File(".");
|
File root = new File(".");
|
||||||
|
|
||||||
if (!root.exists())
|
if (!root.exists())
|
||||||
@ -138,19 +184,41 @@ public class WorldGen extends JavaPlugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File previousSession = new File("generating");
|
||||||
|
|
||||||
|
if (previousSession.exists())
|
||||||
|
{
|
||||||
|
if (!FileUtils.deleteQuietly(previousSession))
|
||||||
|
{
|
||||||
|
getLogger().severe("Could not delete previous generation session. Aborting");
|
||||||
|
System.exit(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getLogger().info("Generating world seed " + seed);
|
getLogger().info("Generating world seed " + seed);
|
||||||
|
|
||||||
World world = new WorldCreator("generating")
|
World world = new WorldCreator("generating")
|
||||||
.environment(World.Environment.NORMAL)
|
.environment(World.Environment.NORMAL)
|
||||||
.seed(seed)
|
.seed(seed)
|
||||||
.createWorld();
|
.createWorld();
|
||||||
world.setDifficulty(Difficulty.HARD);
|
|
||||||
world.setKeepSpawnInMemory(false);
|
world.setKeepSpawnInMemory(false);
|
||||||
|
world.setDifficulty(Difficulty.HARD);
|
||||||
|
WorldBorder border = world.getWorldBorder();
|
||||||
|
border.setCenter(0.0, 0.0);
|
||||||
|
border.setSize(MAP_SIZE * 2);
|
||||||
|
|
||||||
int minChunkX = (MIN_X >> 4) - VIEW_DISTANCE;
|
int minChunkX = (-MAP_SIZE >> 4) - VIEW_DISTANCE;
|
||||||
int minChunkZ = (MIN_Z >> 4) - VIEW_DISTANCE;
|
int minChunkZ = (-MAP_SIZE >> 4) - VIEW_DISTANCE;
|
||||||
int maxChunkX = (MAX_X >> 4) + VIEW_DISTANCE;
|
int maxChunkX = (MAP_SIZE >> 4) + VIEW_DISTANCE;
|
||||||
int maxChunkZ = (MAX_Z >> 4) + VIEW_DISTANCE;
|
int maxChunkZ = (MAP_SIZE >> 4) + VIEW_DISTANCE;
|
||||||
|
|
||||||
|
net.minecraft.server.v1_8_R3.WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||||
|
//
|
||||||
|
// Field mfield = nmsWorld.getClass().getDeclaredField("M");
|
||||||
|
// mfield.setAccessible(true);
|
||||||
|
//
|
||||||
|
// HashTreeSet<NextTickListEntry> treeSet = ((HashTreeSet) mfield.get(nmsWorld));
|
||||||
|
|
||||||
for (int x = minChunkX; x <= maxChunkX; x++)
|
for (int x = minChunkX; x <= maxChunkX; x++)
|
||||||
{
|
{
|
||||||
@ -158,7 +226,15 @@ public class WorldGen extends JavaPlugin
|
|||||||
for (int z = minChunkZ; z <= maxChunkZ; z++)
|
for (int z = minChunkZ; z <= maxChunkZ; z++)
|
||||||
{
|
{
|
||||||
world.getChunkAt(x, z).load(true);
|
world.getChunkAt(x, z).load(true);
|
||||||
|
nmsWorld.a(true);
|
||||||
|
// Manually tick blocks - this should be the equivalent of letting a full server tick run once
|
||||||
|
// between each chunk generation, except we cut out the extra useless stuff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// System.out.println("M: " + treeSet.size());
|
||||||
|
// System.out.println("E: " + nmsWorld.entityList.size());
|
||||||
|
// System.out.println("TE: " + nmsWorld.tileEntityList.size());
|
||||||
|
// System.out.println("C: " + nmsWorld.chunkProviderServer.chunks.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = minChunkX; x <= maxChunkX; x++)
|
for (int x = minChunkX; x <= maxChunkX; x++)
|
||||||
@ -168,6 +244,11 @@ public class WorldGen extends JavaPlugin
|
|||||||
{
|
{
|
||||||
world.getChunkAt(x, z).unload(true, false);
|
world.getChunkAt(x, z).unload(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// System.out.println("M: " + treeSet.size());
|
||||||
|
// System.out.println("E: " + nmsWorld.entityList.size());
|
||||||
|
// System.out.println("TE: " + nmsWorld.tileEntityList.size());
|
||||||
|
// System.out.println("C: " + nmsWorld.chunkProviderServer.chunks.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
getLogger().info("Unloading and saving world");
|
getLogger().info("Unloading and saving world");
|
||||||
@ -179,10 +260,10 @@ public class WorldGen extends JavaPlugin
|
|||||||
StringBuilder worldconfig = new StringBuilder();
|
StringBuilder worldconfig = new StringBuilder();
|
||||||
worldconfig.append("MAP_NAME:UHC World").append(System.lineSeparator());
|
worldconfig.append("MAP_NAME:UHC World").append(System.lineSeparator());
|
||||||
worldconfig.append("MAP_AUTHOR:Mineplex").append(System.lineSeparator());
|
worldconfig.append("MAP_AUTHOR:Mineplex").append(System.lineSeparator());
|
||||||
worldconfig.append("MIN_X:").append(MIN_X).append(System.lineSeparator());
|
worldconfig.append("MIN_X:").append(-MAP_SIZE).append(System.lineSeparator());
|
||||||
worldconfig.append("MIN_Z:").append(MIN_Z).append(System.lineSeparator());
|
worldconfig.append("MIN_Z:").append(-MAP_SIZE).append(System.lineSeparator());
|
||||||
worldconfig.append("MAX_X:").append(MAX_X).append(System.lineSeparator());
|
worldconfig.append("MAX_X:").append(MAP_SIZE).append(System.lineSeparator());
|
||||||
worldconfig.append("MAX_Z:").append(MAX_Z).append(System.lineSeparator());
|
worldconfig.append("MAX_Z:").append(MAP_SIZE).append(System.lineSeparator());
|
||||||
for (int i = 1; i <= 60; i++)
|
for (int i = 1; i <= 60; i++)
|
||||||
{
|
{
|
||||||
worldconfig.append("TEAM_NAME:").append(i).append(System.lineSeparator());
|
worldconfig.append("TEAM_NAME:").append(i).append(System.lineSeparator());
|
||||||
@ -203,72 +284,12 @@ public class WorldGen extends JavaPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<ZipEntrySource> zipEntrySourceList = new ArrayList<>();
|
List<ZipEntrySource> zipEntrySourceList = new ArrayList<>();
|
||||||
zipEntrySourceList.add(new ZipEntrySource()
|
zipEntrySourceList.add(new ByteSource("WorldConfig.dat", worldconfig.toString().getBytes(StandardCharsets.UTF_8)));
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public String getPath()
|
|
||||||
{
|
|
||||||
return "WorldConfig.dat";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ZipEntry getEntry()
|
|
||||||
{
|
|
||||||
return new ZipEntry(getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getInputStream() throws IOException
|
|
||||||
{
|
|
||||||
return new ByteArrayInputStream(worldconfig.toString().getBytes(StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
for (File file : regionFiles)
|
for (File file : regionFiles)
|
||||||
{
|
{
|
||||||
zipEntrySourceList.add(new ZipEntrySource()
|
zipEntrySourceList.add(new FileSource("region/" + file.getName(), file));
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public String getPath()
|
|
||||||
{
|
|
||||||
return "region/" + file.getName();
|
|
||||||
}
|
}
|
||||||
|
zipEntrySourceList.add(new FileSource("level.dat", new File(worldFolder, "level.dat")));
|
||||||
@Override
|
|
||||||
public ZipEntry getEntry()
|
|
||||||
{
|
|
||||||
return new ZipEntry(getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getInputStream() throws IOException
|
|
||||||
{
|
|
||||||
return new FileInputStream(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
zipEntrySourceList.add(new ZipEntrySource()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public String getPath()
|
|
||||||
{
|
|
||||||
return "level.dat";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ZipEntry getEntry()
|
|
||||||
{
|
|
||||||
return new ZipEntry(getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getInputStream() throws IOException
|
|
||||||
{
|
|
||||||
return new FileInputStream(new File(worldFolder, "level.dat"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ZipUtil.pack(zipEntrySourceList.toArray(new ZipEntrySource[zipEntrySourceList.size()]), outputFile);
|
ZipUtil.pack(zipEntrySourceList.toArray(new ZipEntrySource[zipEntrySourceList.size()]), outputFile);
|
||||||
|
|
||||||
@ -325,17 +346,13 @@ public class WorldGen extends JavaPlugin
|
|||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
getLogger().log(Level.SEVERE, "An error occurred while uploading " + seed + "!", e);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
getLogger().info("Finished generating world seed " + seed);
|
getLogger().info("Finished generating world seed " + seed);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Throwable t)
|
Bukkit.shutdown();
|
||||||
{
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
System.exit(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,17 +365,19 @@ public abstract class UHC extends Game
|
|||||||
UtilPlayer.message(caller, F.main("Debug", "World info for " + targetWorld.getName()));
|
UtilPlayer.message(caller, F.main("Debug", "World info for " + targetWorld.getName()));
|
||||||
UtilPlayer.message(caller, F.desc("Chunks", String.valueOf(chunks.length)));
|
UtilPlayer.message(caller, F.desc("Chunks", String.valueOf(chunks.length)));
|
||||||
UtilPlayer.message(caller, F.desc("Entities", String.valueOf(targetWorld.getEntities().size())));
|
UtilPlayer.message(caller, F.desc("Entities", String.valueOf(targetWorld.getEntities().size())));
|
||||||
UtilPlayer.message(caller, F.desc("Tile Entities", String.valueOf(Arrays.stream(chunks).map(Chunk::getTileEntities).map(Arrays::asList).flatMap(Collection::stream)
|
UtilPlayer.message(caller, F.desc("Tile Entities", String.valueOf(Arrays.stream(chunks).map(Chunk::getTileEntities).map(Arrays::asList).mapToLong(Collection::size).sum())));
|
||||||
.count())));
|
|
||||||
UtilPlayer.message(caller, F.desc("View Distance", String.valueOf(nmsWorld.spigotConfig.viewDistance)));
|
UtilPlayer.message(caller, F.desc("View Distance", String.valueOf(nmsWorld.spigotConfig.viewDistance)));
|
||||||
UtilPlayer.message(caller, F.desc("Unload queue size", String.valueOf(nmsWorld.chunkProviderServer.unloadQueue.size())));
|
UtilPlayer.message(caller, F.desc("Unload queue size", String.valueOf(nmsWorld.chunkProviderServer.unloadQueue.size())));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HashTreeSet<NextTickListEntry> m = (HashTreeSet<NextTickListEntry>) nmsWorld.getClass().getField("M").get(nmsWorld);
|
Field f = nmsWorld.getClass().getDeclaredField("M");
|
||||||
|
f.setAccessible(true);
|
||||||
|
HashTreeSet<NextTickListEntry> m = (HashTreeSet<NextTickListEntry>) f.get(nmsWorld);
|
||||||
|
|
||||||
UtilPlayer.message(caller, F.desc("Pending tick", String.valueOf(m.size())));
|
UtilPlayer.message(caller, F.desc("Pending tick", String.valueOf(m.size())));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e)
|
catch (ReflectiveOperationException e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -571,7 +573,7 @@ public abstract class UHC extends Game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
registerDebugCommand(new DebugCommand("uhccallchunks", Rank.DEVELOPER)
|
registerDebugCommand(new DebugCommand("uhcallchunks", Rank.DEVELOPER)
|
||||||
{
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user