#39: Copy files and load worlds asynchronously

This commit is contained in:
Daniel Saukel 2016-07-08 20:41:04 +02:00
parent 3778009785
commit 27afe9b1fd
26 changed files with 624 additions and 137 deletions

View File

@ -32,6 +32,7 @@ DungeonsXL also provides custom game mechanics to make these worlds interesting.
* A powerful API: [Read more...](../../wiki/api-tutorial)
* Different game types allow you to use your maps dynamically for different purposes. [Read more...](../../wiki/game-types)
* Announcements sothat users can join the next match easily. [Read more...](../../wiki/announcements)
* Great performance due to a custom, asynchronous world loading and creation method and several other performance tweaks
* ...and many more!
@ -49,7 +50,7 @@ If you want to learn how to use DungeonsXL step by step, please have a look at t
DungeonsXL works with 1.7.8 and higher. However, support for 1.10.x / 1.9.x has a higher priority than support for 1.8.x and lower. Some cosmetic features require the Spigot API and will therefore not work with CraftBukkit.
Older versions of DungeonsXL support versions since Minecraft 1.3.x, but of course, they are completely unsupported.
* [1.7.8-1.10](../../tree/master)
* [1.7.8-1.10.2](../../tree/master)
* [1.7.5](../../tree/50f772d14281bfe278dba2559d1758cc459c1a30)
* [1.7.2](../../tree/eccf82b7335dfb0723e3cd37a57df1a968ea7842)
* [1.6.4](../../tree/780145cf783ea76fe1bfee04cf89216bd4f92e1d)

View File

@ -70,7 +70,7 @@
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<artifactId>spigot</artifactId>
<version>1.10.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@ -121,11 +121,6 @@
<artifactId>BetonQuest</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>com.boydti</groupId>
<artifactId>fawe-api</artifactId>
<version>3.5.0-dev</version>
</dependency>
</dependencies>
<repositories>
<repository>

View File

@ -188,6 +188,7 @@ public class DungeonsXL extends BRPlugin {
@Override
public void onDisable() {
mainConfig.setTweaksEnabled(false);
// Save
saveData();
messageConfig.save();

View File

@ -97,7 +97,7 @@ public class CreateCommand extends BRCommand {
MessageUtil.log(plugin, DMessages.LOG_WORLD_GENERATION_FINISHED.getMessage());
// Tp Player
new DEditPlayer(player, editWorld.getWorld());
DEditPlayer.create(player, editWorld);
}
}

View File

@ -77,7 +77,7 @@ public class EditCommand extends BRCommand {
return;
}
new DEditPlayer(player, editWorld.getWorld());
DEditPlayer.create(player, editWorld);
}
}

View File

@ -81,7 +81,7 @@ public class EnterCommand extends BRCommand {
joining.sendMessage(DMessages.CMD_ENTER_SUCCESS.getMessage(joining.getName(), targetName));
for (Player player : joining.getPlayers()) {
new DGamePlayer(player, game.getWorld()).ready();
DGamePlayer.create(player, game.getWorld(), true);
}
}

View File

@ -27,6 +27,7 @@ import java.io.File;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.scheduler.BukkitRunnable;
/**
* @author Frank Baumann, Daniel Saukel
@ -47,8 +48,8 @@ public class ImportCommand extends BRCommand {
@Override
public void onExecute(String[] args, CommandSender sender) {
File target = new File(DungeonsXL.MAPS, args[1]);
File source = new File(Bukkit.getWorldContainer(), args[1]);
final File target = new File(DungeonsXL.MAPS, args[1]);
final File source = new File(Bukkit.getWorldContainer(), args[1]);
if (!source.exists()) {
MessageUtil.sendMessage(sender, DMessages.ERROR_NO_SUCH_MAP.getMessage(args[1]));
@ -68,10 +69,19 @@ public class ImportCommand extends BRCommand {
MessageUtil.log(plugin, DMessages.LOG_NEW_MAP.getMessage());
MessageUtil.log(plugin, DMessages.LOG_IMPORT_WORLD.getMessage());
FileUtil.copyDirectory(source, target, new String[]{"playerdata", "stats"});
if (!plugin.getMainConfig().areTweaksEnabled()) {
FileUtil.copyDirectory(source, target, new String[]{"playerdata", "stats"});
} else {
new BukkitRunnable() {
@Override
public void run() {
FileUtil.copyDirectory(source, target, new String[]{"playerdata", "stats"});
}
}.runTaskAsynchronously(plugin);
}
plugin.getDWorlds().addResource(new DResourceWorld(plugin.getDWorlds(), args[1]));
MessageUtil.sendMessage(sender, DMessages.CMD_IMPORT_SUCCESS.getMessage(args[1]));
}

View File

@ -58,7 +58,9 @@ public class ListCommand extends BRCommand {
}
ArrayList<String> mapList = new ArrayList<>();
for (File file : DungeonsXL.MAPS.listFiles()) {
mapList.add(file.getName());
if (!file.equals(DWorlds.RAW)) {
mapList.add(file.getName());
}
}
ArrayList<String> loadedList = new ArrayList<>();
for (DEditWorld editWorld : worlds.getEditWorlds()) {

View File

@ -145,12 +145,12 @@ public class PlayCommand extends BRCommand {
if (dGroup.getGameWorld().getLobbyLocation() == null) {
for (Player groupPlayer : dGroup.getPlayers()) {
new DGamePlayer(groupPlayer, dGroup.getGameWorld());
DGamePlayer.create(groupPlayer, dGroup.getGameWorld());
}
} else {
for (Player groupPlayer : dGroup.getPlayers()) {
new DGamePlayer(groupPlayer, dGroup.getGameWorld());
DGamePlayer.create(groupPlayer, dGroup.getGameWorld());
}
}
}

View File

@ -20,6 +20,7 @@ import io.github.dre2n.commons.command.BRCommand;
import io.github.dre2n.commons.util.messageutil.MessageUtil;
import io.github.dre2n.dungeonsxl.DungeonsXL;
import io.github.dre2n.dungeonsxl.config.DMessages;
import io.github.dre2n.dungeonsxl.config.MainConfig;
import io.github.dre2n.dungeonsxl.config.MainConfig.BackupMode;
import io.github.dre2n.dungeonsxl.player.DPermissions;
import io.github.dre2n.dungeonsxl.world.DEditWorld;
@ -32,6 +33,7 @@ import org.bukkit.entity.Player;
public class SaveCommand extends BRCommand {
DungeonsXL plugin = DungeonsXL.getInstance();
MainConfig mainConfig = plugin.getMainConfig();
public SaveCommand() {
setCommand("save");
@ -47,9 +49,9 @@ public class SaveCommand extends BRCommand {
Player player = (Player) sender;
DEditWorld editWorld = DEditWorld.getByWorld(player.getWorld());
if (editWorld != null) {
BackupMode backupMode = plugin.getMainConfig().getBackupMode();
BackupMode backupMode = mainConfig.getBackupMode();
if (backupMode == BackupMode.ON_SAVE || backupMode == BackupMode.ON_DISABLE_AND_SAVE) {
editWorld.getResource().backup(false);
editWorld.getResource().backup(mainConfig.areTweaksEnabled());
}
editWorld.save();

View File

@ -38,7 +38,7 @@ public class MainConfig extends BRConfig {
NEVER
}
public static final int CONFIG_VERSION = 10;
public static final int CONFIG_VERSION = 11;
private String language = "english";
private boolean enableEconomy = false;
@ -65,7 +65,10 @@ public class MainConfig extends BRConfig {
/* Misc */
private boolean sendFloorTitle = true;
private Map<String, Object> externalMobProviders = new HashMap<>();
/* Performance */
private int maxInstances = 10;
private boolean tweaksEnabled = false;
/* Secure Mode */
private boolean secureModeEnabled = false;
@ -247,6 +250,21 @@ public class MainConfig extends BRConfig {
this.maxInstances = maxInstances;
}
/**
* @return if the performance tweaks are enabled
*/
public boolean areTweaksEnabled() {
return tweaksEnabled;
}
/**
* @param enabled
* if the performance tweaks are enabled
*/
public void setTweaksEnabled(boolean enabled) {
tweaksEnabled = enabled;
}
/**
* @return if the secure mode is enabled
*/
@ -390,6 +408,10 @@ public class MainConfig extends BRConfig {
config.set("maxInstances", maxInstances);
}
if (!config.contains("tweaksEnabled")) {
config.set("tweaksEnabled", tweaksEnabled);
}
if (!config.contains("secureMode.enabled")) {
config.set("secureMode.enabled", secureModeEnabled);
}
@ -473,6 +495,10 @@ public class MainConfig extends BRConfig {
maxInstances = config.getInt("maxInstances");
}
if (config.contains("tweaksEnabled")) {
tweaksEnabled = config.getBoolean("tweaksEnabled");
}
if (config.contains("secureMode.enabled")) {
secureModeEnabled = config.getBoolean("secureMode.enabled");
}

View File

@ -57,26 +57,31 @@ public class SignData {
* the DEditWorld where the signs are
* @throws IOException
*/
public void deserializeSigns(DEditWorld editWorld) throws IOException {
ObjectInputStream os = new ObjectInputStream(new FileInputStream(file));
int length = os.readInt();
public void deserializeSigns(DEditWorld editWorld) {
try {
ObjectInputStream os = new ObjectInputStream(new FileInputStream(file));
int length = os.readInt();
for (int i = 0; i < length; i++) {
int x = os.readInt();
int y = os.readInt();
int z = os.readInt();
for (int i = 0; i < length; i++) {
int x = os.readInt();
int y = os.readInt();
int z = os.readInt();
Block block = editWorld.getWorld().getBlockAt(x, y, z);
editWorld.getSigns().add(block);
Block block = editWorld.getWorld().getBlockAt(x, y, z);
editWorld.getSigns().add(block);
if (block.getState() instanceof Sign) {
Sign sign = (Sign) block.getState();
String[] lines = sign.getLines();
if (block.getState() instanceof Sign) {
Sign sign = (Sign) block.getState();
String[] lines = sign.getLines();
if (lines[0].equalsIgnoreCase("[lobby]")) {
editWorld.setLobbyLocation(block.getLocation());
if (lines[0].equalsIgnoreCase("[lobby]")) {
editWorld.setLobbyLocation(block.getLocation());
}
}
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
@ -88,23 +93,28 @@ public class SignData {
* @return a Set of all DSign blocks
* @throws IOException
*/
public void deserializeSigns(DGameWorld gameWorld) throws IOException {
ObjectInputStream os = new ObjectInputStream(new FileInputStream(file));
public void deserializeSigns(DGameWorld gameWorld) {
try {
ObjectInputStream os = new ObjectInputStream(new FileInputStream(file));
int length = os.readInt();
for (int i = 0; i < length; i++) {
int x = os.readInt();
int y = os.readInt();
int z = os.readInt();
int length = os.readInt();
for (int i = 0; i < length; i++) {
int x = os.readInt();
int y = os.readInt();
int z = os.readInt();
Block block = gameWorld.getWorld().getBlockAt(x, y, z);
if (block.getState() instanceof Sign) {
DSign dSign = DSign.create((Sign) block.getState(), gameWorld);
gameWorld.getDSigns().add(dSign);
Block block = gameWorld.getWorld().getBlockAt(x, y, z);
if (block.getState() instanceof Sign) {
DSign dSign = DSign.create((Sign) block.getState(), gameWorld);
gameWorld.getDSigns().add(dSign);
}
}
}
os.close();
os.close();
} catch (IOException exception) {
exception.printStackTrace();
}
}
/**
@ -114,7 +124,7 @@ public class SignData {
* the DEditWorld that contains the signs to serialize
* @throws IOException
*/
public void serializeSigns(DEditWorld editWorld) throws IOException {
public void serializeSigns(DEditWorld editWorld) {
serializeSigns(editWorld.getSigns());
}
@ -125,17 +135,22 @@ public class SignData {
* the signs to serialize
* @throws IOException
*/
public void serializeSigns(List<Block> signs) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
out.writeInt(signs.size());
public void serializeSigns(List<Block> signs) {
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
out.writeInt(signs.size());
for (Block sign : signs) {
out.writeInt(sign.getX());
out.writeInt(sign.getY());
out.writeInt(sign.getZ());
for (Block sign : signs) {
out.writeInt(sign.getX());
out.writeInt(sign.getY());
out.writeInt(sign.getZ());
}
out.close();
} catch (IOException exception) {
exception.printStackTrace();
}
out.close();
}
}

View File

@ -202,7 +202,7 @@ public class DPortal extends GlobalProtection {
dGroup.setGameWorld(target);
}
new DGamePlayer(player, target);
DGamePlayer.create(player, target);
}
@Override

View File

@ -554,7 +554,7 @@ public class PlayerListener implements Listener {
continue;
}
new DGamePlayer(player, dGroup.getGameWorld());
DGamePlayer.create(player, dGroup.getGameWorld());
plugin.debug.end("PlayerListener#onJoin", true);
return;
}

View File

@ -20,6 +20,7 @@ import io.github.dre2n.commons.util.messageutil.MessageUtil;
import io.github.dre2n.commons.util.playerutil.PlayerUtil;
import io.github.dre2n.dungeonsxl.config.DMessages;
import io.github.dre2n.dungeonsxl.event.dplayer.DPlayerUpdateEvent;
import io.github.dre2n.dungeonsxl.task.CreateDInstancePlayerTask;
import io.github.dre2n.dungeonsxl.world.DEditWorld;
import java.util.concurrent.CopyOnWriteArrayList;
import org.bukkit.ChatColor;
@ -40,19 +41,15 @@ public class DEditPlayer extends DInstancePlayer {
private String[] linesCopy;
public DEditPlayer(DGlobalPlayer player, DEditWorld world) {
this(player.getPlayer(), world.getWorld());
}
public DEditPlayer(Player player, World world) {
super(player, world);
public DEditPlayer(Player player, DEditWorld world) {
super(player, world.getWorld());
player.setGameMode(GameMode.CREATIVE);
clearPlayerData();
Location teleport = DEditWorld.getByWorld(world).getLobbyLocation();
Location teleport = world.getLobbyLocation();
if (teleport == null) {
PlayerUtil.secureTeleport(player, world.getSpawnLocation());
PlayerUtil.secureTeleport(player, world.getWorld().getSpawnLocation());
} else {
PlayerUtil.secureTeleport(player, teleport);
}
@ -65,6 +62,16 @@ public class DEditPlayer extends DInstancePlayer {
}
}
/**
* @param player
* the represented Player
* @param editWorld
* the player's EditWorld
*/
public static void create(Player player, DEditWorld editWorld) {
new CreateDInstancePlayerTask(player, editWorld).runTaskTimer(plugin, 0L, 5L);
}
/* Getters and setters */
/**
* @return the linesCopy

View File

@ -33,9 +33,11 @@ import io.github.dre2n.dungeonsxl.game.GameRules;
import io.github.dre2n.dungeonsxl.game.GameType;
import io.github.dre2n.dungeonsxl.game.GameTypeDefault;
import io.github.dre2n.dungeonsxl.mob.DMob;
import static io.github.dre2n.dungeonsxl.player.DGlobalPlayer.plugin;
import io.github.dre2n.dungeonsxl.requirement.Requirement;
import io.github.dre2n.dungeonsxl.reward.DLootInventory;
import io.github.dre2n.dungeonsxl.reward.Reward;
import io.github.dre2n.dungeonsxl.task.CreateDInstancePlayerTask;
import io.github.dre2n.dungeonsxl.trigger.DistanceTrigger;
import io.github.dre2n.dungeonsxl.world.DGameWorld;
import io.github.dre2n.dungeonsxl.world.DResourceWorld;
@ -54,6 +56,7 @@ import org.bukkit.entity.Wolf;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.scheduler.BukkitRunnable;
/**
* Represents a player in a DGameWorld.
@ -77,15 +80,11 @@ public class DGamePlayer extends DInstancePlayer {
private int initialLives = -1;
private int lives;
public DGamePlayer(Player player, DGameWorld gameWorld) {
this(player, gameWorld.getWorld());
}
public DGamePlayer(Player player, World world) {
super(player, world);
public DGamePlayer(Player player, DGameWorld world) {
super(player, world.getWorld());
plugin.debug.start("DGamePlayer#init");
Game game = Game.getByWorld(world);
Game game = Game.getByGameWorld(world);
if (game == null) {
game = new Game(DGroup.getByPlayer(player));
}
@ -104,15 +103,37 @@ public class DGamePlayer extends DInstancePlayer {
initialLives = rules.getInitialLives();
lives = initialLives;
Location teleport = DGameWorld.getByWorld(world).getLobbyLocation();
Location teleport = world.getLobbyLocation();
if (teleport == null) {
PlayerUtil.secureTeleport(player, world.getSpawnLocation());
PlayerUtil.secureTeleport(player, world.getWorld().getSpawnLocation());
} else {
PlayerUtil.secureTeleport(player, teleport);
}
plugin.debug.end("DGamePlayer#init", true);
}
/**
* @param player
* the represented Player
* @param gameWorld
* the player's GameWorld
*/
public static void create(Player player, DGameWorld gameWorld) {
create(player, gameWorld, false);
}
/**
* @param player
* the represented Player
* @param gameWorld
* the player's GameWorld
* @param ready
* if the player will be ready from the beginning
*/
public static void create(Player player, DGameWorld gameWorld, boolean ready) {
new CreateDInstancePlayerTask(player, gameWorld, ready).runTaskTimer(plugin, 0L, 5L);
}
/* Getters and setters */
/**
* @param player

View File

@ -31,7 +31,7 @@ public abstract class DInstancePlayer extends DGlobalPlayer {
private World world;
private boolean inDungeonChat = false;
public DInstancePlayer(Player player, World world) {
DInstancePlayer(Player player, World world) {
super(player);
double health = player.getHealth();

View File

@ -87,7 +87,7 @@ public class AnnouncerStartGameTask extends BukkitRunnable {
}
for (Player player : game.getPlayers()) {
new DGamePlayer(player, game.getWorld());
DGamePlayer.create(player, game.getWorld());
}
announcer.endStartTask();

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2012-2016 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.dre2n.dungeonsxl.task;
import io.github.dre2n.commons.util.messageutil.MessageUtil;
import io.github.dre2n.dungeonsxl.player.DEditPlayer;
import io.github.dre2n.dungeonsxl.player.DGamePlayer;
import io.github.dre2n.dungeonsxl.world.DEditWorld;
import io.github.dre2n.dungeonsxl.world.DGameWorld;
import io.github.dre2n.dungeonsxl.world.DInstanceWorld;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
/**
* @author Daniel Saukel
*/
public class CreateDInstancePlayerTask extends BukkitRunnable {
public static final String BAR = "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588";
private UUID player;
private DInstanceWorld instance;
private boolean ready;
private int i = 12;
public CreateDInstancePlayerTask(Player player, DInstanceWorld instance) {
this.player = player.getUniqueId();
this.instance = instance;
}
public CreateDInstancePlayerTask(Player player, DInstanceWorld instance, boolean ready) {
this.player = player.getUniqueId();
this.instance = instance;
this.ready = ready;
}
@Override
public void run() {
Player player = Bukkit.getPlayer(this.player);
if (player == null || !player.isOnline()) {
cancel();
return;
}
if (instance.exists()) {
if (instance instanceof DGameWorld) {
DGamePlayer gamePlayer = new DGamePlayer(player, (DGameWorld) instance);
if (ready) {
gamePlayer.ready();
}
} else if (instance instanceof DEditWorld) {
new DEditPlayer(player, (DEditWorld) instance);
}
cancel();
return;
}
StringBuilder bar = new StringBuilder(BAR);
int pos = i;
if (bar.length() - pos < 0) {
pos = bar.length();
}
bar.insert(bar.length() - pos, ChatColor.GREEN.toString());
pos = i - 2;
if (pos > 0) {
bar.insert(bar.length() - pos, ChatColor.DARK_RED.toString());
}
MessageUtil.sendActionBarMessage(player, ChatColor.DARK_RED + bar.toString());
i--;
if (i == 0) {
i = 12;
}
}
}

View File

@ -32,16 +32,20 @@ public class WorldUnloadTask extends BukkitRunnable {
@Override
public void run() {
for (DGameWorld gameWorld : plugin.getDWorlds().getGameWorlds()) {
if (gameWorld.getWorld().getPlayers().isEmpty()) {
if (DGamePlayer.getByWorld(gameWorld.getWorld()).isEmpty()) {
gameWorld.delete();
if (gameWorld.exists()) {
if (gameWorld.getWorld().getPlayers().isEmpty()) {
if (DGamePlayer.getByWorld(gameWorld.getWorld()).isEmpty()) {
gameWorld.delete();
}
}
}
}
for (DEditWorld editWorld : plugin.getDWorlds().getEditWorlds()) {
if (editWorld.getWorld().getPlayers().isEmpty()) {
editWorld.delete(true);
if (editWorld.exists()) {
if (editWorld.getWorld().getPlayers().isEmpty()) {
editWorld.delete(true);
}
}
}
}

View File

@ -0,0 +1,206 @@
/*
* Copyright (C) 2012-2016 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.dre2n.dungeonsxl.util;
import java.io.File;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.logging.Logger;
import net.minecraft.server.v1_10_R1.BlockPosition;
import net.minecraft.server.v1_10_R1.Convertable;
import net.minecraft.server.v1_10_R1.EntityTracker;
import net.minecraft.server.v1_10_R1.EnumDifficulty;
import net.minecraft.server.v1_10_R1.EnumGamemode;
import net.minecraft.server.v1_10_R1.IDataManager;
import net.minecraft.server.v1_10_R1.IProgressUpdate;
import net.minecraft.server.v1_10_R1.MinecraftServer;
import net.minecraft.server.v1_10_R1.ServerNBTManager;
import net.minecraft.server.v1_10_R1.WorldData;
import net.minecraft.server.v1_10_R1.WorldLoaderServer;
import net.minecraft.server.v1_10_R1.WorldManager;
import net.minecraft.server.v1_10_R1.WorldServer;
import net.minecraft.server.v1_10_R1.WorldSettings;
import net.minecraft.server.v1_10_R1.WorldType;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.craftbukkit.v1_10_R1.CraftServer;
import org.bukkit.craftbukkit.v1_10_R1.CraftWorld;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.PluginManager;
/**
* A custom thread safe world loader.
*
* @author Daniel Saukel
*/
public class WorldLoader {
static MinecraftServer console;
static CraftServer server = ((CraftServer) Bukkit.getServer());
static Map<String, World> worlds;
static PluginManager pluginManager = Bukkit.getPluginManager();
static File worldContainer = Bukkit.getWorldContainer();
static Logger logger = Bukkit.getLogger();
static {
try {
Field fConsole = CraftServer.class.getDeclaredField("console");
fConsole.setAccessible(true);
console = (MinecraftServer) fConsole.get(server);
Field fWorlds = CraftServer.class.getDeclaredField("worlds");
fWorlds.setAccessible(true);
worlds = (Map<String, World>) fWorlds.get(server);
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException exception) {
exception.printStackTrace();
}
}
/**
* @param creator
* the WorldCreator which stores the information to create the new world
* @return
* the new World
*/
@SuppressWarnings("deprecation")
public static World createWorld(WorldCreator creator) {
String name = creator.name();
ChunkGenerator generator = creator.generator();
File folder = new File(worldContainer, name);
World world = Bukkit.getWorld(name);
WorldType type = WorldType.getType(creator.type().getName());
boolean generateStructures = creator.generateStructures();
if (world != null) {
return world;
}
if ((folder.exists()) && (!folder.isDirectory())) {
throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder");
}
if (generator == null) {
generator = server.getGenerator(name);
}
Convertable converter = new WorldLoaderServer(worldContainer, server.getHandle().getServer().getDataConverterManager());
if (converter.isConvertable(name)) {
logger.info("Converting world '" + name + "'");
converter.convert(name, new IProgressUpdate() {
private long b = System.currentTimeMillis();
@Override
public void a(String s) {
}
@Override
public void a(int i) {
if (System.currentTimeMillis() - this.b >= 1000L) {
this.b = System.currentTimeMillis();
MinecraftServer.LOGGER.info("Converting... " + i + "%");
}
}
@Override
public void c(String s) {
}
});
}
int dimension = CraftWorld.CUSTOM_DIMENSION_OFFSET + console.worlds.size();
boolean used = false;
do {
for (WorldServer server : console.worlds) {
used = server.dimension == dimension;
if (used) {
dimension++;
break;
}
}
} while (used);
boolean hardcore = false;
IDataManager sdm = new ServerNBTManager(worldContainer, name, true, server.getHandle().getServer().getDataConverterManager());
WorldData worlddata = sdm.getWorldData();
WorldSettings worldSettings = null;
if (worlddata == null) {
worldSettings = new WorldSettings(creator.seed(), EnumGamemode.getById(server.getDefaultGameMode().getValue()), generateStructures, hardcore, type);
worldSettings.setGeneratorSettings(creator.generatorSettings());
worlddata = new WorldData(worldSettings, name);
}
worlddata.checkName(name); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end)
WorldServer internal = (WorldServer) new WorldServer(console, sdm, worlddata, dimension, console.methodProfiler, creator.environment(), generator).b();
if (!(worlds.containsKey(name.toLowerCase(java.util.Locale.ENGLISH)))) {
return null;
}
if (worldSettings != null) {
internal.a(worldSettings);
}
internal.scoreboard = server.getScoreboardManager().getMainScoreboard().getHandle();
internal.tracker = new EntityTracker(internal);
internal.addIWorldAccess(new WorldManager(console, internal));
internal.worldData.setDifficulty(EnumDifficulty.EASY);
internal.setSpawnFlags(true, true);
console.worlds.add(internal);
if (generator != null) {
internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld()));
}
pluginManager.callEvent(new WorldInitEvent(internal.getWorld()));
logger.info("Preparing start region for level " + (console.worlds.size() - 1) + " (Seed: " + internal.getSeed() + ")");
if (internal.getWorld().getKeepSpawnInMemory()) {
short short1 = 196;
long i = System.currentTimeMillis();
for (int j = -short1; j <= short1; j += 16) {
for (int k = -short1; k <= short1; k += 16) {
long l = System.currentTimeMillis();
if (l < i) {
i = l;
}
if (l > i + 1000L) {
int i1 = (short1 * 2 + 1) * (short1 * 2 + 1);
int j1 = (j + short1) * (short1 * 2 + 1) + k + 1;
logger.info("Preparing spawn area for " + name + ", " + (j1 * 100 / i1) + "%");
i = l;
}
BlockPosition chunkcoordinates = internal.getSpawn();
try {
internal.getChunkProviderServer().getChunkAt(chunkcoordinates.getX() + j >> 4, chunkcoordinates.getZ() + k >> 4);
} catch (Exception exception) {
}
}
}
}
pluginManager.callEvent(new WorldLoadEvent(internal.getWorld()));
return internal.getWorld();
}
}

View File

@ -28,6 +28,7 @@ import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
/**
* @author Frank Baumann, Daniel Saukel
@ -43,7 +44,10 @@ public class DEditWorld extends DInstanceWorld {
DEditWorld(DResourceWorld resourceWorld, File folder, World world, int id) {
super(resourceWorld, folder, world, id);
generateIdFile();
}
DEditWorld(DResourceWorld resourceWorld, File folder, int id) {
this(resourceWorld, folder, null, id);
}
/* Getters and setters */
@ -113,14 +117,21 @@ public class DEditWorld extends DInstanceWorld {
getWorld().save();
FileUtil.copyDirectory(getFolder(), getResource().getFolder(), DungeonsXL.EXCLUDED_FILES);
FileUtil.deleteUnusedFiles(getResource().getFolder());
if (!plugin.getMainConfig().areTweaksEnabled()) {
FileUtil.copyDirectory(getFolder(), getResource().getFolder(), DungeonsXL.EXCLUDED_FILES);
FileUtil.deleteUnusedFiles(getResource().getFolder());
try {
getResource().getSignData().serializeSigns(signs);
} catch (IOException exception) {
exception.printStackTrace();
} else {
new BukkitRunnable() {
@Override
public void run() {
FileUtil.copyDirectory(getFolder(), getResource().getFolder(), DungeonsXL.EXCLUDED_FILES);
FileUtil.deleteUnusedFiles(getResource().getFolder());
}
}.runTaskAsynchronously(plugin);
}
getResource().getSignData().serializeSigns(signs);
}
@Override
@ -134,7 +145,8 @@ public class DEditWorld extends DInstanceWorld {
* @param save
* whether this world should be saved
*/
public void delete(boolean save) {
public void delete(final boolean save) {
plugin.debug.start("DEditWorld#delete");
EditWorldUnloadEvent event = new EditWorldUnloadEvent(this, true);
plugin.getServer().getPluginManager().callEvent(event);
@ -142,26 +154,42 @@ public class DEditWorld extends DInstanceWorld {
return;
}
worlds.getInstances().remove(this);
for (Player player : getWorld().getPlayers()) {
DEditPlayer dPlayer = DEditPlayer.getByPlayer(player);
dPlayer.leave();
}
if (save) {
plugin.getServer().unloadWorld(getWorld(), true);
if (!plugin.getMainConfig().areTweaksEnabled()) {
if (save) {
plugin.getServer().unloadWorld(getWorld(), true);
}
FileUtil.copyDirectory(getFolder(), getResource().getFolder(), DungeonsXL.EXCLUDED_FILES);
FileUtil.deleteUnusedFiles(getResource().getFolder());
if (!save) {
plugin.getServer().unloadWorld(getWorld(), true);
}
FileUtil.removeDirectory(getFolder());
worlds.removeInstance(this);
} else {
final DEditWorld editWorld = this;
new BukkitRunnable() {
@Override
public void run() {
if (save) {
plugin.getServer().unloadWorld(getWorld(), true);
}
FileUtil.copyDirectory(getFolder(), getResource().getFolder(), DungeonsXL.EXCLUDED_FILES);
FileUtil.deleteUnusedFiles(getResource().getFolder());
if (!save) {
plugin.getServer().unloadWorld(getWorld(), true);
}
FileUtil.removeDirectory(getFolder());
worlds.removeInstance(editWorld);
}
}.runTaskAsynchronously(plugin);
}
FileUtil.copyDirectory(getFolder(), getResource().getFolder(), DungeonsXL.EXCLUDED_FILES);
FileUtil.deleteUnusedFiles(getResource().getFolder());
if (!save) {
plugin.getServer().unloadWorld(getWorld(), true);
}
FileUtil.removeDirectory(getFolder());
worlds.removeInstance(this);
plugin.debug.end("DEditWorld#delete", true);
}
/* Statics */

View File

@ -49,6 +49,7 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Spider;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
/**
* @author Frank Baumann, Milan Albrecht, Daniel Saukel
@ -73,6 +74,10 @@ public class DGameWorld extends DInstanceWorld {
super(resourceWorld, folder, world, id);
}
DGameWorld(DResourceWorld resourceWorld, File folder, int id) {
this(resourceWorld, folder, null, id);
}
/**
* @return
* the Game connected to the DGameWorld
@ -354,7 +359,6 @@ public class DGameWorld extends DInstanceWorld {
* Set up the instance for the game
*/
public void startGame() {
plugin.debug.start("DGameWorld#startGame");
GameWorldStartGameEvent event = new GameWorldStartGameEvent(this, getGame());
plugin.getServer().getPluginManager().callEvent(event);
@ -387,7 +391,6 @@ public class DGameWorld extends DInstanceWorld {
}
}
}
plugin.debug.end("DGameWorld#startGame", true);
}
/**
@ -403,11 +406,22 @@ public class DGameWorld extends DInstanceWorld {
return;
}
plugin.getDWorlds().getInstances().remove(this);
plugin.getServer().unloadWorld(getWorld(), true);
FileUtil.removeDirectory(getFolder());
if (!plugin.getMainConfig().areTweaksEnabled()) {
plugin.getServer().unloadWorld(getWorld(), false);
FileUtil.removeDirectory(getFolder());
worlds.removeInstance(this);
worlds.removeInstance(this);
} else {
final DGameWorld gameWorld = this;
new BukkitRunnable() {
@Override
public void run() {
plugin.getServer().unloadWorld(getWorld(), false);
FileUtil.removeDirectory(getFolder());
worlds.removeInstance(gameWorld);
}
}.runTaskAsynchronously(plugin);
}
plugin.debug.end("DGameWorld#delete", true);
}

View File

@ -34,7 +34,7 @@ public abstract class DInstanceWorld {
private DResourceWorld resourceWorld;
private File folder;
private World world;
World world;
private int id;
private Location lobby;
@ -83,6 +83,13 @@ public abstract class DInstanceWorld {
return world;
}
/**
* @return false if this instance does not have a world, yet
*/
public boolean exists() {
return world != null;
}
/**
* @return the unique ID
*/

View File

@ -20,13 +20,14 @@ import io.github.dre2n.commons.util.FileUtil;
import io.github.dre2n.dungeonsxl.DungeonsXL;
import io.github.dre2n.dungeonsxl.config.SignData;
import io.github.dre2n.dungeonsxl.config.WorldConfig;
import io.github.dre2n.dungeonsxl.event.editworld.EditWorldGenerateEvent;
import io.github.dre2n.dungeonsxl.player.DEditPlayer;
import io.github.dre2n.dungeonsxl.task.BackupResourceTask;
import io.github.dre2n.dungeonsxl.util.WorldLoader;
import java.io.File;
import java.io.IOException;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.scheduler.BukkitRunnable;
@ -187,32 +188,47 @@ public class DResourceWorld {
* whether the instance is a DGameWorld
* @return an instance of this world
*/
public DInstanceWorld instantiate(boolean game) {
public DInstanceWorld instantiate(final boolean game) {
plugin.debug.start("DResourceWorld#instantiate");
int id = worlds.generateId();
String name = worlds.generateName(game);
File instanceFolder = new File(Bukkit.getWorldContainer(), name);
FileUtil.copyDirectory(folder, instanceFolder, DungeonsXL.EXCLUDED_FILES);
final File instanceFolder = new File(Bukkit.getWorldContainer(), name);
if (Bukkit.getWorld(name) != null) {
return null;
}
World world = plugin.getServer().createWorld(WorldCreator.name(name));
final DInstanceWorld instance = game ? new DGameWorld(this, instanceFolder, id) : new DEditWorld(this, instanceFolder, id);
if (!plugin.getMainConfig().areTweaksEnabled()) {
FileUtil.copyDirectory(folder, instanceFolder, DungeonsXL.EXCLUDED_FILES);
instance.world = plugin.getServer().createWorld(WorldCreator.name(name));
DInstanceWorld instance = null;
try {
if (game) {
instance = new DGameWorld(this, instanceFolder, world, id);
signData.deserializeSigns((DGameWorld) instance);
} else {
instance = new DEditWorld(this, instanceFolder, world, id);
signData.deserializeSigns((DEditWorld) instance);
}
} catch (IOException exception) {
exception.printStackTrace();
} else {
new BukkitRunnable() {
@Override
public void run() {
FileUtil.copyDirectory(folder, instanceFolder, DungeonsXL.EXCLUDED_FILES);
instance.world = WorldLoader.createWorld(WorldCreator.name(instanceFolder.getName()));
new BukkitRunnable() {
@Override
public void run() {
if (game) {
signData.deserializeSigns((DGameWorld) instance);
} else {
signData.deserializeSigns((DEditWorld) instance);
}
}
}.runTask(plugin);
}
}.runTaskAsynchronously(plugin);
}
plugin.debug.end("DResourceWorld#instantiate", true);
@ -240,23 +256,34 @@ public class DResourceWorld {
*/
public DEditWorld generate() {
plugin.debug.start("DResourceWorld#generate");
String name = worlds.generateName(false);
WorldCreator creator = WorldCreator.name(name);
final String name = worlds.generateName(false);
int id = worlds.generateId();
final File folder = new File(Bukkit.getWorldContainer(), name);
final WorldCreator creator = new WorldCreator(name);
creator.type(WorldType.FLAT);
creator.generateStructures(false);
/*EditWorldGenerateEvent event = new EditWorldGenerateEvent(this);
final DEditWorld editWorld = new DEditWorld(this, folder, id);
EditWorldGenerateEvent event = new EditWorldGenerateEvent(editWorld);
plugin.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
return null;
}
*/
int id = worlds.generateId();
File folder = new File(Bukkit.getWorldContainer(), name);
World world = plugin.getServer().createWorld(creator);
DEditWorld editWorld = new DEditWorld(this, folder, world, id);
if (!plugin.getMainConfig().areTweaksEnabled()) {
editWorld.world = creator.createWorld();
} else {
new BukkitRunnable() {
@Override
public void run() {
FileUtil.copyDirectory(DWorlds.RAW, folder, DungeonsXL.EXCLUDED_FILES);
editWorld.generateIdFile();
editWorld.world = WorldLoader.createWorld(creator);
}
}.runTaskAsynchronously(plugin);
}
plugin.debug.end("DResourceWorld#generate", true);
return editWorld;

View File

@ -19,11 +19,15 @@ package io.github.dre2n.dungeonsxl.world;
import io.github.dre2n.commons.util.FileUtil;
import io.github.dre2n.commons.util.NumberUtil;
import io.github.dre2n.dungeonsxl.DungeonsXL;
import io.github.dre2n.dungeonsxl.config.MainConfig;
import io.github.dre2n.dungeonsxl.config.MainConfig.BackupMode;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
/**
* @author Daniel Saukel
@ -31,16 +35,21 @@ import org.bukkit.Bukkit;
public class DWorlds {
DungeonsXL plugin = DungeonsXL.getInstance();
MainConfig mainConfig = plugin.getMainConfig();
public static final File RAW = new File(DungeonsXL.MAPS, ".raw");
private Set<DResourceWorld> resources = new HashSet<>();
private Set<DInstanceWorld> instances = new HashSet<>();
public DWorlds(File folder) {
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
if (file.isDirectory() && !file.getName().equals(".raw")) {
resources.add(new DResourceWorld(this, file));
}
}
createRaw();
}
/* Getters and setters */
@ -203,11 +212,11 @@ public class DWorlds {
* Clean up all instances.
*/
public void deleteAllInstances() {
BackupMode backupMode = plugin.getMainConfig().getBackupMode();
BackupMode backupMode = mainConfig.getBackupMode();
HashSet<DInstanceWorld> instances = new HashSet<>(this.instances);
for (DInstanceWorld instance : instances) {
if (backupMode == BackupMode.ON_DISABLE | backupMode == BackupMode.ON_DISABLE_AND_SAVE && instance instanceof DEditWorld) {
instance.getResource().backup(false);
instance.getResource().backup(mainConfig.areTweaksEnabled());
}
instance.delete();
@ -246,4 +255,18 @@ public class DWorlds {
return "DXL_" + (game ? "Game" : "Edit") + "_" + generateId();
}
/**
* Creates a raw, new flat world sothat it can be copied if needed instead of getting generated from scratch.
*/
public void createRaw() {
WorldCreator creator = WorldCreator.name(".raw");
creator.type(WorldType.FLAT);
creator.generateStructures(false);
World world = creator.createWorld();
File worldFolder = new File(Bukkit.getWorldContainer(), ".raw");
FileUtil.copyDirectory(worldFolder, RAW, DungeonsXL.EXCLUDED_FILES);
Bukkit.unloadWorld(world, false);
FileUtil.removeDirectory(worldFolder);
}
}