add /spawn

add /setspawn
add worldsettings for spawn locations
add global spawning
This commit is contained in:
Taah 2022-04-24 20:02:39 -07:00
parent 3d850d3698
commit 6e30af29f8
20 changed files with 552 additions and 13 deletions

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
/.gradle/ /.gradle/
/**/*/build/ /**/*/build/
/build/ /build/
/.idea/ /.idea/
/**/*/gradle/
/**/*/gradlew*

View File

@ -0,0 +1,9 @@
package dev.plex.exception;
public class WorldNotFoundException extends RuntimeException
{
public WorldNotFoundException()
{
super("<red>This world does not exist!");
}
}

View File

@ -1,12 +1,14 @@
package dev.plex.plugin; package dev.plex.plugin;
import dev.plex.util.ObjectHolder; import dev.plex.util.ObjectHolder;
import dev.plex.world.IWorldManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public abstract class SunburstPlugin extends JavaPlugin public abstract class SunburstPlugin extends JavaPlugin
{ {
private static SunburstPlugin plugin; private static SunburstPlugin plugin;
private ObjectHolder holder; private ObjectHolder holder;
private IWorldManager<?> worldManager;
@Override @Override
public void onLoad() public void onLoad()
@ -23,8 +25,14 @@ public abstract class SunburstPlugin extends JavaPlugin
return this.holder; return this.holder;
} }
public IWorldManager<?> getWorldManager()
{
return worldManager;
}
public static SunburstPlugin getPlugin() public static SunburstPlugin getPlugin()
{ {
return plugin; return plugin;
} }
} }

View File

@ -1,6 +1,8 @@
package dev.plex.storage; package dev.plex.storage;
import dev.plex.player.ISunburstPlayer; import dev.plex.player.ISunburstPlayer;
import dev.plex.world.IWorldSettings;
import org.bukkit.World;
import java.util.UUID; import java.util.UUID;

View File

@ -1,6 +1,5 @@
package dev.plex.util; package dev.plex.util;
import dev.plex.plugin.SunburstPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -9,7 +8,7 @@ public class Logger
public static void log(String message) public static void log(String message)
{ {
Bukkit.getScheduler().runTask(SunburstPlugin.getPlugin(), () -> Bukkit.getConsoleSender().sendMessage(MiniMessage.miniMessage().deserialize("<green>[Sunburst] <gold>" + message))); Bukkit.getConsoleSender().sendMessage(MiniMessage.miniMessage().deserialize("<green>[Sunburst] <gold>" + message));
} }
public static void error(String message) public static void error(String message)

View File

@ -0,0 +1,41 @@
package dev.plex.util;
public class XYZLocation
{
private final double x, y, z;
private final float yaw, pitch;
public XYZLocation(double x, double y, double z, float yaw, float pitch)
{
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
}
public double getX()
{
return x;
}
public double getY()
{
return y;
}
public double getZ()
{
return z;
}
public float getYaw()
{
return yaw;
}
public float getPitch()
{
return pitch;
}
}

View File

@ -0,0 +1,36 @@
package dev.plex.util.gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.bukkit.Bukkit;
import org.bukkit.World;
import java.io.IOException;
public class WorldAdapter extends TypeAdapter<World>
{
@Override
public void write(JsonWriter out, World value) throws IOException
{
if (value == null)
{
out.nullValue();
return;
}
out.value(value.getName());
}
@Override
public World read(JsonReader reader) throws IOException
{
if (reader.peek() == JsonToken.NULL)
{
reader.nextNull();
return null;
}
String worldName = reader.nextString();
return Bukkit.getWorld(worldName);
}
}

View File

@ -0,0 +1,42 @@
package dev.plex.util.gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import dev.plex.util.XYZLocation;
import java.io.IOException;
public class XYZLocationAdapter extends TypeAdapter<XYZLocation>
{
@Override
public void write(JsonWriter out, XYZLocation value) throws IOException
{
if (value == null)
{
out.nullValue();
return;
}
out.value(String.format("%s, %s, %s, %s, %s", value.getX(), value.getY(), value.getZ(), value.getYaw(), value.getPitch()));
}
@Override
public XYZLocation read(JsonReader reader) throws IOException
{
if (reader.peek() == JsonToken.NULL)
{
reader.nextNull();
return null;
}
String s = reader.nextString();
String[] args = s.split(", ");
double x = Double.parseDouble(args[0]);
double y = Double.parseDouble(args[1]);
double z = Double.parseDouble(args[2]);
float yaw = Float.parseFloat(args[3]);
float pitch = Float.parseFloat(args[4]);
return new XYZLocation(x, y, z, yaw, pitch);
}
}

View File

@ -0,0 +1,18 @@
package dev.plex.world;
import org.bukkit.World;
import java.util.Collection;
public interface IWorldManager<T extends IWorldSettings>
{
void addSetting(T settings);
void removeSettings(T settings);
T getSettings(World world);
Collection<T> getSettings();
void clear();
}

View File

@ -0,0 +1,17 @@
package dev.plex.world;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializer;
import dev.plex.util.XYZLocation;
import dev.plex.util.gson.WorldAdapter;
import dev.plex.util.gson.XYZLocationAdapter;
import org.bukkit.World;
public interface IWorldSettings
{
World world();
XYZLocation spawnLocation();
void spawnLocation(XYZLocation location);
}

View File

@ -4,6 +4,7 @@ import dev.plex.command.impl.*;
import dev.plex.listener.impl.player.ChatListener; import dev.plex.listener.impl.player.ChatListener;
import dev.plex.listener.impl.player.GodListener; import dev.plex.listener.impl.player.GodListener;
import dev.plex.listener.impl.player.JoinListener; import dev.plex.listener.impl.player.JoinListener;
import dev.plex.listener.impl.player.SpawnListener;
import dev.plex.permission.PermissionHandlerImpl; import dev.plex.permission.PermissionHandlerImpl;
import dev.plex.player.ISunburstPlayer; import dev.plex.player.ISunburstPlayer;
import dev.plex.player.PlayerCache; import dev.plex.player.PlayerCache;
@ -13,10 +14,10 @@ import dev.plex.storage.FileStorage;
import dev.plex.util.ComponentUtil; import dev.plex.util.ComponentUtil;
import dev.plex.util.Configuration; import dev.plex.util.Configuration;
import dev.plex.util.Logger; import dev.plex.util.Logger;
import dev.plex.world.JsonWorldManager;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.java.Log;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -31,6 +32,8 @@ public final class Sunburst extends SunburstPlugin
private Configuration configuration; private Configuration configuration;
private Configuration messages; private Configuration messages;
@Getter(AccessLevel.NONE)
private JsonWorldManager jsonWorldManager;
@Override @Override
public void load() public void load()
@ -59,16 +62,20 @@ public final class Sunburst extends SunburstPlugin
public void onEnable() public void onEnable()
{ {
this.getObjectHolder().setStorageSystem(new FileStorage()); this.getObjectHolder().setStorageSystem(new FileStorage());
this.jsonWorldManager = new JsonWorldManager();
new JoinListener(); new JoinListener();
new ChatListener(); new ChatListener();
new GodListener(); new GodListener();
new SpawnListener();
new NicknameCMD(); new NicknameCMD();
new SunburstCMD(); new SunburstCMD();
new MessageCMD(); new MessageCMD();
new ReplyCMD(); new ReplyCMD();
new GodCMD(); new GodCMD();
new SetSpawnCMD();
new SpawnCMD();
Bukkit.getOnlinePlayers().forEach(player -> Bukkit.getOnlinePlayers().forEach(player ->
{ {
@ -94,6 +101,12 @@ public final class Sunburst extends SunburstPlugin
}); });
} }
@Override
public JsonWorldManager getWorldManager()
{
return jsonWorldManager;
}
public static Sunburst inst() public static Sunburst inst()
{ {
return plugin; return plugin;

View File

@ -5,7 +5,6 @@ import dev.plex.command.util.CommandInfo;
import dev.plex.command.util.CommandPerms; import dev.plex.command.util.CommandPerms;
import dev.plex.player.ISunburstPlayer; import dev.plex.player.ISunburstPlayer;
import dev.plex.util.ComponentUtil; import dev.plex.util.ComponentUtil;
import dev.plex.util.Logger;
import dev.plex.util.MojangUtils; import dev.plex.util.MojangUtils;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
@ -40,13 +39,17 @@ public class NicknameCMD extends SunburstCommand
} }
if (Bukkit.getOnlinePlayers().stream().anyMatch(p -> p.getName().equalsIgnoreCase(args[0]))) if (Bukkit.getOnlinePlayers().stream().anyMatch(p -> p.getName().equalsIgnoreCase(args[0])))
{ {
Player target = getNonNullPlayer(args[0]); if (!sender.hasPermission(getPermission() + ".other"))
ISunburstPlayer sunburstPlayer = plugin.getObjectHolder().getStorageSystem().getPlayer(target.getUniqueId()); {
return confMsg("noPermission", getPermission() + ".other");
}
if (args.length < 2) if (args.length < 2)
{ {
return usage(); return usage();
} }
if (args[1].equalsIgnoreCase("off")) Player target = getNonNullPlayer(args[0]);
ISunburstPlayer sunburstPlayer = plugin.getObjectHolder().getStorageSystem().getPlayer(target.getUniqueId());
if (args[1].equalsIgnoreCase("off") || args[1].equalsIgnoreCase("clear"))
{ {
sunburstPlayer.displayName(null); sunburstPlayer.displayName(null);
target.sendMessage(confMsg("nicknameRemoved")); target.sendMessage(confMsg("nicknameRemoved"));
@ -68,7 +71,7 @@ public class NicknameCMD extends SunburstCommand
return confMsg("nicknameSetOther", ComponentUtil.REGULAR_TAGS, target.getName(), ComponentUtil.mmCustom(newNickname, ComponentUtil.REGULAR_TAGS)); return confMsg("nicknameSetOther", ComponentUtil.REGULAR_TAGS, target.getName(), ComponentUtil.mmCustom(newNickname, ComponentUtil.REGULAR_TAGS));
} }
if (args[0].equalsIgnoreCase("off")) if (args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("clear"))
{ {
if (sender instanceof ConsoleCommandSender) if (sender instanceof ConsoleCommandSender)
{ {

View File

@ -0,0 +1,37 @@
package dev.plex.command.impl;
import dev.plex.Sunburst;
import dev.plex.command.SunburstCommand;
import dev.plex.command.util.CommandInfo;
import dev.plex.command.util.CommandPerms;
import dev.plex.command.util.RequiredSource;
import dev.plex.util.ComponentUtil;
import dev.plex.util.XYZLocation;
import dev.plex.world.WorldSettingsImpl;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@CommandInfo(name = "setspawn", description = "Sets the world spawn")
@CommandPerms(permission = "sunburst.command.setspawn", source = RequiredSource.PLAYER)
public class SetSpawnCMD extends SunburstCommand
{
@Override
public Component execute(@NotNull CommandSender sender, @Nullable Player player, String[] args)
{
XYZLocation location = new XYZLocation(player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player.getLocation().getYaw(), player.getLocation().getPitch());
if (plugin.getWorldManager().getSettings(player.getWorld()) != null)
{
plugin.getWorldManager().getSettings(player.getWorld()).spawnLocation(location);
} else {
WorldSettingsImpl worldSettings = new WorldSettingsImpl();
worldSettings.world(player.getWorld());
worldSettings.spawnLocation(location);
plugin.getWorldManager().addSetting(worldSettings);
}
plugin.getWorldManager().writeSettings();
return confMsg("spawnSet");
}
}

View File

@ -0,0 +1,98 @@
package dev.plex.command.impl;
import dev.plex.command.SunburstCommand;
import dev.plex.command.util.CommandInfo;
import dev.plex.command.util.CommandPerms;
import dev.plex.command.util.RequiredSource;
import dev.plex.exception.WorldNotFoundException;
import dev.plex.util.Logger;
import dev.plex.world.WorldSettingsImpl;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@CommandInfo(name = "spawn", description = "Teleports to spawn", usage = "/<command> [player]")
@CommandPerms(permission = "sunburst.command.spawn", source = RequiredSource.BOTH)
public class SpawnCMD extends SunburstCommand
{
@Override
public Component execute(@NotNull CommandSender sender, @Nullable Player player, String[] args)
{
if (args.length == 0)
{
if (sender instanceof ConsoleCommandSender)
{
return usage();
} else
{
String globalSpawn = plugin.getConfiguration().getString("options.global-spawn-world", "");
if (!globalSpawn.isEmpty())
{
World world = Bukkit.getWorld(globalSpawn);
if (world == null)
{
throw new WorldNotFoundException();
}
WorldSettingsImpl worldSettings = plugin.getWorldManager().getSettings(world);
if (worldSettings == null)
{
Logger.warn("The world '" + globalSpawn + "' does not have a set spawn point! Defaulting to bukkit's methods");
player.teleportAsync(world.getSpawnLocation());
} else
{
Location loc = new Location(worldSettings.world(), worldSettings.spawnLocation().getX(), worldSettings.spawnLocation().getY(), worldSettings.spawnLocation().getZ(), worldSettings.spawnLocation().getYaw(), worldSettings.spawnLocation().getPitch());
player.teleportAsync(loc);
}
}
WorldSettingsImpl worldSettings = plugin.getWorldManager().getSettings(player.getWorld());
if (worldSettings != null)
{
Location loc = new Location(worldSettings.world(), worldSettings.spawnLocation().getX(), worldSettings.spawnLocation().getY(), worldSettings.spawnLocation().getZ(), worldSettings.spawnLocation().getYaw(), worldSettings.spawnLocation().getPitch());
player.teleportAsync(loc);
}
}
return null;
}
if (!sender.hasPermission(getPermission() + ".other"))
{
return confMsg("noPermission", getPermission() + ".other");
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null)
{
return confMsg("playerNotFound");
}
String globalSpawn = plugin.getConfiguration().getString("options.global-spawn-world", "");
if (!globalSpawn.isEmpty())
{
World world = Bukkit.getWorld(globalSpawn);
if (world == null)
{
throw new WorldNotFoundException();
}
WorldSettingsImpl worldSettings = plugin.getWorldManager().getSettings(world);
if (worldSettings == null)
{
Logger.warn("The world '" + globalSpawn + "' does not have a set spawn point! Defaulting to bukkit's methods");
target.teleportAsync(world.getSpawnLocation());
} else
{
Location loc = new Location(worldSettings.world(), worldSettings.spawnLocation().getX(), worldSettings.spawnLocation().getY(), worldSettings.spawnLocation().getZ(), worldSettings.spawnLocation().getYaw(), worldSettings.spawnLocation().getPitch());
target.teleportAsync(loc);
}
}
WorldSettingsImpl worldSettings = plugin.getWorldManager().getSettings(target.getWorld());
if (worldSettings != null)
{
Location loc = new Location(worldSettings.world(), worldSettings.spawnLocation().getX(), worldSettings.spawnLocation().getY(), worldSettings.spawnLocation().getZ(), worldSettings.spawnLocation().getYaw(), worldSettings.spawnLocation().getPitch());
target.teleportAsync(loc);
}
return null;
}
}

View File

@ -0,0 +1,56 @@
package dev.plex.listener.impl.player;
import dev.plex.exception.WorldNotFoundException;
import dev.plex.listener.SunburstListener;
import dev.plex.util.Logger;
import dev.plex.world.WorldSettingsImpl;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.spigotmc.event.player.PlayerSpawnLocationEvent;
public class SpawnListener extends SunburstListener
{
@EventHandler(priority = EventPriority.HIGHEST)
public void onJoin(PlayerSpawnLocationEvent event)
{
if (!plugin.getConfiguration().getBoolean("options.auto-spawn"))
{
return;
}
String globalSpawn = plugin.getConfiguration().getString("options.global-spawn-world", "");
if (!globalSpawn.isEmpty())
{
World world = Bukkit.getWorld(globalSpawn);
if (world == null)
{
throw new WorldNotFoundException();
}
WorldSettingsImpl worldSettings = plugin.getWorldManager().getSettings(world);
if (worldSettings == null)
{
Logger.warn("The world '" + globalSpawn + "' does not have a set spawn point! Defaulting to bukkit's methods");
event.setSpawnLocation(world.getSpawnLocation());
} else
{
Logger.log("Teleporting to: " + worldSettings.toJSON());
Location loc = new Location(worldSettings.world(), worldSettings.spawnLocation().getX(), worldSettings.spawnLocation().getY(), worldSettings.spawnLocation().getZ(), worldSettings.spawnLocation().getYaw(), worldSettings.spawnLocation().getPitch());
Logger.log("Location: " + loc);
event.getPlayer().setBedSpawnLocation(loc);
event.setSpawnLocation(loc);
}
return;
}
WorldSettingsImpl worldSettings = plugin.getWorldManager().getSettings(event.getPlayer().getWorld());
if (worldSettings != null)
{
Location loc = new Location(worldSettings.world(), worldSettings.spawnLocation().getX(), worldSettings.spawnLocation().getY(), worldSettings.spawnLocation().getZ(), worldSettings.spawnLocation().getYaw(), worldSettings.spawnLocation().getPitch());
event.getPlayer().setBedSpawnLocation(loc);
event.setSpawnLocation(loc);
}
}
}

View File

@ -0,0 +1,99 @@
package dev.plex.world;
import com.google.common.collect.Lists;
import com.google.gson.GsonBuilder;
import dev.plex.Sunburst;
import dev.plex.util.Logger;
import dev.plex.util.XYZLocation;
import dev.plex.util.gson.XYZLocationAdapter;
import lombok.SneakyThrows;
import org.bukkit.World;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class JsonWorldManager implements IWorldManager<WorldSettingsImpl>
{
private static final List<WorldSettingsImpl> WORLD_SETTINGS = Lists.newArrayList();
private final Sunburst plugin = Sunburst.inst();
private final File file;
@SneakyThrows
public JsonWorldManager()
{
this.file = new File(plugin.getDataFolder(), "worlds.json");
if (!this.file.exists())
{
this.file.createNewFile();
try (FileWriter writer = new FileWriter(this.file))
{
writer.write("[]");
writer.flush();
}
} else
{
this.loadAll();
}
}
@SneakyThrows
public void loadAll()
{
clear();
try (FileInputStream fis = new FileInputStream(this.file))
{
final JSONTokener tokener = new JSONTokener(fis);
final JSONArray array = new JSONArray(tokener);
array.forEach(object ->
{
final JSONObject obj = new JSONObject(object.toString());
addSetting(WorldSettingsImpl.fromJSON(obj.toString()));
});
}
}
@SneakyThrows
public void writeSettings()
{
try (FileWriter writer = new FileWriter(this.file))
{
String json = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(XYZLocation.class, new XYZLocationAdapter())
.create().toJson(getSettings());
writer.write(json);
writer.flush();
}
}
public void addSetting(WorldSettingsImpl settings)
{
WORLD_SETTINGS.add(settings);
}
public void removeSettings(WorldSettingsImpl settings)
{
WORLD_SETTINGS.remove(settings);
}
public WorldSettingsImpl getSettings(World world)
{
return WORLD_SETTINGS.stream().filter(settings -> settings.world().equals(world)).findFirst().orElse(null);
}
public Collection<WorldSettingsImpl> getSettings()
{
return WORLD_SETTINGS.stream().toList();
}
public void clear()
{
WORLD_SETTINGS.clear();
}
}

View File

@ -0,0 +1,52 @@
package dev.plex.world;
import com.google.gson.GsonBuilder;
import dev.plex.util.XYZLocation;
import dev.plex.util.gson.XYZLocationAdapter;
import org.bukkit.Bukkit;
import org.bukkit.World;
public class WorldSettingsImpl implements IWorldSettings
{
private String worldName;
private XYZLocation spawnLocation;
@Override
public World world()
{
return Bukkit.getWorld(worldName);
}
@Override
public XYZLocation spawnLocation()
{
return spawnLocation;
}
public void world(World world)
{
this.worldName = world.getName();
}
@Override
public void spawnLocation(XYZLocation location)
{
this.spawnLocation = location;
}
public String toJSON()
{
return new GsonBuilder().setPrettyPrinting()
.registerTypeAdapter(XYZLocation.class, new XYZLocationAdapter())
.create()
.toJson(this);
}
public static WorldSettingsImpl fromJSON(String string)
{
return new GsonBuilder()
.registerTypeAdapter(XYZLocation.class, new XYZLocationAdapter())
.create()
.fromJson(string, WorldSettingsImpl.class);
}
}

View File

@ -5,4 +5,9 @@ storage:
options: options:
# Enable/Disable Sunburst's chat listening # Enable/Disable Sunburst's chat listening
chat: false chat: true
# If the player should be teleported to the world spawn on join
auto-spawn: true
# If set, the player will spawn in this world automatically at its set spawn location, and if the world
# does not exist, they will spawn at the world they're in's spawn point
global-spawn-world: "flatlands"

View File

@ -46,4 +46,6 @@ messageSent: "<red><bold>ME <white><!bold>---> <red><bold>{1}<white><!bold>: {2}
messengerNotFound: "<red>You have not messaged anyone!" messengerNotFound: "<red>You have not messaged anyone!"
# 0 - Toggled on/off # 0 - Toggled on/off
godModeToggle: "<gold>God mode has been turned {0}" godModeToggle: "<gold>God mode has been turned {0}"
spawnSet: "<green>This world's spawn location has been set!"

View File

@ -8,5 +8,5 @@ pluginManagement {
rootProject.name = "sunburst" rootProject.name = "sunburst"
include(":server") include(":server")
project(":server").name = "sunburst-server" project(":server").name = "sunburst-server"
include("api") include(":api")
project(":api").name = "sunburst-api" project(":api").name = "sunburst-api"