mirror of
https://gitlab.com/phoenix-dvpmt/mmocore.git
synced 2024-10-22 20:10:00 +02:00
Debug + max-bound-skills+mmocore admin skill give...
This commit is contained in:
parent
4d08a98ed2
commit
a61b9bc634
@ -849,7 +849,10 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
|
|||||||
|
|
||||||
public void setBoundSkill(int slot, ClassSkill skill) {
|
public void setBoundSkill(int slot, ClassSkill skill) {
|
||||||
Validate.notNull(skill, "Skill cannot be null");
|
Validate.notNull(skill, "Skill cannot be null");
|
||||||
if (boundSkills.size() < 6)
|
|
||||||
|
|
||||||
|
|
||||||
|
if (boundSkills.size() < getProfess().getMaxBoundSkills())
|
||||||
boundSkills.add(skill);
|
boundSkills.add(skill);
|
||||||
else
|
else
|
||||||
boundSkills.set(slot, skill);
|
boundSkills.set(slot, skill);
|
||||||
|
@ -49,7 +49,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
|
|||||||
private final int maxLevel, displayOrder;
|
private final int maxLevel, displayOrder;
|
||||||
private final ExpCurve expCurve;
|
private final ExpCurve expCurve;
|
||||||
private final ExperienceTable expTable;
|
private final ExperienceTable expTable;
|
||||||
|
private final int maxBoundSkills;
|
||||||
private final Map<String, LinearValue> stats = new HashMap<>();
|
private final Map<String, LinearValue> stats = new HashMap<>();
|
||||||
private final Map<String, ClassSkill> skills = new LinkedHashMap<>();
|
private final Map<String, ClassSkill> skills = new LinkedHashMap<>();
|
||||||
private final List<Subclass> subclasses = new ArrayList<>();
|
private final List<Subclass> subclasses = new ArrayList<>();
|
||||||
@ -100,7 +100,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
|
|||||||
? MMOCore.plugin.experience.getCurveOrThrow(
|
? MMOCore.plugin.experience.getCurveOrThrow(
|
||||||
config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-"))
|
config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-"))
|
||||||
: ExpCurve.DEFAULT;
|
: ExpCurve.DEFAULT;
|
||||||
|
maxBoundSkills = config.getInt("max-bound-skills", 6);
|
||||||
ExperienceTable expTable = null;
|
ExperienceTable expTable = null;
|
||||||
if (config.contains("exp-table"))
|
if (config.contains("exp-table"))
|
||||||
try {
|
try {
|
||||||
@ -206,7 +206,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
|
|||||||
this.icon = new ItemStack(material);
|
this.icon = new ItemStack(material);
|
||||||
setOption(ClassOption.DISPLAY, false);
|
setOption(ClassOption.DISPLAY, false);
|
||||||
setOption(ClassOption.DEFAULT, false);
|
setOption(ClassOption.DEFAULT, false);
|
||||||
|
maxBoundSkills = 6;
|
||||||
for (PlayerResource resource : PlayerResource.values())
|
for (PlayerResource resource : PlayerResource.values())
|
||||||
resourceHandlers.put(resource, new ResourceRegeneration(resource));
|
resourceHandlers.put(resource, new ResourceRegeneration(resource));
|
||||||
}
|
}
|
||||||
@ -262,6 +262,10 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
|
|||||||
return expCurve;
|
return expCurve;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMaxBoundSkills() {
|
||||||
|
return maxBoundSkills;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ExperienceTable getExperienceTable() {
|
public ExperienceTable getExperienceTable() {
|
||||||
return Objects.requireNonNull(expTable, "Class has no exp table");
|
return Objects.requireNonNull(expTable, "Class has no exp table");
|
||||||
|
@ -49,6 +49,7 @@ public class CommandVerbose {
|
|||||||
|
|
||||||
public enum CommandType {
|
public enum CommandType {
|
||||||
ATTRIBUTE,
|
ATTRIBUTE,
|
||||||
|
SKILL,
|
||||||
CLASS,
|
CLASS,
|
||||||
EXPERIENCE,
|
EXPERIENCE,
|
||||||
LEVEL,
|
LEVEL,
|
||||||
|
@ -25,7 +25,7 @@ public class AdminCommandTreeNode extends CommandTreeNode {
|
|||||||
addChild(new PointsCommandTreeNode("class", this, PlayerData::setClassPoints, PlayerData::giveClassPoints, PlayerData::getClassPoints));
|
addChild(new PointsCommandTreeNode("class", this, PlayerData::setClassPoints, PlayerData::giveClassPoints, PlayerData::getClassPoints));
|
||||||
addChild(new PointsCommandTreeNode("attribute", this, PlayerData::setAttributePoints, PlayerData::giveAttributePoints, PlayerData::getAttributePoints));
|
addChild(new PointsCommandTreeNode("attribute", this, PlayerData::setAttributePoints, PlayerData::giveAttributePoints, PlayerData::getAttributePoints));
|
||||||
addChild(new PointsCommandTreeNode("attr-realloc", this, PlayerData::setAttributeReallocationPoints, PlayerData::giveAttributeReallocationPoints, PlayerData::getAttributeReallocationPoints));
|
addChild(new PointsCommandTreeNode("attr-realloc", this, PlayerData::setAttributeReallocationPoints, PlayerData::giveAttributeReallocationPoints, PlayerData::getAttributeReallocationPoints));
|
||||||
|
addChild(new SkillCommandTreeNode(this));
|
||||||
for (PlayerResource res : PlayerResource.values())
|
for (PlayerResource res : PlayerResource.values())
|
||||||
addChild(new ResourceCommandTreeNode(res.name().toLowerCase(), this, res));
|
addChild(new ResourceCommandTreeNode(res.name().toLowerCase(), this, res));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
package net.Indyuce.mmocore.command.rpg.admin;
|
||||||
|
|
||||||
|
import io.lumine.mythic.lib.command.api.CommandTreeNode;
|
||||||
|
import io.lumine.mythic.lib.command.api.Parameter;
|
||||||
|
import net.Indyuce.mmocore.MMOCore;
|
||||||
|
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||||
|
import net.Indyuce.mmocore.command.CommandVerbose;
|
||||||
|
import net.Indyuce.mmocore.skill.ClassSkill;
|
||||||
|
import net.Indyuce.mmocore.skill.RegisteredSkill;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
|
||||||
|
public class SkillCommandTreeNode extends CommandTreeNode {
|
||||||
|
public SkillCommandTreeNode(CommandTreeNode parent) {
|
||||||
|
super(parent, "skill");
|
||||||
|
|
||||||
|
addChild(new ActionCommandTreeNode(this, "give", (old, amount) -> old + amount));
|
||||||
|
addChild(new ActionCommandTreeNode(this, "set", (old, amount) -> amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class ActionCommandTreeNode extends CommandTreeNode {
|
||||||
|
private final BiFunction<Integer, Integer, Integer> change;
|
||||||
|
|
||||||
|
public ActionCommandTreeNode(CommandTreeNode parent, String type, BiFunction<Integer, Integer, Integer> change) {
|
||||||
|
super(parent, type);
|
||||||
|
this.change = change;
|
||||||
|
addParameter(Parameter.PLAYER);
|
||||||
|
addParameter(new Parameter("<attribute>",
|
||||||
|
(explorer, list) -> MMOCore.plugin.skillManager.getAll().forEach(skill -> list.add(skill.getHandler().getId().toUpperCase()))));
|
||||||
|
addParameter(Parameter.AMOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult execute(CommandSender sender, String[] args) {
|
||||||
|
if (args.length < 6)
|
||||||
|
return CommandResult.THROW_USAGE;
|
||||||
|
|
||||||
|
Player player = Bukkit.getPlayer(args[3]);
|
||||||
|
if (player == null) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Could not find the player called " + args[3] + ".");
|
||||||
|
return CommandResult.FAILURE;
|
||||||
|
}
|
||||||
|
PlayerData playerData = PlayerData.get(player);
|
||||||
|
|
||||||
|
RegisteredSkill skill = MMOCore.plugin.skillManager.getSkill(args[4]);
|
||||||
|
if (skill == null) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Could not find the skill called " + args[4] + ".");
|
||||||
|
return CommandResult.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ClassSkill classSkill=null;
|
||||||
|
for(ClassSkill var:playerData.getProfess().getSkills()) {
|
||||||
|
if(var.getSkill().equals(skill))
|
||||||
|
classSkill=var;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(classSkill==null||classSkill.getUnlockLevel() > playerData.getLevel()) {
|
||||||
|
sender.sendMessage(ChatColor.RED+ skill.getName()+" is not unlockable for "+player.getName()+".");
|
||||||
|
return CommandResult.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int amount;
|
||||||
|
try {
|
||||||
|
amount = Integer.parseInt(args[5]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
sender.sendMessage(ChatColor.RED + args[5] + " is not a valid number.");
|
||||||
|
return CommandResult.FAILURE;
|
||||||
|
}
|
||||||
|
int value = change.apply(playerData.getSkillLevel(skill), amount);
|
||||||
|
playerData.setSkillLevel(skill, value);
|
||||||
|
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + player.getName() + ChatColor.YELLOW
|
||||||
|
+ " is now level " + ChatColor.GOLD + value + ChatColor.YELLOW + " for " + skill.getName() + ".");
|
||||||
|
return CommandResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult execute(CommandSender sender, String[] args) {
|
||||||
|
return CommandResult.THROW_USAGE;
|
||||||
|
}
|
||||||
|
}
|
@ -70,6 +70,9 @@ public class SkillList extends EditableInventory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack display(SkillViewerInventory inv, int n) {
|
public ItemStack display(SkillViewerInventory inv, int n) {
|
||||||
|
if (n >= inv.getPlayerData().getProfess().getMaxBoundSkills()) {
|
||||||
|
return new ItemStack(Material.AIR);
|
||||||
|
}
|
||||||
ItemStack item = super.display(inv, n);
|
ItemStack item = super.display(inv, n);
|
||||||
if (!inv.getPlayerData().hasSkillBound(n)) {
|
if (!inv.getPlayerData().hasSkillBound(n)) {
|
||||||
item.setType(emptyMaterial);
|
item.setType(emptyMaterial);
|
||||||
|
@ -28,7 +28,7 @@ public class ConfigManager {
|
|||||||
public ChatColor staminaFull, staminaHalf, staminaEmpty;
|
public ChatColor staminaFull, staminaHalf, staminaEmpty;
|
||||||
public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown;
|
public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown;
|
||||||
public double lootChestsChanceWeight, fishingDropsChanceWeight;
|
public double lootChestsChanceWeight, fishingDropsChanceWeight;
|
||||||
public int maxPartyLevelDifference;
|
public int maxPartyLevelDifference,maxBoundSkills;
|
||||||
|
|
||||||
private final FileConfiguration messages;
|
private final FileConfiguration messages;
|
||||||
|
|
||||||
@ -113,6 +113,7 @@ public class ConfigManager {
|
|||||||
canCreativeCast = MMOCore.plugin.getConfig().getBoolean("can-creative-cast");
|
canCreativeCast = MMOCore.plugin.getConfig().getBoolean("can-creative-cast");
|
||||||
cobbleGeneratorXP = MMOCore.plugin.getConfig().getBoolean("should-cobblestone-generators-give-exp");
|
cobbleGeneratorXP = MMOCore.plugin.getConfig().getBoolean("should-cobblestone-generators-give-exp");
|
||||||
saveDefaultClassInfo = MMOCore.plugin.getConfig().getBoolean("save-default-class-info");
|
saveDefaultClassInfo = MMOCore.plugin.getConfig().getBoolean("save-default-class-info");
|
||||||
|
maxBoundSkills= MMOCore.plugin.getConfig().getInt("max-bound-skills",6);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChatColor getColorOrDefault(String key, ChatColor defaultColor) {
|
private ChatColor getColorOrDefault(String key, ChatColor defaultColor) {
|
||||||
|
@ -26,6 +26,7 @@ public class SkillManager implements MMOCoreManager {
|
|||||||
skills.put(skill.getHandler().getId().toUpperCase(), skill);
|
skills.put(skill.getHandler().getId().toUpperCase(), skill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public RegisteredSkill getSkill(String id) {
|
public RegisteredSkill getSkill(String id) {
|
||||||
return skills.get(id.toUpperCase());
|
return skills.get(id.toUpperCase());
|
||||||
|
@ -35,6 +35,11 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
|
|||||||
BukkitRunnable runnable = new BukkitRunnable() {
|
BukkitRunnable runnable = new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
//To prevent infinite loops
|
||||||
|
if (System.currentTimeMillis() - startTime > 4000) {
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
provider.getResult("SELECT * FROM mmocore_playerdata WHERE uuid = '" + data.getUniqueId() + "';", (result) -> {
|
provider.getResult("SELECT * FROM mmocore_playerdata WHERE uuid = '" + data.getUniqueId() + "';", (result) -> {
|
||||||
try {
|
try {
|
||||||
|
@ -17,6 +17,7 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -89,7 +90,13 @@ public class SkillBar implements Listener {
|
|||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
if (event.getPressed() == mainKey && event.getPlayer().equals(getCaster().getPlayer())) {
|
if (event.getPressed() == mainKey && event.getPlayer().equals(getCaster().getPlayer())) {
|
||||||
MMOCore.plugin.soundManager.getSound(SoundEvent.SPELL_CAST_END).playTo(player);
|
MMOCore.plugin.soundManager.getSound(SoundEvent.SPELL_CAST_END).playTo(player);
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
MMOCore.plugin.configManager.getSimpleMessage("casting.no-longer").send(getCaster().getPlayer());
|
MMOCore.plugin.configManager.getSimpleMessage("casting.no-longer").send(getCaster().getPlayer());
|
||||||
|
}
|
||||||
|
}.runTask(MMOCore.plugin);
|
||||||
PlayerData.get(player).leaveCastingMode();
|
PlayerData.get(player).leaveCastingMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,7 @@ skill-casting:
|
|||||||
mode: SKILL_BAR
|
mode: SKILL_BAR
|
||||||
open: SWAP_HANDS
|
open: SWAP_HANDS
|
||||||
|
|
||||||
|
|
||||||
loot-chests:
|
loot-chests:
|
||||||
|
|
||||||
# Time in seconds it takes for a loot chest to
|
# Time in seconds it takes for a loot chest to
|
||||||
@ -246,6 +247,7 @@ resource-bar-colors:
|
|||||||
# false - Never verbose
|
# false - Never verbose
|
||||||
command-verbose:
|
command-verbose:
|
||||||
attribute: true
|
attribute: true
|
||||||
|
skill: true
|
||||||
class: true
|
class: true
|
||||||
experience: true
|
experience: true
|
||||||
level: true
|
level: true
|
||||||
|
@ -100,6 +100,11 @@ skills:
|
|||||||
level: 15
|
level: 15
|
||||||
max-level: 30
|
max-level: 30
|
||||||
|
|
||||||
|
|
||||||
|
#The number of skills a player can bound.
|
||||||
|
max-bound-skills: 6
|
||||||
|
|
||||||
|
|
||||||
# Experience sources for main class experience.
|
# Experience sources for main class experience.
|
||||||
main-exp-sources:
|
main-exp-sources:
|
||||||
- 'killmob{type=ZOMBIE;amount=1-3}'
|
- 'killmob{type=ZOMBIE;amount=1-3}'
|
||||||
|
@ -20,6 +20,9 @@ options:
|
|||||||
# Must match an existing exp curve filename from the 'expcurves' folder
|
# Must match an existing exp curve filename from the 'expcurves' folder
|
||||||
exp-curve: levels
|
exp-curve: levels
|
||||||
|
|
||||||
|
#The number of skills a player can bound.
|
||||||
|
max-bound-skills: 5
|
||||||
|
|
||||||
# Experience sources for main class experience.
|
# Experience sources for main class experience.
|
||||||
main-exp-sources:
|
main-exp-sources:
|
||||||
- 'killmob{type=ZOMBIE;amount=1-3}'
|
- 'killmob{type=ZOMBIE;amount=1-3}'
|
||||||
|
@ -54,6 +54,8 @@ mana:
|
|||||||
cast-particle:
|
cast-particle:
|
||||||
particle: SPELL_INSTANT
|
particle: SPELL_INSTANT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Special resource regeneration: (when out of combat),
|
# Special resource regeneration: (when out of combat),
|
||||||
# players can regen a set % of their maximum mana/missing mana.
|
# players can regen a set % of their maximum mana/missing mana.
|
||||||
# This % can scale with the player level.
|
# This % can scale with the player level.
|
||||||
@ -140,6 +142,11 @@ skills:
|
|||||||
level: 15
|
level: 15
|
||||||
max-level: 30
|
max-level: 30
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#The number of skills a player can bound.
|
||||||
|
max-bound-skills: 6
|
||||||
|
|
||||||
# Experience sources for main class experience.
|
# Experience sources for main class experience.
|
||||||
main-exp-sources:
|
main-exp-sources:
|
||||||
- 'killmob{type=ZOMBIE;amount=1-3}'
|
- 'killmob{type=ZOMBIE;amount=1-3}'
|
||||||
|
@ -33,6 +33,8 @@ max-level: 100
|
|||||||
|
|
||||||
exp-table: class_exp_table
|
exp-table: class_exp_table
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Particles displayed around the player
|
# Particles displayed around the player
|
||||||
# when he enters the casting mode.
|
# when he enters the casting mode.
|
||||||
cast-particle:
|
cast-particle:
|
||||||
@ -85,6 +87,11 @@ attributes:
|
|||||||
base: .105
|
base: .105
|
||||||
per-level: 0
|
per-level: 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#The number of skills a player can bound.
|
||||||
|
max-bound-skills: 5
|
||||||
|
|
||||||
# Experience sources for main class experience.
|
# Experience sources for main class experience.
|
||||||
main-exp-sources:
|
main-exp-sources:
|
||||||
- 'killmob{type=ZOMBIE;amount=1-3}'
|
- 'killmob{type=ZOMBIE;amount=1-3}'
|
||||||
|
@ -30,6 +30,8 @@ display:
|
|||||||
# Must match an existing exp curve filename from the 'expcurves' folder
|
# Must match an existing exp curve filename from the 'expcurves' folder
|
||||||
exp-curve: levels
|
exp-curve: levels
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# The maximum level players can reach
|
# The maximum level players can reach
|
||||||
max-level: 100
|
max-level: 100
|
||||||
|
|
||||||
@ -75,6 +77,11 @@ attributes:
|
|||||||
base: .095
|
base: .095
|
||||||
per-level: 0
|
per-level: 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#The number of skills a player can bound.
|
||||||
|
max-bound-skills: 5
|
||||||
|
|
||||||
# Experience sources for main class experience.
|
# Experience sources for main class experience.
|
||||||
main-exp-sources:
|
main-exp-sources:
|
||||||
- 'killmob{type=ZOMBIE;amount=1-3}'
|
- 'killmob{type=ZOMBIE;amount=1-3}'
|
||||||
|
@ -33,6 +33,7 @@ max-level: 100
|
|||||||
|
|
||||||
exp-table: class_exp_table
|
exp-table: class_exp_table
|
||||||
|
|
||||||
|
|
||||||
options:
|
options:
|
||||||
# Mana and health regen only applies when out of combat
|
# Mana and health regen only applies when out of combat
|
||||||
off-combat-mana-regen: true
|
off-combat-mana-regen: true
|
||||||
@ -80,6 +81,10 @@ attributes:
|
|||||||
base: .105
|
base: .105
|
||||||
per-level: 0
|
per-level: 0
|
||||||
|
|
||||||
|
|
||||||
|
#The number of skills a player can bound.
|
||||||
|
max-bound-skills: 5
|
||||||
|
|
||||||
# Experience sources for main class experience.
|
# Experience sources for main class experience.
|
||||||
main-exp-sources:
|
main-exp-sources:
|
||||||
- 'killmob{type=ZOMBIE;amount=1-3}'
|
- 'killmob{type=ZOMBIE;amount=1-3}'
|
||||||
|
@ -116,6 +116,11 @@ attributes:
|
|||||||
base: 4.2
|
base: 4.2
|
||||||
per-level: 0.05
|
per-level: 0.05
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#The number of skills a player can bound.
|
||||||
|
max-bound-skills: 5
|
||||||
|
|
||||||
# Experience sources for main class experience.
|
# Experience sources for main class experience.
|
||||||
main-exp-sources:
|
main-exp-sources:
|
||||||
- 'killmob{type=ZOMBIE;amount=1-3}'
|
- 'killmob{type=ZOMBIE;amount=1-3}'
|
||||||
|
Loading…
Reference in New Issue
Block a user