probably riddled with bugs but i think it works
Some checks are pending
Build plugin / build (push) Waiting to run
Some checks are pending
Build plugin / build (push) Waiting to run
This commit is contained in:
parent
3ea2b796a5
commit
dca1320275
|
@ -12,6 +12,7 @@ import dev.rollczi.litecommands.annotations.permission.Permission;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import xyz.twovb.sgm.SGM;
|
import xyz.twovb.sgm.SGM;
|
||||||
|
import xyz.twovb.sgm.games.Minigame;
|
||||||
import xyz.twovb.sgm.games.impl.TestGame;
|
import xyz.twovb.sgm.games.impl.TestGame;
|
||||||
import xyz.twovb.toolbox.api.CustomPlayer;
|
import xyz.twovb.toolbox.api.CustomPlayer;
|
||||||
import xyz.twovb.toolbox.utils.ChatUtils;
|
import xyz.twovb.toolbox.utils.ChatUtils;
|
||||||
|
@ -36,11 +37,19 @@ public class GameCommand {
|
||||||
sender.sendMessage(ChatUtils.translate(builder.toString()));
|
sender.sendMessage(ChatUtils.translate(builder.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Execute(name = "init")
|
||||||
|
@Permission("sgm.games.init")
|
||||||
|
void init(@Context Player player, @Arg("name") String name) {
|
||||||
|
CustomPlayer cPlayer = new CustomPlayer(player);
|
||||||
|
SGM.getInstance().getGameManager().initGame(new TestGame(), player, name);
|
||||||
|
}
|
||||||
|
|
||||||
@Execute(name = "start")
|
@Execute(name = "start")
|
||||||
@Permission("sgm.games.start")
|
@Permission("sgm.games.start")
|
||||||
void game(@Context Player player, @Arg("name") String name) {
|
void start(@Context Player player) {
|
||||||
CustomPlayer cPlayer = new CustomPlayer(player);
|
CustomPlayer cPlayer = new CustomPlayer(player);
|
||||||
SGM.getInstance().getGameManager().createGame(new TestGame(), player, name);
|
Minigame game = SGM.getInstance().getGameManager().findGame(player);
|
||||||
|
game.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Execute(name = "join")
|
@Execute(name = "join")
|
||||||
|
|
|
@ -18,6 +18,7 @@ import xyz.twovb.toolbox.api.CustomPlayer;
|
||||||
import xyz.twovb.toolbox.managers.PlaceholderManager;
|
import xyz.twovb.toolbox.managers.PlaceholderManager;
|
||||||
import xyz.twovb.toolbox.utils.ChatUtils;
|
import xyz.twovb.toolbox.utils.ChatUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -38,7 +39,7 @@ public class LevelCommand {
|
||||||
@Permission("sgm.levels.create")
|
@Permission("sgm.levels.create")
|
||||||
void create(@Context CommandSender sender, @Arg("game") String game, @Arg("name") Optional<String> LevelName) {
|
void create(@Context CommandSender sender, @Arg("game") String game, @Arg("name") Optional<String> LevelName) {
|
||||||
String name = LevelName.orElse(UUID.randomUUID().toString());
|
String name = LevelName.orElse(UUID.randomUUID().toString());
|
||||||
LevelManager.CreationResult result = SGM.getInstance().getLevelManager().createLevel(name, game);
|
LevelManager.LevelResult result = SGM.getInstance().getLevelManager().createLevel(name, game);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
sender.sendMessage(ChatUtils.translate(PlaceholderManager.setPlaceholders(SGM.getInstance().getMessages().getString("sgm.level.new"), sender).replace("%level%", name)));
|
sender.sendMessage(ChatUtils.translate(PlaceholderManager.setPlaceholders(SGM.getInstance().getMessages().getString("sgm.level.new"), sender).replace("%level%", name)));
|
||||||
|
@ -65,4 +66,15 @@ public class LevelCommand {
|
||||||
cPlayer.sendMessage("<red>tele&aport");
|
cPlayer.sendMessage("<red>tele&aport");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Execute(name = "export")
|
||||||
|
@Permission("sgm.levels.export")
|
||||||
|
void export(@Context Player player, @Arg("name") String name) {
|
||||||
|
CustomPlayer cPlayer = new CustomPlayer(player);
|
||||||
|
try {
|
||||||
|
SGM.getInstance().getLevelManager().exportLevel(name);
|
||||||
|
} catch (IOException e) {
|
||||||
|
SGM.getInstance().getCLogger().error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,9 @@ package xyz.twovb.sgm.games;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.NamespacedKey;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.WorldCreator;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import xyz.twovb.sgm.SGM;
|
import xyz.twovb.sgm.SGM;
|
||||||
import xyz.twovb.sgm.levels.LevelManager;
|
|
||||||
import xyz.twovb.toolbox.managers.PlaceholderManager;
|
import xyz.twovb.toolbox.managers.PlaceholderManager;
|
||||||
import xyz.twovb.toolbox.utils.ChatUtils;
|
import xyz.twovb.toolbox.utils.ChatUtils;
|
||||||
|
|
||||||
|
@ -32,7 +28,7 @@ public class GameManager {
|
||||||
return activeGames.get(gameId);
|
return activeGames.get(gameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Minigame findGame(Player player) {
|
public Minigame findGame(Player player) {
|
||||||
for (Minigame game : activeGames.values()) {
|
for (Minigame game : activeGames.values()) {
|
||||||
if (game.getPlayers().contains(player)) {
|
if (game.getPlayers().contains(player)) {
|
||||||
return game;
|
return game;
|
||||||
|
@ -50,7 +46,7 @@ public class GameManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createGame(Minigame game, CommandSender owner, String level) {
|
public void initGame(Minigame game, CommandSender owner, String level) {
|
||||||
// World world = createGameWorld(level);
|
// World world = createGameWorld(level);
|
||||||
try {
|
try {
|
||||||
game.init(owner, level);
|
game.init(owner, level);
|
||||||
|
|
|
@ -5,7 +5,6 @@ package xyz.twovb.sgm.games;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
|
@ -53,23 +52,27 @@ public interface Minigame extends Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
default World createGameWorld(String name, UUID id) throws IOException {
|
default World createGameWorld(String name, UUID id) throws IOException {
|
||||||
File levelDir = new File(LevelManager.path + name);
|
File mapDir = new File(LevelManager.mapPath + name);
|
||||||
// if (Bukkit.getWorld(new NamespacedKey(SGM.getInstance(), "level_" + name)) != null) {
|
|
||||||
// World levelWorld = Bukkit.getWorld(new NamespacedKey(SGM.getInstance(), "level_" + name));
|
|
||||||
// if (levelWorld != null && levelWorld.getPlayerCount() == 0 && !Bukkit.isTickingWorlds()) {
|
|
||||||
// Bukkit.getServer().unloadWorld(levelWorld, true);
|
|
||||||
// } else {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
String tempName = name + "_" + id;
|
String tempName = name + "_" + id;
|
||||||
File tempDir = new File(LevelManager.gamePath + tempName);
|
File tempDir = new File(LevelManager.gamePath + tempName);
|
||||||
FileUtils.copyDirectory(levelDir, tempDir);
|
if (tempDir.mkdirs()) {
|
||||||
WorldCreator wc = new WorldCreator(LevelManager.gamePath + name, new NamespacedKey(SGM.getInstance(), name + "-" + UUID.randomUUID()));
|
FileUtils.copyDirectory(mapDir, tempDir);
|
||||||
World world = wc.createWorld();
|
WorldCreator wc = new WorldCreator(LevelManager.gamePath + tempName, new NamespacedKey(SGM.getInstance(), tempName));
|
||||||
if (world == null) return null;
|
World world = wc.createWorld();
|
||||||
world.setAutoSave(false);
|
if (world == null) return null;
|
||||||
return world;
|
world.setAutoSave(false);
|
||||||
|
return world;
|
||||||
|
// FileUtils.copyFile(new File(levelDir + "/sgm.yml"), tempDir);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileUtils.copyDirectory(levelDir, tempDir);
|
||||||
|
// WorldCreator wc = new WorldCreator(LevelManager.gamePath + tempName, new NamespacedKey(SGM.getInstance(), tempName));
|
||||||
|
// World world = wc.createWorld();
|
||||||
|
// if (world == null) return null;
|
||||||
|
// world.setAutoSave(false);
|
||||||
|
// return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum GameState {
|
enum GameState {
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class TestGame implements Minigame {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void start() {
|
||||||
if (state == GameState.PRESTART) {
|
if (state == GameState.READY) {
|
||||||
state = GameState.STARTED;
|
state = GameState.STARTED;
|
||||||
sendMessageToAllPlayers("The game has started!");
|
sendMessageToAllPlayers("The game has started!");
|
||||||
for (Player player : players) {
|
for (Player player : players) {
|
||||||
|
@ -92,7 +92,7 @@ public class TestGame implements Minigame {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
void onPlayerDeath(PlayerDeathEvent event) {
|
void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
if (players.contains(player)) {
|
if (players.contains(player) && state == GameState.STARTED) {
|
||||||
sendMessageToAllPlayers(player.getName() + " was eliminated!");
|
sendMessageToAllPlayers(player.getName() + " was eliminated!");
|
||||||
event.setDeathMessage("");
|
event.setDeathMessage("");
|
||||||
removePlayer(player);
|
removePlayer(player);
|
||||||
|
|
|
@ -4,12 +4,15 @@ package xyz.twovb.sgm.levels;
|
||||||
* Created by 2vb - 4/6/2024
|
* Created by 2vb - 4/6/2024
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.yaml.snakeyaml.DumperOptions;
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
import xyz.twovb.sgm.SGM;
|
import xyz.twovb.sgm.SGM;
|
||||||
|
import xyz.twovb.toolbox.api.CustomPlayer;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
|
@ -21,21 +24,31 @@ import java.util.Map;
|
||||||
|
|
||||||
public class LevelManager {
|
public class LevelManager {
|
||||||
|
|
||||||
public static final String path = SGM.getInstance().getDataFolder().getPath() + "/levels/";
|
public static final String levelPath = SGM.getInstance().getDataFolder().getPath() + "/levels/";
|
||||||
|
|
||||||
public static final String gamePath = SGM.getInstance().getDataFolder().getPath() + "/games/";
|
public static final String gamePath = SGM.getInstance().getDataFolder().getPath() + "/games/";
|
||||||
|
|
||||||
|
public static final String mapPath = SGM.getInstance().getDataFolder().getPath() + "/maps/";
|
||||||
|
|
||||||
|
// todo: make it the actual map and not levels
|
||||||
public HashMap<String, List<String>> enabledMaps = new HashMap<>();
|
public HashMap<String, List<String>> enabledMaps = new HashMap<>();
|
||||||
|
|
||||||
private static void loadWorld(String worldName) {
|
private static void loadWorld(String worldName, LevelType type) {
|
||||||
// Check if the world is already loaded
|
// Check if the world is already loaded
|
||||||
if (Bukkit.getWorld(new NamespacedKey(SGM.getInstance(), "level_" + worldName)) != null) {
|
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.");
|
SGM.getInstance().getCLogger().log("World " + worldName + " is already loaded.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the world
|
// Load the world
|
||||||
WorldCreator wc = new WorldCreator(path + worldName, new NamespacedKey(SGM.getInstance(), "level_" + worldName));
|
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));
|
||||||
|
};
|
||||||
|
// WorldCreator wc = new WorldCreator(levelPath + worldName, new NamespacedKey(SGM.getInstance(), key));
|
||||||
World world = wc.createWorld();
|
World world = wc.createWorld();
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
SGM.getInstance().getCLogger().log("Loaded world: " + worldName);
|
SGM.getInstance().getCLogger().log("Loaded world: " + worldName);
|
||||||
|
@ -44,33 +57,8 @@ public class LevelManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CreationResult createLevel(String name, String game) {
|
|
||||||
File level = new File(path + name);
|
|
||||||
if (!SGM.getInstance().getGameManager().getRegisteredGames().contains(game.toLowerCase())) {
|
|
||||||
return CreationResult.INVALID_ARGS;
|
|
||||||
}
|
|
||||||
WorldCreator wc = new WorldCreator(path + name, new NamespacedKey(SGM.getInstance(), "level_" + name));
|
|
||||||
if (level.exists()) {
|
|
||||||
return CreationResult.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 CreationResult.UNKNOWN;
|
|
||||||
}
|
|
||||||
Location location = new Location(world, 0, 0, 0);
|
|
||||||
Block block = location.subtract(0, 2, 0).getBlock();
|
|
||||||
block.setType(Material.STONE);
|
|
||||||
world.setSpawnLocation(location);
|
|
||||||
world.setSpawnFlags(false, false);
|
|
||||||
genDataFile(level, name, game.toLowerCase());
|
|
||||||
enabledMaps.get(game).add(name);
|
|
||||||
return CreationResult.SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void genDataFile(File path, String name, String game) {
|
private static void genDataFile(File path, String name, String game) {
|
||||||
|
// probably rewriting tmr
|
||||||
// these are opposite
|
// these are opposite
|
||||||
Map<String, Object> data = new HashMap<>();
|
Map<String, Object> data = new HashMap<>();
|
||||||
data.put("name", name);
|
data.put("name", name);
|
||||||
|
@ -90,12 +78,61 @@ public class LevelManager {
|
||||||
return Bukkit.getWorld(new NamespacedKey(SGM.getInstance(), "level_" + 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());
|
||||||
|
}
|
||||||
|
if (!Bukkit.isTickingWorlds() && Bukkit.getServer().unloadWorld(world, true)) {
|
||||||
|
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);
|
||||||
|
Block block = location.subtract(0, 2, 0).getBlock();
|
||||||
|
block.setType(Material.STONE);
|
||||||
|
world.setSpawnLocation(location);
|
||||||
|
world.setSpawnFlags(false, false);
|
||||||
|
genDataFile(level, name, game.toLowerCase());
|
||||||
|
enabledMaps.get(game).add(name);
|
||||||
|
return LevelResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
public void loadLevels() {
|
public void loadLevels() {
|
||||||
for (String game : SGM.getInstance().getGameManager().getRegisteredGames()) {
|
for (String game : SGM.getInstance().getGameManager().getRegisteredGames()) {
|
||||||
enabledMaps.put(game, new ArrayList<>()); // Initialize an empty ArrayList for each game
|
enabledMaps.put(game, new ArrayList<>()); // Initialize an empty ArrayList for each game
|
||||||
}
|
}
|
||||||
// List all files (worlds) in the folder
|
// List all files (worlds) in the folder
|
||||||
File folder = new File(path);
|
File folder = new File(levelPath);
|
||||||
File[] files = folder.listFiles();
|
File[] files = folder.listFiles();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
|
@ -109,7 +146,7 @@ public class LevelManager {
|
||||||
if (enabledMaps.containsKey(game)) {
|
if (enabledMaps.containsKey(game)) {
|
||||||
enabledMaps.get(game).add(name);
|
enabledMaps.get(game).add(name);
|
||||||
// Load the world if sgm.yml exists
|
// Load the world if sgm.yml exists
|
||||||
loadWorld(file.getName());
|
loadWorld(file.getName(), LevelType.LEVEL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SGM.getInstance().getCLogger().log("Skipping directory " + file.getName() + ": sgm.yml not found.");
|
SGM.getInstance().getCLogger().log("Skipping directory " + file.getName() + ": sgm.yml not found.");
|
||||||
|
@ -119,14 +156,12 @@ public class LevelManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CreationResult {
|
public enum LevelResult {
|
||||||
SUCCESS, WORLD_EXISTS, INVALID_ARGS, UNKNOWN
|
SUCCESS, WORLD_NO_EXISTS, WORLD_EXISTS, INVALID_ARGS, UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void deleteLevel(String name) {
|
public enum LevelType {
|
||||||
// World world = Bukkit.getWorld(new NamespacedKey(SGM.getInstance(), "level_" + name));
|
GAME, MAP, LEVEL
|
||||||
// assert world != null;
|
}
|
||||||
// Bukkit.unloadWorld(world, false);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,4 +23,7 @@ sgm:
|
||||||
new: "&7A level with the name %level% has been created."
|
new: "&7A level with the name %level% has been created."
|
||||||
deleted: "&7A level with the name %level% has been deleted."
|
deleted: "&7A level with the name %level% has been deleted."
|
||||||
exists: "&7A level with the name %level% already exists."
|
exists: "&7A level with the name %level% already exists."
|
||||||
not-found: "&7Level couldn't be found!"
|
not-found: "&7Level couldn't be found!"
|
||||||
|
export:
|
||||||
|
kick: "&7You have been sent to a random world while this level is being exported."
|
||||||
|
done: "&7%level% has been exported into a map and can now be played."
|
Loading…
Reference in New Issue
Block a user