mirror of
https://github.com/Maxlego08/zKoth.git
synced 2024-09-26 04:02:35 +02:00
🚧 Create koth selection
This commit is contained in:
parent
3c051e1588
commit
075734a6aa
86
src/fr/maxlego08/koth/KothListener.java
Normal file
86
src/fr/maxlego08/koth/KothListener.java
Normal file
@ -0,0 +1,86 @@
|
||||
package fr.maxlego08.koth;
|
||||
|
||||
import fr.maxlego08.koth.board.Board;
|
||||
import fr.maxlego08.koth.board.ColorBoard;
|
||||
import fr.maxlego08.koth.board.EmptyBoard;
|
||||
import fr.maxlego08.koth.listener.ListenerAdapter;
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.utils.nms.NMSUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Shulker;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class KothListener extends ListenerAdapter {
|
||||
|
||||
private final KothPlugin plugin;
|
||||
private final KothManager manager;
|
||||
private final Board board = NMSUtils.isHexColor() ? new ColorBoard() : new EmptyBoard();
|
||||
|
||||
public KothListener(KothPlugin plugin, KothManager manager) {
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInteract(PlayerInteractEvent event, Player player) {
|
||||
|
||||
ItemStack itemStack = player.getItemInHand();
|
||||
|
||||
if (itemStack != null && event.getClickedBlock() != null && same(itemStack, Message.AXE_NAME.getMessage())) {
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
if (NMSUtils.isTwoHand() && event.getHand() == EquipmentSlot.OFF_HAND) return;
|
||||
|
||||
Optional<Selection> optional = this.manager.getSelection(player.getUniqueId());
|
||||
Selection selection = null;
|
||||
|
||||
if (!optional.isPresent()) {
|
||||
selection = new Selection();
|
||||
this.manager.createSelection(player.getUniqueId(), selection);
|
||||
} else {
|
||||
selection = optional.get();
|
||||
}
|
||||
|
||||
Location location = event.getClickedBlock().getLocation();
|
||||
org.bukkit.event.block.Action action = event.getAction();
|
||||
|
||||
LivingEntity entity = null;
|
||||
|
||||
if (NMSUtils.isHexColor()) {
|
||||
|
||||
Shulker shulker = location.getWorld().spawn(location, Shulker.class);
|
||||
shulker.setInvulnerable(true);
|
||||
shulker.setAI(false);
|
||||
shulker.addPotionEffect(new PotionEffect(PotionEffectType.GLOWING, 99999, 1, false, false));
|
||||
shulker.setInvisible(true);
|
||||
shulker.setCollidable(false);
|
||||
|
||||
entity = shulker;
|
||||
|
||||
Bukkit.getScheduler().runTaskLater(this.plugin, shulker::remove, 20 * 60);
|
||||
}
|
||||
|
||||
selection.action(action, location, entity);
|
||||
|
||||
this.board.addEntity(selection.isCorrect(), selection.getLeftEntity());
|
||||
this.board.addEntity(selection.isCorrect(), selection.getRightEntity());
|
||||
|
||||
Message message = action.equals(org.bukkit.event.block.Action.LEFT_CLICK_BLOCK) ? Message.AXE_POS1 : Message.AXE_POS2;
|
||||
message(player, message, "%x%", String.valueOf(location.getBlockX()), "%y%", String.valueOf(location.getBlockY()), "%z%", String.valueOf(location.getBlockZ()), "%world%", location.getWorld().getName());
|
||||
|
||||
if (selection.isValid()) {
|
||||
message(player, selection.isCorrect() ? Message.AXE_VALID : Message.AXE_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
src/fr/maxlego08/koth/KothManager.java
Normal file
52
src/fr/maxlego08/koth/KothManager.java
Normal file
@ -0,0 +1,52 @@
|
||||
package fr.maxlego08.koth;
|
||||
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import fr.maxlego08.koth.zcore.utils.builder.ItemBuilder;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Persist;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Savable;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class KothManager extends ZUtils implements Savable {
|
||||
|
||||
private final Map<UUID, Selection> selections = new HashMap<>();
|
||||
private final KothPlugin plugin;
|
||||
private final File folder;
|
||||
|
||||
public KothManager(KothPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.folder = new File(plugin.getDataFolder(), "koths");
|
||||
if (!this.folder.exists()) this.folder.mkdir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Persist persist) {
|
||||
this.selections.values().forEach(Selection::clear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Persist persist) {
|
||||
|
||||
}
|
||||
|
||||
public Optional<Selection> getSelection(UUID uuid) {
|
||||
return Optional.ofNullable(this.selections.getOrDefault(uuid, null));
|
||||
}
|
||||
|
||||
public ItemStack getKothAxe() {
|
||||
ItemBuilder builder = new ItemBuilder(Material.STONE_AXE, Message.AXE_NAME.getMessage());
|
||||
Message.AXE_DESCRIPTION.getMessages().forEach(builder::addLine);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void createSelection(UUID uniqueId, Selection selection) {
|
||||
this.selections.put(uniqueId, selection);
|
||||
}
|
||||
}
|
@ -13,6 +13,8 @@ import fr.maxlego08.koth.zcore.ZPlugin;
|
||||
*/
|
||||
public class KothPlugin extends ZPlugin {
|
||||
|
||||
private KothManager kothManager;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
@ -21,11 +23,16 @@ public class KothPlugin extends ZPlugin {
|
||||
|
||||
this.preEnable();
|
||||
|
||||
this.kothManager = new KothManager(this);
|
||||
|
||||
this.registerCommand("zkoth", new CommandKoth(this), "koth");
|
||||
|
||||
this.saveDefaultConfig();
|
||||
// this.addSave(Config.getInstance());
|
||||
this.addSave(new MessageLoader(this));
|
||||
this.addSave(this.kothManager);
|
||||
|
||||
this.addListener(new KothListener(this, this.kothManager));
|
||||
|
||||
this.loadFiles();
|
||||
|
||||
@ -42,4 +49,7 @@ public class KothPlugin extends ZPlugin {
|
||||
this.postDisable();
|
||||
}
|
||||
|
||||
public KothManager getKothManager() {
|
||||
return kothManager;
|
||||
}
|
||||
}
|
||||
|
86
src/fr/maxlego08/koth/Selection.java
Normal file
86
src/fr/maxlego08/koth/Selection.java
Normal file
@ -0,0 +1,86 @@
|
||||
package fr.maxlego08.koth;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.block.Action;
|
||||
|
||||
public class Selection {
|
||||
|
||||
private Location rightLocation;
|
||||
private Location leftLocation;
|
||||
private LivingEntity rightEntity;
|
||||
private LivingEntity leftEntity;
|
||||
|
||||
public Location getRightLocation() {
|
||||
return this.rightLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rightLocation the rightLocation to set
|
||||
*/
|
||||
private void setRightLocation(Location rightLocation) {
|
||||
this.rightLocation = rightLocation;
|
||||
}
|
||||
|
||||
public Location getLeftLocation() {
|
||||
return this.leftLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leftLocation the leftLocation to set
|
||||
*/
|
||||
private void setLeftLocation(Location leftLocation) {
|
||||
this.leftLocation = leftLocation;
|
||||
}
|
||||
|
||||
public void action(Action action, Location location, LivingEntity livingEntity) {
|
||||
switch (action) {
|
||||
case LEFT_CLICK_BLOCK:
|
||||
this.setLeftLocation(location);
|
||||
if (this.leftEntity != null && this.leftEntity.isValid()) {
|
||||
this.leftEntity.remove();
|
||||
}
|
||||
this.leftEntity = livingEntity;
|
||||
break;
|
||||
case RIGHT_CLICK_BLOCK:
|
||||
this.setRightLocation(location);
|
||||
if (this.rightEntity != null && this.rightEntity.isValid()) {
|
||||
this.rightEntity.remove();
|
||||
}
|
||||
this.rightEntity = livingEntity;
|
||||
break;
|
||||
default:
|
||||
case LEFT_CLICK_AIR:
|
||||
case PHYSICAL:
|
||||
case RIGHT_CLICK_AIR:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isValid() {
|
||||
return this.leftLocation != null && this.rightLocation != null;
|
||||
}
|
||||
|
||||
public boolean isCorrect() {
|
||||
return isValid() && Math.abs(this.leftLocation.getY() - this.rightLocation.getY()) > 1;
|
||||
}
|
||||
|
||||
public LivingEntity getRightEntity() {
|
||||
return this.rightEntity;
|
||||
}
|
||||
|
||||
public LivingEntity getLeftEntity() {
|
||||
return this.leftEntity;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if (this.rightEntity != null && this.rightEntity.isValid()) {
|
||||
this.rightEntity.remove();
|
||||
}
|
||||
if (this.leftEntity != null && this.leftEntity.isValid()) {
|
||||
this.leftEntity.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
26
src/fr/maxlego08/koth/api/Koth.java
Normal file
26
src/fr/maxlego08/koth/api/Koth.java
Normal file
@ -0,0 +1,26 @@
|
||||
package fr.maxlego08.koth.api;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.Cuboid;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Koth {
|
||||
|
||||
String getName();
|
||||
|
||||
Location getMinLocation();
|
||||
|
||||
Location getMaxLocation();
|
||||
|
||||
Cuboid getCuboid();
|
||||
|
||||
Location getCenter();
|
||||
|
||||
List<String> getStartCommands();
|
||||
|
||||
List<String> getEndCommands();
|
||||
|
||||
void move(Location minLocation, Location maxLocation);
|
||||
|
||||
}
|
9
src/fr/maxlego08/koth/board/Board.java
Normal file
9
src/fr/maxlego08/koth/board/Board.java
Normal file
@ -0,0 +1,9 @@
|
||||
package fr.maxlego08.koth.board;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
|
||||
public interface Board {
|
||||
|
||||
void addEntity(boolean isGreen, LivingEntity entity);
|
||||
|
||||
}
|
44
src/fr/maxlego08/koth/board/ColorBoard.java
Normal file
44
src/fr/maxlego08/koth/board/ColorBoard.java
Normal file
@ -0,0 +1,44 @@
|
||||
package fr.maxlego08.koth.board;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.scoreboard.Scoreboard;
|
||||
import org.bukkit.scoreboard.Team;
|
||||
|
||||
public class ColorBoard implements Board {
|
||||
|
||||
private final Team redTeam;
|
||||
private final Team greenTeam;
|
||||
|
||||
public ColorBoard() {
|
||||
|
||||
Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard();
|
||||
this.greenTeam = board.getTeams().stream().filter(e -> e.getName().equals("zkothgreenteam")).findFirst().orElseGet(() -> board.registerNewTeam("zkothgreenteam"));
|
||||
this.greenTeam.setColor(ChatColor.GREEN);
|
||||
|
||||
this.redTeam = board.getTeams().stream().filter(e -> e.getName().equals("zkothredteam")).findFirst().orElseGet(() -> board.registerNewTeam("zkothredteam"));
|
||||
this.redTeam.setColor(ChatColor.RED);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(boolean isGreen, LivingEntity entity) {
|
||||
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String uuid = entity.getUniqueId().toString();
|
||||
|
||||
this.redTeam.removeEntry(uuid);
|
||||
this.greenTeam.removeEntry(uuid);
|
||||
|
||||
if (isGreen) {
|
||||
this.greenTeam.addEntry(uuid);
|
||||
} else {
|
||||
this.redTeam.addEntry(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
12
src/fr/maxlego08/koth/board/EmptyBoard.java
Normal file
12
src/fr/maxlego08/koth/board/EmptyBoard.java
Normal file
@ -0,0 +1,12 @@
|
||||
package fr.maxlego08.koth.board;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
|
||||
public class EmptyBoard implements Board {
|
||||
|
||||
@Override
|
||||
public void addEntity(boolean isGreen, LivingEntity entity) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import fr.maxlego08.koth.KothManager;
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.enums.Permission;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.Arguments;
|
||||
@ -22,6 +23,7 @@ import fr.maxlego08.koth.zcore.utils.commands.Tab;
|
||||
public abstract class VCommand extends Arguments {
|
||||
|
||||
protected final KothPlugin plugin;
|
||||
protected KothManager manager;
|
||||
|
||||
/**
|
||||
* Permission used for the command, if it is a null then everyone can
|
||||
@ -448,6 +450,7 @@ public abstract class VCommand extends Arguments {
|
||||
return CommandType.SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
this.manager = plugin.getKothManager();
|
||||
this.sender = commandSender;
|
||||
if (this.sender instanceof Player) {
|
||||
this.player = (Player) commandSender;
|
||||
|
@ -9,7 +9,7 @@ public class CommandKoth extends VCommand {
|
||||
|
||||
public CommandKoth(KothPlugin plugin) {
|
||||
super(plugin);
|
||||
this.setPermission(Permission.EXAMPLE_PERMISSION);
|
||||
this.setPermission(Permission.ZKOTH_USE);
|
||||
this.addSubCommand(new CommandKothReload(plugin));
|
||||
}
|
||||
|
||||
|
28
src/fr/maxlego08/koth/command/commands/CommandKothAxe.java
Normal file
28
src/fr/maxlego08/koth/command/commands/CommandKothAxe.java
Normal file
@ -0,0 +1,28 @@
|
||||
package fr.maxlego08.koth.command.commands;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.command.VCommand;
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.enums.Permission;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.CommandType;
|
||||
|
||||
public class CommandKothAxe extends VCommand {
|
||||
|
||||
public CommandKothAxe(KothPlugin plugin) {
|
||||
super(plugin);
|
||||
this.setPermission(Permission.ZKOTH_AXE);
|
||||
this.addSubCommand("axe");
|
||||
this.setDescription(Message.DESCRIPTION_AXE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommandType perform(KothPlugin plugin) {
|
||||
|
||||
plugin.reloadConfig();
|
||||
plugin.reloadFiles();
|
||||
message(sender, Message.RELOAD);
|
||||
|
||||
return CommandType.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
@ -5,12 +5,13 @@ import fr.maxlego08.koth.command.VCommand;
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.enums.Permission;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.CommandType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class CommandKothReload extends VCommand {
|
||||
|
||||
public CommandKothReload(KothPlugin plugin) {
|
||||
super(plugin);
|
||||
this.setPermission(Permission.EXAMPLE_PERMISSION_RELOAD);
|
||||
this.setPermission(Permission.ZKOTH_RELOAD);
|
||||
this.addSubCommand("reload", "rl");
|
||||
this.setDescription(Message.DESCRIPTION_RELOAD);
|
||||
}
|
||||
@ -18,9 +19,9 @@ public class CommandKothReload extends VCommand {
|
||||
@Override
|
||||
protected CommandType perform(KothPlugin plugin) {
|
||||
|
||||
plugin.reloadConfig();
|
||||
plugin.reloadFiles();
|
||||
message(sender, Message.RELOAD);
|
||||
ItemStack itemStack = this.manager.getKothAxe();
|
||||
this.player.getInventory().addItem(itemStack);
|
||||
message(this.sender, Message.AXE_RECEIVE);
|
||||
|
||||
return CommandType.SUCCESS;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
@ -76,7 +77,7 @@ public class AdapterListener extends ZUtils implements Listener {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onEntityDeath(event, event.getEntity()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onInteract(event, event.getPlayer()));
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import java.util.Map;
|
||||
|
||||
public enum Message {
|
||||
|
||||
PREFIX("§8(§6Template§8) "),
|
||||
PREFIX("§8(§6zKoth§8) "),
|
||||
|
||||
TELEPORT_MOVE("§cYou must not move!"),
|
||||
TELEPORT_MESSAGE("§7Teleportation in §3%second% §7seconds!"),
|
||||
@ -44,9 +44,26 @@ public enum Message {
|
||||
RELOAD("§aYou have just reloaded the configuration files."),
|
||||
|
||||
DESCRIPTION_RELOAD("Reload configuration files"),
|
||||
DESCRIPTION_AXE("Getting the selection axe"),
|
||||
|
||||
AXE_RECEIVE("§7You have just received the axe for zone selection."),
|
||||
AXE_NAME("§6✤ §7zKoth axe §6✤"),
|
||||
AXE_DESCRIPTION("§8§m-+------------------------------+-", "",
|
||||
"",
|
||||
"§f§l» §7Allows you to select a zone to create a koth",
|
||||
" §7§oYou must select an area with the right click",
|
||||
" §7§oand left then do the command §b/koth create §8<§aname§8>",
|
||||
"",
|
||||
"§8§m-+------------------------------+-"),
|
||||
|
||||
AXE_POS1("§7You have just put the first position in §f%world%§7, §f%x%§7, §f%y%§7, §f%z%§7."),
|
||||
AXE_POS2("§7You have just put the second position in §f%world%§7, §f%x%§7, §f%y%§7, §f%z%§7."),
|
||||
AXE_ERROR("§cYour selection is invalid, you must have at least 2 blocks of height."),
|
||||
AXE_VALID("§aYour selection is valid, you can create a koth with the command §f/koth create <name>§a."),
|
||||
|
||||
;
|
||||
|
||||
|
||||
private List<String> messages;
|
||||
private String message;
|
||||
private Map<String, Object> titles = new HashMap<>();
|
||||
|
@ -1,9 +1,10 @@
|
||||
package fr.maxlego08.koth.zcore.enums;
|
||||
|
||||
public enum Permission {
|
||||
|
||||
EXAMPLE_PERMISSION,
|
||||
EXAMPLE_PERMISSION_RELOAD,
|
||||
|
||||
ZKOTH_USE,
|
||||
ZKOTH_RELOAD,
|
||||
ZKOTH_AXE,
|
||||
|
||||
;
|
||||
|
||||
|
@ -6,6 +6,10 @@ public class NMSUtils {
|
||||
|
||||
public static double version = getNMSVersion();
|
||||
|
||||
public static boolean isTwoHand() {
|
||||
return !(version == 1.7 || version == 1.8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minecraft serveur version
|
||||
*
|
||||
|
@ -150,6 +150,10 @@ public enum NmsVersion {
|
||||
return version != 1880;
|
||||
}
|
||||
|
||||
public boolean isTwoHand() {
|
||||
return version >= 1900;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version number associated with the enumeration.
|
||||
*
|
||||
|
19
src/main/resources/config.yml
Normal file
19
src/main/resources/config.yml
Normal file
@ -0,0 +1,19 @@
|
||||
#########################################################################################################
|
||||
#
|
||||
# ███████╗██╗░░██╗░█████╗░████████╗██╗░░██╗
|
||||
# ╚════██║██║░██╔╝██╔══██╗╚══██╔══╝██║░░██║
|
||||
# ░░███╔═╝█████═╝░██║░░██║░░░██║░░░███████║
|
||||
# ██╔══╝░░██╔═██╗░██║░░██║░░░██║░░░██╔══██║
|
||||
# ███████╗██║░╚██╗╚█████╔╝░░░██║░░░██║░░██║
|
||||
# ╚══════╝╚═╝░░╚═╝░╚════╝░░░░╚═╝░░░╚═╝░░╚═╝
|
||||
#
|
||||
# Commands:
|
||||
# /zkoth - zkoth.use - Displays the list of commands
|
||||
# /zkoth reload - zkoth.reload - Reload configuration files
|
||||
# /zkoth axe - zkoth.axe - Getting the selection axe
|
||||
#
|
||||
# Placeholders:
|
||||
#
|
||||
#
|
||||
#
|
||||
#########################################################################################################
|
Loading…
Reference in New Issue
Block a user