256 lines
10 KiB
Java
256 lines
10 KiB
Java
package xyz.twovb.sgm.levels;
|
|
/*
|
|
* Created by 2vb - 4/6/2024
|
|
*/
|
|
|
|
import org.apache.commons.io.FileUtils;
|
|
import org.bukkit.*;
|
|
import org.bukkit.block.Block;
|
|
import org.bukkit.configuration.file.YamlConfiguration;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
import org.yaml.snakeyaml.DumperOptions;
|
|
import org.yaml.snakeyaml.Yaml;
|
|
import xyz.twovb.sgm.SGM;
|
|
import xyz.twovb.toolbox.api.CustomPlayer;
|
|
|
|
import java.io.File;
|
|
import java.io.FileReader;
|
|
import java.io.FileWriter;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
public class LevelManager {
|
|
|
|
public static final String levelPath = SGM.getInstance().getDataFolder().getPath() + "/levels/";
|
|
|
|
public static final String gamePath = SGM.getInstance().getDataFolder().getPath() + "/games/";
|
|
|
|
public static final String gameWorldsPath = gamePath + "worlds/";
|
|
|
|
public static final String mapPath = SGM.getInstance().getDataFolder().getPath() + "/maps/";
|
|
|
|
public HashMap<String, List<String>> enabledMaps = new HashMap<>();
|
|
|
|
// This isn't really used rn but I can't be bothered to do anything thb
|
|
public void loadWorld(String worldName, LevelType type) {
|
|
// Check if the world is already loaded
|
|
String key = type.toString().toLowerCase() + "_" + worldName;
|
|
WorldCreator wc = null;
|
|
if (Bukkit.getWorld(new NamespacedKey(SGM.getInstance(), key)) != null) {
|
|
SGM.getInstance().getCLogger().log("World " + worldName + " is already loaded.");
|
|
return;
|
|
}
|
|
|
|
// Load the world
|
|
wc = switch (type) {
|
|
case LEVEL -> new WorldCreator(levelPath + worldName, new NamespacedKey(SGM.getInstance(), key));
|
|
case GAME -> new WorldCreator(gamePath + worldName, new NamespacedKey(SGM.getInstance(), key));
|
|
case MAP -> new WorldCreator(mapPath + worldName, new NamespacedKey(SGM.getInstance(), key));
|
|
};
|
|
World world = wc.createWorld();
|
|
setGameRules(world);
|
|
SGM.getInstance().getCLogger().log("Loaded world: " + worldName);
|
|
}
|
|
|
|
private static void genDataFile(File path, String name, String game) {
|
|
Map<String, Object> data = new HashMap<>();
|
|
data.put("game", game);
|
|
data.put("name", name);
|
|
|
|
DumperOptions options = new DumperOptions();
|
|
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
|
Yaml yaml = new Yaml(options);
|
|
|
|
File optFile = new File(gamePath + game + "/options.yml");
|
|
|
|
// Attempt to load options.yml
|
|
new BukkitRunnable() {
|
|
private final int maxAttempts = SGM.getInstance().getConfig().getInt("retry-attempts");
|
|
private int attempts = 0;
|
|
|
|
@Override
|
|
public void run() {
|
|
if (attempts >= maxAttempts) {
|
|
cancel();
|
|
SGM.getInstance().getCLogger().error("Unable to load game options after " + attempts + " attempts.");
|
|
return;
|
|
}
|
|
|
|
try (FileReader reader = new FileReader(optFile)) {
|
|
Map<String, Object> optData = yaml.load(reader);
|
|
if (optData != null) {
|
|
SGM.getInstance().getCLogger().log("Loaded YAML data: " + optData);
|
|
data.putAll(optData); // Append loaded data to new data
|
|
cancel(); // Cancel the task once data is successfully loaded
|
|
}
|
|
} catch (IOException e) {
|
|
attempts++;
|
|
}
|
|
}
|
|
}.runTaskTimerAsynchronously(SGM.getInstance(), 0L, 20L); // Run the task asynchronously with 20 ticks delay
|
|
|
|
// Schedule a task to write the combined data to the target YAML file once loaded
|
|
new BukkitRunnable() {
|
|
@Override
|
|
public void run() {
|
|
// Check if data has been loaded
|
|
if (data.isEmpty()) {
|
|
return; // Exit if data is empty (not loaded yet)
|
|
}
|
|
|
|
// Write the combined data to the target YAML file
|
|
File yamlFile = new File(path, "sgm.yml");
|
|
try (FileWriter writer = new FileWriter(yamlFile)) {
|
|
yaml.dump(data, writer);
|
|
this.cancel();
|
|
} catch (IOException e) {
|
|
SGM.getInstance().getCLogger().error("Error writing data file: " + e.getMessage());
|
|
}
|
|
}
|
|
}.runTaskTimer(SGM.getInstance(), 20L, 20L); // Run the task synchronously with 20 ticks delay after initial load attempt
|
|
}
|
|
|
|
public static World getLevel(String name) {
|
|
return Bukkit.getWorld(new NamespacedKey(SGM.getInstance(), "level_" + name));
|
|
}
|
|
|
|
public LevelResult exportLevel(String name) throws IOException {
|
|
File levelDir = new File(levelPath + name);
|
|
File mapDir = new File(mapPath + name);
|
|
World world = Bukkit.getWorld(new NamespacedKey(SGM.getInstance(), "level_" + name));
|
|
if (world != null) {
|
|
for (Player player : world.getPlayers()) {
|
|
CustomPlayer cPlayer = new CustomPlayer(player);
|
|
cPlayer.sendMessage(SGM.getInstance().getMessages().getString("sgm.level.export.kick"));
|
|
// This is probably gonna be funny later
|
|
player.teleport(Bukkit.getServer().getWorlds().get(0).getSpawnLocation());
|
|
}
|
|
// TODO: make better
|
|
if (!Bukkit.isTickingWorlds() && Bukkit.getServer().unloadWorld(world, true)) {
|
|
if (mapDir.exists()) {
|
|
FileUtils.deleteDirectory(mapDir);
|
|
}
|
|
File configFile = new File(levelDir + "/sgm.yml");
|
|
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
|
String gameIntName = config.getString("game");
|
|
if (SGM.getInstance().getGameManager().getRegisteredGames().contains(gameIntName)) {
|
|
List<String> maps = enabledMaps.get(gameIntName);
|
|
if (!maps.contains(name)) {
|
|
enabledMaps.get(gameIntName).add(name);
|
|
}
|
|
}
|
|
FileUtils.copyDirectory(levelDir, mapDir);
|
|
FileUtils.delete(new File(mapDir + "/uid.dat"));
|
|
loadWorld(name, LevelType.LEVEL);
|
|
return LevelResult.SUCCESS;
|
|
}
|
|
return LevelResult.UNKNOWN;
|
|
} else {
|
|
return LevelResult.WORLD_NO_EXISTS;
|
|
}
|
|
}
|
|
|
|
public LevelResult createLevel(String name, String game) {
|
|
File level = new File(levelPath + name);
|
|
if (!SGM.getInstance().getGameManager().getRegisteredGames().contains(game.toLowerCase())) {
|
|
return LevelResult.INVALID_ARGS;
|
|
}
|
|
WorldCreator wc = new WorldCreator(levelPath + name, new NamespacedKey(SGM.getInstance(), "level_" + name));
|
|
if (level.exists()) {
|
|
return LevelResult.WORLD_EXISTS;
|
|
}
|
|
wc.type(WorldType.FLAT);
|
|
wc.generatorSettings("{\"layers\": [{\"block\": \"air\", \"height\": 1}], \"biome\":\"plains\"}");
|
|
wc.generateStructures(false);
|
|
World world = wc.createWorld();
|
|
if (world == null) {
|
|
return LevelResult.UNKNOWN;
|
|
}
|
|
Location location = new Location(world, 0.5, 0, 0.5);
|
|
// Create a 3x3 stone platform
|
|
for (int x = -1; x <= 1; x++) {
|
|
for (int z = -1; z <= 1; z++) {
|
|
Location blockLocation = location.clone().add(x, -2, z);
|
|
Block block = blockLocation.getBlock();
|
|
block.setType(Material.STONE);
|
|
}
|
|
}
|
|
world.setSpawnLocation(location);
|
|
world.setSpawnFlags(false, false);
|
|
setGameRules(world);
|
|
world.setTime(1000);
|
|
genDataFile(level, name, game.toLowerCase());
|
|
return LevelResult.SUCCESS;
|
|
}
|
|
|
|
public static void setGameRules(World world) {
|
|
world.setGameRule(GameRule.KEEP_INVENTORY, true);
|
|
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
|
|
world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
|
|
world.setGameRule(GameRule.RANDOM_TICK_SPEED, 0);
|
|
world.setGameRule(GameRule.DO_MOB_SPAWNING, false);
|
|
world.setGameRule(GameRule.DO_MOB_LOOT, false);
|
|
world.setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true);
|
|
}
|
|
|
|
public void loadLevels() {
|
|
// Initialize enabledMaps for each registered game
|
|
for (String game : SGM.getInstance().getGameManager().getRegisteredGames()) {
|
|
enabledMaps.put(game, new ArrayList<>()); // Initialize an empty ArrayList for each game
|
|
}
|
|
|
|
try {
|
|
File gameWorldsDir = new File(gameWorldsPath);
|
|
if (gameWorldsDir.exists()) {
|
|
FileUtils.cleanDirectory(gameWorldsDir);
|
|
}
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
// load levels when level tries to be editted
|
|
// Load levels from levelPath
|
|
loadWorldDir(levelPath, LevelType.LEVEL);
|
|
loadWorldDir(mapPath, LevelType.MAP);
|
|
}
|
|
|
|
private void loadWorldDir(String path, LevelType levelType) {
|
|
File folder = new File(path);
|
|
File[] files = folder.listFiles();
|
|
|
|
if (files != null) {
|
|
for (File file : files) {
|
|
if (file.isDirectory()) {
|
|
File configFile = new File(file, "sgm.yml");
|
|
if (configFile.exists()) {
|
|
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
|
String game = config.getString("game");
|
|
String name = config.getString("name");
|
|
|
|
if (enabledMaps.containsKey(game) && levelType == LevelType.MAP) {
|
|
enabledMaps.get(game).add(name);
|
|
}
|
|
if (levelType == LevelType.LEVEL) {
|
|
// Load the world if sgm.yml exists
|
|
loadWorld(file.getName(), levelType);
|
|
}
|
|
} else {
|
|
SGM.getInstance().getCLogger().log("Skipping directory " + file.getName() + ": sgm.yml not found.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum LevelResult {
|
|
SUCCESS, WORLD_NO_EXISTS, WORLD_EXISTS, INVALID_ARGS, UNKNOWN
|
|
}
|
|
|
|
public enum LevelType {
|
|
GAME, MAP, LEVEL
|
|
}
|
|
|
|
} |