Compare commits

...

47 Commits

Author SHA1 Message Date
fa826efe40 Merge pull request 'Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.12.0' (#10) from renovate/org.apache.maven.plugins-maven-javadoc-plugin-3.x into main
Reviewed-on: #10
2025-11-07 11:20:16 +01:00
41f1e8e536 Merge pull request 'Update dependency org.jetbrains:annotations to v26.0.2-1' (#9) from renovate/org.jetbrains-annotations-26.x into main
Reviewed-on: #9
2025-11-07 11:20:03 +01:00
b131545aad Merge pull request 'Update dependency com.sk89q.worldedit:worldedit-bukkit to v7.3.17' (#8) from renovate/com.sk89q.worldedit-worldedit-bukkit-7.x into main
Reviewed-on: #8
2025-11-07 11:19:55 +01:00
86c83c4ff3 Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.12.0 2025-11-06 13:44:43 +00:00
d348fc34b4 Update dependency org.jetbrains:annotations to v26.0.2-1 2025-11-06 13:44:41 +00:00
f4ff9f5529 Update dependency com.sk89q.worldedit:worldedit-bukkit to v7.3.17 2025-11-06 13:44:40 +00:00
07010f1043 Merge pull request 'Update dependency com.sk89q.worldedit:worldedit-bukkit to v7.3.13' (#7) from renovate/com.sk89q.worldedit-worldedit-bukkit-7.x into main
Some checks failed
continuous-integration/drone/push Build was killed
Reviewed-on: #7
2025-06-01 21:03:32 +02:00
e5a2be44f9 Update dependency com.sk89q.worldedit:worldedit-bukkit to v7.3.13
Some checks failed
continuous-integration/drone/pr Build was killed
continuous-integration/drone/push Build was killed
2025-05-24 11:00:40 +00:00
3448303bbb Merge pull request 'Update dependency com.sk89q.worldedit:worldedit-bukkit to v7.3.11' (#6) from renovate/com.sk89q.worldedit-worldedit-bukkit-7.x into main
Some checks failed
continuous-integration/drone Build was killed
Reviewed-on: #6
2025-03-24 13:08:30 +01:00
2f754f736a Update dependency com.sk89q.worldedit:worldedit-bukkit to v7.3.11 2025-03-24 11:00:39 +00:00
8043a794ac Merge remote-tracking branch 'origin/renovate/org.jetbrains-annotations-26.x' 2025-03-23 15:39:33 +01:00
872dab9e75 Merge pull request 'Update dependency org.jetbrains:annotations to v23.1.0' (#4) from renovate/org.jetbrains-annotations-23.x into main
Reviewed-on: #4
2025-03-23 15:33:35 +01:00
e3b1e2a48a Update dependency org.jetbrains:annotations to v26 2025-03-23 12:26:47 +00:00
9dfdd7adbb Update dependency org.jetbrains:annotations to v23.1.0 2025-03-23 12:26:45 +00:00
59867a42b7 Merge pull request 'Update dependency com.sk89q.worldedit:worldedit-bukkit to v7.3.10' (#2) from renovate/com.sk89q.worldedit-worldedit-bukkit-7.x into main
Reviewed-on: #2
2025-03-23 12:55:00 +01:00
4e86b6cd9a Merge pull request 'Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.11.2' (#3) from renovate/org.apache.maven.plugins-maven-javadoc-plugin-3.x into main
Reviewed-on: #3
2025-03-23 12:54:53 +01:00
11bf17f89d Update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.11.2 2025-03-23 11:28:59 +00:00
e17bb909f5 Update dependency com.sk89q.worldedit:worldedit-bukkit to v7.3.10 2025-03-23 11:28:56 +00:00
144425ac5f Merge pull request 'Configure Renovate' (#1) from renovate/configure into main
Reviewed-on: #1
2025-03-23 12:05:26 +01:00
9f246a5f9b Add renovate.json 2025-03-22 23:12:32 +00:00
aa181c3b15 Allow MultiBlock place event
Some checks failed
continuous-integration/drone/push Build was killed
2022-11-12 07:14:24 +01:00
b1b7e5d910 Fix all commands not working
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 07:10:50 +01:00
fea420f2bc Fix ignored events also getting whitelisted
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 07:08:45 +01:00
36dd8afec1 Implement chat format support
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 06:57:44 +01:00
3b744fe113 Fix glitchy item dropping
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 06:38:07 +01:00
1c51701903 Remove deprecated player inventory event listener
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 06:26:04 +01:00
b6aeed7ea8 Add Super Listener to whitelist events
All checks were successful
continuous-integration/drone/push Build is passing
This is a very strict measure, but works great in disabling features and keeping the server to a very barebones setup.
2022-11-12 06:22:40 +01:00
4c9689af6f Reinit limbo world at startup
All checks were successful
continuous-integration/drone/push Build is passing
In case server crashed, was stopped before all regions were cleared, and various other cases including folder size.
2022-11-12 05:31:14 +01:00
598dcd7e09 Whitelist inventory events
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 05:23:36 +01:00
e6eb4a416b Add chat cool-down feature
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 05:14:07 +01:00
2de28d64a5 Disable void falling and entity damage
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 05:03:27 +01:00
cadc5854ef Enable own world generator and handling
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 04:59:45 +01:00
73bb8e4de2 Implement World limitations at startup
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 04:44:35 +01:00
09884f1646 Fix broken island spot finder
All checks were successful
continuous-integration/drone/push Build is passing
It was working as long as the coordinates in the map were ordered, but since this is not ensured, we need a more complex way of checking for them.
2022-11-12 04:34:08 +01:00
7abfb4d536 Disable all entities generation
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 04:11:13 +01:00
e68326cb87 Use WorldEdit API for area cleanup instead
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 04:07:55 +01:00
3ef681e839 Implement async area cleanup on quit (slow)
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 03:47:49 +01:00
8e299009a4 Implement island distance config option
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 01:50:27 +01:00
2866573d0d Implement island max walking range from spawnpoint
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 01:44:07 +01:00
fcbd6c5d01 Fix null position async errors
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 01:27:41 +01:00
8d4284138f Fix OutOfBounds errors
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 01:25:55 +01:00
51c178ab4f Implement config file and spawn offset
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-12 01:12:45 +01:00
dd1425863a Fix player null check in location runnable
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-11 23:29:15 +01:00
500f7b33cb Use new method for island spawn teleport
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-11 23:23:02 +01:00
09396fa09a Implement basic spawn command
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-11 23:22:26 +01:00
8bc992a707 Set creative gamemode on join
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-11 23:17:15 +01:00
8a86f15996 Disable player flight 2022-11-11 23:16:59 +01:00
20 changed files with 744 additions and 117 deletions

45
pom.xml
View File

@@ -42,20 +42,61 @@
<version>1.19.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jetbrains/annotations -->
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>23.0.0</version>
<version>26.0.2-1</version>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.2.0-SNAPSHOT</version>
<version>7.3.17</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>wtf.beatrice.limbomanager.LimboManager</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.12.0</version>
</plugin>
</plugins>
</build>
</project>

3
renovate.json Normal file
View File

@@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}

View File

@@ -1,30 +1,36 @@
package wtf.beatrice.limbomanager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import wtf.beatrice.limbomanager.objects.Coordinates;
import wtf.beatrice.limbomanager.objects.LocationCheckRunnable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Cache
{
public static List<Player> chatCooldown = new ArrayList<>();
public static final String worldName = "limbo";
public static World limboWorld;
public static final Coordinates baseCoords = new Coordinates(1000, 1000);
public static int islandsDistance = 500;
public static int islandWalkingRange = 100;
private static YamlConfiguration configuration;
public static final HashMap<String, Coordinates> playerIslands = new HashMap<>();
public static LocationCheckRunnable locationCheckRunnable;
public static void teleportToOwnIsland(Player player)
{
Coordinates islandCoords = playerIslands.get(player.getName());
Location targetLocation = new Location(player.getWorld(), islandCoords.getX(), 100, islandCoords.getZ());
Bukkit.getScheduler().runTask(LimboManager.getInstance(), () -> {
targetLocation.getWorld().loadChunk(targetLocation.getChunk().getX(), targetLocation.getChunk().getZ(), true);
player.teleport(targetLocation);
});
public static void setConfiguration(YamlConfiguration configuration) {
Cache.configuration = configuration;
}
public static YamlConfiguration getConfiguration() {
return configuration;
}
}

View File

@@ -1,15 +1,18 @@
package wtf.beatrice.limbomanager;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import wtf.beatrice.limbomanager.listeners.CommandCanceller;
import wtf.beatrice.limbomanager.listeners.PlayerHider;
import wtf.beatrice.limbomanager.listeners.PlayerTeleporter;
import wtf.beatrice.limbomanager.listeners.RiskyBlocksHandler;
import wtf.beatrice.limbomanager.commands.Spawn;
import wtf.beatrice.limbomanager.listeners.*;
import wtf.beatrice.limbomanager.objects.LocationCheckRunnable;
import wtf.beatrice.limbomanager.objects.WorldGenerator;
import wtf.beatrice.limbomanager.utils.FileUtils;
import java.io.File;
import java.io.IOException;
public class LimboManager extends JavaPlugin {
@@ -23,20 +26,47 @@ public class LimboManager extends JavaPlugin {
instance = this;
pluginManager = Bukkit.getServer().getPluginManager();
pluginManager.registerEvents(new PlayerHider(), this);
// register commands
getCommand("spawn").setExecutor(new Spawn());
// register listeners
pluginManager.registerEvents(new PlayerChecker(), this);
pluginManager.registerEvents(new PlayerTeleporter(), this);
pluginManager.registerEvents(new CommandCanceller(), this);
pluginManager.registerEvents(new RiskyBlocksHandler(), this);
pluginManager.registerEvents(new WorldLoadHandler(), this);
pluginManager.registerEvents(new PlayerChatManager(), this);
// no need to check if it exists, it will just skip creation.
SuperListener superListener = new SuperListener();
pluginManager.registerEvents(superListener, this);
superListener.doStuff();
// no need to check if folder exists, it will just skip creation.
getDataFolder().mkdirs();
schematicsFolderPath = getDataFolder().getAbsolutePath() + File.separator + "schematics";
getSchematicsFolder().mkdirs();
String configPath = getDataFolder().getAbsolutePath() + File.separator + "config.yml";
File config = new File(configPath);
FileUtils.copyFileFromSrc(config);
YamlConfiguration configuration = new YamlConfiguration();
try {
configuration.load(config);
Cache.setConfiguration(configuration);
} catch (IOException | InvalidConfigurationException e) {
throw new RuntimeException(e);
}
// cache some config variables
Cache.islandWalkingRange = configuration.getInt("sizing.allowed-range");
Cache.islandsDistance = configuration.getInt("sizing.island-distance");
// start location check runnable
Cache.locationCheckRunnable = new LocationCheckRunnable();
Cache.locationCheckRunnable.task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Cache.locationCheckRunnable, 10L, 5L);
// create limbo world
WorldGenerator worldGenerator = new WorldGenerator();
worldGenerator.generateWorld();
}

View File

@@ -0,0 +1,27 @@
package wtf.beatrice.limbomanager.commands;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import wtf.beatrice.limbomanager.utils.LocationUtils;
public class Spawn implements CommandExecutor
{
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args)
{
if(!(sender instanceof Player))
{
sender.sendMessage("Not a player");
return true;
}
LocationUtils.teleportToOwnIsland((Player) sender);
sender.sendMessage("Teleported");
return true;
}
}

View File

@@ -4,13 +4,10 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import java.util.ArrayList;
import java.util.List;
public class CommandCanceller implements Listener
{
private final static String allowedCmdsRegex = "\\/(login|register|changepassword|premium|cracked)\\b";
private final static String allowedCmdsRegex = "\\/(login|register|changepassword|premium|cracked|spawn)\\b";
/*
first "/" is the command prefix
(login|register|...) means either one or the other

View File

@@ -0,0 +1,37 @@
package wtf.beatrice.limbomanager.listeners;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import wtf.beatrice.limbomanager.Cache;
import wtf.beatrice.limbomanager.LimboManager;
public class PlayerChatManager implements Listener
{
@EventHandler
public void onPlayerChat(AsyncPlayerChatEvent event)
{
String format = Cache.getConfiguration().getString("chat.format");
format = format.replace("{player}", "%s")
.replace("{message}", "%s");
event.setFormat(format);
int coolDown = Cache.getConfiguration().getInt("chat.cool-down", 3);
if(coolDown < 1) return; // disable this feature if cooldown is 0 or negative.
Player player = event.getPlayer();
if(Cache.chatCooldown.contains(player))
{
player.sendMessage("Chat is limited in this server. Please wait.");
event.setCancelled(true);
return;
}
Cache.chatCooldown.add(player);
Bukkit.getScheduler().runTaskLater(LimboManager.getInstance(), () -> Cache.chatCooldown.remove(player), 20L * coolDown);
}
}

View File

@@ -0,0 +1,70 @@
package wtf.beatrice.limbomanager.listeners;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntitySpawnEvent;
import org.bukkit.event.inventory.*;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import wtf.beatrice.limbomanager.LimboManager;
public class PlayerChecker implements Listener
{
// this class performs various checks on player join and quit to ensure general safety.
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event)
{
// remove join msg
event.setJoinMessage(null);
LimboManager plugin = LimboManager.getInstance();
Player joiner = event.getPlayer();
// hide player from everyone and hide everyone from player
for(Player otherPlayer : Bukkit.getServer().getOnlinePlayers())
{
otherPlayer.hidePlayer(plugin, joiner);
joiner.hidePlayer(plugin, otherPlayer);
}
// disable flight
joiner.setAllowFlight(false);
joiner.setFlying(false);
// set gamemode
joiner.setGameMode(GameMode.CREATIVE);
// clear inventory
joiner.getInventory().clear();
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event)
{
event.setQuitMessage(null);
}
@EventHandler
public void onEntityCreate(EntitySpawnEvent event)
{
// disable ALL entities
if(event.getEntity().getType() != EntityType.PLAYER)
{
event.setCancelled(true);
}
}
@EventHandler
public void onEntityDamage(EntityDamageEvent event)
{
event.setCancelled(true);
}
}

View File

@@ -1,38 +0,0 @@
package wtf.beatrice.limbomanager.listeners;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import wtf.beatrice.limbomanager.LimboManager;
public class PlayerHider implements Listener
{
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event)
{
// remove join msg
event.setJoinMessage(null);
LimboManager plugin = LimboManager.getInstance();
Player joiner = event.getPlayer();
// hide player from everyone and hide everyone from player
for(Player otherPlayer : Bukkit.getServer().getOnlinePlayers())
{
otherPlayer.hidePlayer(plugin, joiner);
joiner.hidePlayer(plugin, otherPlayer);
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event)
{
event.setQuitMessage(null);
}
}

View File

@@ -1,6 +1,7 @@
package wtf.beatrice.limbomanager.listeners;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
@@ -11,9 +12,13 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -22,10 +27,13 @@ import org.bukkit.event.player.PlayerQuitEvent;
import wtf.beatrice.limbomanager.Cache;
import wtf.beatrice.limbomanager.LimboManager;
import wtf.beatrice.limbomanager.objects.Coordinates;
import wtf.beatrice.limbomanager.utils.LocationUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;
public class PlayerTeleporter implements Listener
{
@@ -39,21 +47,24 @@ public class PlayerTeleporter implements Listener
Coordinates islandCoords = calcNewCoordinates();
Cache.playerIslands.put(playerName, islandCoords);
Location islandLocation = new Location(player.getWorld(), islandCoords.getX(), 64, islandCoords.getZ());
Location islandLocation = new Location(Cache.limboWorld, islandCoords.getX(), 64, islandCoords.getZ());
// load chunk otherwise it will be buggy (no schem load, no tp)
islandLocation.getWorld().loadChunk(islandLocation.getChunk().getX(), islandLocation.getChunk().getZ(), true);
String testSchematicPath = LimboManager.getSchematicsFolder().getAbsolutePath() + File.separator + "endcityship.schem";
String testSchematicPath = LimboManager.getSchematicsFolder().getAbsolutePath() + File.separator + "default.schem";
File schematicFile = new File(testSchematicPath);
if(!schematicFile.exists())
System.out.println("no exist");
{
LimboManager.getInstance().getLogger().severe("Missing schematic file. This will cause issues!");
return;
}
// todo: check if exists, but this is just a test
// todo: improve and make as async as possible
World islandWEWorld = BukkitAdapter.adapt(islandLocation.getWorld());
World islandWEWorld = BukkitAdapter.adapt(Cache.limboWorld);
Clipboard shematicClipboard;
ClipboardFormat clipboardFormat = ClipboardFormats.findByFile(schematicFile);
@@ -67,7 +78,6 @@ public class PlayerTeleporter implements Listener
// configure here
.build();
Operations.complete(operation);
editSession.flushSession();
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
@@ -77,8 +87,7 @@ public class PlayerTeleporter implements Listener
}
islandLocation.setY(islandLocation.getY() + 20);
player.teleport(islandLocation);
LocationUtils.teleportToOwnIsland(player);
}
@@ -86,9 +95,69 @@ public class PlayerTeleporter implements Listener
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event)
{
String playerName = event.getPlayer().getName();
Player player = event.getPlayer();
String playerName = player.getName();
// clean the whole island space after the player left.
// we will go 20 blocks over the limit in case the location checker timer was extremely slow
// and let the player go that far out of them.
//
// this should never happen.
int maxRange = Cache.islandWalkingRange + 20;
Location islandSpawnLocation = LocationUtils.getPlayerSpawnLocation(player);
Location startFrom = new Location(Cache.limboWorld,
islandSpawnLocation.getX() - maxRange,
islandSpawnLocation.getWorld().getMinHeight(),
islandSpawnLocation.getZ() - maxRange);
Location endAt = new Location(islandSpawnLocation.getWorld(),
islandSpawnLocation.getX() + maxRange,
islandSpawnLocation.getWorld().getMaxHeight(),
islandSpawnLocation.getZ() + maxRange);
// announce area cleanup
LimboManager.getInstance().getLogger().info("Player " + playerName + " quit, clearing region...");
// WorldEdit API integration for faster area cleanup
World weWorld = BukkitAdapter.adapt(islandSpawnLocation.getWorld());
try(EditSession editSession = WorldEdit.getInstance().newEditSession(weWorld))
{
// we only need to set everything to air
BlockState air = BukkitAdapter.adapt(Material.AIR.createBlockData());
// convert our area borders to WE blockvectors
BlockVector3 min = BlockVector3.at(startFrom.getBlockX(), startFrom.getBlockY(), startFrom.getBlockZ());
BlockVector3 max = BlockVector3.at(endAt.getBlockX(), endAt.getBlockY(), endAt.getBlockZ());
// create a cuboid region
CuboidRegion cuboidRegion = new CuboidRegion(weWorld, min, max);
// do the cleaning
editSession.setBlocks(cuboidRegion, air);
// set that island spot to "cool-down mode"
String randUUID = UUID.randomUUID().toString();
Coordinates islandCoords = new Coordinates(Cache.playerIslands.get(playerName));
Cache.playerIslands.put(randUUID, islandCoords);
Cache.playerIslands.remove(playerName);
// start a timer to set the spot to free after X time.
Bukkit.getScheduler().runTaskLater(LimboManager.getInstance(), () -> {
LimboManager.getInstance().getLogger().info("Region [" + randUUID + ", "
+ islandCoords.getX() + ", "
+ islandCoords.getZ()
+ "] of " + playerName + " is now available again.");
Cache.playerIslands.remove(randUUID);
}, 60 * 20L);
} catch (MaxChangedBlocksException e) {
throw new RuntimeException(e);
}
Cache.playerIslands.remove(playerName);
}
@@ -96,35 +165,30 @@ public class PlayerTeleporter implements Listener
/*
how are islands laid out?
we start from (1000, 1000) and we put islands at 500 blocks distance up to 10000. then we move to a new row.
we start from (1000, 1000) and we put islands at <Cache.islandsDistance> blocks distance up to 10000. then we move to a new row.
*/
Coordinates islandCoords = new Coordinates(1000, 1000);
for(Coordinates currentCoords : Cache.playerIslands.values()) {
Coordinates islandCoords = new Coordinates(Cache.baseCoords);
ArrayList<Coordinates> playerIslands = new ArrayList<>(Cache.playerIslands.values());
// if the two are not the same, it means we found a free spot.
// we can thus quit the loop and keep the current coords as valid.
if(!islandCoords.equals(currentCoords)) break;
for(int i = 0; i < playerIslands.size(); i++)
{
Coordinates checkCoords = playerIslands.get(i);
// else, if they are the same,
// we have to either increase X or move to a new row, in case it's over 10000.
if(islandCoords.getX() >= 10000) // if we need to create a new row
if(islandCoords.equals(checkCoords))
{
islandCoords.setX(1000);
islandCoords.setZ(islandCoords.getZ() + 500);
} else { // if we just need to increase the column
islandCoords.setX(islandCoords.getX() + 500);
// we have to either increase X or move to a new row and reset X, in case it's over 10000.
if(islandCoords.getX() >= 10000) // if we need to create a new row
{
islandCoords.setX(1000);
islandCoords.setZ(islandCoords.getZ() + Cache.islandsDistance);
} else { // if we just need to increase the column
islandCoords.setX(islandCoords.getX() + Cache.islandsDistance);
}
i = 0; // restart the loop and check again (ugh)
}
}
} // at the end of the loop, we should have unique coordinates.
return islandCoords;
}
}
/*
player joins -> we look for the first free space -> we add it to the list and generate the island
*/

View File

@@ -0,0 +1,74 @@
package wtf.beatrice.limbomanager.listeners;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.reflections.Reflections;
import wtf.beatrice.limbomanager.LimboManager;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
public class SuperListener implements Listener
{
public void doStuff() {
// search event classes
Reflections reflections = new Reflections("org.bukkit");// change to also find custom events
Set<Class<? extends Event>> eventClasses = reflections.getSubTypesOf(Event.class).stream().
filter(clazz -> Arrays.stream(clazz.getDeclaredFields())
.anyMatch(field -> field.getType().getName().endsWith("HandlerList")))
.collect(Collectors.toSet());
LimboManager.getInstance().getLogger().info("Found " + eventClasses.size() + " available events!");
LimboManager.getInstance().getLogger()
.info(eventClasses.stream().map(Class::getName).collect(Collectors.joining(", ")));
// register events
EventExecutor eventExecutor = (listener, event) -> iGetCalledForEveryEvent(event);
eventClasses.forEach(clazz -> LimboManager.getInstance().getServer().getPluginManager()
.registerEvent(clazz, this, EventPriority.MONITOR, eventExecutor, LimboManager.getInstance()));
}
private final String[] dontLog = { "PlayerMoveEvent", "BlockFadeEvent", "BlockPhysicsEvent", "LeavesDecayEvent",
"PlayerStatisticIncrementEvent", "PlayerRecipeDiscoverEvent", "PlayerArmSwingEvent", "BlockDropItemEvent",
"BlockFertilizeEvent", "AsyncPlayerChatPreviewEvent", "ItemSpawnEvent", "InventoryOpenEvent", "BlockIgniteEvent"
};
private final String[] allowed = {"PlayerMoveEvent", "PlayerTeleportEvent", "ServerCommandEvent",
"StandardPaperServerListPingEventImpl", "PlayerGameModeChangeEvent", "WorldUnloadEvent",
"TimeSkipEvent", "PlayerToggleSprintEvent", "PlayerChatEvent", "AsyncPlayerChatEvent",
"GenericGameEvent", "InventoryCreativeEvent", "PlayerItemHeldEvent", "PlayerInteractEvent",
"BlockPlaceEvent", "BlockBreakEvent", "PlayerToggleSneakEvent", "PlayerKickEvent",
"InventoryClickEvent", "PlayerDropItemEvent", "PlayerCommandPreprocessEvent",
"BlockMultiPlaceEvent"
};
public void iGetCalledForEveryEvent(Event event) {
if(Arrays.stream(allowed).noneMatch(allowed -> event.getEventName().equals(allowed))) {
if(event instanceof Cancellable)
{
((Cancellable) event).setCancelled(true);
}
}
if (Arrays.stream(dontLog).anyMatch(ignored -> event.getEventName().equals(ignored))) {
return;
}
if(event instanceof Cancellable)
{
if(Arrays.stream(allowed).noneMatch(allowed -> event.getEventName().equals(allowed))) {
LimboManager.getInstance().getLogger().warning(event.getEventName() + " was called!");
}
}
}
}

View File

@@ -0,0 +1,46 @@
package wtf.beatrice.limbomanager.listeners;
import org.bukkit.Difficulty;
import org.bukkit.GameRule;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldLoadEvent;
public class WorldLoadHandler implements Listener
{
@EventHandler
public void onWorldLoad(WorldLoadEvent event)
{
World loaded = event.getWorld();
loaded.setDifficulty(Difficulty.PEACEFUL);
loaded.setAutoSave(false);
loaded.setFullTime(6000L);
loaded.setPVP(false);
loaded.setStorm(false);
loaded.setHardcore(false);
loaded.setGameRule(GameRule.DO_INSOMNIA, false);
loaded.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false);
loaded.setGameRule(GameRule.COMMAND_BLOCK_OUTPUT, false);
loaded.setGameRule(GameRule.DISABLE_RAIDS, true);
loaded.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
loaded.setGameRule(GameRule.DO_ENTITY_DROPS, false);
loaded.setGameRule(GameRule.DO_FIRE_TICK,false);
loaded.setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true);
loaded.setGameRule(GameRule.DO_MOB_LOOT, false);
loaded.setGameRule(GameRule.DO_MOB_SPAWNING, false);
loaded.setGameRule(GameRule.DO_PATROL_SPAWNING, false);
loaded.setGameRule(GameRule.DO_TILE_DROPS, false);
loaded.setGameRule(GameRule.DO_TRADER_SPAWNING, false);
loaded.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
loaded.setGameRule(GameRule.DO_WARDEN_SPAWNING, false);
loaded.setGameRule(GameRule.FALL_DAMAGE, false);
loaded.setGameRule(GameRule.FIRE_DAMAGE, false);
loaded.setGameRule(GameRule.DROWNING_DAMAGE, false);
loaded.setGameRule(GameRule.FREEZE_DAMAGE, false);
loaded.setGameRule(GameRule.MOB_GRIEFING, false);
loaded.setGameRule(GameRule.NATURAL_REGENERATION, false);
loaded.setGameRule(GameRule.SHOW_DEATH_MESSAGES, false);
loaded.setGameRule(GameRule.KEEP_INVENTORY, false);
}
}

View File

@@ -0,0 +1,78 @@
package wtf.beatrice.limbomanager.objects;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.scheduler.BukkitTask;
import wtf.beatrice.limbomanager.Cache;
import wtf.beatrice.limbomanager.LimboManager;
import java.util.ArrayList;
import java.util.List;
@Deprecated // this works, but it's too slow. (fast-async)worldedit's api has a far better way of handling it.
public class AreaCleanerRunnable implements Runnable
{
public BukkitTask task;
Location min, max;
List<Location> blocksList = new ArrayList<>();
Location current;
int blocksPerRun = 384;
String playerName, cleanUpID;
public AreaCleanerRunnable(Location min, Location max, String playerName, String cleanUpID)
{
this.playerName = playerName;
this.cleanUpID = cleanUpID;
this.min = min;
this.max = max;
current = new Location(min.getWorld(), min.getBlockX(), min.getBlockY(), min.getBlockZ());
LimboManager.getInstance().getLogger().info(min.getBlockX() + " " + min.getBlockY() + " " + min.getBlockZ());
LimboManager.getInstance().getLogger().info(max.getBlockX() + " " + max.getBlockY() + " " + max.getBlockZ());
}
@Override
public void run()
{
boolean cancelled = false;
for(int i = 0; i < blocksPerRun; i++)
{
if(cancelled) break;
Bukkit.getScheduler().runTask(LimboManager.getInstance(), () ->
{
current.getBlock().setType(Material.AIR);
if(current.getBlockY() < max.getBlockY()) {
current.setY(current.getBlockY() + 1 );
} else {
current.setY(min.getBlockY());
if (current.getBlockX() < max.getBlockX()) {
current.setX(current.getBlockX() + 1);
} else {
current.setX(min.getBlockX());
if (current.getBlockZ() < max.getBlockZ()) {
current.setZ(current.getBlockZ() + 1);
LimboManager.getInstance().getLogger().info("c: " + current.getBlockX() + " " + current.getBlockY() + " " + current.getBlockZ());
} else {
// we finished, free the location and cancel the task.
Cache.playerIslands.remove(cleanUpID);
LimboManager.getInstance().getLogger().info("finished cleaning area for " + playerName);
task.cancel();
return;
}
}
}
});
}
}
}

View File

@@ -11,6 +11,12 @@ public class Coordinates
this.z = z;
}
public Coordinates(Coordinates old)
{
this.x = old.x;
this.z = old.z;
}
public void setX(int x) { this.x = x; }
public void setZ(int z) { this.z = z; }

View File

@@ -5,6 +5,7 @@ import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import wtf.beatrice.limbomanager.Cache;
import wtf.beatrice.limbomanager.utils.LocationUtils;
import java.util.ArrayList;
import java.util.List;
@@ -15,7 +16,6 @@ public class LocationCheckRunnable implements Runnable
public BukkitTask task;
List<Player> playersToCheck = new ArrayList<>();
private final static int distanceMax = 100;
// we give players a distanceMax block range to move in.
@@ -25,34 +25,55 @@ public class LocationCheckRunnable implements Runnable
public void run()
{
// if we checked all players, refill the list and skip the check for this time (in case server is empty).
if(playersToCheck.isEmpty()) {
playersToCheck.addAll(Bukkit.getServer().getOnlinePlayers());
return;
}
Player player = playersToCheck.get(0);
Location playerLocation = player.getLocation();
playersToCheck.remove(player);
Coordinates playerIslandCoordinates = Cache.playerIslands.get(player.getName());
int distanceX = Math.abs(playerLocation.getBlockX() - playerIslandCoordinates.getX());
int distanceZ = Math.abs(playerLocation.getBlockZ() - playerIslandCoordinates.getZ());
if(distanceX > distanceMax || distanceZ > distanceMax)
// load the player
Player player = null;
while(player == null || !player.isOnline()) // check if player left and in case, move to next one
{
Cache.teleportToOwnIsland(player);
player.sendMessage("Out of island limits");
if(!playersToCheck.isEmpty()) player = playersToCheck.get(0);
if(player != null) playersToCheck.remove(player);
}
if(!Cache.playerIslands.containsKey(player.getName()))
return; //it means the player just joined and still didn't get an island (reminder that this is async)
Location playerLocation = player.getLocation();
int spawnOffsetX = Cache.getConfiguration().getInt("island.spawn-offset.x");
int spawnOffsetZ = Cache.getConfiguration().getInt("island.spawn-offset.z");
// we are copying the object because otherwise we'd be directly editing the reference in the hashmap
// and causing a lot of trouble by moving the spawnpoint itself.
Coordinates islandSpawnCoordinates = new Coordinates(Cache.playerIslands.get(player.getName()));
islandSpawnCoordinates.setX(islandSpawnCoordinates.getX() + spawnOffsetX);
islandSpawnCoordinates.setZ(islandSpawnCoordinates.getZ() + spawnOffsetZ);
// boolean to know if after the different checks we have to teleport the player
boolean teleport = false;
// check if player is free-falling into the void
if(playerLocation.getBlockY() <= playerLocation.getWorld().getMinHeight())
teleport = true;
// calculate absolute distance from spawnpoint
int distanceX = Math.abs(playerLocation.getBlockX() - islandSpawnCoordinates.getX());
int distanceZ = Math.abs(playerLocation.getBlockZ() - islandSpawnCoordinates.getZ());
// check if player is inside bounds
if(distanceX > Cache.islandWalkingRange || distanceZ > Cache.islandWalkingRange)
teleport = true;
if(teleport)
{
LocationUtils.teleportToOwnIsland(player);
player.sendMessage("Out of bounds");
}
}
}
// 1500 1000
// 1000 1000
// 700 1000

View File

@@ -0,0 +1,47 @@
package wtf.beatrice.limbomanager.objects;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import wtf.beatrice.limbomanager.Cache;
import wtf.beatrice.limbomanager.LimboManager;
import java.io.File;
public class WorldGenerator
{
public void generateWorld()
{
// unload world
LimboManager.getInstance().getLogger().info("Force unloading world...");
Bukkit.getServer().unloadWorld(Cache.worldName, false);
// delete world files
LimboManager.getInstance().getLogger().info("Resetting world...");
String worldFolderPath = Bukkit.getServer().getWorldContainer().getAbsolutePath() + File.separator + Cache.worldName;
File worldFolder = new File(worldFolderPath);
deleteDirectory(worldFolder);
// create world
LimboManager.getInstance().getLogger().info("Creating world from scratch...");
WorldCreator worldCreator = new WorldCreator(Cache.worldName);
worldCreator.environment(World.Environment.THE_END);
worldCreator.generateStructures(false);
worldCreator.type(WorldType.FLAT);
worldCreator.generator("VoidGen");
Cache.limboWorld = worldCreator.createWorld();
LimboManager.getInstance().getLogger().info("World ready!");
}
boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}
}

View File

@@ -0,0 +1,40 @@
package wtf.beatrice.limbomanager.utils;
import wtf.beatrice.limbomanager.LimboManager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.logging.Level;
public class FileUtils
{
public static void copyFileFromSrc(File destination)
{
// Check if files already exists and if it doesn't, then create it.
if(!destination.exists())
{
// Load the InputStream of the file in the source folder.
InputStream is = FileUtils.class.getResourceAsStream("/" + destination.getName());
try
{
// Try copying the file to the directory where it's supposed to be, and log it.
Files.copy(is, Paths.get(destination.getAbsolutePath()));
is.close();
LimboManager.getInstance().getLogger().log(Level.INFO, "File " + destination.getName() + " successfully created.");
}
catch (IOException e)
{
// Throw exception if something went wrong
LimboManager.getInstance().getLogger().log(Level.SEVERE, "There were some unexpected errors from " + destination.getName() + " file creation. Please contact the developer and send him this log:");
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,57 @@
package wtf.beatrice.limbomanager.utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import wtf.beatrice.limbomanager.Cache;
import wtf.beatrice.limbomanager.LimboManager;
import wtf.beatrice.limbomanager.objects.Coordinates;
import java.util.logging.Level;
public class LocationUtils {
public static void teleportToOwnIsland(Player player)
{
Location targetLocation = getPlayerSpawnLocation(player);
Bukkit.getScheduler().runTask(LimboManager.getInstance(), () -> {
targetLocation.getWorld().loadChunk(targetLocation.getChunk().getX(), targetLocation.getChunk().getZ(), true);
player.teleport(targetLocation);
});
}
public static Location getPlayerSpawnLocation(Player player) {
String worldName = Cache.getConfiguration().getString("island.world-name");
if(worldName == null)
{
LimboManager.getInstance().getLogger().log(Level.SEVERE, "World name is null!");
return null;
}
World spawnWorld = Bukkit.getWorld(worldName);
if(spawnWorld == null)
{
LimboManager.getInstance().getLogger().log(Level.SEVERE, "World is null!");
return null;
}
String playerName = player.getName();
Coordinates coordinates = Cache.playerIslands.get(playerName);
double offsetX = Cache.getConfiguration().getDouble("island.spawn-offset.x");
double y = Cache.getConfiguration().getDouble("island.spawn-offset.y");
double offsetZ = Cache.getConfiguration().getDouble("island.spawn-offset.z");
double x = coordinates.getX() + offsetX;
double z = coordinates.getZ() + offsetZ;
float yaw = (float) Cache.getConfiguration().getDouble("island.spawn-offset.yaw");
float pitch = (float) Cache.getConfiguration().getDouble("island.spawn-offset.pitch");
return new Location(spawnWorld, x, y, z, yaw, pitch);
}
}

View File

@@ -0,0 +1,14 @@
sizing:
island-distance: 500
allowed-range: 50
island:
world-name: world
spawn-offset:
x: 0.0
y: 20.0
z: 0.0
yaw: 0.0
pitch: 0.0
chat:
cool-down: 3
format: '§7{player} » {message}'

View File

@@ -1,8 +1,15 @@
name: LimboManager
main: wtf.beatrice.limbomanager.LimboManager
version: 0.0.2
version: 0.0.3
# load: STARTUP
description: Mix of tools to run a Limbo server
api-version: 1.19
author: astro_bea
depend:
- WorldEdit
- VoidGen
commands:
spawn:
usage: /<command>
description: teleport a player to their own island