461 lines
16 KiB
Java
461 lines
16 KiB
Java
|
|
package de.butzlabben.world.wrapper;
|
|
|
|
import com.google.common.base.Preconditions;
|
|
import de.butzlabben.WorldSystem;
|
|
import de.butzlabben.world.config.*;
|
|
import de.butzlabben.world.event.WorldCreateEvent;
|
|
import de.butzlabben.world.event.WorldLoadEvent;
|
|
import de.butzlabben.world.event.WorldUnloadEvent;
|
|
import de.butzlabben.world.util.PlayerPositions;
|
|
import de.butzlabben.world.util.PlayerWrapper;
|
|
import de.butzlabben.world.util.VersionUtil;
|
|
import org.apache.commons.io.FileUtils;
|
|
import org.bukkit.*;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
import org.bukkit.scheduler.BukkitTask;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.HashMap;
|
|
import java.util.UUID;
|
|
|
|
/**
|
|
* This class represents a systemworld, loaded or not
|
|
*
|
|
* @author Butzlabben
|
|
* @since 14.02.2018
|
|
*/
|
|
public class SystemWorld {
|
|
|
|
private static final HashMap<String, SystemWorld> cached = new HashMap<>();
|
|
private World w;
|
|
private String worldname;
|
|
private boolean unloading = false;
|
|
private boolean creating = false;
|
|
|
|
private BukkitTask unloadLaterTask;
|
|
|
|
private SystemWorld(String worldname) {
|
|
this.worldname = worldname;
|
|
w = Bukkit.getWorld(worldname);
|
|
}
|
|
|
|
/**
|
|
* This method is the online way to get a system world instance
|
|
*
|
|
* @param worldname as in minecraft
|
|
* @return a systemworld instance if it is a systemworld or null if is not a
|
|
* systemworld
|
|
* @throws NullPointerException worldname == null
|
|
*/
|
|
public static SystemWorld getSystemWorld(String worldname) {
|
|
Preconditions.checkNotNull(worldname, "worldname must not be null");
|
|
if (cached.containsKey(worldname))
|
|
return cached.get(worldname);
|
|
SystemWorld sw = new SystemWorld(worldname);
|
|
if (sw != null && sw.exists()) {
|
|
cached.put(worldname, sw);
|
|
return sw;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param w a world in bukkit, no matter if systemworld or not Trys to unload a
|
|
* systemworld later, with the given delay in the config
|
|
*/
|
|
public static void tryUnloadLater(World w) {
|
|
if (w != null)
|
|
Bukkit.getScheduler().runTaskLater(WorldSystem.getInstance(), () -> {
|
|
if (w.getPlayers().size() == 0) {
|
|
SystemWorld sw = SystemWorld.getSystemWorld(w.getName());
|
|
if (sw != null && sw.isLoaded())
|
|
sw.unloadLater(w);
|
|
}
|
|
}, 20);
|
|
}
|
|
|
|
public static boolean create(Player p, WorldTemplate template) {
|
|
return create(p.getUniqueId(), template);
|
|
}
|
|
|
|
|
|
/**
|
|
* Trys to create a new systemworld with all entries etc. finally loads the
|
|
* world
|
|
*
|
|
* @param uniqueID UUID of the player to create the world for
|
|
* @return whether it succesfull or not
|
|
*/
|
|
public static boolean create(UUID uniqueID, WorldTemplate template) {
|
|
|
|
DependenceConfig dc = new DependenceConfig(uniqueID);
|
|
|
|
String uuid = uniqueID.toString();
|
|
int id = DependenceConfig.getHighestID() + 1;
|
|
String worldname = "ID" + id + "-" + uuid;
|
|
Player p = Bukkit.getPlayer(uniqueID);
|
|
|
|
WorldCreator creator = template.generatorSettings.asWorldCreator(worldname);
|
|
|
|
WorldCreateEvent event = new WorldCreateEvent(uniqueID, creator);
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
if (event.isCancelled())
|
|
return false;
|
|
|
|
dc.createNewEntry();
|
|
|
|
String worlddir = PluginConfig.getWorlddir();
|
|
File exampleworld = new File(template.getPath());
|
|
if (new File(template.getPath() + "/uid.dat").exists()) {
|
|
new File(template.getPath() + "/uid.dat").delete();
|
|
}
|
|
|
|
File newworld = new File(worlddir + "/" + worldname);
|
|
|
|
if (exampleworld.isDirectory())
|
|
try {
|
|
FileUtils.copyDirectory(exampleworld, newworld);
|
|
} catch (IOException e) {
|
|
System.err.println("Couldn't create world for " + uuid);
|
|
e.printStackTrace();
|
|
}
|
|
else
|
|
newworld.mkdirs();
|
|
|
|
WorldConfig.create(uniqueID, template);
|
|
|
|
// Move World into Server dir
|
|
File world = new File(worlddir + "/" + worldname);
|
|
if (!world.exists()) {
|
|
world = new File(Bukkit.getWorldContainer(), worldname);
|
|
} else {
|
|
if (new File(Bukkit.getWorldContainer(), worldname).exists()
|
|
&& new File(PluginConfig.getWorlddir() + "/" + worldname).exists()) {
|
|
try {
|
|
FileUtils.deleteDirectory(new File(Bukkit.getWorldContainer(), worldname));
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
try {
|
|
FileUtils.moveDirectoryToDirectory(world, Bukkit.getWorldContainer(), false);
|
|
} catch (IOException e) {
|
|
if (p != null && p.isOnline())
|
|
p.sendMessage(PluginConfig.getPrefix() + "§cError: " + e.getMessage());
|
|
System.err.println("Couldn't load world of " + uuid);
|
|
e.printStackTrace();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SystemWorld sw = SystemWorld.getSystemWorld(worldname);
|
|
sw.setCreating(true);
|
|
|
|
// Run in scheduler so method returns without delay
|
|
new BukkitRunnable() {
|
|
@Override
|
|
public void run() {
|
|
WorldSystem.getInstance().getAdapter().create(event.getWorldCreator(), sw, () -> {
|
|
// Fix for #16
|
|
new BukkitRunnable() {
|
|
@Override
|
|
public void run() {
|
|
if (p != null && p.isOnline()) {
|
|
p.sendMessage(MessageConfig.getWorldCreated());
|
|
SettingsConfig.getCommandsonGet().stream()
|
|
.map(s -> s.replace("%player", p.getName()).replace("%world", sw.getName())
|
|
.replace("%uuid", p.getUniqueId().toString()))
|
|
.forEach(s -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), s));
|
|
}
|
|
}
|
|
}.runTask(WorldSystem.getInstance());
|
|
});
|
|
}
|
|
}.runTaskLater(WorldSystem.getInstance(), 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Trys to force-unload this world
|
|
*
|
|
* @param w associated world
|
|
* @throws NullPointerException w == null
|
|
*/
|
|
public void directUnload(World w) {
|
|
if (!Bukkit.isPrimaryThread()) {
|
|
Bukkit.getScheduler().runTask(WorldSystem.getInstance(), () -> directUnload(w));
|
|
return;
|
|
}
|
|
Preconditions.checkNotNull(w, "world must not be null");
|
|
setUnloading(true);
|
|
w.save();
|
|
Chunk[] arrayOfChunk;
|
|
int j = (arrayOfChunk = w.getLoadedChunks()).length;
|
|
for (int i = 0; i < j; i++) {
|
|
Chunk c = arrayOfChunk[i];
|
|
c.unload();
|
|
}
|
|
|
|
WorldConfig config = WorldConfig.getWorldConfig(worldname);
|
|
for (Player a : w.getPlayers()) {
|
|
PlayerPositions.instance.saveWorldsPlayerLocation(a, config);
|
|
a.teleport(PluginConfig.getSpawn(a));
|
|
a.setGameMode(PluginConfig.getSpawnGamemode());
|
|
}
|
|
if (unloading) {
|
|
if (Bukkit.unloadWorld(w, true)) {
|
|
File worldinserver = new File(Bukkit.getWorldContainer(), worldname);
|
|
File worlddir = new File(PluginConfig.getWorlddir());
|
|
try {
|
|
FileUtils.moveDirectoryToDirectory(worldinserver, worlddir, false);
|
|
Bukkit.getWorlds().remove(w);
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trys to unload this world later, with the given delay in the config
|
|
*
|
|
* @param w the associated world
|
|
* @throws NullPointerException w == null
|
|
*/
|
|
private void unloadLater(World w) {
|
|
if (!Bukkit.isPrimaryThread()) {
|
|
Bukkit.getScheduler().runTask(WorldSystem.getInstance(), () -> unloadLater(w));
|
|
return;
|
|
}
|
|
|
|
// Do not start another unload task
|
|
if (unloading) {
|
|
return;
|
|
}
|
|
|
|
Preconditions.checkNotNull(w, "world must not be null");
|
|
WorldUnloadEvent event = new WorldUnloadEvent(this);
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
if (event.isCancelled())
|
|
return;
|
|
// Set unloading to true
|
|
setUnloading(true);
|
|
w.save();
|
|
Chunk[] arrayOfChunk;
|
|
int j = (arrayOfChunk = w.getLoadedChunks()).length;
|
|
for (int i = 0; i < j; i++) {
|
|
Chunk c = arrayOfChunk[i];
|
|
c.unload();
|
|
}
|
|
for (Player a : w.getPlayers()) {
|
|
a.teleport(PluginConfig.getSpawn(a));
|
|
a.setGameMode(PluginConfig.getSpawnGamemode());
|
|
}
|
|
|
|
unloadLaterTask = Bukkit.getScheduler().runTaskLater(WorldSystem.getInstance(), () -> {
|
|
// Still in world unloading process?
|
|
if (unloading && w.getPlayers().size() == 0) {
|
|
if (Bukkit.unloadWorld(w, true)) {
|
|
File worldinserver = new File(Bukkit.getWorldContainer(), worldname);
|
|
File worlddir = new File(PluginConfig.getWorlddir());
|
|
try {
|
|
FileUtils.moveDirectoryToDirectory(worldinserver, worlddir, false);
|
|
Bukkit.getWorlds().remove(w);
|
|
setUnloading(false);
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}, 20 * PluginConfig.getUnloadingTime());
|
|
}
|
|
|
|
/**
|
|
* Trys to load this world, and messages the player about the process
|
|
*
|
|
* @param p the player to teleport on the world
|
|
* @throws NullPointerException if p is null
|
|
* @throws IllegalArgumentException if player is not online
|
|
*/
|
|
public void load(Player p) {
|
|
if (!Bukkit.isPrimaryThread()) {
|
|
Bukkit.getScheduler().runTask(WorldSystem.getInstance(), () -> load(p));
|
|
return;
|
|
}
|
|
Preconditions.checkNotNull(p, "player must not be null");
|
|
Preconditions.checkArgument(p.isOnline(), "player must be online");
|
|
|
|
if (creating) {
|
|
p.sendMessage(MessageConfig.getWorldStillCreating());
|
|
return;
|
|
}
|
|
|
|
WorldLoadEvent event = new WorldLoadEvent(p, this);
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
if (event.isCancelled())
|
|
return;
|
|
|
|
setUnloading(false);
|
|
|
|
p.sendMessage(MessageConfig.getSettingUpWorld());
|
|
|
|
// Move World into Server dir
|
|
String worlddir = PluginConfig.getWorlddir();
|
|
File world = new File(worlddir + "/" + worldname);
|
|
|
|
if (world.exists()) {
|
|
// Check for duplicated worlds
|
|
File propablyExistingWorld = new File(Bukkit.getWorldContainer(), worldname);
|
|
if (propablyExistingWorld.exists()) {
|
|
System.err.println("World " + worldname + " existed twice!");
|
|
try {
|
|
FileUtils.deleteDirectory(propablyExistingWorld);
|
|
} catch (IOException e) {
|
|
p.sendMessage(MessageConfig.getUnknownError());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
//Move world if exists
|
|
try {
|
|
FileUtils.moveDirectoryToDirectory(world, Bukkit.getWorldContainer(), false);
|
|
} catch (IOException e) {
|
|
System.err.println("Couldn't load world of " + p.getName());
|
|
p.sendMessage(PluginConfig.getPrefix() + "§cError: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
// Check for old named worlds
|
|
if (worldname.charAt(worldname.length() - 37) == ' ') {
|
|
StringBuilder myName = new StringBuilder(worldname);
|
|
myName.setCharAt(worldname.length() - 37, '-');
|
|
world.renameTo(new File(Bukkit.getWorldContainer(), myName.toString()));
|
|
worldname = myName.toString();
|
|
}
|
|
|
|
|
|
WorldCreator creator = new WorldCreator(worldname);
|
|
|
|
String templateKey = WorldConfig.getWorldConfig(worldname).getTemplateKey();
|
|
WorldTemplate template = WorldTemplateProvider.getInstance().getTemplate(templateKey);
|
|
if (template == null)
|
|
template = WorldTemplateProvider.getInstance().getTemplate(PluginConfig.getDefaultWorldTemplate());
|
|
|
|
if (template != null)
|
|
creator = template.generatorSettings.asWorldCreator(worldname);
|
|
|
|
|
|
World w = Bukkit.getWorld(worldname);
|
|
if (w == null)
|
|
w = Bukkit.createWorld(creator);
|
|
|
|
this.w = w;
|
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(WorldSystem.getInstance(), new Runnable() {
|
|
public void run() {
|
|
teleportToWorldSpawn(p);
|
|
}
|
|
}, 10L);
|
|
|
|
OfflinePlayer owner = PlayerWrapper.getOfflinePlayer(WorldConfig.getWorldConfig(worldname).getOwner());
|
|
DependenceConfig dc = new DependenceConfig(owner);
|
|
dc.setLastLoaded();
|
|
}
|
|
|
|
/**
|
|
* @return if the world is loaded
|
|
*/
|
|
public boolean isLoaded() {
|
|
File worldAsDir = new File(Bukkit.getWorldContainer(), worldname + "/worldconfig.yml");
|
|
World w = Bukkit.getWorld(worldname);
|
|
return worldAsDir.exists() && w != null;
|
|
}
|
|
|
|
private boolean exists() {
|
|
File worldAsDir = new File(Bukkit.getWorldContainer(), worldname + "/worldconfig.yml");
|
|
if (worldAsDir.exists()) {
|
|
return true;
|
|
}
|
|
worldAsDir = new File(PluginConfig.getWorlddir() + "/" + worldname + "/worldconfig.yml");
|
|
return worldAsDir.exists();
|
|
}
|
|
|
|
/**
|
|
* Teleports the player to the world with the given settings in the config
|
|
*
|
|
* @param p player to teleport
|
|
* @throws NullPointerException if player is null
|
|
* @throws IllegalArgumentException if player is not online
|
|
*/
|
|
public void teleportToWorldSpawn(Player p) {
|
|
Preconditions.checkNotNull(p, "player must not be null");
|
|
Preconditions.checkArgument(p.isOnline(), "player must be online");
|
|
PlayerPositions positions = PlayerPositions.instance;
|
|
|
|
if (creating) {
|
|
p.sendMessage(MessageConfig.getWorldStillCreating());
|
|
return;
|
|
}
|
|
|
|
setUnloading(false);
|
|
w = Bukkit.getWorld(worldname);
|
|
if (w == null)
|
|
return;
|
|
|
|
WorldConfig config = WorldConfig.getWorldConfig(worldname);
|
|
if (config.getHome() != null) {
|
|
p.teleport(positions.injectWorldsLocation(p, config, config.getHome()));
|
|
} else {
|
|
if (PluginConfig.useWorldSpawn()) {
|
|
p.teleport(positions.injectWorldsLocation(p, config, PluginConfig.getWorldSpawn(w)));
|
|
} else {
|
|
p.teleport(positions.injectWorldsLocation(p, config, w.getSpawnLocation()));
|
|
}
|
|
}
|
|
if (PluginConfig.isSurvival()) {
|
|
p.setGameMode(GameMode.SURVIVAL);
|
|
} else {
|
|
p.setGameMode(GameMode.CREATIVE);
|
|
}
|
|
|
|
OfflinePlayer owner = PlayerWrapper.getOfflinePlayer(WorldConfig.getWorldConfig(worldname).getOwner());
|
|
DependenceConfig dc = new DependenceConfig(owner);
|
|
dc.setLastLoaded();
|
|
}
|
|
|
|
/**
|
|
* @return the world
|
|
*/
|
|
public World getWorld() {
|
|
return w;
|
|
}
|
|
|
|
public boolean isCreating() {
|
|
return creating;
|
|
}
|
|
|
|
public void setCreating(boolean creating) {
|
|
this.creating = creating;
|
|
}
|
|
|
|
public void setUnloading(boolean unloading) {
|
|
this.unloading = unloading;
|
|
|
|
// Cancel unload task if unloading is set to false
|
|
if (!unloading && unloadLaterTask != null && !VersionUtil.isCancelled(unloadLaterTask)) {
|
|
unloadLaterTask.cancel();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the worldname
|
|
*/
|
|
public String getName() {
|
|
return worldname;
|
|
}
|
|
} |