diff --git a/src/main/java/org/adrianvictor/sweetdreams/Configuration.java b/src/main/java/org/adrianvictor/sweetdreams/Configuration.java index 2a52b89..34002af 100644 --- a/src/main/java/org/adrianvictor/sweetdreams/Configuration.java +++ b/src/main/java/org/adrianvictor/sweetdreams/Configuration.java @@ -10,12 +10,15 @@ public class Configuration { private final YamlConfiguration playerStorage = new YamlConfiguration(); private final File playerStorageFile; private final YamlConfiguration pluginConfig = new YamlConfiguration(); - private final File pluginConfigFile = new File(""); + private final File pluginConfigFile; private final SweetDreams plugin; public Configuration() { plugin = SweetDreams.getPlugin(); playerStorageFile = new File(plugin.getDataFolder(), "playerstorage.yml"); + pluginConfigFile = new File(plugin.getDataFolder(), "config.yml"); + + plugin.saveResource("config.yml", false); if (playerStorageFile.exists()) { try { @@ -25,6 +28,15 @@ public class Configuration { throw new RuntimeException(e); } } + + if (pluginConfigFile.exists()) { + try { + pluginConfig.load(pluginConfigFile); + } catch (IOException | InvalidConfigurationException e) { + plugin.getLogger().severe("Error loading plugin configuration: " + e.getMessage()); + throw new RuntimeException(e); + } + } } public void savePlayerStorage() { diff --git a/src/main/java/org/adrianvictor/sweetdreams/EventListener.java b/src/main/java/org/adrianvictor/sweetdreams/EventListener.java index be2f9ac..9a593e4 100644 --- a/src/main/java/org/adrianvictor/sweetdreams/EventListener.java +++ b/src/main/java/org/adrianvictor/sweetdreams/EventListener.java @@ -1,10 +1,8 @@ package org.adrianvictor.sweetdreams; import com.destroystokyo.paper.event.player.PlayerSetSpawnEvent; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Sound; -import org.bukkit.World; + +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -14,20 +12,18 @@ import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerBedEnterEvent; import org.bukkit.util.Vector; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - public class EventListener implements Listener { private final PlayerStorage storage; - private final Set teleporting = new HashSet<>(); + private final PlayerTeleporter tp; + private final YamlConfiguration configuration; public EventListener() { this.storage = SweetDreams.getPlugin().getStorage(); + this.tp = new PlayerTeleporter(); + this.configuration = SweetDreams.getPlugin().getConfiguration().getPluginConfig(); } - @EventHandler + @EventHandler(ignoreCancelled = true) public void onPlayerBedEnterEvent(PlayerBedEnterEvent event) { if (event.getPlayer().getWorld() == SweetDreams.getPlugin().getWorld()) { storage.savePlayerSpawnPoint(event.getPlayer()); @@ -43,7 +39,7 @@ public class EventListener implements Listener { return; } - teleport(event.getPlayer()); + tp.teleport(event.getPlayer(), false); event.setCancelled(true); } @@ -53,8 +49,6 @@ public class EventListener implements Listener { if (event.getPlayer().getWorld() != SweetDreams.getPlugin().getWorld()) return; - // TODO save player spawn point on dreamlands - event.setCancelled(true); } @@ -69,8 +63,9 @@ public class EventListener implements Listener { if (event.getEntity().getWorld() != SweetDreams.getPlugin().getWorld()) return; if (event.getEntity() instanceof Player player) { if (event.getCause() == EntityDamageEvent.DamageCause.VOID) { - teleport(player); + tp.teleport(player, true); + // player holds the momentum from the fall to the void after teleport player.setVelocity(new Vector(0, 0, 0)); player.setFallDistance(0); } @@ -82,41 +77,7 @@ public class EventListener implements Listener { if (event.getEntity().getWorld() != SweetDreams.getPlugin().getWorld()) return; Player player = event.getPlayer(); - teleport(player); + tp.teleport(player, true); event.setCancelled(true); } - - private void teleport(Player player) { - UUID uuid = player.getUniqueId(); - if (!teleporting.add(uuid)) return; - - Bukkit.getScheduler().runTask(SweetDreams.getPlugin(), () -> { - try { - World playerWorld = player.getWorld(); - - if (playerWorld == SweetDreams.getPlugin().getWorld()) { - storage.savePlayer(player, PlayerStorage.StorageWorldType.SKYLANDS); - - player.teleport(Objects.requireNonNullElse( - player.getRespawnLocation(), - Bukkit.getWorld("world").getSpawnLocation() - )); - player.getInventory().clear(); - - storage.loadPlayer(player, PlayerStorage.StorageWorldType.OVERWORLD); - - player.sendMessage("You woke up from a bad dream..."); - player.playSound(player.getLocation(), Sound.ENTITY_ENDER_DRAGON_DEATH, 1.0f, 1.0f); - } else { - World world = SweetDreams.getPlugin().getWorld(); - - storage.savePlayer(player, PlayerStorage.StorageWorldType.OVERWORLD); - player.getInventory().clear(); - player.teleport(storage.loadPlayer(player, PlayerStorage.StorageWorldType.SKYLANDS)); - } - } finally { - teleporting.remove(uuid); - } - }); - } } diff --git a/src/main/java/org/adrianvictor/sweetdreams/KickerRunnable.java b/src/main/java/org/adrianvictor/sweetdreams/KickerRunnable.java new file mode 100644 index 0000000..3d707a7 --- /dev/null +++ b/src/main/java/org/adrianvictor/sweetdreams/KickerRunnable.java @@ -0,0 +1,26 @@ +package org.adrianvictor.sweetdreams; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; + +public class KickerRunnable implements Runnable { + private final World world; + private final PlayerTeleporter teleporter; + + public KickerRunnable() { + world = SweetDreams.getPlugin().getWorld(); + teleporter = new PlayerTeleporter(); + } + + + @Override + public void run() { + long time = Bukkit.getWorld("world").getTime(); + if (!(time >= 13000 && time <= 23000)) { + for (Player p : world.getPlayers()) { + teleporter.teleport(p.getPlayer(), false); + } + } + } +} diff --git a/src/main/java/org/adrianvictor/sweetdreams/PlayerTeleporter.java b/src/main/java/org/adrianvictor/sweetdreams/PlayerTeleporter.java new file mode 100644 index 0000000..00cff9a --- /dev/null +++ b/src/main/java/org/adrianvictor/sweetdreams/PlayerTeleporter.java @@ -0,0 +1,85 @@ +package org.adrianvictor.sweetdreams; + +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.World; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +public class PlayerTeleporter { + private final Set teleporting = new HashSet<>(); + private final PlayerStorage storage = SweetDreams.getPlugin().getStorage(); + + public void teleport(Player player, boolean bad) { + UUID uuid = player.getUniqueId(); + Sound sound = bad ? Sound.ENTITY_ENDERMAN_SCREAM : Sound.ENTITY_PLAYER_LEVELUP; + YamlConfiguration configuration = SweetDreams.getPlugin().getConfiguration().getPluginConfig(); + String message = bad ? "You woke up from a bad dream..." : "You woke up!"; + boolean clearInventory = (bad && configuration.getBoolean("keepInventory", true)); + + if (!teleporting.add(uuid)) return; + + Bukkit.getScheduler().runTask(SweetDreams.getPlugin(), () -> { + try { + World playerWorld = player.getWorld(); + + if (playerWorld == SweetDreams.getPlugin().getWorld()) { + if (clearInventory) + spreadPlayerItems(player); + + switchInventories(player, PlayerStorage.StorageWorldType.SKYLANDS, PlayerStorage.StorageWorldType.OVERWORLD); + + player.teleport(Objects.requireNonNullElse( + player.getRespawnLocation(), + Bukkit.getWorld(configuration.getString("defaultWorld", "world")).getSpawnLocation() + )); + + if (configuration.getBoolean("sendMessageOnWakeUp", true)) { + player.sendMessage(message); + } + + if (configuration.getBoolean("playSoundOnWakeUp", true)) { + player.playSound(player.getLocation(), sound, 1.0f, 1.0f); + } + } else { + switchInventories(player, PlayerStorage.StorageWorldType.OVERWORLD, PlayerStorage.StorageWorldType.SKYLANDS); + player.teleport(storage.loadPlayer(player, PlayerStorage.StorageWorldType.SKYLANDS)); + } + } finally { + teleporting.remove(uuid); + } + }); + } + + private void switchInventories(Player player, PlayerStorage.StorageWorldType from, PlayerStorage.StorageWorldType to) { + storage.savePlayer(player, from); + player.getInventory().clear(); + storage.loadPlayer(player, to); + } + + private void spreadPlayerItems(Player player) { + for (ItemStack item : player.getInventory().getContents()) { + if (item != null && !item.isEmpty()) { + Item droppedItem = player.getWorld().dropItem(player.getLocation(), item); + + droppedItem.setVelocity( + new Vector( + Math.random() - 0.5, + Math.random() * 0.5, + Math.random() - 0.5 + ) + ); + } + } + + player.getInventory().clear(); + } +} diff --git a/src/main/java/org/adrianvictor/sweetdreams/SkyIslandsGenerator.java b/src/main/java/org/adrianvictor/sweetdreams/SkyIslandsGenerator.java index c9b3efe..d94894c 100644 --- a/src/main/java/org/adrianvictor/sweetdreams/SkyIslandsGenerator.java +++ b/src/main/java/org/adrianvictor/sweetdreams/SkyIslandsGenerator.java @@ -2,6 +2,7 @@ package org.adrianvictor.sweetdreams; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.WorldInfo; @@ -12,6 +13,8 @@ import java.util.concurrent.atomic.AtomicBoolean; public class SkyIslandsGenerator extends ChunkGenerator { + private final YamlConfiguration cfg; + private enum IslandType { ROUND, LONG, @@ -23,13 +26,20 @@ public class SkyIslandsGenerator extends ChunkGenerator { private record Blob(double x, double y, double z, double rx, double ry, double rz) {} - private static final int CELL_SIZE = 30; - - private static final int MIN_RADIUS = 6; - private static final int MAX_RADIUS = 16; - - private static final int MIN_Y = 80; - private static final int MAX_Y = 180; + private final int CELL_SIZE; + private final int MIN_Y; + private final int MAX_Y; + private final int TREE_RANDOM_VALUE; + private final int TREE_PLACEMENT_BOUND_X_MIN; + private final int TREE_PLACEMENT_BOUND_X_MAX; + private final int TREE_PLACEMENT_BOUND_Y_MIN; + private final int TREE_PLACEMENT_BOUND_Y_MAX; + private final int TREE_MIN_HEIGHT; + private final int TREE_MAX_HEIGHT; + private final float ISLAND_CHANCE; + private final int ORE_MAX_DEPTH; + private final int ORE_MAX_SPREAD; + private final int DIRT_LAYERS; private record LeafOffset(int dx, int dy, int dz) {} @@ -52,6 +62,24 @@ public class SkyIslandsGenerator extends ChunkGenerator { LEAF_OFFSETS = offsets.toArray(LeafOffset[]::new); } + public SkyIslandsGenerator() { + this.cfg = SweetDreams.getPlugin().getConfiguration().getPluginConfig(); + this.CELL_SIZE = cfg.getInt("worldGeneration.cellSize", 30); + this.MIN_Y = cfg.getInt("worldGeneration.minY", 80); + this.MAX_Y = cfg.getInt("worldGeneration.maxY", 180); + this.TREE_RANDOM_VALUE = cfg.getInt("worldGeneration.treeRandomValue", 500); + this.ISLAND_CHANCE = (float) cfg.getDouble("worldGeneration.islandChance", 0.8); + this.TREE_PLACEMENT_BOUND_X_MIN = cfg.getInt("worldGeneration.treePlacementBoundMinX", 2); + this.TREE_PLACEMENT_BOUND_Y_MIN = cfg.getInt("worldGeneration.treePlacementBoundMinY", 2); + this.TREE_PLACEMENT_BOUND_X_MAX = cfg.getInt("worldGeneration.treePlacementBoundMaxX", 14); + this.TREE_PLACEMENT_BOUND_Y_MAX = cfg.getInt("worldGeneration.treePlacementBoundMaxY", 14); + this.ORE_MAX_DEPTH = cfg.getInt("worldGeneration.oreMaxDepth", 20); + this.ORE_MAX_SPREAD = cfg.getInt("worldGeneration.oreMaxSpread", 5); + this.TREE_MAX_HEIGHT = cfg.getInt("worldGeneration.treeMaxHeight", 3); + this.TREE_MIN_HEIGHT = cfg.getInt("worldGeneration.treeMinHeight", 4); + this.DIRT_LAYERS = cfg.getInt("worldGeneration.dirtLayers", 3); + } + @Override public @NonNull List getDefaultPopulators(@NonNull World world) { return Collections.singletonList(new SkylandsBlockPopulator()); @@ -80,7 +108,7 @@ public class SkyIslandsGenerator extends ChunkGenerator { for (int gz = cellZ - 2; gz <= cellZ + 2; gz++) { SplittableRandom r = new SplittableRandom(hash(seed, gx, gz)); - if (r.nextDouble() > 0.8) { + if (r.nextDouble() > this.ISLAND_CHANCE) { continue; } @@ -180,7 +208,7 @@ public class SkyIslandsGenerator extends ChunkGenerator { private void decorateTerrain(ChunkData chunkData, Random random, short[][] highestY) { generateSurfaceLayers(chunkData, highestY); - generateOres(chunkData, random); + generateOres(chunkData, random, highestY); generateTrees(chunkData, random, highestY); } @@ -198,7 +226,7 @@ public class SkyIslandsGenerator extends ChunkGenerator { chunkData.setBlock(x, highest, z, Material.GRASS_BLOCK); - for (int y = highest - 1; y >= highest - 3; y--) { + for (int y = highest - 1; y >= highest - this.DIRT_LAYERS; y--) { if (y >= minHeight) { chunkData.setBlock(x, y, z, Material.DIRT); } @@ -207,27 +235,29 @@ public class SkyIslandsGenerator extends ChunkGenerator { } } - private void generateOres(ChunkData chunkData, Random random) { - generateOreVeins(chunkData, random, Material.COAL_ORE, 25, 10); - generateOreVeins(chunkData, random, Material.IRON_ORE, 15, 8); - generateOreVeins(chunkData, random, Material.GOLD_ORE, 6, 6); - generateOreVeins(chunkData, random, Material.DIAMOND_ORE, 2, 4); + private void generateOres(ChunkData chunkData, Random random, short[][] highestY) { + generateOreVeins(chunkData, random, Material.COAL_ORE, 25, 10, highestY); + generateOreVeins(chunkData, random, Material.IRON_ORE, 15, 8, highestY); + generateOreVeins(chunkData, random, Material.GOLD_ORE, 6, 6, highestY); + generateOreVeins(chunkData, random, Material.DIAMOND_ORE, 2, 4, highestY); } - private void generateOreVeins(ChunkData chunkData, Random random, Material ore, int veins, int size) { + private void generateOreVeins(ChunkData chunkData, Random random, Material ore, int veins, int size, short[][] highestY) { for (int i = 0; i < veins; i++) { int startX = random.nextInt(16); - int startY = chunkData.getMinHeight() + random.nextInt(chunkData.getMaxHeight() - chunkData.getMinHeight()); - int startZ = random.nextInt(16); + if (highestY[startX][startZ] == Short.MIN_VALUE) continue; + + int startY = highestY[startX][startZ] - random.nextInt(this.ORE_MAX_DEPTH); + for (int j = 0; j < size; j++) { - int x = startX + random.nextInt(5) - 2; - int y = startY + random.nextInt(5) - 2; - int z = startZ + random.nextInt(5) - 2; + int x = startX + random.nextInt(this.ORE_MAX_SPREAD) - 2; + int y = startY + random.nextInt(this.ORE_MAX_SPREAD) - 2; + int z = startZ + random.nextInt(this.ORE_MAX_SPREAD) - 2; if (x < 0 || x >= 16) continue; if (z < 0 || z >= 16) continue; @@ -242,10 +272,10 @@ public class SkyIslandsGenerator extends ChunkGenerator { } private void generateTrees(ChunkData chunkData, Random random, short[][] highestY) { - for (int x = 2; x < 14; x++) { - for (int z = 2; z < 14; z++) { + for (int x = this.TREE_PLACEMENT_BOUND_X_MIN; x < TREE_PLACEMENT_BOUND_X_MAX; x++) { + for (int z = TREE_PLACEMENT_BOUND_Y_MIN; z < TREE_PLACEMENT_BOUND_Y_MAX; z++) { - if (random.nextInt(500) != 0) { + if (random.nextInt(this.TREE_RANDOM_VALUE) != 0) { continue; } @@ -265,7 +295,7 @@ public class SkyIslandsGenerator extends ChunkGenerator { } private void placeTree(ChunkData chunkData, int x, int y, int z, Random random) { - int height = 4 + random.nextInt(3); + int height = this.TREE_MIN_HEIGHT + random.nextInt(this.TREE_MAX_HEIGHT); for (int dy = 0; dy < height; dy++) { chunkData.setBlock(x, y + dy, z, Material.OAK_LOG); diff --git a/src/main/java/org/adrianvictor/sweetdreams/SkylandsBlockPopulator.java b/src/main/java/org/adrianvictor/sweetdreams/SkylandsBlockPopulator.java index f893c5c..7cada46 100644 --- a/src/main/java/org/adrianvictor/sweetdreams/SkylandsBlockPopulator.java +++ b/src/main/java/org/adrianvictor/sweetdreams/SkylandsBlockPopulator.java @@ -1,7 +1,5 @@ package org.adrianvictor.sweetdreams; -import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.LimitedRegion; import org.bukkit.generator.WorldInfo; @@ -17,6 +15,5 @@ public class SkylandsBlockPopulator extends BlockPopulator { int chunkX, int chunkZ, @NonNull LimitedRegion region - ) { - } + ) {} } diff --git a/src/main/java/org/adrianvictor/sweetdreams/SweetDreams.java b/src/main/java/org/adrianvictor/sweetdreams/SweetDreams.java index 5c95735..1863a07 100644 --- a/src/main/java/org/adrianvictor/sweetdreams/SweetDreams.java +++ b/src/main/java/org/adrianvictor/sweetdreams/SweetDreams.java @@ -22,14 +22,11 @@ public final class SweetDreams extends JavaPlugin { boolean generated = false; for (World world: getServer().getWorlds()) { - if (world.getName().equals("world_sweetdreams")) { - Bukkit.unloadWorld(world, true); - File worldFolder = new File(Bukkit.getWorldContainer(), "world_sweetdreams"); - if (worldFolder.exists()) { - deleteFolder(worldFolder); - } -// this.world = world; -// generated = true; + if (world.getName().equals( + configuration.getPluginConfig().getString("dreamlandsWorld", "world_sweetdreams")) + ) { + this.world = world; + generated = true; } } @@ -38,6 +35,8 @@ public final class SweetDreams extends JavaPlugin { } getServer().getPluginManager().registerEvents(new EventListener(), this); + + Bukkit.getScheduler().runTaskTimer(this, new KickerRunnable(), 20L, 20L); } private void deleteFolder(File folder) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e69de29..1c4166f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -0,0 +1,28 @@ +dreamlandsWorld: "world_sweetdreams" + +# World to watch for day start when kicking players from the dreamland +# /!\ Don't change unless you know what you're doing +defaultWorld: "world" + +kickOnDayStart: true +playSoundOnWakeUp: true +sendMessageOnWakeUp: true +keepInventory: true + +# Won't affect already generated chunks +# /!\ Don't change unless you know what you're doing +worldGeneration: + cellSize: 30 + minY: 80 + maxY: 180 + islandChance: 0.8 + # The greater this is, rarer trees are. I'd recommend changing from 100 to 100 to se results. + treeRandomValue: 500 + treePlacementBoundMinX: 2 + treePlacementBoundMinY: 2 + treePlacementBoundMaxX: 14 + treePlacementBoundMaxY: 14 + treeMaxHeight: 3 # Max random number that will be ADDED to the minimum size + treeMinHeight: 4 + oreMaxDepth: 20 + dirtLayers: 3 \ No newline at end of file