diff --git a/Plugins/Mineplex.Core.Common/pom.xml b/Plugins/Mineplex.Core.Common/pom.xml index 3e9fed6c9..92c1a7ff4 100644 --- a/Plugins/Mineplex.Core.Common/pom.xml +++ b/Plugins/Mineplex.Core.Common/pom.xml @@ -20,6 +20,11 @@ org.apache.httpcomponents httpclient + + com.mineplex + mineplex-serverdata + dev-SNAPSHOT + diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/RangeShuffleIterator.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/RangeShuffleIterator.java new file mode 100644 index 000000000..49af0d468 --- /dev/null +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/RangeShuffleIterator.java @@ -0,0 +1,162 @@ +package mineplex.core.common; + +import java.util.Iterator; +import java.util.Map; +import java.util.NavigableMap; +import java.util.PrimitiveIterator; +import java.util.Random; +import java.util.Set; +import java.util.TreeMap; + +import com.google.common.base.Preconditions; + +/** + * An Iterator that shuffles and provides integers from a specified range. + * The shuffle strategy is based on the Fisher-Yates shuffle. + * + * @see #nextInts(int) + * @see #nextInt() + */ +public class RangeShuffleIterator implements PrimitiveIterator.OfInt +{ + private static final Random random = new Random(); + private final IntSet _remaining; + private int _remainingCount; + + /** + * Create a RangeShuffleIterator encompassing the specified range (inclusive) + * + * @param start The range lower bound, inclusive + * @param end The range upper bound, inclusive + */ + public RangeShuffleIterator(int start, int end) + { + Preconditions.checkArgument(start <= end); + _remaining = new IntSet(start, end); + _remainingCount = end - start + 1; + } + + /** + * Provide a specified number of integers in an int array. If the number + * of elements remaining is fewer than {@code maxAmount}, return all + * remaining elements. + * + * @param maxAmount The number of elements to retrieve + * @return An array containing the retrieved elements + */ + public int[] nextInts(int maxAmount) + { + int[] ret = new int[Math.min(_remainingCount, maxAmount)]; + for (int i = 0; i < ret.length; i++) + { + ret[i] = nextInt(); + } + return ret; + } + + @Override + public int nextInt() + { + if (!hasNext()) + { + throw new IllegalStateException("No remaining ranges to iterate"); + } + + int selectedPosition = random.nextInt(_remainingCount); + + Iterator> it = _remaining.ranges().iterator(); + + final int selected; + while (true) + { + Map.Entry range = it.next(); + int span = range.getValue() - range.getKey(); + if (span < selectedPosition) + { + selectedPosition -= span + 1; + + } + else + { + selected = range.getKey() + selectedPosition; + break; + } + } + + _remaining.remove(selected); + --_remainingCount; + + return selected; + } + + @Override + public boolean hasNext() + { + return _remainingCount > 0; + } + + /** + * A set of integers. The set is seeded by a single range, and the only + * supported operation is int removal. + *

+ * This implementation only exists for performance reasons. + */ + private static class IntSet + { + /** + * A set of ranges representing the remaining integers in this set + */ + private final NavigableMap ranges = new TreeMap<>(); + + /** + * Create an IntSet containing all numbers from {@code start} to + * {@code end}, inclusive + * + * @param start The range lower bound, inclusive + * @param end The range upper bound, inclusive + */ + private IntSet(int start, int end) + { + ranges.put(start, end); + } + + public Set> ranges() + { + return ranges.entrySet(); + } + + /** + * Remove an integer from this IntSet + * @param value The integer to remove + */ + public void remove(int value) + { + Map.Entry range = ranges.floorEntry(value); + if (range == null || range.getValue() < value) + { + return; + } + + int lower = range.getKey(); + int upper = range.getValue(); + + if (upper > value) + { + reinsert(value + 1, upper); + } + reinsert(lower, Math.min(upper, value - 1)); + } + + private void reinsert(int start, int end) + { + if (end < start) + { + ranges.remove(start); + } + else + { + ranges.put(start, end); + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/F.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/F.java index 08d6147ad..49da7d9cf 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/F.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/F.java @@ -104,6 +104,11 @@ public class F return rank.getColor() + cmd + " " + C.mBody + body + " " + rank(rank); } + public static String help(String cmd, String body, Rank rank, ChatColor displayColor) + { + return displayColor + cmd + " " + C.mBody + body + " " + rank(rank); + } + public static String rank(Rank rank) { if (rank == Rank.ALL) diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/PlayerMap.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/PlayerMap.java index 426d2fd20..5cb6e7758 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/PlayerMap.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/PlayerMap.java @@ -4,6 +4,7 @@ import com.google.common.collect.Sets; import org.apache.commons.lang3.Validate; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; @@ -218,7 +219,7 @@ public class PlayerMap implements Map private static class RemovalListener implements Listener { - @EventHandler + @EventHandler (priority = EventPriority.MONITOR) public void onQuit(PlayerQuitEvent event) { synchronized (LOCK) diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilServer.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilServer.java index 80e388daf..c6e1edcdc 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilServer.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilServer.java @@ -1,7 +1,10 @@ package mineplex.core.common.util; import com.google.common.collect.Lists; + import mineplex.core.common.events.PlayerRecieveBroadcastEvent; +import mineplex.serverdata.Region; + import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.Sound; @@ -13,6 +16,7 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; import java.lang.reflect.Field; import java.util.*; @@ -52,7 +56,7 @@ public class UtilServer { return Bukkit.getServer(); } - + public static void broadcast(String message) { for (Player cur : getPlayers()) @@ -61,13 +65,13 @@ public class UtilServer UtilPlayer.message(cur, message); } } - + public static void broadcast(LinkedList messages) { for (Player cur : getPlayers()) UtilPlayer.message(cur, messages); } - + public static void broadcastSpecial(String event, String message) { for (Player cur : getPlayers()) @@ -78,32 +82,32 @@ public class UtilServer cur.playSound(cur.getLocation(), Sound.ORB_PICKUP, 2f, 0f); } } - + public static void broadcast(String sender, String message) { broadcast("§f§l" + sender + " " + "§b" + message); } - + public static void broadcastMagic(String sender, String message) { broadcast("§2§k" + message); } - - public static double getFilledPercent() + + public static double getFilledPercent() { - return (double)getPlayers().length / (double)UtilServer.getServer().getMaxPlayers(); + return (double) getPlayers().length / (double) UtilServer.getServer().getMaxPlayers(); } - + public static void RegisterEvents(Listener listener) { getPluginManager().registerEvents(listener, getPlugin()); } - + public static void Unregister(Listener listener) { HandlerList.unregisterAll(listener); } - + public static JavaPlugin getPlugin() { return JavaPlugin.getProvidingPlugin(UtilServer.class); @@ -135,6 +139,16 @@ public class UtilServer return getPlugin().getConfig().getString("serverstatus.name"); } + public static Region getRegion() + { + return getPlugin().getConfig().getBoolean("serverstatus.us") ? Region.US : Region.EU; + } + + public static String getGroup() + { + return getPlugin().getConfig().getString("serverstatus.group"); + } + public static boolean isTestServer() { return getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing"); @@ -185,4 +199,39 @@ public class UtilServer { return getPlugin().getConfig().getString("webServer"); } + + public static BukkitTask runAsync(Runnable runnable) + { + return getPlugin().getServer().getScheduler().runTaskAsynchronously(getPlugin(), runnable); + } + + public static BukkitTask runAsync(Runnable runnable, long time) + { + return getPlugin().getServer().getScheduler().runTaskLaterAsynchronously(getPlugin(), runnable, time); + } + + public static BukkitTask runAsyncTimer(Runnable runnable, long time, long period) + { + return getPlugin().getServer().getScheduler().runTaskTimerAsynchronously(getPlugin(), runnable, time, period); + } + + public static BukkitTask runSync(Runnable runnable) + { + return getPlugin().getServer().getScheduler().runTask(getPlugin(), runnable); + } + + public static BukkitTask runSyncLater(Runnable runnable, long delay) + { + return getPlugin().getServer().getScheduler().runTaskLater(getPlugin(), runnable, delay); + } + + public static BukkitTask runSyncTimer(Runnable runnable, long delay, long period) + { + return getPlugin().getServer().getScheduler().runTaskTimer(getPlugin(), runnable, delay, period); + } + + public static BukkitTask runSyncTimer(BukkitRunnable runnable, long delay, long period) + { + return runnable.runTaskTimer(getPlugin(), delay, period); + } } diff --git a/Plugins/Mineplex.Core/pom.xml b/Plugins/Mineplex.Core/pom.xml index c4dbb202a..65a90f2a7 100644 --- a/Plugins/Mineplex.Core/pom.xml +++ b/Plugins/Mineplex.Core/pom.xml @@ -45,6 +45,11 @@ anticheat 1.2 + + org.tukaani + xz + 1.5 + diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java index 735494949..d6414e463 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java @@ -14,6 +14,18 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.java.JavaPlugin; + import com.google.gson.Gson; import mineplex.cache.player.PlayerCache; @@ -26,26 +38,14 @@ import mineplex.core.account.event.ClientWebResponseEvent; import mineplex.core.account.repository.AccountRepository; import mineplex.core.account.repository.token.ClientToken; import mineplex.core.common.Rank; +import mineplex.core.common.timing.TimingManager; import mineplex.core.common.util.Callback; import mineplex.core.common.util.UUIDFetcher; import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilTasks; -import mineplex.core.common.timing.TimingManager; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; - import mineplex.core.utils.UtilGameProfile; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.AsyncPlayerPreLoginEvent; -import org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.plugin.java.JavaPlugin; public class CoreClientManager extends MiniPlugin { @@ -453,6 +453,12 @@ public class CoreClientManager extends MiniPlugin return !CLIENT_LOGIN_LOCKS.containsKey(client.getName()); } + + public ClientToken loadOfflineClient(UUID uuid) + { + String client = _repository.getClientByUUID(uuid); + return new Gson().fromJson(client, ClientToken.class); + } @EventHandler(priority = EventPriority.LOWEST) public void Login(PlayerLoginEvent event) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHack.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHack.java index b5f56ca2e..0023bb1e6 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHack.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHack.java @@ -1,605 +1,270 @@ package mineplex.core.antihack; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.AtomicDouble; -import com.mineplex.anticheat.api.GameEndEvent; -import com.mineplex.anticheat.api.GameStartEvent; -import com.mineplex.anticheat.api.MineplexLink; -import com.mineplex.anticheat.api.PlayerViolationEvent; -import com.mineplex.anticheat.checks.Check; -import mineplex.core.Managers; -import mineplex.core.MiniPlugin; -import mineplex.core.PlayerSelector; -import mineplex.core.ReflectivelyCreateMiniPlugin; -import mineplex.core.account.CoreClient; -import mineplex.core.account.CoreClientManager; -import mineplex.core.antihack.actions.AntiHackAction; -import mineplex.core.antihack.banwave.BanWaveManager; -import mineplex.core.antihack.types.Fly; -import mineplex.core.antihack.types.Idle; -import mineplex.core.antihack.types.Reach; -import mineplex.core.antihack.types.Speed; -import mineplex.core.command.CommandBase; -import mineplex.core.common.Rank; -import mineplex.core.common.util.*; -import mineplex.core.disguise.DisguiseManager; -import mineplex.core.disguise.disguises.DisguiseBase; -import mineplex.core.portal.Portal; -import mineplex.core.preferences.Preference; -import mineplex.core.preferences.PreferencesManager; -import mineplex.core.punish.Category; -import mineplex.core.punish.Punish; -import mineplex.core.punish.PunishClient; -import mineplex.core.punish.Punishment; -import mineplex.core.updater.UpdateType; -import mineplex.core.updater.event.UpdateEvent; -import mineplex.serverdata.commands.ServerCommandManager; -import net.minecraft.server.v1_8_R3.*; -import org.bukkit.*; -import org.bukkit.Material; +import javax.xml.bind.DatatypeConverter; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.minecraft.server.v1_8_R3.MinecraftServer; + +import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; -import org.bukkit.event.player.*; -import org.bukkit.event.server.ServerListPingEvent; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerToggleFlightEvent; import org.bukkit.plugin.ServicePriority; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitTask; -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.function.Predicate; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonObject; +import com.mineplex.anticheat.MineplexAnticheat; +import com.mineplex.anticheat.api.GameEndEvent; +import com.mineplex.anticheat.api.GameStartEvent; +import com.mineplex.anticheat.api.MineplexLink; +import com.mineplex.anticheat.api.PlayerViolationEvent; +import com.mineplex.anticheat.checks.Check; +import com.mineplex.anticheat.checks.CheckManager; +import com.mineplex.anticheat.checks.combat.KillauraTypeA; +import com.mineplex.anticheat.checks.combat.KillauraTypeB; +import com.mineplex.anticheat.checks.combat.KillauraTypeC; +import com.mineplex.anticheat.checks.combat.KillauraTypeD; +import com.mineplex.anticheat.checks.combat.KillauraTypeE; +import com.mineplex.anticheat.checks.combat.KillauraTypeF; +import com.mineplex.anticheat.checks.move.Glide; +import com.mineplex.anticheat.checks.move.HeadRoll; +import com.mineplex.anticheat.checks.move.Speed; +import com.mineplex.anticheat.checks.player.BadPackets; + +import mineplex.core.Managers; +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClient; +import mineplex.core.account.CoreClientManager; +import mineplex.core.antihack.actions.AntiHackAction; +import mineplex.core.antihack.actions.BanwaveAction; +import mineplex.core.antihack.actions.ImmediateBanAction; +import mineplex.core.antihack.actions.NoopAction; +import mineplex.core.antihack.animations.BanwaveAnimationSpin; +import mineplex.core.antihack.banwave.BanWaveInfo; +import mineplex.core.antihack.banwave.BanWaveManager; +import mineplex.core.antihack.commands.AnticheatOffCommand; +import mineplex.core.antihack.commands.AnticheatOnCommand; +import mineplex.core.antihack.commands.DetailedMessagesCommand; +import mineplex.core.antihack.commands.GetVlsCommand; +import mineplex.core.antihack.commands.TestBanCommand; +import mineplex.core.antihack.guardians.GuardianManager; +import mineplex.core.antihack.logging.AntihackLogger; +import mineplex.core.antihack.redisnotifications.GwenBanNotification; +import mineplex.core.antihack.redisnotifications.GwenBanwaveNotification; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.disguises.DisguiseBase; +import mineplex.core.preferences.Preference; +import mineplex.core.preferences.PreferencesManager; +import mineplex.core.punish.Category; +import mineplex.core.punish.Punish; +import mineplex.core.punish.PunishmentResponse; +import mineplex.serverdata.commands.ServerCommandManager; @ReflectivelyCreateMiniPlugin public class AntiHack extends MiniPlugin { - public static final Map CHECKS = ImmutableMap.builder() - .put("Killaura (Type A)", new CheckThresholds("Kill Aura", 0, 25, 50)) - .put("Killaura (Type B)", new CheckThresholds("High CPS", 0, 0, Integer.MAX_VALUE)) - .put("Killaura (Type C)", new CheckThresholds("Reach", 0, Integer.MAX_VALUE, Integer.MAX_VALUE)) - .put("Killaura (Type D)", new CheckThresholds("Kill Aura", 500, 1000, 1500)) - .put("Killaura (Type E)", new CheckThresholds("Kill Aura", 300, 700, 2000)) - .put("Killaura (Type F)", new CheckThresholds("Kill Aura", 150, 250, 350)) - .put("BadPackets", new CheckThresholds("Regen", 500, 1000, 2000)) - .put("Glide", new CheckThresholds("Flying", 50, 100, 200)) // TODO: specific VL levels - .put("Speed", new CheckThresholds("Speed", 50, 100, 200)) // TODO: specific VL levels - .put("HeadRoll", new CheckThresholds("Illegal Movement", 0, 0, 0)) + private static final Map, CheckThresholds> CHECKS = ImmutableMap., CheckThresholds>builder() + .put(KillauraTypeA.class, new CheckThresholds("Kill Aura", 0, 25, 50)) + .put(KillauraTypeB.class, new CheckThresholds("High CPS", 0, 0, Integer.MAX_VALUE)) + .put(KillauraTypeC.class, new CheckThresholds("Reach", 0, Integer.MAX_VALUE, Integer.MAX_VALUE)) + .put(KillauraTypeD.class, new CheckThresholds("Kill Aura", 500, 1000, 1500)) + .put(KillauraTypeE.class, new CheckThresholds("Kill Aura", 300, 700, 2000)) + .put(KillauraTypeF.class, new CheckThresholds("Kill Aura", 150, 250, 350)) + .put(BadPackets.class, new CheckThresholds("Regen", 500, 1000, 2000)) + .put(Glide.class, new CheckThresholds("Flying", 150, 250, 500)) + .put(Speed.class, new CheckThresholds("Speed", 150, 250, 500)) + .put(HeadRoll.class, new CheckThresholds("Illegal Movement", 0, 0, 0)) .build(); - public static final String NAME = "Chiss"; - public static final String USER_HAS_BEEN_BANNED = F.main("GWEN", "%s has been banned. I am always watching."); - public static final String USER_HAS_BEEN_BANNED_BANWAVE = USER_HAS_BEEN_BANNED; + private static final CheckThresholds NOOP_THRESHOLD = new CheckThresholds("Unknown", 0, Integer.MAX_VALUE, Integer.MAX_VALUE); - private static final int VL_DIFF_BEFORE_RENOTIFY = 999999; - private static final int MAX_STALKED_PLAYERS = 3; - private static final int STALK_COOLDOWN_TIME_SECONDS = 5; - private static final int MIN_STALK_TIME = 10 * 20; - private static final int MAX_STALK_TIME = 20 * 20; - private static final int MAX_MIN_DIFF = MAX_STALK_TIME - MIN_STALK_TIME; - private static final Function STALK_END_PROBABILITY_EQUATION = x -> - { - return 1.0/ MAX_MIN_DIFF * x; // linear equation with points (0, 0) and (diff, 1) - }; + private static final Map, AntiHackAction> ACTIONS = ImmutableMap., AntiHackAction>builder() + .put(KillauraTypeA.class, new ImmediateBanAction(200)) + .put(KillauraTypeD.class, new BanwaveAction(1500)) + .put(Glide.class, new ImmediateBanAction(10000)) + .put(Speed.class, new ImmediateBanAction(10000)) +// .put(HeadRoll.class, new ImmediateBanAction(200)) + .build(); + + private static final AntiHackAction NOOP_ACTION = new NoopAction(); + + private static final String NAME = "Chiss"; + private static final String USER_HAS_BEEN_BANNED = F.main("GWEN", "%s has been banned. I am always watching."); + private static final String USER_HAS_BEEN_BANNED_BANWAVE = USER_HAS_BEEN_BANNED; + + public static final int ID_LENGTH = 5; private final Cache _cooldown = CacheBuilder.newBuilder() .concurrencyLevel(1) .expireAfterWrite(30, TimeUnit.SECONDS) .build(); - private final Cache _stalkingCooldown = CacheBuilder.newBuilder() - .concurrencyLevel(1) - .expireAfterWrite(STALK_COOLDOWN_TIME_SECONDS, TimeUnit.SECONDS) - .build(); - private final List _stalking = new ArrayList<>(); - private final String _thisServer; + private final String _thisServer = UtilServer.getServerName(); - private boolean _enabled = true; - private boolean _strict = false; - private boolean _kick = true; + private final CoreClientManager _clientManager = require(CoreClientManager.class); + private final AntihackLogger _logger = require(AntihackLogger.class); + private final PreferencesManager _preferences = require(PreferencesManager.class); + private final Punish _punish = require(Punish.class); - public Portal Portal = require(Portal.class); - private PreferencesManager _preferences = require(PreferencesManager.class); - private CoreClientManager _clientManager = require(CoreClientManager.class); - - //Record Offenses - private HashMap>> _offense = new HashMap>>(); - - //Ignore Player - private HashMap _ignore = new HashMap(); - - //Player Info - private HashSet _velocityEvent = new HashSet(); - private HashMap _lastMoveEvent = new HashMap(); - - private HashSet _hubAttempted = new HashSet(); - - //Hack Requirements - public int FloatHackTicks = 10; - public int HoverHackTicks = 4; - public int RiseHackTicks = 6; - public int SpeedHackTicks = 6; - public int IdleTime = 20000; - - public int KeepOffensesFor = 30000; - - //Other Times - public int FlightTriggerCancel = 2000; - - public ArrayList _movementDetectors; - public ArrayList _combatDetectors; - - private AntiHackRepository _repository; - - private List _guardians = new ArrayList<>(); + private final Set _detailedMessages = new HashSet<>(); private Set _pendingBan = new HashSet<>(); // These are the GWEN checks to ignore when handling PlayerViolationEvent private HashSet> _ignoredChecks = new HashSet<>(); - @SuppressWarnings("Convert2streamapi") private AntiHack() { super("AntiHack"); - DisguiseManager disguiseManager = require(DisguiseManager.class); + _detailedMessages.add("Spoobncoobr"); - this._thisServer = UtilServer.getServerName(); + require(GuardianManager.class); + require(BanWaveManager.class); - _repository = new AntiHackRepository(this._thisServer); - _repository.initialize(); - - _movementDetectors = new ArrayList(); - _combatDetectors = new ArrayList(); - - _movementDetectors.add(new Fly(this)); - _movementDetectors.add(new Idle(this)); - _movementDetectors.add(new Speed(this)); - - _combatDetectors.add(new Reach(this)); - - Bukkit.getServicesManager().register(MineplexLink.class, new MineplexLink() - { - @Override - public EntityType getActiveDisguise(Player player) - { - DisguiseBase disguise = disguiseManager.getActiveDisguise(player); - return disguise != null ? disguise.getDisguiseType() : null; - } - - @Override - public boolean isSpectator(Player player) - { - return UtilPlayer.isSpectator(player); - } - - @Override - public double getTPS() - { - return MinecraftServer.getServer().recentTps[0]; // Return the average TPS from the last minute - } - - @Override - public int getPing(Player player) - { - return Math.min(((CraftPlayer)player).getHandle().ping, 1000); - } - - @Override - public boolean isUsingItem(Player player) - { - return ((CraftPlayer)player).getHandle().bS(); // See Anticheat javadoc - } - }, this._plugin, ServicePriority.Normal); + Bukkit.getServicesManager().register(MineplexLink.class, new MineplexLinkImpl(), this._plugin, ServicePriority.Normal); ServerCommandManager.getInstance().registerCommandType(MajorViolationCommand.class, violation -> { - IChatBaseComponent component = getMinimalMessage(violation); - + BaseComponent[] minimal = getMinimalMessage(violation); + BaseComponent[] detailed = getDetailedMessage(violation); for (Player player : Bukkit.getOnlinePlayers()) { - if (player.getName().equals("Spoobncoobr")) - { - ((CraftPlayer) player).getHandle().sendMessage(getDetailedMessage(violation)); + if (_detailedMessages.contains(player.getName())) + player.spigot().sendMessage(detailed); + else if (_clientManager.Get(player).GetRank().has(Rank.HELPER) && (violation.getOriginatingServer().equals(_thisServer) || _preferences.get(player).isActive(Preference.GLOBAL_GWEN_REPORTS))) + player.spigot().sendMessage(minimal); + } + }); + } - } else if (_clientManager.Get(player).GetRank().has(Rank.HELPER) && (violation.getOriginatingServer().equals(_thisServer) || Managers.get(PreferencesManager.class).get(player).isActive(Preference.GLOBAL_GWEN_REPORTS))) + @Override + public void addCommands() + { + if (UtilServer.isTestServer()) + { + addCommand(new AnticheatOnCommand(this)); + addCommand(new AnticheatOffCommand(this)); + addCommand(new TestBanCommand(this)); + } + addCommand(new GetVlsCommand(this)); + addCommand(new DetailedMessagesCommand(this)); + } + + private void runBanAnimation(Player player, Runnable after) + { + new BanwaveAnimationSpin().run(player, after); + } + + public void doBan(Player player, Class cause) + { + runSync(() -> + { + if (_pendingBan.add(player)) + { + CoreClient coreClient = _clientManager.Get(player); + + Consumer> doPunish = after -> { - ((CraftPlayer) player).getHandle().sendMessage(component); + JsonObject custom = new JsonObject(); + custom.addProperty("ban-reason", CheckManager.getCheckSimpleName(cause)); + + String id = generateId(); + String finalMessage = "[GWEN] " + id; + _logger.saveMetadata(player, id, () -> + { + _logger.resetViolations(player, () -> + { + runAsync(() -> + { + GwenBanNotification notification = new GwenBanNotification(_thisServer, player.getName(), player.getUniqueId().toString(), CheckManager.getCheckSimpleName(cause), id); + ServerCommandManager.getInstance().publishCommand(notification); + }); + + _punish.AddPunishment(coreClient.getName(), Category.Hacking, finalMessage, AntiHack.NAME, 3, true, -1, true, after); + }); + }, custom); + }; + + if (coreClient.GetRank().has(Rank.TWITCH)) + { + doPunish.accept(result -> _pendingBan.remove(player)); + } + else + { + runBanAnimation(player, () -> + doPunish.accept(result -> + { + if (result == PunishmentResponse.Punished) + { + announceBan(player); + } + _pendingBan.remove(player); + }) + ); } } }); + } - this._plugin.getServer().getScheduler().runTaskTimer(this._plugin, () -> + public void doBanWave(Player player, BanWaveInfo info) + { + runSync(() -> { - for (AntiHackGuardian guardian : this._guardians) + CoreClient coreClient = _clientManager.Get(player); + + Consumer> doPunish = after -> { - if (guardian.getTarget() != null && !guardian.getTarget().isOnline()) - { - this._stalking.remove(guardian.getTarget().getUniqueId()); - guardian.stopTargeting(); - } - else if (guardian.getTargetingTime() > MIN_STALK_TIME) - { - double threshold = STALK_END_PROBABILITY_EQUATION.apply(guardian.getTargetingTime() - MIN_STALK_TIME); - if (Math.random() <= threshold) - { - this._stalking.remove(guardian.getTarget().getUniqueId()); - _stalkingCooldown.put(guardian.getTarget().getUniqueId(), true); - guardian.stopTargeting(); - } - } - guardian.tick(); - } - }, 0L, 1L); - - this._plugin.getServer().getScheduler().runTaskTimer(this._plugin, () -> - { - if (_stalking.size() >= MAX_STALKED_PLAYERS) - { - return; - } - - if (_guardians.size() == 0) - { - return; - } - - List targets = PlayerSelector.selectPlayers( - UtilLambda.and( - PlayerSelector.NOT_VANISHED, - PlayerSelector.hasAnyRank(false, - Rank.ALL, - Rank.ULTRA, - Rank.HERO, - Rank.LEGEND, - Rank.TITAN, - Rank.TWITCH, - Rank.YOUTUBE_SMALL, - Rank.YOUTUBE, - Rank.MEDIA, - Rank.ADMIN, - Rank.DEVELOPER, - Rank.OWNER, - Rank.LT - ), - player -> !_stalking.contains(player.getUniqueId()), - player -> _stalkingCooldown.getIfPresent(player.getUniqueId()) == null - )); - - while (_stalking.size() < MAX_STALKED_PLAYERS && targets.size() > 0) - { - Player target = targets.remove(ThreadLocalRandom.current().nextInt(targets.size())); - - int start = ThreadLocalRandom.current().nextInt(_guardians.size()); - - for (int i = start, j = 0; j < _guardians.size(); i++, j++) - { - if (i >= _guardians.size()) - { - i -= _guardians.size(); - } - AntiHackGuardian guardian = _guardians.get(i); - if (!guardian.isTargeting()) - { - guardian.target(target); - _stalking.add(target.getUniqueId()); - break; - } - } - } - }, 0L, 20L); - - require(BanWaveManager.class); - } - - private IChatBaseComponent getDetailedMessage(MajorViolationCommand violation) - { - return new ChatComponentText("") - .addSibling( - new ChatComponentText("A") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.AQUA) - .setRandom(true) - ) - ) - .addSibling( - new ChatComponentText(" GWEN > ") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.RED) - .setBold(true) - ) - ) - .addSibling( - new ChatComponentText(violation.getPlayerName()) - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.GOLD) - ) - ) - .addSibling( - new ChatComponentText(" failed " + violation.getHackType() + " VL" + violation.getViolations() + " in server ") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.YELLOW) - ) - ) - .addSibling( - new ChatComponentText( - violation.getOriginatingServer() - ) - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.YELLOW) - .setChatClickable( - new ChatClickable( - ChatClickable.EnumClickAction.RUN_COMMAND, - "/server " + violation.getOriginatingServer() - ) - ) - .setChatHoverable( - new ChatHoverable( - ChatHoverable.EnumHoverAction.SHOW_TEXT, - new ChatComponentText("Teleport to " + violation.getOriginatingServer()) - ) - ) - ) - ) - .addSibling( - new ChatComponentText(": " + violation.getMessage() + ".") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.YELLOW) - ) - ); - } - - private IChatBaseComponent getMinimalMessage(MajorViolationCommand violation) - { - IChatBaseComponent component = new ChatComponentText("") - .addSibling( - new ChatComponentText("A") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.AQUA) - .setRandom(true) - ) - ) - .addSibling( - new ChatComponentText(" GWEN > ") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.RED) - .setBold(true) - ) - ) - .addSibling( - new ChatComponentText(violation.getPlayerName()) - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.GOLD) - ) - ) - .addSibling( - new ChatComponentText(" suspected of ") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.YELLOW) - ) - ) - .addSibling(CHECKS.get(violation.getHackType()).format(violation.getViolations())); - - if (!violation.getOriginatingServer().equals(this._thisServer)) - { - component - .addSibling( - new ChatComponentText(" in ") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.YELLOW) - ) - ) - .addSibling( - new ChatComponentText(violation.getOriginatingServer()) - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.AQUA) - .setChatClickable( - new ChatClickable( - ChatClickable.EnumClickAction.RUN_COMMAND, - "/server " + violation.getOriginatingServer() - ) - ) - .setChatHoverable( - new ChatHoverable( - ChatHoverable.EnumHoverAction.SHOW_TEXT, - new ChatComponentText("Teleport to " + violation.getOriginatingServer()) - ) - ) - ) - ); - } - - return component.addSibling( - new ChatComponentText(".") - .setChatModifier( - new ChatModifier() - .setColor(EnumChatFormat.YELLOW) - ) - ); - } - - public void registerGuardian(AntiHackGuardian guardian) - { - this._guardians.add(guardian); - } - - public void clearGuardians() - { - this._guardians.forEach(AntiHackGuardian::remove); - this._guardians.clear(); - this._stalking.clear(); - this._stalkingCooldown.cleanUp(); - } - - public void runBanAnimation(Player player, Runnable after) - { - if (_pendingBan.add(player)) - { - float oldWalkSpeed = player.getWalkSpeed(); - player.setWalkSpeed(0); - player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 999999, -10)); - - double radius = 4; - double heightAdj = 8; - - double baseDeg = 18; - - Location center = player.getLocation().add(0, heightAdj, 0); - AntiHackGuardian north = new AntiHackGuardian(center.clone().add(0, 0, -radius), 0, 0, 0, 0, 0, 0, false); - AntiHackGuardian east = new AntiHackGuardian(center.clone().add(radius, 0, 0), 0, 0, 0, 0, 0, 0, false); - AntiHackGuardian south = new AntiHackGuardian(center.clone().add(0, 0, radius), 0, 0, 0, 0, 0, 0, false); - AntiHackGuardian west = new AntiHackGuardian(center.clone().add(-radius, 0, 0), 0, 0, 0, 0, 0, 0, false); - - UtilEnt.CreatureLook(east.getEntity(), player); - UtilEnt.CreatureLook(west.getEntity(), player); - UtilEnt.CreatureLook(south.getEntity(), player); - UtilEnt.CreatureLook(north.getEntity(), player); - - Function magic = seconds -> - { - return Math.pow(2, seconds - 5); + _punish.AddPunishment(coreClient.getName(), Category.Hacking, info.getMessage(), AntiHack.NAME, 3, true, -1, true, after); }; - runSyncLater(() -> - { - north.shoot(player); - east.shoot(player); - south.shoot(player); - west.shoot(player); - - // We get 5 seconds, or 100 ticks - AtomicInteger timer = new AtomicInteger(5); - AtomicReference task = new AtomicReference<>(); - - AtomicDouble cNorth = new AtomicDouble(270); - AtomicDouble cEast = new AtomicDouble(0); - AtomicDouble cSouth = new AtomicDouble(90); - AtomicDouble cWest = new AtomicDouble(180); - - task.set(runSyncTimer(() -> - { - timer.getAndIncrement(); - if (timer.get() > 100) - { - task.get().cancel(); - - player.removePotionEffect(PotionEffectType.JUMP); - player.setWalkSpeed(oldWalkSpeed); - Location location = player.getLocation(); - - UtilParticle.PlayParticle(UtilParticle.ParticleType.HUGE_EXPLOSION, player.getLocation(), 3f, 3f, 3f, 0, 32, UtilParticle.ViewDist.MAX, UtilServer.getPlayers()); - - after.run(); - - _pendingBan.remove(player); - - north.shoot(null); - south.shoot(null); - east.shoot(null); - west.shoot(null); - UtilEnt.CreatureLook(north.getEntity(), location); - UtilEnt.CreatureLook(south.getEntity(), location); - UtilEnt.CreatureLook(east.getEntity(), location); - UtilEnt.CreatureLook(west.getEntity(), location); - runSyncLater(() -> - { - north.remove(); - south.remove(); - east.remove(); - west.remove(); - }, 40L); - return; - } - - double seconds = timer.get() / 20.0; - - double rate = magic.apply(seconds) * 3 * baseDeg; - - player.getLocation(center); - center.add(0, heightAdj, 0); - - { - cNorth.addAndGet(rate); - north.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cNorth.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cNorth.get()))); - } - { - cSouth.addAndGet(rate); - south.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cSouth.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cSouth.get()))); - } - { - cEast.addAndGet(rate); - east.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cEast.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cEast.get()))); - } - { - cWest.addAndGet(rate); - west.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cWest.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cWest.get()))); - } - }, 5, 1)); - }, 20); - } - } - - public void doBan(Player player, String message) - { - runSync(() -> - { - CoreClient coreClient = _clientManager.Get(player); - if (coreClient.GetRank().has(Rank.TWITCH)) { - require(Punish.class).AddPunishment(coreClient.getName(), Category.Hacking, message, AntiHack.NAME, 3, true, -1, true); - } - else - { - runBanAnimation(player, () -> + doPunish.accept(response -> { - require(Punish.class).AddPunishment(coreClient.getName(), Category.Hacking, message, AntiHack.NAME, 3, true, -1, true); - announceBan(player); }); } - }); - } - - public void doBanWave(Player player, String message) - { - runSync(() -> - { - int totalPunishments = getPunishments(player); - int daysBanned = getDaysBanned(player); - CoreClient coreClient = _clientManager.Get(player); - if (coreClient.GetRank().has(Rank.TWITCH)) - { - require(Punish.class).AddPunishment(coreClient.getName(), Category.Hacking, message, AntiHack.NAME, totalPunishments + 1, true, daysBanned == -1 ? -1 : TimeUnit.DAYS.toHours(daysBanned), true); - } else { runBanAnimation(player, () -> { - require(Punish.class).AddPunishment(coreClient.getName(), Category.Hacking, message, AntiHack.NAME, totalPunishments + 1, true, daysBanned == -1 ? -1 : TimeUnit.DAYS.toHours(daysBanned), true); - announceBanwave(player); + doPunish.accept(result -> + { + if (result == PunishmentResponse.Punished) + { + announceBanwave(player); + } + }); }); } }); @@ -642,13 +307,18 @@ public class AntiHack extends MiniPlugin } } - @EventHandler - public void on(PlayerViolationEvent event) + @EventHandler(priority = EventPriority.LOWEST) + public void on(EntityDamageEvent event) { - if (_ignoredChecks.contains(event.getCheckClass())) - return; + if (_pendingBan.contains(event.getEntity())) + event.setCancelled(true); + } - AntiHackAction.getAction(event.getCheckClass()).handle(event); + @EventHandler(priority = EventPriority.LOWEST) + public void on(EntityDamageByEntityEvent event) + { + if (_pendingBan.contains(event.getDamager())) + event.setCancelled(true); } public void announceBan(Player player) @@ -661,326 +331,16 @@ public class AntiHack extends MiniPlugin Bukkit.getServer().broadcastMessage(String.format(USER_HAS_BEEN_BANNED_BANWAVE, player.getName())); } - public int getPunishments(Player player) + public boolean toggleDetailedMessage(Player player) { - PunishClient punishClient = require(Punish.class).GetClient(player.getName()); - - int totalPunishments = 0; - - if (punishClient.GetPunishments().containsKey(Category.Hacking)) - { - for (Punishment punishment : punishClient.GetPunishments().get(Category.Hacking)) - { - if (punishment.GetAdmin().equalsIgnoreCase(NAME)) - { - totalPunishments++; - } - } - } - - return totalPunishments; - } - - public int getDaysBanned(Player player) - { - int totalPunishments = getPunishments(player); - - int daysBanned = 0; - - switch (totalPunishments) - { - case 0: - daysBanned = 7; - break; - case 1: - daysBanned = 30; - break; - case 2: - default: - daysBanned = -1; - } - - return daysBanned; - } - - @Override - public void addCommands() - { - if (UtilServer.isTestServer()) - { - addCommand(new CommandBase(this, Rank.DEVELOPER, "acon") - { - @Override - public void Execute(Player caller, String[] args) - { - if (caller.getUniqueId().toString().equals("b86b54da-93dd-46f9-be33-27bd92aa36d7")) - { - enableNewAnticheat(); - UtilPlayer.message(caller, F.main(getName(), "Enabled new anticheat")); - } - } - }); - addCommand(new CommandBase(this, Rank.DEVELOPER, "acoff") - { - @Override - public void Execute(Player caller, String[] args) - { - if (caller.getUniqueId().toString().equals("b86b54da-93dd-46f9-be33-27bd92aa36d7")) - { - disableNewAnticheat(); - UtilPlayer.message(caller, F.main(getName(), "Disabled new anticheat")); - } - } - }); - addCommand(new CommandBase(this, Rank.DEVELOPER, "testban") - { - @Override - public void Execute(Player caller, String[] args) - { - if (caller.getUniqueId().toString().equals("b86b54da-93dd-46f9-be33-27bd92aa36d7")) - { - if (args.length > 0) - { - Player p = Bukkit.getPlayerExact(args[0]); - if (p != null) - { - runBanAnimation(p, () -> - { - String reason = C.cRed + C.Bold + "You are banned for permanent by " + NAME + - "\n" + C.cWhite + "Seems to be speeding up time. (" + ThreadLocalRandom.current().nextInt(200, 400) + " packets/150 ms)" + - "\n" + C.cDGreen + "Unfairly banned? Appeal at " + C.cGreen + "www.mineplex.com/appeals"; - p.kickPlayer(reason); - - announceBan(p); - }); - } - else - { - UtilPlayer.message(caller, F.main(getName(), "Could not find player")); - } - } - else - { - UtilPlayer.message(caller, F.main(getName(), "No player specified")); - } - } - } - }); - } - } - - @EventHandler - public void playerMove(PlayerMoveEvent event) - { - if (!_enabled) - return; - - _lastMoveEvent.put(event.getPlayer(), System.currentTimeMillis()); - } - - @EventHandler - public void playerTeleport(PlayerTeleportEvent event) - { - if (!_enabled) - return; - - setIgnore(event.getPlayer(), 2000); - } - - @EventHandler - public void playerVelocity(PlayerVelocityEvent event) - { - if (!_enabled) - return; - - _velocityEvent.add(event.getPlayer()); - } - - @EventHandler - public void playerQuit(PlayerQuitEvent event) - { - if (!_enabled) - return; - - resetAll(event.getPlayer()); - } - - @EventHandler - public void startIgnore(PlayerMoveEvent event) - { - if (!_enabled) - return; - - Player player = event.getPlayer(); - - if (_velocityEvent.remove(player)) - { - setIgnore(player, 2000); - } - - //Initial Move (or Lag) Ignore - if (_lastMoveEvent.containsKey(player)) - { - long timeBetweenPackets = System.currentTimeMillis() - _lastMoveEvent.get(player); - - if (timeBetweenPackets > 500) - { - setIgnore(player, Math.min(4000, timeBetweenPackets)); - } - } - } - - public void setIgnore(Player player, long time) - { - //Wipe Detection - for (Detector detector : _movementDetectors) - detector.Reset(player); - - //Already ignoring for a longer period - if (_ignore.containsKey(player) && _ignore.get(player) > System.currentTimeMillis() + time) - return; - - //Add Ignore - _ignore.put(player, System.currentTimeMillis() + time); - } - - public boolean isValid(Player player, boolean groundValid) - { - //Near Other Player - for (Player other : UtilServer.getPlayers()) - { - if (player.equals(other)) - continue; - - if (other.getGameMode() != GameMode.SURVIVAL || UtilPlayer.isSpectator(player)) - continue; - - if (other.getVehicle() != null) - continue; - - if (UtilMath.offset(player, other) < 2) - return true; - } - - if (player.isFlying() || ((CraftPlayer) player).getHandle().isGliding() || player.isInsideVehicle() || player.getGameMode() != GameMode.SURVIVAL || UtilPlayer.isSpectator(player)) + if (_detailedMessages.add(player.getName())) { return true; } - - if (UtilInv.IsItem(player.getInventory().getArmorContents()[2], Material.ELYTRA, (byte) 0)) + else { - return true; - } - - //On Ground - if (groundValid) - { - if (UtilEnt.onBlock(player) || player.getLocation().getBlock().getType() != Material.AIR) - { - return true; - } - } - - if ((_ignore.containsKey(player) && System.currentTimeMillis() < _ignore.get(player))) - { - return true; - } - - return false; - } - - public void addSuspicion(Player player, String type) - { - if (!_enabled) - return; - - System.out.println(C.cRed + C.Bold + player.getName() + " suspected for " + type + "."); - - //Add Offense - if (!_offense.containsKey(player)) - _offense.put(player, new HashMap>()); - - if (!_offense.get(player).containsKey(type)) - _offense.get(player).put(type, new ArrayList()); - - _offense.get(player).get(type).add(System.currentTimeMillis()); - - //Cull & Count - int total = 0; - for (String curType : _offense.get(player).keySet()) - { - //Remove Old Offenses - Iterator offenseIterator = _offense.get(player).get(curType).iterator(); - while (offenseIterator.hasNext()) - { - if (UtilTime.elapsed(offenseIterator.next(), KeepOffensesFor)) - offenseIterator.remove(); - } - - //Count - total += _offense.get(player).get(curType).size(); - } - - // Print (Debug) - System.out.println("[Offense] #" + total + ": " + player.getName() + " received suspicion for " + type + "."); - } - - @EventHandler - public void generateReports(UpdateEvent event) - { - if (!_enabled) - return; - - if (event.getType() != UpdateType.SEC) - return; - - for (Iterator>>> playerIterator = _offense.entrySet().iterator(); playerIterator.hasNext(); ) - { - Entry>> entry = playerIterator.next(); - Player player = entry.getKey(); - - String out = ""; - int total = 0; - - for (String type : entry.getValue().keySet()) - { - //Remove Old Offenses - Iterator offenseIterator = entry.getValue().get(type).iterator(); - while (offenseIterator.hasNext()) - { - long time = offenseIterator.next(); - - if (UtilTime.elapsed(time, KeepOffensesFor)) - offenseIterator.remove(); - } - - //Count - int count = entry.getValue().get(type).size(); - total += count; - - out += count + " " + type + ", "; - } - - if (out.length() > 0) - out = out.substring(0, out.length() - 2); - - String severity = "Low"; - - if (total > (_strict ? 6 : 18)) - severity = "Extreme"; - else if (total > (_strict ? 4 : 12)) - severity = "High"; - else if (total > (_strict ? 2 : 6)) - severity = "Medium"; - - //Send Report - sendReport(player, out, severity); - - if (severity.equalsIgnoreCase("Extreme")) - { - playerIterator.remove(); - resetAll(player, false); - } + _detailedMessages.remove(player.getName()); + return false; } } @@ -990,13 +350,11 @@ public class AntiHack extends MiniPlugin if (_ignoredChecks.contains(event.getCheckClass())) return; + ACTIONS.getOrDefault(event.getCheckClass(), NOOP_ACTION).handle(event); + if (event.shouldTellStaff()) { - CheckThresholds thresholds = CHECKS.get(event.getHackType()); - if (thresholds == null) - { - thresholds = new CheckThresholds(event.getHackType(), 0, Integer.MAX_VALUE, Integer.MAX_VALUE); - } + CheckThresholds thresholds = CHECKS.getOrDefault(event.getCheckClass(), NOOP_THRESHOLD); CheckThresholds.Severity severity = thresholds.getSeverity(event.getViolations()); if (severity == CheckThresholds.Severity.NONE) @@ -1007,18 +365,9 @@ public class AntiHack extends MiniPlugin String key = event.getPlayer().getName() + "." + event.getHackType() + "." + severity.toString(); Integer pastVl = this._cooldown.getIfPresent(key); - if (pastVl != null) + if (pastVl == null) { - if (event.getViolations() - pastVl > VL_DIFF_BEFORE_RENOTIFY) - { - this._cooldown.put(key, event.getViolations()); - MajorViolationCommand command = new MajorViolationCommand(_thisServer, event.getPlayer().getName(), event.getHackType(), event.getViolations(), event.getMessage()); - ServerCommandManager.getInstance().publishCommand(command); - } - } - else - { - MajorViolationCommand command = new MajorViolationCommand(_thisServer, event.getPlayer().getName(), event.getHackType(), event.getViolations(), event.getMessage()); + MajorViolationCommand command = new MajorViolationCommand(_thisServer, event.getPlayer().getName(), CheckManager.getCheckSimpleName(event.getCheckClass()), event.getViolations(), event.getMessage()); ServerCommandManager.getInstance().publishCommand(command); this._cooldown.put(key, event.getViolations()); @@ -1026,138 +375,10 @@ public class AntiHack extends MiniPlugin } } - public void sendReport(Player player, String report, String severity) - { - if (severity.equals("Extreme")) - { - //Staff - boolean handled = false; - for (Player staff : UtilServer.getPlayers()) - { - if (_clientManager.Get(staff).GetRank().has(Rank.MODERATOR)) - { - UtilPlayer.message(staff, C.cAqua + C.Scramble + "A" + ChatColor.RESET + C.cRed + C.Bold + " MAC > " + ChatColor.RESET + C.cYellow + report); - UtilPlayer.message(staff, C.cAqua + C.Scramble + "A" + ChatColor.RESET + C.cRed + C.Bold + " MAC > " + ChatColor.RESET + C.cGold + player.getName() + C.cYellow + " has extreme violation."); - - handled = true; - } - } - - //Record - ServerListPingEvent event = new ServerListPingEvent(null, Bukkit.getServer().getMotd(), Bukkit.getServer().getOnlinePlayers().size(), Bukkit.getServer().getMaxPlayers()); - getPluginManager().callEvent(event); - - String motd = event.getMotd(); - String game = "N/A"; - String map = "N/A"; - - String[] args = motd.split("\\|"); - - if (args.length > 0) - motd = args[0]; - - if (args.length > 2) - game = args[2]; - - if (args.length > 3) - map = args[3]; - - _repository.saveOffense(player, motd, game, map, report); - } - } - - private void reset() - { - for (Player player : UtilServer.getPlayers()) - resetAll(player); - } - - private void resetAll(Player player) - { - resetAll(player, true); - } - - private void resetAll(Player player, boolean removeOffenses) - { - _ignore.remove(player); - _velocityEvent.remove(player); - _lastMoveEvent.remove(player); - - if (removeOffenses) - _offense.remove(player); - - for (Detector detector : _movementDetectors) - detector.Reset(player); - - for (Detector detector : _combatDetectors) - detector.Reset(player); - } - - @EventHandler - public void cleanupPlayers(UpdateEvent event) - { - if (!_enabled) - return; - - if (event.getType() != UpdateType.SLOW) - return; - - for (Iterator> playerIterator = _ignore.entrySet().iterator(); playerIterator.hasNext(); ) - { - Player player = playerIterator.next().getKey(); - - if (!player.isOnline() || player.isDead() || !player.isValid()) - { - playerIterator.remove(); - - _velocityEvent.remove(player); - _lastMoveEvent.remove(player); - - _offense.remove(player); - - for (Detector detector : _movementDetectors) - detector.Reset(player); - - for (Detector detector : _combatDetectors) - detector.Reset(player); - } - } - - - for (Iterator playerIterator = _hubAttempted.iterator(); playerIterator.hasNext(); ) - { - Player player = playerIterator.next(); - - if (!player.isOnline() || !player.isValid()) - { - playerIterator.remove(); - } - } - } - - public void setEnabled(boolean b) - { - _enabled = b; - System.out.println("MAC Enabled: " + b); - } - - public boolean isEnabled() - { - return _enabled; - } - - public void setStrict(boolean strict) - { - _strict = strict; - - reset(); - - System.out.println("MAC Strict: " + strict); - } - /** * Add a GWEN Anticheat class to the ignored checks. * All violation events for these checks will be ignored + * * @param check The class of the check to ignore */ public void addIgnoredCheck(Class check) @@ -1174,27 +395,63 @@ public class AntiHack extends MiniPlugin _ignoredChecks.clear(); } - public boolean isStrict() - { - return _strict; - } - - public void setKick(boolean kick) - { - _kick = kick; - - System.out.println("MAC Kick: " + kick); - } - - public void enableNewAnticheat() + public void enableAnticheat() { UtilServer.CallEvent(new GameStartEvent()); - System.out.println("Enabled new anticheat"); } - public void disableNewAnticheat() + public void disableAnticheat() { UtilServer.CallEvent(new GameEndEvent()); - System.out.println("Disabled new anticheat"); + } + + private BaseComponent[] getDetailedMessage(MajorViolationCommand violation) + { + return new ComponentBuilder("") + .append("A").color(ChatColor.AQUA).obfuscated(true) + .append(" GWEN > ", ComponentBuilder.FormatRetention.NONE).color(ChatColor.RED).bold(true) + .append(violation.getPlayerName(), ComponentBuilder.FormatRetention.NONE).color(ChatColor.GOLD) + .append(" failed " + violation.getHackType() + " VL" + violation.getViolations() + " in server", ComponentBuilder.FormatRetention.NONE).color(ChatColor.YELLOW) + .append(violation.getOriginatingServer(), ComponentBuilder.FormatRetention.NONE).color(ChatColor.YELLOW) + .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/server " + violation.getOriginatingServer())) + .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder("Teleport to " + violation.getOriginatingServer()).create())) + .append(": " + violation.getMessage() + ".", ComponentBuilder.FormatRetention.NONE).color(ChatColor.YELLOW) + .create(); + } + + private BaseComponent[] getMinimalMessage(MajorViolationCommand violation) + { + Class checkType = CheckManager.getCheckBySimpleName(violation.getHackType()); + if (!CHECKS.containsKey(checkType)) + { + System.out.println("Warning: Unknown check type '" + violation.getHackType() + "' " + checkType); + } + ComponentBuilder componentBuilder = new ComponentBuilder("") + .append("A").color(ChatColor.AQUA).obfuscated(true) + .append(" GWEN > ", ComponentBuilder.FormatRetention.NONE).color(ChatColor.RED).bold(true) + .append(violation.getPlayerName(), ComponentBuilder.FormatRetention.NONE).color(ChatColor.GOLD) + .append(" suspected of ", ComponentBuilder.FormatRetention.NONE).color(ChatColor.YELLOW); + CHECKS.getOrDefault(checkType, NOOP_THRESHOLD).format(componentBuilder, violation.getViolations()); + + if (!violation.getOriginatingServer().equals(this._thisServer)) + { + componentBuilder.append(" in ", ComponentBuilder.FormatRetention.NONE).color(ChatColor.YELLOW) + .append(violation.getOriginatingServer()).color(ChatColor.AQUA) + .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/server " + violation.getOriginatingServer())) + .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder("Teleport to " + violation.getOriginatingServer()).create())); + } + + componentBuilder.append(".").color(ChatColor.YELLOW); + + return componentBuilder.create(); + } + + public static String generateId() + { + byte[] holder = new byte[ID_LENGTH]; + ThreadLocalRandom.current().nextBytes(holder); + return DatatypeConverter.printHexBinary(holder); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackRepository.java deleted file mode 100644 index eb3b3cd0c..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackRepository.java +++ /dev/null @@ -1,71 +0,0 @@ -package mineplex.core.antihack; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import mineplex.serverdata.database.DBPool; - -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; - -public class AntiHackRepository -{ - private String _serverName; - - //private static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS AntiHack_Kick_Log (id INT NOT NULL AUTO_INCREMENT, updated LONG, playerName VARCHAR(256), motd VARCHAR(56), gameType VARCHAR(56), map VARCHAR(256), serverName VARCHAR(256), report VARCHAR(256), ping VARCHAR(25), PRIMARY KEY (id));"; - private static String UPDATE_PLAYER_OFFENSES = "INSERT INTO AntiHack_Kick_Log (updated, playerName, motd, gameType, map, serverName, report, ping) VALUES (now(), ?, ?, ?, ?, ?, ?, ?);"; - - public AntiHackRepository(String serverName) - { - _serverName = serverName; - } - - public void initialize() - { - } - - public void saveOffense(final Player player, final String motd, final String game, final String map, final String report) - { - new Thread(new Runnable() - { - public void run() - { - PreparedStatement preparedStatement = null; - - try (Connection connection = DBPool.getMineplexStats().getConnection()) - { - preparedStatement = connection.prepareStatement(UPDATE_PLAYER_OFFENSES); - - preparedStatement.setString(1, player.getName()); - preparedStatement.setString(2, motd); - preparedStatement.setString(3, game); - preparedStatement.setString(4, map); - preparedStatement.setString(5, _serverName); - preparedStatement.setString(6, report); - preparedStatement.setString(7, ((CraftPlayer)player).getHandle().ping + "ms"); - - preparedStatement.execute(); - } - catch (Exception exception) - { - exception.printStackTrace(); - } - finally - { - if (preparedStatement != null) - { - try - { - preparedStatement.close(); - } - catch (SQLException e) - { - e.printStackTrace(); - } - } - } - } - }).start(); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/CheckThresholds.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/CheckThresholds.java index f64783e55..590739775 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/CheckThresholds.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/CheckThresholds.java @@ -1,5 +1,7 @@ package mineplex.core.antihack; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.ComponentBuilder; import net.minecraft.server.v1_8_R3.ChatComponentText; import net.minecraft.server.v1_8_R3.ChatModifier; import net.minecraft.server.v1_8_R3.EnumChatFormat; @@ -25,10 +27,9 @@ public class CheckThresholds return _friendlyName; } - public IChatBaseComponent format(int violationLevel) + public void format(ComponentBuilder builder, int violationLevel) { - EnumChatFormat color = getSeverity(violationLevel)._color; - return new ChatComponentText(_friendlyName).setChatModifier(new ChatModifier().setColor(color)); + builder.append(_friendlyName, ComponentBuilder.FormatRetention.NONE).color(getSeverity(violationLevel)._color); } public Severity getSeverity(int violationLevel) @@ -51,14 +52,14 @@ public class CheckThresholds public enum Severity { - NONE(EnumChatFormat.GREEN), - LOW(EnumChatFormat.GREEN), - MEDIUM(EnumChatFormat.GOLD), - HIGH(EnumChatFormat.RED), + NONE(ChatColor.GREEN), + LOW(ChatColor.GREEN), + MEDIUM(ChatColor.GOLD), + HIGH(ChatColor.RED), ; - private final EnumChatFormat _color; + private final ChatColor _color; - Severity(EnumChatFormat color) + Severity(ChatColor color) { _color = color; } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/Detector.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/Detector.java deleted file mode 100644 index 5cfec165e..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/Detector.java +++ /dev/null @@ -1,8 +0,0 @@ -package mineplex.core.antihack; - -import org.bukkit.entity.Player; - -public interface Detector -{ - public void Reset(Player player); -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/MineplexLinkImpl.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/MineplexLinkImpl.java new file mode 100644 index 000000000..6195a3fd2 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/MineplexLinkImpl.java @@ -0,0 +1,50 @@ +package mineplex.core.antihack; + +import net.minecraft.server.v1_8_R3.MinecraftServer; + +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; + +import com.mineplex.anticheat.api.MineplexLink; + +import mineplex.core.Managers; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.disguises.DisguiseBase; + +public class MineplexLinkImpl implements MineplexLink +{ + private final DisguiseManager _disguiseManager = Managers.require(DisguiseManager.class); + + @Override + public EntityType getActiveDisguise(Player player) + { + DisguiseBase disguise = _disguiseManager.getActiveDisguise(player); + return disguise != null ? disguise.getDisguiseType() : null; + } + + @Override + public boolean isSpectator(Player player) + { + return UtilPlayer.isSpectator(player); + } + + @Override + public double getTPS() + { + return MinecraftServer.getServer().recentTps[0]; // Return the average TPS from the last minute + } + + @Override + public int getPing(Player player) + { + return Math.min(((CraftPlayer) player).getHandle().ping, 1000); + } + + @Override + public boolean isUsingItem(Player player) + { + return ((CraftPlayer) player).getHandle().bS(); // See Anticheat javadoc + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/ViolationLevels.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/ViolationLevels.java new file mode 100644 index 000000000..00a800bce --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/ViolationLevels.java @@ -0,0 +1,87 @@ +package mineplex.core.antihack; + +import com.mineplex.anticheat.checks.Check; +import com.mineplex.anticheat.checks.CheckManager; + +import gnu.trove.map.TObjectIntMap; +import gnu.trove.map.hash.TObjectIntHashMap; + +/** + * Locally cached information about a user's max violations and total number of alerts for each + * check type. + *

+ * Instances of this have no concept of identity i.e. account id is not tracked by this. + */ +public class ViolationLevels +{ + private final TObjectIntMap> _maxViolations; + + private final TObjectIntMap> _totalAlerts; + + private final TObjectIntMap> _lastBan; + + public ViolationLevels() + { + _maxViolations = new TObjectIntHashMap<>(CheckManager.AVAILABLE_CHECKS.size()); + _totalAlerts = new TObjectIntHashMap<>(CheckManager.AVAILABLE_CHECKS.size()); + _lastBan = new TObjectIntHashMap<>(CheckManager.AVAILABLE_CHECKS.size()); + } + + public void updateMaxViolations(Class check, int violationLevel) + { + if (violationLevel > _maxViolations.get(check)) + { + _maxViolations.put(check, violationLevel); + } + } + + public void updateMaxViolationsSinceLastBan(Class check, int violationLevel) + { + if (violationLevel > _lastBan.get(check)) + { + _lastBan.put(check, violationLevel); + } + } + + public void incrementAlerts(Class check) + { + int cur = _totalAlerts.get(check); + + setTotalAlerts(check, cur + 1); + } + + public void setTotalAlerts(Class check, int totalAlerts) + { + _totalAlerts.put(check, totalAlerts); + } + + public int getTotalAlertsForCheck(Class check) + { + if (_totalAlerts.containsKey(check)) + { + return _totalAlerts.get(check); + } + + return -1; + } + + public int getMaxViolationsForCheck(Class check) + { + if (_maxViolations.containsKey(check)) + { + return _maxViolations.get(check); + } + + return -1; + } + + public int getLastBanViolationsForCheck(Class check) + { + if (_lastBan.containsKey(check)) + { + return _lastBan.get(check); + } + + return -1; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/AntiHackAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/AntiHackAction.java index ddcc5e909..c919bba58 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/AntiHackAction.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/AntiHackAction.java @@ -4,6 +4,7 @@ import com.mineplex.anticheat.api.PlayerViolationEvent; import com.mineplex.anticheat.checks.combat.KillauraTypeA; import com.mineplex.anticheat.checks.combat.KillauraTypeD; import com.mineplex.anticheat.checks.move.Glide; +import com.mineplex.anticheat.checks.move.HeadRoll; import com.mineplex.anticheat.checks.move.Speed; import mineplex.core.common.util.UtilServer; import org.bukkit.event.Listener; @@ -13,40 +14,19 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; -public abstract class AntiHackAction implements Listener +public abstract class AntiHackAction { - private static final Map, AntiHackAction> ACTIONS = new HashMap<>(); - private static final AntiHackAction NOOP_ACTION = new NoopAction(); - - private static final Date NEXT_BAN_WAVE = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5)); - - static - { - ACTIONS.put(KillauraTypeA.class, new ImmediateBanAction(200)); - ACTIONS.put(KillauraTypeD.class, new BanwaveAction(2000)); - ACTIONS.put(Glide.class, new ImmediateBanAction(10000)); - ACTIONS.put(Speed.class, new ImmediateBanAction(10000)); - } - - private int _vl; + private final int _vl; AntiHackAction(int vl) { this._vl = vl; - - UtilServer.RegisterEvents(this); } - public abstract void handle(PlayerViolationEvent event); - - public int getMinVl() + public final int getMinVl() { return this._vl; } - public static AntiHackAction getAction(Class checkClass) - { - AntiHackAction action = ACTIONS.getOrDefault(checkClass, NOOP_ACTION); - return action; - } + public abstract void handle(PlayerViolationEvent event); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/BanwaveAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/BanwaveAction.java index 876671029..24408afe9 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/BanwaveAction.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/BanwaveAction.java @@ -1,17 +1,18 @@ package mineplex.core.antihack.actions; import com.mineplex.anticheat.api.PlayerViolationEvent; + import mineplex.core.Managers; import mineplex.core.antihack.banwave.BanWaveManager; import mineplex.core.common.util.UtilMath; import mineplex.core.common.util.UtilServer; -class BanwaveAction extends AntiHackAction +public class BanwaveAction extends AntiHackAction { private static final int BAN_DELAY_AVERAGE = 6 * 60 * 60 * 1000; // 6 hours private static final int BAN_DELAY_VARIANCE_SPAN = 4 * 60 * 60 * 1000; // 4 hours total; 2 on either side - BanwaveAction(int vl) + public BanwaveAction(int vl) { super(vl); } @@ -27,7 +28,6 @@ class BanwaveAction extends AntiHackAction event.getPlayer(), banTime, event.getCheckClass(), - "[GWEN] Hacking [BanWave]", event.getViolations(), UtilServer.getServerName() ); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/ImmediateBanAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/ImmediateBanAction.java index ce6eeaf08..a06b38daf 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/ImmediateBanAction.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/ImmediateBanAction.java @@ -5,9 +5,9 @@ import mineplex.core.Managers; import mineplex.core.antihack.AntiHack; import mineplex.core.common.util.UtilServer; -class ImmediateBanAction extends AntiHackAction +public class ImmediateBanAction extends AntiHackAction { - ImmediateBanAction(int vl) + public ImmediateBanAction(int vl) { super(vl); } @@ -17,12 +17,7 @@ class ImmediateBanAction extends AntiHackAction { if (event.getViolations() >= this.getMinVl()) { - String server = UtilServer.getServerName(); - if (server.contains("-")) - { - server = server.substring(0, server.indexOf('-')); - } - Managers.get(AntiHack.class).doBan(event.getPlayer(), "[GWEN] Hacking [" + server + "]"); + Managers.get(AntiHack.class).doBan(event.getPlayer(), event.getCheckClass()); } } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/MixedAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/MixedAction.java deleted file mode 100644 index 14066a4d7..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/MixedAction.java +++ /dev/null @@ -1,49 +0,0 @@ -package mineplex.core.antihack.actions; - -import com.mineplex.anticheat.api.PlayerViolationEvent; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -public class MixedAction extends AntiHackAction -{ - private List _actions = new ArrayList<>(); - private Map> _punished = new HashMap<>(); - - public MixedAction(AntiHackAction firstAction, AntiHackAction... actions) - { - super(firstAction.getMinVl()); - this._actions.add(firstAction); - this._actions.addAll(Arrays.asList(actions)); - } - - - @Override - public void handle(PlayerViolationEvent event) - { - for (int i = this._actions.size() - 1; i >= 0; i--) - { - AntiHackAction action = this._actions.get(i); - if (action.getMinVl() <= event.getViolations()) - { - if (_punished.computeIfAbsent(event.getPlayer().getUniqueId(), key -> new HashSet<>()).add(action)) - { - action.handle(event); - } - break; - } - } - } - - public int getMinVl() - { - return this._actions.get(0).getMinVl(); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/NoopAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/NoopAction.java index 38794c630..848322ac3 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/NoopAction.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/NoopAction.java @@ -4,7 +4,7 @@ import com.mineplex.anticheat.api.PlayerViolationEvent; public class NoopAction extends AntiHackAction { - NoopAction() + public NoopAction() { super(Integer.MAX_VALUE); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/animations/BanwaveAnimation.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/animations/BanwaveAnimation.java new file mode 100644 index 000000000..e3af1b117 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/animations/BanwaveAnimation.java @@ -0,0 +1,9 @@ +package mineplex.core.antihack.animations; + +import mineplex.core.antihack.AntiHack; +import org.bukkit.entity.Player; + +public interface BanwaveAnimation +{ + void run(Player player, Runnable after); +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/animations/BanwaveAnimationSpin.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/animations/BanwaveAnimationSpin.java new file mode 100644 index 000000000..3370f28f2 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/animations/BanwaveAnimationSpin.java @@ -0,0 +1,123 @@ +package mineplex.core.antihack.animations; + +import com.google.common.util.concurrent.AtomicDouble; +import mineplex.core.antihack.AntiHack; +import mineplex.core.antihack.guardians.AntiHackGuardian; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilServer; +import net.minecraft.server.v1_8_R3.MathHelper; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; + +public class BanwaveAnimationSpin implements BanwaveAnimation +{ + @Override + public void run(Player player, Runnable after) + { + float oldWalkSpeed = player.getWalkSpeed(); + player.setWalkSpeed(0); + player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 999999, -10)); + + double radius = 4; + double heightAdj = 8; + + double baseDeg = 18; + + Location center = player.getLocation().add(0, heightAdj, 0); + AntiHackGuardian north = new AntiHackGuardian(center.clone().add(0, 0, -radius), 0, 0, 0, 0, 0, 0, false); + AntiHackGuardian east = new AntiHackGuardian(center.clone().add(radius, 0, 0), 0, 0, 0, 0, 0, 0, false); + AntiHackGuardian south = new AntiHackGuardian(center.clone().add(0, 0, radius), 0, 0, 0, 0, 0, 0, false); + AntiHackGuardian west = new AntiHackGuardian(center.clone().add(-radius, 0, 0), 0, 0, 0, 0, 0, 0, false); + + UtilEnt.CreatureLook(east.getEntity(), player); + UtilEnt.CreatureLook(west.getEntity(), player); + UtilEnt.CreatureLook(south.getEntity(), player); + UtilEnt.CreatureLook(north.getEntity(), player); + + Function magic = seconds -> Math.pow(2, seconds - 5); + + UtilServer.runSyncLater(() -> + { + north.shoot(player); + east.shoot(player); + south.shoot(player); + west.shoot(player); + + // We get 5 seconds, or 100 ticks + AtomicInteger timer = new AtomicInteger(5); + + AtomicDouble cNorth = new AtomicDouble(270); + AtomicDouble cEast = new AtomicDouble(0); + AtomicDouble cSouth = new AtomicDouble(90); + AtomicDouble cWest = new AtomicDouble(180); + + UtilServer.runSyncTimer(new BukkitRunnable() + { + public void run() + { + timer.getAndIncrement(); + if (timer.get() > 100) + { + cancel(); + + player.removePotionEffect(PotionEffectType.JUMP); + player.setWalkSpeed(oldWalkSpeed); + Location location = player.getLocation(); + + UtilParticle.PlayParticle(UtilParticle.ParticleType.HUGE_EXPLOSION, player.getLocation(), 3f, 3f, 3f, 0, 32, UtilParticle.ViewDist.MAX, UtilServer.getPlayers()); + + after.run(); + + north.shoot(null); + south.shoot(null); + east.shoot(null); + west.shoot(null); + UtilEnt.CreatureLook(north.getEntity(), location); + UtilEnt.CreatureLook(south.getEntity(), location); + UtilEnt.CreatureLook(east.getEntity(), location); + UtilEnt.CreatureLook(west.getEntity(), location); + UtilServer.runSyncLater(() -> + { + north.remove(); + south.remove(); + east.remove(); + west.remove(); + }, 40L); + return; + } + + double seconds = timer.get() / 20.0; + + double rate = magic.apply(seconds) * 3 * baseDeg; + + player.getLocation(center); + center.add(0, heightAdj, 0); + + { + cNorth.addAndGet(rate); + north.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cNorth.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cNorth.get()))); + } + { + cSouth.addAndGet(rate); + south.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cSouth.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cSouth.get()))); + } + { + cEast.addAndGet(rate); + east.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cEast.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cEast.get()))); + } + { + cWest.addAndGet(rate); + west.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cWest.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cWest.get()))); + } + } + }, 5L, 1L); + }, 20); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveManager.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveManager.java index dd2bebe96..7349cde03 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveManager.java @@ -5,14 +5,25 @@ import mineplex.core.ReflectivelyCreateMiniPlugin; import mineplex.core.account.CoreClient; import mineplex.core.account.CoreClientManager; import mineplex.core.antihack.AntiHack; +import mineplex.core.antihack.logging.AntihackLogger; +import mineplex.core.antihack.redisnotifications.GwenBanwaveNotification; +import mineplex.core.common.util.UtilServer; +import mineplex.serverdata.commands.ServerCommandManager; + +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerJoinEvent; +import com.google.gson.JsonObject; +import com.mineplex.anticheat.checks.Check; +import com.mineplex.anticheat.checks.CheckManager; + @ReflectivelyCreateMiniPlugin public class BanWaveManager extends MiniPlugin { private final BanWaveRepository _repository = new BanWaveRepository(); + private final CoreClientManager _clientManager = require(CoreClientManager.class); private BanWaveManager() { @@ -32,29 +43,39 @@ public class BanWaveManager extends MiniPlugin if (info.getTimeToBan() < now) { - require(AntiHack.class).doBanWave(event.getPlayer(), info.getMessage()); + require(AntiHack.class).doBanWave(event.getPlayer(), info); _repository.flagDone(info); } }); }); } - public void insertBanWaveInfo(Player player, long timeToBan, Class checkClass, String message, int vl, String server) + public void insertBanWaveInfo(Player player, long timeToBan, Class checkClass, int vl, String server) { - insertBanWaveInfo(player, timeToBan, checkClass, message, vl, server, null); + insertBanWaveInfo(player, timeToBan, checkClass, vl, server, null); } - public void insertBanWaveInfo(Player player, long timeToBan, Class checkClass, String message, int vl, String server, Runnable after) + public void insertBanWaveInfo(Player player, long timeToBan, Class checkClass, int vl, String server, Runnable after) { runAsync(() -> { - CoreClient client = require(CoreClientManager.class).Get(player); + String id = AntiHack.generateId(); + String newMessage = "[GWEN] [BanWave] " + id; - this._repository.insertBanWaveInfo(client.getAccountId(), timeToBan, checkClass.getName(), message, vl, server); + CoreClient client = _clientManager.Get(player); - if (after != null) + if (this._repository.insertBanWaveInfo(client.getAccountId(), timeToBan, CheckManager.getCheckSimpleName(checkClass), newMessage, vl, server)) { - after.run(); + runAsync(() -> + { + GwenBanwaveNotification notification = new GwenBanwaveNotification(UtilServer.getServerName(), player.getName(), player.getUniqueId().toString(), CheckManager.getCheckSimpleName(checkClass), id, timeToBan); + ServerCommandManager.getInstance().publishCommand(notification); + }); + + JsonObject custom = new JsonObject(); + custom.addProperty("is-banwave", true); + + require(AntihackLogger.class).saveMetadata(player, id, after, custom); } }); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveRepository.java index 1ddab86f0..baf39fe4e 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveRepository.java @@ -59,9 +59,9 @@ public class BanWaveRepository extends MinecraftRepository }, new ColumnInt("accountId", accountId)); } - void insertBanWaveInfo(int accountId, long timeToBan, String hackType, String message, int vl, String server) + boolean insertBanWaveInfo(int accountId, long timeToBan, String hackType, String message, int vl, String server) { - executeInsert(INSERT_PENDING, null, + int affectedRows = executeInsert(INSERT_PENDING, null, new ColumnInt("accountId", accountId), new ColumnLong("timeToBan", timeToBan), new ColumnVarChar("hacktype", 64, hackType), @@ -69,6 +69,7 @@ public class BanWaveRepository extends MinecraftRepository new ColumnInt("vl", vl), new ColumnVarChar("server", 32, server) ); + return affectedRows > 0; } void flagDone(BanWaveInfo info) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/AnticheatOffCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/AnticheatOffCommand.java new file mode 100644 index 000000000..a3d1f4267 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/AnticheatOffCommand.java @@ -0,0 +1,24 @@ +package mineplex.core.antihack.commands; + +import org.bukkit.entity.Player; + +import mineplex.core.antihack.AntiHack; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; + +public class AnticheatOffCommand extends CommandBase +{ + public AnticheatOffCommand(AntiHack plugin) + { + super(plugin, Rank.DEVELOPER, "acoff"); + } + + @Override + public void Execute(Player caller, String[] args) + { + Plugin.disableAnticheat(); + UtilPlayer.message(caller, F.main(Plugin.getName(), "Disabled anticheat")); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/AnticheatOnCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/AnticheatOnCommand.java new file mode 100644 index 000000000..7c1f3a767 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/AnticheatOnCommand.java @@ -0,0 +1,24 @@ +package mineplex.core.antihack.commands; + +import org.bukkit.entity.Player; + +import mineplex.core.antihack.AntiHack; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; + +public class AnticheatOnCommand extends CommandBase +{ + public AnticheatOnCommand(AntiHack plugin) + { + super(plugin, Rank.DEVELOPER, "acon"); + } + + @Override + public void Execute(Player caller, String[] args) + { + Plugin.enableAnticheat(); + UtilPlayer.message(caller, F.main(Plugin.getName(), "Enabled anticheat")); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/DetailedMessagesCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/DetailedMessagesCommand.java new file mode 100644 index 000000000..e873d22e8 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/DetailedMessagesCommand.java @@ -0,0 +1,30 @@ +package mineplex.core.antihack.commands; + +import org.bukkit.entity.Player; + +import mineplex.core.antihack.AntiHack; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; + +public class DetailedMessagesCommand extends CommandBase +{ + public DetailedMessagesCommand(AntiHack plugin) + { + super(plugin, Rank.DEVELOPER, "detailedmessages"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (Plugin.toggleDetailedMessage(caller)) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "Detailed messages enabled")); + } + else + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "Detailed messages disabled")); + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/GetVlsCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/GetVlsCommand.java new file mode 100644 index 000000000..84f32311b --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/GetVlsCommand.java @@ -0,0 +1,47 @@ +package mineplex.core.antihack.commands; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import com.mineplex.anticheat.MineplexAnticheat; +import com.mineplex.anticheat.checks.Check; +import com.mineplex.anticheat.checks.CheckManager; + +import mineplex.core.antihack.AntiHack; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; + +public class GetVlsCommand extends CommandBase +{ + public GetVlsCommand(AntiHack plugin) + { + super(plugin, Rank.DEVELOPER, "getvls"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length > 0) + { + Player p = Bukkit.getPlayerExact(args[0]); + if (p != null) + { + CheckManager manager = MineplexAnticheat.getPlugin(MineplexAnticheat.class).getCheckManager(); + for (Check check : manager.getActiveChecks()) + { + UtilPlayer.message(caller, F.desc(check.getName(), String.valueOf(check.getViolationLevel(p)))); + } + } + else + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "Could not find player")); + } + } + else + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "No player specified")); + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/TestBanCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/TestBanCommand.java new file mode 100644 index 000000000..40ac6c1aa --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/commands/TestBanCommand.java @@ -0,0 +1,51 @@ +package mineplex.core.antihack.commands; + +import java.util.concurrent.ThreadLocalRandom; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import mineplex.core.antihack.AntiHack; +import mineplex.core.antihack.animations.BanwaveAnimationSpin; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; + +public class TestBanCommand extends CommandBase +{ + public TestBanCommand(AntiHack plugin) + { + super(plugin, Rank.DEVELOPER, "testban"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length > 0) + { + Player p = Bukkit.getPlayerExact(args[0]); + if (p != null) + { + new BanwaveAnimationSpin().run(p, () -> + { + String reason = C.cRed + C.Bold + "You are banned for permanent by Test" + + "\n" + C.cWhite + "Seems to be speeding up time. (" + ThreadLocalRandom.current().nextInt(200, 400) + " packets/150 ms)" + + "\n" + C.cDGreen + "Unfairly banned? Appeal at " + C.cGreen + "www.mineplex.com/appeals"; + p.kickPlayer(reason); + + Plugin.announceBan(p); + }); + } + else + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "Could not find player")); + } + } + else + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "No player specified")); + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackGuardian.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/guardians/AntiHackGuardian.java similarity index 99% rename from Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackGuardian.java rename to Plugins/Mineplex.Core/src/mineplex/core/antihack/guardians/AntiHackGuardian.java index 9cff0ce43..cb9ef2898 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackGuardian.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/guardians/AntiHackGuardian.java @@ -1,4 +1,4 @@ -package mineplex.core.antihack; +package mineplex.core.antihack.guardians; import com.mineplex.spigot.ChunkAddEntityEvent; import mineplex.core.Managers; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/guardians/GuardianManager.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/guardians/GuardianManager.java new file mode 100644 index 000000000..a5806e753 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/guardians/GuardianManager.java @@ -0,0 +1,129 @@ +package mineplex.core.antihack.guardians; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import mineplex.core.MiniPlugin; +import mineplex.core.PlayerSelector; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.Rank; +import mineplex.core.common.util.UtilLambda; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +@ReflectivelyCreateMiniPlugin +public class GuardianManager extends MiniPlugin +{ + private static final int MAX_STALKED_PLAYERS = 3; + private static final int STALK_COOLDOWN_TIME_SECONDS = 5; + + private static final int MIN_STALK_TIME = 10 * 20; + private static final int MAX_STALK_TIME = 20 * 20; + private static final int MAX_MIN_DIFF = MAX_STALK_TIME - MIN_STALK_TIME; + private static final Function STALK_END_PROBABILITY_EQUATION = x -> + { + return 1.0/ MAX_MIN_DIFF * x; // linear equation with points (0, 0) and (diff, 1) + }; + + private final Cache _stalkingCooldown = CacheBuilder.newBuilder() + .concurrencyLevel(1) + .expireAfterWrite(STALK_COOLDOWN_TIME_SECONDS, TimeUnit.SECONDS) + .build(); + private final List _stalking = new ArrayList<>(); + private List _guardians = new ArrayList<>(); + + private GuardianManager() + { + super("GuardianManager"); + + this._plugin.getServer().getScheduler().runTaskTimer(this._plugin, () -> + { + for (AntiHackGuardian guardian : this._guardians) + { + if (guardian.getTarget() != null && !guardian.getTarget().isOnline()) + { + this._stalking.remove(guardian.getTarget().getUniqueId()); + guardian.stopTargeting(); + } + else if (guardian.getTargetingTime() > MIN_STALK_TIME) + { + double threshold = STALK_END_PROBABILITY_EQUATION.apply(guardian.getTargetingTime() - MIN_STALK_TIME); + if (Math.random() <= threshold) + { + this._stalking.remove(guardian.getTarget().getUniqueId()); + _stalkingCooldown.put(guardian.getTarget().getUniqueId(), true); + guardian.stopTargeting(); + } + } + guardian.tick(); + } + }, 0L, 1L); + + this._plugin.getServer().getScheduler().runTaskTimer(this._plugin, () -> + { + if (_stalking.size() >= MAX_STALKED_PLAYERS) + { + return; + } + + if (_guardians.size() == 0) + { + return; + } + + List targets = PlayerSelector.selectPlayers( + UtilLambda.and( + PlayerSelector.NOT_VANISHED, + PlayerSelector.hasAnyRank(false, + Rank.ALL, + Rank.ULTRA, + Rank.HERO, + Rank.LEGEND, + Rank.TITAN, + Rank.TWITCH, + Rank.YOUTUBE_SMALL, + Rank.YOUTUBE, + Rank.MEDIA, + Rank.ADMIN, + Rank.DEVELOPER, + Rank.OWNER, + Rank.LT + ), + player -> !_stalking.contains(player.getUniqueId()), + player -> _stalkingCooldown.getIfPresent(player.getUniqueId()) == null + )); + + while (_stalking.size() < MAX_STALKED_PLAYERS && targets.size() > 0) + { + Player target = targets.remove(ThreadLocalRandom.current().nextInt(targets.size())); + + int start = ThreadLocalRandom.current().nextInt(_guardians.size()); + + for (int i = start, j = 0; j < _guardians.size(); i++, j++) + { + if (i >= _guardians.size()) + { + i -= _guardians.size(); + } + AntiHackGuardian guardian = _guardians.get(i); + if (!guardian.isTargeting()) + { + guardian.target(target); + _stalking.add(target.getUniqueId()); + break; + } + } + } + }, 0L, 20L); + } + + public void registerGuardian(AntiHackGuardian guardian) + { + this._guardians.add(guardian); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AnticheatDatabase.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AnticheatDatabase.java new file mode 100644 index 000000000..8d2f78421 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AnticheatDatabase.java @@ -0,0 +1,196 @@ +package mineplex.core.antihack.logging; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; +import java.util.Optional; + +import org.bukkit.plugin.java.JavaPlugin; + +import com.mineplex.anticheat.checks.Check; +import com.mineplex.anticheat.checks.CheckManager; + +import mineplex.core.antihack.ViolationLevels; +import mineplex.core.database.MinecraftRepository; +import mineplex.serverdata.database.DBPool; + +import gnu.trove.map.TIntObjectMap; + +public class AnticheatDatabase extends MinecraftRepository +{ + /* + CREATE TABLE IF NOT EXISTS anticheat_vl_logs (accountId INT, checkId INT, maxViolations INT, totalAlerts INT, sinceLastBan INT, PRIMARY KEY(accountId, checkId)); + CREATE TABLE IF NOT EXISTS anticheat_ban_metadata (id INT NOT NULL AUTO_INCREMENT, accountId INT, banId CHAR(10) NOT NULL, data MEDIUMTEXT NOT NULL, PRIMARY KEY(id)); + */ + + private static final String INSERT_INTO_METADATA = "INSERT INTO anticheat_ban_metadata (accountId, banId, data) VALUES (?, ?, ?);"; + + private static final String UPDATE_VIOLATIONS = "INSERT INTO anticheat_vl_logs (accountId, checkId, " + + "maxViolations, sinceLastBan, totalAlerts) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY" + + " UPDATE maxViolations = VALUES(maxViolations), totalAlerts = VALUES(totalAlerts), sinceLastBan = VALUES(sinceLastBan);"; + + private static final String CLEAR_LAST_BAN_VIOLATIONS = "UPDATE anticheat_vl_logs SET sinceLastBan = 0 WHERE accountId = ?;"; + + private static final String GET_VLS = "SELECT checkId, maxViolations, sinceLastBan, totalAlerts FROM anticheat_vl_logs"; + + private static final String GET_VLS_BY_ACCOUNT_ID = GET_VLS + " WHERE accountId = ?"; + + private static final String GET_VLS_FOR_CHECK = GET_VLS + " WHERE checkId = ? AND accountId = ?"; + + + public AnticheatDatabase(JavaPlugin plugin) + { + super(DBPool.getAccount()); + } + + /** + * Submit a set of user violation changes batch style. + * + * @param uploadQueue the {@link TIntObjectMap} describing the changes. + */ + public void saveViolationLevels(Map uploadQueue) + { + try (Connection connection = getConnection()) + { + PreparedStatement preparedStatement = connection.prepareStatement(UPDATE_VIOLATIONS); + + uploadQueue.forEach((accountId, vls) -> + { + CheckManager.AVAILABLE_CHECKS.values().forEach(check -> + { + int checkId = CheckManager.getCheckId(check), + maxVls = vls.getMaxViolationsForCheck(check), + maxVlsSinceLastBan = vls.getLastBanViolationsForCheck(check), + totalAlerts = vls.getTotalAlertsForCheck(check); + + // if neither value has been set don't store anything + if (maxVls < 0 && totalAlerts < 0 && maxVlsSinceLastBan < 0) + { + return; + } + + maxVls = Math.max(maxVls, 0); + maxVlsSinceLastBan = Math.max(maxVlsSinceLastBan, 0); + totalAlerts = Math.max(totalAlerts, 0); + + try + { + preparedStatement.setInt(1, accountId); + preparedStatement.setInt(2, checkId); + preparedStatement.setInt(3, maxVls); + preparedStatement.setInt(4, maxVlsSinceLastBan); + preparedStatement.setInt(5, totalAlerts); + preparedStatement.addBatch(); + } + catch (SQLException e) + { + e.printStackTrace(); + } + }); + }); + + preparedStatement.executeBatch(); + } + catch (SQLException ex) + { + ex.printStackTrace(); + } + } + + /** + * Attempts to retrieve violation levels for the given account id. + * + * @param accountId The account id; + * @return an {@link Optional} describing the user's violation levels, or an empty one if none + * are found. + * @throws SQLException On failing to connect to the database. + */ + public Optional getViolationLevels(int accountId) + { + ViolationLevels levels = new ViolationLevels(); + + try (Connection connection = getConnection()) + { + PreparedStatement statement = connection.prepareStatement(GET_VLS_BY_ACCOUNT_ID); + statement.setInt(1, accountId); + + ResultSet result = statement.executeQuery(); + + while (result.next()) + { + int checkId = result.getInt("checkId"); + Class checkType = CheckManager.getCheckById(checkId); + if (checkType == null) + { + System.err.println("Whoops. Unintended refactor?"); + continue; + } + levels.updateMaxViolations(checkType, result.getInt("maxViolations")); + levels.updateMaxViolationsSinceLastBan(checkType, result.getInt("sinceLastBan")); + levels.setTotalAlerts(checkType, result.getInt("totalAlerts")); + } + } + catch (SQLException ex) + { + ex.printStackTrace(); + } + + return Optional.of(levels); + } + + public void clearLastBan(int accountId, Runnable after) + { + try (Connection connection = getConnection()) + { + PreparedStatement statement = connection.prepareStatement(CLEAR_LAST_BAN_VIOLATIONS); + statement.setInt(1, accountId); + + statement.executeUpdate(); + } + catch (SQLException e) + { + e.printStackTrace(); + } + finally + { + if (after != null) + after.run(); + } + } + + public void saveMetadata(int accountId, String id, String base64, Runnable after) + { + try (Connection connection = getConnection()) + { + PreparedStatement statement = connection.prepareStatement(INSERT_INTO_METADATA); + statement.setInt(1, accountId); + statement.setString(2, id); + statement.setString(3, base64); + + statement.executeUpdate(); + } + catch (SQLException ex) + { + ex.printStackTrace(); + } + finally + { + if (after != null) + after.run(); + } + } + + @Override + protected void initialize() + { + + } + + @Override + protected void update() + { + + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AnticheatMetadata.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AnticheatMetadata.java new file mode 100644 index 000000000..dc015a66a --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AnticheatMetadata.java @@ -0,0 +1,23 @@ +package mineplex.core.antihack.logging; + +import java.util.UUID; + +import org.bukkit.event.Listener; + +import com.google.gson.JsonElement; + +import mineplex.core.common.util.UtilServer; + +public abstract class AnticheatMetadata implements Listener +{ + public AnticheatMetadata() + { + UtilServer.RegisterEvents(this); + } + + public abstract String getId(); + + public abstract JsonElement build(UUID player); + + public abstract void remove(UUID player); +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AntihackLogger.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AntihackLogger.java new file mode 100644 index 000000000..2a9a628c8 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/AntihackLogger.java @@ -0,0 +1,214 @@ +package mineplex.core.antihack.logging; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.tukaani.xz.LZMA2Options; +import org.tukaani.xz.XZ; +import org.tukaani.xz.XZOutputStream; + +import com.google.gson.Gson; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.mineplex.anticheat.api.PlayerViolationEvent; +import com.mineplex.anticheat.checks.Check; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClientManager; +import mineplex.core.antihack.AntiHack; +import mineplex.core.antihack.ViolationLevels; +import mineplex.core.antihack.logging.builtin.PartyInfoMetadata; +import mineplex.core.antihack.logging.builtin.PlayerInfoMetadata; +import mineplex.core.antihack.logging.builtin.ServerInfoMetadata; +import mineplex.core.antihack.logging.builtin.ViolationInfoMetadata; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; + +@ReflectivelyCreateMiniPlugin +public class AntihackLogger extends MiniPlugin +{ + public static final Gson GSON = new Gson(); + + private static final int PUSH_QUEUE_TIME_IN_SECONDS = 60; + + private final CoreClientManager _clientManager = require(CoreClientManager.class); + + private final Map _violationLevels = new ConcurrentHashMap<>(); + + private final Map _metadata = new HashMap<>(); + + private final AnticheatDatabase _db; + + private AntihackLogger() + { + super("AnticheatPlugin"); + + _db = new AnticheatDatabase(getPlugin()); + + runSyncTimer(this::pushQueuedViolationChanges, 20, 20 * PUSH_QUEUE_TIME_IN_SECONDS); + + registerMetadata(new ServerInfoMetadata()); + registerMetadata(new ViolationInfoMetadata()); + registerMetadata(new PartyInfoMetadata()); + registerMetadata(new PlayerInfoMetadata()); + } + + @Override + public void disable() + { + pushQueuedViolationChanges(); + } + + @EventHandler + public void addCommands() + { + if (UtilServer.isTestServer()) + { + addCommand(new CommandBase(this, Rank.SNR_MODERATOR, "savemetadata") + { + @Override + public void Execute(Player caller, String[] args) + { + if (args.length == 1) + { + Player player = Bukkit.getPlayer(args[0]); + if (player != null) + { + JsonObject custom = new JsonObject(); + custom.addProperty("is-test-metadata", true); + String id = AntiHack.generateId(); + saveMetadata(player, id, () -> + { + UtilPlayer.message(caller, F.main(getName(), "Saved metadata for " + player.getName() + " with id " + id)); + }, custom); + } + } + } + }); + } + } + + private void pushQueuedViolationChanges() + { + Map clone = new HashMap<>(_violationLevels); + runAsync(() -> _db.saveViolationLevels(clone)); + } + + @EventHandler + public void onCheckFail(PlayerViolationEvent event) + { + ViolationLevels playerVls = _violationLevels.get(_clientManager.getAccountId(event.getPlayer())); + Class check = event.getCheckClass(); + playerVls.updateMaxViolations(check, event.getViolations()); + playerVls.updateMaxViolationsSinceLastBan(check, event.getViolations()); + playerVls.incrementAlerts(check); + } + + @EventHandler + public void onLoad(PlayerLoginEvent event) + { + runAsync(() -> + { + int accountId = _clientManager.getAccountId(event.getPlayer()); + + _db.getViolationLevels(accountId) + .ifPresent(vls -> + { + _violationLevels.put(accountId, vls); + }); + }); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + int accountId =_clientManager.getAccountId(event.getPlayer()); + + ViolationLevels levels = _violationLevels.get(accountId); + + if (levels != null) + { + Map clone = new HashMap<>(); + clone.put(accountId, levels); + + runAsync(() -> _db.saveViolationLevels(clone)); + } + + _metadata.values().forEach(metadata -> metadata.remove(event.getPlayer().getUniqueId())); + } + + public void saveMetadata(Player player, String id, Runnable after, JsonObject custom) + { + runAsync(() -> + { + JsonObject info = new JsonObject(); + + for (AnticheatMetadata anticheatMetadata : _metadata.values()) + { + try + { + info.add(anticheatMetadata.getId(), anticheatMetadata.build(player.getUniqueId())); + } + catch (Throwable t) + { + t.printStackTrace(); + } + } + + info.add("custom", custom == null ? JsonNull.INSTANCE: custom); + + String str = GSON.toJson(info); + byte[] b = str.getBytes(StandardCharsets.UTF_8); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + try + { + XZOutputStream o2 = new XZOutputStream(bout, new LZMA2Options(LZMA2Options.PRESET_MIN), XZ.CHECK_NONE); + o2.write(b); + o2.close(); + } + catch (IOException ex) + { + // Should never happen + ex.printStackTrace(); + } + + String base64 = Base64.getEncoder().encodeToString(bout.toByteArray()); + + _db.saveMetadata(_clientManager.getAccountId(player), id, base64, after); + }); + } + + public void registerMetadata(AnticheatMetadata metadata) + { + if (!this._metadata.containsKey(metadata.getId())) + { + this._metadata.put(metadata.getId(), metadata); + } + else + { + throw new IllegalArgumentException("Attempting to register: " + metadata.getId()); + } + } + + public void resetViolations(Player player, Runnable after) + { + _db.clearLastBan(_clientManager.getAccountId(player), after); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/PartyInfoMetadata.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/PartyInfoMetadata.java new file mode 100644 index 000000000..9ffba8361 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/PartyInfoMetadata.java @@ -0,0 +1,55 @@ +package mineplex.core.antihack.logging.builtin; + +import java.util.UUID; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import mineplex.core.antihack.logging.AnticheatMetadata; +import mineplex.core.party.Party; +import mineplex.core.party.PartyManager; + +import static mineplex.core.Managers.require; + +public class PartyInfoMetadata extends AnticheatMetadata +{ + private static final String KEY_OWNER = "owner"; + private static final String KEY_MEMBERS = "members"; + + @Override + public String getId() + { + return "party-info"; + } + + @Override + public JsonElement build(UUID player) + { + Party party = require(PartyManager.class).getPlayerParties().get(player); + if (party != null) + { + JsonObject partyData = new JsonObject(); + partyData.addProperty(KEY_OWNER, party.getOwner()); + + JsonArray members = new JsonArray(); + party.getMembers().forEach(m -> members.add(new JsonPrimitive(m))); + + partyData.add(KEY_MEMBERS, members); + + return partyData; + } + else + { + return JsonNull.INSTANCE; + } + } + + @Override + public void remove(UUID player) + { + + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/PlayerInfoMetadata.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/PlayerInfoMetadata.java new file mode 100644 index 000000000..479db70d2 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/PlayerInfoMetadata.java @@ -0,0 +1,51 @@ +package mineplex.core.antihack.logging.builtin; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import mineplex.core.account.CoreClientManager; +import mineplex.core.antihack.logging.AnticheatMetadata; + +import static mineplex.core.Managers.require; + +public class PlayerInfoMetadata extends AnticheatMetadata +{ + private static final String KEY_UUID = "uuid"; + private static final String KEY_ACCOUNT_ID = "accountid"; + private static final String KEY_NAME = "name"; + + private final CoreClientManager _clientManager = require(CoreClientManager.class); + + @Override + public String getId() + { + return "player-info"; + } + + @Override + public JsonElement build(UUID player) + { + JsonObject object = new JsonObject(); + object.addProperty(KEY_UUID, player.toString()); + + Player bPlayer = Bukkit.getPlayer(player); + if (bPlayer != null) + { + object.addProperty(KEY_NAME, bPlayer.getName()); + object.addProperty(KEY_ACCOUNT_ID, _clientManager.getAccountId(bPlayer)); + } + + return object; + } + + @Override + public void remove(UUID player) + { + + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/ServerInfoMetadata.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/ServerInfoMetadata.java new file mode 100644 index 000000000..7376a6d3e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/ServerInfoMetadata.java @@ -0,0 +1,38 @@ +package mineplex.core.antihack.logging.builtin; + +import java.util.UUID; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import mineplex.core.antihack.logging.AnticheatMetadata; +import mineplex.core.common.util.UtilServer; + +public class ServerInfoMetadata extends AnticheatMetadata +{ + private static final String KEY_SERVER_NAME = "server-name"; + private static final String KEY_SERVER_REGION = "server-region"; + private static final String KEY_SERVER_GROUP = "server-group"; + + @Override + public String getId() + { + return "server-info"; + } + + @Override + public JsonElement build(UUID player) + { + JsonObject info = new JsonObject(); + info.addProperty(KEY_SERVER_NAME, UtilServer.getServerName()); + info.addProperty(KEY_SERVER_REGION, UtilServer.getRegion().name()); + info.addProperty(KEY_SERVER_GROUP, UtilServer.getGroup()); + return info; + } + + @Override + public void remove(UUID player) + { + + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/ViolationInfoMetadata.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/ViolationInfoMetadata.java new file mode 100644 index 000000000..da2ee4278 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/logging/builtin/ViolationInfoMetadata.java @@ -0,0 +1,154 @@ +package mineplex.core.antihack.logging.builtin; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import net.minecraft.server.v1_8_R3.MinecraftServer; + +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mineplex.anticheat.api.CheckDisabledEvent; +import com.mineplex.anticheat.api.PlayerViolationEvent; +import com.mineplex.anticheat.checks.Check; + +import mineplex.core.antihack.logging.AnticheatMetadata; + +import gnu.trove.map.TObjectIntMap; +import gnu.trove.map.TObjectLongMap; +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.map.hash.TObjectLongHashMap; + +public class ViolationInfoMetadata extends AnticheatMetadata +{ + private static final Location MUTABLE_LOCATION = new Location(null, 0, 0, 0); + + private static final String KEY_JOIN_TIME_MS = "join-time-ms"; + private static final String KEY_JOIN_TIME_TICK = "join-time-tick"; + + private static final String KEY_CURRENT_TIME = "current-time"; + private static final String KEY_MS = "ms"; + private static final String KEY_TICK = "tick"; + + private static final String KEY_VIOLATION_INFO = "violation-info"; + private static final String KEY_VL = "current-vl"; + private static final String KEY_MESSAGE = "msg"; + + private static final String KEY_PLAYER_INFO = "player-info"; + private static final String KEY_LOCATION = "loc"; + private static final String KEY_WORLD = "world"; + private static final String KEY_X = "x"; + private static final String KEY_Y = "y"; + private static final String KEY_Z = "z"; + private static final String KEY_YAW = "yaw"; + private static final String KEY_PITCH = "pitch"; + + private static final JsonObject VAL_CHECK_DISABLED; + + static + { + VAL_CHECK_DISABLED = new JsonObject(); + VAL_CHECK_DISABLED.addProperty(KEY_MESSAGE, "disabled"); + } + + private TObjectLongMap _joinTime = new TObjectLongHashMap<>(); + private TObjectIntMap _joinTimeTick = new TObjectIntHashMap<>(); + private Map, List>> _violations = new HashMap<>(); + + @Override + public String getId() + { + return "violation-info"; + } + + @Override + public JsonElement build(UUID player) + { + JsonObject object = new JsonObject(); + object.addProperty(KEY_JOIN_TIME_MS, _joinTime.get(player)); + object.addProperty(KEY_JOIN_TIME_TICK, _joinTimeTick.get(player)); + _violations.get(player).forEach((check, list) -> + { + JsonArray checkElem = new JsonArray(); + list.forEach(checkElem::add); + object.add(check.getName(), checkElem); + }); + + return object; + } + + @Override + public void remove(UUID player) + { + _joinTime.remove(player); + _joinTimeTick.remove(player); + _violations.remove(player); + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) + { + long thisMs = System.currentTimeMillis(); + int thisTick = MinecraftServer.getServer().at(); + _joinTime.put(event.getPlayer().getUniqueId(), thisMs); + _joinTimeTick.put(event.getPlayer().getUniqueId(), thisTick); + _violations.put(event.getPlayer().getUniqueId(), new HashMap<>()); + } + + @EventHandler + public void onDisabledCheck(CheckDisabledEvent event) + { + _violations.values().forEach(map -> + { + List data = map.get(event.getCheck()); + if (data != null) + { + data.add(VAL_CHECK_DISABLED); + } + }); + } + + @EventHandler + public void onViolation(PlayerViolationEvent event) + { + long thisMs = System.currentTimeMillis(); + int thisTick = MinecraftServer.getServer().at(); + + List violations = _violations.get(event.getPlayer().getUniqueId()).computeIfAbsent(event.getCheckClass(), key -> new ArrayList<>()); + + JsonObject currentTime = new JsonObject(); + currentTime.addProperty(KEY_MS, thisMs); + currentTime.addProperty(KEY_TICK, thisTick); + + JsonObject violationInfo = new JsonObject(); + violationInfo.addProperty(KEY_VL, event.getViolations()); + violationInfo.addProperty(KEY_MESSAGE, event.getMessage()); + + event.getPlayer().getLocation(MUTABLE_LOCATION); + + JsonObject playerInfo = new JsonObject(); + JsonObject location = new JsonObject(); + location.addProperty(KEY_WORLD, MUTABLE_LOCATION.getWorld().getName()); + location.addProperty(KEY_X, MUTABLE_LOCATION.getX()); + location.addProperty(KEY_Y, MUTABLE_LOCATION.getY()); + location.addProperty(KEY_Z, MUTABLE_LOCATION.getZ()); + location.addProperty(KEY_YAW, MUTABLE_LOCATION.getYaw()); + location.addProperty(KEY_PITCH, MUTABLE_LOCATION.getPitch()); + + playerInfo.add(KEY_LOCATION, location); + + JsonObject data = new JsonObject(); + data.add(KEY_CURRENT_TIME, currentTime); + data.add(KEY_VIOLATION_INFO, violationInfo); + data.add(KEY_PLAYER_INFO, playerInfo); + + violations.add(data); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/redisnotifications/GwenBanNotification.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/redisnotifications/GwenBanNotification.java new file mode 100644 index 000000000..5be1a474c --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/redisnotifications/GwenBanNotification.java @@ -0,0 +1,46 @@ +package mineplex.core.antihack.redisnotifications; + +import mineplex.serverdata.commands.ServerCommand; + +public class GwenBanNotification extends ServerCommand +{ + private final String _serverName; + private final String _playerName; + private final String _playerUUID; + private final String _hackType; + private final String _metadataId; + + public GwenBanNotification(String serverName, String playerName, String playerUUID, String hackType, String metadataId) + { + _serverName = serverName; + _playerName = playerName; + _playerUUID = playerUUID; + _hackType = hackType; + _metadataId = metadataId; + } + + public String getServerName() + { + return _serverName; + } + + public String getPlayerName() + { + return _playerName; + } + + public String getPlayerUUID() + { + return _playerUUID; + } + + public String getHackType() + { + return _hackType; + } + + public String getMetadataId() + { + return _metadataId; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/redisnotifications/GwenBanwaveNotification.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/redisnotifications/GwenBanwaveNotification.java new file mode 100644 index 000000000..0ca1cf628 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/redisnotifications/GwenBanwaveNotification.java @@ -0,0 +1,53 @@ +package mineplex.core.antihack.redisnotifications; + +import mineplex.serverdata.commands.ServerCommand; + +public class GwenBanwaveNotification extends ServerCommand +{ + private final String _serverName; + private final String _playerName; + private final String _playerUUID; + private final String _hackType; + private final String _metadataId; + private final long _timeToBan; + + public GwenBanwaveNotification(String serverName, String playerName, String playerUUID, String hackType, String metadataId, long timeToBan) + { + _serverName = serverName; + _playerName = playerName; + _playerUUID = playerUUID; + _hackType = hackType; + _metadataId = metadataId; + _timeToBan = timeToBan; + } + + public String getServerName() + { + return _serverName; + } + + public String getPlayerName() + { + return _playerName; + } + + public String getPlayerUUID() + { + return _playerUUID; + } + + public String getHackType() + { + return _hackType; + } + + public String getMetadataId() + { + return _metadataId; + } + + public long getTimeToBan() + { + return _timeToBan; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Fly.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Fly.java deleted file mode 100644 index 0941d4a2a..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Fly.java +++ /dev/null @@ -1,172 +0,0 @@ -package mineplex.core.antihack.types; - -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.Map.Entry; - -import mineplex.core.MiniPlugin; -import mineplex.core.antihack.AntiHack; -import mineplex.core.antihack.Detector; -import mineplex.core.common.util.UtilBlock; -import mineplex.core.common.util.UtilMath; - -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; - -public class Fly extends MiniPlugin implements Detector -{ - private AntiHack Host; - - private HashMap> _floatTicks = new HashMap>(); //Ticks, PrevY - private HashMap> _hoverTicks = new HashMap>(); //Ticks, PrevY - private HashMap> _riseTicks = new HashMap>(); //Ticks, PrevY - - public Fly (AntiHack host) - { - super("Fly Detector", host.getPlugin()); - Host = host; - } - - @EventHandler(priority = EventPriority.MONITOR) - public void updateFlyhack(PlayerMoveEvent event) - { - if (!Host.isEnabled()) - return; - - Player player = event.getPlayer(); - - //100% Valid - if (Host.isValid(player, true)) - Reset(player); - - //Hasn't moved, just looking around - if (UtilMath.offset(event.getFrom(), event.getTo()) <= 0) - { - updateFloat(player); - return; - } - else - { - _floatTicks.remove(player); - } - - updateHover(player); - updateRise(player); - } - - private void updateFloat(Player player) - { - int count = 0; - - if (_floatTicks.containsKey(player)) - { - if (player.getLocation().getY() == _floatTicks.get(player).getValue()) - { - count = _floatTicks.get(player).getKey() + 1; - } - else - { - count = 0; - } - } - - if (count > Host.FloatHackTicks) - { - Host.addSuspicion(player, "Fly (Float)"); - count -= 2; - } - - _floatTicks.put(player, new AbstractMap.SimpleEntry(count, player.getLocation().getY())); - } - - private void updateHover(Player player) - { - int count = 0; - - if (_hoverTicks.containsKey(player)) - { - if (player.getLocation().getY() == _hoverTicks.get(player).getValue()) - { - count = _hoverTicks.get(player).getKey() + 1; - } - else - { - count = 0; - } - - //player.sendMessage(count + " - " + player.getLocation().getY() + " vs " + _hoverTicks.get(player).getValue()); - } - - if (count > Host.HoverHackTicks) - { - Host.addSuspicion(player, "Fly (Hover)"); - count -= 2; - } - - _hoverTicks.put(player, new AbstractMap.SimpleEntry(count, player.getLocation().getY())); - } - - private void updateRise(Player player) - { - int count = 0; - - if (_riseTicks.containsKey(player)) - { - if (player.getLocation().getY() >= _riseTicks.get(player).getValue()) - { - boolean nearBlocks = false; - for (Block block : UtilBlock.getSurrounding(player.getLocation().getBlock(), true)) - { - if (block.getType() != Material.AIR) - { - nearBlocks = true; - break; - } - } - - for (PotionEffect effect : player.getActivePotionEffects()) - if (effect.getType() == PotionEffectType.JUMP || effect.getType().equals(PotionEffectType.JUMP)) - nearBlocks = true; - - if (nearBlocks) - { - count = 0; - } - else - { - count = _riseTicks.get(player).getKey() + 1; - } - - } - else - { - count = 0; - } - } - - if (count > Host.RiseHackTicks) - { - //Only give Offense if actually rising - initial ticks can be trigged via Hover. - if (player.getLocation().getY() > _riseTicks.get(player).getValue()) - Host.addSuspicion(player, "Fly (Rise)"); - - count -= 2; - } - - _riseTicks.put(player, new AbstractMap.SimpleEntry(count, player.getLocation().getY())); - } - - @Override - public void Reset(Player player) - { - _floatTicks.remove(player); - _hoverTicks.remove(player); - _riseTicks.remove(player); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Idle.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Idle.java deleted file mode 100644 index 18889a4c6..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Idle.java +++ /dev/null @@ -1,78 +0,0 @@ -package mineplex.core.antihack.types; - -import java.util.HashMap; - -import mineplex.core.MiniPlugin; -import mineplex.core.antihack.AntiHack; -import mineplex.core.antihack.Detector; -import mineplex.core.common.util.C; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.common.util.UtilServer; -import mineplex.core.common.util.UtilTime; -import mineplex.core.updater.UpdateType; -import mineplex.core.updater.event.UpdateEvent; - -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.PlayerMoveEvent; - -public class Idle extends MiniPlugin implements Detector -{ - private AntiHack Host; - - private HashMap _idleTime = new HashMap(); - - public Idle (AntiHack host) - { - super("Idle Detector", host.getPlugin()); - Host = host; - } - - @EventHandler(priority = EventPriority.MONITOR) - public void updateFlyhack(PlayerMoveEvent event) - { - if (!Host.isEnabled()) - return; - - Player player = event.getPlayer(); - - _idleTime.put(player, System.currentTimeMillis()); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void updateFreeCam(UpdateEvent event) - { - if (!Host.isEnabled()) - return; - - if (event.getType() != UpdateType.FAST) - return; - - for (Player player : UtilServer.getPlayers()) - { - //100% Valid - if (Host.isValid(player, true)) - continue; - - if (!_idleTime.containsKey(player)) - continue; - - if (!UtilTime.elapsed(_idleTime.get(player), Host.IdleTime)) - continue; - - //Host.addSuspicion(player, "Lag / Fly (Idle)"); - //player.kickPlayer(C.cGold + "Mineplex " + C.cRed + "Anti-Cheat " + C.cWhite + "Kicked for Lag / Fly (Idle)"); - - UtilPlayer.message(player, C.cRed + C.Bold + "Mineplex Anti-Cheat detected Lagging / Fly (Idle)"); - UtilPlayer.message(player, C.cRed + C.Bold + "You have been returned to Lobby."); - Host.Portal.sendPlayerToServer(player, "Lobby"); - } - } - - @Override - public void Reset(Player player) - { - _idleTime.remove(player); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Reach.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Reach.java deleted file mode 100644 index 9bf8b4a00..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Reach.java +++ /dev/null @@ -1,123 +0,0 @@ -package mineplex.core.antihack.types; - -import java.util.ArrayList; -import java.util.HashMap; - -import mineplex.core.MiniPlugin; -import mineplex.core.antihack.AntiHack; -import mineplex.core.antihack.Detector; -import mineplex.core.common.util.UtilEvent; -import mineplex.core.common.util.UtilMath; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.common.util.UtilServer; -import mineplex.core.updater.UpdateType; -import mineplex.core.updater.event.UpdateEvent; - -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.EntityDamageEvent.DamageCause; - -public class Reach extends MiniPlugin implements Detector -{ - private AntiHack Host; - - private HashMap> _history = new HashMap>(); - - public Reach (AntiHack host) - { - super("Reach Detector", host.getPlugin()); - Host = host; - } - - @EventHandler(priority = EventPriority.LOWEST) - public void recordMove(UpdateEvent event) - { - if (!Host.isEnabled()) - return; - - if (event.getType() != UpdateType.TICK) - return; - - for (Player player : UtilServer.getPlayers()) - { - if (player.getGameMode() != GameMode.SURVIVAL || UtilPlayer.isSpectator(player)) - continue; - - if (!_history.containsKey(player)) - _history.put(player, new ArrayList()); - - _history.get(player).add(0, player.getLocation()); - - while (_history.get(player).size() > 40) - { - _history.get(player).remove(_history.get(player).size()-1); - } - } - } - - @EventHandler(priority = EventPriority.LOWEST) - public void reachDetect(EntityDamageEvent event) - { - if (event.getCause() != DamageCause.ENTITY_ATTACK) - return; - - if (!(event.getEntity() instanceof Player)) - return; - - LivingEntity damagerEntity = UtilEvent.GetDamagerEntity(event, false); - - if (!(damagerEntity instanceof Player)) - return; - - Player damager = (Player)damagerEntity; - Player damagee = (Player)event.getEntity(); - - if (!isInRange(damager.getLocation(), damagee.getLocation())) - { - ArrayList damageeHistory = _history.get(damagee); - - if (damageeHistory != null) - { - for (Location historyLoc : damageeHistory) - { - if (isInRange(damager.getLocation(), historyLoc)) - { - return; - } - } - } - - //Host.addSuspicion(damager, "Reach"); - } - } - - private boolean isInRange(Location a, Location b) - { - //2d Range - double distFlat = UtilMath.offset2d(a, b); //Limit is 3.40 - if (distFlat > 3.4) - { - return true; - } - - //3d Range - double dist = UtilMath.offset(a, b); //Limit is 6 (highest i saw was 5.67) - if (dist > 6.0) - { - return true; - } - - return false; - } - - @Override - public void Reset(Player player) - { - _history.remove(player); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Speed.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Speed.java deleted file mode 100644 index 9e57c33df..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/types/Speed.java +++ /dev/null @@ -1,105 +0,0 @@ -package mineplex.core.antihack.types; - -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.Map.Entry; - -import mineplex.core.MiniPlugin; -import mineplex.core.antihack.AntiHack; -import mineplex.core.antihack.Detector; -import mineplex.core.common.util.UtilEnt; -import mineplex.core.common.util.UtilMath; -import mineplex.core.common.util.UtilTime; - -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; - -public class Speed extends MiniPlugin implements Detector -{ - private AntiHack Host; - - private HashMap> _speedTicks = new HashMap>(); //Ticks, PrevY - - public Speed (AntiHack host) - { - super("Speed Detector", host.getPlugin()); - Host = host; - } - - @EventHandler(priority = EventPriority.MONITOR) - public void updateSpeedhack(PlayerMoveEvent event) - { - if (!Host.isEnabled()) - return; - - Player player = event.getPlayer(); - - //100% Valid - if (Host.isValid(player, false)) - return; - - UpdateSpeed(player, event); - } - - private void UpdateSpeed(Player player, PlayerMoveEvent event) - { - int count = 0; - - if (_speedTicks.containsKey(player)) - { - double offset; - if (event.getFrom().getY() > event.getTo().getY()) - { - offset = UtilMath.offset2d(event.getFrom(), event.getTo()); - } - else - { - offset = UtilMath.offset(event.getFrom(), event.getTo()); - } - - //Limit - double limit = 0.74; - if (UtilEnt.isGrounded(player)) - limit = 0.32; - - for (PotionEffect effect : player.getActivePotionEffects()) - { - if (effect.getType().equals(PotionEffectType.SPEED)) - { - if (UtilEnt.isGrounded(player)) - limit += 0.08 * (effect.getAmplifier() + 1); - else - limit += 0.04 * (effect.getAmplifier() + 1); - } - } - - //Check - if (offset > limit && !UtilTime.elapsed(_speedTicks.get(player).getValue(), 100))//Counters Lag - { - count = _speedTicks.get(player).getKey() + 1; - } - else - { - count = 0; - } - } - - if (count > Host.SpeedHackTicks) - { - Host.addSuspicion(player, "Speed (Fly/Move)"); - count -= 2; - } - - _speedTicks.put(player, new AbstractMap.SimpleEntry(count, System.currentTimeMillis())); - } - - @Override - public void Reset(Player player) - { - _speedTicks.remove(player); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/Community.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/Community.java new file mode 100644 index 000000000..41c4391d3 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/Community.java @@ -0,0 +1,159 @@ +package mineplex.core.communities; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.game.GameDisplay; + +public class Community +{ + private final int _id; + private String _name; + private String _description; + private Map _members = new HashMap<>(); + private Map _joinRequests = new HashMap<>(); + private ChatColor[] _chatFormat; + private long _chatDelay; + private GameDisplay _favoriteGame; + private PrivacySetting _privacy; + + public Community(int id, String name) + { + _id = id; + _name = name; + _description = "No Description Set"; + _chatFormat = new ChatColor[] {ChatColor.BLUE, ChatColor.RED, ChatColor.GREEN}; + _chatDelay = 1000; + _favoriteGame = GameDisplay.ChampionsCTF; + _privacy = PrivacySetting.RECRUITING; + } + + public Integer getId() + { + return _id; + } + + public String getName() + { + return _name; + } + + public void setName(String name) + { + _name = name; + } + + public String getDescription() + { + return _description; + } + + public void setDescription(String description) + { + _description = description; + } + + public Map getMembers() + { + return _members; + } + + public Map getJoinRequests() + { + return _joinRequests; + } + + public ChatColor[] getChatFormatting() + { + return _chatFormat; + } + + public void setChatFormatting(ChatColor[] colors) + { + _chatFormat = colors; + } + + public Long getChatDelay() + { + return _chatDelay; + } + + public void setChatDelay(Long delay) + { + _chatDelay = delay; + } + + public GameDisplay getFavoriteGame() + { + return _favoriteGame; + } + + public void setFavoriteGame(GameDisplay game) + { + _favoriteGame = game; + } + + public PrivacySetting getPrivacySetting() + { + return _privacy; + } + + public void setPrivacySetting(PrivacySetting privacy) + { + _privacy = privacy; + } + + public void sendChat(String chat) + { + getMembers().values().stream().filter(info -> info.ReadingChat).forEach(member -> UtilPlayer.message(Bukkit.getPlayer(member.UUID), chat)); + } + + public void message(String message) + { + getMembers().values().forEach(member -> UtilPlayer.message(Bukkit.getPlayer(member.UUID), message)); + } + + public void message(String message, CommunityRole minimumRole) + { + getMembers().values().stream().filter(member -> member.Role.ordinal() <= minimumRole.ordinal()).forEach(member -> UtilPlayer.message(Bukkit.getPlayer(member.UUID), message)); + } + + public static enum PrivacySetting + { + OPEN("Open to Join"), + RECRUITING("Accepting Join Requests"), + PRIVATE("Closed") + ; + + private String _display; + + private PrivacySetting(String display) + { + _display = display; + } + + public String getDisplayText() + { + return _display; + } + + public static PrivacySetting parsePrivacy(String privacy) + { + for (PrivacySetting setting : PrivacySetting.values()) + { + if (setting.toString().equalsIgnoreCase(privacy)) + { + return setting; + } + } + + return PrivacySetting.RECRUITING; + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityBrowserUpdateEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityBrowserUpdateEvent.java new file mode 100644 index 000000000..d9dff9fe7 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityBrowserUpdateEvent.java @@ -0,0 +1,21 @@ +package mineplex.core.communities; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class CommunityBrowserUpdateEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + public CommunityBrowserUpdateEvent() {} + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityDisbandEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityDisbandEvent.java new file mode 100644 index 000000000..ce97ed20e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityDisbandEvent.java @@ -0,0 +1,31 @@ +package mineplex.core.communities; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class CommunityDisbandEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + private Community _community; + + public CommunityDisbandEvent(Community community) + { + _community = community; + } + + public Community getCommunity() + { + return _community; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityJoinRequestInfo.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityJoinRequestInfo.java new file mode 100644 index 000000000..1eb973551 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityJoinRequestInfo.java @@ -0,0 +1,47 @@ +package mineplex.core.communities; + +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityJoinRequestInfo +{ + public String Name; + public final UUID UUID; + public final int AccountId; + private ItemStack _icon; + + public CommunityJoinRequestInfo(String name, UUID uuid, int accountId) + { + Name = name; + UUID = uuid; + AccountId = accountId; + + buildIcon(); + } + + private void buildIcon() + { + ItemBuilder builder = new ItemBuilder(Material.SKULL_ITEM); + builder.setTitle(C.cGreenB + Name); + builder.setLore(C.cRed, C.cYellow + "Left Click " + C.cWhite + "Accept", C.cYellow + "Shift-Right Click " + C.cWhite + "Deny"); + builder.setData((short)3); + builder.setPlayerHead(Name); + _icon = builder.build(); + } + + public void update(String name) + { + Name = name; + buildIcon(); + } + + public ItemStack getRepresentation() + { + return _icon; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityJoinRequestsUpdateEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityJoinRequestsUpdateEvent.java new file mode 100644 index 000000000..899ee7f5e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityJoinRequestsUpdateEvent.java @@ -0,0 +1,31 @@ +package mineplex.core.communities; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class CommunityJoinRequestsUpdateEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + private Community _community; + + public CommunityJoinRequestsUpdateEvent(Community community) + { + _community = community; + } + + public Community getCommunity() + { + return _community; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityManager.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityManager.java new file mode 100644 index 000000000..b4c5e5555 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityManager.java @@ -0,0 +1,709 @@ +package mineplex.core.communities; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import com.google.common.collect.Lists; + +import mineplex.core.Managers; +import mineplex.core.MiniDbClientPlugin; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.jsonchat.ClickEvent; +import mineplex.core.common.jsonchat.JsonMessage; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.communities.Community.PrivacySetting; +import mineplex.core.communities.commands.CommunityCommand; +import mineplex.core.communities.redis.CommunityChat; +import mineplex.core.communities.redis.CommunityChatHandler; +import mineplex.core.communities.redis.CommunityCloseJoinRequest; +import mineplex.core.communities.redis.CommunityCloseJoinRequestHandler; +import mineplex.core.communities.redis.CommunityCreate; +import mineplex.core.communities.redis.CommunityCreateHandler; +import mineplex.core.communities.redis.CommunityDisband; +import mineplex.core.communities.redis.CommunityDisbandHandler; +import mineplex.core.communities.redis.CommunityInvite; +import mineplex.core.communities.redis.CommunityInviteHandler; +import mineplex.core.communities.redis.CommunityJoinRequest; +import mineplex.core.communities.redis.CommunityJoinRequestHandler; +import mineplex.core.communities.redis.CommunityUnInvite; +import mineplex.core.communities.redis.CommunityUnInviteHandler; +import mineplex.core.communities.redis.CommunityUpdateMemberChatReading; +import mineplex.core.communities.redis.CommunityUpdateMemberChatReadingHandler; +import mineplex.core.communities.redis.CommunityUpdateMemberRole; +import mineplex.core.communities.redis.CommunityUpdateMemberRoleHandler; +import mineplex.core.communities.redis.CommunityUpdateMembership; +import mineplex.core.communities.redis.CommunityUpdateMembershipHandler; +import mineplex.core.communities.redis.CommunityUpdateName; +import mineplex.core.communities.redis.CommunityUpdateNameHandler; +import mineplex.core.communities.redis.CommunityUpdateSetting; +import mineplex.core.communities.redis.CommunityUpdateSettingHandler; +import mineplex.core.communities.storage.CommunityRepository; +import mineplex.core.preferences.Preference; +import mineplex.core.preferences.PreferencesManager; +import mineplex.core.recharge.Recharge; +import mineplex.serverdata.Region; +import mineplex.serverdata.commands.ServerCommandManager; +import mineplex.serverdata.data.DataRepository; +import mineplex.serverdata.data.PlayerStatus; +import mineplex.serverdata.redis.RedisDataRepository; +import mineplex.serverdata.servers.ServerManager; +import mineplex.serverdata.servers.ServerRepository; + +public class CommunityManager extends MiniDbClientPlugin +{ + public final Pattern ALPHA_NUMERIC_PATTERN = Pattern.compile("[^A-Za-z0-9]"); + public final String[] BLOCKED_NAMES = new String[] {"help", "chat", "create", "description", "disband", "invite", "join", "mcs", "rename", "uninvite", "trainee", "mod", "moderator", "srmod", "seniormod", "seniormoderator", "builder", "maplead", "twitch", "youtube", "support", "admin", "administrator", "leader", "dev", "developer", "owner", "party", "mineplex", "mineplexOfficial", "staff", "mineplexstaff", "qualityassurance", "traineemanagement", "modcoordination", "forumninja", "communitymanagement", "event", "socialmedia"}; + private final CommunityRepository _repo; + private final Map _loadedCommunities; + + public final List BrowserIds = new LinkedList<>(); + + public final DataRepository StatusRepository; + + private ServerRepository _serverRepo; + private boolean _us; + + private boolean _cycling = false; + + @SuppressWarnings("deprecation") + public CommunityManager(JavaPlugin plugin, CoreClientManager clientManager) + { + super("Communities", plugin, clientManager); + + StatusRepository = new RedisDataRepository(ServerManager.getMasterConnection(), ServerManager.getSlaveConnection(), + Region.currentRegion(), PlayerStatus.class, "playerStatus"); + + _us = plugin.getConfig().getBoolean("serverstatus.us"); + + Region region = _us ? Region.US : Region.EU; + _serverRepo = ServerManager.getServerRepository(region); + + _repo = new CommunityRepository(plugin, StatusRepository, _us); + + _loadedCommunities = new ConcurrentHashMap<>(); + + Bukkit.getScheduler().scheduleAsyncRepeatingTask(plugin, () -> + { + if (_cycling) + { + return; + } + + LinkedList communities = new LinkedList<>(); + _loadedCommunities.values().forEach(community -> communities.add(community)); + _repo.updateMembersAndJoinRequests(communities); + }, 0L, 20 * 5); + + Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, () -> + { + cycleBrowser(); + }, 0L, 20 * 30); + + _repo.loadCommunities(_loadedCommunities); + + addCommand(new CommunityCommand(this)); + + ServerCommandManager.getInstance().registerCommandType(CommunityChat.class, new CommunityChatHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityCloseJoinRequest.class, new CommunityCloseJoinRequestHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityCreate.class, new CommunityCreateHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityDisband.class, new CommunityDisbandHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityInvite.class, new CommunityInviteHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityJoinRequest.class, new CommunityJoinRequestHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityUnInvite.class, new CommunityUnInviteHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityUpdateMemberChatReading.class, new CommunityUpdateMemberChatReadingHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityUpdateMemberRole.class, new CommunityUpdateMemberRoleHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityUpdateMembership.class, new CommunityUpdateMembershipHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityUpdateName.class, new CommunityUpdateNameHandler(this)); + ServerCommandManager.getInstance().registerCommandType(CommunityUpdateSetting.class, new CommunityUpdateSettingHandler(this)); + } + + private void cycleBrowser() + { + if (_cycling) + { + return; + } + _cycling = true; + runAsync(() -> + { + final List resultant = Lists.newArrayList(); + final List ids = new LinkedList<>(); + _loadedCommunities.values().stream().filter(c -> c.getMembers().size() >= 5 && c.getPrivacySetting() != PrivacySetting.PRIVATE).forEach(c -> resultant.add(c.getId())); + + Random random = new Random(); + while (!resultant.isEmpty()) + { + ids.add(resultant.remove(random.nextInt(resultant.size()))); + } + + runSync(() -> + { + BrowserIds.clear(); + BrowserIds.addAll(ids); + _cycling = false; + UtilServer.CallEvent(new CommunityBrowserUpdateEvent()); + }); + }); + } + + public Community getLoadedCommunity(Integer id) + { + return _loadedCommunities.get(id); + } + + public Community getLoadedCommunity(String name) + { + for (Entry entry : _loadedCommunities.entrySet()) + { + if (entry.getValue().getName().equalsIgnoreCase(name)) + { + return entry.getValue(); + } + } + + return null; + } + + public void handleCommunitySettingUpdate(Integer id, String sender, CommunitySetting setting, String newValue) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + setting.parseValueInto(newValue, community); + //community.message(F.main(getName(), F.name(sender) + " has changed settings in " + F.name(community.getName()) + "!")); + UtilServer.CallEvent(new CommunitySettingUpdateEvent(community)); + } + + public void handleCommunityNameUpdate(Integer id, String sender, String name) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + String oldName = community.getName(); + community.setName(name); + community.message(F.main(getName(), F.name(sender) + " has changed the name of " + F.name(oldName) + " to " + F.name(community.getName()) + "!")); + UtilServer.CallEvent(new CommunityNameUpdateEvent(community)); + } + + public void handleCommunityMembershipRoleUpdate(Integer id, String sender, UUID uuid, CommunityRole role) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + CommunityMemberInfo member = community.getMembers().get(uuid); + member.Role = role; + if (Bukkit.getPlayer(uuid) != null) + { + if (role.ordinal() > CommunityRole.COLEADER.ordinal()) + { + UtilPlayer.message(Bukkit.getPlayer(uuid), F.main(getName(), F.name(sender) + " has changed your role to " + F.elem(role.getDisplay()) + " in " + F.name(community.getName()) + "!")); + } + Get(Bukkit.getPlayer(uuid)).setRoleIn(community, role); + } + String name = member.Name; + community.message(F.main(getName(), F.name(sender) + " has changed " + F.name(name + "'s") + " role to " + F.elem(role.getDisplay()) + " in " + F.name(community.getName()) + "!"), CommunityRole.COLEADER); + UtilServer.CallEvent(new CommunityMembershipUpdateEvent(community)); + } + + public void handleCommunityMembershipUpdate(Integer id, String sender, String playerName, UUID playerUUID, Integer accountId, boolean kick, boolean leave) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + + if (kick) + { + community.message(F.main(getName(), F.name(sender) + " has kicked " + F.name(playerName) + " from " + F.name(community.getName()) + "!")); + community.getMembers().remove(playerUUID); + if (Bukkit.getPlayer(playerUUID) != null) + { + Get(Bukkit.getPlayer(playerUUID)).leaveCommunity(community); + } + } + else if (leave) + { + community.message(F.main(getName(), F.name(playerName) + " has left " + F.name(community.getName()) + "!")); + community.getMembers().remove(playerUUID); + if (Bukkit.getPlayer(playerUUID) != null) + { + Get(Bukkit.getPlayer(playerUUID)).leaveCommunity(community); + } + } + else + { + community.getMembers().put(playerUUID, new CommunityMemberInfo(playerName, playerUUID, accountId, CommunityRole.MEMBER, System.currentTimeMillis())); + if (Bukkit.getPlayer(playerUUID) != null) + { + Get(Bukkit.getPlayer(playerUUID)).joinCommunity(community); + Get(Bukkit.getPlayer(playerUUID)).Invites.remove(community.getId()); + } + + community.message(F.main(getName(), F.name(playerName) + " has joined " + F.name(community.getName()) + "!")); + } + + UtilServer.CallEvent(new CommunityMembershipUpdateEvent(community)); + if (Bukkit.getPlayer(playerUUID) != null) + { + UtilServer.CallEvent(new CommunityMemberDataUpdateEvent(Bukkit.getPlayer(playerUUID))); + } + } + + public void handleCommunityInvite(Integer id, String sender, String targetName, UUID targetUUID) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + if (Bukkit.getPlayer(targetUUID) != null) + { + if (!Get(Bukkit.getPlayer(targetUUID)).Invites.contains(community.getId())) + { + Get(Bukkit.getPlayer(targetUUID)).Invites.add(community.getId()); + if (Managers.get(PreferencesManager.class).get(Bukkit.getPlayer(targetUUID)).isActive(Preference.COMMUNITY_INVITES)) + { + new JsonMessage(F.main(getName(), "You have been invited to join " + F.elem(community.getName()) + " by " + F.name(sender) + "! Click to join!")).click(ClickEvent.RUN_COMMAND, "/community join " + community.getName()).sendToPlayer(Bukkit.getPlayer(targetUUID)); + } + + UtilServer.CallEvent(new CommunityMemberDataUpdateEvent(Bukkit.getPlayer(targetUUID))); + } + } + community.message(F.main(getName(), F.name(sender) + " has invited " + F.name(targetName) + " to " + F.name(community.getName()) + "!"), CommunityRole.COLEADER); + } + + public void handleCommunityUninvite(Integer id, String sender, String targetName, UUID targetUUID, boolean announce) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + if (Bukkit.getPlayer(targetUUID) != null) + { + Get(Bukkit.getPlayer(targetUUID)).Invites.remove(community.getId()); + if (Managers.get(PreferencesManager.class).get(Bukkit.getPlayer(targetUUID)).isActive(Preference.COMMUNITY_INVITES) && announce) + { + UtilPlayer.message(Bukkit.getPlayer(targetUUID), F.main(getName(), "Your invitation to join " + F.elem(community.getName()) + " has been revoked by " + F.name(sender) + "!")); + } + UtilServer.CallEvent(new CommunityMemberDataUpdateEvent(Bukkit.getPlayer(targetUUID))); + } + if (announce) + { + community.message(F.main(getName(), F.name(targetName) + "'s invitation to join " + F.name(community.getName()) + " has been revoked by " + F.name(sender) + "!"), CommunityRole.COLEADER); + } + } + + public void handleCommunityJoinRequest(Integer id, String playerName, UUID playerUUID, Integer accountId) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + if (Bukkit.getPlayer(playerUUID) != null) + { + UtilPlayer.message(Bukkit.getPlayer(playerUUID), F.main(getName(), "You have requested to join " + F.elem(community.getName()) + "!")); + } + community.getJoinRequests().put(playerUUID, new CommunityJoinRequestInfo(playerName, playerUUID, accountId)); + community.message(F.main(getName(), F.name(playerName) + " has requested to join " + F.name(community.getName()) + "!"), CommunityRole.COLEADER); + + UtilServer.CallEvent(new CommunityJoinRequestsUpdateEvent(community)); + } + + public void handleCommunityCloseJoinRequest(Integer id, String sender, String playerName, UUID playerUUID, Integer accountId, boolean announce) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + community.getJoinRequests().remove(playerUUID); + if (announce) + { + if (Bukkit.getPlayer(playerUUID) != null) + { + UtilPlayer.message(Bukkit.getPlayer(playerUUID), F.main(getName(), "Your request to join " + F.name(community.getName()) + " has been denied by " + F.name(sender) + "!")); + } + community.message(F.main(getName(), F.name(playerName) + "'s request to join " + F.name(community.getName()) + " has been denied by " + F.name(sender) + "!"), CommunityRole.COLEADER); + } + + UtilServer.CallEvent(new CommunityJoinRequestsUpdateEvent(community)); + } + + public void handleCommunityCreation(Integer id, UUID leaderUUID) + { + runAsync(() -> + { + _repo.loadCommunity(id, _loadedCommunities); + runSync(() -> + { + Community community = _loadedCommunities.get(id); + if (Bukkit.getPlayer(leaderUUID) != null) + { + Player leader = Bukkit.getPlayer(leaderUUID); + UtilPlayer.message(leader, F.main(getName(), "You have created a community named " + F.name(community.getName()) + "!")); + Get(leader).joinCommunity(id, CommunityRole.LEADER); + } + }); + }); + } + + public void handleCommunityDisband(Integer id, String senderName) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + community.message(F.main(getName(), F.name(senderName) + " has disbanded community " + F.name(community.getName()) + "!")); + UtilServer.CallEvent(new CommunityDisbandEvent(community)); + UtilServer.GetPlayers().stream().filter(player -> Get(player).Invites.contains(community.getId())).forEach(player -> Get(player).Invites.remove(community.getId())); + community.getMembers().keySet().stream().filter(uuid -> Bukkit.getPlayer(uuid) != null).forEach(uuid -> Get(Bukkit.getPlayer(uuid)).leaveCommunity(community)); + _loadedCommunities.remove(community.getId()); + runSync(() -> + { + if (BrowserIds.remove(community.getId())) + { + UtilServer.CallEvent(new CommunityBrowserUpdateEvent()); + } + }); + } + + public void handleToggleReadingCommunityChat(Integer id, UUID uuid, boolean reading) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + + if (community.getMembers().containsKey(uuid)) + { + community.getMembers().get(uuid).ReadingChat = reading; + if (reading) + { + UtilPlayer.message(Bukkit.getPlayer(uuid), F.main(getName(), "You are now reading chat from " + F.name(community.getName()) + "!")); + } + else + { + UtilPlayer.message(Bukkit.getPlayer(uuid), F.main(getName(), "You are no longer reading chat from " + F.name(community.getName()) + "!")); + } + } + } + + public void handleCommunityChat(Integer id, String senderName, String message) + { + Community community = _loadedCommunities.get(id); + if (community == null) + { + return; + } + community.sendChat(community.getChatFormatting()[0] + C.Bold + community.getName() + " " + community.getChatFormatting()[1] + C.Bold + senderName + " " + community.getChatFormatting()[2] + message); + } + + public void handleInvite(Player sender, Community community, String target) + { + CommunityJoinRequestInfo[] jr = community.getJoinRequests().values().stream().filter(data -> data.Name.equalsIgnoreCase(target)).toArray(size -> new CommunityJoinRequestInfo[size]); + if (jr.length == 1) + { + UtilPlayer.message(sender, F.main(getName(), "You have accepted " + F.name(target) + "'s join request to " + F.name(community.getName()) + "!")); + runAsync(() -> + { + _repo.addToCommunity(jr[0].AccountId, community.getId()); + _repo.removeJoinRequest(community.getId(), jr[0].AccountId); + }); + new CommunityCloseJoinRequest(community.getId(), sender.getName(), jr[0].Name, jr[0].UUID.toString(), jr[0].AccountId, false).publish(); + new CommunityUpdateMembership(community.getId(), sender.getName(), jr[0].Name, jr[0].UUID.toString(), jr[0].AccountId, false, false).publish(); + return; + } + runAsync(() -> + { + if (_repo.inviteToCommunity(community.getId(), target)) + { + if (!community.getMembers().containsKey(sender.getUniqueId())) + { + UtilPlayer.message(sender, F.main(getName(), "You have invited " + F.name(target) + " to join " + F.name(community.getName()) + "!")); + } + new CommunityInvite(community.getId(), sender.getName(), target, Managers.get(CoreClientManager.class).loadUUIDFromDB(target).toString()).publish(); + } + else + { + UtilPlayer.message(sender, F.main(getName(), "Either " + F.name(target) + " does not exist or you have already invited them to " + F.name(community.getName()) + "!")); + } + }); + } + + public void handleUninvite(Player sender, Community community, String target) + { + runAsync(() -> + { + if (_repo.deleteInviteToCommunity(community.getId(), target)) + { + if (!community.getMembers().containsKey(sender.getUniqueId())) + { + UtilPlayer.message(sender, F.main(getName(), "You have revoked " + F.name(target) + "'s invitation to join " + F.name(community.getName()) + "!")); + } + new CommunityUnInvite(community.getId(), sender.getName(), target, Managers.get(CoreClientManager.class).loadUUIDFromDB(target).toString(), true).publish(); + } + else + { + UtilPlayer.message(sender, F.main(getName(), "Either " + F.name(target) + " does not exist or you have not invited them to " + F.name(community.getName()) + "!")); + } + }); + } + + public void handleRejectInvite(Player sender, Community community) + { + final String playerName = Managers.get(CoreClientManager.class).Get(sender).getName(); + runAsync(() -> + { + _repo.deleteInviteToCommunity(community.getId(), playerName); + }); + + new CommunityUnInvite(community.getId(), sender.getName(), sender.getName(), sender.getUniqueId().toString(), false).publish(); + } + + public void handleJoinRequest(Player sender, Community community) + { + final int accountId = Managers.get(CoreClientManager.class).getAccountId(sender); + + if (Get(sender).Invites.contains(community.getId())) + { + String playerName = Managers.get(CoreClientManager.class).Get(sender).getName(); //Guarantee real name (important in this instance) + runAsync(() -> + { + _repo.addToCommunity(accountId, community.getId()); + _repo.deleteInviteToCommunity(community.getId(), playerName); + }); + new CommunityUnInvite(community.getId(), sender.getName(), sender.getName(), sender.getUniqueId().toString(), false).publish(); + new CommunityUpdateMembership(community.getId(), sender.getName(), sender.getName(), sender.getUniqueId().toString(), accountId, false, false).publish(); + return; + } + runAsync(() -> + { + _repo.addJoinRequest(community.getId(), accountId); + }); + new CommunityJoinRequest(community.getId(), sender.getName(), sender.getUniqueId().toString(), accountId).publish(); + } + + public void handleCloseJoinRequest(Player sender, Community community, CommunityJoinRequestInfo info, boolean announce) + { + runAsync(() -> + { + _repo.removeJoinRequest(community.getId(), info.AccountId); + }); + new CommunityCloseJoinRequest(community.getId(), sender.getName(), info.Name, info.UUID.toString(), info.AccountId, announce).publish(); + } + + public void handleJoin(Player sender, Community community, boolean fromInvite) + { + final int accountId = Managers.get(CoreClientManager.class).getAccountId(sender); + final String playerName = Managers.get(CoreClientManager.class).Get(sender).getName(); + runAsync(() -> + { + _repo.addToCommunity(accountId, community.getId()); + if (fromInvite) + { + _repo.deleteInviteToCommunity(community.getId(), playerName); + } + }); + new CommunityUpdateMembership(community.getId(), sender.getName(), sender.getName(), sender.getUniqueId().toString(), accountId, false, false).publish(); + if (fromInvite) + { + new CommunityUnInvite(community.getId(), sender.getName(), sender.getName(), sender.getUniqueId().toString(), false).publish(); + } + } + + public void handleKick(Player sender, Community community, CommunityMemberInfo info) + { + runAsync(() -> + { + _repo.removeFromCommunity(info.AccountId, community.getId()); + }); + new CommunityUpdateMembership(community.getId(), sender.getName(), info.Name, info.UUID.toString(), info.AccountId, true, false).publish(); + } + + public void handleLeave(Player sender, Community community, CommunityMemberInfo info) + { + runAsync(() -> + { + _repo.removeFromCommunity(info.AccountId, community.getId()); + }); + new CommunityUpdateMembership(community.getId(), sender.getName(), info.Name, info.UUID.toString(), info.AccountId, false, true).publish(); + } + + public void handleSettingUpdate(Player sender, Community community, CommunitySetting setting, String newValue) + { + runAsync(() -> + { + _repo.updateCommunitySetting(setting, community.getId(), newValue); + }); + new CommunityUpdateSetting(community.getId(), sender.getName(), setting.toString(), newValue).publish(); + } + + public void handleNameUpdate(Player sender, Community community, String newName) + { + runAsync(() -> + { + _repo.updateCommunityName(community.getId(), newName); + }); + new CommunityUpdateName(community.getId(), sender.getName(), newName).publish(); + } + + public void handleRoleUpdate(Player sender, Community community, CommunityMemberInfo info, CommunityRole role) + { + runAsync(() -> + { + _repo.updateCommunityRole(info.AccountId, community.getId(), role); + }); + new CommunityUpdateMemberRole(community.getId(), sender.getName(), info.UUID.toString(), role.toString()).publish(); + } + + public void handleCreate(Player sender, String name) + { + int accountId = Managers.get(CoreClientManager.class).getAccountId(sender); + runAsync(() -> + { + _repo.createCommunity(name, accountId, id -> + { + if (id == -1) + { + sender.sendMessage(F.main(getName(), "Failed to create community " + F.elem(name))); + } + else + { + new CommunityCreate(sender.getUniqueId().toString(), id).publish(); + } + }); + }); + } + + public void handleDisband(Player sender, Community community) + { + runAsync(() -> + { + _repo.deleteCommunity(community.getId()); + }); + new CommunityDisband(sender.getName(), community.getId()).publish(); + } + + public void handleToggleReadingChat(Player sender, Community community) + { + final int accountId = Managers.get(CoreClientManager.class).getAccountId(sender); + final boolean reading = !community.getMembers().get(sender.getUniqueId()).ReadingChat; + + runAsync(() -> + { + _repo.setReadingChat(accountId, community.getId(), reading); + }); + new CommunityUpdateMemberChatReading(community.getId(), sender.getUniqueId().toString(), reading).publish(); + } + + @Override + public String getQuery(int accountId, String uuid, String name) + { + return "SELECT cm.communityId, cm.communityRole, c.region FROM communityMembers AS cm INNER JOIN communities AS c ON c.id=cm.communityId WHERE accountId=" + accountId + ";"; + } + + @Override + public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException + { + CommunityMemberData data = new CommunityMemberData(); + while (resultSet.next()) + { + Integer communityId = resultSet.getInt("communityId"); + CommunityRole role = CommunityRole.parseRole(resultSet.getString("communityRole")); + String region = resultSet.getString("region"); + if ((_us && region.equalsIgnoreCase("US")) || (!_us && region.equalsIgnoreCase("EU"))) + { + data.joinCommunity(communityId, role); + } + } + Set(uuid, data); + } + + @EventHandler + public void loadInvites(PlayerJoinEvent event) + { + final int accountId = Managers.get(CoreClientManager.class).getAccountId(event.getPlayer()); + final CommunityMemberData data = Get(event.getPlayer()); + runAsync(() -> + { + _repo.loadInvites(accountId, data.Invites); + runSync(() -> + { + if (data.Invites.size() > 0 && Managers.get(PreferencesManager.class).get(event.getPlayer()).isActive(Preference.COMMUNITY_INVITES)) + { + UtilPlayer.message(event.getPlayer(), F.main(getName(), "You have been invited to join " + F.elem(data.Invites.size()) + " communities!")); + } + }); + }); + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onChat(AsyncPlayerChatEvent event) + { + if (!event.getMessage().startsWith("!")) + { + return; + } + event.setCancelled(true); + Player sender = event.getPlayer(); + if (Get(sender).getCommunityChattingTo() != -1) + { + Community target = _loadedCommunities.get(Get(sender).getCommunityChattingTo()); + if (target == null || !target.getMembers().containsKey(event.getPlayer().getUniqueId())) + { + UtilPlayer.message(sender, F.main(getName(), "You are not in that community! Use " + F.elem("/com chat ") + " to select a new community to chat to!")); + } + else + { + if (Recharge.Instance.use(sender, "Community Chat to " + target.getId(), target.getChatDelay(), false, false)) + { + new CommunityChat(sender.getName(), target.getId(), event.getMessage().substring(1)).publish(); + } + else + { + UtilPlayer.message(sender, F.main(getName(), "You cannot chat to " + F.name(target.getName()) + " that quickly!")); + } + } + } + else + { + UtilPlayer.message(sender, F.main(getName(), "You are not chatting to a specific community! Use " + F.elem("/com chat ") + " to select a community to chat to.")); + } + } + + @Override + protected CommunityMemberData addPlayer(UUID uuid) + { + return new CommunityMemberData(); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberData.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberData.java new file mode 100644 index 000000000..d7138721a --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberData.java @@ -0,0 +1,84 @@ +package mineplex.core.communities; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import mineplex.core.Managers; + +public class CommunityMemberData +{ + private final Map _communities = new HashMap<>(); + + public final List Invites = new ArrayList<>(); + + private int _chattingTo = -1; + + public CommunityMemberData() + { + + } + + public int getTotalCommunities() + { + return _communities.size(); + } + + public boolean ownsCommunity() + { + return _communities.containsValue(CommunityRole.LEADER); + } + + public int getCommunityChattingTo() + { + return _chattingTo; + } + + public void setCommunityChattingTo(Community community) + { + _chattingTo = community.getId(); + } + + public Community[] getCommunities() + { + Community[] communities = new Community[_communities.size()]; + int index = 0; + for (Integer comId : _communities.keySet()) + { + communities[index] = Managers.get(CommunityManager.class).getLoadedCommunity(comId); + index++; + } + return communities; + } + + public boolean isMemberOf(Community community) + { + return _communities.containsKey(community.getId()); + } + + public CommunityRole getRoleIn(Community community) + { + return _communities.get(community.getId()); + } + + public void joinCommunity(Integer communityId, CommunityRole role) + { + _communities.put(communityId, role); + } + + public void joinCommunity(Community community) + { + joinCommunity(community.getId(), CommunityRole.MEMBER); + } + + public void setRoleIn(Community community, CommunityRole role) + { + _communities.replace(community.getId(), role); + } + + public void leaveCommunity(Community community) + { + _communities.remove(community.getId()); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberDataUpdateEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberDataUpdateEvent.java new file mode 100644 index 000000000..1fd22e0e1 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberDataUpdateEvent.java @@ -0,0 +1,32 @@ +package mineplex.core.communities; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class CommunityMemberDataUpdateEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + private Player _player; + + public CommunityMemberDataUpdateEvent(Player player) + { + _player = player; + } + + public Player getPlayer() + { + return _player; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberInfo.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberInfo.java new file mode 100644 index 000000000..fe62d8376 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMemberInfo.java @@ -0,0 +1,99 @@ +package mineplex.core.communities; + +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilTime; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityMemberInfo +{ + public String Name; + public final UUID UUID; + public final int AccountId; + public CommunityRole Role; + public boolean OwnsCommunity = false; + public boolean ReadingChat = true; + private ItemStack _memberIcon, _outsiderIcon; + private long _sinceLastLogin; + private boolean _online = false; + private String _currentServer = ""; + + public CommunityMemberInfo(String name, UUID uuid, int accountId, CommunityRole role, long timeSinceLastLogin) + { + Name = name; + UUID = uuid; + AccountId = accountId; + Role = role; + _sinceLastLogin = timeSinceLastLogin; + + buildIcons(); + } + + private void buildIcons() + { + ItemBuilder builder = new ItemBuilder(Material.SKULL_ITEM).setTitle(C.cGreenB + Name).setLore(C.cRed, C.cYellow + "Role " + C.cWhite + Role.getDisplay()); + _outsiderIcon = builder.build(); + builder.setTitle(!_online ? C.cRedB + Name : C.cGreenB + Name); + if (_online) + { + builder.addLore(C.cYellow + "Server " + C.cWhite + _currentServer); + } + else + { + builder.addLore(C.cYellow + "Last Seen " + C.cWhite + UtilTime.MakeStr(_sinceLastLogin) + " Ago"); + } + if (_online) + { + builder.setData((short)3); + builder.setPlayerHead(Name); + } + _memberIcon = builder.build(); + } + + public void update(String name, CommunityRole role, long timeSinceLastLogin, boolean online, String currentServer) + { + Name = name; + Role = role; + _sinceLastLogin = timeSinceLastLogin; + _online = online; + _currentServer = currentServer; + + buildIcons(); + } + + public boolean isOnline() + { + return _online; + } + + public ItemStack getRepresentation(CommunityRole viewerRole) + { + if (viewerRole == null) + { + return _outsiderIcon; + } + + ItemBuilder builder = new ItemBuilder(_memberIcon); + if ((viewerRole == CommunityRole.LEADER && Role != CommunityRole.LEADER) || (viewerRole.ordinal() < Role.ordinal())) + { + builder.addLore(C.cGold); + } + if (viewerRole == CommunityRole.LEADER && Role != CommunityRole.LEADER) + { + builder.addLore(C.cYellow + (Role == CommunityRole.COLEADER ? "Shift-" : "" ) + "Left Click " + C.cWhite + "Promote"); + if (Role != CommunityRole.MEMBER) + { + builder.addLore(C.cYellow + "Right Click " + C.cWhite + "Demote"); + } + } + if (viewerRole.ordinal() < Role.ordinal()) + { + builder.addLore(C.cYellow + "Shift-Right Click " + C.cWhite + "Kick"); + } + return builder.build(); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMembershipUpdateEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMembershipUpdateEvent.java new file mode 100644 index 000000000..959044ea3 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityMembershipUpdateEvent.java @@ -0,0 +1,31 @@ +package mineplex.core.communities; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class CommunityMembershipUpdateEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + private Community _community; + + public CommunityMembershipUpdateEvent(Community community) + { + _community = community; + } + + public Community getCommunity() + { + return _community; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityNameUpdateEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityNameUpdateEvent.java new file mode 100644 index 000000000..a583c6ee9 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityNameUpdateEvent.java @@ -0,0 +1,31 @@ +package mineplex.core.communities; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class CommunityNameUpdateEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + private Community _community; + + public CommunityNameUpdateEvent(Community community) + { + _community = community; + } + + public Community getCommunity() + { + return _community; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityRole.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityRole.java new file mode 100644 index 000000000..c98d7f0b9 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityRole.java @@ -0,0 +1,34 @@ +package mineplex.core.communities; + +public enum CommunityRole +{ + LEADER("Leader"), + COLEADER("Co-Leader"), + MEMBER("Member") + ; + + private String _displayName; + + private CommunityRole(String displayName) + { + _displayName = displayName; + } + + public String getDisplay() + { + return _displayName; + } + + public static CommunityRole parseRole(String role) + { + for (CommunityRole test : CommunityRole.values()) + { + if (test.toString().equalsIgnoreCase(role)) + { + return test; + } + } + + return CommunityRole.MEMBER; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySetting.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySetting.java new file mode 100644 index 000000000..fc049ac5e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySetting.java @@ -0,0 +1,124 @@ +package mineplex.core.communities; + +import org.bukkit.ChatColor; + +import mineplex.core.common.Pair; +import mineplex.core.common.util.Callback; +import mineplex.core.communities.Community.PrivacySetting; +import mineplex.core.game.GameDisplay; + +public enum CommunitySetting +{ + CHAT_NAME_COLOR(1, pair -> + { + String value = pair.getLeft(); + Community community = pair.getRight(); + + ChatColor color = ChatColor.valueOf(value); + if (color == null || !color.isColor()) + { + return; + } + community.setChatFormatting(new ChatColor[] {color, community.getChatFormatting()[1], community.getChatFormatting()[2]}); + } + ), + CHAT_PLAYER_COLOR(2, pair -> + { + String value = pair.getLeft(); + Community community = pair.getRight(); + + ChatColor color = ChatColor.valueOf(value); + if (color == null || !color.isColor()) + { + return; + } + community.setChatFormatting(new ChatColor[] {community.getChatFormatting()[0], color, community.getChatFormatting()[2]}); + } + ), + CHAT_MESSAGE_COLOR(3, pair -> + { + String value = pair.getLeft(); + Community community = pair.getRight(); + + ChatColor color = ChatColor.valueOf(value); + if (color == null || !color.isColor()) + { + return; + } + community.setChatFormatting(new ChatColor[] {community.getChatFormatting()[0], community.getChatFormatting()[1], color}); + } + ), + CHAT_DELAY(4, pair -> + { + String value = pair.getLeft(); + Community community = pair.getRight(); + + try + { + Long delay = Long.parseLong(value); + community.setChatDelay(delay); + } + catch (Exception e) + { + return; + } + } + ), + FAVORITE_GAME(5, pair -> + { + String value = pair.getLeft(); + Community community = pair.getRight(); + + GameDisplay display = GameDisplay.matchName(value); + community.setFavoriteGame(display); + } + ), + PRIVACY(6, pair -> + { + String value = pair.getLeft(); + Community community = pair.getRight(); + + PrivacySetting setting = PrivacySetting.parsePrivacy(value); + community.setPrivacySetting(setting); + } + ), + DESCRIPTION(7, pair -> + { + String value = pair.getLeft(); + Community community = pair.getRight(); + + community.setDescription(value); + }); + + private int _id; + private Callback> _parser; + + private CommunitySetting(int id, Callback> parseValue) + { + _id = id; + _parser = parseValue; + } + + public int getId() + { + return _id; + } + + public void parseValueInto(String value, Community community) + { + _parser.run(Pair.create(value, community)); + } + + public static CommunitySetting getSetting(Integer id) + { + for (CommunitySetting setting : CommunitySetting.values()) + { + if (setting.getId() == id) + { + return setting; + } + } + + return null; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySettingUpdateEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySettingUpdateEvent.java new file mode 100644 index 000000000..5f7185fdc --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySettingUpdateEvent.java @@ -0,0 +1,31 @@ +package mineplex.core.communities; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class CommunitySettingUpdateEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + private Community _community; + + public CommunitySettingUpdateEvent(Community community) + { + _community = community; + } + + public Community getCommunity() + { + return _community; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityChatCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityChatCommand.java new file mode 100644 index 000000000..a1edba960 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityChatCommand.java @@ -0,0 +1,42 @@ +package mineplex.core.communities.commands; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; + +public class CommunityChatCommand extends CommandBase +{ + public CommunityChatCommand(CommunityManager plugin) + { + super(plugin, Rank.ALL, "chat"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + UtilPlayer.message(caller, F.help("/com chat ", "Selects which community you chat to", Rank.ALL, ChatColor.AQUA)); + return; + } + Community c = Plugin.getLoadedCommunity(args[0]); + if (c == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That community was not found!")); + return; + } + if (!c.getMembers().containsKey(caller.getUniqueId())) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are not in " + F.name(c.getName()) + "!")); + return; + } + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are now chatting to " + F.name(c.getName()) + "! Use " + F.elem("!") + " before your message to use community chat!")); + Plugin.Get(caller).setCommunityChattingTo(c); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityCommand.java new file mode 100644 index 000000000..90af36ac7 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityCommand.java @@ -0,0 +1,68 @@ +package mineplex.core.communities.commands; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.command.MultiCommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.gui.community.CommunityMembersPage; +import mineplex.core.communities.gui.overview.CommunityOverviewPage; + +public class CommunityCommand extends MultiCommandBase +{ + public CommunityCommand(CommunityManager plugin) + { + super(plugin, Rank.ALL, "community", "communities", "com"); + + AddCommand(new CommunityChatCommand(plugin)); + AddCommand(new CommunityCreateCommand(plugin)); + AddCommand(new CommunityDescriptionCommand(plugin)); + AddCommand(new CommunityDisbandCommand(plugin)); + AddCommand(new CommunityInviteCommand(plugin)); + AddCommand(new CommunityJoinCommand(plugin)); + AddCommand(new CommunityMCSCommand(plugin)); + //AddCommand(new CommunityMenuCommand(plugin)); + AddCommand(new CommunityRenameCommand(plugin)); + AddCommand(new CommunityUnInviteCommand(plugin)); + } + + @Override + protected void Help(Player caller, String[] args) + { + if (args.length > 0) + { + if (args[0].equalsIgnoreCase("help")) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "Community Commands:")); + UtilPlayer.message(caller, F.help("/com ", "Opens a community's menu", Rank.ALL, ChatColor.DARK_AQUA)); + //UtilPlayer.message(caller, F.help("/com menu", "Opens your community menu", Rank.ALL)); + UtilPlayer.message(caller, F.help("/com invite ", "Invites a player to a community you manage", Rank.ALL, ChatColor.DARK_AQUA)); + UtilPlayer.message(caller, F.help("/com uninvite ", "Revokes a player's invitation to a community you manage", Rank.ALL, ChatColor.DARK_AQUA)); + UtilPlayer.message(caller, F.help("/com join ", "Joins a community that is open or you have been invited to", Rank.ALL, ChatColor.DARK_AQUA)); + UtilPlayer.message(caller, F.help("/com chat ", "Selects which community you chat to", Rank.ALL, ChatColor.DARK_AQUA)); + UtilPlayer.message(caller, F.help("/com create ", "Creates a new community", Rank.ETERNAL, ChatColor.DARK_AQUA)); + UtilPlayer.message(caller, F.help("/com rename ", "Changes the name of a community you own", Rank.ETERNAL, ChatColor.DARK_AQUA)); + UtilPlayer.message(caller, F.help("/com mcs ", "Opens the Mineplex Community Server of a community you manage", Rank.ALL, ChatColor.DARK_AQUA)); + UtilPlayer.message(caller, F.help("/com description ", "Sets the description of a community you manage", Rank.ALL, ChatColor.DARK_AQUA)); + UtilPlayer.message(caller, F.help("/com disband ", "Disbands a community you own", Rank.ETERNAL, ChatColor.DARK_AQUA)); + return; + } + Community community = Plugin.getLoadedCommunity(args[0]); + if (community == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "Could not find community " + F.name(args[0]) + "!")); + } + else + { + new CommunityMembersPage(caller, community); + } + return; + } + + new CommunityOverviewPage(caller); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityCreateCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityCreateCommand.java new file mode 100644 index 000000000..35c545edc --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityCreateCommand.java @@ -0,0 +1,65 @@ +package mineplex.core.communities.commands; + +import java.util.Arrays; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.chat.Chat; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; + +public class CommunityCreateCommand extends CommandBase +{ + public CommunityCreateCommand(CommunityManager plugin) + { + super(plugin, Rank.ETERNAL, "create"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + UtilPlayer.message(caller, F.help("/com create ", "Creates a new community", Rank.ETERNAL, ChatColor.AQUA)); + return; + } + Community c = Plugin.getLoadedCommunity(args[0]); + if (c != null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "A community already exists with that name!")); + return; + } + if (Plugin.Get(caller).ownsCommunity()) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You already own a community!")); + return; + } + if (args[0].length() > 15 || Plugin.ALPHA_NUMERIC_PATTERN.matcher(args[0]).find()) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "A community name cannot be longer than 15 characters and must be alphanumeric!")); + return; + } + if (Arrays.asList(Plugin.BLOCKED_NAMES).contains(args[0].toLowerCase())) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That name is not allowed!")); + return; + } + Plugin.runAsync(() -> + { + if (Managers.get(Chat.class).getFilteredMessage(caller, args[0]).contains("*")) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That name is not allowed!")); + } + else + { + Plugin.handleCreate(caller, args[0]); + } + }); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityDescriptionCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityDescriptionCommand.java new file mode 100644 index 000000000..efaae74b2 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityDescriptionCommand.java @@ -0,0 +1,77 @@ +package mineplex.core.communities.commands; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.chat.Chat; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.CommunitySetting; + +public class CommunityDescriptionCommand extends CommandBase +{ + public CommunityDescriptionCommand(CommunityManager plugin) + { + super(plugin, Rank.ALL, "description"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 2) + { + UtilPlayer.message(caller, F.help("/com description ", "Sets the description of a community you manage", Rank.ALL, ChatColor.AQUA)); + return; + } + Community c = Plugin.getLoadedCommunity(args[0]); + String desc = args[1]; + for (int i = 2; i < args.length; i++) + { + desc += (" " + args[i]); + } + if (c == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That community was not found!")); + return; + } + if (c.getMembers().getOrDefault(caller.getUniqueId(), new CommunityMemberInfo(caller.getName(), caller.getUniqueId(), -1, CommunityRole.MEMBER, -1L)).Role.ordinal() > CommunityRole.COLEADER.ordinal()) + { + if (!Managers.get(CoreClientManager.class).Get(caller).GetRank().has(Rank.ADMIN)) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are not a co-leader of " + F.name(c.getName()) + "!")); + return; + } + } + if (desc.length() > 30) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "A community description cannot be longer than 30 characters!")); + return; + } + if (Plugin.ALPHA_NUMERIC_PATTERN.matcher(desc.replace(" ", "").replace("!", "").replace("?", "").replace(".", "").replace("'", "").replace("\"", "")).find()) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "A community description must be alphanumeric!")); + return; + } + final String description = desc; + Plugin.runAsync(() -> + { + if (Managers.get(Chat.class).getFilteredMessage(caller, description).contains("*")) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That description is not allowed!")); + } + else + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You have changed the description of " + F.name(c.getName()) + " to " + F.elem(description) + "!")); + Plugin.handleSettingUpdate(caller, c, CommunitySetting.DESCRIPTION, description); + } + }); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityDisbandCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityDisbandCommand.java new file mode 100644 index 000000000..a70b77542 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityDisbandCommand.java @@ -0,0 +1,52 @@ +package mineplex.core.communities.commands; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityRole; + +public class CommunityDisbandCommand extends CommandBase +{ + public CommunityDisbandCommand(CommunityManager plugin) + { + super(plugin, Rank.ETERNAL, "disband"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + UtilPlayer.message(caller, F.help("/com disband ", "Disbands a community you own", Rank.ETERNAL, ChatColor.AQUA)); + return; + } + Community c = Plugin.getLoadedCommunity(args[0]); + if (c == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That community was not found!")); + return; + } + if (c.getMembers().getOrDefault(caller.getUniqueId(), new CommunityMemberInfo(caller.getName(), caller.getUniqueId(), -1, CommunityRole.MEMBER, -1L)).Role != CommunityRole.LEADER) + { + if (!Managers.get(CoreClientManager.class).Get(caller).GetRank().has(Rank.ADMIN)) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are not the leader of " + F.name(c.getName()) + "!")); + return; + } + } + if (!c.getMembers().containsKey(caller.getUniqueId())) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You have disbanded community " + F.name(c.getName()) + "!")); + } + Plugin.handleDisband(caller, c); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityInviteCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityInviteCommand.java new file mode 100644 index 000000000..f3b6e6b65 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityInviteCommand.java @@ -0,0 +1,57 @@ +package mineplex.core.communities.commands; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityRole; + +public class CommunityInviteCommand extends CommandBase +{ + public CommunityInviteCommand(CommunityManager plugin) + { + super(plugin, Rank.ALL, "invite"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 2) + { + UtilPlayer.message(caller, F.help("/com invite ", "Invites a player to a community you manage", Rank.ALL, ChatColor.AQUA)); + return; + } + String player = args[0]; + Community c = Plugin.getLoadedCommunity(args[1]); + if (c == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That community was not found!")); + return; + } + if (c.getMembers().getOrDefault(caller.getUniqueId(), new CommunityMemberInfo(caller.getName(), caller.getUniqueId(), -1, CommunityRole.MEMBER, -1L)).Role.ordinal() > CommunityRole.COLEADER.ordinal()) + { + if (!Managers.get(CoreClientManager.class).Get(caller).GetRank().has(Rank.ADMIN)) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are not a co-leader of " + F.name(c.getName()) + "!")); + return; + } + } + for (CommunityMemberInfo info : c.getMembers().values()) + { + if (info.Name.equalsIgnoreCase(player)) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), F.name(player) + " is already a member of " + F.name(c.getName()) + "!")); + return; + } + } + Plugin.handleInvite(caller, c, player); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityJoinCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityJoinCommand.java new file mode 100644 index 000000000..202d73fc3 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityJoinCommand.java @@ -0,0 +1,47 @@ +package mineplex.core.communities.commands; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.Community.PrivacySetting; +import mineplex.core.communities.CommunityManager; + +public class CommunityJoinCommand extends CommandBase +{ + public CommunityJoinCommand(CommunityManager plugin) + { + super(plugin, Rank.ALL, "join"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + UtilPlayer.message(caller, F.help("/com join ", "Joins a community that is open or you have been invited to", Rank.ALL, ChatColor.AQUA)); + return; + } + Community c = Plugin.getLoadedCommunity(args[0]); + if (c == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That community was not found!")); + return; + } + if (c.getMembers().containsKey(caller.getUniqueId())) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are already in " + F.name(c.getName()) + "!")); + return; + } + if (c.getPrivacySetting() != PrivacySetting.OPEN && !Plugin.Get(caller).Invites.contains(c.getId())) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are have not been invited to " + F.name(c.getName()) + "!")); + return; + } + Plugin.handleJoin(caller, c, Plugin.Get(caller).Invites.contains(c.getId())); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityMCSCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityMCSCommand.java new file mode 100644 index 000000000..1e499c57f --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityMCSCommand.java @@ -0,0 +1,50 @@ +package mineplex.core.communities.commands; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityRole; +import mineplex.core.personalServer.PersonalServerManager; + +public class CommunityMCSCommand extends CommandBase +{ + public CommunityMCSCommand(CommunityManager plugin) + { + super(plugin, Rank.ALL, "mcs"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + UtilPlayer.message(caller, F.help("/com mcs ", "Opens the Mineplex Community Server of a community you manage", Rank.ALL, ChatColor.AQUA)); + return; + } + Community c = Plugin.getLoadedCommunity(args[0]); + if (c == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That community was not found!")); + return; + } + if (c.getMembers().getOrDefault(caller.getUniqueId(), new CommunityMemberInfo(caller.getName(), caller.getUniqueId(), -1, CommunityRole.MEMBER, -1L)).Role.ordinal() > CommunityRole.COLEADER.ordinal()) + { + if (!Managers.get(CoreClientManager.class).Get(caller).GetRank().has(Rank.ADMIN)) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are not a co-leader of " + F.name(c.getName()) + "!")); + return; + } + } + + Managers.get(PersonalServerManager.class).hostCommunityServer(caller, c); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityMenuCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityMenuCommand.java new file mode 100644 index 000000000..1e93f267e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityMenuCommand.java @@ -0,0 +1,22 @@ +package mineplex.core.communities.commands; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.gui.overview.CommunityOverviewPage; + +public class CommunityMenuCommand extends CommandBase +{ + public CommunityMenuCommand(CommunityManager plugin) + { + super(plugin, Rank.ALL, "menu"); + } + + @Override + public void Execute(Player caller, String[] args) + { + new CommunityOverviewPage(caller); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityRenameCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityRenameCommand.java new file mode 100644 index 000000000..bfa1863bf --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityRenameCommand.java @@ -0,0 +1,81 @@ +package mineplex.core.communities.commands; + +import java.util.Arrays; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.chat.Chat; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityRole; + +public class CommunityRenameCommand extends CommandBase +{ + public CommunityRenameCommand(CommunityManager plugin) + { + super(plugin, Rank.ETERNAL, "rename"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 2) + { + UtilPlayer.message(caller, F.help("/com rename ", "Changes the name of a community you own", Rank.ETERNAL, ChatColor.AQUA)); + return; + } + Community c = Plugin.getLoadedCommunity(args[0]); + String newName = args[1]; + if (c == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That community was not found!")); + return; + } + if (c.getMembers().getOrDefault(caller.getUniqueId(), new CommunityMemberInfo(caller.getName(), caller.getUniqueId(), -1, CommunityRole.MEMBER, -1L)).Role != CommunityRole.LEADER) + { + if (!Managers.get(CoreClientManager.class).Get(caller).GetRank().has(Rank.ADMIN)) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are not the leader of " + F.name(c.getName()) + "!")); + return; + } + } + if (Plugin.getLoadedCommunity(newName) != null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "A community already exists with that name!")); + return; + } + if (newName.length() > 15 || Plugin.ALPHA_NUMERIC_PATTERN.matcher(newName).find()) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "A community name cannot be longer than 15 characters and must be alphanumeric!")); + return; + } + if (Arrays.asList(Plugin.BLOCKED_NAMES).contains(newName.toLowerCase())) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That name is not allowed!")); + return; + } + Plugin.runAsync(() -> + { + if (Managers.get(Chat.class).getFilteredMessage(caller, newName).contains("*")) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That name is not allowed!")); + } + else + { + if (!c.getMembers().containsKey(caller.getUniqueId())) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You have changed the name of " + F.name(c.getName()) + " to " + F.name(newName) + "!")); + } + Plugin.handleNameUpdate(caller, c, newName); + } + }); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityUnInviteCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityUnInviteCommand.java new file mode 100644 index 000000000..99b5e9636 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityUnInviteCommand.java @@ -0,0 +1,49 @@ +package mineplex.core.communities.commands; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityRole; + +public class CommunityUnInviteCommand extends CommandBase +{ + public CommunityUnInviteCommand(CommunityManager plugin) + { + super(plugin, Rank.ALL, "uninvite"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 2) + { + UtilPlayer.message(caller, F.help("/com uninvite ", "Revokes a player's invitation to a community you manage", Rank.ALL, ChatColor.AQUA)); + return; + } + String player = args[0]; + Community c = Plugin.getLoadedCommunity(args[1]); + if (c == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "That community was not found!")); + return; + } + if (c.getMembers().getOrDefault(caller.getUniqueId(), new CommunityMemberInfo(caller.getName(), caller.getUniqueId(), -1, CommunityRole.MEMBER, -1L)).Role.ordinal() > CommunityRole.COLEADER.ordinal()) + { + if (!Managers.get(CoreClientManager.class).Get(caller).GetRank().has(Rank.ADMIN)) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "You are not a co-leader of " + F.name(c.getName()) + "!")); + return; + } + } + Plugin.handleUninvite(caller, c, player); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/ActionButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/ActionButton.java new file mode 100644 index 000000000..b7e1a94bc --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/ActionButton.java @@ -0,0 +1,27 @@ +package mineplex.core.communities.gui; + +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.Callback; + +public class ActionButton extends CommunitiesGUIButton +{ + private Callback _onClick; + + public ActionButton(ItemStack icon, Callback onClick) + { + super(icon); + + _onClick = onClick; + } + + @Override + public void update() {} + + @Override + public void handleClick(ClickType type) + { + _onClick.run(type); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIButton.java new file mode 100644 index 000000000..a18b7e1f2 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIButton.java @@ -0,0 +1,26 @@ +package mineplex.core.communities.gui; + +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.Managers; +import mineplex.core.communities.CommunityManager; + +public abstract class CommunitiesGUIButton +{ + public ItemStack Button = null; + + public CommunitiesGUIButton(ItemStack button) + { + Button = button; + } + + public static CommunityManager getCommunityManager() + { + return Managers.get(CommunityManager.class); + } + + public abstract void update(); + + public abstract void handleClick(ClickType type); +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIPage.java new file mode 100644 index 000000000..15bdbaf82 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIPage.java @@ -0,0 +1,107 @@ +package mineplex.core.communities.gui; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; + +import mineplex.core.Managers; +import mineplex.core.common.util.UtilServer; +import mineplex.core.communities.CommunityManager; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; + +public abstract class CommunitiesGUIPage implements Listener +{ + protected Player Viewer; + protected Inventory Inv; + protected Map Buttons = new HashMap<>(); + + public CommunitiesGUIPage(String name, int rows, Player viewer) + { + Viewer = viewer; + Inv = Bukkit.createInventory(viewer, 9 * rows, name); + } + + private void disable() + { + HandlerList.unregisterAll(this); + } + + public static CommunityManager getCommunityManager() + { + return Managers.get(CommunityManager.class); + } + + public void open() + { + Viewer.openInventory(Inv); + UtilServer.RegisterEvents(this); + } + + public void updateButtons(boolean callUpdate) + { + Inv.clear(); + Buttons.entrySet().stream().forEach(entry -> + { + if (callUpdate) + { + entry.getValue().update(); + } + Inv.setItem(entry.getKey(), entry.getValue().Button); + }); + Viewer.updateInventory(); + } + + @EventHandler + public void onUpdate(UpdateEvent event) + { + if (event.getType() == UpdateType.TICK) + { + if (Viewer.getOpenInventory() == null || Viewer.getOpenInventory().getTopInventory() == null || !Viewer.getOpenInventory().getTopInventory().getTitle().equals(Inv.getTitle())) + { + disable(); + return; + } + } + if (event.getType() == UpdateType.SEC_05) + { + Buttons.entrySet().forEach(entry -> + { + entry.getValue().update(); + Inv.setItem(entry.getKey(), entry.getValue().Button); + }); + } + } + + @EventHandler + public void handleClick(InventoryClickEvent event) + { + if (event.getClickedInventory() == null || !event.getClickedInventory().getTitle().equals(Inv.getTitle())) + { + return; + } + if (!Viewer.getName().equals(event.getWhoClicked().getName())) + { + return; + } + event.setCancelled(true); + if (!Recharge.Instance.use(Viewer, "Communities Button Click", 500, false, false)) + { + return; + } + Integer slot = event.getSlot(); + if (!Buttons.containsKey(slot)) + { + return; + } + Buttons.get(slot).handleClick(event.getClick()); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserButton.java new file mode 100644 index 000000000..e999b2a8f --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserButton.java @@ -0,0 +1,41 @@ +package mineplex.core.communities.gui.browser; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.LineFormat; +import mineplex.core.common.util.UtilText; +import mineplex.core.communities.Community; +import mineplex.core.communities.gui.CommunitiesGUIButton; +import mineplex.core.communities.gui.community.CommunityMembersPage; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityBrowserButton extends CommunitiesGUIButton +{ + private Player _viewer; + private Community _community; + + @SuppressWarnings("deprecation") + public CommunityBrowserButton(Player viewer, Community community) + { + super(new ItemBuilder(new ItemStack(community.getFavoriteGame().getMaterial(), 1, community.getFavoriteGame().getMaterialData(), null)).setTitle(C.cGreenB + community.getName()).addLore(UtilText.splitLinesToArray(new String[] {C.cRed, C.cYellow + "Members " + C.cWhite + community.getMembers().size(), C.cYellow + "Favorite Game " + C.cWhite + community.getFavoriteGame().getName(), C.cYellow + "Privacy " + C.cWhite + community.getPrivacySetting().getDisplayText(), C.cYellow + "Description " + C.cWhite + community.getDescription(), C.cBlue, C.cGreen + "Click to view community"}, LineFormat.LORE)).build()); + + _viewer = viewer; + _community = community; + } + + @SuppressWarnings("deprecation") + @Override + public void update() + { + Button = new ItemBuilder(new ItemStack(_community.getFavoriteGame().getMaterial(), 1, _community.getFavoriteGame().getMaterialData(), null)).setTitle(C.cGreenB + _community.getName()).addLore(UtilText.splitLinesToArray(new String[] {C.cRed, C.cYellow + "Members " + C.cWhite + _community.getMembers().size(), C.cYellow + "Favorite Game " + C.cWhite + _community.getFavoriteGame().getName(), C.cYellow + "Privacy " + C.cWhite + _community.getPrivacySetting().getDisplayText(), C.cYellow + "Description " + C.cWhite + _community.getDescription(), C.cBlue, C.cGreen + "Click to view community"}, LineFormat.LORE)).build(); + } + + @Override + public void handleClick(ClickType type) + { + new CommunityMembersPage(_viewer, _community).open(); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserPage.java new file mode 100644 index 000000000..482a40142 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserPage.java @@ -0,0 +1,124 @@ +package mineplex.core.communities.gui.browser; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.C; +import mineplex.core.communities.CommunityBrowserUpdateEvent; +import mineplex.core.communities.CommunityDisbandEvent; +import mineplex.core.communities.gui.ActionButton; +import mineplex.core.communities.gui.CommunitiesGUIPage; +import mineplex.core.communities.gui.overview.CommunityInvitesPage; +import mineplex.core.communities.gui.overview.CommunityOverviewPage; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityBrowserPage extends CommunitiesGUIPage +{ + private static final int COMMUNITIES_PER_PAGE = 27; + + private int _page = 1; + + private List _displaying = new ArrayList<>(); + + //protected PrivacySetting PrivacyFilter = null; + //protected GameDisplay GameFilter = null; + + public CommunityBrowserPage(Player viewer) + { + super("Community Browser", 6, viewer); + + setup(1, true); + open(); + } + + private void setup(int page, boolean initial) + { + if (initial) + { + Buttons.clear(); + Inv.clear(); + } + { + //1 + ActionButton communitiesButton = new ActionButton(new ItemBuilder(Material.EMERALD).setTitle(C.cGreenB + "Your Communities").build(), clickType -> + { + new CommunityOverviewPage(Viewer).open(); + }); + Buttons.put(1, communitiesButton); + Inv.setItem(1, communitiesButton.Button); + //4 + ActionButton browserButton = new ActionButton(new ItemBuilder(Material.COMPASS).setTitle(C.cGreenB + "Browse Communities").build(), clickType -> {}); + Buttons.put(4, browserButton); + Inv.setItem(4, browserButton.Button); + //7 + ActionButton invitesButton = new ActionButton(new ItemBuilder(Material.PAPER).setTitle(C.cGreenB + "Community Invites").build(), clickType -> + { + new CommunityInvitesPage(Viewer); + }); + Buttons.put(7, invitesButton); + Inv.setItem(7, invitesButton.Button); + } + { + ActionButton back = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Previous Page").build(), clickType -> + { + if (_page == 1) + { + return; + } + setup(_page - 1, false); + }); + ActionButton next = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Next Page").build(), clickType -> + { + setup(_page + 1, false); + }); + Buttons.put(45, back); + Inv.setItem(45, back.Button); + Buttons.put(53, next); + Inv.setItem(53, next.Button); + } + + int slot = 18; + boolean cleared = false; + _displaying.clear(); + for (int i = (page - 1) * COMMUNITIES_PER_PAGE; i < (page - 1) * COMMUNITIES_PER_PAGE + COMMUNITIES_PER_PAGE && i < getCommunityManager().BrowserIds.size(); i++) + { + if (!cleared && !initial) + { + cleared = true; + _page = page; + for (int clear = 18; clear < 45; clear++) + { + Buttons.remove(clear); + Inv.setItem(clear, null); + } + } + CommunityBrowserButton button = new CommunityBrowserButton(Viewer, getCommunityManager().getLoadedCommunity(getCommunityManager().BrowserIds.get(i))); + _displaying.add(getCommunityManager().BrowserIds.get(i)); + Buttons.put(slot, button); + Inv.setItem(slot, button.Button); + + slot++; + } + + Viewer.updateInventory(); + } + + @EventHandler + public void onBrowserUpdate(CommunityBrowserUpdateEvent event) + { + setup(1, true); + } + + @EventHandler + public void onCommunityDisband(CommunityDisbandEvent event) + { + if (_displaying.contains(event.getCommunity().getId())) + { + setup(1, true); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityButton.java new file mode 100644 index 000000000..ee5696f5a --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityButton.java @@ -0,0 +1,99 @@ +package mineplex.core.communities.gui.community; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.LineFormat; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilText; +import mineplex.core.communities.Community; +import mineplex.core.communities.Community.PrivacySetting; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.gui.CommunitiesGUIButton; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityButton extends CommunitiesGUIButton +{ + private Player _viewer; + private Community _community; + + public CommunityButton(Player viewer, Community community) + { + super(getDisplay(community, viewer)); + + _viewer = viewer; + _community = community; + } + + private static ItemStack getDisplay(Community community, Player viewer) + { + ItemStack item = new ItemBuilder(Material.REDSTONE_BLOCK).setTitle(C.cGreenB + community.getName()).addLore(UtilText.splitLinesToArray(new String[] {C.cGreen, C.cYellow + "Members " + C.cWhite + community.getMembers().size(), C.cYellow + "Description " + C.cWhite + community.getDescription(), C.cRed, C.cYellow + "Shift-Left Click " + C.cWhite + "Request To Join"}, LineFormat.LORE)).build(); + + if (community.getMembers().containsKey(viewer.getUniqueId())) + { + ItemBuilder builder = new ItemBuilder(Material.EMERALD_BLOCK).setTitle(C.cGreenB + community.getName()).addLore(UtilText.splitLinesToArray(new String[] {C.cGreen, C.cYellow + "Members " + C.cWhite + community.getMembers().size(), C.cYellow + "Description " + C.cWhite + community.getDescription(), C.cRed, C.cYellow + "Shift-Left Click " + C.cWhite + "Leave Community"}, LineFormat.LORE)); + if (community.getMembers().get(viewer.getUniqueId()).Role == CommunityRole.LEADER) + { + builder.addLore(C.cBlue); + builder.addLore(UtilText.splitLineToArray(C.cGray + "Use " + C.cYellow + "/com disband " + community.getName() + C.cGray + " to disband!", LineFormat.LORE)); + } + item = builder.build(); + } + else if (community.getJoinRequests().containsKey(viewer.getUniqueId())) + { + item = new ItemBuilder(Material.REDSTONE_BLOCK).setTitle(C.cGold + community.getName()).addLore(UtilText.splitLinesToArray(new String[] {C.cGreen, C.cYellow + "Members " + C.cWhite + community.getMembers().size(), C.cYellow + "Description " + C.cWhite + community.getDescription(), C.cRed, C.cYellow + "Shift-Left Click " + C.cWhite + "Cancel Join Request"}, LineFormat.LORE)).build(); + } + else if (getCommunityManager().Get(viewer).Invites.contains(community.getId()) || community.getPrivacySetting() == PrivacySetting.OPEN) + { + item = new ItemBuilder(Material.REDSTONE_BLOCK).setTitle(C.cGold + community.getName()).addLore(UtilText.splitLinesToArray(new String[] {C.cGreen, C.cYellow + "Members " + C.cWhite + community.getMembers().size(), C.cYellow + "Description " + C.cWhite + community.getDescription(), C.cRed, C.cYellow + "Shift-Left Click " + C.cWhite + "Join Community"}, LineFormat.LORE)).build(); + } + else if (community.getPrivacySetting() == PrivacySetting.PRIVATE) + { + item = new ItemBuilder(Material.REDSTONE_BLOCK).setTitle(C.cGreenB + community.getName()).addLore(UtilText.splitLinesToArray(new String[] {C.cGreen, C.cYellow + "Members " + C.cWhite + community.getMembers().size(), C.cYellow + "Description " + C.cWhite + community.getDescription(), C.cRed, C.cRed + "Closed"}, LineFormat.LORE)).build(); + } + + return item; + } + + @Override + public void update() + { + Button = getDisplay(_community, _viewer); + } + + @Override + public void handleClick(ClickType type) + { + if (type == ClickType.SHIFT_LEFT) + { + if (_community.getMembers().containsKey(_viewer.getUniqueId())) + { + if (_community.getMembers().get(_viewer.getUniqueId()).Role == CommunityRole.LEADER) + { + UtilPlayer.message(_viewer, F.main(getCommunityManager().getName(), "You cannot leave " + F.name(_community.getName()) + " without passing on leadership first! If you want to disband your community, type " + F.elem("/com disband " + _community.getName()) + "!")); + return; + } + getCommunityManager().handleLeave(_viewer, _community, _community.getMembers().get(_viewer.getUniqueId())); + } + else if (_community.getJoinRequests().containsKey(_viewer.getUniqueId())) + { + getCommunityManager().handleCloseJoinRequest(_viewer, _community, _community.getJoinRequests().get(_viewer.getUniqueId()), false); + } + else if (getCommunityManager().Get(_viewer).Invites.contains(_community.getId()) || _community.getPrivacySetting() == PrivacySetting.OPEN) + { + getCommunityManager().handleJoin(_viewer, _community, getCommunityManager().Get(_viewer).Invites.contains(_community.getId())); + } + else + { + if (_community.getPrivacySetting() != PrivacySetting.PRIVATE) + { + getCommunityManager().handleJoinRequest(_viewer, _community); + } + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityChatReadingButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityChatReadingButton.java new file mode 100644 index 000000000..38382123a --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityChatReadingButton.java @@ -0,0 +1,47 @@ +package mineplex.core.communities.gui.community; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.communities.Community; +import mineplex.core.communities.gui.CommunitiesGUIButton; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityChatReadingButton extends CommunitiesGUIButton +{ + private Player _viewer; + private Community _community; + + public CommunityChatReadingButton(Player viewer, Community community) + { + super(getDisplay(community, viewer)); + + _viewer = viewer; + _community = community; + } + + private static ItemStack getDisplay(Community community, Player viewer) + { + ItemStack item = new ItemBuilder(Material.BOOK_AND_QUILL).setTitle(C.cGreenB + "Toggle Chat Visibility").build(); + + return item; + } + + @Override + public void update() + { + Button = getDisplay(_community, _viewer); + } + + @Override + public void handleClick(ClickType type) + { + if (_community.getMembers().containsKey(_viewer.getUniqueId())) + { + getCommunityManager().handleToggleReadingChat(_viewer, _community); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityJoinRequestButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityJoinRequestButton.java new file mode 100644 index 000000000..ad9af1d6e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityJoinRequestButton.java @@ -0,0 +1,50 @@ +package mineplex.core.communities.gui.community; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityJoinRequestInfo; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.gui.CommunitiesGUIButton; + +public class CommunityJoinRequestButton extends CommunitiesGUIButton +{ + private Player _viewer; + private Community _community; + private CommunityJoinRequestInfo _info; + + public CommunityJoinRequestButton(Player viewer, Community community, CommunityJoinRequestInfo info) + { + super(info.getRepresentation()); + + _viewer = viewer; + _community = community; + _info = info; + } + + @Override + public void update() + { + Button = _info.getRepresentation(); + } + + @Override + public void handleClick(ClickType type) + { + if (type == ClickType.LEFT) + { + if (getCommunityManager().Get(_viewer).getRoleIn(_community) != null && getCommunityManager().Get(_viewer).getRoleIn(_community).ordinal() <= CommunityRole.COLEADER.ordinal()) + { + getCommunityManager().handleInvite(_viewer, _community, _info.Name); + } + } + if (type == ClickType.SHIFT_RIGHT) + { + if (getCommunityManager().Get(_viewer).getRoleIn(_community) != null && getCommunityManager().Get(_viewer).getRoleIn(_community).ordinal() <= CommunityRole.COLEADER.ordinal()) + { + getCommunityManager().handleCloseJoinRequest(_viewer, _community, _info, true); + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityJoinRequestsPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityJoinRequestsPage.java new file mode 100644 index 000000000..1c5c69c92 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityJoinRequestsPage.java @@ -0,0 +1,184 @@ +package mineplex.core.communities.gui.community; + +import java.util.LinkedList; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.C; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityDisbandEvent; +import mineplex.core.communities.CommunityJoinRequestInfo; +import mineplex.core.communities.CommunityJoinRequestsUpdateEvent; +import mineplex.core.communities.CommunityMemberDataUpdateEvent; +import mineplex.core.communities.CommunityMembershipUpdateEvent; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.gui.ActionButton; +import mineplex.core.communities.gui.CommunitiesGUIPage; +import mineplex.core.communities.gui.overview.CommunityOverviewPage; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityJoinRequestsPage extends CommunitiesGUIPage +{ + private static final int REQUESTS_PER_PAGE = 27; + + private Community _community; + private int _page = 1; + + public CommunityJoinRequestsPage(Player viewer, Community community) + { + super(community.getName() + C.cBlack, 6, viewer); + _community = community; + + setup(1, true); + open(); + } + + private void setup(int page, boolean initial) + { + if (initial) + { + Buttons.clear(); + Inv.clear(); + } + { + //0 + ActionButton membersButton = new ActionButton(new ItemBuilder(Material.SKULL_ITEM).setData((short)3).setTitle(C.cGreenB + "Members").build(), clickType -> + { + new CommunityMembersPage(Viewer, _community).open(); + }); + Buttons.put(0, membersButton); + Inv.setItem(0, membersButton.Button); + //4 + CommunityButton communityButton = new CommunityButton(Viewer, _community); + Buttons.put(4, communityButton); + Inv.setItem(4, communityButton.Button); + //8 + ActionButton returnButton = new ActionButton(new ItemBuilder(Material.BED).setTitle(C.cGray + "\u21FD Go Back").build(), clickType -> + { + new CommunityOverviewPage(Viewer).open(); + }); + Buttons.put(8, returnButton); + Inv.setItem(8, returnButton.Button); + //CoLeader+ + if (_community.getMembers().containsKey(Viewer.getUniqueId()) && _community.getMembers().get(Viewer.getUniqueId()).Role.ordinal() <= CommunityRole.COLEADER.ordinal()) + { + ActionButton requestsButton = new ActionButton(new ItemBuilder(Material.PAPER).setTitle(C.cGreenB + "Join Requests").build(), clickType -> {}); + Buttons.put(2, requestsButton); + Inv.setItem(2, requestsButton.Button); + ActionButton settingsButton = new ActionButton(new ItemBuilder(Material.REDSTONE_COMPARATOR).setTitle(C.cGreenB + "Community Settings").build(), clickType -> + { + new CommunitySettingsPage(Viewer, _community); + }); + Buttons.put(6, settingsButton); + Inv.setItem(6, settingsButton.Button); + } + else if (_community.getMembers().containsKey(Viewer.getUniqueId())) + { + CommunityChatReadingButton chatButton = new CommunityChatReadingButton(Viewer, _community); + Buttons.put(6, chatButton); + Inv.setItem(6, chatButton.Button); + } + } + { + ActionButton back = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Previous Page").build(), clickType -> + { + if (_page == 1) + { + return; + } + setup(_page - 1, false); + }); + ActionButton next = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Next Page").build(), clickType -> + { + setup(_page + 1, false); + }); + Buttons.put(45, back); + Inv.setItem(45, back.Button); + Buttons.put(53, next); + Inv.setItem(53, next.Button); + } + List requests = new LinkedList<>(); + for (CommunityJoinRequestInfo info : _community.getJoinRequests().values()) + { + requests.add(info); + } + requests.sort((info1, info2) -> + { + return info1.Name.compareToIgnoreCase(info2.Name); + }); + + int slot = 18; + boolean cleared = false; + for (int i = (page - 1) * REQUESTS_PER_PAGE; i < (page - 1) * REQUESTS_PER_PAGE + REQUESTS_PER_PAGE && i < requests.size(); i++) + { + if (!cleared && !initial) + { + cleared = true; + _page = page; + for (int clear = 18; clear < 45; clear++) + { + Buttons.remove(clear); + Inv.setItem(clear, null); + } + } + CommunityJoinRequestButton button = new CommunityJoinRequestButton(Viewer, _community, requests.get(i)); + Buttons.put(slot, button); + Inv.setItem(slot, button.Button); + + slot++; + } + + Viewer.updateInventory(); + } + + @EventHandler + public void onMembershipUpdate(CommunityMembershipUpdateEvent event) + { + if (event.getCommunity().getId().intValue() != _community.getId().intValue()) + { + return; + } + + if (_community.getMembers().containsKey(Viewer.getUniqueId()) && _community.getMembers().get(Viewer.getUniqueId()).Role.ordinal() <= CommunityRole.COLEADER.ordinal()) + { + setup(1, true); + } + else + { + new CommunityMembersPage(Viewer, _community).open(); + } + } + + @EventHandler + public void onRequestsUpdate(CommunityJoinRequestsUpdateEvent event) + { + if (event.getCommunity().getId().intValue() != _community.getId().intValue()) + { + return; + } + setup(1, true); + } + + @EventHandler + public void onCommunityDisband(CommunityDisbandEvent event) + { + if (_community.getId().intValue() == event.getCommunity().getId().intValue()) + { + Viewer.closeInventory(); + } + } + + @EventHandler + public void onMembershipUpdate(CommunityMemberDataUpdateEvent event) + { + if (!event.getPlayer().getUniqueId().toString().equalsIgnoreCase(Viewer.getUniqueId().toString())) + { + return; + } + + setup(1, true); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityMemberButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityMemberButton.java new file mode 100644 index 000000000..79f2fd375 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityMemberButton.java @@ -0,0 +1,80 @@ +package mineplex.core.communities.gui.community; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.gui.CommunitiesGUIButton; + +public class CommunityMemberButton extends CommunitiesGUIButton +{ + private Player _viewer; + private Community _community; + private CommunityMemberInfo _info; + + public CommunityMemberButton(Player viewer, Community community, CommunityMemberInfo info) + { + super(info.getRepresentation(getCommunityManager().Get(viewer).getRoleIn(community))); + + _viewer = viewer; + _community = community; + _info = info; + } + + @Override + public void update() + { + Button = _info.getRepresentation(getCommunityManager().Get(_viewer).getRoleIn(_community)); + } + + @Override + public void handleClick(ClickType type) + { + if (type == ClickType.SHIFT_RIGHT) + { + if (getCommunityManager().Get(_viewer).getRoleIn(_community) != null && getCommunityManager().Get(_viewer).getRoleIn(_community).ordinal() < _info.Role.ordinal()) + { + getCommunityManager().handleKick(_viewer, _community, _info); + } + } + if (type == ClickType.LEFT || type == ClickType.SHIFT_LEFT) + { + if (getCommunityManager().Get(_viewer).getRoleIn(_community) != null && getCommunityManager().Get(_viewer).getRoleIn(_community) == CommunityRole.LEADER && _info.Role != CommunityRole.LEADER) + { + if (_info.Role == CommunityRole.MEMBER) + { + getCommunityManager().handleRoleUpdate(_viewer, _community, _info, CommunityRole.COLEADER); + } + if (_info.Role == CommunityRole.COLEADER && type == ClickType.SHIFT_LEFT) + { + if (_info.OwnsCommunity) + { + UtilPlayer.message(_viewer, F.main(getCommunityManager().getName(), F.name(_info.Name) + " can only own one community at a time!")); + return; + } + if (!Rank.valueOf(Managers.get(CoreClientManager.class).loadOfflineClient(_info.UUID).Rank).has(Rank.ETERNAL)) + { + UtilPlayer.message(_viewer, F.main(getCommunityManager().getName(), "Only Eternal rank and above can own a community!")); + return; + } + getCommunityManager().handleRoleUpdate(_viewer, _community, _info, CommunityRole.LEADER); + getCommunityManager().handleRoleUpdate(_viewer, _community, _community.getMembers().get(_viewer.getUniqueId()), CommunityRole.COLEADER); + } + } + } + if (type == ClickType.RIGHT) + { + if (getCommunityManager().Get(_viewer).getRoleIn(_community) != null && getCommunityManager().Get(_viewer).getRoleIn(_community) == CommunityRole.LEADER && _info.Role == CommunityRole.COLEADER) + { + getCommunityManager().handleRoleUpdate(_viewer, _community, _info, CommunityRole.MEMBER); + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityMembersPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityMembersPage.java new file mode 100644 index 000000000..347312750 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunityMembersPage.java @@ -0,0 +1,175 @@ +package mineplex.core.communities.gui.community; + +import java.util.LinkedList; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.C; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityDisbandEvent; +import mineplex.core.communities.CommunityMemberDataUpdateEvent; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityMembershipUpdateEvent; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.gui.ActionButton; +import mineplex.core.communities.gui.CommunitiesGUIPage; +import mineplex.core.communities.gui.overview.CommunityOverviewPage; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityMembersPage extends CommunitiesGUIPage +{ + private static final int MEMBERS_PER_PAGE = 27; + + private Community _community; + private int _page = 1; + + public CommunityMembersPage(Player viewer, Community community) + { + super(community.getName() + C.cAqua, 6, viewer); + _community = community; + + setup(1, true); + open(); + } + + private void setup(int page, boolean initial) + { + if (initial) + { + Buttons.clear(); + Inv.clear(); + } + { + //0 + ActionButton membersButton = new ActionButton(new ItemBuilder(Material.SKULL_ITEM).setData((short)3).setTitle(C.cGreenB + "Members").build(), clickType -> {}); + Buttons.put(0, membersButton); + Inv.setItem(0, membersButton.Button); + //4 + CommunityButton communityButton = new CommunityButton(Viewer, _community); + Buttons.put(4, communityButton); + Inv.setItem(4, communityButton.Button); + //8 + ActionButton returnButton = new ActionButton(new ItemBuilder(Material.BED).setTitle(C.cGray + "\u21FD Go Back").build(), clickType -> + { + new CommunityOverviewPage(Viewer).open(); + }); + Buttons.put(8, returnButton); + Inv.setItem(8, returnButton.Button); + //CoLeader+ + if (_community.getMembers().containsKey(Viewer.getUniqueId()) && _community.getMembers().get(Viewer.getUniqueId()).Role.ordinal() <= CommunityRole.COLEADER.ordinal()) + { + ActionButton requestsButton = new ActionButton(new ItemBuilder(Material.PAPER).setTitle(C.cGreenB + "Join Requests").build(), clickType -> + { + new CommunityJoinRequestsPage(Viewer, _community).open(); + }); + Buttons.put(2, requestsButton); + Inv.setItem(2, requestsButton.Button); + ActionButton settingsButton = new ActionButton(new ItemBuilder(Material.REDSTONE_COMPARATOR).setTitle(C.cGreenB + "Community Settings").build(), clickType -> + { + new CommunitySettingsPage(Viewer, _community); + }); + Buttons.put(6, settingsButton); + Inv.setItem(6, settingsButton.Button); + } + else if (_community.getMembers().containsKey(Viewer.getUniqueId())) + { + CommunityChatReadingButton chatButton = new CommunityChatReadingButton(Viewer, _community); + Buttons.put(6, chatButton); + Inv.setItem(6, chatButton.Button); + } + } + { + ActionButton back = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Previous Page").build(), clickType -> + { + if (_page == 1) + { + return; + } + setup(_page - 1, false); + }); + ActionButton next = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Next Page").build(), clickType -> + { + setup(_page + 1, false); + }); + Buttons.put(45, back); + Inv.setItem(45, back.Button); + Buttons.put(53, next); + Inv.setItem(53, next.Button); + } + List members = new LinkedList<>(); + for (CommunityMemberInfo info : _community.getMembers().values()) + { + members.add(info); + } + members.sort((info1, info2) -> + { + if (info1.isOnline() == info2.isOnline()) + { + return info1.Name.compareToIgnoreCase(info2.Name); + } + + if (info1.isOnline()) + { + return -1; + } + return 1; + }); + + int slot = 18; + boolean cleared = false; + for (int i = (page - 1) * MEMBERS_PER_PAGE; i < (page - 1) * MEMBERS_PER_PAGE + MEMBERS_PER_PAGE && i < members.size(); i++) + { + if (!cleared && !initial) + { + cleared = true; + _page = page; + for (int clear = 18; clear < 45; clear++) + { + Buttons.remove(clear); + Inv.setItem(clear, null); + } + } + CommunityMemberButton button = new CommunityMemberButton(Viewer, _community, members.get(i)); + Buttons.put(slot, button); + Inv.setItem(slot, button.Button); + + slot++; + } + + Viewer.updateInventory(); + } + + @EventHandler + public void onMembershipUpdate(CommunityMembershipUpdateEvent event) + { + if (event.getCommunity().getId().intValue() != _community.getId().intValue()) + { + return; + } + + setup(1, true); + } + + @EventHandler + public void onCommunityDisband(CommunityDisbandEvent event) + { + if (_community.getId().intValue() == event.getCommunity().getId().intValue()) + { + Viewer.closeInventory(); + } + } + + @EventHandler + public void onMembershipUpdate(CommunityMemberDataUpdateEvent event) + { + if (!event.getPlayer().getUniqueId().toString().equalsIgnoreCase(Viewer.getUniqueId().toString())) + { + return; + } + + setup(1, true); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunitySettingButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunitySettingButton.java new file mode 100644 index 000000000..27a9bee13 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunitySettingButton.java @@ -0,0 +1,258 @@ +package mineplex.core.communities.gui.community; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; + +import mineplex.core.common.util.C; +import mineplex.core.communities.Community; +import mineplex.core.communities.Community.PrivacySetting; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.CommunitySetting; +import mineplex.core.communities.gui.CommunitiesGUIButton; +import mineplex.core.game.GameDisplay; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunitySettingButton extends CommunitiesGUIButton +{ + @SuppressWarnings("serial") + private static final Map COLOR_MAP = new HashMap() + { + { + put(ChatColor.AQUA, DyeColor.CYAN); + put(ChatColor.BLACK, DyeColor.BLACK); + put(ChatColor.BLUE, DyeColor.LIGHT_BLUE); + put(ChatColor.DARK_AQUA, DyeColor.CYAN); + put(ChatColor.DARK_BLUE, DyeColor.BLUE); + put(ChatColor.DARK_GRAY, DyeColor.GRAY); + put(ChatColor.DARK_GREEN, DyeColor.GREEN); + put(ChatColor.DARK_PURPLE, DyeColor.PURPLE); + put(ChatColor.DARK_RED, DyeColor.RED); + put(ChatColor.GOLD, DyeColor.YELLOW); + put(ChatColor.GRAY, DyeColor.SILVER); + put(ChatColor.GREEN, DyeColor.LIME); + put(ChatColor.LIGHT_PURPLE, DyeColor.PINK); + put(ChatColor.RED, DyeColor.RED); + put(ChatColor.WHITE, DyeColor.WHITE); + put(ChatColor.YELLOW, DyeColor.YELLOW); + } + }; + @SuppressWarnings("serial") + private static final Map COLOR_NAME_MAP = new HashMap() + { + { + put(ChatColor.AQUA, "Aqua"); + put(ChatColor.BLACK, "Black"); + put(ChatColor.BLUE, "Blue"); + put(ChatColor.DARK_AQUA, "Cyan"); + put(ChatColor.DARK_BLUE, "Dark Blue"); + put(ChatColor.DARK_GRAY, "Dark Gray"); + put(ChatColor.DARK_GREEN, "Dark Green"); + put(ChatColor.DARK_PURPLE, "Purple"); + put(ChatColor.DARK_RED, "Dark Red"); + put(ChatColor.GOLD, "Gold"); + put(ChatColor.GRAY, "Gray"); + put(ChatColor.GREEN, "Green"); + put(ChatColor.LIGHT_PURPLE, "Pink"); + put(ChatColor.RED, "Red"); + put(ChatColor.WHITE, "White"); + put(ChatColor.YELLOW, "Yellow"); + } + }; + + private Player _viewer; + private Community _community; + private CommunitySetting _setting; + + public CommunitySettingButton(Player viewer, Community community, CommunitySetting setting) + { + super(new ItemBuilder(Material.BARRIER).build()); + + _viewer = viewer; + _community = community; + _setting = setting; + update(); + } + + @SuppressWarnings("deprecation") + @Override + public void update() + { + if (_setting == CommunitySetting.FAVORITE_GAME) + { + Button = new ItemBuilder(new ItemStack(_community.getFavoriteGame().getMaterial(), 1, _community.getFavoriteGame().getMaterialData(), null)).setTitle(C.cGreenB + "Favorite Game").addLore(C.cWhite + _community.getFavoriteGame().getName(), C.cRed, C.cYellow + "Left Click " + C.cWhite + "Next Game", C.cYellow + "Right Click " + C.cWhite + "Previous Game").build(); + } + else if (_setting == CommunitySetting.PRIVACY) + { + Button = new ItemBuilder(Material.DARK_OAK_DOOR_ITEM).setTitle(C.cGreenB + "Privacy").addLore(C.cWhite + _community.getPrivacySetting().getDisplayText(), C.cRed, C.cYellow + "Left Click " + C.cWhite + "Next Privacy Setting", C.cYellow + "Right Click " + C.cWhite + "Previous Privacy Setting").build(); + } + else if (_setting == CommunitySetting.CHAT_DELAY) + { + Button = new ItemBuilder(Material.PAPER).setTitle(C.cGreenB + "Chat Delay").addLore(C.cWhite + (_community.getChatDelay() == 0 ? "No Delay" : _community.getChatDelay() / 1000 + " Second(s)"), C.cRed, C.cYellow + "Left Click " + C.cWhite + "Next Delay Setting", C.cYellow + "Right Click " + C.cWhite + "Previous Delay Setting").build(); + } + else if (_setting == CommunitySetting.CHAT_NAME_COLOR) + { + ItemStack base = new MaterialData(Material.WOOL, COLOR_MAP.get(_community.getChatFormatting()[0]).getWoolData()).toItemStack(1); + Button = new ItemBuilder(base).setTitle(C.cGreenB + "Chat Community Color").addLore(C.cWhite + COLOR_NAME_MAP.get(_community.getChatFormatting()[0]), C.cRed, C.cYellow + "Left Click " + C.cWhite + "Next Color", C.cYellow + "Right Click " + C.cWhite + "Previous Color").build(); + } + else if (_setting == CommunitySetting.CHAT_PLAYER_COLOR) + { + ItemStack base = new MaterialData(Material.WOOL, COLOR_MAP.get(_community.getChatFormatting()[1]).getWoolData()).toItemStack(1); + Button = new ItemBuilder(base).setTitle(C.cGreenB + "Chat Player Color").addLore(C.cWhite + COLOR_NAME_MAP.get(_community.getChatFormatting()[1]), C.cRed, C.cYellow + "Left Click " + C.cWhite + "Next Color", C.cYellow + "Right Click " + C.cWhite + "Previous Color").build(); + } + else if (_setting == CommunitySetting.CHAT_MESSAGE_COLOR) + { + ItemStack base = new MaterialData(Material.WOOL, COLOR_MAP.get(_community.getChatFormatting()[2]).getWoolData()).toItemStack(1); + Button = new ItemBuilder(base).setTitle(C.cGreenB + "Chat Message Color").addLore(C.cWhite + COLOR_NAME_MAP.get(_community.getChatFormatting()[2]), C.cRed, C.cYellow + "Left Click " + C.cWhite + "Next Color", C.cYellow + "Right Click " + C.cWhite + "Previous Color").build(); + } + } + + @Override + public void handleClick(ClickType type) + { + if (type == ClickType.LEFT) + { + if (getCommunityManager().Get(_viewer).getRoleIn(_community) != null && getCommunityManager().Get(_viewer).getRoleIn(_community).ordinal() <= CommunityRole.COLEADER.ordinal()) + { + String[] valueArray = new String[] {}; + int index = 0; + + if (_setting == CommunitySetting.FAVORITE_GAME) + { + GameDisplay[] games = Arrays.asList(GameDisplay.values()).stream().filter(display -> display.isCommunityFavoriteOption()).toArray(size -> new GameDisplay[size]); + valueArray = new String[games.length]; + for (int i = 0; i < games.length; i++) + { + valueArray[i] = games[i].getName(); + } + + index = Arrays.asList(valueArray).indexOf(_community.getFavoriteGame().getName()); + } + else if (_setting == CommunitySetting.PRIVACY) + { + valueArray = new String[] {PrivacySetting.OPEN.toString(), PrivacySetting.RECRUITING.toString(), PrivacySetting.PRIVATE.toString()}; + + index = Arrays.asList(valueArray).indexOf(_community.getPrivacySetting().toString()); + } + else if (_setting == CommunitySetting.CHAT_DELAY) + { + valueArray = new String[] {1000L + "", 3000L + "", 5000L + ""}; + + index = Arrays.asList(valueArray).indexOf(_community.getChatDelay().toString()); + } + else if (_setting == CommunitySetting.CHAT_NAME_COLOR) + { + ChatColor[] colors = COLOR_MAP.keySet().toArray(new ChatColor[COLOR_MAP.size()]); + valueArray = new String[colors.length]; + for (int i = 0; i < colors.length; i++) + { + valueArray[i] = colors[i].name(); + } + + index = Arrays.asList(valueArray).indexOf(_community.getChatFormatting()[0].name()); + } + else if (_setting == CommunitySetting.CHAT_PLAYER_COLOR) + { + ChatColor[] colors = COLOR_MAP.keySet().toArray(new ChatColor[COLOR_MAP.size()]); + valueArray = new String[colors.length]; + for (int i = 0; i < colors.length; i++) + { + valueArray[i] = colors[i].name(); + } + + index = Arrays.asList(valueArray).indexOf(_community.getChatFormatting()[1].name()); + } + else if (_setting == CommunitySetting.CHAT_MESSAGE_COLOR) + { + ChatColor[] colors = COLOR_MAP.keySet().toArray(new ChatColor[COLOR_MAP.size()]); + valueArray = new String[colors.length]; + for (int i = 0; i < colors.length; i++) + { + valueArray[i] = colors[i].name(); + } + + index = Arrays.asList(valueArray).indexOf(_community.getChatFormatting()[2].name()); + } + + int newIndex = (index + 1 >= valueArray.length) ? 0 : (index + 1); + getCommunityManager().handleSettingUpdate(_viewer, _community, _setting, valueArray[newIndex]); + } + } + if (type == ClickType.RIGHT) + { + if (getCommunityManager().Get(_viewer).getRoleIn(_community) != null && getCommunityManager().Get(_viewer).getRoleIn(_community).ordinal() <= CommunityRole.COLEADER.ordinal()) + { + String[] valueArray = new String[] {}; + int index = 0; + + if (_setting == CommunitySetting.FAVORITE_GAME) + { + GameDisplay[] games = Arrays.asList(GameDisplay.values()).stream().filter(display -> display.isCommunityFavoriteOption()).toArray(size -> new GameDisplay[size]); + valueArray = new String[games.length]; + for (int i = 0; i < games.length; i++) + { + valueArray[i] = games[i].getName(); + } + + index = Arrays.asList(valueArray).indexOf(_community.getFavoriteGame().getName()); + } + else if (_setting == CommunitySetting.PRIVACY) + { + valueArray = new String[] {PrivacySetting.OPEN.toString(), PrivacySetting.RECRUITING.toString(), PrivacySetting.PRIVATE.toString()}; + + index = Arrays.asList(valueArray).indexOf(_community.getPrivacySetting().toString()); + } + else if (_setting == CommunitySetting.CHAT_DELAY) + { + valueArray = new String[] {1000L + "", 3000L + "", 5000L + ""}; + + index = Arrays.asList(valueArray).indexOf(_community.getChatDelay().toString()); + } + else if (_setting == CommunitySetting.CHAT_NAME_COLOR) + { + ChatColor[] colors = COLOR_MAP.keySet().toArray(new ChatColor[COLOR_MAP.size()]); + valueArray = new String[colors.length]; + for (int i = 0; i < colors.length; i++) + { + valueArray[i] = colors[i].name(); + } + + index = Arrays.asList(valueArray).indexOf(_community.getChatFormatting()[0].name()); + } + else if (_setting == CommunitySetting.CHAT_PLAYER_COLOR) + { + ChatColor[] colors = COLOR_MAP.keySet().toArray(new ChatColor[COLOR_MAP.size()]); + valueArray = new String[colors.length]; + for (int i = 0; i < colors.length; i++) + { + valueArray[i] = colors[i].name(); + } + + index = Arrays.asList(valueArray).indexOf(_community.getChatFormatting()[1].name()); + } + else if (_setting == CommunitySetting.CHAT_MESSAGE_COLOR) + { + ChatColor[] colors = COLOR_MAP.keySet().toArray(new ChatColor[COLOR_MAP.size()]); + valueArray = new String[colors.length]; + for (int i = 0; i < colors.length; i++) + { + valueArray[i] = colors[i].name(); + } + + index = Arrays.asList(valueArray).indexOf(_community.getChatFormatting()[2].name()); + } + + int newIndex = (index - 1 < 0) ? (valueArray.length - 1) : (index - 1); + getCommunityManager().handleSettingUpdate(_viewer, _community, _setting, valueArray[newIndex]); + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunitySettingsPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunitySettingsPage.java new file mode 100644 index 000000000..4ed663137 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/community/CommunitySettingsPage.java @@ -0,0 +1,149 @@ +package mineplex.core.communities.gui.community; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.C; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityDisbandEvent; +import mineplex.core.communities.CommunityMemberDataUpdateEvent; +import mineplex.core.communities.CommunityMembershipUpdateEvent; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.CommunitySetting; +import mineplex.core.communities.CommunitySettingUpdateEvent; +import mineplex.core.communities.gui.ActionButton; +import mineplex.core.communities.gui.CommunitiesGUIPage; +import mineplex.core.communities.gui.overview.CommunityOverviewPage; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunitySettingsPage extends CommunitiesGUIPage +{ + private Community _community; + + public CommunitySettingsPage(Player viewer, Community community) + { + super(community.getName() + C.cBlue, 6, viewer); + _community = community; + + setup(); + open(); + } + + private void setup() + { + { + //0 + ActionButton membersButton = new ActionButton(new ItemBuilder(Material.SKULL_ITEM).setData((short)3).setTitle(C.cGreenB + "Members").build(), clickType -> + { + new CommunityMembersPage(Viewer, _community).open(); + }); + Buttons.put(0, membersButton); + Inv.setItem(0, membersButton.Button); + //4 + CommunityButton communityButton = new CommunityButton(Viewer, _community); + Buttons.put(4, communityButton); + Inv.setItem(4, communityButton.Button); + //8 + ActionButton returnButton = new ActionButton(new ItemBuilder(Material.BED).setTitle(C.cGray + "\u21FD Go Back").build(), clickType -> + { + new CommunityOverviewPage(Viewer).open(); + }); + Buttons.put(8, returnButton); + Inv.setItem(8, returnButton.Button); + //CoLeader+ + if (_community.getMembers().containsKey(Viewer.getUniqueId()) && _community.getMembers().get(Viewer.getUniqueId()).Role.ordinal() <= CommunityRole.COLEADER.ordinal()) + { + ActionButton requestsButton = new ActionButton(new ItemBuilder(Material.PAPER).setTitle(C.cGreenB + "Join Requests").build(), clickType -> + { + new CommunityJoinRequestsPage(Viewer, _community).open(); + }); + Buttons.put(2, requestsButton); + Inv.setItem(2, requestsButton.Button); + ActionButton settingsButton = new ActionButton(new ItemBuilder(Material.REDSTONE_COMPARATOR).setTitle(C.cGreenB + "Community Settings").build(), clickType -> {}); + Buttons.put(6, settingsButton); + Inv.setItem(6, settingsButton.Button); + } + else if (_community.getMembers().containsKey(Viewer.getUniqueId())) + { + CommunityChatReadingButton chatButton = new CommunityChatReadingButton(Viewer, _community); + Buttons.put(6, chatButton); + Inv.setItem(6, chatButton.Button); + } + } + { + CommunitySettingButton gameButton = new CommunitySettingButton(Viewer, _community, CommunitySetting.FAVORITE_GAME); + Buttons.put(20, gameButton); + Inv.setItem(20, gameButton.Button); + + CommunitySettingButton privacyButton = new CommunitySettingButton(Viewer, _community, CommunitySetting.PRIVACY); + Buttons.put(22, privacyButton); + Inv.setItem(22, privacyButton.Button); + + CommunityChatReadingButton chatButton = new CommunityChatReadingButton(Viewer, _community); + Buttons.put(24, chatButton); + Inv.setItem(24, chatButton.Button); + + CommunitySettingButton delayButton = new CommunitySettingButton(Viewer, _community, CommunitySetting.CHAT_DELAY); + Buttons.put(38, delayButton); + Inv.setItem(38, delayButton.Button); + + CommunitySettingButton communityColorButton = new CommunitySettingButton(Viewer, _community, CommunitySetting.CHAT_NAME_COLOR); + Buttons.put(40, communityColorButton); + Inv.setItem(40, communityColorButton.Button); + + CommunitySettingButton playerColorButton = new CommunitySettingButton(Viewer, _community, CommunitySetting.CHAT_PLAYER_COLOR); + Buttons.put(41, playerColorButton); + Inv.setItem(41, playerColorButton.Button); + + CommunitySettingButton messageColorButton = new CommunitySettingButton(Viewer, _community, CommunitySetting.CHAT_MESSAGE_COLOR); + Buttons.put(42, messageColorButton); + Inv.setItem(42, messageColorButton.Button); + } + + Viewer.updateInventory(); + } + + @EventHandler + public void onMembershipUpdate(CommunityMembershipUpdateEvent event) + { + if (event.getCommunity().getId().intValue() != _community.getId().intValue()) + { + return; + } + + if (!_community.getMembers().containsKey(Viewer.getUniqueId()) || _community.getMembers().get(Viewer.getUniqueId()).Role.ordinal() > CommunityRole.COLEADER.ordinal()) + { + new CommunityMembersPage(Viewer, _community).open(); + } + } + + @EventHandler + public void onSettingsUpdate(CommunitySettingUpdateEvent event) + { + if (event.getCommunity().getId() != _community.getId()) + { + return; + } + setup(); + } + + @EventHandler + public void onCommunityDisband(CommunityDisbandEvent event) + { + if (_community.getId().intValue() == event.getCommunity().getId().intValue()) + { + Viewer.closeInventory(); + } + } + + @EventHandler + public void onMembershipUpdate(CommunityMemberDataUpdateEvent event) + { + if (!event.getPlayer().getUniqueId().toString().equalsIgnoreCase(Viewer.getUniqueId().toString())) + { + return; + } + setup(); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityInvitesPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityInvitesPage.java new file mode 100644 index 000000000..93796bede --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityInvitesPage.java @@ -0,0 +1,118 @@ +package mineplex.core.communities.gui.overview; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.C; +import mineplex.core.communities.CommunityDisbandEvent; +import mineplex.core.communities.CommunityMemberDataUpdateEvent; +import mineplex.core.communities.gui.ActionButton; +import mineplex.core.communities.gui.CommunitiesGUIPage; +import mineplex.core.communities.gui.browser.CommunityBrowserPage; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityInvitesPage extends CommunitiesGUIPage +{ + private static final int COMMUNITIES_PER_PAGE = 27; + + private int _page = 1; + + public CommunityInvitesPage(Player viewer) + { + super("Community Invites", 6, viewer); + + setup(1, true); + open(); + } + + private void setup(int page, boolean initial) + { + if (initial) + { + Buttons.clear(); + Inv.clear(); + } + { + //1 + ActionButton communitiesButton = new ActionButton(new ItemBuilder(Material.EMERALD).setTitle(C.cGreenB + "Your Communities").build(), clickType -> + { + new CommunityOverviewPage(Viewer).open(); + }); + Buttons.put(1, communitiesButton); + Inv.setItem(1, communitiesButton.Button); + //4 + ActionButton browserButton = new ActionButton(new ItemBuilder(Material.COMPASS).setTitle(C.cGreenB + "Browse Communities").build(), clickType -> + { + new CommunityBrowserPage(Viewer).open(); + }); + Buttons.put(4, browserButton); + Inv.setItem(4, browserButton.Button); + //7 + ActionButton invitesButton = new ActionButton(new ItemBuilder(Material.PAPER).setTitle(C.cGreenB + "Community Invites").build(), clickType -> {}); + Buttons.put(7, invitesButton); + Inv.setItem(7, invitesButton.Button); + } + { + ActionButton back = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Previous Page").build(), clickType -> + { + if (_page == 1) + { + return; + } + setup(_page - 1, false); + }); + ActionButton next = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Next Page").build(), clickType -> + { + setup(_page + 1, false); + }); + Buttons.put(45, back); + Inv.setItem(45, back.Button); + Buttons.put(53, next); + Inv.setItem(53, next.Button); + } + + int slot = 18; + boolean cleared = false; + for (int i = (page - 1) * COMMUNITIES_PER_PAGE; i < (page - 1) * COMMUNITIES_PER_PAGE + COMMUNITIES_PER_PAGE && i < getCommunityManager().Get(Viewer).Invites.size(); i++) + { + if (!cleared && !initial) + { + cleared = true; + _page = page; + for (int clear = 18; clear < 45; clear++) + { + Buttons.remove(clear); + Inv.setItem(clear, null); + } + } + CommunityVisualizationButton button = new CommunityVisualizationButton(Viewer, getCommunityManager().getLoadedCommunity(getCommunityManager().Get(Viewer).Invites.get(i)), true); + Buttons.put(slot, button); + Inv.setItem(slot, button.Button); + + slot++; + } + + Viewer.updateInventory(); + } + + @EventHandler + public void onMembershipUpdate(CommunityMemberDataUpdateEvent event) + { + if (!event.getPlayer().getUniqueId().toString().equalsIgnoreCase(Viewer.getUniqueId().toString())) + { + return; + } + + setup(1, true); + } + + @EventHandler + public void onCommunityDisband(CommunityDisbandEvent event) + { + if (getCommunityManager().Get(Viewer).Invites.contains(event.getCommunity().getId())) + { + setup(1, true); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityOverviewPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityOverviewPage.java new file mode 100644 index 000000000..342afa5bd --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityOverviewPage.java @@ -0,0 +1,136 @@ +package mineplex.core.communities.gui.overview; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.C; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityDisbandEvent; +import mineplex.core.communities.CommunityMemberDataUpdateEvent; +import mineplex.core.communities.gui.ActionButton; +import mineplex.core.communities.gui.CommunitiesGUIPage; +import mineplex.core.communities.gui.browser.CommunityBrowserPage; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityOverviewPage extends CommunitiesGUIPage +{ + private static final int COMMUNITIES_PER_PAGE = 27; + + private int _page = 1; + + public CommunityOverviewPage(Player viewer) + { + super("Your Communities", 6, viewer); + + setup(1, true); + open(); + } + + private void setup(int page, boolean initial) + { + if (initial) + { + Buttons.clear(); + Inv.clear(); + } + { + //1 + ActionButton communitiesButton = new ActionButton(new ItemBuilder(Material.EMERALD).setTitle(C.cGreenB + "Your Communities").build(), clickType -> {}); + Buttons.put(1, communitiesButton); + Inv.setItem(1, communitiesButton.Button); + //4 + ActionButton browserButton = new ActionButton(new ItemBuilder(Material.COMPASS).setTitle(C.cGreenB + "Browse Communities").build(), clickType -> + { + new CommunityBrowserPage(Viewer).open(); + }); + Buttons.put(4, browserButton); + Inv.setItem(4, browserButton.Button); + //7 + ActionButton invitesButton = new ActionButton(new ItemBuilder(Material.PAPER).setTitle(C.cGreenB + "Community Invites").build(), clickType -> + { + new CommunityInvitesPage(Viewer); + }); + Buttons.put(7, invitesButton); + Inv.setItem(7, invitesButton.Button); + } + { + ActionButton back = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Previous Page").build(), clickType -> + { + if (_page == 1) + { + return; + } + setup(_page - 1, false); + }); + ActionButton next = new ActionButton(new ItemBuilder(Material.ARROW).setTitle(C.cGreen + "Next Page").build(), clickType -> + { + setup(_page + 1, false); + }); + Buttons.put(45, back); + Inv.setItem(45, back.Button); + Buttons.put(53, next); + Inv.setItem(53, next.Button); + } + + int slot = 18; + boolean cleared = false; + for (int i = (page - 1) * COMMUNITIES_PER_PAGE; i < (page - 1) * COMMUNITIES_PER_PAGE + COMMUNITIES_PER_PAGE && i < getCommunityManager().Get(Viewer).getTotalCommunities(); i++) + { + if (!cleared && !initial) + { + cleared = true; + _page = page; + for (int clear = 18; clear < 45; clear++) + { + Buttons.remove(clear); + Inv.setItem(clear, null); + } + } + List coms = Arrays.asList(getCommunityManager().Get(Viewer).getCommunities()); + coms.sort((c1, c2) -> + { + if (c1.getMembers().get(Viewer.getUniqueId()).Role == c2.getMembers().get(Viewer.getUniqueId()).Role) + { + return c1.getName().compareTo(c2.getName()); + } + + if (c1.getMembers().get(Viewer.getUniqueId()).Role.ordinal() < c2.getMembers().get(Viewer.getUniqueId()).Role.ordinal()) + { + return -1; + } + return 1; + }); + CommunityVisualizationButton button = new CommunityVisualizationButton(Viewer, coms.get(i), false); + Buttons.put(slot, button); + Inv.setItem(slot, button.Button); + + slot++; + } + + Viewer.updateInventory(); + } + + @EventHandler + public void onMembershipUpdate(CommunityMemberDataUpdateEvent event) + { + if (!event.getPlayer().getUniqueId().toString().equalsIgnoreCase(Viewer.getUniqueId().toString())) + { + return; + } + + setup(1, true); + } + + @EventHandler + public void onCommunityDisband(CommunityDisbandEvent event) + { + if (getCommunityManager().Get(Viewer).Invites.contains(event.getCommunity().getId())) + { + setup(1, true); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityVisualizationButton.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityVisualizationButton.java new file mode 100644 index 000000000..64ca6a19d --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/overview/CommunityVisualizationButton.java @@ -0,0 +1,61 @@ +package mineplex.core.communities.gui.overview; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.LineFormat; +import mineplex.core.common.util.UtilText; +import mineplex.core.communities.Community; +import mineplex.core.communities.gui.CommunitiesGUIButton; +import mineplex.core.communities.gui.community.CommunityMembersPage; +import mineplex.core.itemstack.ItemBuilder; + +public class CommunityVisualizationButton extends CommunitiesGUIButton +{ + private Player _viewer; + private Community _community; + private boolean _invite; + + public CommunityVisualizationButton(Player viewer, Community community, boolean invite) + { + super(new ItemBuilder(Material.BARRIER).build()); + + _viewer = viewer; + _community = community; + _invite = invite; + update(); + } + + @SuppressWarnings("deprecation") + @Override + public void update() + { + ItemBuilder builder = new ItemBuilder(new ItemStack(_community.getFavoriteGame().getMaterial(), 1, _community.getFavoriteGame().getMaterialData(), null)).setTitle(C.cGreenB + _community.getName()).addLore(UtilText.splitLinesToArray(new String[] {C.cRed, C.cYellow + "Members " + C.cWhite + _community.getMembers().size(), C.cYellow + "Favorite Game " + C.cWhite + _community.getFavoriteGame().getName(), C.cYellow + "Description " + C.cWhite + _community.getDescription()}, LineFormat.LORE)); + if (_invite) + { + builder.addLore(UtilText.splitLinesToArray(new String[] {C.cGold, C.cYellow + "Shift-Left Click " + C.cWhite + "Join", C.cYellow + "Shift-Right Click " + C.cWhite + "Decline"}, LineFormat.LORE)); + } + builder.addLore(C.cBlue, C.cGreen + "Click to view community"); + Button = builder.build(); + } + + @Override + public void handleClick(ClickType type) + { + if (_invite && type == ClickType.SHIFT_RIGHT) + { + getCommunityManager().handleRejectInvite(_viewer, _community); + } + else if (_invite && type == ClickType.SHIFT_LEFT) + { + getCommunityManager().handleJoin(_viewer, _community, true); + } + else + { + new CommunityMembersPage(_viewer, _community).open(); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/mcs/MCSTheme.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/mcs/MCSTheme.java new file mode 100644 index 000000000..a7ed05b78 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/mcs/MCSTheme.java @@ -0,0 +1,50 @@ +package mineplex.core.communities.mcs; + +import org.bukkit.Material; + +import mineplex.core.common.util.C; + +public enum MCSTheme +{ + CANDYLAND(1, C.cPurple + "Candyland", Material.COOKIE, 1000, "Lobby_MPS_Candyland.zip") + ; + + private final int _id; + private final String _displayName, _file; + private final Material _displayType; + private final int _cost; + + private MCSTheme(int id, String displayName, Material displayType, int cost, String file) + { + _id = id; + _displayName = displayName; + _displayType = displayType; + _cost = cost; + _file = file; + } + + public int getId() + { + return _id; + } + + public String getDisplayName() + { + return _displayName; + } + + public Material getDisplayType() + { + return _displayType; + } + + public int getCost() + { + return _cost; + } + + public String getFile() + { + return _file; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityChat.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityChat.java new file mode 100644 index 000000000..15028f160 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityChat.java @@ -0,0 +1,32 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityChat extends ServerCommand +{ + private String _senderName; + private Integer _communityId; + private String _message; + + public CommunityChat(String senderName, Integer communityId, String message) + { + _senderName = senderName; + _communityId = communityId; + _message = message; + } + + public String getSenderName() + { + return _senderName; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getMessage() + { + return _message; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityChatHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityChatHandler.java new file mode 100644 index 000000000..de82598e9 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityChatHandler.java @@ -0,0 +1,25 @@ +package mineplex.core.communities.redis; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityChatHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityChatHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityChat) + { + CommunityChat chat = ((CommunityChat) command); + _manager.handleCommunityChat(chat.getCommunityId(), chat.getSenderName(), chat.getMessage()); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCloseJoinRequest.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCloseJoinRequest.java new file mode 100644 index 000000000..569a02958 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCloseJoinRequest.java @@ -0,0 +1,53 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityCloseJoinRequest extends ServerCommand +{ + private Integer _communityId; + private String _sender; + private String _playerName; + private String _playerUUID; + private Integer _accountId; + private boolean _announce; + + public CommunityCloseJoinRequest(Integer communityId, String sender, String playerName, String playerUUID, Integer accountId, boolean announce) + { + _communityId = communityId; + _sender = sender; + _playerName = playerName; + _playerUUID = playerUUID; + _accountId = accountId; + _announce = announce; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getSender() + { + return _sender; + } + + public String getPlayerName() + { + return _playerName; + } + + public String getPlayerUUID() + { + return _playerUUID; + } + + public Integer getAccountId() + { + return _accountId; + } + + public boolean shouldAnnounce() + { + return _announce; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCloseJoinRequestHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCloseJoinRequestHandler.java new file mode 100644 index 000000000..15f2e2164 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCloseJoinRequestHandler.java @@ -0,0 +1,34 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityCloseJoinRequestHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityCloseJoinRequestHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityCloseJoinRequest) + { + CommunityCloseJoinRequest update = ((CommunityCloseJoinRequest) command); + Integer id = update.getCommunityId(); + String sender = update.getSender(); + UUID uuid = UUID.fromString(update.getPlayerUUID()); + String name = update.getPlayerName(); + Integer accountId = update.getAccountId(); + boolean announce = update.shouldAnnounce(); + + _manager.handleCommunityCloseJoinRequest(id, sender, name, uuid, accountId, announce); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCreate.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCreate.java new file mode 100644 index 000000000..0637057e5 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCreate.java @@ -0,0 +1,25 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityCreate extends ServerCommand +{ + private String _leaderUUID; + private Integer _communityId; + + public CommunityCreate(String leaderUUID, Integer communityId) + { + _leaderUUID = leaderUUID; + _communityId = communityId; + } + + public String getLeaderUUID() + { + return _leaderUUID; + } + + public Integer getCommunityId() + { + return _communityId; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCreateHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCreateHandler.java new file mode 100644 index 000000000..87803feeb --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityCreateHandler.java @@ -0,0 +1,30 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityCreateHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityCreateHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityCreate) + { + CommunityCreate update = ((CommunityCreate) command); + UUID leaderUUID = UUID.fromString(update.getLeaderUUID()); + Integer communityId = update.getCommunityId(); + + _manager.handleCommunityCreation(communityId, leaderUUID); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityDisband.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityDisband.java new file mode 100644 index 000000000..fe69e4404 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityDisband.java @@ -0,0 +1,25 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityDisband extends ServerCommand +{ + private String _senderName; + private Integer _communityId; + + public CommunityDisband(String senderName, Integer communityId) + { + _senderName = senderName; + _communityId = communityId; + } + + public String getSenderName() + { + return _senderName; + } + + public Integer getCommunityId() + { + return _communityId; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityDisbandHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityDisbandHandler.java new file mode 100644 index 000000000..8b4c31e20 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityDisbandHandler.java @@ -0,0 +1,30 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityDisbandHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityDisbandHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityDisband) + { + CommunityDisband update = ((CommunityDisband) command); + String senderName = update.getSenderName(); + Integer communityId = update.getCommunityId(); + + _manager.handleCommunityDisband(communityId, senderName); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityInvite.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityInvite.java new file mode 100644 index 000000000..374d3b5e1 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityInvite.java @@ -0,0 +1,39 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityInvite extends ServerCommand +{ + private Integer _communityId; + private String _sender; + private String _playerName; + private String _playerUUID; + + public CommunityInvite(Integer communityId, String sender, String playerName, String playerUUID) + { + _communityId = communityId; + _sender = sender; + _playerName = playerName; + _playerUUID = playerUUID; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getSender() + { + return _sender; + } + + public String getPlayerName() + { + return _playerName; + } + + public String getPlayerUUID() + { + return _playerUUID; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityInviteHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityInviteHandler.java new file mode 100644 index 000000000..065ac86a7 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityInviteHandler.java @@ -0,0 +1,32 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityInviteHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityInviteHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityInvite) + { + CommunityInvite update = ((CommunityInvite) command); + Integer id = update.getCommunityId(); + String sender = update.getSender(); + String name = update.getPlayerName(); + UUID uuid = UUID.fromString(update.getPlayerUUID()); + + _manager.handleCommunityInvite(id, sender, name, uuid); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityJoinRequest.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityJoinRequest.java new file mode 100644 index 000000000..ccfdaf6bd --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityJoinRequest.java @@ -0,0 +1,39 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityJoinRequest extends ServerCommand +{ + private Integer _communityId; + private String _playerName; + private String _playerUUID; + private Integer _accountId; + + public CommunityJoinRequest(Integer communityId, String playerName, String playerUUID, Integer accountId) + { + _communityId = communityId; + _playerName = playerName; + _playerUUID = playerUUID; + _accountId = accountId; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getPlayerName() + { + return _playerName; + } + + public String getPlayerUUID() + { + return _playerUUID; + } + + public Integer getAccountId() + { + return _accountId; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityJoinRequestHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityJoinRequestHandler.java new file mode 100644 index 000000000..f68ba99d0 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityJoinRequestHandler.java @@ -0,0 +1,32 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityJoinRequestHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityJoinRequestHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityJoinRequest) + { + CommunityJoinRequest update = ((CommunityJoinRequest) command); + Integer id = update.getCommunityId(); + UUID uuid = UUID.fromString(update.getPlayerUUID()); + String name = update.getPlayerName(); + Integer accountId = update.getAccountId(); + + _manager.handleCommunityJoinRequest(id, name, uuid, accountId); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUnInvite.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUnInvite.java new file mode 100644 index 000000000..13537e115 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUnInvite.java @@ -0,0 +1,46 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUnInvite extends ServerCommand +{ + private Integer _communityId; + private String _sender; + private String _playerName; + private String _playerUUID; + private boolean _announce; + + public CommunityUnInvite(Integer communityId, String sender, String playerName, String playerUUID, boolean announce) + { + _communityId = communityId; + _sender = sender; + _playerName = playerName; + _playerUUID = playerUUID; + _announce = announce; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getSender() + { + return _sender; + } + + public String getPlayerName() + { + return _playerName; + } + + public String getPlayerUUID() + { + return _playerUUID; + } + + public boolean shouldAnnounce() + { + return _announce; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUnInviteHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUnInviteHandler.java new file mode 100644 index 000000000..d38f9779f --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUnInviteHandler.java @@ -0,0 +1,33 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUnInviteHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityUnInviteHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityUnInvite) + { + CommunityUnInvite update = ((CommunityUnInvite) command); + Integer id = update.getCommunityId(); + String sender = update.getSender(); + String name = update.getPlayerName(); + UUID uuid = UUID.fromString(update.getPlayerUUID()); + boolean announce = update.shouldAnnounce(); + + _manager.handleCommunityUninvite(id, sender, name, uuid, announce); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberChatReading.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberChatReading.java new file mode 100644 index 000000000..de74302de --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberChatReading.java @@ -0,0 +1,32 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateMemberChatReading extends ServerCommand +{ + private Integer _communityId; + private String _playerUUID; + private boolean _reading; + + public CommunityUpdateMemberChatReading(Integer communityId, String playerUUID, boolean reading) + { + _communityId = communityId; + _playerUUID = playerUUID; + _reading = reading; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getPlayerUUID() + { + return _playerUUID; + } + + public boolean reading() + { + return _reading; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberChatReadingHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberChatReadingHandler.java new file mode 100644 index 000000000..a536ee7f8 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberChatReadingHandler.java @@ -0,0 +1,31 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateMemberChatReadingHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityUpdateMemberChatReadingHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityUpdateMemberChatReading) + { + CommunityUpdateMemberChatReading update = ((CommunityUpdateMemberChatReading) command); + Integer id = update.getCommunityId(); + UUID uuid = UUID.fromString(update.getPlayerUUID()); + boolean reading = update.reading(); + + _manager.handleToggleReadingCommunityChat(id, uuid, reading); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberRole.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberRole.java new file mode 100644 index 000000000..9f42ad0c4 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberRole.java @@ -0,0 +1,39 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateMemberRole extends ServerCommand +{ + private Integer _communityId; + private String _sender; + private String _playerUUID; + private String _memberRole; + + public CommunityUpdateMemberRole(Integer communityId, String sender, String playerUUID, String memberRole) + { + _communityId = communityId; + _sender = sender; + _playerUUID = playerUUID; + _memberRole = memberRole; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getSender() + { + return _sender; + } + + public String getPlayerUUID() + { + return _playerUUID; + } + + public String getMemberRole() + { + return _memberRole; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberRoleHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberRoleHandler.java new file mode 100644 index 000000000..bced0dc12 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMemberRoleHandler.java @@ -0,0 +1,32 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunityRole; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateMemberRoleHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityUpdateMemberRoleHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityUpdateMemberRole) + { + CommunityUpdateMemberRole update = ((CommunityUpdateMemberRole) command); + Integer id = update.getCommunityId(); + UUID uuid = UUID.fromString(update.getPlayerUUID()); + CommunityRole role = CommunityRole.parseRole(update.getMemberRole()); + + _manager.handleCommunityMembershipRoleUpdate(id, update.getSender(), uuid, role); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMembership.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMembership.java new file mode 100644 index 000000000..cb870d786 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMembership.java @@ -0,0 +1,60 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateMembership extends ServerCommand +{ + private Integer _communityId; + private String _sender; + private String _playerName; + private String _playerUUID; + private Integer _accountId; + private boolean _kick; + private boolean _leave; + + public CommunityUpdateMembership(Integer communityId, String sender, String playerName, String playerUUID, Integer accountId, boolean kick, boolean leave) + { + _communityId = communityId; + _sender = sender; + _playerName = playerName; + _playerUUID = playerUUID; + _accountId = accountId; + _kick = kick; + _leave = leave; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getSender() + { + return _sender; + } + + public String getPlayerName() + { + return _playerName; + } + + public String getPlayerUUID() + { + return _playerUUID; + } + + public Integer getAccountId() + { + return _accountId; + } + + public boolean isKick() + { + return _kick; + } + + public boolean isLeave() + { + return _leave; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMembershipHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMembershipHandler.java new file mode 100644 index 000000000..2ca354304 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateMembershipHandler.java @@ -0,0 +1,35 @@ +package mineplex.core.communities.redis; + +import java.util.UUID; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateMembershipHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityUpdateMembershipHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityUpdateMembership) + { + CommunityUpdateMembership update = ((CommunityUpdateMembership) command); + Integer id = update.getCommunityId(); + UUID uuid = UUID.fromString(update.getPlayerUUID()); + String sender = update.getSender(); + String name = update.getPlayerName(); + Integer accountId = update.getAccountId(); + boolean kick = update.isKick(); + boolean leave = update.isLeave(); + + _manager.handleCommunityMembershipUpdate(id, sender, name, uuid, accountId, kick, leave); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateName.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateName.java new file mode 100644 index 000000000..a58347a2c --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateName.java @@ -0,0 +1,32 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateName extends ServerCommand +{ + private Integer _communityId; + private String _sender; + private String _name; + + public CommunityUpdateName(Integer communityId, String sender, String name) + { + _communityId = communityId; + _sender = sender; + _name = name; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getSender() + { + return _sender; + } + + public String getName() + { + return _name; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateNameHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateNameHandler.java new file mode 100644 index 000000000..b854b121f --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateNameHandler.java @@ -0,0 +1,29 @@ +package mineplex.core.communities.redis; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateNameHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityUpdateNameHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityUpdateName) + { + CommunityUpdateName update = ((CommunityUpdateName) command); + Integer id = update.getCommunityId(); + String sender = update.getSender(); + String name = update.getName(); + + _manager.handleCommunityNameUpdate(id, sender, name); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateSetting.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateSetting.java new file mode 100644 index 000000000..bae592d9c --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateSetting.java @@ -0,0 +1,39 @@ +package mineplex.core.communities.redis; + +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateSetting extends ServerCommand +{ + private Integer _communityId; + private String _sender; + private String _setting; + private String _newValue; + + public CommunityUpdateSetting(Integer communityId, String sender, String setting, String newValue) + { + _communityId = communityId; + _sender = sender; + _setting = setting; + _newValue = newValue; + } + + public Integer getCommunityId() + { + return _communityId; + } + + public String getSender() + { + return _sender; + } + + public String getSetting() + { + return _setting; + } + + public String getNewValue() + { + return _newValue; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateSettingHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateSettingHandler.java new file mode 100644 index 000000000..198a50694 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/CommunityUpdateSettingHandler.java @@ -0,0 +1,30 @@ +package mineplex.core.communities.redis; + +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunitySetting; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.ServerCommand; + +public class CommunityUpdateSettingHandler implements CommandCallback +{ + private CommunityManager _manager; + + public CommunityUpdateSettingHandler(CommunityManager manager) + { + _manager = manager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof CommunityUpdateSetting) + { + CommunityUpdateSetting update = ((CommunityUpdateSetting) command); + Integer id = update.getCommunityId(); + CommunitySetting setting = CommunitySetting.valueOf(update.getSetting()); + String newValue = update.getNewValue(); + + _manager.handleCommunitySettingUpdate(id, update.getSender(), setting, newValue); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/storage/CommunityRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/storage/CommunityRepository.java new file mode 100644 index 000000000..3147d104c --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/storage/CommunityRepository.java @@ -0,0 +1,438 @@ +package mineplex.core.communities.storage; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.common.util.Callback; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityJoinRequestInfo; +import mineplex.core.communities.CommunityMemberInfo; +import mineplex.core.communities.CommunityRole; +import mineplex.core.communities.CommunitySetting; +import mineplex.core.database.MinecraftRepository; +import mineplex.serverdata.data.DataRepository; +import mineplex.serverdata.data.PlayerStatus; +import mineplex.serverdata.database.DBPool; +import mineplex.serverdata.database.column.ColumnBoolean; +import mineplex.serverdata.database.column.ColumnInt; +import mineplex.serverdata.database.column.ColumnVarChar; + +public class CommunityRepository extends MinecraftRepository +{ + private static final String GET_ALL_COMMUNITIES = "SELECT * FROM communities WHERE region=?;"; + private static final String GET_COMMUNITY_BY_ID = "SELECT * FROM communities WHERE id=?;"; + private static final String GET_COMMUNITY_BY_NAME = "SELECT * FROM communities WHERE name=? AND region=?;"; + private static final String GET_COMMUNITY_MEMBERS = "SELECT cm.accountId, cm.communityRole, ac.name, ac.uuid, ac.lastLogin, now(), cm.readingChat, (SELECT COUNT(id) FROM communityMembers WHERE accountId=cm.accountId AND communityRole='LEADER') FROM communityMembers cm INNER JOIN accounts ac ON ac.id=cm.accountId WHERE communityId=?;"; + private static final String GET_COMMUNITY_JOIN_REQUESTS = "SELECT cjr.accountId, ac.name, ac.uuid FROM communityJoinRequests cjr INNER JOIN accounts ac ON ac.id=cjr.accountId WHERE communityId=?;"; + private static final String GET_COMMUNITY_SETTINGS = "SELECT settingId, settingValue FROM communitySettings WHERE communityId=?;"; + + private static final String REMOVE_FROM_COMMUNITY = "DELETE FROM communityMembers WHERE accountId=? AND communityId=?;"; + private static final String UPDATE_COMMUNITY_ROLE = "UPDATE communityMembers SET communityRole=? WHERE accountId=? AND communityId=?;"; + private static final String ADD_TO_COMMUNITY = "INSERT INTO communityMembers (accountId, communityId, communityRole, readingChat) VALUES (?, ?, ?, true);"; + private static final String UPDATE_COMMUNITY_SETTING = "INSERT INTO communitySettings (settingId, communityId, settingValue) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE settingValue=VALUES(settingValue);"; + private static final String UPDATE_COMMUNITY_NAME = "UPDATE communities SET name=? WHERE id=?;"; + private static final String INVITE_TO_COMMUNITY = "INSERT INTO communityInvites (accountId, communityId) SELECT a.id AS accountId, ? FROM accounts as a WHERE a.name = ? ORDER BY a.lastLogin DESC LIMIT 1 ON DUPLICATE KEY UPDATE communityInvites.id=communityInvites.id;"; + private static final String DELETE_INVITE_TO_COMMUNITY = "DELETE i FROM communityInvites AS i INNER JOIN accounts as a ON i.accountId = a.id WHERE a.name = ? AND i.communityId=?;"; + private static final String ADD_JOIN_REQUEST = "INSERT INTO communityJoinRequests (accountId, communityId) VALUES (?, ?);"; + private static final String REMOVE_JOIN_REQUEST = "DELETE FROM communityJoinRequests WHERE accountId=? AND communityId=?;"; + + private static final String CREATE_COMMUNITY = "INSERT INTO communities (name, region) VALUES (?, ?);"; + + private static final String SET_READING_CHAT_IN = "UPDATE communityMembers SET readingChat=? WHERE accountId=? AND communityId=?;"; + + private DataRepository _repo; + private boolean _us; + + public CommunityRepository(JavaPlugin plugin, DataRepository statusRepo, boolean us) + { + super(DBPool.getAccount()); + + _repo = statusRepo; + _us = us; + } + + public void loadCommunity(int communityId, final Map communityMap) + { + try (Connection connection = getConnection()) + { + executeQuery(connection, GET_COMMUNITY_BY_ID, resultSet -> + { + if (resultSet.next()) + { + final int id = resultSet.getInt("id"); + final String cName = resultSet.getString("name"); + final Community community = new Community(id, cName); + executeQuery(connection, GET_COMMUNITY_MEMBERS, memberSet -> + { + while (memberSet.next()) + { + final int accountId = memberSet.getInt("accountId"); + final String name = memberSet.getString("name"); + final UUID uuid = UUID.fromString(memberSet.getString("uuid")); + final CommunityRole role = CommunityRole.parseRole(memberSet.getString("communityRole")); + final long timeSinceOnline = memberSet.getTimestamp(6).getTime() - memberSet.getTimestamp(5).getTime(); + boolean readingChat = memberSet.getBoolean("readingChat"); + final int owns = memberSet.getInt(8); + + CommunityMemberInfo info = new CommunityMemberInfo(name, uuid, accountId, role, timeSinceOnline); + PlayerStatus status = _repo.getElement(name); + if (status != null) + { + info.update(name, role, timeSinceOnline, true, status.getServer()); + } + info.ReadingChat = readingChat; + info.OwnsCommunity = owns > 0; + community.getMembers().put(info.UUID, info); + } + }, new ColumnInt("communityId", community.getId())); + + executeQuery(connection, GET_COMMUNITY_JOIN_REQUESTS, requestSet -> + { + while (requestSet.next()) + { + final int accountId = requestSet.getInt("accountId"); + final UUID uuid = UUID.fromString(requestSet.getString("uuid")); + final String name = requestSet.getString("name"); + + community.getJoinRequests().put(uuid, new CommunityJoinRequestInfo(name, uuid, accountId)); + } + }, new ColumnInt("communityId", community.getId())); + + executeQuery(connection, GET_COMMUNITY_SETTINGS, settingSet -> + { + while (settingSet.next()) + { + final int settingId = settingSet.getInt("settingId"); + final String value = settingSet.getString("settingValue"); + + CommunitySetting setting = CommunitySetting.getSetting(settingId); + if (setting != null) + { + setting.parseValueInto(value, community); + } + } + }, new ColumnInt("communityId", community.getId())); + + communityMap.put(community.getId(), community); + } + }, new ColumnInt("id", communityId)); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + + public void loadCommunities(final Map communityMap) + { + try (Connection connection = getConnection()) + { + executeQuery(connection, GET_ALL_COMMUNITIES, resultSet -> + { + Map resultant = new HashMap<>(); + while (resultSet.next()) + { + final int id = resultSet.getInt("id"); + final String cName = resultSet.getString("name"); + final Community community = new Community(id, cName); + executeQuery(connection, GET_COMMUNITY_MEMBERS, memberSet -> + { + while (memberSet.next()) + { + final int accountId = memberSet.getInt("accountId"); + final String name = memberSet.getString("name"); + final UUID uuid = UUID.fromString(memberSet.getString("uuid")); + final CommunityRole role = CommunityRole.parseRole(memberSet.getString("communityRole")); + final long timeSinceOnline = memberSet.getTimestamp(6).getTime() - memberSet.getTimestamp(5).getTime(); + boolean readingChat = memberSet.getBoolean("readingChat"); + final int owns = memberSet.getInt(8); + + CommunityMemberInfo info = new CommunityMemberInfo(name, uuid, accountId, role, timeSinceOnline); + PlayerStatus status = _repo.getElement(name); + if (status != null) + { + info.update(name, role, timeSinceOnline, true, status.getServer()); + } + info.ReadingChat = readingChat; + info.OwnsCommunity = owns > 0; + community.getMembers().put(info.UUID, info); + } + }, new ColumnInt("communityId", community.getId())); + + executeQuery(connection, GET_COMMUNITY_JOIN_REQUESTS, requestSet -> + { + while (requestSet.next()) + { + final int accountId = requestSet.getInt("accountId"); + final UUID uuid = UUID.fromString(requestSet.getString("uuid")); + final String name = requestSet.getString("name"); + + community.getJoinRequests().put(uuid, new CommunityJoinRequestInfo(name, uuid, accountId)); + } + }, new ColumnInt("communityId", community.getId())); + + executeQuery(connection, GET_COMMUNITY_SETTINGS, settingSet -> + { + while (settingSet.next()) + { + final int settingId = settingSet.getInt("settingId"); + final String value = settingSet.getString("settingValue"); + + CommunitySetting setting = CommunitySetting.getSetting(settingId); + if (setting != null) + { + setting.parseValueInto(value, community); + } + } + }, new ColumnInt("communityId", community.getId())); + + resultant.put(community.getId(), community); + } + + communityMap.clear(); + communityMap.putAll(resultant); + }, new ColumnVarChar("region", 5, _us ? "US" : "EU")); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + + public void updateMembersAndJoinRequests(LinkedList communities) + { + if (communities.isEmpty()) + { + return; + } + String query = ""; + for (Community c : communities) + { + query = query + GET_COMMUNITY_MEMBERS.replace("?", c.getId().toString()) + GET_COMMUNITY_JOIN_REQUESTS.replace("?", c.getId().toString()); + } + + if (query.isEmpty()) + { + return; + } + + try (Connection connection = getConnection(); Statement statement = connection.createStatement()) + { + statement.executeQuery(query); + + for (Community c : communities) + { + ResultSet memberSet = statement.getResultSet(); + while (memberSet.next()) + { + final UUID uuid = UUID.fromString(memberSet.getString("uuid")); + final String name = memberSet.getString("name"); + final CommunityRole role = CommunityRole.parseRole(memberSet.getString("communityRole")); + final long timeSinceOnline = memberSet.getTimestamp(6).getTime() - memberSet.getTimestamp(5).getTime(); + //boolean readingChat = memberSet.getBoolean("readingChat"); + final int owns = memberSet.getInt(8); + + if (c.getMembers().containsKey(uuid)) + { + PlayerStatus status = _repo.getElement(name); + boolean online = false; + String server = ""; + if (status != null) + { + online = true; + server = status.getServer(); + } + //c.getMembers().get(uuid).ReadingChat = readingChat; + c.getMembers().get(uuid).OwnsCommunity = owns > 0; + c.getMembers().get(uuid).update(name, role, timeSinceOnline, online, server); + } + } + + statement.getMoreResults(); + + ResultSet requestSet = statement.getResultSet(); + while (requestSet.next()) + { + final UUID uuid = UUID.fromString(requestSet.getString("uuid")); + final String name = requestSet.getString("name"); + + if (c.getJoinRequests().containsKey(uuid)) + { + c.getJoinRequests().get(uuid).update(name); + } + } + + statement.getMoreResults(); + } + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + + public void updateMembers(Map members, int communityId) + { + executeQuery(GET_COMMUNITY_MEMBERS, memberSet -> + { + while (memberSet.next()) + { + final UUID uuid = UUID.fromString(memberSet.getString("uuid")); + final String name = memberSet.getString("name"); + final CommunityRole role = CommunityRole.parseRole(memberSet.getString("communityRole")); + final long timeSinceOnline = memberSet.getTimestamp(5).getTime() - memberSet.getTimestamp(4).getTime(); + //boolean readingChat = memberSet.getBoolean("readingChat"); + final int owns = memberSet.getInt(8); + + if (members.containsKey(uuid)) + { + PlayerStatus status = _repo.getElement(name); + boolean online = false; + String server = ""; + if (status != null) + { + online = true; + server = status.getServer(); + } + //members.get(uuid).ReadingChat = readingChat; + members.get(uuid).OwnsCommunity = owns > 0; + members.get(uuid).update(name, role, timeSinceOnline, online, server); + } + } + }, new ColumnInt("communityId", communityId)); + } + + public void updateJoinRequests(Map requests, int communityId) + { + executeQuery(GET_COMMUNITY_JOIN_REQUESTS, requestSet -> + { + while (requestSet.next()) + { + final UUID uuid = UUID.fromString(requestSet.getString("uuid")); + final String name = requestSet.getString("name"); + + if (requests.containsKey(uuid)) + { + requests.get(uuid).update(name); + } + } + }, new ColumnInt("communityId", communityId)); + } + + public void loadInvites(int accountId, List invites) + { + executeQuery("SELECT ci.communityId, c.region FROM communityInvites AS ci INNER JOIN communities AS c ON c.id=ci.communityId WHERE accountId=?;", resultSet -> + { + while (resultSet.next()) + { + String region = resultSet.getString("region"); + if ((_us && region.equalsIgnoreCase("US")) || (!_us && region.equalsIgnoreCase("EU"))) + { + invites.add(resultSet.getInt("communityId")); + } + } + }, new ColumnInt("accountId", accountId)); + } + + public void removeFromCommunity(int accountId, int communityId) + { + executeUpdate(REMOVE_FROM_COMMUNITY, new ColumnInt("accountId", accountId), new ColumnInt("communityId", communityId)); + } + + public void updateCommunityRole(int accountId, int communityId, CommunityRole role) + { + executeUpdate(UPDATE_COMMUNITY_ROLE, new ColumnVarChar("communityRole", 20, role.toString()), new ColumnInt("accountId", accountId), new ColumnInt("communityId", communityId)); + } + + public void addToCommunity(int accountId, int communityId) + { + executeUpdate(ADD_TO_COMMUNITY, new ColumnInt("accountId", accountId), new ColumnInt("communityId", communityId), new ColumnVarChar("communityRole", 20, CommunityRole.MEMBER.toString())); + } + + public void updateCommunitySetting(CommunitySetting setting, int communityId, String value) + { + executeUpdate(UPDATE_COMMUNITY_SETTING, new ColumnInt("settingId", setting.getId()), new ColumnInt("communityId", communityId), new ColumnVarChar("settingValue", 100, value)); + } + + public void updateCommunityName(int communityId, String name) + { + executeUpdate(UPDATE_COMMUNITY_NAME, new ColumnVarChar("name", 15, name), new ColumnInt("id", communityId)); + } + + public boolean inviteToCommunity(int communityId, String name) + { + return executeUpdate(INVITE_TO_COMMUNITY, new ColumnInt("communityId", communityId), new ColumnVarChar("name", 32, name)) > 0; + } + + public boolean deleteInviteToCommunity(int communityId, String name) + { + return executeUpdate(DELETE_INVITE_TO_COMMUNITY, new ColumnVarChar("name", 32, name), new ColumnInt("communityId", communityId)) > 0; + } + + public void addJoinRequest(int communityId, int accountId) + { + executeUpdate(ADD_JOIN_REQUEST, new ColumnInt("accountId", accountId), new ColumnInt("communityId", communityId)); + } + + public void removeJoinRequest(int communityId, int accountId) + { + executeUpdate(REMOVE_JOIN_REQUEST, new ColumnInt("accountId", accountId), new ColumnInt("communityId", communityId)); + } + + public void createCommunity(String name, int leaderAccount, Callback idCallback) + { + try (Connection connection = getConnection()) + { + executeInsert(connection, CREATE_COMMUNITY, resultSet -> + { + if (resultSet.next()) + { + int id = resultSet.getInt(1); + executeUpdate(connection, ADD_TO_COMMUNITY, new ColumnInt("accountId", leaderAccount), new ColumnInt("communityId", id), new ColumnVarChar("communityRole", 20, CommunityRole.LEADER.toString())); + idCallback.run(id); + } + else + { + idCallback.run(-1); + } + }, new ColumnVarChar("name", 15, name), new ColumnVarChar("region", 5, _us ? "US" : "EU")); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + + public void deleteCommunity(int communityId) + { + try (Connection connection = getConnection()) + { + executeUpdate(connection, "DELETE FROM communities WHERE id=?;", new ColumnInt("id", communityId)); + executeUpdate(connection, "DELETE FROM communitySettings WHERE communityId=?;", new ColumnInt("communityId", communityId)); + executeUpdate(connection, "DELETE FROM communityMembers WHERE communityId=?;", new ColumnInt("communityId", communityId)); + executeUpdate(connection, "DELETE FROM communityInvites WHERE communityId=?;", new ColumnInt("communityId", communityId)); + executeUpdate(connection, "DELETE FROM communityJoinRequests WHERE communityId=?", new ColumnInt("communityId", communityId)); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + + public void setReadingChat(int accountId, int communityId, boolean reading) + { + executeUpdate(SET_READING_CHAT_IN, new ColumnBoolean("readingChat", reading), new ColumnInt("accountId", accountId), new ColumnInt("communityId", communityId)); + } + + protected void initialize() {} + protected void update() {} +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/button/open/OpenTaunts.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/button/open/OpenTaunts.java new file mode 100644 index 000000000..e87cdcfb1 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/button/open/OpenTaunts.java @@ -0,0 +1,21 @@ +package mineplex.core.cosmetic.ui.button.open; + +import org.bukkit.entity.Player; + +import mineplex.core.cosmetic.ui.page.Menu; +import mineplex.core.cosmetic.ui.page.TauntPage; +import mineplex.core.gadget.types.Gadget; + +public class OpenTaunts extends OpenPageButton +{ + public OpenTaunts(Menu menu, Gadget active) + { + super(menu, active); + } + + @Override + protected void leftClick(Player player) + { + getMenu().getShop().openPageForPlayer(player, new TauntPage(getMenu().getPlugin(), getMenu().getShop(), getMenu().getClientManager(), getMenu().getDonationManager(), "Taunts", player)); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/GadgetPage.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/GadgetPage.java index 17e2a0b20..566443c22 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/GadgetPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/GadgetPage.java @@ -201,6 +201,11 @@ public class GadgetPage extends ShopPageBase itemLore.add(C.cBlack); itemLore.add(C.cRed + "Unlocked with Titan Rank"); } + else if (gadget.getCost(GlobalCurrency.TREASURE_SHARD) == -15) + { + itemLore.add(C.cBlack); + itemLore.add(C.cDAqua + "Unlocked with Eternal Rank"); + } } //Special case for item gadgets! diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/Menu.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/Menu.java index 229448b95..ef27ea645 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/Menu.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/Menu.java @@ -1,9 +1,17 @@ package mineplex.core.cosmetic.ui.page; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +import org.bukkit.Material; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Player; + import mineplex.core.account.CoreClientManager; import mineplex.core.common.currency.GlobalCurrency; import mineplex.core.common.util.C; -import mineplex.core.common.util.F; import mineplex.core.common.util.LineFormat; import mineplex.core.common.util.UtilText; import mineplex.core.cosmetic.CosmeticManager; @@ -20,24 +28,15 @@ import mineplex.core.cosmetic.ui.button.open.OpenMounts; import mineplex.core.cosmetic.ui.button.open.OpenMusic; import mineplex.core.cosmetic.ui.button.open.OpenParticles; import mineplex.core.cosmetic.ui.button.open.OpenPets; +import mineplex.core.cosmetic.ui.button.open.OpenTaunts; import mineplex.core.cosmetic.ui.button.open.OpenWinEffect; import mineplex.core.donation.DonationManager; import mineplex.core.gadget.types.Gadget; import mineplex.core.gadget.types.GadgetType; import mineplex.core.mount.Mount; import mineplex.core.pet.PetType; -import mineplex.core.shop.item.IButton; import mineplex.core.shop.item.ShopItem; import mineplex.core.shop.page.ShopPageBase; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; - -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; public class Menu extends ShopPageBase { @@ -187,14 +186,10 @@ public class Menu extends ShopPageBase addButton(musicSlot, new ShopItem(Material.GREEN_RECORD, "Music", lore, 1, false), new OpenMusic(this, enabled.get(type))); if (enabled.containsKey(type)) addGlow(musicSlot); - addButton(tauntSlot, new ShopItem(Material.NAME_TAG, "Taunts", new String[]{C.Bold + "", C.cDGreen + C.Italics + "Coming soon!"}, 1, false), new IButton() - { - @Override - public void onClick(Player player, ClickType clickType) - { - player.sendMessage(F.main("Shop", "Coming soon!")); - } - }); + type = GadgetType.TAUNT; + lore = getLore(ownedCount.get(type), maxCount.get(type), "Taunt your enemies or just show off. Use /taunt to have a good time!", "Visible in Games", enabled.get(type)); + addButton(tauntSlot, new ShopItem(Material.NAME_TAG, "Taunts", lore, 1, false), new OpenTaunts(this, enabled.get(type))); + if (enabled.containsKey(type)) addGlow(tauntSlot); type = GadgetType.WIN_EFFECT; lore = getLore(ownedCount.get(type), maxCount.get(type), "Winning a game with your friends all good and dandy, but then being able to also show off awesome effects is even more fun!", "Usable in Lobbies", enabled.get(type)); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/TauntPage.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/TauntPage.java index 3db625e5d..a519cfce8 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/TauntPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/TauntPage.java @@ -1,57 +1,57 @@ -package mineplex.core.cosmetic.ui.page; - -import java.util.List; - -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; - -import mineplex.core.account.CoreClientManager; -import mineplex.core.common.util.C; -import mineplex.core.cosmetic.CosmeticManager; -import mineplex.core.cosmetic.ui.CosmeticShop; -import mineplex.core.donation.DonationManager; -import mineplex.core.gadget.types.Gadget; -import mineplex.core.gadget.types.GadgetType; -import mineplex.core.shop.item.IButton; -import mineplex.core.shop.item.ShopItem; - -public class TauntPage extends GadgetPage -{ - - - public TauntPage(CosmeticManager plugin, CosmeticShop shop, CoreClientManager clientManager, DonationManager donationManager, String name, - Player player) - { - super(plugin, shop, clientManager, donationManager, name, player); - } - - @Override - protected void buildPage() - { - int slot = 10; - - List list = getPlugin().getGadgetManager().getGadgets(GadgetType.TAUNT); - if(list != null) - for (Gadget gadget : list) - { - addGadget(gadget, slot); - - if (getPlugin().getGadgetManager().getActive(getPlayer(), GadgetType.MORPH) == gadget) - addGlow(slot); - - slot++; - - if (slot == 26) - slot += 2; - } - - addButton(4, new ShopItem(Material.BED, C.cGray + " \u21FD Go Back", new String[]{}, 1, false), new IButton() - { - public void onClick(Player player, ClickType clickType) - { - getShop().openPageForPlayer(getPlayer(), new Menu(getPlugin(), getShop(), getClientManager(), getDonationManager(), player)); - } - }); - } -} +package mineplex.core.cosmetic.ui.page; + +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.util.C; +import mineplex.core.cosmetic.CosmeticManager; +import mineplex.core.cosmetic.ui.CosmeticShop; +import mineplex.core.donation.DonationManager; +import mineplex.core.gadget.types.Gadget; +import mineplex.core.gadget.types.GadgetType; +import mineplex.core.shop.item.IButton; +import mineplex.core.shop.item.ShopItem; + +public class TauntPage extends GadgetPage +{ + + + public TauntPage(CosmeticManager plugin, CosmeticShop shop, CoreClientManager clientManager, DonationManager donationManager, String name, + Player player) + { + super(plugin, shop, clientManager, donationManager, name, player); + } + + @Override + protected void buildPage() + { + int slot = 10; + + List list = getPlugin().getGadgetManager().getGadgets(GadgetType.TAUNT); + if(list != null) + for (Gadget gadget : list) + { + addGadget(gadget, slot); + + if (getPlugin().getGadgetManager().getActive(getPlayer(), GadgetType.TAUNT) == gadget) + addGlow(slot); + + slot++; + + if (slot == 26) + slot += 2; + } + + addButton(4, new ShopItem(Material.BED, C.cGray + " \u21FD Go Back", new String[]{}, 1, false), new IButton() + { + public void onClick(Player player, ClickType clickType) + { + getShop().openPageForPlayer(getPlayer(), new Menu(getPlugin(), getShop(), getClientManager(), getDonationManager(), player)); + } + }); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/GadgetManager.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/GadgetManager.java index f2d007fb3..e0cc2219b 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/GadgetManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/GadgetManager.java @@ -31,6 +31,7 @@ import mineplex.core.common.util.F; import mineplex.core.common.util.NautHashMap; import mineplex.core.common.util.UtilEnt; import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilTime; import mineplex.core.disguise.DisguiseManager; @@ -42,6 +43,7 @@ import mineplex.core.gadget.event.GadgetChangeEvent; import mineplex.core.gadget.event.GadgetCollideEntityEvent; import mineplex.core.gadget.event.GadgetEnableEvent; import mineplex.core.gadget.event.PlayerToggleSwimEvent; +import mineplex.core.gadget.event.TauntCommandEvent; import mineplex.core.gadget.gadgets.arrowtrail.ArrowTrailHalloween; import mineplex.core.gadget.gadgets.arrowtrail.candycane.ArrowTrailCandyCane; import mineplex.core.gadget.gadgets.arrowtrail.cupidslove.ArrowTrailCupid; @@ -168,6 +170,7 @@ import mineplex.core.gadget.gadgets.particle.shadow.ParticleFoot; import mineplex.core.gadget.gadgets.particle.titan.ParticleTitan; import mineplex.core.gadget.gadgets.particle.vampire.ParticleBlood; import mineplex.core.gadget.gadgets.particle.wisdom.ParticleEnchant; +import mineplex.core.gadget.gadgets.taunts.EternalTaunt; import mineplex.core.gadget.gadgets.wineffect.WinEffectBabyChicken; import mineplex.core.gadget.gadgets.wineffect.WinEffectFlames; import mineplex.core.gadget.gadgets.wineffect.WinEffectHalloween; @@ -207,6 +210,7 @@ import mineplex.core.gadget.types.MusicGadget; import mineplex.core.gadget.types.OutfitGadget; import mineplex.core.gadget.types.OutfitGadget.ArmorSlot; import mineplex.core.gadget.types.ParticleGadget; +import mineplex.core.gadget.types.TauntGadget; import mineplex.core.gadget.types.WinEffectGadget; import mineplex.core.hologram.HologramManager; import mineplex.core.incognito.IncognitoManager; @@ -531,6 +535,9 @@ public class GadgetManager extends MiniPlugin // Balloons //addGadget(new BabyCowBalloon(this)); + // TAUNTS!!! + addGadget(new EternalTaunt(this)); + for (GadgetType gadgetType : GadgetType.values()) { if (!_gadgets.containsKey(gadgetType)) @@ -765,7 +772,10 @@ public class GadgetManager extends MiniPlugin if (gadget instanceof WinEffectGadget) continue; - if(gadget instanceof GameModifierGadget) + if (gadget instanceof GameModifierGadget) + continue; + + if (gadget instanceof TauntGadget) continue; for (Player player : UtilServer.getPlayers()) @@ -1239,4 +1249,56 @@ public class GadgetManager extends MiniPlugin { return _soulManager; } + + /** + * Handles taunt commands + * @param event + */ + @EventHandler + public void onTauntCommand(TauntCommandEvent event) + { + Player player = event.getPlayer(); + + Gadget gadget = getActive(player, GadgetType.TAUNT); + + if (gadget == null) + { + event.setState(TauntCommandEvent.TauntState.NO_TAUNT); + UtilPlayer.message(player, F.main("Taunt", event.getState().getMessage())); + return; + } + + if (!(gadget instanceof TauntGadget)) + { + event.setState(TauntCommandEvent.TauntState.NO_TAUNT); + UtilPlayer.message(player, F.main("Taunt", event.getState().getMessage())); + return; + } + + TauntGadget taunt = (TauntGadget) gadget; + + if (!event.isGameInProgress() && event.getState().equals(TauntCommandEvent.TauntState.NONE)) + event.setState(TauntCommandEvent.TauntState.NOT_IN_GAME); + + if (taunt.isGameDisabled(event.getGameType()) && event.getState().equals(TauntCommandEvent.TauntState.NONE)) + event.setState(TauntCommandEvent.TauntState.GAME_DISABLED); + + if (!event.isAlive() && event.getState().equals(TauntCommandEvent.TauntState.NONE)) + event.setState(TauntCommandEvent.TauntState.NOT_ALIVE); + + if (event.isSpectator() && event.getState().equals(TauntCommandEvent.TauntState.NONE)) + event.setState(TauntCommandEvent.TauntState.SPECTATOR); + + if (event.isInPvp(taunt.getPvpCooldown()) && !taunt.canPlayWithPvp() + && event.getState().equals(TauntCommandEvent.TauntState.NONE)) + event.setState(TauntCommandEvent.TauntState.PVP); + + if (event.getState() != TauntCommandEvent.TauntState.NONE) + { + UtilPlayer.message(player, F.main("Taunt", event.getState().getMessage())); + return; + } + + taunt.start(player); + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/event/TauntCommandEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/event/TauntCommandEvent.java new file mode 100644 index 000000000..fc6e643f3 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/event/TauntCommandEvent.java @@ -0,0 +1,106 @@ +package mineplex.core.gadget.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import mineplex.core.common.util.UtilTime; +import mineplex.core.gadget.gadgets.taunts.GameType; + +public class TauntCommandEvent extends Event +{ + + private static final HandlerList handlers = new HandlerList(); + + private Player _player; + private boolean _gameInProgress; + private boolean _alive; + private boolean _spectator; + private long _lastPvp; + private TauntState _state = TauntState.NONE; + private GameType _gameType; + + public TauntCommandEvent(Player player, boolean gameInProgress, boolean alive, boolean spectator, long lastPvp, GameType gameType) + { + _player = player; + _gameInProgress = gameInProgress; + _alive = alive; + _spectator = spectator; + _lastPvp = lastPvp; + _gameType = gameType; + } + + public Player getPlayer() + { + return _player; + } + + public boolean isGameInProgress() + { + return _gameInProgress; + } + + public boolean isAlive() + { + return _alive; + } + + public boolean isSpectator() + { + return _spectator; + } + + public boolean isInPvp(long cooldown) + { + return !UtilTime.elapsed(_lastPvp, cooldown); + } + + public TauntState getState() + { + return _state; + } + + public GameType getGameType() + { + return _gameType; + } + + public void setState(TauntState state) + { + _state = state; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } + + public enum TauntState + { + NONE(""), + NO_TAUNT("You have no active taunts!"), + NOT_IN_GAME("You are not in a game!"), + NOT_ALIVE("You are not playing the game!"), + SPECTATOR("You can't run this as a spectator!"), + PVP("You can't run this while in pvp!"), + GAME_DISABLED("Taunts are disabled in this game!"); + + private String _message; + + TauntState(String message) + { + _message = message; + } + + public String getMessage() + { + return _message; + } + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/EternalTaunt.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/EternalTaunt.java new file mode 100644 index 000000000..f34726000 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/EternalTaunt.java @@ -0,0 +1,153 @@ +package mineplex.core.gadget.gadgets.taunts; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.util.Vector; + +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.LineFormat; +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilText; +import mineplex.core.disguise.disguises.DisguiseSkeleton; +import mineplex.core.events.EnableArcadeSpawnEvent; +import mineplex.core.gadget.GadgetManager; +import mineplex.core.gadget.gadgets.morph.managers.UtilMorph; +import mineplex.core.gadget.types.TauntGadget; +import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; + +public class EternalTaunt extends TauntGadget +{ + + private static final int COOLDOWN = 30000; + private static final int PVP_COOLDOWN = 10000; + + private Map> _clocks = new HashMap<>(); + + public EternalTaunt(GadgetManager manager) + { + super(manager, "Eternal Taunt", UtilText.splitLinesToArray(new String[]{C.cGray + "Although the Eternal has been around forever, he waited to long for a worthy opponent and he turned to bones.", + "", + C.cWhite + "Use /taunt in game to show how long you've been waiting.", + C.cRed + "Cannot be used while in PvP!"}, LineFormat.LORE), + -15, Material.WATCH, (byte) 0); + setCanPlayWithPvp(false); + setPvpCooldown(PVP_COOLDOWN); + setShouldPlay(true); + setEventType(UpdateType.FAST); + addDisabledGames(GameType.SMASH, GameType.SMASHTEAMS, GameType.SMASHDOMINATION); + } + + @Override + public void disableCustom(Player player, boolean message) + { + finish(player); + } + + @Override + public void onStart(Player player) + { + if (!Recharge.Instance.use(player, getName(), COOLDOWN, true, false, "Cosmetics")) + return; + UtilFirework.playFirework(player.getLocation(), FireworkEffect.builder().with(FireworkEffect.Type.BALL_LARGE).withColor(Color.fromRGB(255, 175, 175)).withFade(Color.RED).build()); + + _clocks.put(player.getUniqueId(), new ArrayList<>()); + + Bukkit.broadcastMessage(F.main("Taunt", F.name(player.getName()) + " waited so long they turned to bones.")); + + DisguiseSkeleton disguiseSkeleton = new DisguiseSkeleton(player); + UtilMorph.disguise(player, disguiseSkeleton, Manager); + } + + @Override + public void onPlay(Player player) + { + if (!_clocks.containsKey(player.getUniqueId())) + return; + + int i = getPlayerTicks(player); + + EnableArcadeSpawnEvent enableArcadeSpawnEvent = new EnableArcadeSpawnEvent(true); + Bukkit.getPluginManager().callEvent(enableArcadeSpawnEvent); + + Item clock = player.getWorld().dropItem(player.getLocation().add(0.5, 1.5, 0.5), + ItemStackFactory.Instance.CreateStack(Material.WATCH, (byte) 0, 1, " " + i)); + + enableArcadeSpawnEvent = new EnableArcadeSpawnEvent(false); + Bukkit.getPluginManager().callEvent(enableArcadeSpawnEvent); + + Vector vel = new Vector(Math.sin(i * 9/5d), 0, Math.cos(i * 9/5d)); + UtilAction.velocity(clock, vel, Math.abs(Math.sin(i * 12/3000d)), false, 0, 0.2 + Math.abs(Math.cos(i * 12/3000d))*0.6, 1, false); + + _clocks.get(player.getUniqueId()).add(clock); + + if (_clocks.get(player.getUniqueId()).size() >= 5) + { + _clocks.get(player.getUniqueId()).get(0).remove(); + _clocks.get(player.getUniqueId()).remove(0); + } + + if (i % 2 == 0) + player.playSound(player.getLocation(), Sound.CLICK, 1f, 1f); + else + player.playSound(player.getLocation(), Sound.CLICK, 0.5f, 0.5f); + + if (i >= 15) + { + finish(player); + } + } + + @Override + public void onFinish(Player player) + { + UtilMorph.undisguise(player, Manager.getDisguiseManager()); + if (_clocks.containsKey(player.getUniqueId())) + { + _clocks.get(player.getUniqueId()).forEach(c -> c.remove()); + _clocks.get(player.getUniqueId()).clear(); + _clocks.remove(player.getUniqueId()); + } + } + + @EventHandler + public void titanOwner(PlayerJoinEvent event) + { + if (Manager.getClientManager().Get(event.getPlayer()).GetRank().has(Rank.ETERNAL)) + { + Manager.getDonationManager().Get(event.getPlayer()).addOwnedUnknownSalesPackage(getName()); + } + } + + @EventHandler + public void onClockPickup(PlayerPickupItemEvent event) + { + for (List clocks : _clocks.values()) + { + for (Item item : clocks) + { + if (event.getItem().equals(item)) + event.setCancelled(true); + } + } + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/GameType.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/GameType.java new file mode 100644 index 000000000..26e0c607c --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/GameType.java @@ -0,0 +1,84 @@ +package mineplex.core.gadget.gadgets.taunts; + +public enum GameType +{ + + BACONBRAWL, + BARBARIANS, + BASKETBALL, + BOSSBATTLES, + BRIDGE, + CASTLESIEGE, + CHAMPIONSCTF, + CHAMPIONSDOMINATE, + CHAMPIONSTDM, + CHRISTMAS, + DEATHTAG, + DRAGONESCAPE, + DRAGONESCAPETEAMS, + DRAGONRIDERS, + DRAGONS, + DRAGONSTEAMS, + DRAW, + ELYTRARINGS, + EVOLUTION, + GRAVITY, + HALLOWEEN, + HALLOWEEN2016, + HIDESEEK, + HOLEINTHEWALL, + HORSE, + LOBBERS, + MICRO, + MILKCOW, + MINESTRIKE, + BAWKBAWKBATTLES, + MINECRAFTLEAGUE, + OLDMINEWARE, + PAINTBALL, + QUIVER, + QUIVERPAYLOAD, + QUIVERTEAMS, + RUNNER, + SEARCHANDDESTROY, + SHEEP, + TYPEWARS, + SMASH, + SMASHDOMINATION, + SMASHTEAMS, + SNAKE, + SNEAKYASSASSINS, + SNOWFIGHT, + SPEEDBUILDERS, + SPLEEF, + SPLEEFTEAMS, + SQUIDSHOOTER, + STACKER, + SURVIVALGAMES, + SURVIVALGAMESTEAMS, + TUG, + TURFWARS, + UHC, + UHCSOLO, + UHCSOLOSPEED, + UHCTEAMSSPEED, + WITHERASSAULT, + WIZARDS, + ZOMBIESURVIVAL, + BUILD, + BUILDMAVERICKS, + CARDS, + SKYWARS, + SKYWARSTEAMS, + MONSTERMAZE, + MONSTERLEAGUE, + GLADIATORS, + SKYFALL, + SKYFALLTEAMS, + BOUNCYBALLS, + VALENTINES, + EVENT, + BRAWL, + NONE + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/types/TauntGadget.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/types/TauntGadget.java new file mode 100644 index 000000000..f1bce90be --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/types/TauntGadget.java @@ -0,0 +1,156 @@ +package mineplex.core.gadget.types; + +import java.time.YearMonth; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.gadget.GadgetManager; +import mineplex.core.gadget.gadgets.taunts.GameType; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; + +/** + * Handles Taunts + */ +public abstract class TauntGadget extends Gadget +{ + + /** Sets if this specific taunt can be used while in PvP */ + private boolean _canPlayWithPvp = false; + /** Sets the cooldown for pvp */ + private long _pvpCooldown = 0; + /** Sets if this taunt needs to run on updates */ + private boolean _shouldPlay = false; + /** Sets when the taunt will run, if set above */ + private UpdateType _updateType = UpdateType.TICK; + /** List of games where this item is disabled */ + private List _disabledGames = new ArrayList<>(); + /** The ticks that passed since the player started the effect */ + private Map _ticksPerPlayer = new HashMap<>(); + + /** + * @param manager The normal GadgetManager + * @param name The name of the item + * @param desc The lore/description of the item + * @param cost The cost of the item + * @param mat The display material of the item + * @param data The display data of the item + * @param alternativeSalesPackageNames Possible alternative names for this package + */ + public TauntGadget(GadgetManager manager, String name, String[] desc, int cost, Material mat, byte data, + String... alternativeSalesPackageNames) + { + super(manager, GadgetType.TAUNT, name, desc, cost, mat, data, 1, alternativeSalesPackageNames); + } + + /** + * @param manager The normal GadgetManager + * @param name The name of the item + * @param desc The lore/description of the item + * @param cost The cost of the item + * @param mat The display material of the item + * @param data The display data of the item + * @param yearMonth The year and month of this item, if it is a PPC item + * @param alternativeSalesPackageNames Possible alternative names for this package + */ + public TauntGadget(GadgetManager manager, String name, String[] desc, int cost, Material mat, byte data, + YearMonth yearMonth, String... alternativeSalesPackageNames) + { + super(manager, GadgetType.TAUNT, name, desc, cost, mat, data, yearMonth, 1, alternativeSalesPackageNames); + } + + public void start(Player player) + { + onStart(player); + _ticksPerPlayer.put(player.getUniqueId(), 0); + } + + public abstract void onStart(Player player); + + public void play(Player player) + { + onPlay(player); + int ticks = getPlayerTicks(player) + 1; + _ticksPerPlayer.put(player.getUniqueId(), ticks); + } + + public abstract void onPlay(Player player); + + public void finish(Player player) + { + onFinish(player); + _ticksPerPlayer.remove(player.getUniqueId()); + } + + public abstract void onFinish(Player player); + + public void setCanPlayWithPvp(boolean canPlayWithPvp) + { + _canPlayWithPvp = canPlayWithPvp; + } + + public void setPvpCooldown(long pvpCooldown) + { + _pvpCooldown = pvpCooldown; + } + + public void setShouldPlay(boolean shouldPlay) + { + _shouldPlay = shouldPlay; + } + + public void setEventType(UpdateType updateType) + { + _updateType = updateType; + } + + public void addDisabledGames(GameType... disabledGames) + { + _disabledGames.addAll(Arrays.asList(disabledGames)); + } + + public boolean canPlayWithPvp() + { + return _canPlayWithPvp; + } + + public boolean isGameDisabled(GameType gameType) + { + return _disabledGames.contains(gameType); + } + + public long getPvpCooldown() + { + return _pvpCooldown; + } + + public int getPlayerTicks(Player player) + { + return (_ticksPerPlayer.containsKey(player.getUniqueId())) ? _ticksPerPlayer.get(player.getUniqueId()) : -1; + } + + @EventHandler + public void onUpdate(UpdateEvent event) + { + if (!_shouldPlay) + return; + + if (event.getType() != _updateType) + return; + + for (Player player : getActive()) + { + if (_ticksPerPlayer.containsKey(player.getUniqueId())) + play(player); + } + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java b/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java index 30467d6f7..585e37864 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java @@ -10,96 +10,96 @@ import org.bukkit.Material; public enum GameDisplay { //Mini - BaconBrawl("Bacon Brawl", Material.PORK, (byte)0, GameCategory.ARCADE, 1), - Barbarians("A Barbarians Life", Material.WOOD_AXE, (byte)0, GameCategory.EXTRA, 2), - BossBattles("Boss Battles", Material.SKULL_ITEM, (byte) 0, GameCategory.EVENT, 55), - Bridge("The Bridges", Material.IRON_PICKAXE, (byte)0, GameCategory.SURVIVAL, 3), - CastleSiege("Castle Siege", Material.DIAMOND_CHESTPLATE, (byte)0, GameCategory.CLASSICS, 4), - ChampionsDominate("Champions Domination", "Champions", Material.BEACON, (byte)0, GameCategory.CHAMPIONS, 6), - ChampionsTDM("Champions TDM", "Champions", Material.GOLD_SWORD, (byte)0, GameCategory.CHAMPIONS, 5), - Christmas("Christmas Chaos", Material.SNOW_BALL, (byte)0, GameCategory.CLASSICS, 8), - DeathTag("Death Tag", Material.SKULL_ITEM, (byte)0, GameCategory.ARCADE, 9), - DragonEscape("Dragon Escape", Material.DRAGON_EGG, (byte)0, GameCategory.ARCADE, 10), - DragonEscapeTeams("Dragon Escape Teams", Material.DRAGON_EGG, (byte)0, GameCategory.TEAM_VARIANT, 11), - DragonRiders("Dragon Riders", Material.DRAGON_EGG, (byte)0, GameCategory.ARCADE, 12), - Dragons("Dragons", Material.ENDER_STONE, (byte)0, GameCategory.ARCADE, 13), - DragonsTeams("Dragons Teams", Material.DRAGON_EGG, (byte)0, GameCategory.TEAM_VARIANT, 14), - Draw("Draw My Thing", Material.BOOK_AND_QUILL, (byte)0, GameCategory.CLASSICS, 15), - ElytraRings("Elytra Rings", Material.ELYTRA, (byte) 0, GameCategory.CLASSICS, 61), - Evolution("Evolution", Material.EMERALD, (byte)0, GameCategory.ARCADE, 16), - Gravity("Gravity", Material.ENDER_PORTAL_FRAME, (byte)0, GameCategory.EXTRA, 18), - Halloween("Halloween Horror", Material.PUMPKIN, (byte)0, GameCategory.CLASSICS, 19), - Halloween2016("Pumpkin's Revenge", Material.PUMPKIN, (byte)0, GameCategory.CLASSICS, 63), - HideSeek("Block Hunt", Material.GRASS, (byte)0, GameCategory.CLASSICS, 20), - HoleInTheWall("Hole in the Wall", Material.STAINED_GLASS, (byte) 2, GameCategory.ARCADE, 52), - Horse("Horseback", Material.IRON_BARDING, (byte)0, GameCategory.ARCADE, 21), + BaconBrawl("Bacon Brawl", Material.PORK, (byte)0, GameCategory.ARCADE, 1, true), + Barbarians("A Barbarians Life", Material.WOOD_AXE, (byte)0, GameCategory.EXTRA, 2, false), + BossBattles("Boss Battles", Material.SKULL_ITEM, (byte) 0, GameCategory.EVENT, 55, false), + Bridge("The Bridges", Material.IRON_PICKAXE, (byte)0, GameCategory.SURVIVAL, 3, true), + CastleSiege("Castle Siege", Material.DIAMOND_CHESTPLATE, (byte)0, GameCategory.CLASSICS, 4, true), + ChampionsDominate("Champions Domination", "Champions", Material.BEACON, (byte)0, GameCategory.CHAMPIONS, 6, true), + ChampionsTDM("Champions TDM", "Champions", Material.GOLD_SWORD, (byte)0, GameCategory.CHAMPIONS, 5, true), + Christmas("Christmas Chaos", Material.SNOW_BALL, (byte)0, GameCategory.CLASSICS, 8, false), + DeathTag("Death Tag", Material.SKULL_ITEM, (byte)0, GameCategory.ARCADE, 9, true), + DragonEscape("Dragon Escape", Material.DRAGON_EGG, (byte)0, GameCategory.ARCADE, 10, true), + DragonEscapeTeams("Dragon Escape Teams", Material.DRAGON_EGG, (byte)0, GameCategory.TEAM_VARIANT, 11, false), + DragonRiders("Dragon Riders", Material.DRAGON_EGG, (byte)0, GameCategory.ARCADE, 12, false), + Dragons("Dragons", Material.ENDER_STONE, (byte)0, GameCategory.ARCADE, 13, true), + DragonsTeams("Dragons Teams", Material.DRAGON_EGG, (byte)0, GameCategory.TEAM_VARIANT, 14, false), + Draw("Draw My Thing", Material.BOOK_AND_QUILL, (byte)0, GameCategory.CLASSICS, 15, true), + ElytraRings("Elytra Rings", Material.ELYTRA, (byte) 0, GameCategory.CLASSICS, 61, false), + Evolution("Evolution", Material.EMERALD, (byte)0, GameCategory.ARCADE, 16, true), + Gravity("Gravity", Material.ENDER_PORTAL_FRAME, (byte)0, GameCategory.EXTRA, 18, false), + Halloween("Halloween Horror", Material.PUMPKIN, (byte)0, GameCategory.CLASSICS, 19, false), + Halloween2016("Pumpkin's Revenge", Material.PUMPKIN, (byte)0, GameCategory.CLASSICS, 63, false), + HideSeek("Block Hunt", Material.GRASS, (byte)0, GameCategory.CLASSICS, 20, true), + HoleInTheWall("Hole in the Wall", Material.STAINED_GLASS, (byte) 2, GameCategory.ARCADE, 52, false), + Horse("Horseback", Material.IRON_BARDING, (byte)0, GameCategory.ARCADE, 21, false), - Micro("Micro Battle", Material.LAVA_BUCKET, (byte)0, GameCategory.ARCADE, 24), - MilkCow("Milk the Cow", Material.MILK_BUCKET, (byte)0, GameCategory.ARCADE, 27), - MineStrike("MineStrike", Material.TNT, (byte)0, GameCategory.CHAMPIONS, 25),// Temp set to CHAMPIONS to fix UI bug - BawkBawkBattles("Bawk Bawk Battles", Material.EGG, (byte)0, GameCategory.CLASSICS, 26), - OldMineWare("Old MineWare", Material.PAPER, (byte)0, GameCategory.EXTRA, 26), - Paintball("Super Paintball", Material.ENDER_PEARL, (byte)0, GameCategory.ARCADE, 28), - Quiver("One in the Quiver", Material.ARROW, (byte)0, GameCategory.ARCADE, 29), - QuiverTeams("One in the Quiver Teams", Material.ARROW, (byte)0, GameCategory.TEAM_VARIANT, 30), - Runner("Runner", Material.LEATHER_BOOTS, (byte)0, GameCategory.ARCADE, 31), - SearchAndDestroy("Search and Destroy", Material.TNT, (byte)0, GameCategory.SURVIVAL, 32), - Sheep("Sheep Quest", Material.WOOL, (byte)4, GameCategory.ARCADE, 33), + Micro("Micro Battle", Material.LAVA_BUCKET, (byte)0, GameCategory.ARCADE, 24, true), + MilkCow("Milk the Cow", Material.MILK_BUCKET, (byte)0, GameCategory.ARCADE, 27, false), + MineStrike("MineStrike", Material.TNT, (byte)0, GameCategory.CHAMPIONS, 25, true),// Temp set to CHAMPIONS to fix UI bug + BawkBawkBattles("Bawk Bawk Battles", Material.EGG, (byte)0, GameCategory.CLASSICS, 26, true), + OldMineWare("Old MineWare", Material.PAPER, (byte)0, GameCategory.EXTRA, 26, false), + Paintball("Super Paintball", Material.ENDER_PEARL, (byte)0, GameCategory.ARCADE, 28, true), + Quiver("One in the Quiver", Material.ARROW, (byte)0, GameCategory.ARCADE, 29, true), + QuiverTeams("One in the Quiver Teams", Material.ARROW, (byte)0, GameCategory.TEAM_VARIANT, 30, false), + Runner("Runner", Material.LEATHER_BOOTS, (byte)0, GameCategory.ARCADE, 31, true), + SearchAndDestroy("Search and Destroy", Material.TNT, (byte)0, GameCategory.SURVIVAL, 32, false), + Sheep("Sheep Quest", Material.WOOL, (byte)4, GameCategory.ARCADE, 33, true), - Smash("Super Smash Mobs", Material.SKULL_ITEM, (byte)4, GameCategory.CLASSICS, 34), - SmashDomination("Super Smash Mobs Domination", "Super Smash Mobs", Material.SKULL_ITEM, (byte)4, GameCategory.EXTRA, 36), - SmashTeams("Super Smash Mobs Teams", "Super Smash Mobs", Material.SKULL_ITEM, (byte)4, GameCategory.TEAM_VARIANT, 35), - Snake("Snake", Material.WOOL, (byte)0, GameCategory.ARCADE, 37), - SneakyAssassins("Sneaky Assassins", Material.INK_SACK, (byte)0, GameCategory.ARCADE, 38), - SnowFight("Snow Fight", Material.SNOW_BALL, (byte)0, GameCategory.EXTRA, 39), - Spleef("Super Spleef", Material.IRON_SPADE, (byte)0, GameCategory.ARCADE, 40), - SpleefTeams("Super Spleef Teams", Material.IRON_SPADE, (byte)0, GameCategory.TEAM_VARIANT, 41), - SquidShooter("Squid Shooter", Material.FIREWORK_CHARGE, (byte)0, GameCategory.ARCADE, 43), - Stacker("Super Stacker", Material.BOWL, (byte)0, GameCategory.ARCADE, 42), - SurvivalGames("Survival Games", Material.IRON_SWORD, (byte)0, GameCategory.SURVIVAL, 22), - SurvivalGamesTeams("Survival Games Teams", "Survival Games", Material.IRON_SWORD, (byte)0, GameCategory.TEAM_VARIANT, 23), - Tug("Tug of Wool", Material.WHEAT, (byte)0, GameCategory.ARCADE, 44), - TurfWars("Turf Wars", Material.STAINED_CLAY, (byte)14, GameCategory.ARCADE, 45), - UHC("Ultra Hardcore", Material.GOLDEN_APPLE, (byte)0, GameCategory.TEAM_VARIANT, 46), - UHCSolo("Ultra Hardcore Solo", "Ultra Hardcore", Material.GOLDEN_APPLE, (byte)0, GameCategory.SURVIVAL, 46), - UHCSoloSpeed("Ultra Hardcore Solo Speed", "Ultra Hardcore", Material.GOLDEN_APPLE, (byte)0, GameCategory.SURVIVAL, 67), - UHCTeamsSpeed("Ultra Hardcore Teams Speed", "Ultra Hardcore", Material.GOLDEN_APPLE, (byte)0, GameCategory.TEAM_VARIANT, 67), - WitherAssault("Wither Assault", Material.SKULL_ITEM, (byte)1, GameCategory.ARCADE, 47), - Wizards("Wizards", Material.BLAZE_ROD, (byte)0, GameCategory.SURVIVAL, 48), - ZombieSurvival("Zombie Survival", Material.SKULL_ITEM, (byte)2, GameCategory.SURVIVAL, 49), + Smash("Super Smash Mobs", Material.SKULL_ITEM, (byte)4, GameCategory.CLASSICS, 34, true), + SmashDomination("Super Smash Mobs Domination", "Super Smash Mobs", Material.SKULL_ITEM, (byte)4, GameCategory.EXTRA, 36, false), + SmashTeams("Super Smash Mobs Teams", "Super Smash Mobs", Material.SKULL_ITEM, (byte)4, GameCategory.TEAM_VARIANT, 35, false), + Snake("Snake", Material.WOOL, (byte)0, GameCategory.ARCADE, 37, true), + SneakyAssassins("Sneaky Assassins", Material.INK_SACK, (byte)0, GameCategory.ARCADE, 38, true), + SnowFight("Snow Fight", Material.SNOW_BALL, (byte)0, GameCategory.EXTRA, 39, false), + Spleef("Super Spleef", Material.IRON_SPADE, (byte)0, GameCategory.ARCADE, 40, true), + SpleefTeams("Super Spleef Teams", Material.IRON_SPADE, (byte)0, GameCategory.TEAM_VARIANT, 41, false), + SquidShooter("Squid Shooter", Material.FIREWORK_CHARGE, (byte)0, GameCategory.ARCADE, 43, false), + Stacker("Super Stacker", Material.BOWL, (byte)0, GameCategory.ARCADE, 42, false), + SurvivalGames("Survival Games", Material.IRON_SWORD, (byte)0, GameCategory.SURVIVAL, 22, true), + SurvivalGamesTeams("Survival Games Teams", "Survival Games", Material.IRON_SWORD, (byte)0, GameCategory.TEAM_VARIANT, 23, false), + Tug("Tug of Wool", Material.WHEAT, (byte)0, GameCategory.ARCADE, 44, false), + TurfWars("Turf Wars", Material.STAINED_CLAY, (byte)14, GameCategory.ARCADE, 45, true), + UHC("Ultra Hardcore", Material.GOLDEN_APPLE, (byte)0, GameCategory.TEAM_VARIANT, 46, true), + UHCSolo("Ultra Hardcore Solo", "Ultra Hardcore", Material.GOLDEN_APPLE, (byte)0, GameCategory.SURVIVAL, 46, false), + UHCSoloSpeed("Ultra Hardcore Solo Speed", "Ultra Hardcore", Material.GOLDEN_APPLE, (byte)0, GameCategory.SURVIVAL, 67, false), + UHCTeamsSpeed("Ultra Hardcore Teams Speed", "Ultra Hardcore", Material.GOLDEN_APPLE, (byte)0, GameCategory.TEAM_VARIANT, 67, false), + WitherAssault("Wither Assault", Material.SKULL_ITEM, (byte)1, GameCategory.ARCADE, 47, true), + Wizards("Wizards", Material.BLAZE_ROD, (byte)0, GameCategory.SURVIVAL, 48, true), + ZombieSurvival("Zombie Survival", Material.SKULL_ITEM, (byte)2, GameCategory.SURVIVAL, 49, false), - Build("Master Builders", Material.WOOD, (byte)0, GameCategory.CLASSICS, 50), - BuildMavericks("Mavericks Master Builders", Material.WOOD, (byte)3, GameCategory.CLASSICS, 63), - Cards("Craft Against Humanity", Material.MAP, (byte)0, GameCategory.CLASSICS, 51), - Skywars("Skywars", Material.FEATHER, (byte) 0, GameCategory.SURVIVAL, 52), - SkywarsTeams("Skywars Teams", "Skywars", Material.FEATHER, (byte)0, GameCategory.TEAM_VARIANT, 53), - MonsterMaze("Monster Maze", Material.ROTTEN_FLESH, (byte)0, GameCategory.ARCADE, 55), - MonsterLeague("Monster League", Material.MINECART, (byte)0, GameCategory.ARCADE, 56), + Build("Master Builders", Material.WOOD, (byte)0, GameCategory.CLASSICS, 50, true), + BuildMavericks("Mavericks Master Builders", Material.WOOD, (byte)3, GameCategory.CLASSICS, 63, false), + Cards("Craft Against Humanity", Material.MAP, (byte)0, GameCategory.CLASSICS, 51, false), + Skywars("Skywars", Material.FEATHER, (byte) 0, GameCategory.SURVIVAL, 52, true), + SkywarsTeams("Skywars Teams", "Skywars", Material.FEATHER, (byte)0, GameCategory.TEAM_VARIANT, 53, false), + MonsterMaze("Monster Maze", Material.ROTTEN_FLESH, (byte)0, GameCategory.ARCADE, 55, true), + MonsterLeague("Monster League", Material.MINECART, (byte)0, GameCategory.ARCADE, 56, false), - Lobbers("Bomb Lobbers", Material.FIREBALL, (byte) 0, GameCategory.ARCADE, 54), + Lobbers("Bomb Lobbers", Material.FIREBALL, (byte) 0, GameCategory.ARCADE, 54, true), - Minecraft_League("MC League", Material.DIAMOND_SWORD, (byte)0, GameCategory.SURVIVAL, 62), + Minecraft_League("MC League", Material.DIAMOND_SWORD, (byte)0, GameCategory.SURVIVAL, 62, false), - ChampionsCTF("Champions CTF", "Champions", Material.BANNER, DyeColor.RED.getDyeData(), GameCategory.CHAMPIONS, 56), + ChampionsCTF("Champions CTF", "Champions", Material.BANNER, DyeColor.RED.getDyeData(), GameCategory.CHAMPIONS, 56, true), - BouncyBalls("Bouncy Balls", Material.SLIME_BALL, (byte)0, GameCategory.ARCADE, 57), - Gladiators("Gladiators", Material.IRON_SWORD, (byte)0, GameCategory.ARCADE, 58), - TypeWars("Type Wars", Material.NAME_TAG, (byte) 0, GameCategory.CLASSICS, 59), + BouncyBalls("Bouncy Balls", Material.SLIME_BALL, (byte)0, GameCategory.ARCADE, 57, false), + Gladiators("Gladiators", Material.IRON_SWORD, (byte)0, GameCategory.ARCADE, 58, true), + TypeWars("Type Wars", Material.NAME_TAG, (byte) 0, GameCategory.CLASSICS, 59, false), - SpeedBuilders("Speed Builders", Material.QUARTZ_BLOCK, (byte) 0, GameCategory.CLASSICS, 60), + SpeedBuilders("Speed Builders", Material.QUARTZ_BLOCK, (byte) 0, GameCategory.CLASSICS, 60, true), - Valentines("Valentines Vendetta", Material.LEATHER, (byte)0, GameCategory.EXTRA, 61), + Valentines("Valentines Vendetta", Material.LEATHER, (byte)0, GameCategory.EXTRA, 61, false), - Skyfall("Skyfall", Material.DIAMOND_BOOTS, (byte)0, GameCategory.SURVIVAL, 62), - SkyfallTeams("Skyfall Teams", Material.DIAMOND_BOOTS, (byte)0, GameCategory.SURVIVAL, 65), + Skyfall("Skyfall", Material.DIAMOND_BOOTS, (byte)0, GameCategory.SURVIVAL, 62, true), + SkyfallTeams("Skyfall Teams", Material.DIAMOND_BOOTS, (byte)0, GameCategory.SURVIVAL, 65, false), - Basketball("Hoops", Material.SLIME_BALL, (byte)0, GameCategory.EXTRA, 63), + Basketball("Hoops", Material.SLIME_BALL, (byte)0, GameCategory.EXTRA, 63, false), - QuiverPayload("One in the Quiver Payload", Material.ARROW, (byte)0, GameCategory.ARCADE, 64), + QuiverPayload("One in the Quiver Payload", Material.ARROW, (byte)0, GameCategory.ARCADE, 64, false), - Event("Mineplex Event", Material.CAKE, (byte)0, GameCategory.EVENT, 999), + Event("Mineplex Event", Material.CAKE, (byte)0, GameCategory.EVENT, 999, false), - Brawl("Brawl", Material.DIAMOND, (byte) 0, GameCategory.EVENT, 998); + Brawl("Brawl", Material.DIAMOND, (byte) 0, GameCategory.EVENT, 998, false); String _name; String _lobbyName; @@ -109,13 +109,16 @@ public enum GameDisplay private int _gameId; // Unique identifying id for this gamemode (used for statistics) public int getGameId() { return _gameId; } + + private boolean _communityFavorite; + public boolean isCommunityFavoriteOption() { return _communityFavorite; } - GameDisplay(String name, Material mat, byte data, GameCategory gameCategory, int gameId) + GameDisplay(String name, Material mat, byte data, GameCategory gameCategory, int gameId, boolean communityFavorite) { - this(name, name, mat, data, gameCategory, gameId); + this(name, name, mat, data, gameCategory, gameId, communityFavorite); } - GameDisplay(String name, String lobbyName, Material mat, byte data, GameCategory gameCategory, int gameId) + GameDisplay(String name, String lobbyName, Material mat, byte data, GameCategory gameCategory, int gameId, boolean communityFavorite) { _name = name; _lobbyName = lobbyName; @@ -123,6 +126,7 @@ public enum GameDisplay _data = data; _gameCategory = gameCategory; _gameId = gameId; + _communityFavorite = communityFavorite; } public String getName() diff --git a/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/Effect.java b/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/Effect.java index 5ddda6a72..f72a32fbf 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/Effect.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/Effect.java @@ -4,6 +4,7 @@ import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; import mineplex.core.common.util.Callback; +import mineplex.core.particleeffects.events.EffectStopEvent; public abstract class Effect { @@ -50,6 +51,8 @@ public abstract class Effect { _running = false; Bukkit.getScheduler().cancelTask(_task); + EffectStopEvent effectStopEvent = new EffectStopEvent(this); + Bukkit.getPluginManager().callEvent(effectStopEvent); if (_callback != null) _callback.run(this); onStop(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/LineEffect.java b/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/LineEffect.java new file mode 100644 index 000000000..8698761dd --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/LineEffect.java @@ -0,0 +1,51 @@ +package mineplex.core.particleeffects; + +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.util.Vector; + +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.particles.ColoredParticle; +import mineplex.core.common.util.particles.DustSpellColor; + +public class LineEffect extends Effect +{ + + private int _particles = 100; + private Color _color; + private int _count = 0; + private Vector _vector; + private Location _fixedLoc; + + public LineEffect(JavaPlugin plugin, Location location, Location target, Color color) + { + super(-1, new EffectLocation(location), plugin); + setTargetLocation(new EffectLocation(target)); + _color = color; + } + + @Override + public void runEffect() + { + Location location = _effectLocation.getFixedLocation().clone().add(0, 1, 0); + if (_vector == null) + { + Location targetLoc = getTargetLocation().getFixedLocation().clone(); + Vector link = targetLoc.toVector().subtract(location.toVector()); + float length = (float) link.length(); + link.normalize(); + Vector vector = link.multiply(length / _particles); + _vector = vector; + _fixedLoc = location.clone().subtract(_vector); + } + ColoredParticle coloredParticle = new ColoredParticle(UtilParticle.ParticleType.RED_DUST, + new DustSpellColor(_color), _effectLocation.getLocation().clone()); + _fixedLoc.add(_vector); + if (_count == _particles) + { + stop(); + } + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/personalServer/PersonalServerManager.java b/Plugins/Mineplex.Core/src/mineplex/core/personalServer/PersonalServerManager.java index 24b4eb9e5..976814e4d 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/personalServer/PersonalServerManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/personalServer/PersonalServerManager.java @@ -20,6 +20,7 @@ import mineplex.core.common.util.C; import mineplex.core.common.util.F; import mineplex.core.common.util.UtilMath; import mineplex.core.common.util.UtilPlayer; +import mineplex.core.communities.Community; import mineplex.core.itemstack.ItemStackFactory; import mineplex.core.recharge.Recharge; import mineplex.serverdata.Region; @@ -36,6 +37,7 @@ public class PersonalServerManager extends MiniPlugin private int _interfaceSlot = 6; private ItemStack _interfaceItem; + private boolean _useInterfaceItem = true; private boolean _giveInterfaceItem = true; public PersonalServerManager(JavaPlugin plugin, CoreClientManager clientManager) @@ -65,6 +67,10 @@ public class PersonalServerManager extends MiniPlugin @EventHandler public void openServer(PlayerInteractEvent event) { + if (!_useInterfaceItem) + { + return; + } if (_interfaceItem.equals(event.getPlayer().getItemInHand())) { if (!Recharge.Instance.use(event.getPlayer(), "Host Server Melon", 30000, false, false)) @@ -124,7 +130,7 @@ public class PersonalServerManager extends MiniPlugin Rank rank = _clientManager.Get(player).GetRank(); - if (eventServer || rank.has(Rank.SNR_MODERATOR) || rank == Rank.YOUTUBE || rank == Rank.TWITCH) + if (rank.has(Rank.SNR_MODERATOR) || rank == Rank.YOUTUBE || rank == Rank.TWITCH) { ram = 2048; cpu = 4; @@ -140,6 +146,34 @@ public class PersonalServerManager extends MiniPlugin createGroup(player, serverName, ram, cpu, 40, 80, "Smash", eventServer); } + public void hostCommunityServer(Player host, Community community) + { + int ram = 2048; + int cpu = 4; + + runAsync(() -> + { + for (ServerGroup existingServerGroup : _repository.getServerGroups(null)) + { + if (existingServerGroup.getPrefix().equalsIgnoreCase("COM-" + community.getName()) || existingServerGroup.getName().equalsIgnoreCase("COM-" + community.getId())) + { + host.sendMessage(F.main(getName(), "Your server is still being created or already exists. If you have just started it up, wait 20 seconds and type /server COM-" + community.getName() + "-1.")); + return; + } + } + + final ServerGroup serverGroup = new ServerGroup("COM-" + community.getId(), "COM-" + community.getName(), "COM-" + community.getId(), ram, cpu, 1, 0, UtilMath.random.nextInt(250) + 19999, "", true, "Lobby_MCS.zip", "Arcade.jar", "plugins/Arcade/", 15, 20, + true, false, false, community.getFavoriteGame().name(), "", "", "Community", true, false, false, true, false, false, true, false, false, false, false, true, true, true, false, false, "", _us ? Region.US : Region.EU, "", "", "", ""); + + _repository.updateServerGroup(serverGroup); + runSync(() -> + { + host.sendMessage(F.main(getName(), "COM-" + community.getName() + "-1 successfully created. You will be able to join it shortly.")); + host.sendMessage(F.main(getName(), "In around 10 seconds, type /server COM-" + community.getName() + "-1.")); + }); + }); + } + private void createGroup(final Player host, final String serverName, final int ram, final int cpu, final int minPlayers, final int maxPlayers, final String games, final boolean event) { getPlugin().getServer().getScheduler().runTaskAsynchronously(getPlugin(), new Runnable() @@ -185,4 +219,9 @@ public class PersonalServerManager extends MiniPlugin { return _clientManager; } + + public void setUseInterfaceItem(boolean use) + { + _useInterfaceItem = use; + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/preferences/Preference.java b/Plugins/Mineplex.Core/src/mineplex/core/preferences/Preference.java index 9f420e218..aef708f46 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/preferences/Preference.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/preferences/Preference.java @@ -32,8 +32,8 @@ public enum Preference SHOW_USER_REPORTS(false, PreferenceCategory.EXCLUSIVE, Material.BOOK, "User Reports"), IGNORE_VELOCITY(false, PreferenceCategory.EXCLUSIVE, Material.SADDLE, "Hub Ignore Velocity"), - PENDING_FRIEND_REQUESTS(true, PreferenceCategory.FRIEND, Material.RED_ROSE, "Show Pending Friend Requests"), - FRIENDS_DISPLAY_INVENTORY_UI(true, PreferenceCategory.FRIEND, Material.CHEST, "Display Friend GUI"), + PENDING_FRIEND_REQUESTS(true, PreferenceCategory.SOCIAL, Material.RED_ROSE, "Show Pending Friend Requests"), + FRIENDS_DISPLAY_INVENTORY_UI(true, PreferenceCategory.SOCIAL, Material.CHEST, "Display Friend GUI"), CLAN_TIPS(true, PreferenceCategory.MISC, Material.IRON_SWORD, "Show Clan Tips"), HUB_MUSIC(true, PreferenceCategory.MISC, Material.NOTE_BLOCK, "Hub Music"), @@ -41,6 +41,8 @@ public enum Preference AUTO_JOIN_NEXT_GAME(true, PreferenceCategory.GAME_PLAY, Material.DIAMOND_SWORD, "Auto Join Next Game", "Feel like playing again?", "Enable this, and when you're out", "a 15 second timer will start", "when it ends, it'll send you", "to another game!"), DISABLE_WARNING(true, PreferenceCategory.GAME_PLAY, Material.BARRIER, "Disable Automatic Warning", "Know what you're doing?", "Disable this to not receive", "a message warning you about Auto-Join"), COUNTDOWN_ON_CLICK(false, PreferenceCategory.GAME_PLAY, Material.WATCH, "Countdown to Join", "See that fancy text when you're out?", "If you click it, and this is enabled", "a 15 second time will countdown", "until you are sent to a new game"), + + COMMUNITY_INVITES(true, PreferenceCategory.SOCIAL, Material.BOOK, "Show Community Invites"), ; private static final Map PREFERENCE_MAP = Maps.newHashMap(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/preferences/PreferenceCategory.java b/Plugins/Mineplex.Core/src/mineplex/core/preferences/PreferenceCategory.java index 7e99cd29e..1f870bd4e 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/preferences/PreferenceCategory.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/preferences/PreferenceCategory.java @@ -15,7 +15,7 @@ public enum PreferenceCategory EXCLUSIVE("Exclusive", Material.DIAMOND), GAME_PLAY("Game Mechanic", Material.REDSTONE_COMPARATOR), MISC("Miscellaneous", Material.COMPASS), - FRIEND("Friend", Material.CHEST), + SOCIAL("Social", Material.RED_ROSE), ; private String _name; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/preferences/ui/ExclusivePreferencesPage.java b/Plugins/Mineplex.Core/src/mineplex/core/preferences/ui/ExclusivePreferencesPage.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/Plugins/Mineplex.Core/src/mineplex/core/punish/Punish.java b/Plugins/Mineplex.Core/src/mineplex/core/punish/Punish.java index 8c5125364..560cd293d 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/punish/Punish.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/punish/Punish.java @@ -1,7 +1,7 @@ package mineplex.core.punish; import java.util.HashMap; -import java.util.UUID; +import java.util.function.Consumer; import java.util.logging.Level; import mineplex.core.account.CoreClient; @@ -170,6 +170,11 @@ public class Punish extends MiniPlugin } public void AddPunishment(String playerName, final Category category, final String reason, String callerName, final int severity, boolean ban, long duration, final boolean silent) + { + AddPunishment(playerName, category, reason, callerName, severity, ban, duration, silent, null); + } + + public void AddPunishment(String playerName, final Category category, final String reason, String callerName, final int severity, boolean ban, long duration, final boolean silent, Consumer callback) { Player player = Bukkit.getPlayerExact(playerName); if (player != null) @@ -257,8 +262,8 @@ public class Punish extends MiniPlugin if (player != null) player.kickPlayer(kickReason); - else - new mineplex.serverdata.commands.PunishCommand(finalPlayerName, true, false, kickReason).publish(); + + new mineplex.serverdata.commands.PunishCommand(finalPlayerName, true, false, kickReason).publish(); } }); @@ -284,8 +289,8 @@ public class Punish extends MiniPlugin UtilPlayer.message(player, F.main("Punish", F.elem(C.cGray + C.Bold + "Reason: ") + reason)); player.playSound(player.getLocation(), Sound.CAT_MEOW, 1f, 1f); } - else - new mineplex.serverdata.commands.PunishCommand(finalPlayerName, false, finalDuration != 0, F.main("Punish", F.elem(C.cGray + C.Bold + "Report Ban Reason: ") + reason)).publish(); + + new mineplex.serverdata.commands.PunishCommand(finalPlayerName, false, finalDuration != 0, F.main("Punish", F.elem(C.cGray + C.Bold + "Report Ban Reason: ") + reason)).publish(); _repository.LoadPunishClient(finalPlayerName, new Callback() { @@ -323,8 +328,8 @@ public class Punish extends MiniPlugin UtilPlayer.message(player, F.main("Punish", F.elem(C.cGray + C.Bold + "Reason: ") + reason)); player.playSound(player.getLocation(), Sound.CAT_MEOW, 1f, 1f); } - else - new mineplex.serverdata.commands.PunishCommand(finalPlayerName, false, finalDuration != 0, F.main("Punish", F.elem(C.cGray + C.Bold + (finalDuration != 0 ? "Mute" : "Warning") + " Reason: ") + reason)).publish(); + + new mineplex.serverdata.commands.PunishCommand(finalPlayerName, false, finalDuration != 0, F.main("Punish", F.elem(C.cGray + C.Bold + (finalDuration != 0 ? "Mute" : "Warning") + " Reason: ") + reason)).publish(); _repository.LoadPunishClient(finalPlayerName, new Callback() { @@ -335,6 +340,10 @@ public class Punish extends MiniPlugin }); } } + if (callback != null) + { + callback.accept(banResult); + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/punish/UI/PunishPage.java b/Plugins/Mineplex.Core/src/mineplex/core/punish/UI/PunishPage.java index 32dff3486..afd83db92 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/punish/UI/PunishPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/punish/UI/PunishPage.java @@ -270,15 +270,6 @@ public class PunishPage extends CraftInventoryCustom implements Listener int flightSeverity = 2; - try - { - if (Managers.get(AntiHack.class).isStrict()) - { - flightSeverity = 3; - } - } - catch (Exception e) {} - AddButton(41, new ShopItem(Material.INK_SACK, (byte)1, "Severity 3",new String[] { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardManager.java b/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardManager.java index 66cae6122..75b658660 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardManager.java @@ -388,8 +388,7 @@ public class RewardManager addMineStrikeSkin(Type.NORMAL, MineStrikeSkin.Steyr_AUG_Torque, rarity, 30); addMineStrikeSkin(Type.NORMAL, MineStrikeSkin.XM1014_Tranquility, rarity, 30); - - + // VALENTINES //Hats addHat(Type.VALENTINES_GIFT, HatType.COMPANION_BLOCK, rarity, 100, 0); @@ -905,9 +904,7 @@ public class RewardManager public Reward[] getRewards(Player player, RewardPool.Type pool, RewardType type) { - int amount = 4; - if(type == RewardType.ILLUMINATED_CHEST || type == RewardType.FREEDOM_CHEST || type == RewardType.OMEGA_CHEST - || type == RewardType.HAUNTED_CHEST || type == RewardType.GINGERBREAD_CHEST) amount = 1; + int amount = pool.getChestAmount(); int currentReward = 0; Reward[] rewards = new Reward[amount]; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardPool.java b/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardPool.java index 904a27659..61306a0b7 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardPool.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardPool.java @@ -53,29 +53,42 @@ public class RewardPool NORMAL(true), WINTER_HOLIDAY(true), VALENTINES_GIFT(false), - ILLUMINATED(false), - FREEDOM(false), - OMEGA(false), - HAUNTED(false), + ILLUMINATED(false, 1), + FREEDOM(false, 1), + OMEGA(false, 1), + HAUNTED(false, 1), TRICK_OR_TREAT(false), INFUSED_CHESTS(false), INFUSED_GADGETS(true), MYTHICAL(true), THANKFUL(false), - GINGERBREAD(false), + GINGERBREAD(false, 1), + MINESTRIKE(false, 1), CARL_SPINNER(true); private boolean _useDuplicates; + private int _chestAmount; + + Type(boolean useDuplicates, int amount) + { + _useDuplicates = useDuplicates; + _chestAmount = amount; + } Type(boolean useDuplicates) { - _useDuplicates = useDuplicates; + this(useDuplicates, 4); } public boolean getUseDuplicates() { return _useDuplicates; } + + public int getChestAmount() + { + return _chestAmount; + } public boolean canGive(Player player, Reward reward) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardType.java b/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardType.java index c30336f2b..8c0ed40a0 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardType.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/reward/RewardType.java @@ -18,6 +18,7 @@ public enum RewardType TRICK_OR_TREAT_CHEST(0.1, 2, 16, 0), THANKFUL_CHEST( 0.1, 2, 16, 0), GINGERBREAD_CHEST( 0, 2, 16, 0), + MINESTRIKE_CHEST( 0, 2, 16, 0), VALENTINES_GIFT( 0, 7, 20, 20), SPINNER_FILLER( 0.1, 1, 4, 20), diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureStyle.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureStyle.java index c32d1e8da..3fd0114c9 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureStyle.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureStyle.java @@ -76,6 +76,13 @@ public enum TreasureStyle ParticleType.SNOW_SHOVEL, Sound.DIG_SNOW, Sound.DIG_SNOW + ), + MINESTRIKE( + ParticleType.FIREWORKS_SPARK, + ParticleType.FIREWORKS_SPARK, + ParticleType.FIREWORKS_SPARK, + Sound.EXPLODE, + Sound.EXPLODE ); private ParticleType _secondaryParticle; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureType.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureType.java index aca216b22..ee63ac714 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureType.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureType.java @@ -28,7 +28,9 @@ public enum TreasureType THANKFUL(C.cGold + "Thankful Treasure", "Thankful Chest", "ThankFul", RewardType.THANKFUL_CHEST, Material.CHEST, TreasureStyle.THANKFUL, RewardPool.Type.THANKFUL, true, 20000), - GINGERBREAD(C.cRed + "Gingerbread " + C.cGreen + "Treasure", "Gingerbread Chest", "Gingerbread", RewardType.GINGERBREAD_CHEST, Material.CHEST, TreasureStyle.GINGERBREAD, RewardPool.Type.GINGERBREAD, true, 20000); + GINGERBREAD(C.cRed + "Gingerbread " + C.cGreen + "Treasure", "Gingerbread Chest", "Gingerbread", RewardType.GINGERBREAD_CHEST, Material.CHEST, TreasureStyle.GINGERBREAD, RewardPool.Type.GINGERBREAD, true, 20000), + + MINESTRIKE(C.cGold + "Minestrike Treasure", "Minestrike Chest", "MinestrikeChest", RewardType.MINESTRIKE_CHEST, Material.CHEST, TreasureStyle.MINESTRIKE, RewardPool.Type.MINESTRIKE, true, 20000); private final String _name; private final RewardType _rewardType; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePage.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePage.java index 77d190c5a..ea864c012 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePage.java @@ -28,23 +28,36 @@ import mineplex.core.gadget.gadgets.particle.freedom.ParticleFreedom; import mineplex.core.gadget.types.Gadget; import mineplex.core.gadget.types.GadgetType; import mineplex.core.inventory.InventoryManager; +import mineplex.core.itemstack.ItemStackFactory; import mineplex.core.mount.Mount; import mineplex.core.shop.item.ShopItem; import mineplex.core.shop.page.ShopPageBase; import mineplex.core.treasure.TreasureLocation; import mineplex.core.treasure.TreasureManager; import mineplex.core.treasure.TreasureType; +import mineplex.core.treasure.gui.pages.NextPageButton; +import mineplex.core.treasure.gui.pages.PreviousPageButton; public class TreasurePage extends ShopPageBase { + + private TreasureManager _treasureManager; + private TreasureShop _treasureShop; private TreasureLocation _treasureLocation; private InventoryManager _inventoryManager; private GadgetManager _gadgetManager; + private int _actualPage = 1; + + private List _specialTreasures = new ArrayList<>(); + private List _normalTreasures = new ArrayList<>(); + private List _seasonalTreasures = new ArrayList<>(); public TreasurePage(TreasureManager plugin, TreasureShop shop, TreasureLocation treasureLocation, CoreClientManager clientManager, DonationManager donationManager, InventoryManager inventoryManager, GadgetManager gadgetManager, Player player) { - super(plugin, shop, clientManager, donationManager, "Open Treasure", player, 54); + super(plugin, shop, clientManager, donationManager, "Open Treasure - Page 1", player, 54); + _treasureManager = plugin; + _treasureShop = shop; _treasureLocation = treasureLocation; _inventoryManager = inventoryManager; _gadgetManager = gadgetManager; @@ -52,8 +65,62 @@ public class TreasurePage extends ShopPageBase buildPage(); } + public TreasurePage(TreasureManager plugin, TreasureShop shop, TreasureLocation treasureLocation, CoreClientManager clientManager, DonationManager donationManager, InventoryManager inventoryManager, GadgetManager gadgetManager, Player player, int actualPage) + { + super(plugin, shop, clientManager, donationManager, "Open Treasure - Page " + actualPage, player, 54); + + _treasureManager = plugin; + _treasureShop = shop; + _treasureLocation = treasureLocation; + _inventoryManager = inventoryManager; + _gadgetManager = gadgetManager; + _actualPage = actualPage; + + buildPage(); + } + + public TreasureManager getTreasureManager() + { + return _treasureManager; + } + + public TreasureShop getTreasureShop() + { + return _treasureShop; + } + + public TreasureLocation getTreasureLocation() + { + return _treasureLocation; + } + + public InventoryManager getInventoryManager() + { + return _inventoryManager; + } + + public GadgetManager getGadgetManager() + { + return _gadgetManager; + } + + public int getActualPage() + { + return _actualPage; + } + @Override - protected void buildPage() + public void buildPage() + { + addAllChests(); + + if (_actualPage == 1) + buildFirstPage(); + else + buildSecondPage(); + } + + private void addAllChests() { int treasureShards = getDonationManager().Get(getPlayer()).getBalance(GlobalCurrency.TREASURE_SHARD); @@ -68,6 +135,7 @@ public class TreasurePage extends ShopPageBase int trickCount = _inventoryManager.Get(getPlayer()).getItemCount(TreasureType.TRICK_OR_TREAT.getItemName()); int thankCount = _inventoryManager.Get(getPlayer()).getItemCount(TreasureType.THANKFUL.getItemName()); int gingerbreadCount = _inventoryManager.Get(getPlayer()).getItemCount(TreasureType.GINGERBREAD.getItemName()); + int minestrikeCount = _inventoryManager.Get(getPlayer()).getItemCount(TreasureType.MINESTRIKE.getItemName()); List shardLore = new ArrayList<>(); shardLore.add(" "); @@ -86,7 +154,7 @@ public class TreasurePage extends ShopPageBase basicLore.add(C.cGray + "many kinds of loot."); basicLore.add(" "); if (basicCount > 0) - basicLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + basicLore.add(C.cGreen + "Click to Open!"); else { basicLore.add(ChatColor.RESET + "Click to craft for " + C.cAqua + "1000 Treasure Shards"); @@ -103,7 +171,7 @@ public class TreasurePage extends ShopPageBase heroicLore.add(C.cGray + "temples hidden in Minecrafts worlds."); heroicLore.add(" "); if (heroicCount > 0) - heroicLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + heroicLore.add(C.cGreen + "Click to Open!"); else { heroicLore.add(ChatColor.RESET + "Click to craft for " + C.cAqua + "5000 Treasure Shards"); @@ -123,7 +191,7 @@ public class TreasurePage extends ShopPageBase legendaryLore.add(C.cGray + "location of these chests on their own."); legendaryLore.add(" "); if (legendaryCount > 0) - legendaryLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + legendaryLore.add(C.cGreen + "Click to Open!"); else { legendaryLore.add(ChatColor.RESET + "Click to craft for " + C.cAqua + "10000 Treasure Shards"); @@ -142,15 +210,10 @@ public class TreasurePage extends ShopPageBase christmasLore.add(C.cGray + "accessed in the deepest parts of Winter..."); christmasLore.add(" "); if (christmasCount > 0) - christmasLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + christmasLore.add(C.cGreen + "Click to Open!"); else { christmasLore.add(C.cRed + "This item is no longer available!"); - /* - christmasLore.add(ChatColor.RESET + "Click to craft for " + C.cAqua + "15000 Treasure Shards"); - christmasLore.add(" "); - christmasLore.add(ChatColor.RESET + "or Purchase at: " + C.cYellow + "www.mineplex.com/shop"); - */ } List illuminatedLore = new ArrayList(); @@ -162,7 +225,7 @@ public class TreasurePage extends ShopPageBase illuminatedLore.add(C.cGray + "treasure from the darkness."); illuminatedLore.add(" "); if (illuminatedCount > 0) - illuminatedLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + illuminatedLore.add(C.cGreen + "Click to Open!"); else { illuminatedLore.add(ChatColor.RESET + "Click to craft for " + C.cAqua + "20000 Treasure Shards"); @@ -179,7 +242,7 @@ public class TreasurePage extends ShopPageBase freedomLore.add(C.cGray + "of the apple tree he cut down..."); freedomLore.add(" "); if (freedomCount > 0 && !hasAllFreedomItems(getPlayer())) - freedomLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + freedomLore.add(C.cGreen + "Click to Open!"); else { freedomLore.add(C.cRed + "This item is no longer available!"); @@ -196,7 +259,7 @@ public class TreasurePage extends ShopPageBase omegaLore.add(C.cGray + "loot that has been lost..."); omegaLore.add(" "); if (omegaCount > 0) - omegaLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + omegaLore.add(C.cGreen + "Click to Open!"); else { @@ -212,13 +275,13 @@ public class TreasurePage extends ShopPageBase hauntedLore.add(" "); if (hauntedCount > 0 && !hasAllHauntedItems(getPlayer())) { - hauntedLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + hauntedLore.add(C.cGreen + "Click to Open!"); } else { hauntedLore.add(C.cRed + "This item is no longer available!"); } - + List trickLore = Lists.newArrayList(); trickLore.add(" "); trickLore.add(F.value("Trick or Treat Chests Owned", "" + trickCount)); @@ -229,7 +292,7 @@ public class TreasurePage extends ShopPageBase trickLore.add(" "); if (trickCount > 0) { - trickLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + trickLore.add(C.cGreen + "Click to Open!"); } else { @@ -245,7 +308,7 @@ public class TreasurePage extends ShopPageBase trickLore.add(ChatColor.RESET + "or Purchase at: " + C.cYellow + "www.mineplex.com/shop"); } } - + List thankLore = Lists.newArrayList(); thankLore.add(" "); thankLore.add(F.value("Thankful Chests Owned", "" + thankCount)); @@ -256,7 +319,7 @@ public class TreasurePage extends ShopPageBase thankLore.add(" "); if (thankCount > 0) { - thankLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + thankLore.add(C.cGreen + "Click to Open!"); } else { @@ -278,13 +341,13 @@ public class TreasurePage extends ShopPageBase gingerbreadLore.add(F.value("Gingerbread Chests Owned", "" + gingerbreadCount)); gingerbreadLore.add(" "); gingerbreadLore.addAll(UtilText.splitLine(C.cGray + "The legendary burglar, " + - "the Gingerbread Man, has finally been caught! Now, for the first time his loot is available for auction." + - " There are 8 pieces available for to collect and no duplicates can be obtained from this chest!", + "the Gingerbread Man, has finally been caught! Now, for the first time his loot is available for auction." + + " There are 8 pieces available for to collect and no duplicates can be obtained from this chest!", LineFormat.LORE)); gingerbreadLore.add(" "); if (gingerbreadCount > 0) { - gingerbreadLore.add(ChatColor.RESET + C.cGreen + "Click to Open!"); + gingerbreadLore.add(C.cGreen + "Click to Open!"); } else { @@ -293,49 +356,202 @@ public class TreasurePage extends ShopPageBase gingerbreadLore.add(ChatColor.RESET + "or Purchase at: " + C.cYellow + "www.mineplex.com/shop"); } + // Minestrike Chests not being released in this update! + /*List minestrikeLore = Lists.newArrayList(); + minestrikeLore.add(" "); + minestrikeLore.add(F.value("Minestrike Chests Owned", "" + minestrikeCount)); + minestrikeLore.add(" "); + minestrikeLore.addAll(UtilText.splitLine(C.cGray + "Placeholder", LineFormat.LORE)); + minestrikeLore.add(" "); + if (minestrikeCount > 0) + { + minestrikeLore.add(C.cGreen + "Click to Open!"); + } + else + { + minestrikeLore.add(ChatColor.RESET + "Click to craft for " + C.cAqua + "20000 Treasure Shards"); + minestrikeLore.add(" "); + minestrikeLore.add(ChatColor.RESET + "or Purchase at: " + C.cYellow + "www.mineplex.com/shop"); + }*/ + ShopItem shards = new ShopItem(Material.PRISMARINE_SHARD, C.cAqua + C.Bold + treasureShards + " Treasure Shards", shardLore.toArray(new String[0]), 0, false); + + // Normal chests ShopItem basic = new ShopItem(Material.CHEST, C.cGreen + C.Bold + "Old Treasure", basicLore.toArray(new String[0]), 0, false, false); ShopItem heroic = new ShopItem(Material.TRAPPED_CHEST, C.cGold + C.Bold + "Ancient Treasure", heroicLore.toArray(new String[0]), 0, false, false); ShopItem legendary = new ShopItem(Material.ENDER_CHEST, C.cRed + C.Bold + "Mythical Treasure", legendaryLore.toArray(new String[0]), 0, false, false); - ItemStack christmas = SkinData.PRESENT.getSkull(C.cDGreen + C.Bold + "Winter Holiday Treasure", christmasLore); ItemStack illuminated = new ShopItem(Material.SEA_LANTERN, C.cDAqua + C.Bold + "Illuminated Treasure", illuminatedLore.toArray(new String[0]), 0, false, false); - ItemStack freedom = SkinData.FREEDOM_CHEST.getSkull(C.cRedB + "Freedom " + C.cBlueB + "Treasure", freedomLore); ItemStack omega = SkinData.OMEGA_CHEST.getSkull(C.cAquaB + "Omega Treasure", omegaLore); + //ItemStack minestrike = new ShopItem(Material.GLASS, C.cGoldB + "Minestrike Treasure", minestrikeLore.toArray(new String[0]), 0, false, false); + + // Seasonal chests + ItemStack christmas = SkinData.PRESENT.getSkull(C.cDGreen + C.Bold + "Winter Holiday Treasure", christmasLore); + ItemStack freedom = SkinData.FREEDOM_CHEST.getSkull(C.cRedB + "Freedom " + C.cBlueB + "Treasure", freedomLore); ItemStack haunted = SkinData.HAUNTED_CHEST.getSkull(C.cGoldB + "Haunted Treasure", hauntedLore); ItemStack trick = new ShopItem(Material.SKULL_ITEM, C.cGoldB + "Trick or Treat Treasure", trickLore.toArray(new String[0]), 0, false, false); ItemStack thank = new ShopItem(Material.COOKED_CHICKEN, C.cGoldB + "Thankful Treasure", thankLore.toArray(new String[0]), 0, false, false); ItemStack gingerbread = SkinData.GINGERBREAD.getSkull(C.cRedB + "Gingerbread" + C.cGreenB + " Treasure", gingerbreadLore); + // Adds shard item addItem(49, shards); - addChest(10, christmas, TreasureType.CHRISTMAS, christmasCount); - addChest(12, freedom, TreasureType.FREEDOM, freedomCount); - addChest(14, haunted, TreasureType.HAUNTED, hauntedCount); - addChest(16, omega, TreasureType.OMEGA, omegaCount); - addChest(20, trick, TreasureType.TRICK_OR_TREAT, trickCount); - addChest(22, gingerbread, TreasureType.GINGERBREAD, gingerbreadCount); - addChest(24, thank, TreasureType.THANKFUL, thankCount); - addChest(28, basic, TreasureType.OLD, basicCount); - addChest(30, heroic, TreasureType.ANCIENT, heroicCount); - addChest(32, legendary, TreasureType.MYTHICAL, legendaryCount); - addChest(34, illuminated, TreasureType.ILLUMINATED, illuminatedCount); + // Adds chests to lists, to handle them later + + // Normal chests + TreasurePageItem oldTreasureItem = new TreasurePageItem(basic, basicCount, TreasureType.OLD); + TreasurePageItem ancientTreasureItem = new TreasurePageItem(heroic, heroicCount, TreasureType.ANCIENT); + TreasurePageItem mythicalTreasureItem = new TreasurePageItem(legendary, legendaryCount, TreasureType.MYTHICAL); + TreasurePageItem illuminatedTreasureItem = new TreasurePageItem(illuminated, illuminatedCount, TreasureType.ILLUMINATED); + TreasurePageItem omegaTreasureItem = new TreasurePageItem(omega, omegaCount, TreasureType.OMEGA); + //TreasurePageItem minestrikeTreasureItem = new TreasurePageItem(minestrike, minestrikeCount, TreasureType.MINESTRIKE); + + // Seasonal chests + TreasurePageItem winterTreasureItem = new TreasurePageItem(christmas, christmasCount, TreasureType.CHRISTMAS); + TreasurePageItem freedomTreasureItem = new TreasurePageItem(freedom, freedomCount, TreasureType.FREEDOM); + TreasurePageItem hauntedTreasureItem = new TreasurePageItem(haunted, hauntedCount, TreasureType.HAUNTED); + TreasurePageItem trickTreasureItem = new TreasurePageItem(trick, trickCount, TreasureType.TRICK_OR_TREAT); + TreasurePageItem thankTreasureItem = new TreasurePageItem(thank, thankCount, TreasureType.THANKFUL); + TreasurePageItem gingerbreadTreasureItem = new TreasurePageItem(gingerbread, gingerbreadCount, TreasureType.GINGERBREAD); + + _normalTreasures.add(oldTreasureItem); + _normalTreasures.add(ancientTreasureItem); + _normalTreasures.add(mythicalTreasureItem); + _normalTreasures.add(illuminatedTreasureItem); + _normalTreasures.add(omegaTreasureItem); + //_normalTreasures.add(minestrikeTreasureItem); + + _seasonalTreasures.add(winterTreasureItem); + _seasonalTreasures.add(freedomTreasureItem); + _seasonalTreasures.add(hauntedTreasureItem); + _seasonalTreasures.add(trickTreasureItem); + _seasonalTreasures.add(thankTreasureItem); + + _specialTreasures.add(gingerbreadTreasureItem); } - private void addChest(int slot, ItemStack item, TreasureType treasureType, int owned) + private void buildFirstPage() { + int i = 0; + if (_specialTreasures.size() >= 0) + { + int[] specialDisplayPositions = getSpecialDisplayOrder(); + for (TreasurePageItem treasurePageItem : _specialTreasures) + { + addChest(treasurePageItem, specialDisplayPositions[i]); + i++; + } + i = 0; + } + + int[] normalDisplayPositions = getNormalDisplayOrder(); + for (TreasurePageItem treasurePageItem : _normalTreasures) + { + addChest(treasurePageItem, normalDisplayPositions[i]); + i++; + } + + ItemStack nextPage = ItemStackFactory.Instance.CreateStack(Material.ARROW, (byte) 0, 1, C.cGreen + "Next Page"); + NextPageButton nextPageButton = new NextPageButton(this, _player); + addButton(53, nextPage, nextPageButton); + } + + private void buildSecondPage() + { + int i = 0; + int[] seasonalDisplayPositions = getSeasonalDisplayOrder(); + for (TreasurePageItem treasurePageItem : _seasonalTreasures) + { + addChest(treasurePageItem, seasonalDisplayPositions[i]); + i++; + } + + ItemStack previousPage = ItemStackFactory.Instance.CreateStack(Material.ARROW, (byte) 0, 1, C.cGreen + "Previous Page"); + PreviousPageButton previousPageButton = new PreviousPageButton(this, _player); + addButton(45, previousPage, previousPageButton); + } + + private void addChest(TreasurePageItem treasurePageItem, int position) + { + ItemStack item = treasurePageItem.getItem(); + int owned = treasurePageItem.getCount(); + TreasureType treasureType = treasurePageItem.getTreasureType(); + if (owned > 0) { - addButton(slot, item, new OpenTreasureButton(getPlayer(), _treasureLocation, treasureType)); + addButton(position, item, new OpenTreasureButton(getPlayer(), _treasureLocation, treasureType)); } else if (treasureType.isPurchasable()) { - addButton(slot, item, new BuyChestButton(_inventoryManager, this, treasureType.getItemName(), Material.CHEST, treasureType.getPurchasePrice(), treasureType)); - } + addButton(position, item, new BuyChestButton(_inventoryManager, this, treasureType.getItemName(), Material.CHEST, treasureType.getPurchasePrice(), treasureType)); + } else { - setItem(slot, item); + setItem(position, item); } } + private int[] getSpecialDisplayOrder() + { + int specialTreasuresSize = _specialTreasures.size(); + switch (specialTreasuresSize) + { + case 1: + return new int[]{4}; + case 2: + return new int[]{3, 5}; + case 3: + return new int[]{2, 4, 6}; + case 4: + return new int[]{1, 3, 5, 7}; + } + return new int[]{4}; + } + + private int[] getNormalDisplayOrder() + { + int seasonalTreasuresSize = _seasonalTreasures.size(); + switch (seasonalTreasuresSize) + { + case 5: + return new int[]{20, 22, 24, 39, 41}; + case 6: + return new int[]{19, 21, 23, 25, 38, 42}; + case 7: + return new int[]{19, 21, 23, 25, 38, 40, 42}; + case 8: + return new int[]{19, 21, 23, 25, 37, 39, 41, 43}; + case 9: + return new int[]{19, 21, 23, 25, 31, 37, 39, 41, 43}; + case 10: + return new int[]{19, 21, 23, 25, 29, 33, 37, 39, 41, 43}; + case 11: + return new int[]{19, 21, 23, 25, 29, 31, 33, 37, 39, 32, 43}; + } + return new int[]{20, 22, 24, 39, 41}; + } + + private int[] getSeasonalDisplayOrder() + { + int seasonalTreasuresSize = _seasonalTreasures.size(); + switch (seasonalTreasuresSize) + { + case 5: + return new int[]{11, 13, 15, 30, 32}; + case 6: + return new int[]{10, 12, 14, 16, 29, 33}; + case 7: + return new int[]{10, 12, 14, 16, 29, 31, 33}; + case 8: + return new int[]{10, 12, 14, 16, 28, 30, 32, 34}; + case 9: + return new int[]{10, 12, 14, 16, 22, 28, 30, 32, 34}; + case 10: + return new int[]{10, 12, 14, 16, 20, 24, 28, 30, 32, 34}; + case 11: + return new int[]{10, 12, 14, 16, 20, 22, 24, 28, 30, 32, 34}; + } + return new int[]{11, 13, 15, 30, 32}; + } + public boolean hasAllFreedomItems(Player player) { return !getPlugin().hasItemsToGivePlayer(TreasureType.FREEDOM.getRewardPool(), player); @@ -378,4 +594,5 @@ public class TreasurePage extends ShopPageBase } return amount; } + } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePageItem.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePageItem.java new file mode 100644 index 000000000..dded3fa99 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePageItem.java @@ -0,0 +1,35 @@ +package mineplex.core.treasure.gui; + +import org.bukkit.inventory.ItemStack; + +import mineplex.core.treasure.TreasureType; + +public class TreasurePageItem +{ + + private final ItemStack _item; + private final int _count; + private final TreasureType _treasureType; + + public TreasurePageItem(ItemStack item, int count, TreasureType treasureType) + { + _item = item; + _count = count; + _treasureType = treasureType; + } + + public ItemStack getItem() + { + return _item; + } + + public int getCount() + { + return _count; + } + + public TreasureType getTreasureType() + { + return _treasureType; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/NextPageButton.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/NextPageButton.java new file mode 100644 index 000000000..c98745293 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/NextPageButton.java @@ -0,0 +1,32 @@ +package mineplex.core.treasure.gui.pages; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +import mineplex.core.shop.item.IButton; +import mineplex.core.treasure.gui.TreasurePage; + +public class NextPageButton implements IButton +{ + + private TreasurePage _treasurePage; + private Player _player; + + public NextPageButton(TreasurePage treasurePage, Player player) + { + _treasurePage = treasurePage; + _player = player; + } + + @Override + public void onClick(Player player, ClickType clickType) + { + if (_player != player) + return; + player.closeInventory(); + TreasurePage nextPage = new TreasurePage(_treasurePage.getTreasureManager(), _treasurePage.getTreasureShop(), _treasurePage.getTreasureLocation(), + _treasurePage.getClientManager(), _treasurePage.getDonationManager(), _treasurePage.getInventoryManager(), + _treasurePage.getGadgetManager(), _player, _treasurePage.getActualPage() + 1); + _treasurePage.getTreasureShop().openPageForPlayer(player, nextPage); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/PreviousPageButton.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/PreviousPageButton.java new file mode 100644 index 000000000..a34b59963 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/PreviousPageButton.java @@ -0,0 +1,33 @@ +package mineplex.core.treasure.gui.pages; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +import mineplex.core.shop.item.IButton; +import mineplex.core.treasure.gui.TreasurePage; + +public class PreviousPageButton implements IButton +{ + + private TreasurePage _treasurePage; + private Player _player; + + public PreviousPageButton(TreasurePage treasurePage, Player player) + { + _treasurePage = treasurePage; + _player = player; + } + + @Override + public void onClick(Player player, ClickType clickType) + { + if (_player != player) + return; + player.closeInventory(); + TreasurePage previousPage = new TreasurePage(_treasurePage.getTreasureManager(), _treasurePage.getTreasureShop(), _treasurePage.getTreasureLocation(), + _treasurePage.getClientManager(), _treasurePage.getDonationManager(), _treasurePage.getInventoryManager(), + _treasurePage.getGadgetManager(), _player, _treasurePage.getActualPage() - 1); + _treasurePage.getTreasureShop().openPageForPlayer(player, previousPage); + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java index 8c5d79ec0..d865e5d6e 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java @@ -6,7 +6,8 @@ import mineplex.core.TimingsFix; import mineplex.core.account.CoreClientManager; import mineplex.core.achievement.AchievementManager; import mineplex.core.antihack.AntiHack; -import mineplex.core.antihack.AntiHackGuardian; +import mineplex.core.antihack.guardians.AntiHackGuardian; +import mineplex.core.antihack.guardians.GuardianManager; import mineplex.core.blockrestore.BlockRestore; import mineplex.core.chat.Chat; import mineplex.core.chatsnap.SnapshotManager; @@ -139,8 +140,9 @@ public class Clans extends JavaPlugin Creature creature = new Creature(this); AntiHack antiHack = require(AntiHack.class); - antiHack.setKick(false); - Bukkit.getScheduler().runTask(this, antiHack::enableNewAnticheat); + GuardianManager guardianManager = require(GuardianManager.class); + + Bukkit.getScheduler().runTask(this, antiHack::enableAnticheat); new EternalGiveawayManager(this, _clientManager, serverStatusManager); @@ -155,7 +157,7 @@ public class Clans extends JavaPlugin Location spawn = new Location(Bukkit.getWorld("world"), -422, 95, 8); for (int i = 0; i < 10; i++) { - antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); + guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); } } @@ -170,7 +172,7 @@ public class Clans extends JavaPlugin Location spawn = new Location(Bukkit.getWorld("world"), 424, 95, -8); for (int i = 0; i < 10; i++) { - antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); + guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); } } @@ -185,7 +187,7 @@ public class Clans extends JavaPlugin Location spawn = new Location(Bukkit.getWorld("world"), 9, 210, -393); for (int i = 0; i < 10; i++) { - antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); + guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); } } @@ -200,7 +202,7 @@ public class Clans extends JavaPlugin Location spawn = new Location(Bukkit.getWorld("world"), 8, 210, 390); for (int i = 0; i < 10; i++) { - antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); + guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); } } @@ -215,7 +217,7 @@ public class Clans extends JavaPlugin Location spawn = new Location(Bukkit.getWorld("world"), 0, 100, 0); for (int i = 0; i < 40; i++) { - antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); + guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java index 325d63309..3fb75c743 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java @@ -54,6 +54,7 @@ import mineplex.core.common.util.UtilBlock; import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.communities.CommunityManager; import mineplex.core.creature.Creature; import mineplex.core.creature.event.CreatureSpawnCustomEvent; import mineplex.core.disguise.DisguiseManager; @@ -70,6 +71,7 @@ import mineplex.core.menu.MenuManager; import mineplex.core.movement.Movement; import mineplex.core.npc.NpcManager; import mineplex.core.packethandler.PacketHandler; +import mineplex.core.personalServer.PersonalServerManager; import mineplex.core.portal.Portal; import mineplex.core.preferences.PreferencesManager; import mineplex.core.projectile.ProjectileManager; @@ -405,6 +407,9 @@ public class ClansManager extends MiniClientPluginimplements IRelati loadClan(token, false); } _bannerManager.loadBanners(this); + + new PersonalServerManager(plugin, _clientManager).setUseInterfaceItem(false); + new CommunityManager(plugin, _clientManager); Bukkit.getMessenger().registerOutgoingPluginChannel(plugin, "Replay|Restrict"); diff --git a/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/ClansHub.java b/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/ClansHub.java index df1993e94..04cf7bd71 100644 --- a/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/ClansHub.java +++ b/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/ClansHub.java @@ -5,7 +5,8 @@ import mineplex.core.PacketsInteractionFix; import mineplex.core.account.CoreClientManager; import mineplex.core.achievement.AchievementManager; import mineplex.core.antihack.AntiHack; -import mineplex.core.antihack.AntiHackGuardian; +import mineplex.core.antihack.guardians.AntiHackGuardian; +import mineplex.core.antihack.guardians.GuardianManager; import mineplex.core.aprilfools.AprilFoolsManager; import mineplex.core.blockrestore.BlockRestore; import mineplex.core.boosters.BoosterManager; @@ -122,10 +123,11 @@ public class ClansHub extends JavaPlugin Portal portal = new Portal(this, clientManager, serverStatusManager.getCurrentServerName()); AntiHack antiHack = require(AntiHack.class); + GuardianManager guardianManager = require(GuardianManager.class); for (int i = 0; i < 8; i++) { - antiHack.registerGuardian(new AntiHackGuardian(new Location(Bukkit.getWorld("world"), 0, 195, 0), 25, -8, 195, 185, 17, -16)); + guardianManager.registerGuardian(new AntiHackGuardian(new Location(Bukkit.getWorld("world"), 0, 195, 0), 25, -8, 195, 185, 17, -16)); } IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal); diff --git a/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/HubManager.java b/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/HubManager.java index 252bd6bca..8357a531b 100644 --- a/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/HubManager.java +++ b/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/HubManager.java @@ -67,6 +67,7 @@ import mineplex.core.common.util.UtilTextBottom; import mineplex.core.common.util.UtilTextTop; import mineplex.core.common.util.UtilTime; import mineplex.core.common.util.UtilWorld; +import mineplex.core.communities.CommunityManager; import mineplex.core.cosmetic.CosmeticManager; import mineplex.core.customdata.CustomDataManager; import mineplex.core.disguise.DisguiseManager; @@ -93,6 +94,7 @@ import mineplex.core.npc.NpcManager; import mineplex.core.packethandler.PacketHandler; import mineplex.core.party.Party; import mineplex.core.party.PartyManager; +import mineplex.core.personalServer.PersonalServerManager; import mineplex.core.pet.PetManager; import mineplex.core.playerCount.PlayerCountManager; import mineplex.core.playwire.PlayWireManager; @@ -259,6 +261,9 @@ public class HubManager extends MiniPlugin implements IChatMessageFormatter _serverName = _serverName.substring(0, Math.min(16, _serverName.length())); new SalesAnnouncementManager(plugin); + + new PersonalServerManager(plugin, _clientManager).setUseInterfaceItem(false); + new CommunityManager(plugin, _clientManager); } @Override diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java index b474dbe30..cd87eaf8e 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java @@ -10,7 +10,8 @@ import mineplex.core.PacketsInteractionFix; import mineplex.core.account.CoreClientManager; import mineplex.core.achievement.AchievementManager; import mineplex.core.antihack.AntiHack; -import mineplex.core.antihack.AntiHackGuardian; +import mineplex.core.antihack.guardians.AntiHackGuardian; +import mineplex.core.antihack.guardians.GuardianManager; import mineplex.core.aprilfools.AprilFoolsManager; import mineplex.core.blockrestore.BlockRestore; import mineplex.core.boosters.BoosterManager; @@ -148,10 +149,11 @@ public class Hub extends JavaPlugin implements IRelation Portal portal = new Portal(this, clientManager, serverStatusManager.getCurrentServerName()); AntiHack antiHack = require(AntiHack.class); + GuardianManager guardianManager = require(GuardianManager.class); for (int i = 0; i < 8; i++) { - antiHack.registerGuardian(new AntiHackGuardian(new Location(Bukkit.getWorld("world"), 0, 100, 0), 50, -50, 105, 95, 50, -50)); + guardianManager.registerGuardian(new AntiHackGuardian(new Location(Bukkit.getWorld("world"), 0, 100, 0), 50, -50, 105, 95, 50, -50)); } IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal); diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/HubManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/HubManager.java index 38fd80ce8..5b65fd27a 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/HubManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/HubManager.java @@ -58,6 +58,7 @@ import mineplex.core.common.util.UtilMath; import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilTime; +import mineplex.core.communities.CommunityManager; import mineplex.core.cosmetic.CosmeticManager; import mineplex.core.customdata.CustomDataManager; import mineplex.core.disguise.DisguiseManager; @@ -273,6 +274,8 @@ public class HubManager extends MiniClientPlugin implements IChatMess _valentinesManager = new ValentinesManager(plugin, clientManager, donationManager); new SalesAnnouncementManager(plugin); + + new CommunityManager(plugin, _clientManager); ScoreboardManager scoreboardManager = new ScoreboardManager(plugin) { diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/combat/CombatLog.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/combat/CombatLog.java index 879fc3c30..c2f6329e5 100644 --- a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/combat/CombatLog.java +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/combat/CombatLog.java @@ -4,14 +4,14 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilTime; -import mineplex.minecraft.game.core.damage.DamageChange; - import org.bukkit.ChatColor; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilTime; +import mineplex.minecraft.game.core.damage.DamageChange; + public class CombatLog { private LinkedList _damager = new LinkedList(); @@ -34,6 +34,7 @@ public class CombatLog { _expireTime = expireTime; _player = new CombatComponent(player.getName(), player); + _lastCombatEngaged = 0; // Just so taunts can be used before pvp } public LinkedList GetAttackers() diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/data/ServerGroup.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/data/ServerGroup.java index ba3295037..04c2c5118 100644 --- a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/data/ServerGroup.java +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/data/ServerGroup.java @@ -325,7 +325,8 @@ public class ServerGroup String serverName = server.getName(); try { - int serverNum = Integer.parseInt(serverName.split("-")[1]); + String[] nameArgs = serverName.split("-"); + int serverNum = Integer.parseInt(nameArgs[nameArgs.length - 1]); if (serverNum == id) { diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/database/RepositoryBase.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/database/RepositoryBase.java index ec5a2c8de..987904b2c 100644 --- a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/database/RepositoryBase.java +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/database/RepositoryBase.java @@ -75,6 +75,11 @@ public abstract class RepositoryBase return null; } } + + protected int executeUpdate(Connection connection, String query, Column...columns) + { + return executeInsert(connection, query, null, columns); + } /** * Execute a query against the repository. @@ -87,13 +92,12 @@ public abstract class RepositoryBase return executeInsert(query, null, columns); } - protected int executeInsert(String query, ResultSetCallable callable, Column...columns) + protected int executeInsert(Connection connection, String query, ResultSetCallable callable, Column...columns) { int affectedRows = 0; // Automatic resource management for handling/closing objects. try ( - Connection connection = getConnection(); PreparedStatement preparedStatement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS) ) { @@ -121,6 +125,29 @@ public abstract class RepositoryBase return affectedRows; } + protected int executeInsert(String query, ResultSetCallable callable, Column...columns) + { + int affectedRows = 0; + + // Automatic resource management for handling/closing objects. + try ( + Connection connection = getConnection(); + ) + { + affectedRows = executeInsert(connection, query, callable, columns); + } + catch (SQLException exception) + { + exception.printStackTrace(); + } + catch (Exception exception) + { + exception.printStackTrace(); + } + + return affectedRows; + } + protected void executeQuery(PreparedStatement statement, ResultSetCallable callable, Column...columns) { try @@ -148,11 +175,10 @@ public abstract class RepositoryBase } } - protected void executeQuery(String query, ResultSetCallable callable, Column...columns) - { + protected void executeQuery(Connection connection, String query, ResultSetCallable callable, Column...columns) + { // Automatic resource management for handling/closing objects. try ( - Connection connection = getConnection(); PreparedStatement preparedStatement = connection.prepareStatement(query) ) { @@ -167,4 +193,23 @@ public abstract class RepositoryBase exception.printStackTrace(); } } -} + + protected void executeQuery(String query, ResultSetCallable callable, Column...columns) + { + // Automatic resource management for handling/closing objects. + try ( + Connection connection = getConnection(); + ) + { + executeQuery(connection, query, callable, columns); + } + catch (SQLException exception) + { + exception.printStackTrace(); + } + catch (Exception exception) + { + exception.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java index 2bb711a58..086e356f2 100644 --- a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java +++ b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java @@ -211,6 +211,14 @@ public class ServerMonitor System.out.println("Removed MPS : " + groupStatus.getName()); } + if (groupStatus.getServerType().equalsIgnoreCase("Community")) + { + _repository.removeServerGroup(groupStatus); + _serverGroupMap.remove(groupStatus.getName()); + groupStatusIterator.remove(); + + System.out.println("Removed MCS : " + groupStatus.getName()); + } } } @@ -226,7 +234,8 @@ public class ServerMonitor try { MinecraftServer server = serverIterator.next(); - int serverNum = Integer.parseInt(server.getName().split("-")[1]); + String[] nameArgs = server.getName().split("-"); + int serverNum = Integer.parseInt(nameArgs[nameArgs.length - 1]); if (serverMap.containsKey(serverNum)) { diff --git a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerSorter.java b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerSorter.java index 06ea39063..dd97c296d 100644 --- a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerSorter.java +++ b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerSorter.java @@ -9,9 +9,11 @@ public class ServerSorter implements Comparator @Override public int compare(MinecraftServer first, MinecraftServer second) { - if (Integer.parseInt(first.getName().split("-")[1]) < Integer.parseInt(second.getName().split("-")[1])) + String[] args1 = first.getName().split("-"); + String[] args2 = second.getName().split("-"); + if (Integer.parseInt(args1[args1.length - 1]) < Integer.parseInt(args2[args2.length - 1])) return -1; - else if (Integer.parseInt(second.getName().split("-")[1]) < Integer.parseInt(first.getName().split("-")[1])) + else if (Integer.parseInt(args2[args2.length - 1]) < Integer.parseInt(args1[args1.length - 1])) return 1; return 0; diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java index f9cd84940..2e09e5181 100644 --- a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java @@ -162,6 +162,7 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable int trickOrTreatChestsReceived = 0; int thankfulChestsReceived = 0; int gingerbreadChestsReceived = 0; + //int minestrikeChestsReceived = 0; for (CoinTransactionToken transaction : donor.getCoinTransactions()) { @@ -295,6 +296,16 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable } } + /*if (transaction.SalesPackageName.startsWith("Minestrike Chest")) + { + if (transaction.Coins == 0 && transaction.Gems == 0) + { + if (transaction.SalesPackageName.split(" ").length == 3) + minestrikeChestsReceived += Integer.parseInt(transaction.SalesPackageName.split(" ")[2]); + else if (transaction.SalesPackageName.split(" ").length == 2) + minestrikeChestsReceived += 1; + } + }*/ if (transaction.SalesPackageName.startsWith("Valentines Gift")) { if (transaction.Coins == 0 && transaction.Gems == 0) @@ -367,6 +378,7 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable caller.sendMessage(C.cBlue + "Trick or Treat Chests Received: " + C.cYellow + trickOrTreatChestsReceived); caller.sendMessage(C.cBlue + "Thankful Chests Received: " + C.cYellow + thankfulChestsReceived); caller.sendMessage(C.cBlue + "Gingerbread Chests Received: " + C.cYellow + gingerbreadChestsReceived); + //caller.sendMessage(C.cBlue + "Minestrike Chests Received: " + C.cYellow + minestrikeChestsReceived); caller.sendMessage(C.cBlue + "Game Amplifiers Received: " + C.cYellow + boostersReceived); caller.sendMessage(C.cBlue + "Rune Amplifiers (20 min) Received: " + C.cYellow + runeAmplifier20); caller.sendMessage(C.cBlue + "Rune Amplifiers (60 min) Received: " + C.cYellow + runeAmplifier60); diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/SalesPackageManager.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/SalesPackageManager.java index 25bb9dffa..1f26eaad6 100644 --- a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/SalesPackageManager.java +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/SalesPackageManager.java @@ -96,6 +96,7 @@ public class SalesPackageManager extends MiniPlugin AddSalesPackage(new PowerPlayClub(this, true)); AddSalesPackage(new OmegaChest(this)); AddSalesPackage(new HauntedChest(this)); + //AddSalesPackage(new MinestrikeChest(this)); AddSalesPackage(new TrickOrTreatChest(this)); AddSalesPackage(new ThankfulChest(this)); @@ -167,7 +168,7 @@ public class SalesPackageManager extends MiniPlugin coinBuilder = coinBuilder.extra("[").color("gray").extra(salesPackage.getName()).color("green").click("run_command", "/display " + playerName + " " + salesPackage.getName()).extra("] ").color("gray"); } else if (salesPackage instanceof MythicalChest || salesPackage instanceof AncientChest || salesPackage instanceof OldChest || salesPackage instanceof IlluminatedChest || salesPackage instanceof FreedomChest || salesPackage instanceof HauntedChest || salesPackage instanceof TrickOrTreatChest - || salesPackage instanceof GingerbreadChest) + || salesPackage instanceof ThankfulChest || salesPackage instanceof GingerbreadChest /*|| salesPackage instanceof MinestrikeChest*/) { chestBuilder = chestBuilder.extra("[").color("gray").extra(salesPackage.getName()).color("green").click("run_command", "/display " + playerName + " " + salesPackage.getName()).extra("] ").color("gray"); } diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/command/RankCommand.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/command/RankCommand.java index 21fad01ea..d46ae258e 100644 --- a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/command/RankCommand.java +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/command/RankCommand.java @@ -34,7 +34,7 @@ public class RankCommand extends CommandBase final Rank rankEnum = Rank.valueOf(rank); - if (rankEnum == Rank.HERO || rankEnum == Rank.ULTRA || rankEnum == Rank.LEGEND || rankEnum == Rank.TITAN || rankEnum == Rank.ALL) + if (rankEnum == Rank.HERO || rankEnum == Rank.ULTRA || rankEnum == Rank.LEGEND || rankEnum == Rank.TITAN || rankEnum == Rank.ETERNAL || rankEnum == Rank.ALL) { Plugin.getClientManager().SaveRank(playerName, uuid, mineplex.core.common.Rank.valueOf(rank), perm); caller.sendMessage(F.main(Plugin.getName(), playerName + "'s rank has been updated to " + rank + "!")); diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/salespackages/MinestrikeChest.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/salespackages/MinestrikeChest.java new file mode 100644 index 000000000..7f984e12d --- /dev/null +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/salespackages/MinestrikeChest.java @@ -0,0 +1,20 @@ +package mineplex.staffServer.salespackage.salespackages; + +import org.bukkit.entity.Player; + +import mineplex.staffServer.salespackage.SalesPackageManager; + +public class MinestrikeChest extends SalesPackageBase +{ + public MinestrikeChest(SalesPackageManager manager) + { + super(manager, "1 Minestrike Chest"); + } + + public void displayToAgent(Player agent, String playerName) + { + addButton(agent, "/sales item " + playerName + " 1 Item Minestrike Chest", "Give 1 Minestrike Chest."); + agent.sendMessage(" "); + addBackButton(agent, playerName); + } +} \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java index c59a47594..5f8828c95 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java @@ -4,6 +4,7 @@ import mineplex.core.CustomTagFix; import mineplex.core.FoodDupeFix; import mineplex.core.PacketsInteractionFix; import mineplex.core.TimingsFix; +import mineplex.core.antihack.logging.AntihackLogger; import mineplex.core.chatsnap.SnapshotRepository; import mineplex.core.customdata.CustomDataManager; import mineplex.core.chatsnap.SnapshotManager; @@ -65,6 +66,8 @@ import mineplex.core.velocity.VelocityFix; import mineplex.core.visibility.VisibilityManager; import mineplex.minecraft.game.core.combat.CombatManager; import mineplex.minecraft.game.core.damage.DamageManager; + +import nautilus.game.arcade.anticheatmetadata.GameInfoMetadata; import nautilus.game.arcade.game.GameServerConfig; import org.bukkit.Bukkit; @@ -148,8 +151,7 @@ public class Arcade extends JavaPlugin Punish punish = new Punish(this, webServerAddress, _clientManager); - AntiHack antiHack = require(AntiHack.class); - antiHack.setKick(false); + require(AntiHack.class); IgnoreManager ignoreManager = new IgnoreManager(this, _clientManager, preferenceManager, portal); StatsManager statsManager = new StatsManager(this, _clientManager); @@ -185,7 +187,9 @@ public class Arcade extends JavaPlugin //Arcade Manager PollManager pollManager = new PollManager(this, _clientManager, _donationManager); _gameManager = new ArcadeManager(this, serverStatusManager, ReadServerConfig(), _clientManager, _donationManager, _damageManager, statsManager, incognito, achievementManager, disguiseManager, creature, teleport, new Blood(this), chat, portal, preferenceManager, inventoryManager, packetHandler, cosmeticManager, projectileManager, petManager, hologramManager, webServerAddress, pollManager, npcmanager, customDataManager, punish, eloManager, thankManager, boosterManager); - + + require(AntihackLogger.class).registerMetadata(new GameInfoMetadata()); + new GlobalPacketManager(this, _clientManager, serverStatusManager, inventoryManager, _donationManager, petManager, statsManager, _gameManager.getBonusManager().getRewardManager()); //new BroadcastManager(this, _gameManager); diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java index f42ea1e7d..cbc0cd184 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java @@ -4,8 +4,6 @@ import java.io.File; import java.util.ArrayList; import java.util.HashSet; -import net.minecraft.server.v1_8_R3.EntityLiving; - import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.GameMode; @@ -54,6 +52,7 @@ import mineplex.core.common.util.UtilGear; import mineplex.core.common.util.UtilInv; import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilServer; +import mineplex.core.communities.CommunityManager; import mineplex.core.cosmetic.CosmeticManager; import mineplex.core.creature.Creature; import mineplex.core.customdata.CustomDataManager; @@ -83,6 +82,7 @@ import mineplex.core.movement.Movement; import mineplex.core.npc.NpcManager; import mineplex.core.packethandler.PacketHandler; import mineplex.core.party.PartyManager; +import mineplex.core.personalServer.PersonalServerManager; import mineplex.core.pet.PetManager; import mineplex.core.playwire.PlayWireManager; import mineplex.core.poll.PollManager; @@ -120,7 +120,6 @@ import mineplex.minecraft.game.core.condition.ConditionManager; import mineplex.minecraft.game.core.damage.DamageManager; import mineplex.minecraft.game.core.fire.Fire; import mineplex.serverdata.Region; - import nautilus.game.arcade.addons.SoupAddon; import nautilus.game.arcade.addons.TeamArmorAddon; import nautilus.game.arcade.booster.GameBoosterManager; @@ -131,6 +130,7 @@ import nautilus.game.arcade.command.GoToNextGameCommand; import nautilus.game.arcade.command.KitUnlockCommand; import nautilus.game.arcade.command.OpenGameMechPrefsCommand; import nautilus.game.arcade.command.RequiredRankCommand; +import nautilus.game.arcade.command.TauntCommand; import nautilus.game.arcade.command.WriteCommand; import nautilus.game.arcade.events.GameStateChangeEvent; import nautilus.game.arcade.game.Game; @@ -165,7 +165,7 @@ import nautilus.game.arcade.managers.lobby.current.NewGameLobbyManager; import nautilus.game.arcade.managers.lobby.legacy.LegacyGameLobbyManager; import nautilus.game.arcade.player.ArcadePlayer; import nautilus.game.arcade.shop.ArcadeShop; -import static mineplex.core.Managers.require; +import net.minecraft.server.v1_8_R3.EntityLiving; public class ArcadeManager extends MiniPlugin implements IRelation { @@ -388,7 +388,7 @@ public class ArcadeManager extends MiniPlugin implements IRelation _progressionKitManager = new ProgressingKitManager(this); _serverUptimeManager = new ServerUptimeManager(this); - if (GetHost() != null && !GetHost().isEmpty()) + if (GetHost() != null && !GetHost().isEmpty() && !GetHost().startsWith("COM-")) { Bukkit.getScheduler().runTaskLater(plugin, () -> Portal.transferPlayer(GetHost(), _serverStatusManager.getCurrentServerName()), 80L); } @@ -404,6 +404,10 @@ public class ArcadeManager extends MiniPlugin implements IRelation addCommand(new GoToNextGameCommand(this)); addCommand(new OpenGameMechPrefsCommand(this)); addCommand(new CancelNextGameCommand(this)); + addCommand(new TauntCommand(this)); + + new PersonalServerManager(plugin, _clientManager).setUseInterfaceItem(false); + new CommunityManager(plugin, _clientManager); _scoreboardManager = new ScoreboardManager(_plugin) { @@ -916,7 +920,7 @@ public class ArcadeManager extends MiniPlugin implements IRelation return; } - if (!GetServerConfig().PublicServer || GetServerConfig().PlayerServerWhitelist) + if (!GetServerConfig().PublicServer || GetServerConfig().PlayerServerWhitelist || _gameHostManager.isCommunityServer()) { event.setMotd(ChatColor.GRAY + "Private"); return; @@ -1751,8 +1755,7 @@ public class ArcadeManager extends MiniPlugin implements IRelation if (_enabled) { - //enableChampionsModules(); - disableChampionsModules(); + enableChampionsModules(); } else { diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/anticheatmetadata/GameInfoMetadata.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/anticheatmetadata/GameInfoMetadata.java new file mode 100644 index 000000000..8cf07119d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/anticheatmetadata/GameInfoMetadata.java @@ -0,0 +1,207 @@ +package nautilus.game.arcade.anticheatmetadata; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import mineplex.core.antihack.logging.AnticheatMetadata; +import mineplex.core.common.util.UtilServer; + +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game; +import nautilus.game.arcade.kit.Kit; +import nautilus.game.arcade.kit.ProgressingKit; +import nautilus.game.arcade.managers.GameHostManager; +import static mineplex.core.Managers.require; + +public class GameInfoMetadata extends AnticheatMetadata +{ + private static final String KEY_GAME_INFO = "game-info"; + private static final String KEY_GAME_MAP = "map"; + private static final String KEY_GAME_TYPE = "type"; + private static final String KEY_GAME_MODE = "mode"; + private static final String KEY_CURRENT_STATE = "current-state"; + private static final String KEY_STATE_START_TIME = "current-state-start-time"; + private static final String KEY_JOIN_GAME_TIME = "join-game-time-ms"; + + private static final String KEY_STATE_TIMES = "state-times"; + + private static final String KEY_KIT_INFO = "kit-info"; + private static final String KEY_KIT_NAME = "name"; + private static final String KEY_KIT_LEVEL = "level"; + + private static final String KEY_MPS = "mps"; + private static final String KEY_OWNER = "owner"; + + private static final String KEY_STATS = "stats"; + + private static final String KEY_WINNER = "winner"; + + private final Map _allGames = new HashMap<>(); + private final Map _currentGame = new HashMap<>(); + + private final ArcadeManager _arcadeManager = require(ArcadeManager.class); + + @Override + public String getId() + { + return "game-info"; + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) + { + _allGames.put(event.getPlayer().getUniqueId(), new JsonArray()); + + JsonObject currentGame = buildCurrentGame(); + + if (currentGame != null) + { + _currentGame.put(event.getPlayer().getUniqueId(), currentGame); + } + } + + private JsonObject buildCurrentGame() + { + Game game = _arcadeManager.GetGame(); + + if (game == null) + return null; + + JsonObject currentGame = new JsonObject(); + + JsonObject gameInfo = new JsonObject(); + gameInfo.addProperty(KEY_GAME_MAP, game.WorldData.File); + gameInfo.addProperty(KEY_GAME_TYPE, game.GetName()); + gameInfo.addProperty(KEY_GAME_MODE, game.GetMode()); + gameInfo.addProperty(KEY_CURRENT_STATE, game.GetState().name()); + gameInfo.addProperty(KEY_STATE_START_TIME, game.GetStateTime()); + gameInfo.addProperty(KEY_JOIN_GAME_TIME, System.currentTimeMillis()); + + if (_arcadeManager.GetGameHostManager() != null && _arcadeManager.GetGameHostManager().isPrivateServer()) + { + GameHostManager gameHostManager = _arcadeManager.GetGameHostManager(); + + JsonObject mpsInfo = new JsonObject(); + mpsInfo.addProperty(KEY_OWNER, _arcadeManager.GetHost()); + + currentGame.add(KEY_MPS, mpsInfo); + } + + currentGame.add(KEY_GAME_INFO, gameInfo); + + JsonObject stateStartTimes = new JsonObject(); + stateStartTimes.addProperty(game.GetState().name(), game.GetStateTime()); + + currentGame.add(KEY_STATE_TIMES, stateStartTimes); + + return currentGame; + } + + @EventHandler + public void onStateChange(GameStateChangeEvent event) + { + if (event.GetState() == Game.GameState.Recruit) + { + for (Player player : UtilServer.getPlayersCollection()) + { + if (!_currentGame.containsKey(player.getUniqueId())) + { + _currentGame.put(player.getUniqueId(), buildCurrentGame()); + } + } + } + + if (event.GetState() == Game.GameState.Live) + { + _currentGame.forEach((id, obj) -> + { + Player player = Bukkit.getPlayer(id); + if (player != null) + { + Kit kit = event.GetGame().GetKit(player); + if (kit != null) + { + JsonObject kitInfo = new JsonObject(); + kitInfo.addProperty(KEY_KIT_NAME, kit.GetName()); + + if (kit instanceof ProgressingKit) + { + ProgressingKit pk = (ProgressingKit) kit; + kitInfo.addProperty(KEY_KIT_LEVEL, pk.getLevel(player.getUniqueId())); + } + + obj.add(KEY_KIT_INFO, kitInfo); + } + } + }); + + } + + _currentGame.values().forEach(obj -> + { + obj.get(KEY_STATE_TIMES).getAsJsonObject().addProperty(event.GetState().name(), System.currentTimeMillis()); + }); + + if (event.GetState() == Game.GameState.Dead) + { + new ArrayList<>(_currentGame.keySet()).forEach(ent -> archivePlayer(event.GetGame(), ent)); + } + } + + private void archivePlayer(Game game, UUID uuid) + { + JsonObject gameObj = _currentGame.remove(uuid); + + if (gameObj == null) + return; + + _allGames.get(uuid).add(gameObj); + + if (game == null) + return; + + Player player = Bukkit.getPlayer(uuid); + + if (player == null) + return; + + Map stats = game.GetStats().get(player); + + if (stats != null) + { + JsonObject statsObject = new JsonObject(); + stats.forEach(statsObject::addProperty); + + gameObj.add(KEY_STATS, statsObject); + } + + gameObj.addProperty(KEY_WINNER, game.Winner); + } + + @Override + public JsonElement build(UUID player) + { + archivePlayer(_arcadeManager.GetGame(), player); + + return _allGames.get(player); + } + + @Override + public void remove(UUID player) + { + _allGames.remove(player); + _currentGame.remove(player); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/command/TauntCommand.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/command/TauntCommand.java new file mode 100644 index 000000000..50a4b4bf6 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/command/TauntCommand.java @@ -0,0 +1,51 @@ +package nautilus.game.arcade.command; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.gadget.event.TauntCommandEvent; +import mineplex.core.gadget.gadgets.taunts.GameType; +import mineplex.minecraft.game.core.combat.CombatManager; + +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.Game; + +public class TauntCommand extends CommandBase +{ + + private ArcadeManager _arcadeManager; + + public TauntCommand(ArcadeManager manager) + { + super(manager, Rank.ALL, "taunt"); + _arcadeManager = manager; + } + + @Override + public void Execute(Player player, String[] args) + { + boolean pvp = false; + CombatManager combatManager = Managers.get(CombatManager.class); + if (combatManager != null) + { + pvp = UtilTime.elapsed(combatManager.Get(player).GetLastCombatEngaged(), 5000 * 60); + } + Game game = _arcadeManager.GetGame(); + GameType gameType = GameType.NONE; + if (game != null) + { + gameType = GameType.valueOf(game.GetType().toString().toUpperCase()); + } + TauntCommandEvent event = new TauntCommandEvent(player, _arcadeManager.isGameInProgress(), + _arcadeManager.GetGame().IsAlive(player), UtilPlayer.isSpectator(player), combatManager.Get(player).GetLastCombatEngaged(), + gameType); + Bukkit.getPluginManager().callEvent(event); + } + + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java index 94d745ab4..d2864e5e5 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java @@ -82,6 +82,9 @@ import nautilus.game.arcade.events.GameStateChangeEvent; import nautilus.game.arcade.events.PlayerGameRespawnEvent; import nautilus.game.arcade.events.PlayerStateChangeEvent; import nautilus.game.arcade.game.GameTeam.PlayerState; +import nautilus.game.arcade.game.games.build.Build; +import nautilus.game.arcade.game.games.draw.Draw; +import nautilus.game.arcade.game.games.speedbuilders.SpeedBuilders; import nautilus.game.arcade.game.modules.Module; import nautilus.game.arcade.kit.ChampionsKit; import nautilus.game.arcade.kit.Kit; @@ -740,11 +743,14 @@ public abstract class Game implements Listener if (this._gameState == Game.GameState.Prepare) { - Managers.get(AntiHack.class).enableNewAnticheat(); + if (!(this instanceof SpeedBuilders) && !(this instanceof Build) && !(this instanceof Draw)) + { + Managers.get(AntiHack.class).enableAnticheat(); + } } else if (this._gameState == Game.GameState.End) { - Managers.get(AntiHack.class).disableNewAnticheat(); + Managers.get(AntiHack.class).disableAnticheat(); } @@ -1648,6 +1654,11 @@ public abstract class Game implements Listener if (!UtilTime.elapsed(_helpTimer, 8000)) return; + + if (Manager.GetGameHostManager().isCommunityServer()) + { + return; + } if (_helpColor == ChatColor.YELLOW) _helpColor = ChatColor.GOLD; diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/gui/privateServer/page/MenuPage.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/gui/privateServer/page/MenuPage.java index 94f2730d9..c31d8d7cd 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/gui/privateServer/page/MenuPage.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/gui/privateServer/page/MenuPage.java @@ -11,6 +11,7 @@ import org.bukkit.inventory.meta.ItemMeta; import mineplex.core.common.Rank; import mineplex.core.common.util.C; import mineplex.core.common.util.UtilServer; +import mineplex.core.itemstack.ItemBuilder; import mineplex.core.shop.item.ShopItem; import nautilus.game.arcade.ArcadeManager; import nautilus.game.arcade.gui.privateServer.PrivateServerShop; @@ -100,9 +101,12 @@ public class MenuPage extends BasePage GameVotingButton votingButton = new GameVotingButton(getPlugin(), getShop()); addButton(3 + 27, new ShopItem(Material.BOOKSHELF, "Game Voting", new String[]{}, 1, false), votingButton); - - WhitelistButton whitelistButton = new WhitelistButton(getPlugin(), getShop()); - addButton(5 + 27, new ShopItem(Material.PAPER, "Whitelisted Players", new String[]{}, 1, false), whitelistButton); + + if (!_manager.isCommunityServer()) + { + WhitelistButton whitelistButton = new WhitelistButton(getPlugin(), getShop()); + addButton(5 + 27, new ShopItem(Material.PAPER, "Whitelisted Players", new String[]{}, 1, false), whitelistButton); + } } OptionsButton optionsButton = new OptionsButton(getPlugin(), getShop()); @@ -114,6 +118,24 @@ public class MenuPage extends BasePage private ShopItem getOwnerHead() { + if (_manager.isCommunityServer()) + { + String title = C.cGreen + C.Bold + _manager.getOwner().getName() + "'s Mineplex Community Server"; + ItemStack head = new ItemBuilder(new ItemStack(_manager.getOwner().getFavoriteGame().getMaterial(), 1, _manager.getOwner().getFavoriteGame().getMaterialData(), null)).setTitle(ChatColor.RESET + title).build(); + ArrayList lore = new ArrayList(); + lore.add(" "); + lore.add(ChatColor.RESET + C.cYellow + "Server Name: " + C.cWhite + getPlugin().getPlugin().getConfig().getString("serverstatus.name")); + lore.add(ChatColor.RESET + C.cYellow + "Players Online: " + C.cWhite + UtilServer.getPlayers().length); + lore.add(ChatColor.RESET + C.cYellow + "Players Max: " + C.cWhite + getPlugin().GetServerConfig().MaxPlayers); + lore.add(" "); + lore.add(ChatColor.RESET + "Left-Click to increase Max Players"); + lore.add(ChatColor.RESET + "Right-Click to decrease Max Players"); + ItemMeta meta = head.getItemMeta(); + meta.setLore(lore); + head.setItemMeta(meta); + + return new ShopItem(head, title, title, 1, false, false); + } String title = C.cGreen + C.Bold + getPlugin().GetHost() + "'s Mineplex Private Server"; ItemStack head = getPlayerHead(getPlugin().GetHost(), ChatColor.RESET + title); ArrayList lore = new ArrayList(); diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/gui/privateServer/page/OptionsPage.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/gui/privateServer/page/OptionsPage.java index e68206e2f..4ac322c5b 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/gui/privateServer/page/OptionsPage.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/gui/privateServer/page/OptionsPage.java @@ -33,24 +33,30 @@ public class OptionsPage extends BasePage //GameAutoStart //GameTimeout //PlayerKickIdle - - buildPreference(11, Material.EYE_OF_ENDER, "Public Server", _config.PublicServer, new IButton() - { - @Override - public void onClick(Player player, ClickType clickType) - { - togglePublic(); - } - }); - buildPreference(13, Material.PAPER, "Enforce Whitelist", _config.PlayerServerWhitelist, new IButton() + if (!_plugin.GetGameHostManager().isCommunityServer()) { - @Override - public void onClick(Player player, ClickType clickType) + buildPreference(11, Material.EYE_OF_ENDER, "Public Server", _config.PublicServer, new IButton() { - toggleWhitelist(); - } - }); + @Override + public void onClick(Player player, ClickType clickType) + { + togglePublic(); + } + }); + } + + if (!_plugin.GetGameHostManager().isCommunityServer()) + { + buildPreference(13, Material.PAPER, "Enforce Whitelist", _config.PlayerServerWhitelist, new IButton() + { + @Override + public void onClick(Player player, ClickType clickType) + { + toggleWhitelist(); + } + }); + } buildPreference(15, Material.RAILS, "Force Team Balancing", _config.TeamForceBalance, new IButton() { diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameFlagManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameFlagManager.java index a76cf81ab..b9c61fddb 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameFlagManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameFlagManager.java @@ -1230,17 +1230,7 @@ public class GameFlagManager implements Listener } } } - - @EventHandler - public void AntiHackStrict(GameStateChangeEvent event) - { - if (event.GetState() == GameState.Prepare || event.GetState() == GameState.Live) - Managers.get(AntiHack.class).setStrict(event.GetGame().StrictAntiHack); - - else - Managers.get(AntiHack.class).setStrict(true); - } - + @EventHandler public void PlayerKillCommandCancel(PlayerCommandPreprocessEvent event) { diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameHostManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameHostManager.java index 77dfa7d8b..2dd77e929 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameHostManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameHostManager.java @@ -4,25 +4,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import mineplex.core.common.Rank; -import mineplex.core.common.util.C; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilGear; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.common.util.UtilServer; -import mineplex.core.common.util.UtilTextBottom; -import mineplex.core.common.util.UtilTime; -import mineplex.core.game.GameCategory; -import mineplex.core.itemstack.ItemStackFactory; -import mineplex.core.punish.PunishClient; -import mineplex.core.updater.UpdateType; -import mineplex.core.updater.event.UpdateEvent; -import nautilus.game.arcade.ArcadeManager; -import nautilus.game.arcade.GameType; -import nautilus.game.arcade.game.Game.GameState; -import nautilus.game.arcade.gui.privateServer.PrivateServerShop; -import nautilus.game.arcade.gui.privateServer.page.GameVotingPage; - import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.GameMode; @@ -30,7 +11,6 @@ import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; -import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.PlayerCommandPreprocessEvent; @@ -40,6 +20,29 @@ import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.Plugin; +import mineplex.core.Managers; +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilGear; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.common.util.UtilTime; +import mineplex.core.communities.Community; +import mineplex.core.communities.CommunityDisbandEvent; +import mineplex.core.communities.CommunityManager; +import mineplex.core.communities.CommunityRole; +import mineplex.core.game.GameCategory; +import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.GameType; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.gui.privateServer.PrivateServerShop; +import nautilus.game.arcade.gui.privateServer.page.GameVotingPage; + public class GameHostManager implements Listener { private ArrayList ultraGames = new ArrayList(); @@ -49,7 +52,6 @@ public class GameHostManager implements Listener ArcadeManager Manager; private Player _host; - private String _hostName; private Rank _hostRank; private long _serverStartTime = System.currentTimeMillis(); private long _serverExpireTime = 21600000; @@ -174,13 +176,13 @@ public class GameHostManager implements Listener // Admins update for (Player player : UtilServer.getPlayers()) { - if (player.equals(_host) || _adminList.contains(player.getName()) || Manager.GetClients().Get(player).GetRank().has(Rank.ADMIN)) + if (isHost(player) || isAdmin(player, true)) { if (Manager.GetGame() == null || Manager.GetGame().GetState() == GameState.Recruit) giveAdminItem(player); } - if (player.equals(_host) || (isAdmin(player, false) && isEventServer())) + if (isHost(player) || (isAdmin(player, false) && (isEventServer() || isCommunityServer()))) _lastOnline = System.currentTimeMillis(); } } @@ -212,6 +214,15 @@ public class GameHostManager implements Listener public void handleLogin(PlayerLoginEvent event) { Player p = event.getPlayer(); + if (isCommunityServer()) + { + if (getOwner().getMembers().containsKey(p.getUniqueId())) + { + return; + } + event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, "You are not a member of this MCS."); + return; + } if (Manager.GetServerConfig().PlayerServerWhitelist){ if (!getWhitelist().contains(p.getName().toLowerCase())){ if ((Manager.GetHost() != null) && (Manager.GetHost().equalsIgnoreCase(p.getName()))) @@ -222,7 +233,16 @@ public class GameHostManager implements Listener } } if (_blacklist.contains(p.getName())) - event.disallow(PlayerLoginEvent.Result.KICK_BANNED, "You were removed from this Mineplex Private Server."); + { + if (isCommunityServer()) + { + event.disallow(PlayerLoginEvent.Result.KICK_BANNED, "You were removed from this Mineplex Community Server."); + } + else + { + event.disallow(PlayerLoginEvent.Result.KICK_BANNED, "You were removed from this Mineplex Private Server."); + } + } } @EventHandler @@ -309,7 +329,16 @@ public class GameHostManager implements Listener return; if (UtilTime.elapsed(_lastOnline, _expireTime)) - setHostExpired(true, Manager.GetServerConfig().HostName + " has abandoned the server. Thanks for playing!"); + { + if (isCommunityServer()) + { + setHostExpired(true, getOwner().getName() + " has abandoned the server. Thanks for playing!"); + } + else + { + setHostExpired(true, Manager.GetServerConfig().HostName + " has abandoned the server. Thanks for playing!"); + } + } else if (UtilTime.elapsed(_serverStartTime, _serverExpireTime)) setHostExpired(true, "This server has expired! Thank you for playing!"); @@ -501,11 +530,23 @@ public class GameHostManager implements Listener public boolean isAdmin(Player player, boolean includeStaff) { + if (isCommunityServer()) + { + return (getOwner().getMembers().containsKey(player.getUniqueId()) && getOwner().getMembers().get(player.getUniqueId()).Role.ordinal() <= CommunityRole.COLEADER.ordinal()) || (includeStaff && Manager.GetClients().Get(player).GetRank().has(Rank.ADMIN)); + } return player.equals(_host) || _adminList.contains(player.getName()) || (includeStaff && Manager.GetClients().Get(player).GetRank().has(Rank.ADMIN)); } public boolean isHost(Player player) { + if (Manager.GetHost() != null && Manager.GetHost().startsWith("COM-")) + { + CommunityManager cmanager = Managers.get(CommunityManager.class); + int communityId = Integer.parseInt(Manager.GetHost().replace("COM-", "")); + Community c = cmanager.getLoadedCommunity(communityId); + return c.getMembers().containsKey(player.getUniqueId()) && c.getMembers().get(player.getUniqueId()).Role == CommunityRole.LEADER; + } + return player.getName().equals(Manager.GetHost()); } @@ -519,6 +560,8 @@ public class GameHostManager implements Listener { if (_host == null || !event.getPlayer().equals(_host)) return; + if (isCommunityServer()) + return; if (!event.getMessage().toLowerCase().startsWith("/whitelist")) return; @@ -540,67 +583,13 @@ public class GameHostManager implements Listener } } } - - public void setGame(GameType type) - { - if (_host == null) - return; - - Manager.GetGameCreationManager().SetNextGameType(type); - - //End Current - if (Manager.GetGame().GetState() == GameState.Recruit) - { - Manager.GetGame().SetState(GameState.Dead); - - Bukkit.broadcastMessage(C.cGreen + C.Bold + _host.getName() + " has changed game to " + type.GetName() + "."); - } - else - { - Bukkit.broadcastMessage(C.cGreen + C.Bold + _host.getName() + " set next game to " + type.GetName() + "."); - } - } - - public void startGame() - { - if (_host == null) - return; - - Manager.GetGameManager().StateCountdown(Manager.GetGame(), 10, true); - - Manager.GetGame().Announce(C.cGreen + C.Bold + _host.getName() + " has started the game."); - } - - public void stopGame() - { - if (_host == null) - return; - - if (Manager.GetGame() == null) - return; - - HandlerList.unregisterAll(Manager.GetGame()); - - if (Manager.GetGame().GetState() == GameState.End || Manager.GetGame().GetState() == GameState.End) - { - _host.sendMessage("Game is already ending..."); - return; - } - else if (Manager.GetGame().GetState() == GameState.Recruit) - { - Manager.GetGame().SetState(GameState.Dead); - } - else - { - Manager.GetGame().SetState(GameState.End); - } - - - Manager.GetGame().Announce(C.cGreen + C.Bold + _host.getName() + " has stopped the game."); - } public boolean hasRank(Rank rank) { + if (isCommunityServer()) + { + return Rank.ETERNAL.has(rank); + } if (_hostRank == null) return false; @@ -642,8 +631,15 @@ public class GameHostManager implements Listener public void ban(Player player) { _blacklist.add(player.getName()); - - Manager.GetPortal().sendToHub(player, "You were removed from this Mineplex Private Server."); + + if (isCommunityServer()) + { + Manager.GetPortal().sendToHub(player, "You were removed from this Mineplex Community Server."); + } + else + { + Manager.GetPortal().sendToHub(player, "You were removed from this Mineplex Private Server."); + } } @EventHandler @@ -656,7 +652,26 @@ public class GameHostManager implements Listener { if (_blacklist.contains(player.getName())) { - Manager.GetPortal().sendToHub(player, "You were removed from this Mineplex Private Server."); + if (isCommunityServer()) + { + Manager.GetPortal().sendToHub(player, "You were removed from this Mineplex Community Server."); + } + else + { + Manager.GetPortal().sendToHub(player, "You were removed from this Mineplex Private Server."); + } + } + } + } + + @EventHandler + public void onDisband(CommunityDisbandEvent event) + { + if (isCommunityServer()) + { + if (getOwner().getId().intValue() == event.getCommunity().getId().intValue()) + { + setHostExpired(true, getOwner().getName() + " has disbanded and abandoned the server. Thanks for playing!"); } } } @@ -715,6 +730,10 @@ public class GameHostManager implements Listener public int getMaxPlayerCap() { + if (isCommunityServer()) + { + return 20; + } if (hasRank(Rank.SNR_MODERATOR) || _hostRank == Rank.YOUTUBE || _hostRank == Rank.TWITCH) return 100; else if (_hostRank == Rank.YOUTUBE_SMALL || _hostRank == Rank.ETERNAL) @@ -809,10 +828,31 @@ public class GameHostManager implements Listener return; String serverName = Manager.getPlugin().getConfig().getString("serverstatus.name"); - UtilPlayer.message(event.getPlayer(), ChatColor.BOLD + "Welcome to Mineplex Private Servers!"); + if (!isCommunityServer()) + { + UtilPlayer.message(event.getPlayer(), ChatColor.BOLD + "Welcome to Mineplex Private Servers!"); + } + else + { + UtilPlayer.message(event.getPlayer(), ChatColor.BOLD + "Welcome to Mineplex Community Servers!"); + } UtilPlayer.message(event.getPlayer(), C.Bold + "Friends can connect with " + C.cGreen + C.Bold + "/server " + serverName); } + public boolean isCommunityServer() + { + return Manager.GetHost() != null && Manager.GetHost().startsWith("COM-"); + } + + public Community getOwner() + { + if (!isCommunityServer()) + { + return null; + } + return Managers.get(CommunityManager.class).getLoadedCommunity(Integer.parseInt(Manager.GetHost().replace("COM-", ""))); + } + public boolean isEventServer() { return _isEventServer; @@ -856,6 +896,5 @@ public class GameHostManager implements Listener public void setHost(Player player) { _host = player; - } - -} + } +} \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/chat/GameChatManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/chat/GameChatManager.java index f8e887c4e..190e2fca7 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/chat/GameChatManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/chat/GameChatManager.java @@ -96,6 +96,8 @@ public class GameChatManager implements Listener { if (_manager.GetGameHostManager().isEventServer()) rankStr = C.cDGreen + C.Bold + "Event Host " + C.Reset; + else if (_manager.GetGameHostManager().isCommunityServer()) + rankStr = C.cDGreen + C.Bold + "MCS Host " + C.Reset; else rankStr = C.cDGreen + C.Bold + "MPS Host " + C.Reset; } @@ -103,6 +105,8 @@ public class GameChatManager implements Listener { if (_manager.GetGameHostManager().isEventServer()) rankStr = C.cDGreen + C.Bold + "Event Co-Host " + C.Reset; + else if (_manager.GetGameHostManager().isCommunityServer()) + rankStr = C.cDGreen + C.Bold + "MCS Co-Host " + C.Reset; else rankStr = C.cDGreen + C.Bold + "MPS Co-Host " + C.Reset; }