SGM/src/main/java/xyz/twovb/sgm/levels/LevelManager.java
2vb f54dcbcfdf
Some checks are pending
Build plugin / build (push) Waiting to run
More fixes
2024-07-10 10:36:18 -07:00

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
}
}