mirror of
https://github.com/GeorgH93/Minepacks.git
synced 2025-01-31 23:11:30 +01:00
Folia Support
This commit is contained in:
parent
a05bcc8f29
commit
0351c37bbe
@ -48,6 +48,13 @@
|
||||
<artifactId>PluginLib</artifactId>
|
||||
<version>${pcgfPluginLibVersion}</version>
|
||||
</dependency>
|
||||
<!-- FoliaLib -->
|
||||
<dependency>
|
||||
<groupId>com.github.technicallycoded</groupId>
|
||||
<artifactId>FoliaLib</artifactId>
|
||||
<version>0.4.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Tests -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
@ -143,6 +150,7 @@
|
||||
<include>at.pcgamingfreaks:Minepacks-API</include>
|
||||
<include>at.pcgamingfreaks:Minepacks-MagicValues</include>
|
||||
<include>at.pcgamingfreaks:PluginLib</include>
|
||||
<include>com.github.technicallycoded:FoliaLib</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<relocations>
|
||||
@ -150,6 +158,10 @@
|
||||
<pattern>at.pcgf.libs</pattern>
|
||||
<shadedPattern>at.pcgamingfreaks.MinepacksStandalone.libs</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.tcoded.folialib</pattern>
|
||||
<shadedPattern>at.pcgamingfreaks.MinepacksStandalone.libs.folialib</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>at.pcgamingfreaks.Minepacks</pattern>
|
||||
<shadedPattern>at.pcgamingfreaks.MinepacksStandalone</shadedPattern>
|
||||
|
@ -7,6 +7,7 @@ version: "${pluginVersion}"
|
||||
api-version: "1.13"
|
||||
depend: [${dependencies}]
|
||||
softdepend: [MVdWPlaceholderAPI, PlaceholderAPI ${soft-dependencies}]
|
||||
folia-supported: true
|
||||
|
||||
permissions:
|
||||
backpack.*:
|
||||
|
@ -104,14 +104,16 @@ public Backpack(final OfflinePlayer owner, ItemStack[] backpack, final int ID)
|
||||
Minepacks.getInstance().getLogger().warning(owner.getName() + "'s backpack has to many items.");
|
||||
if(owner.isOnline())
|
||||
{
|
||||
Bukkit.getScheduler().runTask(Minepacks.getInstance(), () -> {
|
||||
Minepacks.getScheduler().runNextTick(task -> {
|
||||
if(owner.isOnline())
|
||||
{
|
||||
Player player = owner.getPlayer();
|
||||
assert player != null;
|
||||
Minepacks.getScheduler().runAtEntity(player, task1 -> {
|
||||
Map<Integer, ItemStack> left = player.getInventory().addItem(toMuch.toArray(new ItemStack[0]));
|
||||
left.forEach((id, stack) -> player.getWorld().dropItemNaturally(player.getLocation(), stack));
|
||||
this.setChanged();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package at.pcgamingfreaks.Minepacks.Bukkit;
|
||||
|
||||
import com.tcoded.folialib.impl.PlatformScheduler;
|
||||
import com.tcoded.folialib.wrapper.task.WrappedTask;
|
||||
|
||||
public abstract class CancellableRunnable {
|
||||
protected WrappedTask task = null;
|
||||
|
||||
public abstract void run();
|
||||
public abstract void schedule();
|
||||
|
||||
public void cancel() {
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
protected PlatformScheduler getScheduler() {
|
||||
return Minepacks.getScheduler();
|
||||
}
|
||||
}
|
@ -24,14 +24,13 @@
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class CooldownManager extends BukkitRunnable implements Listener
|
||||
public class CooldownManager extends CancellableRunnable implements Listener
|
||||
{
|
||||
private final Minepacks plugin;
|
||||
private final Map<UUID, Long> cooldowns = new HashMap<>();
|
||||
@ -47,8 +46,6 @@ public CooldownManager(Minepacks plugin)
|
||||
addOnJoin = plugin.getConfiguration().isCommandCooldownAddOnJoinEnabled();
|
||||
clearOnLeave = plugin.getConfiguration().isCommandCooldownClearOnLeaveEnabled();
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
|
||||
runTaskTimer(plugin, plugin.getConfiguration().getCommandCooldownCleanupInterval(), plugin.getConfiguration().getCommandCooldownCleanupInterval());
|
||||
}
|
||||
|
||||
public void close()
|
||||
@ -109,4 +106,9 @@ public void run()
|
||||
{
|
||||
cooldowns.entrySet().removeIf(entry -> entry.getValue() < System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void schedule() {
|
||||
task = getScheduler().runTimer(this::run, plugin.getConfiguration().getCommandCooldownCleanupInterval(), plugin.getConfiguration().getCommandCooldownCleanupInterval());
|
||||
}
|
||||
}
|
@ -63,7 +63,7 @@ public void migrateDB(final String targetDatabaseType, final MigrationCallback c
|
||||
}
|
||||
//endregion
|
||||
//region Migrate data
|
||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
Minepacks.getScheduler().runAsync(task -> {
|
||||
MigrationResult migrationResult = null;
|
||||
try
|
||||
{
|
||||
@ -80,7 +80,7 @@ public void migrateDB(final String targetDatabaseType, final MigrationCallback c
|
||||
|
||||
//region Start the plugin again
|
||||
final MigrationResult migrationResultFinal = migrationResult;
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
Minepacks.getScheduler().runNextTick(task1 -> {
|
||||
db.close();
|
||||
// No need to reload the config
|
||||
try
|
||||
|
@ -219,7 +219,7 @@ public void saveBackpack(final Backpack backpack)
|
||||
{
|
||||
final int newID = rs.getInt(fieldPlayerID);
|
||||
DBTools.runStatement(connection, queryInsertBp, newID, data, usedSerializer);
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> backpack.setOwnerDatabaseId(newID));
|
||||
Minepacks.getScheduler().runNextTick(task -> backpack.setOwnerDatabaseId(newID));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -240,13 +240,13 @@ public void saveBackpack(final Backpack backpack)
|
||||
writeBackup(name, nameOrUUID, usedSerializer, data);
|
||||
}
|
||||
};
|
||||
if(asyncSave) Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable); else runnable.run();
|
||||
if(asyncSave) Minepacks.getScheduler().runAsync(task -> runnable.run()); else runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadBackpack(final OfflinePlayer player, final Callback<Backpack> callback)
|
||||
{
|
||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
Minepacks.getScheduler().runAsync(task -> {
|
||||
try(Connection conn = getConnection(); PreparedStatement ps = conn.prepareStatement(queryGetBP))
|
||||
{
|
||||
final String playerUUID = getPlayerFormattedUUID(player);
|
||||
@ -275,7 +275,7 @@ protected void loadBackpack(final OfflinePlayer player, final Callback<Backpack>
|
||||
writeBackup(player.getName(), playerUUID, version, data);
|
||||
}
|
||||
final Backpack backpack = (its != null) ? new Backpack(player, its, bpID) : null;
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
Minepacks.getScheduler().runNextTick(task1 -> {
|
||||
if(backpack != null)
|
||||
{
|
||||
callback.onResult(backpack);
|
||||
@ -289,7 +289,7 @@ protected void loadBackpack(final OfflinePlayer player, final Callback<Backpack>
|
||||
catch(SQLException e)
|
||||
{
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to load backpack! Error: {0}", e.getMessage());
|
||||
plugin.getServer().getScheduler().runTask(plugin, callback::onFail);
|
||||
Minepacks.getScheduler().runNextTick(task1 -> callback.onFail());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -304,20 +304,20 @@ public void syncCooldown(Player player, long cooldownTime)
|
||||
@Override
|
||||
public void getCooldown(final Player player, final Callback<Long> callback)
|
||||
{
|
||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
Minepacks.getScheduler().runAsync(asyncTask -> {
|
||||
try(Connection conn = getConnection(); PreparedStatement ps = conn.prepareStatement(queryGetCooldown))
|
||||
{
|
||||
ps.setString(1, getPlayerFormattedUUID(player));
|
||||
try(ResultSet rs = ps.executeQuery())
|
||||
{
|
||||
final long time = (rs.next()) ? rs.getTimestamp(fieldCdTime).getTime() : 0;
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> callback.onResult(time));
|
||||
Minepacks.getScheduler().runNextTick(task -> callback.onResult(time));
|
||||
}
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to load cooldown! Error: {0}", e.getMessage());
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> callback.onResult(0L));
|
||||
Minepacks.getScheduler().runNextTick(task -> callback.onResult(0L));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
import at.pcgamingfreaks.Database.DBTools;
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
|
||||
import at.pcgamingfreaks.Version;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -124,7 +123,7 @@ protected void checkDB()
|
||||
@Override
|
||||
public void updatePlayer(final Player player)
|
||||
{
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
Minepacks.getScheduler().runAsync(task -> {
|
||||
runStatement(queryUpdatePlayerAdd, player.getName(), getPlayerFormattedUUID(player));
|
||||
runStatement("UPDATE `" + tablePlayers + "` SET `" + fieldPlayerName + "`=? WHERE `" + fieldPlayerUUID + "`=?;", player.getName(), getPlayerFormattedUUID(player));
|
||||
});
|
||||
|
@ -20,16 +20,16 @@
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Backpack;
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Database;
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
|
||||
import org.bukkit.Bukkit;
|
||||
import com.tcoded.folialib.wrapper.task.WrappedTask;
|
||||
|
||||
public class Interval extends UnCacheStrategy implements Runnable
|
||||
{
|
||||
private final int taskID;
|
||||
private final WrappedTask task;
|
||||
|
||||
public Interval(Database cache)
|
||||
{
|
||||
super(cache);
|
||||
taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(Minepacks.getInstance(), this, Minepacks.getInstance().getConfiguration().getUnCacheDelay(), Minepacks.getInstance().getConfiguration().getUnCacheInterval());
|
||||
task = Minepacks.getScheduler().runTimer(this, Minepacks.getInstance().getConfiguration().getUnCacheDelay(), Minepacks.getInstance().getConfiguration().getUnCacheInterval());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -47,7 +47,7 @@ public void run()
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
Bukkit.getScheduler().cancelTask(taskID);
|
||||
Minepacks.getScheduler().cancelTask(task);
|
||||
super.close();
|
||||
}
|
||||
}
|
@ -21,19 +21,19 @@
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Database;
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import com.tcoded.folialib.wrapper.task.WrappedTask;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
public class IntervalChecked extends UnCacheStrategy implements Runnable
|
||||
{
|
||||
private final long delay;
|
||||
private final int taskID;
|
||||
private final WrappedTask task;
|
||||
|
||||
public IntervalChecked(Database cache)
|
||||
{
|
||||
super(cache);
|
||||
long delayTicks = Minepacks.getInstance().getConfiguration().getUnCacheDelay();
|
||||
taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(Minepacks.getInstance(), this, delayTicks, Minepacks.getInstance().getConfiguration().getUnCacheInterval());
|
||||
task = Minepacks.getScheduler().runTimer(this, delayTicks, Minepacks.getInstance().getConfiguration().getUnCacheInterval());
|
||||
this.delay = delayTicks * 50L;
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ public void run()
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
Bukkit.getScheduler().cancelTask(taskID);
|
||||
Minepacks.getScheduler().cancelTask(task);
|
||||
super.close();
|
||||
}
|
||||
}
|
@ -26,7 +26,6 @@
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
public class OnDisconnectDelayed extends UnCacheStrategy implements Listener
|
||||
{
|
||||
@ -45,21 +44,20 @@ public void playerLeaveEvent(PlayerQuitEvent event)
|
||||
final Backpack backpack = cache.getBackpack(event.getPlayer());
|
||||
if(backpack != null) // We only uncache unmarried player.
|
||||
{
|
||||
new BukkitRunnable()
|
||||
Minepacks.getScheduler().runLater(() -> {
|
||||
if (!backpack.isOpen())
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
cache.unloadBackpack(backpack);
|
||||
} else {
|
||||
Minepacks.getScheduler().runLater(() ->
|
||||
{
|
||||
if (!backpack.isOpen())
|
||||
{
|
||||
cache.unloadBackpack(backpack);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.runTaskLater(Minepacks.getInstance(), delay);
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
}.runTaskLater(Minepacks.getInstance(), delay);
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,16 +24,12 @@
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ItemsCollector extends BukkitRunnable
|
||||
{
|
||||
public class ItemsCollector extends CancellableRunnable {
|
||||
private final Minepacks plugin;
|
||||
private final double radius;
|
||||
private final BukkitTask task;
|
||||
private final ItemFilter itemFilter;
|
||||
|
||||
/**
|
||||
@ -59,8 +55,7 @@ public ItemsCollector(Minepacks plugin)
|
||||
this.isToggleable = plugin.getConfiguration().isFullInvToggleAllowed();
|
||||
this.enabledOnJoin = plugin.getConfiguration().isFullInvEnabledOnJoin();
|
||||
this.toggleList = new HashSet<>();
|
||||
|
||||
task = runTaskTimer(plugin, plugin.getConfiguration().getFullInvCheckInterval(), plugin.getConfiguration().getFullInvCheckInterval());
|
||||
schedule();
|
||||
itemFilter = plugin.getItemFilter();
|
||||
}
|
||||
|
||||
@ -81,14 +76,15 @@ public void run()
|
||||
{
|
||||
for(Player player : Bukkit.getServer().getOnlinePlayers())
|
||||
{
|
||||
if (!canUseAutoPickup(player)) continue;
|
||||
Minepacks.getScheduler().runAtEntity(player, entityTask -> {
|
||||
if (!canUseAutoPickup(player)) return;
|
||||
|
||||
// Inventory is full
|
||||
if (player.getInventory().firstEmpty() != -1) continue;
|
||||
if (player.getInventory().firstEmpty() != -1) return;
|
||||
|
||||
// Only check loaded backpacks (loading them would take too much time for a repeating task, the backpack will be loaded async soon enough)
|
||||
Backpack backpack = (Backpack) plugin.getBackpackCachedOnly(player);
|
||||
if (backpack == null) continue;
|
||||
if (backpack == null) return;
|
||||
|
||||
List<Entity> entities = player.getNearbyEntities(radius, radius, radius);
|
||||
for(Entity entity : entities)
|
||||
@ -119,12 +115,17 @@ public void run()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
task.cancel();
|
||||
@Override
|
||||
public void schedule() {
|
||||
task = getScheduler().runTimer(this::run, plugin.getConfiguration().getFullInvCheckInterval(), plugin.getConfiguration().getFullInvCheckInterval());
|
||||
}
|
||||
|
||||
public void close() {
|
||||
cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,6 @@
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.API.WorldBlacklistMode;
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Permissions;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -150,21 +149,22 @@ private void removeItem(Player player)
|
||||
public void onJoin(PlayerJoinEvent event)
|
||||
{
|
||||
if(plugin.isDisabled(event.getPlayer()) != WorldBlacklistMode.None) return;
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> addItem(event.getPlayer()), 2L);
|
||||
Minepacks.getScheduler().runAtEntityLater(event.getPlayer(), task -> addItem(event.getPlayer()), 2L);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onSpawn(PlayerRespawnEvent event)
|
||||
{
|
||||
if(plugin.isDisabled(event.getPlayer()) != WorldBlacklistMode.None) return;
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> addItem(event.getPlayer()), 2L);
|
||||
Minepacks.getScheduler().runAtEntityLater(event.getPlayer(), task -> addItem(event.getPlayer()), 2L);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onWorldChange(final PlayerChangedWorldEvent event)
|
||||
{
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
Minepacks.getScheduler().runAtEntityLater(player, () -> {
|
||||
if(!player.isOnline()) return;
|
||||
if(player.hasPermission(Permissions.USE) && plugin.isDisabled(player) == WorldBlacklistMode.None)
|
||||
addItem(player);
|
||||
@ -271,7 +271,7 @@ public void onItemClick(InventoryClickEvent event)
|
||||
}
|
||||
else if(event.getClick() == ClickType.RIGHT || event.getClick() == ClickType.SHIFT_RIGHT)
|
||||
{
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> { player.performCommand(openCommand); });
|
||||
Minepacks.getScheduler().runAtEntity(player, task -> player.performCommand(openCommand));
|
||||
event.setCancelled(true);
|
||||
}
|
||||
else if(event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY)
|
||||
|
@ -43,6 +43,8 @@
|
||||
import at.pcgamingfreaks.Util.StringUtils;
|
||||
import at.pcgamingfreaks.Version;
|
||||
|
||||
import com.tcoded.folialib.FoliaLib;
|
||||
import com.tcoded.folialib.impl.PlatformScheduler;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
@ -65,6 +67,7 @@
|
||||
public class Minepacks extends JavaPlugin implements MinepacksPlugin, IPlugin
|
||||
{
|
||||
@Getter private static Minepacks instance = null;
|
||||
@Getter private static FoliaLib foliaLib = null;
|
||||
|
||||
private ManagedUpdater updater = null;
|
||||
private Config config;
|
||||
@ -110,6 +113,7 @@ public void onEnable()
|
||||
|
||||
updater = new ManagedUpdater(this);
|
||||
instance = this;
|
||||
foliaLib = new FoliaLib(this);
|
||||
config = new Config(this);
|
||||
updater.setChannel(config.getUpdateChannel());
|
||||
if(config.useUpdater()) updater.update();
|
||||
@ -404,6 +408,9 @@ public ItemsCollector getItemsCollector()
|
||||
return collector;
|
||||
}
|
||||
|
||||
public static PlatformScheduler getScheduler() {
|
||||
return foliaLib.getScheduler();
|
||||
}
|
||||
@Override
|
||||
public @NotNull Version getVersion()
|
||||
{
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
package at.pcgamingfreaks.Minepacks.Bukkit.SpecialInfoWorker;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
@ -40,7 +40,7 @@ public void onJoin(final PlayerJoinEvent event)
|
||||
{
|
||||
if(event.getPlayer().hasPermission(permission))
|
||||
{
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||
Minepacks.getScheduler().runAtEntityLater(event.getPlayer(), () -> {
|
||||
if(event.getPlayer().isOnline())
|
||||
{
|
||||
sendMessage(event.getPlayer());
|
||||
|
Loading…
Reference in New Issue
Block a user