Initial commit: LoParkour v1.1.0

This commit is contained in:
loki 2026-02-24 22:07:03 +01:00
commit aecb03ccf8
120 changed files with 9668 additions and 0 deletions

View file

@ -0,0 +1,125 @@
package dev.loki.loparkour.world;
import dev.loki.loparkour.LoParkour;
import dev.loki.loparkour.config.Option;
import dev.loki.loparkour.session.Session;
import dev.efnilite.vilib.util.Locations;
import org.bukkit.Location;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;
/**
* <p>Divides the parkour world in sections, each with an active session.</p>
* <p>Iteration 2.</p>
*
* @author loki
* @since 5.0.0
*/
public class Divider {
/**
* Map with all session ids map to the session instances.
*/
public static final Map<Session, Integer> sections = new HashMap<>();
/**
* Associates a session to a specific section.
*
* @param session The session.
*/
public static synchronized Location add(Session session) {
// attempts to get the closest available section to the center
var missing = IntStream.range(0, sections.size() + 1)
.filter(i -> !sections.containsValue(i))
.findFirst()
.orElseThrow();
sections.put(session, missing);
var location = toLocation(session);
LoParkour.log("Added session at %s".formatted(Locations.toString(location, true)));
return location;
}
/**
* Disassociates a session from a specific section.
*
* @param session The session.
*/
public static void remove(Session session) {
LoParkour.log("Removed session at %s".formatted(Locations.toString(toLocation(session), true)));
sections.remove(session);
}
/**
* @param session The session.
* @return The location at the center of section n.
*/
private static Location toLocation(Session session) {
int[] xz = spiralAt(sections.get(session));
return new Location(World.getWorld(),
xz[0] * Option.BORDER_SIZE,
(Option.MAX_Y + Option.MIN_Y) / 2.0,
xz[1] * Option.BORDER_SIZE);
}
/**
* @param session The session.
* @return Array where the first item is the smallest location and second item is the largest.
*/
public static Location[] toSelection(Session session) {
Location center = toLocation(session);
// get the min and max locations
Location max = center.clone().add(Option.BORDER_SIZE / 2, 0, Option.BORDER_SIZE / 2);
Location min = center.clone().subtract(Option.BORDER_SIZE / 2, 0, Option.BORDER_SIZE / 2);
max.setY(Option.MAX_Y);
min.setY(Option.MIN_Y);
return new Location[]{min, max};
}
/**
* Gets a spiral
*
* @param n The number of value
* @return the coords of this value
*/
// https://math.stackexchange.com/a/163101
private static int[] spiralAt(int n) {
if (n < 0) {
throw new IllegalArgumentException("Invalid n bound: %d".formatted(n));
}
n++; // one-index
int k = (int) Math.ceil((Math.sqrt(n) - 1) / 2);
int t = 2 * k + 1;
int m = t * t;
t--;
if (n > m - t) {
return new int[]{k - (m - n), -k};
} else {
m -= t;
}
if (n > m - t) {
return new int[]{-k, -k + (m - n)};
} else {
m -= t;
}
if (n > m - t) {
return new int[]{-k + (m - n), k};
} else {
return new int[]{k, k - (m - n - t)};
}
}
}

View file

@ -0,0 +1,126 @@
package dev.loki.loparkour.world;
import dev.loki.loparkour.LoParkour;
import dev.loki.loparkour.config.Config;
import dev.efnilite.vilib.util.VoidGenerator;
import org.bukkit.*;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.stream.Stream;
public class World {
private static String name;
private static org.bukkit.World world;
/**
* Creates a new world and sets all according settings in it.
*/
public static void create() {
name = Config.CONFIG.getString("world.name");
var world = Bukkit.getWorld(name);
if (!Config.CONFIG.getBoolean("joining")) {
return;
}
if (world != null) {
LoParkour.logging().warn("Crash detected! The parkour world loading twice is not usual behaviour. This only happens after a server crash.");
}
if (Config.CONFIG.getBoolean("world.delete-on-reload")) {
deleteWorld();
}
createWorld();
setup();
}
private static void createWorld() {
LoParkour.log("Creating Spigot world");
try {
WorldCreator creator = new WorldCreator(name)
.generateStructures(false)
.type(WorldType.NORMAL)
.generator(VoidGenerator.getGenerator()) // to fix No keys in MapLayer etc.
.environment(org.bukkit.World.Environment.NORMAL);
world = Bukkit.createWorld(creator);
} catch (Exception ex) {
LoParkour.logging().stack("Error while trying to create the parkour world", "delete the parkour world folder and restart the server", ex);
}
}
private static void setup() {
LoParkour.log("Initializing world rules");
world.setGameRule(GameRule.DO_FIRE_TICK, false);
world.setGameRule(GameRule.DO_MOB_SPAWNING, false);
world.setGameRule(GameRule.DO_TILE_DROPS, false);
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.setGameRule(GameRule.LOG_ADMIN_COMMANDS, false);
world.setGameRule(GameRule.KEEP_INVENTORY, true);
world.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false);
world.getWorldBorder().setCenter(0, 0);
world.getWorldBorder().setSize(10_000_000);
world.setDifficulty(Difficulty.PEACEFUL);
world.setClearWeatherDuration(1000000);
world.setAutoSave(false);
}
/**
* Deletes the world.
*/
public static void delete() {
if (!Config.CONFIG.getBoolean("world.delete-on-reload") || !Config.CONFIG.getBoolean("joining")) {
return;
}
LoParkour.log("Deleting world");
getWorld().getPlayers().forEach(player -> player.kickPlayer("Server is restarting"));
deleteWorld();
}
private static void deleteWorld() {
LoParkour.log("Deleting Spigot world");
File file = new File(name);
// world has already been deleted
if (!file.exists()) {
return;
}
Bukkit.unloadWorld(name, false);
try (Stream<Path> files = Files.walk(file.toPath())) {
files.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
} catch (Exception ex) {
LoParkour.logging().stack("Error while trying to delete the parkour world", ex);
}
}
/**
* @return the name of the parkour world.
*/
public static String getName() {
return name;
}
/**
* @return the Bukkit world wherein LoParkour is currently active.
*/
public static org.bukkit.World getWorld() {
return world;
}
}