diff --git a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java index de8602e07..fca669fba 100644 --- a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java @@ -2,33 +2,34 @@ package mineplex.bungee.lobbyBalancer; import java.io.File; import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.EnumMap; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; -import mineplex.serverdata.Region; -import mineplex.serverdata.data.MinecraftServer; -import mineplex.serverdata.servers.ServerManager; -import mineplex.serverdata.servers.ServerRepository; import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.event.EventHandler; -import com.google.common.collect.Lists; +import mineplex.serverdata.Region; +import mineplex.serverdata.data.MinecraftServer; +import mineplex.serverdata.servers.ServerManager; +import mineplex.serverdata.servers.ServerRepository; public class LobbyBalancer implements Listener, Runnable { private Plugin _plugin; private ServerRepository _repository; - - private List _sortedLobbies = Lists.newArrayList(); - private List _sortedClans = Lists.newArrayList(); - private static Object _serverLock = new Object(); - - private int _lobbyIndex = 0; - private int _clansIndex = 0; + + private final Map> _sortedLobbyMap = new EnumMap<>(LobbyType.class); + private final Map _nextIndexMap = new EnumMap<>(LobbyType.class); + private static final LobbySorter LOBBY_SORTER = new LobbySorter(); + private static final Object _serverLock = new Object(); public LobbyBalancer(Plugin plugin) { @@ -46,45 +47,42 @@ public class LobbyBalancer implements Listener, Runnable @EventHandler public void playerConnect(ServerConnectEvent event) { - if (event.getTarget().getName().equalsIgnoreCase("Lobby")) - { - synchronized (_serverLock) - { - if (_lobbyIndex >= _sortedLobbies.size() || _sortedLobbies.get(_lobbyIndex).getPlayerCount() >= _sortedLobbies.get(_lobbyIndex).getMaxPlayerCount()) - _lobbyIndex = 0; + Arrays.stream(LobbyType.values()) + .filter(type -> type.getConnectName().equalsIgnoreCase(event.getTarget().getName())) + .findFirst() + .ifPresent(lobbyType -> + { + synchronized (_serverLock) + { + List lobbies = _sortedLobbyMap.get(lobbyType); - event.setTarget(_plugin.getProxy().getServerInfo(_sortedLobbies.get(_lobbyIndex).getName())); - _sortedLobbies.get(_lobbyIndex).incrementPlayerCount(1); - System.out.println("Sending " + event.getPlayer().getName() + " to " + _sortedLobbies.get(_lobbyIndex).getName() + "(" + _sortedLobbies.get(_lobbyIndex).getPublicAddress() + ")"); - _lobbyIndex++; - } - } - if (event.getTarget().getName().equalsIgnoreCase("ClansHub")) - { - synchronized (_serverLock) - { - if (_clansIndex >= _sortedClans.size() || _sortedClans.get(_clansIndex).getPlayerCount() >= _sortedClans.get(_clansIndex).getMaxPlayerCount()) - _clansIndex = 0; + int nextIndex = _nextIndexMap.getOrDefault(lobbyType, 0); + if (nextIndex >= lobbies.size()) + { + nextIndex = 0; + } - event.setTarget(_plugin.getProxy().getServerInfo(_sortedClans.get(_clansIndex).getName())); - _sortedClans.get(_clansIndex).incrementPlayerCount(1); - System.out.println("Sending " + event.getPlayer().getName() + " to " + _sortedClans.get(_clansIndex).getName() + "(" + _sortedClans.get(_clansIndex).getPublicAddress() + ")"); - _clansIndex++; - } - } + MinecraftServer server = lobbies.get(nextIndex); + + event.setTarget(_plugin.getProxy().getServerInfo(server.getName())); + server.incrementPlayerCount(1); + System.out.println("Sending " + event.getPlayer().getName() + " to " + server.getName() + "(" + server.getPublicAddress() + ")"); + + _nextIndexMap.put(lobbyType, ++nextIndex); + } + }); } public void run() { loadServers(); - - if (!_plugin.getProxy().getServers().containsKey("ClansHub")) + + for (LobbyType type : LobbyType.values()) { - _plugin.getProxy().getServers().put("ClansHub", _plugin.getProxy().constructServerInfo("ClansHub", new InetSocketAddress("lobby.mineplex.com", 25565), "LobbyBalancer", false)); - } - if (!_plugin.getProxy().getServers().containsKey("Lobby")) - { - _plugin.getProxy().getServers().put("Lobby", _plugin.getProxy().constructServerInfo("Lobby", new InetSocketAddress("lobby.mineplex.com", 25565), "LobbyBalancer", false)); + if (!_plugin.getProxy().getServers().containsKey(type.getConnectName())) + { + _plugin.getProxy().getServers().put(type.getConnectName(), _plugin.getProxy().constructServerInfo(type.getConnectName(), new InetSocketAddress("lobby.mineplex.com", 25565), "LobbyBalancer", false)); + } } } @@ -95,9 +93,12 @@ public class LobbyBalancer implements Listener, Runnable synchronized (_serverLock) { long startTime = System.currentTimeMillis(); - _sortedLobbies.clear(); - _sortedClans.clear(); - + _sortedLobbyMap.clear(); + for (LobbyType type : LobbyType.values()) + { + _sortedLobbyMap.put(type, new ArrayList<>()); + } + for (MinecraftServer server : servers) { if (server.getName() == null) @@ -105,32 +106,26 @@ public class LobbyBalancer implements Listener, Runnable InetSocketAddress socketAddress = new InetSocketAddress(server.getPublicAddress(), server.getPort()); _plugin.getProxy().getServers().put(server.getName(), _plugin.getProxy().constructServerInfo(server.getName(), socketAddress, "LobbyBalancer", false)); - - if (server.getName().toUpperCase().startsWith("LOBBY-")) - { - if (server.getMotd() == null || !server.getMotd().contains("Restarting")) - { - _sortedLobbies.add(server); - } - } - if (server.getName().toUpperCase().startsWith("CLANSHUB-")) - { - if (server.getMotd() == null || !server.getMotd().contains("Restarting")) - { - _sortedClans.add(server); - } - } + + if (server.getMotd() != null && server.getMotd().contains("Restarting")) + { + continue; + } + + Arrays.stream(LobbyType.values()) + .filter(type -> server.getName().toUpperCase().startsWith(type.getUppercasePrefix())) + .findFirst() + .ifPresent(type -> _sortedLobbyMap.get(type).add(server)); } - - Collections.sort(_sortedLobbies, new LobbySorter()); - Collections.sort(_sortedClans, new LobbySorter()); - + + _sortedLobbyMap.values().forEach(lobbies -> Collections.sort(lobbies, LOBBY_SORTER)); + long timeSpentInLock = System.currentTimeMillis() - startTime; if (timeSpentInLock > 50) System.out.println("[==] TIMING [==] Locked loading servers for " + timeSpentInLock + "ms"); - - _lobbyIndex = 0; + + _nextIndexMap.clear(); } } } diff --git a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyType.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyType.java new file mode 100644 index 000000000..8b4e4fb5d --- /dev/null +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyType.java @@ -0,0 +1,34 @@ +package mineplex.bungee.lobbyBalancer; + +public enum LobbyType +{ + NORMAL("Lobby", "LOBBY-", "MainMotd"), + CLANS("ClansHub", "CLANSHUB-", "ClansMotd"), + BETA("BetaHub","BETAHUB-", "BetaMotd"), + ; + private final String _connectName; // The name of the server the player is connecting to + private final String _uppercasePrefix; // The (toUpperCase()) prefix given to servers of this lobby type + private final String _redisMotdKey; + + LobbyType(String connectName, String uppercasePrefix, String redisMotdKey) + { + _connectName = connectName; + _uppercasePrefix = uppercasePrefix; + _redisMotdKey = redisMotdKey; + } + + public String getConnectName() + { + return _connectName; + } + + public String getUppercasePrefix() + { + return _uppercasePrefix; + } + + public String getRedisMotdKey() + { + return _redisMotdKey; + } +} diff --git a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/motd/MotdManager.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/motd/MotdManager.java index aa2565f27..4b556d2e2 100644 --- a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/motd/MotdManager.java +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/motd/MotdManager.java @@ -1,138 +1,82 @@ package mineplex.bungee.motd; -import java.io.File; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.EnumMap; +import java.util.Map; +import java.util.Optional; import java.util.Random; import java.util.concurrent.TimeUnit; -import mineplex.serverdata.Region; -import mineplex.serverdata.data.DataRepository; -import mineplex.serverdata.redis.RedisDataRepository; -import mineplex.serverdata.servers.ConnectionData; -import mineplex.serverdata.servers.ConnectionData.ConnectionType; -import mineplex.serverdata.servers.ServerManager; import net.md_5.bungee.api.event.ProxyPingEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.event.EventHandler; +import mineplex.bungee.lobbyBalancer.LobbyType; +import mineplex.serverdata.Region; +import mineplex.serverdata.data.DataRepository; +import mineplex.serverdata.redis.RedisDataRepository; +import mineplex.serverdata.servers.ServerManager; + public class MotdManager implements Listener, Runnable { - private Plugin _plugin; - - private DataRepository _repository; - private DataRepository _secondRepository; - private Region _region; - - private Random _random = new Random(); - private String _firstLine = " §b§l§m §8§l§m[ §r §9§lMineplex§r §f§lGames§r §8§l§m ]§b§l§m §r"; - private List _motdLines; - private String _firstCLine = " §b§l§m §8§l§m[ §r §9§lMineplex§r §f§lGames§r §8§l§m ]§b§l§m §r"; - private List _motdCLines; + private static final String DEFAULT_HEADLINE = " §b§l§m §8§l§m[ §r §9§lMineplex§r §f§lGames§r §8§l§m ]§b§l§m §r"; + + private final DataRepository _repository; + private final Random _random = new Random(); + private final Map motds = new EnumMap<>(LobbyType.class); public MotdManager(Plugin plugin) { - _plugin = plugin; - _region = !new File("eu.dat").exists() ? Region.US : Region.EU; - - _plugin.getProxy().getScheduler().schedule(_plugin, this, 5L, 30L, TimeUnit.SECONDS); - _plugin.getProxy().getPluginManager().registerListener(_plugin, this); + plugin.getProxy().getScheduler().schedule(plugin, this, 5L, 30L, TimeUnit.SECONDS); + plugin.getProxy().getPluginManager().registerListener(plugin, this); _repository = new RedisDataRepository(ServerManager.getConnection(true, ServerManager.SERVER_STATUS_LABEL), ServerManager.getConnection(false, ServerManager.SERVER_STATUS_LABEL), Region.ALL, GlobalMotd.class, "globalMotd"); run(); - - if (new File("updateMOTD.dat").exists()) - { - if (_region == Region.US) - _secondRepository = new RedisDataRepository(new ConnectionData("10.81.1.156", 6379, ConnectionType.MASTER, "ServerStatus"), new ConnectionData("10.81.1.156", 6377, ConnectionType.SLAVE, "ServerStatus"), - Region.ALL, GlobalMotd.class, "globalMotd"); - else - _secondRepository = new RedisDataRepository(new ConnectionData("10.33.53.16", 6379, ConnectionType.MASTER, "ServerStatus"), new ConnectionData("10.33.53.16", 6377, ConnectionType.SLAVE, "ServerStatus"), - Region.ALL, GlobalMotd.class, "globalMotd"); - - //String motdLine = "§f§l◄ §c§lMaintenance§f§l ►"; - //String motdLine = "§f§l◄ §a§lCarl the Creeper§f§l ►"; -// String motdLine = " §2§l§n M O N S T E R M A Z E B E T A §f"; - String motdLine = " §f> §4§lCLANS BETA §f- §c§lOpen to Everyone §f<"; -// String motdLine = " §f❄ §2§lServer Maintenance §f❄ §2§lBe Back Soon §f❄"; - //String motdLine = " §d§lRank Sale §a§l40% Off"); - //String motdLine = " §f§l◄§c§lMAINTENANCE§f§l►"); - - updateMainMotd(" §f§m §8§l§m[ §r §9§lMineplex§r §f§lGames§r §8§l§m ]§f§m §r", motdLine); - System.out.println("Updated Bungee MOTD"); - } } @EventHandler public void serverPing(ProxyPingEvent event) { + net.md_5.bungee.api.ServerPing serverPing = event.getResponse(); - if (event.getConnection().getListener() != null && event.getConnection().getListener().getDefaultServer().equalsIgnoreCase("ClansHub")) + Optional maybeType = Optional.empty(); + + if (event.getConnection().getListener() != null) { - String motd = _firstCLine; - if (_motdCLines != null && _motdCLines.size() > 0) - { - motd += "\n" + _motdCLines.get(_random.nextInt(_motdCLines.size())); - } - event.setResponse(new net.md_5.bungee.api.ServerPing(serverPing.getVersion(), serverPing.getPlayers(), motd, serverPing.getFaviconObject())); + maybeType = Arrays.stream(LobbyType.values()) + .filter(type -> event.getConnection().getListener().getDefaultServer().equalsIgnoreCase(type.getConnectName())) + .findFirst(); } - else + + LobbyType lobbyType = maybeType.orElse(LobbyType.NORMAL); + GlobalMotd globalMotd = motds.get(lobbyType); + + String motd = DEFAULT_HEADLINE; + if (globalMotd != null && globalMotd.getHeadline() != null) { - String motd = _firstLine; - if (_motdLines != null && _motdLines.size() > 0) + motd = globalMotd.getHeadline() == null ? DEFAULT_HEADLINE : globalMotd.getHeadline(); + if (globalMotd.getMotd() != null) { - motd += "\n" + _motdLines.get(_random.nextInt(_motdLines.size())); + motd += "\n" + globalMotd.getMotd().get(_random.nextInt(globalMotd.getMotd().size())); } - event.setResponse(new net.md_5.bungee.api.ServerPing(serverPing.getVersion(), serverPing.getPlayers(), motd, serverPing.getFaviconObject())); } + + event.setResponse(new net.md_5.bungee.api.ServerPing(serverPing.getVersion(), serverPing.getPlayers(), motd, serverPing.getFaviconObject())); } @Override public void run() { + for (LobbyType type : LobbyType.values()) { - GlobalMotd motd = _repository.getElement("MainMotd"); + GlobalMotd motd = _repository.getElement(type.getRedisMotdKey()); if (motd != null) - { - _motdLines = motd.getMotd(); - _firstLine = motd.getHeadline(); - } - } - { - GlobalMotd motd = _repository.getElement("ClansMotd"); - - if (motd != null) - { - _motdCLines = motd.getMotd(); - _firstCLine = motd.getHeadline(); - } - else { - _repository.addElement(new GlobalMotd("ClansMotd", "§4§lMineplex Clans§r", Arrays.asList("Default MOTD"))); + motds.put(type, motd); } } } - - /** - * Update the main {@link GlobalMotd} determining the MOTD for Bungee instances. - * @param motdLines - the lines to update the MOTD to. - */ - public void updateMainMotd(String headline, String motdLine) - { - List motdLines = new ArrayList(); - - motdLines.add(motdLine); - - _repository.addElement(new GlobalMotd("MainMotd", headline, motdLines)); - _secondRepository.addElement(new GlobalMotd("MainMotd", headline, motdLines)); - } - - public List getMotdLines() - { - return _motdLines; - } } diff --git a/Plugins/Mineplex.Core.Common/pom.xml b/Plugins/Mineplex.Core.Common/pom.xml index 92c1a7ff4..65ec63dd8 100644 --- a/Plugins/Mineplex.Core.Common/pom.xml +++ b/Plugins/Mineplex.Core.Common/pom.xml @@ -1,40 +1,40 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - - com.mineplex - mineplex-parent - dev-SNAPSHOT - + + com.mineplex + mineplex-parent + dev-SNAPSHOT + - mineplex-core-common + mineplex-core-common - - - com.mineplex - spigot - - - org.apache.httpcomponents - httpclient - - - com.mineplex - mineplex-serverdata - dev-SNAPSHOT - - + + + com.mineplex + spigot + + + org.apache.httpcomponents + httpclient + + + com.mineplex + mineplex-serverdata + dev-SNAPSHOT + + - - - - - - ascii.png - - - - + + + + + + ascii.png + + + + diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiHost.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiHost.java index a168c3540..a6dd1cbae 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiHost.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiHost.java @@ -1,21 +1,80 @@ package mineplex.core.common.api; -/** - * TODO: Store this in a file instead of being hardcoded - * - * @author Shaun Bennett - */ -public enum ApiHost +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.configuration.file.YamlConfiguration; + +public class ApiHost { - AMPLIFIERS("10.33.53.12", 7979), - ANTISPAM("10.33.53.12", 8181), - ENDERCHEST("10.33.53.10", 8010) - ; + private static final String API_HOST_FILE = "api-config.dat"; + private static final Object LOCK = new Object(); + + private static volatile boolean LOADED = false; + + private static final Map API_HOST_MAP = new HashMap<>(); + + public static ApiHost getAPIHost(String identifier) + { + if (!LOADED) + { + synchronized (LOCK) + { + if (!LOADED) + { + try + { + File configFile = new File(API_HOST_FILE); + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configFile); + + for (String key : configuration.getKeys(false)) + { + String ip = configuration.getConfigurationSection(key).getString("ip"); + // Use parseInt to catch non-ints instead of a 0 + int port = Integer.parseInt(configuration.getConfigurationSection(key).getString("port")); + if (ip == null) + { + throw new NullPointerException(); + } + + API_HOST_MAP.put(key, new ApiHost(ip, port)); + } + } + catch (Throwable t) + { + t.printStackTrace(); + } + finally + { + LOADED = true; + } + } + } + } + + return API_HOST_MAP.get(identifier); + } + + public static ApiHost getAmplifierService() + { + return getAPIHost("AMPLIFIERS"); + } + + public static ApiHost getAntispamService() + { + return getAPIHost("ANTISPAM"); + } + + public static ApiHost getEnderchestService() + { + return getAPIHost("ENDERCHEST"); + } private String _host; private int _port; - ApiHost(String host, int port) + private ApiHost(String host, int port) { _host = host; _port = port; diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/enderchest/EnderchestWorldLoader.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/enderchest/EnderchestWorldLoader.java index 0a782d6d7..c11615902 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/enderchest/EnderchestWorldLoader.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/enderchest/EnderchestWorldLoader.java @@ -18,7 +18,7 @@ public class EnderchestWorldLoader public EnderchestWorldLoader() { - String url = "http://" + ApiHost.ENDERCHEST.getHost() + ":" + ApiHost.ENDERCHEST.getPort() + "/"; + String url = "http://" + ApiHost.getEnderchestService().getHost() + ":" + ApiHost.getEnderchestService().getPort() + "/"; _webCall = new ApiWebCall(url); } @@ -26,7 +26,7 @@ public class EnderchestWorldLoader { TimingManager.start(TIMINGS_PREFIX + "DownloadMap"); String fileName = mapType + "_map.zip"; - File f = _webCall.getFile("map/" + mapType + "/random", fileName); + File f = _webCall.getFile("map/" + mapType + "/next", fileName); TimingManager.stop(TIMINGS_PREFIX + "DownloadMap"); TimingManager.start(TIMINGS_PREFIX + "CreateFolders"); diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilBlock.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilBlock.java index f6287b349..6a43363de 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilBlock.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilBlock.java @@ -4,18 +4,9 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Set; import java.util.UUID; -import net.minecraft.server.v1_8_R3.BlockPosition; -import net.minecraft.server.v1_8_R3.Blocks; -import net.minecraft.server.v1_8_R3.IBlockData; -import net.minecraft.server.v1_8_R3.Item; -import net.minecraft.server.v1_8_R3.MathHelper; -import net.minecraft.server.v1_8_R3.MinecraftKey; -import net.minecraft.server.v1_8_R3.NBTTagCompound; -import net.minecraft.server.v1_8_R3.TileEntityFlowerPot; -import net.minecraft.server.v1_8_R3.WorldServer; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.SkullType; @@ -41,8 +32,18 @@ import org.bukkit.material.Bed; import com.mojang.authlib.GameProfile; +import mineplex.core.common.Pair; import mineplex.core.common.block.MultiBlockUpdaterAgent; import mineplex.core.common.skin.SkinData; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.Blocks; +import net.minecraft.server.v1_8_R3.IBlockData; +import net.minecraft.server.v1_8_R3.Item; +import net.minecraft.server.v1_8_R3.MathHelper; +import net.minecraft.server.v1_8_R3.MinecraftKey; +import net.minecraft.server.v1_8_R3.NBTTagCompound; +import net.minecraft.server.v1_8_R3.TileEntityFlowerPot; +import net.minecraft.server.v1_8_R3.WorldServer; public class UtilBlock { @@ -1670,4 +1671,38 @@ public class UtilBlock return null; } + /** + * Returns a {@link Set} containing all the relevant data regarding beacon construction. + * Useful for adding them to block restore. + * + * @param surface + * The Location of the glass coloured block (at surface level). The beacon is placed one block below this. + * @param glassData + * The colour data value of glass that colours the beacon + */ + public static Set>> getBeaconBlocks(Location surface, byte glassData) + { + Set>> blocks = new HashSet<>(); + + for (int x = -1; x <= 1; x++) + { + for (int z = -1; z <= 1; z++) + { + blocks.add(Pair.create(surface.clone().add(x, -3, z), Pair.create(Material.IRON_BLOCK, (byte) 0))); + + if (x == 0 && z == 0) + { + continue; + } + + blocks.add(Pair.create(surface.clone().add(x, -1, z), Pair.create(Material.QUARTZ_BLOCK, (byte) 0))); + } + } + + blocks.add(Pair.create(surface.clone().add(0, -2, 0), Pair.create(Material.BEACON, (byte) 0))); + blocks.add(Pair.create(surface.clone().add(0, -1, 0), Pair.create(Material.STAINED_GLASS, glassData))); + + return blocks; + } + } diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilInv.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilInv.java index f7b6cbec7..246105fc8 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilInv.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilInv.java @@ -447,6 +447,21 @@ public class UtilInv return false; } + + public static boolean hasSpace(Player player, int slots) + { + int slotsFree = 0; + + for (int slot = 0; slot < player.getInventory().getSize(); slot++) + { + if (player.getInventory().getItem(slot) == null) + { + slotsFree++; + } + } + + return slotsFree >= slots; + } public static void give(Player player, Material material) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antispam/repository/AntiSpamRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/antispam/repository/AntiSpamRepository.java index 4211d3116..be920e079 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antispam/repository/AntiSpamRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antispam/repository/AntiSpamRepository.java @@ -17,7 +17,7 @@ public class AntiSpamRepository extends ApiEndpoint { public AntiSpamRepository() { - super(ApiHost.ANTISPAM, "/chat"); + super(ApiHost.getAntispamService(), "/chat"); } public AntiSpamApiResponse sendMessage(String source, ChatPayload payload) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/beta/BetaWhitelist.java b/Plugins/Mineplex.Core/src/mineplex/core/beta/BetaWhitelist.java new file mode 100644 index 000000000..ca0f67e27 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/beta/BetaWhitelist.java @@ -0,0 +1,68 @@ +package mineplex.core.beta; + +import java.util.Set; +import java.util.UUID; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +import com.google.common.collect.ImmutableSet; + +import mineplex.core.MiniPlugin; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.Rank; +import mineplex.core.powerplayclub.PowerPlayClubRepository; + +public class BetaWhitelist extends MiniPlugin +{ + private static final Set EXTRA_PLAYERS = ImmutableSet.builder() + // GI Members + .add(UUID.fromString("8506533f-1da7-4d5c-a835-a483b5a18b54")) // Awquard + .add(UUID.fromString("a8526c97-95be-4cb7-ae58-7df5d3b108a6")) // ASlime + .add(UUID.fromString("ae6d71b7-3d49-429f-b31f-5cf5af136540")) // Cabob + .add(UUID.fromString("ea1f709c-031f-4028-8f7d-2073c5a37d1a")) // CharlieHacks + .add(UUID.fromString("d3c1457a-1084-43e1-846c-addc47393b90")) // Chocobutter + .add(UUID.fromString("6b60782e-f95b-4449-a39e-0ad7fa5fdab0")) // CosmoLink + .add(UUID.fromString("18697323-50d3-47ea-a5c2-e7ac1a0d9fa0")) // Danah + .add(UUID.fromString("1cc18d8d-ab28-4354-8cce-f93fb06423bf")) // Fetch + .add(UUID.fromString("c56e5b96-8dc3-46ca-b682-24cf8467e3a1")) // KingOfWizards + .add(UUID.fromString("ea30fe99-2044-438f-bfd8-97bcc639239e")) // Mauo + .add(UUID.fromString("933b2f93-806a-4f39-88a2-935442418ae5")) // Tier4Global + .add(UUID.fromString("ac239b94-3079-4a8a-a52f-7b81c8a87b4d")) // Paddi + .add(UUID.fromString("3ced328d-f079-45e4-ad71-8c721c4a699b")) // Smaland47 + .add(UUID.fromString("d51fc65b-fce9-4464-9391-b259525dc6ca")) // SnitSays + .add(UUID.fromString("12bbeda2-567a-400a-9d66-f76fab832de0")) // StoneColdKiller + .add(UUID.fromString("2e0c1d88-7f44-44f5-85b4-9ad0b2cfddce")) // Tours + .add(UUID.fromString("32aff2d0-f68c-4eb9-b5d4-139fc48b7ca6")) // Trimzon + .add(UUID.fromString("3dcfe366-fcaa-48f7-abcc-b73fb62616e1")) // gamefish32 + .add(UUID.fromString("6795643a-2b61-41bf-9429-c7549fd128a8")) // umGim + .add(UUID.fromString("47ba454a-4999-42f4-a269-2f4114ceb3c7")) // falconviii + .build(); + private final CoreClientManager _clientManager; + private final PowerPlayClubRepository _powerPlayClubRepository; + + public BetaWhitelist(CoreClientManager clientManager, PowerPlayClubRepository powerPlayRepository) + { + super("Beta Whitelist"); + _clientManager = clientManager; + _powerPlayClubRepository = powerPlayRepository; + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) + { + Player player = event.getPlayer(); + Rank rank = _clientManager.Get(player).GetRank(true); + if ((rank != Rank.MAPDEV && rank != Rank.MAPLEAD && rank.has(Rank.ETERNAL) // If this player is Eternal+ (and not a builder), + || _powerPlayClubRepository.getCachedData(player).isSubscribed()) // a PPC subscriber, + || EXTRA_PLAYERS.contains(player.getUniqueId())) // or explicitly whitelisted, + { + return; // allow them in + } + + // Otherwise, kick them out + event.getPlayer().kickPlayer("Sorry, you aren't whitelisted on this beta server.\n\nSubscribe to " + ChatColor.GOLD + "Power Play Club " + ChatColor.WHITE + "at " + ChatColor.GREEN + "mineplex.com/shop" + ChatColor.WHITE + "!"); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/blockrestore/BlockRestore.java b/Plugins/Mineplex.Core/src/mineplex/core/blockrestore/BlockRestore.java index 664a742de..c2859d691 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/blockrestore/BlockRestore.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/blockrestore/BlockRestore.java @@ -18,22 +18,23 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.world.ChunkUnloadEvent; -import org.bukkit.plugin.java.JavaPlugin; import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; import mineplex.core.common.util.UtilBlock; import mineplex.core.common.util.UtilMath; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; +@ReflectivelyCreateMiniPlugin public class BlockRestore extends MiniPlugin { private HashMap _blocks = new HashMap(); private LinkedList _restoreMaps; - public BlockRestore(JavaPlugin plugin) + private BlockRestore() { - super("Block Restore", plugin); + super("Block Restore"); _restoreMaps = new LinkedList(); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java index d1a06f0a4..13f355f0a 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java @@ -236,11 +236,11 @@ public class BonusManager extends MiniClientPlugin implements I if (event.getType() != UpdateType.TICK) return; - _animation.itemClean(); - if (!_enabled) return; + _animation.itemClean(); + if (!_animationRunning) return; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PowerPlayClubButton.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PowerPlayClubButton.java index 67b1ae492..d1282cc18 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PowerPlayClubButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PowerPlayClubButton.java @@ -170,7 +170,8 @@ public class PowerPlayClubButton implements GuiItem public static boolean isAvailable(Player player, PowerPlayClubRepository repo) { - return !repo.getCachedData(player).getUnclaimedMonths().isEmpty(); + PowerPlayData data = repo.getCachedData(player); + return data != null && !data.getUnclaimedMonths().isEmpty(); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterRepository.java index 25e8c2c64..2f42602e9 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterRepository.java @@ -24,7 +24,7 @@ public class BoosterRepository extends ApiEndpoint { public BoosterRepository() { - super(ApiHost.AMPLIFIERS, "/booster", new GsonBuilder().setFieldNamingStrategy(new ApiFieldNamingStrategy()) + super(ApiHost.getAmplifierService(), "/booster", new GsonBuilder().setFieldNamingStrategy(new ApiFieldNamingStrategy()) // .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()) .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX").create()); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java b/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java index 0feeae737..71f36d24d 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java @@ -147,8 +147,11 @@ public class Chat extends MiniPlugin || event.getMessage().toLowerCase().startsWith("/bukkit") || event.getMessage().toLowerCase().startsWith("/minecraft")) { - event.getPlayer().sendMessage(F.main(getName(), "Nope, not allowed!")); - event.setCancelled(true); + if (!event.getPlayer().isOp()) + { + event.getPlayer().sendMessage(F.main(getName(), "Nope, not allowed!")); + event.setCancelled(true); + } } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityJoinCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityJoinCommand.java index 202d73fc3..b1b167e7b 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityJoinCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityJoinCommand.java @@ -1,47 +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())); - } +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 index 1e499c57f..683283e3c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityMCSCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/commands/CommunityMCSCommand.java @@ -1,50 +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); - } +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/mcs/MCSTheme.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/mcs/MCSTheme.java index a7ed05b78..215cf9106 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/mcs/MCSTheme.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/mcs/MCSTheme.java @@ -1,50 +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; - } +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/PlayerJoinHandler.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/PlayerJoinHandler.java index a691f1f9b..5ed774fcb 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/PlayerJoinHandler.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/redis/PlayerJoinHandler.java @@ -1,26 +1,26 @@ -package mineplex.core.communities.redis; - -import mineplex.core.communities.CommunityManager; -import mineplex.serverdata.commands.CommandCallback; -import mineplex.serverdata.commands.PlayerJoinCommand; -import mineplex.serverdata.commands.ServerCommand; - -public class PlayerJoinHandler implements CommandCallback -{ - private CommunityManager _communityManager; - - public PlayerJoinHandler(CommunityManager communityManager) - { - _communityManager = communityManager; - } - - @Override - public void run(ServerCommand command) - { - if (command instanceof PlayerJoinCommand) - { - PlayerJoinCommand joinCommand = (PlayerJoinCommand)command; - //_communityManager.updateAllMemberData(UUID.fromString(joinCommand.getUuid()), joinCommand.getName()); - } - } +package mineplex.core.communities.redis; + +import mineplex.core.communities.CommunityManager; +import mineplex.serverdata.commands.CommandCallback; +import mineplex.serverdata.commands.PlayerJoinCommand; +import mineplex.serverdata.commands.ServerCommand; + +public class PlayerJoinHandler implements CommandCallback +{ + private CommunityManager _communityManager; + + public PlayerJoinHandler(CommunityManager communityManager) + { + _communityManager = communityManager; + } + + @Override + public void run(ServerCommand command) + { + if (command instanceof PlayerJoinCommand) + { + PlayerJoinCommand joinCommand = (PlayerJoinCommand)command; + //_communityManager.updateAllMemberData(UUID.fromString(joinCommand.getUuid()), joinCommand.getName()); + } + } } \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/CosmeticManager.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/CosmeticManager.java index 590e814fd..d1ae7b491 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/CosmeticManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/CosmeticManager.java @@ -242,6 +242,11 @@ public class CosmeticManager extends MiniPlugin { return _boosterManager; } + + public void displayUI(Player player) + { + _shop.attemptShopOpen(player); + } public void disableTeamArmor() { 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 index e87cdcfb1..a7c9e9923 100644 --- 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 @@ -1,21 +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)); - } +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/TauntPage.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/TauntPage.java index b4e8a1568..687516e0f 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,59 +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 (gadget.isActive(getPlayer())) - { - 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/disguise/disguises/DisguiseBlock.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBlock.java index 387208c51..d0c32a21d 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBlock.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBlock.java @@ -5,6 +5,9 @@ import java.util.Random; import net.minecraft.server.v1_8_R3.MathHelper; import net.minecraft.server.v1_8_R3.Packet; import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity; + +import org.bukkit.Material; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; public class DisguiseBlock extends DisguiseBase @@ -14,7 +17,7 @@ public class DisguiseBlock extends DisguiseBase private int _blockId; private int _blockData; - public DisguiseBlock(org.bukkit.entity.Entity entity, int blockId, int blockData) + public DisguiseBlock(Entity entity, int blockId, int blockData) { super(EntityType.FALLING_BLOCK, entity); @@ -22,6 +25,14 @@ public class DisguiseBlock extends DisguiseBase _blockData = blockData; } + public DisguiseBlock(Entity entity, Material material, byte data) + { + super(EntityType.FALLING_BLOCK, entity); + + _blockId = material.getId(); + _blockData = (int) data; + } + public int GetBlockId() { return _blockId; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/GadgetManager.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/GadgetManager.java index 014504a07..d2acbf740 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/GadgetManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/GadgetManager.java @@ -87,6 +87,8 @@ import mineplex.core.gadget.gadgets.doublejump.titan.DoubleJumpTitan; import mineplex.core.gadget.gadgets.doublejump.vampire.DoubleJumpBlood; import mineplex.core.gadget.gadgets.doublejump.wisdom.DoubleJumpEnchant; import mineplex.core.gadget.gadgets.gamemodifiers.GameModifierType; +import mineplex.core.gadget.gadgets.gamemodifiers.gemhunters.GameModifierMount; +import mineplex.core.gadget.gadgets.gamemodifiers.gemhunters.MountType; import mineplex.core.gadget.gadgets.gamemodifiers.kits.KitGameModifier; import mineplex.core.gadget.gadgets.gamemodifiers.kits.KitModifier; import mineplex.core.gadget.gadgets.gamemodifiers.kits.KitModifierType; @@ -121,6 +123,7 @@ import mineplex.core.gadget.gadgets.morph.MorphCow; import mineplex.core.gadget.gadgets.morph.MorphCreeper; import mineplex.core.gadget.gadgets.morph.MorphDinnerbone; import mineplex.core.gadget.gadgets.morph.MorphEnderman; +import mineplex.core.gadget.gadgets.morph.MorphGoldPot; import mineplex.core.gadget.gadgets.morph.MorphGrimReaper; import mineplex.core.gadget.gadgets.morph.MorphLoveDoctor; import mineplex.core.gadget.gadgets.morph.MorphMetalMan; @@ -418,6 +421,7 @@ public class GadgetManager extends MiniPlugin addGadget(new MorphSanta(this)); addGadget(new MorphDinnerbone(this)); addGadget(new MorphLoveDoctor(this)); + addGadget(new MorphGoldPot(this)); // Particles addGadget(new ParticleFoot(this)); @@ -574,6 +578,12 @@ public class GadgetManager extends MiniPlugin addGadget(new BlowAKissTaunt(this)); addGadget(new RainbowTaunt(this)); + // Gem Hunters Mounts + for (MountType mount : MountType.values()) + { + addGadget(new GameModifierMount(this, mount)); + } + for (GadgetType gadgetType : GadgetType.values()) { if (!_gadgets.containsKey(gadgetType)) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/commands/LockCosmeticsCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/commands/LockCosmeticsCommand.java index 649f26444..a4968bead 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/commands/LockCosmeticsCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/commands/LockCosmeticsCommand.java @@ -7,6 +7,7 @@ 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; import mineplex.core.common.util.UtilText; import mineplex.core.donation.Donor; import mineplex.core.gadget.GadgetManager; @@ -22,13 +23,19 @@ public class LockCosmeticsCommand extends CommandBase public LockCosmeticsCommand(GadgetManager plugin) { - super(plugin, Rank.JNR_DEV, "lockCosmetics"); + super(plugin, Rank.SNR_MODERATOR, "lockCosmetics"); _plugin = plugin; } @Override public void Execute(Player caller, String[] args) { + if (!UtilServer.isTestServer()) + { + UtilPlayer.message(caller, F.main("Lock Cosmetics", "This command requires a test server!")); + return; + } + // Adds all cosmetic types if (args.length == 0) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/commands/UnlockCosmeticsCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/commands/UnlockCosmeticsCommand.java index d18f05207..43e1a4756 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/commands/UnlockCosmeticsCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/commands/UnlockCosmeticsCommand.java @@ -7,6 +7,7 @@ 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; import mineplex.core.common.util.UtilText; import mineplex.core.donation.Donor; import mineplex.core.gadget.GadgetManager; @@ -29,6 +30,12 @@ public class UnlockCosmeticsCommand extends CommandBase @Override public void Execute(Player caller, String[] args) { + if (!UtilServer.isTestServer()) + { + UtilPlayer.message(caller, F.main("Unlock Cosmetics", "This command requires a test server!")); + return; + } + // Adds all cosmetic types if (args.length == 0) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/event/TauntCommandEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/event/TauntCommandEvent.java index fc6e643f3..e803d54e2 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/event/TauntCommandEvent.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/event/TauntCommandEvent.java @@ -1,106 +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; - } - } - -} +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/gamemodifiers/GameModifierType.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/GameModifierType.java index 569a71dcf..018092c15 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/GameModifierType.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/GameModifierType.java @@ -19,7 +19,11 @@ public enum GameModifierType MineStrike("MineStrike", new String[]{"Apply custom gun models and skin to use ingame"}, Material.TNT, 0), SurvivalGames("Survival Games", new String[]{"Placeholder"}, Material.DIAMOND_SWORD, 0, true), - Bridges("Bridges", new String[]{"Placeholder"}, Material.IRON_PICKAXE, 0, true); + Bridges("Bridges", new String[]{"Placeholder"}, Material.IRON_PICKAXE, 0, true), + + GemHunters("Gem Hunters", new String[] { "" }, Material.EMERALD, 0) + + ; private String _name; private List _desc; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/gemhunters/GameModifierMount.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/gemhunters/GameModifierMount.java new file mode 100644 index 000000000..eb23fea91 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/gemhunters/GameModifierMount.java @@ -0,0 +1,23 @@ +package mineplex.core.gadget.gadgets.gamemodifiers.gemhunters; + +import mineplex.core.gadget.GadgetManager; +import mineplex.core.gadget.gadgets.gamemodifiers.GameModifierType; +import mineplex.core.gadget.types.GameModifierGadget; + +public class GameModifierMount extends GameModifierGadget +{ + + private final MountType _mountType; + + public GameModifierMount(GadgetManager manager, MountType mountType) + { + super(manager, GameModifierType.GemHunters, mountType.getName() + " Mount", mountType.getDescription(), -2, mountType.getMaterial(), mountType.getData(), false); + + _mountType = mountType; + } + + public final MountType getMountType() + { + return _mountType; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/gemhunters/MountType.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/gemhunters/MountType.java new file mode 100644 index 000000000..c1af6c427 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/gamemodifiers/gemhunters/MountType.java @@ -0,0 +1,53 @@ +package mineplex.core.gadget.gadgets.gamemodifiers.gemhunters; + +import org.bukkit.Material; +import org.bukkit.entity.EntityType; + +public enum MountType +{ + + SKELETON(EntityType.HORSE, Material.BONE, (byte) 0, "Skeleton Horse", "Spooky") + + ; + + private final EntityType _entityType; + private final Material _material; + private final byte _data; + private final String _name; + private final String[] _description; + + private MountType(EntityType entityType, Material material, byte data, String name, String... description) + { + _entityType = entityType; + _material = material; + _data = data; + _name = name; + _description = description; + } + + public final EntityType getEntityType() + { + return _entityType; + } + + public final Material getMaterial() + { + return _material; + } + + public byte getData() + { + return _data; + } + + public final String getName() + { + return _name; + } + + public final String[] getDescription() + { + return _description; + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/MorphGoldPot.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/MorphGoldPot.java new file mode 100644 index 000000000..017c3642f --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/MorphGoldPot.java @@ -0,0 +1,132 @@ +package mineplex.core.gadget.gadgets.morph; + +import java.time.Month; +import java.time.YearMonth; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.LineFormat; +import mineplex.core.common.util.UtilText; +import mineplex.core.disguise.disguises.DisguiseBlock; +import mineplex.core.gadget.GadgetManager; +import mineplex.core.gadget.gadgets.morph.managers.GoldPotHelper; +import mineplex.core.gadget.gadgets.morph.managers.UtilMorph; +import mineplex.core.gadget.types.MorphGadget; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; + +public class MorphGoldPot extends MorphGadget +{ + + private Map _helpers = new HashMap<>(); + + public MorphGoldPot(GadgetManager manager) + { + super(manager, "Gold Pot Morph", UtilText.splitLinesToArray(new String[] + { + C.cGray + "They say at the end of every rainbow a leprechaun has a pot filled with gold.", + C.blankLine, + C.cWhite + "Stand still to hide in place and fill up with treasure. Players who find you will earn a reward!", + }, LineFormat.LORE), + -14, + Material.CAULDRON_ITEM, (byte) 0, YearMonth.of(2017, Month.MARCH)); + } + + @Override + public void enableCustom(Player player, boolean message) + { + applyArmor(player, message); + + _helpers.put(player, new GoldPotHelper(player, Manager, this)); + + DisguiseBlock disguiseBlock = new DisguiseBlock(player, Material.CAULDRON, (byte) 0); + UtilMorph.disguise(player, disguiseBlock, Manager); + } + + @Override + public void disableCustom(Player player, boolean message) + { + removeArmor(player); + + if (_helpers.containsKey(player)) + { + _helpers.get(player).unsolidifyPlayer(); + _helpers.get(player).cleanItems(true); + _helpers.remove(player); + } + + UtilMorph.undisguise(player, Manager.getDisguiseManager()); + } + + @EventHandler + public void onUpdate(UpdateEvent event) + { for (GoldPotHelper goldPotHelper : _helpers.values()) + { + boolean solid = goldPotHelper.updatePlayer(event.getType() == UpdateType.SEC, event.getType() == UpdateType.TICK); + if (solid) + { + goldPotHelper.solififyPlayer(); + } + } + } + + @EventHandler + public void onRightClick(PlayerInteractEvent event) + { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK) + { + for (GoldPotHelper goldPotHelper : _helpers.values()) + { + goldPotHelper.performRightClick(event.getPlayer(), event.getClickedBlock()); + } + } + } + + @EventHandler + public void onItemPickup(PlayerPickupItemEvent event) + { + for (GoldPotHelper goldPotHelper : _helpers.values()) + { + if (goldPotHelper.getItems().contains(event.getItem())) + { + event.setCancelled(true); + } + } + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) + { + if (!isActive(event.getPlayer())) + return; + + if (_helpers.containsKey(event.getPlayer())) + { + if (!_helpers.get(event.getPlayer()).isSolid()) + return; + } + + Location from = event.getFrom(), to = event.getTo(); + double xFrom = from.getX(), yFrom = from.getY(), zFrom = from.getZ(), + xTo = to.getX(), yTo = to.getY(), zTo = to.getZ(); + if (xFrom != xTo || yFrom != yTo || zFrom != zTo) + { + if (_helpers.containsKey(event.getPlayer())) + { + _helpers.get(event.getPlayer()).unsolidifyPlayer(); + } + event.getPlayer().setExp(0f); + } + } + +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/managers/GoldPotHelper.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/managers/GoldPotHelper.java new file mode 100644 index 000000000..bd4f43c48 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/managers/GoldPotHelper.java @@ -0,0 +1,213 @@ +package mineplex.core.gadget.gadgets.morph.managers; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.util.Vector; + +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.disguise.disguises.DisguiseBlock; +import mineplex.core.disguise.disguises.DisguiseCat; +import mineplex.core.disguise.disguises.DisguiseChicken; +import mineplex.core.gadget.GadgetManager; +import mineplex.core.gadget.event.GadgetBlockEvent; +import mineplex.core.gadget.types.Gadget; +import mineplex.core.recharge.Recharge; + +public class GoldPotHelper +{ + + private static final float EXP_INCREMENT = 0.2f; + private static final long COOLDOWN = 300000; + private static final int SHARDS = 250; + private static final int GEMS = 60; + + private Player _player; + private GadgetManager _manager; + private Gadget _gadget; + private GoldPotStands _goldPotStands; + private Block _block; + private boolean _solid = false; + private boolean _nuggets = false; + + private HashSet _items = new HashSet<>(); + + public GoldPotHelper(Player player, GadgetManager manager, Gadget gadget) + { + _player = player; + _manager = manager; + _gadget = gadget; + _goldPotStands = new GoldPotStands(); + } + + public void solififyPlayer() + { + if (_solid) + return; + + Block block = _player.getLocation().getBlock(); + + GadgetBlockEvent event = new GadgetBlockEvent(_gadget, Collections.singletonList(block)); + + Bukkit.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled() || block.getType() != Material.AIR) + { + UtilPlayer.message(_player, F.main("Morph", "You cannot become a gold pot here!")); + return; + } + + if (!Recharge.Instance.usable(_player, _gadget.getName(), true, "Your pot will be refilled with gold in %t")) + { + return; + } + + UtilMorph.undisguise(_player, _manager.getDisguiseManager()); + DisguiseChicken disguiseChicken = new DisguiseChicken(_player); + disguiseChicken.setSoundDisguise(new DisguiseCat(_player)); + disguiseChicken.setInvisible(true); + UtilMorph.disguise(_player, disguiseChicken, _manager); + + block.setType(Material.CAULDRON); + _block = block; + _goldPotStands.setBlock(_block); + _goldPotStands.createStands(); + + _solid = true; + + UtilPlayer.message(_player, F.main("Gold Pot", "You're now filled with gold!")); + } + + public void unsolidifyPlayer() + { + if (!_solid) + return; + + _goldPotStands.removeStands(); + UtilMorph.undisguise(_player, _manager.getDisguiseManager()); + DisguiseBlock disguiseBlock = new DisguiseBlock(_player, Material.CAULDRON, (byte) 0); + UtilMorph.disguise(_player, disguiseBlock, _manager); + + if (_block != null) + { + _block.setType(Material.AIR); + _block = null; + } + + _solid = false; + + UtilPlayer.message(_player, F.main("Gold Pot", "You're no longer filled with gold!")); + } + + public boolean updatePlayer(boolean second, boolean tick) + { + boolean solidify = false; + if (second) + { + if (!_solid) + { + // Updates EXP Bar + _player.setExp(_player.getExp() + EXP_INCREMENT); + + if (_player.getExp() == 1) + { + // Solidifies (or tries to) + solidify = true; + _player.setExp(0f); + } + if (_manager.isMoving(_player)) + { + _player.setExp(0f); + solidify = false; + } + } + else + { + // Throws items in the air + for (int i = 1; i < 5; i++) + { + ItemStack itemStack = new ItemStack((_nuggets) ? Material.GOLD_NUGGET : Material.GOLD_INGOT); + ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.setDisplayName("DROPPED" + System.currentTimeMillis() + i); + itemStack.setItemMeta(itemMeta); + Item gold = _block.getWorld().dropItem(_block.getLocation().add(0.5, 1.5, 0.5), itemStack); + _items.add(gold); + + gold.setVelocity(new Vector((Math.random()-0.5)*0.3, Math.random()-0.4, (Math.random()-0.5)*0.3)); + } + _nuggets = !_nuggets; + } + } + if (tick) + { + UtilParticle.PlayParticleToAll(UtilParticle.ParticleType.ICON_CRACK.getParticle(Material.GOLD_BLOCK, + (byte) 0), _player.getLocation().add(0, 0.5, 0), 0.1f, 0.1f, 0.1f, 0.3f, 1, UtilParticle.ViewDist.LONG); + cleanItems(false); + } + return solidify; + } + + public void performRightClick(Player clicked, Block block) + { + if (_block == null) + return; + + if (!block.equals(_block)) + return; + + if (clicked.equals(_player)) + return; + + unsolidifyPlayer(); + + Recharge.Instance.use(_player, _gadget.getName(), COOLDOWN, false, false, "Cosmetics"); + + boolean shards = UtilMath.random.nextBoolean(); + if (shards) + { + _manager.getDonationManager().rewardCurrency(GlobalCurrency.TREASURE_SHARD, clicked, _gadget.getName() + " Gold Pot Pickup Shards", SHARDS); + Bukkit.broadcastMessage(F.main("Gold Pot", F.name(clicked.getName()) + " found a gold pot worth " + F.currency(GlobalCurrency.TREASURE_SHARD, SHARDS) + "!")); + } else + { + _manager.getDonationManager().rewardCurrency(GlobalCurrency.GEM, clicked, _gadget.getName() + " Gold Pot Pickup Gems", GEMS); + Bukkit.broadcastMessage(F.main("Gold Pot", F.name(clicked.getName()) + " found a gold pot worth " + F.currency(GlobalCurrency.GEM, GEMS) + "!")); + } + } + + public HashSet getItems() + { + return _items; + } + + public void cleanItems(boolean force) + { + Iterator it = _items.iterator(); + while (it.hasNext()) + { + Item item = it.next(); + if (item.getTicksLived() >= 20 || force) + { + item.remove(); + it.remove(); + } + } + } + + public boolean isSolid() + { + return _solid; + } + +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/managers/GoldPotStands.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/managers/GoldPotStands.java new file mode 100644 index 000000000..a448db9b6 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/managers/GoldPotStands.java @@ -0,0 +1,98 @@ +package mineplex.core.gadget.gadgets.morph.managers; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.ArmorStand; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.EulerAngle; + +public class GoldPotStands +{ + + private ArmorStand _helmet, _armsA, _armsB, _armsC; + private Block _block; + + public void setBlock(Block block) + { + _block = block; + } + + public void createStands() + { + if (_block == null) + { + return; + } + Location loc = _block.getLocation().clone().add(0.5, 0, 0.5); + + // Spawns main armorstand + Location asHelmetGoldLoc = loc.clone().subtract(0, 1, 0); + ArmorStand asHelmetGold = loc.getWorld().spawn(asHelmetGoldLoc, ArmorStand.class); + asHelmetGold.setVisible(false); + asHelmetGold.setGravity(false); + asHelmetGold.setHelmet(new ItemStack(Material.GOLD_BLOCK)); + + // Spawns second armorstand + Location asArmsGoldALoc = asHelmetGoldLoc.clone(); + ArmorStand asArmsGoldA = loc.getWorld().spawn(asArmsGoldALoc, ArmorStand.class); + asArmsGoldA.setVisible(false); + asArmsGoldA.setGravity(false); + asArmsGoldA.setItemInHand(new ItemStack(Material.GOLD_BLOCK)); + double asArmsGoldAX = Math.toRadians(158), asArmsGoldAY = Math.toRadians(75); + EulerAngle asArmsGoldAEuler = new EulerAngle(asArmsGoldAX, asArmsGoldAY, 0); + asArmsGoldA.setRightArmPose(asArmsGoldAEuler); + + // Spawns third armorstand + Location asArmsGoldBLoc = asHelmetGoldLoc.clone(); + ArmorStand asArmsGoldB = loc.getWorld().spawn(asArmsGoldBLoc, ArmorStand.class); + asArmsGoldB.setVisible(false); + asArmsGoldB.setGravity(false); + asArmsGoldB.setItemInHand(new ItemStack(Material.GOLD_BLOCK)); + double asArmsGoldBX = Math.toRadians(202), asArmsGoldBY = Math.toRadians(245); + EulerAngle asArmsGoldBEuler = new EulerAngle(asArmsGoldBX, asArmsGoldBY, 0); + asArmsGoldB.setRightArmPose(asArmsGoldBEuler); + + // Spawns fourth armorstand + Location asArmsGoldCLoc = loc.clone().add(0.4, 0.1, 0.1); + ArmorStand asArmsGoldC = loc.getWorld().spawn(asArmsGoldCLoc, ArmorStand.class); + asArmsGoldC.setVisible(false); + asArmsGoldC.setGravity(false); + asArmsGoldC.setSmall(true); + asArmsGoldC.setItemInHand(new ItemStack(Material.GOLD_BLOCK)); + double asArmsGoldCX = Math.toRadians(191), asArmsGoldCY = Math.toRadians(245); + EulerAngle asArmsGoldCEuler = new EulerAngle(asArmsGoldCX, asArmsGoldCY, 0); + asArmsGoldC.setRightArmPose(asArmsGoldCEuler); + + _helmet = asHelmetGold; + _armsA = asArmsGoldA; + _armsB = asArmsGoldB; + _armsC = asArmsGoldC; + } + + public void removeStands() + { + if (_helmet != null) + { + _helmet.remove(); + _helmet = null; + } + if (_armsA != null) + { + _armsA.remove(); + _armsA = null; + } + if (_armsB != null) + { + _armsB.remove(); + _armsB = null; + } + if (_armsC != null) + { + _armsC.remove(); + _armsC = null; + } + _block = null; + } + +} \ No newline at end of file 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 index d68c4382f..53e6a7793 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/EternalTaunt.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/EternalTaunt.java @@ -1,147 +1,147 @@ -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 too 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 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); - } - } - } - -} +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 too 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 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 index 26e0c607c..a0fe9230b 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/GameType.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/taunts/GameType.java @@ -1,84 +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 - -} +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 index 730cbcfcd..0cca83b9f 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/types/TauntGadget.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/types/TauntGadget.java @@ -1,163 +1,163 @@ -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); - } - - @Override - public void disableCustom(Player player, boolean message) - { - super.disableCustom(player, message); - finish(player); - } - - 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); - } - } - -} +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); + } + + @Override + public void disableCustom(Player player, boolean message) + { + super.disableCustom(player, message); + finish(player); + } + + 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); + } + } + +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/google/GoogleSheetsManager.java b/Plugins/Mineplex.Core/src/mineplex/core/google/GoogleSheetsManager.java new file mode 100644 index 000000000..12be686f9 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/google/GoogleSheetsManager.java @@ -0,0 +1,81 @@ +package mineplex.core.google; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; + +@ReflectivelyCreateMiniPlugin +public class GoogleSheetsManager extends MiniPlugin +{ + + private static final File DATA_STORE_DIR = new File(".." + File.separatorChar + ".." + File.separatorChar + "update" + File.separatorChar + "files"); + + private GoogleSheetsManager() + { + super("Google Sheets"); + } + + public Map>> getSheetData(String name) + { + return getSheetData(new File(DATA_STORE_DIR + File.separator + name + ".json")); + } + + public Map>> getSheetData(File file) + { + if (!file.exists()) + { + return null; + } + + Map>> valuesMap = new HashMap<>(); + + try + { + JsonParser parser = new JsonParser(); + JsonElement data = parser.parse(new FileReader(file)); + JsonArray parent = data.getAsJsonObject().getAsJsonArray("data"); + + for (int i = 0; i < parent.size(); i++) + { + JsonObject sheet = parent.get(i).getAsJsonObject(); + String name = sheet.get("name").getAsString(); + JsonArray values = sheet.getAsJsonArray("values"); + List> valuesList = new ArrayList<>(values.size()); + + for (int j = 0; j < values.size(); j++) + { + List list = new ArrayList<>(); + Iterator iterator = values.get(j).getAsJsonArray().iterator(); + + while (iterator.hasNext()) + { + String value = iterator.next().getAsString(); + list.add(value); + } + + valuesList.add(list); + } + + valuesMap.put(name, valuesList); + } + } + catch (FileNotFoundException e) + { + } + + return valuesMap; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/google/SheetObjectDeserialiser.java b/Plugins/Mineplex.Core/src/mineplex/core/google/SheetObjectDeserialiser.java new file mode 100644 index 000000000..d254f7cf0 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/google/SheetObjectDeserialiser.java @@ -0,0 +1,8 @@ +package mineplex.core.google; + +public interface SheetObjectDeserialiser +{ + + public T deserialise(String[] values) throws ArrayIndexOutOfBoundsException; + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemBuilder.java b/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemBuilder.java index f506bfe18..14af0f28d 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemBuilder.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemBuilder.java @@ -53,6 +53,7 @@ public class ItemBuilder private int _amount; private Color _color; private short _data; + private short _durability; private final HashMap _enchants = new HashMap(); private final List _lore = new ArrayList(); private Material _mat; @@ -90,6 +91,7 @@ public class ItemBuilder _itemFlags.addAll(meta.getItemFlags()); _unbreakable = meta.spigot().isUnbreakable(); + _durability = item.getDurability(); } } @@ -108,6 +110,7 @@ public class ItemBuilder _mat = mat; _amount = amount; _data = data; + _durability = 0; } public ItemBuilder(Material mat, short data) @@ -115,6 +118,13 @@ public class ItemBuilder this(mat, 1, data); } + public ItemBuilder setDurability(short durability) + { + _durability = durability; + + return this; + } + public HashSet getItemFlags() { return _itemFlags; @@ -278,7 +288,8 @@ public class ItemBuilder item.addUnsafeEnchantments(_enchants); if (_glow) item.addEnchantment(UtilInv.getDullEnchantment(), 1); - + if (_durability != 0) item.setDurability(_durability); + return item; } @@ -298,7 +309,8 @@ public class ItemBuilder newBuilder.setColor(_color); // newBuilder.potion = potion; - + newBuilder.setDurability(_durability); + return newBuilder; } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/LineEffect.java b/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/LineEffect.java index 3f1612f79..15a55f406 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/LineEffect.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/particleeffects/LineEffect.java @@ -1,52 +1,52 @@ -package mineplex.core.particleeffects; - -import java.awt.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(); - } - } - -} +package mineplex.core.particleeffects; + +import java.awt.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/pet/PetManager.java b/Plugins/Mineplex.Core/src/mineplex/core/pet/PetManager.java index fbf972c22..9eae213a0 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/pet/PetManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/pet/PetManager.java @@ -169,8 +169,12 @@ public class PetManager extends MiniClientPlugin if (player != null && player.isOnline()) { - getActivePet(playerName).setCustomNameVisible(true); - getActivePet(playerName).setCustomName(_petRenameQueue.get(playerName)); + Creature activePet = getActivePet(playerName); + if (activePet != null) + { + activePet.setCustomNameVisible(true); + activePet.setCustomName(_petRenameQueue.get(playerName)); + } } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/portal/commands/SendCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/portal/Commands/SendCommand.java similarity index 100% rename from Plugins/Mineplex.Core/src/mineplex/core/portal/commands/SendCommand.java rename to Plugins/Mineplex.Core/src/mineplex/core/portal/Commands/SendCommand.java diff --git a/Plugins/Mineplex.Core/src/mineplex/core/portal/commands/ServerCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/portal/Commands/ServerCommand.java similarity index 100% rename from Plugins/Mineplex.Core/src/mineplex/core/portal/commands/ServerCommand.java rename to Plugins/Mineplex.Core/src/mineplex/core/portal/Commands/ServerCommand.java diff --git a/Plugins/Mineplex.Core/src/mineplex/core/portal/GenericServer.java b/Plugins/Mineplex.Core/src/mineplex/core/portal/GenericServer.java index 02cb2da42..94059bbb3 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/portal/GenericServer.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/portal/GenericServer.java @@ -12,7 +12,12 @@ public enum GenericServer /** * The Clans Hubs, such as ClansHub-1 */ - CLANS_HUB("ClansHub"); + CLANS_HUB("ClansHub"), + /** + * The Beta Hubs, such as BetaHub-1 + */ + BETA_HUB("BetaHub"), + ; private final String _name; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRewards.java b/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRewards.java index cf4367873..3d5f61a42 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRewards.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRewards.java @@ -35,6 +35,7 @@ public class PowerPlayClubRewards .put(YearMonth.of(2016, Month.DECEMBER), new UnknownSalesPackageItem("Santa Morph")) .put(YearMonth.of(2017, Month.JANUARY), new UnknownSalesPackageItem("Over Easy Morph")) .put(YearMonth.of(2017, Month.FEBRUARY), new PetItem(PetType.TRUE_LOVE_PET)) + .put(YearMonth.of(2017, Month.MARCH), new UnknownSalesPackageItem("Gold Pot Morph")) .build(); public interface PowerPlayClubItem diff --git a/Plugins/Mineplex.Core/src/mineplex/core/recharge/Recharge.java b/Plugins/Mineplex.Core/src/mineplex/core/recharge/Recharge.java index 6422651d6..ce46f7dfb 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/recharge/Recharge.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/recharge/Recharge.java @@ -12,8 +12,6 @@ import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.plugin.java.JavaPlugin; import mineplex.core.MiniPlugin; -import mineplex.core.updater.event.UpdateEvent; -import mineplex.core.updater.UpdateType; import mineplex.core.account.event.ClientUnloadEvent; import mineplex.core.common.util.F; import mineplex.core.common.util.NautHashMap; @@ -21,6 +19,8 @@ import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilTime; import mineplex.core.common.util.UtilTime.TimeUnit; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; public class Recharge extends MiniPlugin { @@ -207,10 +207,23 @@ public class Recharge extends MiniPlugin } public boolean usable(Player player, String ability, boolean inform) + { + return usable(player, ability, inform, null); + } + + /** + * Checks if cooldown is over, using a custom message or not + * @param player The player to be checked + * @param ability The ability to be checked + * @param inform Should it inform the player? + * @param message The custom message (if NULL, default message will be shown) + * @return If the ability is in cooldown or not for that player + */ + public boolean usable(Player player, String ability, boolean inform, String message) { if (!Get(player).containsKey(ability)) return true; - + if (Get(player).get(ability).GetRemaining() <= 0) { return true; @@ -218,9 +231,20 @@ public class Recharge extends MiniPlugin else { if (inform && !Get(player).get(ability).DisplayForce && !Get(player).get(ability).AttachItem) - UtilPlayer.message(player, F.main("Recharge", "You cannot use " + F.skill(ability) + " for " + - F.time(UtilTime.convertString((Get(player).get(ability).GetRemaining()), 1, TimeUnit.FIT)) + ".")); - + { + if (message == null) + { + UtilPlayer.message(player, F.main("Recharge", "You cannot use " + F.skill(ability) + " for " + + F.time(UtilTime.convertString((Get(player).get(ability).GetRemaining()), 1, TimeUnit.FIT)) + ".")); + } + else + { + UtilPlayer.message(player, F.main("Recharge", message.replace("%a", F.skill(ability)) + .replace("%t", F.time(UtilTime.convertString(Get(player).get(ability).GetRemaining(), + 1, TimeUnit.FIT))))); + } + } + return false; } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/sponsorbranding/BrandingManager.java b/Plugins/Mineplex.Core/src/mineplex/core/sponsorbranding/BrandingManager.java index 944be5f58..883975960 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/sponsorbranding/BrandingManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/sponsorbranding/BrandingManager.java @@ -3,28 +3,29 @@ package mineplex.core.sponsorbranding; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.net.URL; import java.util.concurrent.ConcurrentHashMap; import javax.imageio.ImageIO; -import mineplex.core.MiniPlugin; - import org.bukkit.Location; import org.bukkit.block.BlockFace; -import org.bukkit.plugin.java.JavaPlugin; +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; /** * * Manager for creating billboards with branding logos */ +@ReflectivelyCreateMiniPlugin public class BrandingManager extends MiniPlugin { private ConcurrentHashMap _posts = new ConcurrentHashMap(); private ConcurrentHashMap _imgCache = new ConcurrentHashMap(); - public BrandingManager(JavaPlugin plugin) + private BrandingManager() { - super("Branding Manager", plugin); + super("Branding Manager"); } private BufferedImage getImage(String fileName) @@ -56,6 +57,28 @@ public class BrandingManager extends MiniPlugin return image; } + private BufferedImage getImage(URL url) + { + if (_imgCache.containsKey(url.toString())) + { + return _imgCache.get(url.toString()); + } + + BufferedImage image = null; + + try + { + image = ImageIO.read(url); + _imgCache.put(url.toString(), image); + } + catch (IOException e) + { + e.printStackTrace(); + } + + return image; + } + /** * Generates a billboard with a stored logo * @param location The center of the billboard @@ -75,6 +98,22 @@ public class BrandingManager extends MiniPlugin _posts.put(_posts.size(), bp); } + public void createPost(Location location, BlockFace facing, URL url) + { + BufferedImage image = getImage(url); + + if (image == null) + { + System.out.println("ERROR! Invalid image url!"); + return; + } + + BrandingPost brandingPost = new BrandingPost(location, facing, image); + brandingPost.spawn(); + // Umm why not use a List? + _posts.put(_posts.size(), brandingPost); + } + /** * Clears away all existing billboards */ diff --git a/Plugins/Mineplex.Core/src/mineplex/core/sponsorbranding/BrandingPost.java b/Plugins/Mineplex.Core/src/mineplex/core/sponsorbranding/BrandingPost.java index 49039ff4d..54f469646 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/sponsorbranding/BrandingPost.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/sponsorbranding/BrandingPost.java @@ -68,6 +68,8 @@ public class BrandingPost int width = (int) Math.ceil(_img.getWidth() / 128); int height = (int) Math.ceil(_img.getHeight() / 128); + Bukkit.broadcastMessage("width=" + width + " height=" + height); + switch (_facing) { case EAST: @@ -160,6 +162,7 @@ public class BrandingPost ItemStack item = getMapItem(x, y, _img); i.setItem(item); + Bukkit.broadcastMessage(x + " <- X Y -> " + y); _ents.add(i); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureLocation.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureLocation.java index ec1012733..69726109f 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureLocation.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureLocation.java @@ -325,7 +325,8 @@ public class TreasureLocation implements Listener event.setTo(newTo); } } - else + else if (event.getFrom().getWorld().equals(_currentTreasure.getCenterBlock().getWorld()) && + event.getTo().getWorld().equals(_currentTreasure.getCenterBlock().getWorld())) { Location fromLocation = event.getFrom(); Location toLocation = event.getTo(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePageItem.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePageItem.java index dded3fa99..6a68fce5c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePageItem.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/TreasurePageItem.java @@ -1,35 +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; - } -} +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 index 7fe48ca3f..a26b6446c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/NextPageButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/NextPageButton.java @@ -1,32 +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); - } -} +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 index a34b59963..f6684b427 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/PreviousPageButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/gui/pages/PreviousPageButton.java @@ -1,33 +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); - } - -} +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.Core/src/mineplex/core/updater/FileUpdater.java b/Plugins/Mineplex.Core/src/mineplex/core/updater/FileUpdater.java index 71aff9639..be2a4a954 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/updater/FileUpdater.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/updater/FileUpdater.java @@ -6,10 +6,6 @@ import java.io.FilenameFilter; import java.io.IOException; import java.util.Properties; -import mineplex.core.portal.GenericServer; -import mineplex.core.portal.Intent; -import mineplex.core.updater.command.BuildVersionCommand; -import mineplex.core.updater.command.RestartServerCommand; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; @@ -24,7 +20,11 @@ import mineplex.core.MiniPlugin; import mineplex.core.common.util.C; import mineplex.core.common.util.F; import mineplex.core.common.util.NautHashMap; +import mineplex.core.portal.GenericServer; +import mineplex.core.portal.Intent; import mineplex.core.portal.Portal; +import mineplex.core.updater.command.BuildVersionCommand; +import mineplex.core.updater.command.RestartServerCommand; import mineplex.core.updater.event.RestartServerEvent; import mineplex.core.updater.event.UpdateEvent; import mineplex.serverdata.Region; @@ -38,19 +38,21 @@ public class FileUpdater extends MiniPlugin private String _serverName; private Region _region; + private final GenericServer _transferHub; private boolean _needUpdate; private boolean _enabled = true; private Properties _buildProperties; - public FileUpdater(JavaPlugin plugin, Portal portal, String serverName, Region region) + public FileUpdater(JavaPlugin plugin, Portal portal, String serverName, Region region, GenericServer transferHub) { super("File Updater", plugin); _portal = portal; _serverName = serverName; _region = region; + _transferHub = transferHub; GetPluginMd5s(); @@ -81,7 +83,7 @@ public class FileUpdater extends MiniPlugin for (Player player : Bukkit.getOnlinePlayers()) { player.sendMessage(F.main("Updater", message)); - _portal.sendPlayerToGenericServer(player, GenericServer.HUB, Intent.KICK); + _portal.sendPlayerToGenericServer(player, _transferHub, Intent.KICK); } } } @@ -110,7 +112,7 @@ public class FileUpdater extends MiniPlugin { public void run() { - _portal.sendAllPlayersToGenericServer(GenericServer.HUB, Intent.KICK); + _portal.sendAllPlayersToGenericServer(_transferHub, Intent.KICK); } }, 60L); 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 e34fc40b2..8df0e0df1 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java @@ -46,6 +46,7 @@ import mineplex.core.memory.MemoryFix; import mineplex.core.message.MessageManager; import mineplex.core.monitor.LagMeter; import mineplex.core.packethandler.PacketHandler; +import mineplex.core.portal.GenericServer; import mineplex.core.portal.Portal; import mineplex.core.preferences.PreferencesManager; import mineplex.core.punish.Punish; @@ -131,7 +132,7 @@ public class Clans extends JavaPlugin Teleport teleport = new Teleport(this, _clientManager); Portal portal = new Portal(); - new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion()); + new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion(), GenericServer.CLANS_HUB); ClansBanManager clansBans = new ClansBanManager(this, _clientManager, _donationManager); @@ -222,7 +223,7 @@ public class Clans extends JavaPlugin } } - BlockRestore blockRestore = new BlockRestore(this); + BlockRestore blockRestore = require(BlockRestore.class); IgnoreManager ignoreManager = new IgnoreManager(this, _clientManager, preferenceManager, portal); diff --git a/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/ClansHub.java b/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/ClansHub.java index 41e7321b8..8a5c7d1f2 100644 --- a/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/ClansHub.java +++ b/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/ClansHub.java @@ -4,7 +4,6 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.plugin.java.JavaPlugin; -import mineplex.core.common.Constants; import mineplex.core.CustomTagFix; import mineplex.core.PacketsInteractionFix; import mineplex.core.account.CoreClientManager; @@ -39,6 +38,7 @@ import mineplex.core.packethandler.PacketHandler; import mineplex.core.party.PartyManager; import mineplex.core.pet.PetManager; import mineplex.core.poll.PollManager; +import mineplex.core.portal.GenericServer; import mineplex.core.portal.Portal; import mineplex.core.preferences.PreferencesManager; import mineplex.core.profileCache.ProfileCacheManager; @@ -71,14 +71,18 @@ import static mineplex.core.Managers.require; */ public class ClansHub extends JavaPlugin { + private String WEB_CONFIG = "webServer"; + @Override public void onEnable() { Bukkit.setSpawnRadius(0); - getConfig().addDefault(Constants.WEB_CONFIG_KEY, Constants.WEB_ADDRESS); - getConfig().set(Constants.WEB_CONFIG_KEY, getConfig().getString(Constants.WEB_CONFIG_KEY)); + getConfig().addDefault(WEB_CONFIG, "http://accounts.mineplex.com/"); + getConfig().set(WEB_CONFIG, getConfig().getString(WEB_CONFIG)); saveConfig(); + String webServerAddress = getConfig().getString(WEB_CONFIG); + //Logger.initialize(this); //Velocity Fix @@ -95,7 +99,7 @@ public class ClansHub extends JavaPlugin Recharge.Initialize(this); VisibilityManager.Initialize(this); Give.Initialize(this); Punish punish = new Punish(this, clientManager); - BlockRestore blockRestore = new BlockRestore(this); + BlockRestore blockRestore = require(BlockRestore.class); DonationManager donationManager = require(DonationManager.class); ServerConfiguration serverConfiguration = new ServerConfiguration(this, clientManager); @@ -153,7 +157,7 @@ public class ClansHub extends JavaPlugin Chat chat = new Chat(this, incognito, clientManager, preferenceManager, achievementManager, serverStatusManager.getCurrentServerName()); new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, friendManager, chat); new MemoryFix(this); - new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion()); + new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion(), GenericServer.CLANS_HUB); new CustomTagFix(this, packetHandler); new PacketsInteractionFix(this, packetHandler); new ResourcePackManager(this, portal); diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java index eaaff57d0..0b6e830e6 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java @@ -5,7 +5,6 @@ import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; -import mineplex.core.common.Constants; import mineplex.core.CustomTagFix; import mineplex.core.PacketsInteractionFix; import mineplex.core.account.CoreClientManager; @@ -22,6 +21,7 @@ import mineplex.core.chatsnap.SnapshotManager; import mineplex.core.chatsnap.SnapshotPlugin; import mineplex.core.chatsnap.SnapshotRepository; import mineplex.core.command.CommandCenter; +import mineplex.core.common.Constants; import mineplex.core.common.events.ServerShutdownEvent; import mineplex.core.creature.Creature; import mineplex.core.customdata.CustomDataManager; @@ -47,6 +47,7 @@ import mineplex.core.party.PartyManager; import mineplex.core.personalServer.PersonalServerManager; import mineplex.core.pet.PetManager; import mineplex.core.poll.PollManager; +import mineplex.core.portal.GenericServer; import mineplex.core.portal.Portal; import mineplex.core.preferences.PreferencesManager; import mineplex.core.profileCache.ProfileCacheManager; @@ -116,7 +117,7 @@ public class Hub extends JavaPlugin implements IRelation Recharge.Initialize(this); VisibilityManager.Initialize(this); Give.Initialize(this); Punish punish = new Punish(this, clientManager); - BlockRestore blockRestore = new BlockRestore(this); + BlockRestore blockRestore = require(BlockRestore.class); DonationManager donationManager = require(DonationManager.class); ServerConfiguration serverConfiguration = new ServerConfiguration(this, clientManager); @@ -182,7 +183,7 @@ public class Hub extends JavaPlugin implements IRelation Chat chat = new Chat(this, incognito, clientManager, preferenceManager, achievementManager, serverStatusManager.getCurrentServerName()); new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, friendManager, chat); new MemoryFix(this); - new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion()); + new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion(), GenericServer.HUB); new CustomTagFix(this, packetHandler); new PacketsInteractionFix(this, packetHandler); new ResourcePackManager(this, portal); @@ -225,7 +226,7 @@ public class Hub extends JavaPlugin implements IRelation //Updates getServer().getScheduler().scheduleSyncRepeatingTask(this, new Updater(this), 1, 1); - BrandingManager brandingManager = new BrandingManager(this); + BrandingManager brandingManager = require(BrandingManager.class); new BillboardManager(this, brandingManager); require(TrackManager.class); diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/modules/BillboardManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/modules/BillboardManager.java index adfa01b62..d1dd5df72 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/modules/BillboardManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/modules/BillboardManager.java @@ -4,9 +4,6 @@ import mineplex.core.MiniPlugin; import mineplex.core.common.events.ServerShutdownEvent; import mineplex.core.sponsorbranding.BrandingManager; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.block.BlockFace; import org.bukkit.entity.ItemFrame; import org.bukkit.event.EventHandler; import org.bukkit.event.entity.EntityDamageEvent; diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/modules/NewsManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/modules/NewsManager.java index 2e1c958d6..0679e29ba 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/modules/NewsManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/modules/NewsManager.java @@ -253,6 +253,9 @@ public class NewsManager extends MiniPlugin { if (event.getType() != UpdateType.FASTEST) return; + + if (_news.length == 0) + return; String text = ""; double healthPercent = 1; diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/StaffServer.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/StaffServer.java index db45f77f7..78526833a 100644 --- a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/StaffServer.java +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/StaffServer.java @@ -1,12 +1,21 @@ package mineplex.staffServer; +import java.util.UUID; + +import net.minecraft.server.v1_8_R3.MinecraftServer; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_8_R3.CraftServer; +import org.bukkit.plugin.java.JavaPlugin; +import org.spigotmc.SpigotConfig; + import com.mojang.authlib.GameProfile; -import mineplex.core.common.Constants; import mineplex.core.account.CoreClientManager; import mineplex.core.achievement.AchievementManager; import mineplex.core.chat.Chat; import mineplex.core.command.CommandCenter; +import mineplex.core.common.Constants; import mineplex.core.common.Rank; import mineplex.core.creature.Creature; import mineplex.core.disguise.DisguiseManager; @@ -17,6 +26,7 @@ import mineplex.core.memory.MemoryFix; import mineplex.core.monitor.LagMeter; import mineplex.core.npc.NpcManager; import mineplex.core.packethandler.PacketHandler; +import mineplex.core.portal.GenericServer; import mineplex.core.portal.Portal; import mineplex.core.powerplayclub.PowerPlayClubRepository; import mineplex.core.preferences.PreferencesManager; @@ -29,13 +39,6 @@ import mineplex.core.updater.FileUpdater; import mineplex.core.updater.Updater; import mineplex.staffServer.customerSupport.CustomerSupport; import mineplex.staffServer.salespackage.SalesPackageManager; -import net.minecraft.server.v1_8_R3.MinecraftServer; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_8_R3.CraftServer; -import org.bukkit.plugin.java.JavaPlugin; -import org.spigotmc.SpigotConfig; - -import java.util.UUID; import static mineplex.core.Managers.require; @@ -67,7 +70,7 @@ public class StaffServer extends JavaPlugin StatsManager statsManager = new StatsManager(this, clientManager); new Chat(this, null, clientManager, preferenceManager, new AchievementManager(statsManager, clientManager, donationManager, null, eloManager), serverStatusManager.getCurrentServerName()); new MemoryFix(this); - new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion()); + new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion(), GenericServer.HUB); require(PacketHandler.class); require(DisguiseManager.class); diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/salespackages/MinestrikeChest.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/salespackages/MinestrikeChest.java index 7f984e12d..20af53a5d 100644 --- a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/salespackages/MinestrikeChest.java +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/salespackage/salespackages/MinestrikeChest.java @@ -1,20 +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); - } +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.UHC.WorldGen/src/nautilus/game/arcade/uhc/WorldGen.java b/Plugins/Nautilus.Game.Arcade.UHC.WorldGen/src/nautilus/game/arcade/uhc/WorldGen.java index 2dd1a54be..24d2483e7 100644 --- a/Plugins/Nautilus.Game.Arcade.UHC.WorldGen/src/nautilus/game/arcade/uhc/WorldGen.java +++ b/Plugins/Nautilus.Game.Arcade.UHC.WorldGen/src/nautilus/game/arcade/uhc/WorldGen.java @@ -1,69 +1,138 @@ package nautilus.game.arcade.uhc; -import net.minecraft.server.v1_8_R3.BiomeBase; -import org.apache.commons.io.FileUtils; -import org.bukkit.Bukkit; -import org.bukkit.Difficulty; -import org.bukkit.World; -import org.bukkit.WorldCreator; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.AsyncPlayerPreLoginEvent; -import org.bukkit.plugin.java.JavaPlugin; -import org.spigotmc.WatchdogThread; -import org.zeroturnaround.zip.ZipEntrySource; -import org.zeroturnaround.zip.ZipUtil; - -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ThreadLocalRandom; import java.util.logging.Level; -import java.util.zip.ZipEntry; -public class WorldGen extends JavaPlugin implements Runnable, Listener +import net.minecraft.server.v1_8_R3.BiomeBase; + +import org.apache.commons.io.FileUtils; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Difficulty; +import org.bukkit.World; +import org.bukkit.WorldBorder; +import org.bukkit.WorldCreator; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.entity.Entity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.event.world.WorldInitEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.spigotmc.WatchdogThread; +import org.zeroturnaround.zip.ByteSource; +import org.zeroturnaround.zip.FileSource; +import org.zeroturnaround.zip.ZipEntrySource; +import org.zeroturnaround.zip.ZipUtil; +import org.zeroturnaround.zip.commons.IOUtils; + +public class WorldGen extends JavaPlugin implements Listener { - private static final int MIN_X = -1000; - private static final int MIN_Z = -1000; - private static final int MAX_X = 1000; - private static final int MAX_Z = 1000; + // The world will be -MAP_SIZE to MAP_SIZE large + private static final int MAP_SIZE = 1000; private static final int VIEW_DISTANCE = 5; + private static final String API_HOST_FILE = "api-config.dat"; + private static final Map API_HOST_MAP = new HashMap<>(); + + static + { + try + { + File configFile = new File(API_HOST_FILE); + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configFile); + + for (String key : configuration.getKeys(false)) + { + String ip = configuration.getConfigurationSection(key).getString("ip"); + // Use parseInt to catch non-ints instead of a 0 + int port = Integer.parseInt(configuration.getConfigurationSection(key).getString("port")); + if (ip == null) + { + throw new NullPointerException(); + } + + API_HOST_MAP.put(key, ip + ":" + port); + } + } + catch (Throwable t) + { + t.printStackTrace(); + } + } + + @EventHandler + public void login(AsyncPlayerPreLoginEvent event) + { + event.setKickMessage("get out"); + event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); + } + + @EventHandler + public void unload(ChunkUnloadEvent event) + { + event.setCancelled(true); + } + + @EventHandler + public void init(WorldInitEvent event) + { + // Prevent any eager generation + event.getWorld().setKeepSpawnInMemory(false); + } + @Override public void onEnable() { + getLogger().info("Cleaning up other worlds"); + for (World world : getServer().getWorlds()) + { + world.setKeepSpawnInMemory(false); + world.setSpawnFlags(false, false); + world.setAmbientSpawnLimit(0); + world.setAnimalSpawnLimit(0); + world.setMonsterSpawnLimit(0); + world.setWaterAnimalSpawnLimit(0); + world.getEntities().forEach(Entity::remove); + for (Chunk chunk : world.getLoadedChunks()) + { + chunk.unload(false, false); + } + getServer().unloadWorld(world, false); + getLogger().info("Unloaded " + world.getName()); + } + + getLogger().info("Replacing biomes"); BiomeBase.getBiomes()[BiomeBase.OCEAN.id] = BiomeBase.PLAINS; BiomeBase.getBiomes()[BiomeBase.DEEP_OCEAN.id] = BiomeBase.PLAINS; BiomeBase.getBiomes()[BiomeBase.SWAMPLAND.id] = BiomeBase.PLAINS; BiomeBase.getBiomes()[BiomeBase.RIVER.id] = BiomeBase.PLAINS; + getLogger().info("Forcing system GC"); + System.gc(); + WatchdogThread.doStop(); - getServer().getScheduler().runTaskTimer(this, this, 20L, 20L * 5L); getServer().getPluginManager().registerEvents(this, this); - } - @EventHandler - public void onJoin(AsyncPlayerPreLoginEvent event) - { - event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); - event.setKickMessage("Shoo, go away"); - } - - @Override - public void run() - { File root = new File("."); if (!root.exists()) { getLogger().severe("Root folder does not exist. Aborting"); - getServer().shutdown(); + System.exit(0); return; } @@ -73,7 +142,7 @@ public class WorldGen extends JavaPlugin implements Runnable, Listener if (!outputDirectory.mkdir()) { getLogger().severe("Could not create output folder. Aborting"); - getServer().shutdown(); + System.exit(0); return; } } @@ -85,6 +154,7 @@ public class WorldGen extends JavaPlugin implements Runnable, Listener if (outputFile.exists()) { getLogger().info("Seed " + seed + " has already been generated. Skipping"); + System.exit(0); return; } @@ -93,30 +163,52 @@ public class WorldGen extends JavaPlugin implements Runnable, Listener if (!outputFile.createNewFile()) { getLogger().severe("Could not create new output file. Aborting"); - getServer().shutdown(); + System.exit(0); return; } } catch (IOException e) { getLogger().log(Level.SEVERE, "Could not create new output file. Aborting", e); - getServer().shutdown(); + System.exit(0); return; } + File previousSession = new File("generating"); + + if (previousSession.exists()) + { + if (!FileUtils.deleteQuietly(previousSession)) + { + getLogger().severe("Could not delete previous generation session. Aborting"); + System.exit(0); + return; + } + } + getLogger().info("Generating world seed " + seed); World world = new WorldCreator("generating") .environment(World.Environment.NORMAL) .seed(seed) .createWorld(); - world.setDifficulty(Difficulty.HARD); world.setKeepSpawnInMemory(false); + world.setDifficulty(Difficulty.HARD); + WorldBorder border = world.getWorldBorder(); + border.setCenter(0.0, 0.0); + border.setSize(MAP_SIZE * 2); - int minChunkX = (MIN_X >> 4) - VIEW_DISTANCE; - int minChunkZ = (MIN_Z >> 4) - VIEW_DISTANCE; - int maxChunkX = (MAX_X >> 4) + VIEW_DISTANCE; - int maxChunkZ = (MAX_Z >> 4) + VIEW_DISTANCE; + int minChunkX = (-MAP_SIZE >> 4) - VIEW_DISTANCE; + int minChunkZ = (-MAP_SIZE >> 4) - VIEW_DISTANCE; + int maxChunkX = (MAP_SIZE >> 4) + VIEW_DISTANCE; + int maxChunkZ = (MAP_SIZE >> 4) + VIEW_DISTANCE; + + net.minecraft.server.v1_8_R3.WorldServer nmsWorld = ((CraftWorld) world).getHandle(); +// +// Field mfield = nmsWorld.getClass().getDeclaredField("M"); +// mfield.setAccessible(true); +// +// HashTreeSet treeSet = ((HashTreeSet) mfield.get(nmsWorld)); for (int x = minChunkX; x <= maxChunkX; x++) { @@ -124,7 +216,15 @@ public class WorldGen extends JavaPlugin implements Runnable, Listener for (int z = minChunkZ; z <= maxChunkZ; z++) { world.getChunkAt(x, z).load(true); + nmsWorld.a(true); + // Manually tick blocks - this should be the equivalent of letting a full server tick run once + // between each chunk generation, except we cut out the extra useless stuff } + +// System.out.println("M: " + treeSet.size()); +// System.out.println("E: " + nmsWorld.entityList.size()); +// System.out.println("TE: " + nmsWorld.tileEntityList.size()); +// System.out.println("C: " + nmsWorld.chunkProviderServer.chunks.size()); } for (int x = minChunkX; x <= maxChunkX; x++) @@ -134,6 +234,11 @@ public class WorldGen extends JavaPlugin implements Runnable, Listener { world.getChunkAt(x, z).unload(true, false); } + +// System.out.println("M: " + treeSet.size()); +// System.out.println("E: " + nmsWorld.entityList.size()); +// System.out.println("TE: " + nmsWorld.tileEntityList.size()); +// System.out.println("C: " + nmsWorld.chunkProviderServer.chunks.size()); } getLogger().info("Unloading and saving world"); @@ -145,10 +250,10 @@ public class WorldGen extends JavaPlugin implements Runnable, Listener StringBuilder worldconfig = new StringBuilder(); worldconfig.append("MAP_NAME:UHC World").append(System.lineSeparator()); worldconfig.append("MAP_AUTHOR:Mineplex").append(System.lineSeparator()); - worldconfig.append("MIN_X:").append(MIN_X).append(System.lineSeparator()); - worldconfig.append("MIN_Z:").append(MIN_Z).append(System.lineSeparator()); - worldconfig.append("MAX_X:").append(MAX_X).append(System.lineSeparator()); - worldconfig.append("MAX_Z:").append(MAX_Z).append(System.lineSeparator()); + worldconfig.append("MIN_X:").append(-MAP_SIZE).append(System.lineSeparator()); + worldconfig.append("MIN_Z:").append(-MAP_SIZE).append(System.lineSeparator()); + worldconfig.append("MAX_X:").append(MAP_SIZE).append(System.lineSeparator()); + worldconfig.append("MAX_Z:").append(MAP_SIZE).append(System.lineSeparator()); for (int i = 1; i <= 60; i++) { worldconfig.append("TEAM_NAME:").append(i).append(System.lineSeparator()); @@ -164,82 +269,68 @@ public class WorldGen extends JavaPlugin implements Runnable, Listener if (regionFiles == null) { getLogger().severe("Unexpected null region files. Aborting"); - getServer().shutdown(); + System.exit(0); return; } List zipEntrySourceList = new ArrayList<>(); - zipEntrySourceList.add(new ZipEntrySource() - { - @Override - public String getPath() - { - return "WorldConfig.dat"; - } - - @Override - public ZipEntry getEntry() - { - return new ZipEntry(getPath()); - } - - @Override - public InputStream getInputStream() throws IOException - { - return new ByteArrayInputStream(worldconfig.toString().getBytes(StandardCharsets.UTF_8)); - } - }); - - + zipEntrySourceList.add(new ByteSource("WorldConfig.dat", worldconfig.toString().getBytes(StandardCharsets.UTF_8))); for (File file : regionFiles) { - zipEntrySourceList.add(new ZipEntrySource() - { - @Override - public String getPath() - { - return "region/" + file.getName(); - } - - @Override - public ZipEntry getEntry() - { - return new ZipEntry(getPath()); - } - - @Override - public InputStream getInputStream() throws IOException - { - return new FileInputStream(file); - } - }); + zipEntrySourceList.add(new FileSource("region/" + file.getName(), file)); } - - zipEntrySourceList.add(new ZipEntrySource() - { - @Override - public String getPath() - { - return "level.dat"; - } - - @Override - public ZipEntry getEntry() - { - return new ZipEntry(getPath()); - } - - @Override - public InputStream getInputStream() throws IOException - { - return new FileInputStream(new File(worldFolder, "level.dat")); - } - }); + zipEntrySourceList.add(new FileSource("level.dat", new File(worldFolder, "level.dat"))); ZipUtil.pack(zipEntrySourceList.toArray(new ZipEntrySource[zipEntrySourceList.size()]), outputFile); FileUtils.deleteQuietly(worldFolder); - getLogger().info("Finished generating world seed " + seed); + try + { + getLogger().info("Uploading " + seed + "!"); + + URL url = new URL("http://" + API_HOST_MAP.get("ENDERCHEST") + "/map/uhc/upload?name=" + outputFile.getName()); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setDoOutput(true); + IOUtils.copy(new FileInputStream(outputFile), connection.getOutputStream()); + connection.connect(); + + if (connection.getResponseCode() != 200) + { + if (connection.getResponseCode() == 409) + { + getLogger().warning("Oops - Server rejected " + seed + " because it was already generated"); + + if (!outputFile.delete()) + { + getLogger().warning("Could not clean up " + seed); + } + } + else + { + getLogger().severe("Failed to upload " + seed + ": " + connection.getResponseCode() + " " + connection.getResponseMessage()); + } + } + else + { + getLogger().info("Uploaded " + seed + "!"); + + if (!outputFile.delete()) + { + getLogger().warning("Could not clean up " + seed); + } + } + } + catch (IOException e) + { + getLogger().log(Level.SEVERE, "An error occurred while uploading " + seed + "!", e); + } + finally + { + getLogger().info("Finished generating world seed " + seed); + } + + Bukkit.shutdown(); } } 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 152a6b8d1..634c33d01 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java @@ -10,12 +10,10 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import org.spigotmc.SpigotConfig; -import mineplex.core.common.Constants; import mineplex.core.CustomTagFix; import mineplex.core.FoodDupeFix; import mineplex.core.PacketsInteractionFix; import mineplex.core.TimingsFix; - import mineplex.core.account.CoreClientManager; import mineplex.core.achievement.AchievementManager; import mineplex.core.antihack.AntiHack; @@ -28,6 +26,7 @@ import mineplex.core.chatsnap.SnapshotManager; import mineplex.core.chatsnap.SnapshotPlugin; import mineplex.core.chatsnap.SnapshotRepository; import mineplex.core.command.CommandCenter; +import mineplex.core.common.Constants; import mineplex.core.common.events.ServerShutdownEvent; import mineplex.core.common.util.FileUtil; import mineplex.core.common.util.UtilServer; @@ -55,6 +54,7 @@ import mineplex.core.npc.NpcManager; import mineplex.core.packethandler.PacketHandler; import mineplex.core.pet.PetManager; import mineplex.core.poll.PollManager; +import mineplex.core.portal.GenericServer; import mineplex.core.portal.Portal; import mineplex.core.preferences.PreferencesManager; import mineplex.core.profileCache.ProfileCacheManager; @@ -138,7 +138,7 @@ public class Arcade extends JavaPlugin LeaderboardManager leaderboardManager = new LeaderboardManager(this, _clientManager); Teleport teleport = new Teleport(this, _clientManager); Portal portal = new Portal(); - new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion()); + new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion(), GenericServer.HUB); DisguiseManager disguiseManager = require(DisguiseManager.class); @@ -162,7 +162,7 @@ public class Arcade extends JavaPlugin new SnapshotPlugin(this, snapshotManager, _clientManager); new ReportPlugin(this, reportManager); - BlockRestore blockRestore = new BlockRestore(this); + BlockRestore blockRestore = require(BlockRestore.class); ProjectileManager projectileManager = new ProjectileManager(this); HologramManager hologramManager = new HologramManager(this, packetHandler); 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 c5112ac40..4b23bcc18 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java @@ -288,7 +288,7 @@ public class ArcadeManager extends MiniPlugin implements IRelation _conditionManager = new SkillConditionManager(plugin); - _brandingManager = new BrandingManager(plugin); + _brandingManager = require(BrandingManager.class); _boosterManager = boosterManager; 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 index 50a4b4bf6..bc17eb83d 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/command/TauntCommand.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/command/TauntCommand.java @@ -1,51 +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); - } - - -} +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/games/minestrike/Minestrike.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/minestrike/Minestrike.java index 088a6f1ef..b5d69dd75 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/minestrike/Minestrike.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/minestrike/Minestrike.java @@ -414,22 +414,29 @@ public class Minestrike extends TeamGame int amount; String gunType = (String) event.GetLog().GetLastDamager().GetDamage().getFirst().getMetadata().get("gunType"); - switch (gunType) + if (gunType == null) { - case "AWP": - amount = 100; - break; - case "PPBIZON": - amount = 600; - break; - case "NOVA": - amount = 900; - break; - case "KNIFE": - amount = 1500; - break; - default: - amount = 300; + amount = 300; + } + else + { + switch (gunType) + { + case "AWP": + amount = 100; + break; + case "PPBIZON": + amount = 600; + break; + case "NOVA": + amount = 900; + break; + case "KNIFE": + amount = 1500; + break; + default: + amount = 300; + } } _shopManager.addMoney(killer, amount, "kill with " + event.GetLog().GetLastDamager().GetReason()); diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/skeletalhorse/PerkBoneRush.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/skeletalhorse/PerkBoneRush.java index 4fc78ea1b..f1d281713 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/skeletalhorse/PerkBoneRush.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/skeletalhorse/PerkBoneRush.java @@ -193,7 +193,7 @@ public class PerkBoneRush extends SmashPerk implements IThrown return; } - if (!(target instanceof Player || data.getThrower() instanceof Player)) + if (!(target instanceof Player) || !(data.getThrower() instanceof Player)) { return; } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/squid/PerkFishFlurry.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/squid/PerkFishFlurry.java index 539e98cf9..184f1b135 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/squid/PerkFishFlurry.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/squid/PerkFishFlurry.java @@ -102,11 +102,6 @@ public class PerkFishFlurry extends SmashPerk implements IThrown return; } - if (!Recharge.Instance.use(player, GetName(), COOLDOWN, true, true)) - { - return; - - } event.setCancelled(true); Set blocks = new HashSet<>(); @@ -131,10 +126,18 @@ public class PerkFishFlurry extends SmashPerk implements IThrown blocks.add(cur); } - _active.add(new DataSquidGeyser(player, blocks)); + if (!blocks.isEmpty()) + { + if (!Recharge.Instance.use(player, GetName(), COOLDOWN, true, true)) + { + return; + } - // Inform - UtilPlayer.message(player, F.main("Game", "You used " + F.skill(GetName()) + ".")); + _active.add(new DataSquidGeyser(player, blocks)); + + // Inform + UtilPlayer.message(player, F.main("Game", "You used " + F.skill(GetName()) + ".")); + } } @EventHandler diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/witherskeleton/PerkWitherImage.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/witherskeleton/PerkWitherImage.java index 6c09145df..ba5a90767 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/witherskeleton/PerkWitherImage.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/witherskeleton/PerkWitherImage.java @@ -169,7 +169,7 @@ public class PerkWitherImage extends SmashPerk } } - if (event.getTarget() != null && _skeletons.get(event.getTarget().getUniqueId()).equals(event.getEntity())) + if (event.getTarget() != null && event.getEntity().equals(_skeletons.get(event.getTarget().getUniqueId()))) { event.setCancelled(true); } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/wolf/PerkWolf.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/wolf/PerkWolf.java index 4482fa932..a5968ac4e 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/wolf/PerkWolf.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/smash/perks/wolf/PerkWolf.java @@ -503,6 +503,12 @@ public class PerkWolf extends SmashPerk UUID uuid = playerIterator.next(); Player player = UtilPlayer.searchExact(uuid); + if (player == null) + { + playerIterator.remove(); + continue; + } + Iterator timeIterator = _repeat.get(uuid).iterator(); while (timeIterator.hasNext()) diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/UHC.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/UHC.java index e79c8f261..3e5b66bc6 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/UHC.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/UHC.java @@ -365,17 +365,19 @@ public abstract class UHC extends Game UtilPlayer.message(caller, F.main("Debug", "World info for " + targetWorld.getName())); UtilPlayer.message(caller, F.desc("Chunks", String.valueOf(chunks.length))); UtilPlayer.message(caller, F.desc("Entities", String.valueOf(targetWorld.getEntities().size()))); - UtilPlayer.message(caller, F.desc("Tile Entities", String.valueOf(Arrays.stream(chunks).map(Chunk::getTileEntities).map(Arrays::asList).flatMap(Collection::stream) - .count()))); + UtilPlayer.message(caller, F.desc("Tile Entities", String.valueOf(Arrays.stream(chunks).map(Chunk::getTileEntities).map(Arrays::asList).mapToLong(Collection::size).sum()))); UtilPlayer.message(caller, F.desc("View Distance", String.valueOf(nmsWorld.spigotConfig.viewDistance))); UtilPlayer.message(caller, F.desc("Unload queue size", String.valueOf(nmsWorld.chunkProviderServer.unloadQueue.size()))); try { - HashTreeSet m = (HashTreeSet) nmsWorld.getClass().getField("M").get(nmsWorld); + Field f = nmsWorld.getClass().getDeclaredField("M"); + f.setAccessible(true); + HashTreeSet m = (HashTreeSet) f.get(nmsWorld); + UtilPlayer.message(caller, F.desc("Pending tick", String.valueOf(m.size()))); } - catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) + catch (ReflectiveOperationException e) { e.printStackTrace(); } @@ -571,7 +573,7 @@ public abstract class UHC extends Game } } }); - registerDebugCommand(new DebugCommand("uhccallchunks", Rank.DEVELOPER) + registerDebugCommand(new DebugCommand("uhcallchunks", Rank.DEVELOPER) { @Override diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/wither/WitherGame.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/wither/WitherGame.java index cf3e5eaa7..fb69f56f2 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/wither/WitherGame.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/wither/WitherGame.java @@ -255,11 +255,15 @@ public class WitherGame extends TeamGame implements IBlockRestorer if (GetState() == GameState.Recruit || GetState() == GameState.Prepare) { Projectile proj = event.getEntity(); - WitherSkull ws = (WitherSkull) proj; - if (ws.getShooter() instanceof Wither) + if (proj instanceof WitherSkull) { - event.setCancelled(true); + WitherSkull ws = (WitherSkull) proj; + + if (ws.getShooter() instanceof Wither) + { + event.setCancelled(true); + } } } } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/ProgressingKitManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/ProgressingKitManager.java index b092d0a17..2ce6c2ac3 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/ProgressingKitManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/ProgressingKitManager.java @@ -157,12 +157,15 @@ public class ProgressingKitManager implements Listener PlayerKit playerKit = _manager.getKitProgressionManager().getDataManager().get(player.getUniqueId()); try { - for (Kit kit : _manager.GetGame().GetKits()) + if (_manager.GetGame() != null) { - if (kit instanceof ProgressingKit) + for (Kit kit : _manager.GetGame().GetKits()) { - ProgressingKit progressingKit = (ProgressingKit) kit; - _manager.getKitProgressionManager().getRepository().insertOrUpdate(playerKit, progressingKit.getInternalName()); + if (kit instanceof ProgressingKit) + { + ProgressingKit progressingKit = (ProgressingKit) kit; + _manager.getKitProgressionManager().getRepository().insertOrUpdate(playerKit, progressingKit.getInternalName()); + } } } } diff --git a/Plugins/Nautilus.Game.PvP/src/nautilus/game/pvp/PvP.java b/Plugins/Nautilus.Game.PvP/src/nautilus/game/pvp/PvP.java index cfe3add2b..d6732cbad 100644 --- a/Plugins/Nautilus.Game.PvP/src/nautilus/game/pvp/PvP.java +++ b/Plugins/Nautilus.Game.PvP/src/nautilus/game/pvp/PvP.java @@ -328,7 +328,7 @@ public class PvP extends JavaPlugin implements IPlugin, Listener public BlockRestore GetBlockRestore() { if (_blockRestore == null) - _blockRestore = new BlockRestore(this); + _blockRestore = require(BlockRestore.class); return _blockRestore; } diff --git a/Plugins/mavericks-review-hub/src/mineplex/mavericks/review/Hub.java b/Plugins/mavericks-review-hub/src/mineplex/mavericks/review/Hub.java index e36c7cfea..7648a03bd 100644 --- a/Plugins/mavericks-review-hub/src/mineplex/mavericks/review/Hub.java +++ b/Plugins/mavericks-review-hub/src/mineplex/mavericks/review/Hub.java @@ -38,6 +38,7 @@ import mineplex.core.monitor.LagMeter; import mineplex.core.mount.MountManager; import mineplex.core.packethandler.PacketHandler; import mineplex.core.pet.PetManager; +import mineplex.core.portal.GenericServer; import mineplex.core.portal.Portal; import mineplex.core.preferences.PreferencesManager; import mineplex.core.profileCache.ProfileCacheManager; @@ -102,7 +103,7 @@ public class Hub extends JavaPlugin Creature creature = new Creature(this); ServerStatusManager serverStatusManager = new ServerStatusManager(this, _clientManager, new LagMeter(this, _clientManager)); Portal portal = new Portal(); - new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion()); + new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion(), GenericServer.HUB); DisguiseManager disguiseManager = require(DisguiseManager.class); @@ -117,7 +118,7 @@ public class Hub extends JavaPlugin Chat chat = new Chat(this, incognito, _clientManager, preferenceManager, achievementManager, serverStatusManager.getCurrentServerName()); new MessageManager(this, incognito, _clientManager, preferenceManager, ignoreManager, punish, friendManager, chat); - BlockRestore blockRestore = new BlockRestore(this); + BlockRestore blockRestore = require(BlockRestore.class); ProjectileManager projectileManager = new ProjectileManager(this); HologramManager hologramManager = new HologramManager(this, packetHandler); diff --git a/Plugins/mineplex-game-gemhunters/plugin.yml b/Plugins/mineplex-game-gemhunters/plugin.yml new file mode 100644 index 000000000..4f013d203 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/plugin.yml @@ -0,0 +1,5 @@ +name: GemHunters +main: mineplex.gemhunters.GemHunters +version: 0.1 +commands: + playwire: \ No newline at end of file diff --git a/Plugins/mineplex-game-gemhunters/pom.xml b/Plugins/mineplex-game-gemhunters/pom.xml new file mode 100644 index 000000000..16129c057 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/pom.xml @@ -0,0 +1,27 @@ + + 4.0.0 + + + com.mineplex + mineplex-plugin + dev-SNAPSHOT + ../plugin.xml + + + GemHunters + mineplex-game-gemhunters + + + + ${project.groupId} + mineplex-core + ${project.version} + + + ${project.groupId} + mineplex-minecraft-game-core + ${project.version} + + + \ No newline at end of file diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/GemHunters.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/GemHunters.java new file mode 100644 index 000000000..3bd9b2550 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/GemHunters.java @@ -0,0 +1,313 @@ +package mineplex.gemhunters; + +import net.minecraft.server.v1_8_R3.MinecraftServer; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.plugin.java.JavaPlugin; +import org.spigotmc.SpigotConfig; + +import mineplex.core.CustomTagFix; +import mineplex.core.FoodDupeFix; +import mineplex.core.TimingsFix; +import mineplex.core.account.CoreClientManager; +import mineplex.core.achievement.AchievementManager; +import mineplex.core.antihack.AntiHack; +import mineplex.core.beta.BetaWhitelist; +import mineplex.core.blockrestore.BlockRestore; +import mineplex.core.boosters.BoosterManager; +import mineplex.core.chat.Chat; +import mineplex.core.command.CommandCenter; +import mineplex.core.common.Constants; +import mineplex.core.common.events.ServerShutdownEvent; +import mineplex.core.communities.CommunityManager; +import mineplex.core.cosmetic.CosmeticManager; +import mineplex.core.creature.Creature; +import mineplex.core.delayedtask.DelayedTask; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.donation.DonationManager; +import mineplex.core.elo.EloManager; +import mineplex.core.explosion.Explosion; +import mineplex.core.friend.FriendManager; +import mineplex.core.gadget.GadgetManager; +import mineplex.core.give.Give; +import mineplex.core.hologram.HologramManager; +import mineplex.core.ignore.IgnoreManager; +import mineplex.core.incognito.IncognitoManager; +import mineplex.core.inventory.InventoryManager; +import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.memory.MemoryFix; +import mineplex.core.menu.MenuManager; +import mineplex.core.message.MessageManager; +import mineplex.core.monitor.LagMeter; +import mineplex.core.mount.MountManager; +import mineplex.core.npc.NpcManager; +import mineplex.core.packethandler.PacketHandler; +import mineplex.core.party.PartyManager; +import mineplex.core.pet.PetManager; +import mineplex.core.portal.GenericServer; +import mineplex.core.portal.Portal; +import mineplex.core.powerplayclub.PowerPlayClubRepository; +import mineplex.core.preferences.PreferencesManager; +import mineplex.core.projectile.ProjectileManager; +import mineplex.core.punish.Punish; +import mineplex.core.recharge.Recharge; +import mineplex.core.serverConfig.ServerConfiguration; +import mineplex.core.stats.StatsManager; +import mineplex.core.status.ServerStatusManager; +import mineplex.core.teleport.Teleport; +import mineplex.core.thank.ThankManager; +import mineplex.core.twofactor.TwoFactorAuth; +import mineplex.core.updater.FileUpdater; +import mineplex.core.updater.Updater; +import mineplex.core.visibility.VisibilityManager; +import mineplex.gemhunters.beta.BetaModule; +import mineplex.gemhunters.bounties.BountyModule; +import mineplex.gemhunters.chat.ChatModule; +import mineplex.gemhunters.death.DeathModule; +import mineplex.gemhunters.death.npc.NPCManager; +import mineplex.gemhunters.economy.CashOutModule; +import mineplex.gemhunters.economy.EconomyModule; +import mineplex.gemhunters.loot.InventoryModule; +import mineplex.gemhunters.loot.LootModule; +import mineplex.gemhunters.map.ItemMapModule; +import mineplex.gemhunters.mount.MountModule; +import mineplex.gemhunters.quest.QuestModule; +import mineplex.gemhunters.safezone.SafezoneModule; +import mineplex.gemhunters.scoreboard.ScoreboardModule; +import mineplex.gemhunters.shop.ShopModule; +import mineplex.gemhunters.spawn.SpawnModule; +import mineplex.gemhunters.supplydrop.SupplyDropModule; +import mineplex.gemhunters.world.DebugListeners; +import mineplex.gemhunters.world.TimeCycle; +import mineplex.gemhunters.world.UndergroundMobs; +import mineplex.gemhunters.world.WorldListeners; +import mineplex.gemhunters.worldevent.WorldEventModule; +import mineplex.minecraft.game.core.combat.CombatManager; +import mineplex.minecraft.game.core.condition.ConditionManager; +import mineplex.minecraft.game.core.damage.DamageManager; + +import static mineplex.core.Managers.require; + +/** + * Gem Hunters main class
+ * + * TODO make documentation and a nice header + * + * @author Sam + */ +public class GemHunters extends JavaPlugin +{ + + @Override + public void onEnable() + { + // Load configuration + getConfig().addDefault(Constants.WEB_CONFIG_KEY, Constants.WEB_ADDRESS); + getConfig().set(Constants.WEB_CONFIG_KEY, getConfig().getString(Constants.WEB_CONFIG_KEY)); + saveConfig(); + + // Load core modules + CommandCenter.Initialize(this); + + // Client Manager + CoreClientManager clientManager = new CoreClientManager(this); + + // Donation Manager + DonationManager donationManager = require(DonationManager.class); + + // Command Centre + CommandCenter.Instance.setClientManager(clientManager); + + // Timings + require(TimingsFix.class); + + // ItemStacks + ItemStackFactory.Initialize(this, false); + + // Delayed Tasks + DelayedTask.Initialize(this); + + // Recharge + Recharge.Initialize(this); + + // Visibility + VisibilityManager.Initialize(this); + + // Give + Give.Initialize(this); + + // Server config + ServerConfiguration serverConfig = new ServerConfiguration(this, clientManager); + + // Teleport + new Teleport(this, clientManager); + + // Packets + PacketHandler packetHandler = require(PacketHandler.class); + + // Vanish + IncognitoManager incognito = new IncognitoManager(this, clientManager, packetHandler); + + // Preferences + PreferencesManager preferenceManager = new PreferencesManager(this, incognito, clientManager); + + // Why do these depend on each other... :( + incognito.setPreferencesManager(preferenceManager); + + // Server Status + ServerStatusManager serverStatusManager = new ServerStatusManager(this, clientManager, new LagMeter(this, clientManager)); + + // Portal + Portal portal = new Portal(); + + // File Updater + new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion(), GenericServer.BETA_HUB); + + // Punish + Punish punish = new Punish(this, clientManager); + + // Disguises + DisguiseManager disguiseManager = require(DisguiseManager.class); + + // Creatures + Creature creature = new Creature(this); + + // The old classic Damage Manager + DamageManager damageManager = new DamageManager(this, new CombatManager(this), new NpcManager(this, creature), disguiseManager, new ConditionManager(this)); + damageManager.SetEnabled(false); + + // GWEN + AntiHack antiHack = require(AntiHack.class); + Bukkit.getScheduler().runTask(this, antiHack::enableAnticheat); + + // Block Restore + BlockRestore blockRestore = require(BlockRestore.class); + + // Ignoring + IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal); + + // Statistics + StatsManager statsManager = new StatsManager(this, clientManager); + + // Elo + EloManager eloManager = new EloManager(this, clientManager); + + // Achievements + AchievementManager achievementManager = new AchievementManager(statsManager, clientManager, donationManager, incognito, eloManager); + + // Chat/Messaging + Chat chat = new Chat(this, incognito, clientManager, preferenceManager, achievementManager, serverStatusManager.getCurrentServerName()); + new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, new FriendManager(this, clientManager, preferenceManager, portal), chat); + + // Parties + new PartyManager(); + + // Communities + new CommunityManager(this, clientManager); + + // Fixes + new MemoryFix(this); + new FoodDupeFix(this); + + // Explosions + Explosion explosion = new Explosion(this, blockRestore); + + explosion.SetDebris(true); + explosion.SetTemporaryDebris(false); + + // Inventories + InventoryManager inventoryManager = new InventoryManager(this, clientManager); + + // Reports + // SnapshotManager snapshotManager = new SnapshotManager(this, new + // SnapshotRepository(serverStatusManager.getCurrentServerName(), + // getLogger())); + // new SnapshotPlugin(this, snapshotManager, clientManager); + // new ReportPlugin(this, new ReportManager(this, snapshotManager, + // clientManager, incognito, punish, serverStatusManager.getRegion(), + // serverStatusManager.getCurrentServerName(), 1)); + + // Tag fix + new CustomTagFix(this, packetHandler); + + // Holograms + HologramManager hologramManager = new HologramManager(this, packetHandler); + + // Menus + new MenuManager(this); + + // Gadgets, used for mounts, lots of managers for something really small + // :( + MountManager mountManager = new MountManager(this, clientManager, donationManager, blockRestore, disguiseManager); + PetManager petManager = new PetManager(this, clientManager, donationManager, inventoryManager, disguiseManager, creature, blockRestore); + ProjectileManager projectileManager = new ProjectileManager(this); + GadgetManager gadgetManager = new GadgetManager(this, clientManager, donationManager, inventoryManager, mountManager, petManager, preferenceManager, disguiseManager, blockRestore, projectileManager, achievementManager, packetHandler, hologramManager, incognito); + ThankManager thankManager = new ThankManager(this, clientManager, donationManager); + BoosterManager boosterManager = new BoosterManager(this, null, clientManager, donationManager, inventoryManager, thankManager); + CosmeticManager cosmeticManager = new CosmeticManager(this, clientManager, donationManager, inventoryManager, gadgetManager, mountManager, petManager, null, boosterManager); + + cosmeticManager.setActive(false); + cosmeticManager.setHideParticles(true); + gadgetManager.setGadgetEnabled(false); + + // Now we finally get to enable the Gem Hunters modules + // Though if any other module needs one of these it will be generated in + // order, however they are all here just for good measure. + require(BetaModule.class); + //require(DebugModule.class); + require(BountyModule.class); + require(CashOutModule.class); + require(ChatModule.class); + require(DeathModule.class); + require(EconomyModule.class); + require(InventoryModule.class); + require(LootModule.class); + require(ItemMapModule.class); + require(MountModule.class); + require(QuestModule.class); + require(SafezoneModule.class); + require(ScoreboardModule.class); + require(SpawnModule.class); + require(ShopModule.class); + require(SupplyDropModule.class); + require(WorldEventModule.class); + + // An arbitrary collection of world listeners such as block place/break, + // interact events etc... + new WorldListeners(this); + new TimeCycle(this); + new UndergroundMobs(this); + new DebugListeners(this); + + // Combat npc + new NPCManager(hologramManager); + + // UpdateEvent!!! + new Updater(this); + + // Disable spigot's item merging + for (World world : getServer().getWorlds()) + { + ((CraftWorld) world).getHandle().spigotConfig.itemMerge = 0; + } + + // Turn off the server's debugging + MinecraftServer.getServer().getPropertyManager().setProperty("debug", false); + SpigotConfig.debug = false; + + // Two-factor auth + require(TwoFactorAuth.class); + + // beta whitelist + new BetaWhitelist(clientManager, new PowerPlayClubRepository(this, clientManager, donationManager)); + } + + @Override + public void onDisable() + { + getServer().getPluginManager().callEvent(new ServerShutdownEvent(this)); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/beta/BetaModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/beta/BetaModule.java new file mode 100644 index 000000000..537455ba9 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/beta/BetaModule.java @@ -0,0 +1,49 @@ +package mineplex.gemhunters.beta; + +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; + +@ReflectivelyCreateMiniPlugin +public class BetaModule extends MiniPlugin +{ + + private static final String[] ANNOUCEMENTS = { + "Please remember this game is an early access BETA and all bugs should be reported at mineplex.com/forums/m/11929946/viewforum/8006500 .", + "Thank you for playing Gem Hunters!", + "Many more features are being added over the coming days!", + "Players in your party show up on your map!", + "Safezones are marked as green areas on your map!", + "Players that have super valuable items show up on your map!" + }; + + private int _lastIndex; + + private BetaModule() + { + super("Beta"); + } + + @EventHandler + public void annouce(UpdateEvent event) + { + if (event.getType() != UpdateType.MIN_01) + { + return; + } + + Bukkit.broadcastMessage(F.main(C.cRedB + "BETA", C.cYellow + ANNOUCEMENTS[_lastIndex])); + + if (++_lastIndex == ANNOUCEMENTS.length) + { + _lastIndex = 0; + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/bounties/Bounty.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/bounties/Bounty.java new file mode 100644 index 000000000..6e9069d16 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/bounties/Bounty.java @@ -0,0 +1,36 @@ +package mineplex.gemhunters.bounties; + +import java.util.UUID; + +import org.bukkit.entity.Player; + +public class Bounty +{ + + private UUID _target; + private UUID _setter; + private int _amount; + + public Bounty(Player target, Player setter, int amount) + { + _target = target.getUniqueId(); + _setter = setter.getUniqueId(); + _amount = amount; + } + + public UUID getTarget() + { + return _target; + } + + public UUID getSetter() + { + return _setter; + } + + public int getAmount() + { + return _amount; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/bounties/BountyModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/bounties/BountyModule.java new file mode 100644 index 000000000..771d58997 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/bounties/BountyModule.java @@ -0,0 +1,46 @@ +package mineplex.gemhunters.bounties; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.bukkit.block.BlockFace; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.sponsorbranding.BrandingManager; + +@ReflectivelyCreateMiniPlugin +public class BountyModule extends MiniPlugin +{ + + private final BrandingManager _brandingManager; + + private BountyModule() + { + super("Bounty"); + + _brandingManager = require(BrandingManager.class); + } + + //@EventHandler + public void test(PlayerCommandPreprocessEvent event) + { + if (!event.getMessage().startsWith("/want")) + { + return; + } + + try + { + event.setCancelled(true); + _brandingManager.createPost(event.getPlayer().getLocation(), BlockFace.SOUTH, new URL("http://minotar.net/helm/Moppletop.png")); + } + catch (MalformedURLException e) + { + e.printStackTrace(); + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/chat/ChatModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/chat/ChatModule.java new file mode 100644 index 000000000..8d17a1905 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/chat/ChatModule.java @@ -0,0 +1,75 @@ +package mineplex.gemhunters.chat; + +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.event.player.PlayerQuitEvent; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClientManager; +import mineplex.core.chat.Chat; +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; + +/** + * This module handles player chat. + */ +@ReflectivelyCreateMiniPlugin +public class ChatModule extends MiniPlugin +{ + + private final CoreClientManager _clientManager; + private final Chat _chat; + + private ChatModule() + { + super("Chat"); + + _clientManager = require(CoreClientManager.class); + _chat = require(Chat.class); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void playerJoin(PlayerJoinEvent event) + { + event.setJoinMessage(F.sys("Join", event.getPlayer().getName())); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void playerQuit(PlayerQuitEvent event) + { + event.setQuitMessage(F.sys("Quit", event.getPlayer().getName())); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void chat(AsyncPlayerChatEvent event) + { + // Checks if the player has been muted/chat is silenced etc... + if (event.isCancelled()) + { + return; + } + + Player player = event.getPlayer(); + String playerName = player.getName(); + + Rank rank = _clientManager.Get(player).getRealOrDisguisedRank(); + String rankString = rank == Rank.ALL ? "" : rank.getTag(true, true); + + // Create a message that follows the rest of the network's chat format + String message = (rankString + " " + C.cYellow + playerName + " " + C.cWhite + _chat.getFilteredMessage(player, event.getMessage())).trim(); + + // We will handle the broadcast + event.setCancelled(true); + + for (Player other : event.getRecipients()) + { + other.sendMessage(message); + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/DeathModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/DeathModule.java new file mode 100644 index 000000000..7ddaf48c0 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/DeathModule.java @@ -0,0 +1,198 @@ +package mineplex.gemhunters.death; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import com.google.common.collect.Sets; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.core.visibility.VisibilityManager; +import mineplex.gemhunters.death.event.PlayerCustomRespawnEvent; +import mineplex.gemhunters.spawn.SpawnModule; + +/** + * This module handles anything to do with a players death + */ +@ReflectivelyCreateMiniPlugin +public class DeathModule extends MiniPlugin +{ + + // Some items like the cash out item (and for some reason players drop + // bones?) don't need to be dropped to avoid duplication. + private static final Set DISALLOWED_DROPS = Sets.newHashSet(Material.EMERALD, Material.MAP, Material.BONE, Material.STAINED_GLASS_PANE); + private static final int DEATH_ANIMATION_TIME = 7000; + private static final int DEATH_ANIMATION_COUNTDOWN = 2000; + + private final SpawnModule _spawn; + + private final Map _toRemove; + + private DeathModule() + { + super("Death"); + + _spawn = require(SpawnModule.class); + + _toRemove = new HashMap<>(); + } + + @EventHandler + public void join(PlayerJoinEvent event) + { + PlayerCustomRespawnEvent event2 = new PlayerCustomRespawnEvent(event.getPlayer()); + + UtilServer.CallEvent(event2); + } + + @EventHandler + public void death(PlayerDeathEvent event) + { + Player player = event.getEntity(); + + // Stop the player dieing + player.setHealth(20); + player.setFoodLevel(20); + player.setExhaustion(0); + + startAnimation(player); + _toRemove.put(player.getUniqueId(), System.currentTimeMillis()); + } + + @EventHandler + public void itemSpawn(ItemSpawnEvent event) + { + if (DISALLOWED_DROPS.contains(event.getEntity().getItemStack().getType())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void updateAnimations(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + Iterator iterator = _toRemove.keySet().iterator(); + + while (iterator.hasNext()) + { + UUID key = iterator.next(); + Player player = UtilPlayer.searchExact(key); + + if (player == null) + { + iterator.remove(); + continue; + } + + long start = _toRemove.get(key); + long end = start + DEATH_ANIMATION_TIME + 1000; + + if (UtilTime.elapsed(start, DEATH_ANIMATION_TIME)) + { + stopAnimation(player); + _toRemove.remove(key); + continue; + } + else if (UtilTime.elapsed(start, DEATH_ANIMATION_COUNTDOWN)) + { + UtilTextMiddle.display(C.cRedB + "YOU DIED", String.valueOf((int) (end - System.currentTimeMillis()) / 1000), 0, 20, 0, player); + } + } + } + + public void startAnimation(Player player) + { + UtilTextMiddle.display(C.cRedB + "YOU DIED", "Respawning shortly", 0, 60, 0, player); + VisibilityManager.Instance.setVisibility(player, false, UtilServer.getPlayers()); + ((CraftPlayer) player).getHandle().spectating = true; + player.setAllowFlight(true); + player.setFlying(true); + player.setGameMode(GameMode.CREATIVE); + } + + public void stopAnimation(Player player) + { + UtilTextMiddle.display(C.cGreenB + "RESPAWNED", "", 0, 20, 20, player); + VisibilityManager.Instance.setVisibility(player, true, UtilServer.getPlayers()); + ((CraftPlayer) player).getHandle().spectating = false; + player.setFlying(false); + player.setAllowFlight(false); + player.setGameMode(GameMode.SURVIVAL); + _spawn.teleportToSpawn(player); + + PlayerCustomRespawnEvent event = new PlayerCustomRespawnEvent(player); + + UtilServer.CallEvent(event); + } + + @EventHandler + public void itemPickup(PlayerPickupItemEvent event) + { + if (_toRemove.containsKey(event.getPlayer().getUniqueId())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void blockBreak(BlockBreakEvent event) + { + if (_toRemove.containsKey(event.getPlayer().getUniqueId())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void blockPlace(BlockPlaceEvent event) + { + if (_toRemove.containsKey(event.getPlayer().getUniqueId())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void inventory(InventoryClickEvent event) + { + if (_toRemove.containsKey(event.getWhoClicked().getUniqueId())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + _toRemove.remove(event.getPlayer().getUniqueId()); + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/event/PlayerCustomRespawnEvent.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/event/PlayerCustomRespawnEvent.java new file mode 100644 index 000000000..e588841cf --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/event/PlayerCustomRespawnEvent.java @@ -0,0 +1,27 @@ +package mineplex.gemhunters.death.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class PlayerCustomRespawnEvent extends PlayerEvent +{ + + private static final HandlerList HANDLERS = new HandlerList(); + + public PlayerCustomRespawnEvent(Player who) + { + super(who); + } + + public HandlerList getHandlers() + { + return HANDLERS; + } + + public static HandlerList getHandlerList() + { + return HANDLERS; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/CombatLogNPC.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/CombatLogNPC.java new file mode 100644 index 000000000..b1337b6bb --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/CombatLogNPC.java @@ -0,0 +1,238 @@ +package mineplex.gemhunters.death.npc; + +import java.io.File; +import java.util.List; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.metadata.FixedMetadataValue; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.disguises.DisguisePlayer; +import mineplex.core.hologram.Hologram; +import mineplex.core.hologram.HologramManager; + +public class CombatLogNPC +{ + public final static EntityType NPC_TYPE = EntityType.VILLAGER; + + private PlayerInfo _playerInfo; + + private Hologram _hologram; + + private DisguiseManager _disguiseManager; + private long _spawnDate; + private final long _endingTime; + private double _spawnHealth; + + private boolean _creative; + + private LivingEntity _npc; + private ArmorStand _stand; + + private CraftLivingEntity _lastDamager; + + public int getEntityId() + { + return _npc.getEntityId(); + } + + public CombatLogNPC(Player player, DisguiseManager disguiseManager, HologramManager hologramManager, boolean wasCreative) + { + _playerInfo = new PlayerInfo(player); + _creative = wasCreative; + + _disguiseManager = disguiseManager; + _hologram = new Hologram(hologramManager, player.getEyeLocation().add(0, 1, 0), C.cYellow + UtilTime.MakeStr(NPCManager.COMBAT_LOG_DURATION) + C.cWhite + " Seconds left before despawn"); + _spawnDate = 0; + _endingTime = System.currentTimeMillis() + NPCManager.COMBAT_LOG_DURATION; + _spawnHealth = player.getHealth(); + _hologram.start(); + } + + /** + * Called when the {@code _npc} associated with this CombatLogNPC is killed + * and thus drops all the owner's items. + */ + public void onDeath(CraftLivingEntity killer) + { + Location location = _npc.getLocation(); + World world = location.getWorld(); + + File file = new File(world.getWorldFolder(), String.format("playerdata/%s.dat", _playerInfo.getPlayerUuid())); + file.delete(); // Delete the player's .dat file so they will join with + // empty inventory/respawn on next login + if (killer != null) + { + String killerName = "Unknown"; + + if (killer instanceof CraftPlayer) + { + killerName = ((CraftPlayer) killer).getName(); + } + else + { + killerName = UtilEnt.getName(killer); + } + +// try +// { +// DataOutputStream stream = new DataOutputStream(new FileOutputStream(_userDataPath + String.format("DEATH_%s.dat", _playerInfo.getPlayerUuid()))); +// +// stream.writeLong(System.currentTimeMillis()); +// stream.writeInt(killerName.length()); +// stream.writeBytes(killerName); +// +// stream.close(); +// } +// catch (IOException e) +// { +// System.out.println(String.format("FATAL ERROR while trying to create player death lock for %s, meaning %s will not be informed that they died next time they log in.", _playerInfo.getPlayerName(), _playerInfo.getPlayerName())); +// } + + UtilServer.broadcast(F.main("Death", F.elem(_playerInfo.getPlayerName()) + " was killed by " + F.elem(killerName) + " while combat logged.")); + } + + _playerInfo.dropItems(location); + _disguiseManager.undisguise(_npc); + } + + public void update() + { + _hologram.setText("Quitting in " + UtilTime.MakeStr(Math.max(_endingTime - System.currentTimeMillis(), 0))); + } + + /** + * @return true, if the {@code _npc} associated with this CombatLogNPC is + * alive, false otherwise. + */ + public boolean isAlive() + { + return _npc != null && !_npc.isDead(); + } + + /** + * @return the amount of time (in milliseconds) that this npc has been alive + * an spawned in. + */ + public long getAliveDuation() + { + return System.currentTimeMillis() - _spawnDate; + } + + public void spawn() + { + if (_npc != null) despawn(); + + _npc = spawnNpc(getPlayer()); + _spawnDate = System.currentTimeMillis(); + } + + public void despawn() + { + System.out.println("Despawning"); + if (_npc != null) + { + if (_stand != null) + { + _stand.setPassenger(null); + _stand.remove(); + _stand = null; + } + + _npc.remove(); + _npc = null; + _hologram.stop(); + _hologram = null; + } + } + + public void remove() + { + if (_hologram != null) + { + _hologram.stop(); + _hologram = null; + } + } + + public PlayerInfo getPlayerInfo() + { + return _playerInfo; + } + + public Player getPlayer() + { + return _playerInfo.getPlayer(); + } + + public boolean matchesPlayer(Player player) + { + return _playerInfo.getPlayerName().equalsIgnoreCase(player.getName()); + } + + private LivingEntity spawnNpc(Player player) + { + Location spawnLoc = player.getLocation(); + Skeleton skel = player.getWorld().spawn(spawnLoc, Skeleton.class); + skel.setMetadata("CombatLogNPC", new FixedMetadataValue(UtilServer.getPlugin(), player.getUniqueId().toString())); + skel.teleport(spawnLoc); + skel.setHealth(_spawnHealth); + UtilEnt.vegetate(skel); + UtilEnt.silence(skel, true); + + skel.getEquipment().setHelmet(player.getInventory().getHelmet()); + skel.getEquipment().setChestplate(player.getInventory().getChestplate()); + skel.getEquipment().setLeggings(player.getInventory().getLeggings()); + skel.getEquipment().setBoots(player.getInventory().getBoots()); + skel.getEquipment().setItemInHand(player.getItemInHand()); + + // Get in range + List inRange = UtilPlayer.getNearby(spawnLoc, 75d); + + // Disguise + DisguisePlayer disguise = new DisguisePlayer(skel, ((CraftPlayer) player).getHandle().getProfile()); + _disguiseManager.disguise(disguise, attempted -> inRange.contains(attempted)); + + if (!UtilEnt.isGrounded(player)) + { + ArmorStand stand = player.getWorld().spawn(spawnLoc.clone().subtract(0,1,0), ArmorStand.class); + + stand.setVisible(false); + stand.setPassenger(skel); + stand.setGravity(false); + + _stand = stand; + } + + return skel; + } + + public boolean wasCreative() + { + return _creative; + } + + public CraftLivingEntity getLastDamager() + { + return _lastDamager; + } + + public void setLastDamager(CraftLivingEntity damager) + { + _lastDamager = damager; + } +} \ No newline at end of file diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/NPCManager.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/NPCManager.java new file mode 100644 index 000000000..c0a95876a --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/NPCManager.java @@ -0,0 +1,262 @@ +package mineplex.gemhunters.death.npc; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Sound; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftLivingEntity; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.metadata.FixedMetadataValue; + +import mineplex.core.MiniPlugin; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.hologram.HologramManager; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.economy.PlayerCashOutCompleteEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class NPCManager extends MiniPlugin +{ + public static final long COMBAT_LOG_DURATION = 30000; + + private static NPCManager _instance; + + public static NPCManager getInstance() + { + return _instance; + } + + private Set _logoutNpcs; + private Set _toKillIds; + private Set _cashedOutPreventNPCs = new HashSet<>(); + + private HologramManager _hologramManager; + + public NPCManager(HologramManager hologramManager) + { + super("NPC Manager"); + + _instance = this; + _logoutNpcs = new HashSet<>(); + _toKillIds = new HashSet<>(); + _hologramManager = hologramManager; + } + + @EventHandler + public void onCashOut(PlayerCashOutCompleteEvent event) + { + _cashedOutPreventNPCs.add(event.getPlayer().getUniqueId()); + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + NPCManager.getInstance().spawnLogoutNpc(event.getPlayer()); + } + + @Override + public void disable() + { + log("Killing logout npcs"); + + // Despawn/kill all combat log NPCs on server shutdown + for (CombatLogNPC npc : _logoutNpcs) + { + npc.despawn(); + } + _logoutNpcs.clear(); + } + + public void spawnLogoutNpc(Player player) + { + if (!_cashedOutPreventNPCs.remove(player.getUniqueId()) && !hasLogoutNpc(player)) + { + CombatLogNPC npc = new CombatLogNPC(player, require(DisguiseManager.class), _hologramManager, player.getGameMode().equals(GameMode.CREATIVE)); + npc.spawn(); + _logoutNpcs.add(npc); + log(String.format("Spawned combat log NPC for %s!", player.getName())); + } + } + + @EventHandler + public void killNpcs(PlayerJoinEvent event) + { + for (LivingEntity entity : Bukkit.getWorlds().get(0).getLivingEntities()) + { + if (entity.hasMetadata("CombatLogNPC") && ((FixedMetadataValue) entity.getMetadata("CombatLogNPC").get(0)).asString().equals(event.getPlayer().getUniqueId().toString())) + { + entity.remove(); + } + } + } + + public void despawnLogoutNpc(Player player) + { + CombatLogNPC npc = getLogoutNpc(player); + + if (npc != null) + { + _toKillIds.add(npc.getEntityId()); + npc.despawn(); + _logoutNpcs.remove(npc); + log(String.format("Despawned combat log NPC for %s!", player.getName())); + } + } + + public boolean hasLogoutNpc(Player player) + { + return getLogoutNpc(player) != null; + } + + public CombatLogNPC getLogoutNpc(Player player) + { + for (CombatLogNPC logoutNpc : _logoutNpcs) + { + if (logoutNpc.matchesPlayer(player)) + { + return logoutNpc; + } + } + + return null; + } + + @EventHandler + public void onChunkUnload(ChunkUnloadEvent event) + { + for (Entity entity : event.getChunk().getEntities()) + { + for (CombatLogNPC npc : _logoutNpcs) + { + if (entity.getEntityId() == npc.getEntityId()) + { + event.setCancelled(true); + + break; + } + } + } + } + + @EventHandler(ignoreCancelled = true) + public void onEntityDeath(EntityDeathEvent event) + { + CombatLogNPC logoutNpc = getLogoutNpc(event.getEntity()); + + if (logoutNpc != null) + { + logoutNpc.onDeath(logoutNpc.getLastDamager()); + event.getDrops().clear(); // Clear the entity's item drops. Manually + // drops combat log items earlier + } + } + + @EventHandler(ignoreCancelled = true) + public void onEntityDamaged(CustomDamageEvent event) + { + CombatLogNPC logoutNpc = getLogoutNpc(event.GetDamageeEntity()); + + if (logoutNpc != null && event.GetDamagerEntity(true) != null) + { + if (logoutNpc.wasCreative()) + { + event.SetCancelled("Cannot hurt creative player"); + return; + } + + if (event.GetDamagerPlayer(true) != null) + { + event.GetDamagerPlayer(true).playSound(event.GetDamagerPlayer(true).getLocation(), Sound.HURT_FLESH, 1, 1); + } + + logoutNpc.setLastDamager(((CraftLivingEntity) event.GetDamagerEntity(true))); + event.SetKnockback(false); + } + } + + @EventHandler + public void onEntityIgnite(EntityCombustEvent event) + { + if (isLogoutNpc(event.getEntity())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void onUpdate(UpdateEvent event) + { + if (event.getType() == UpdateType.FASTER) + { + for (CombatLogNPC npc : _logoutNpcs) + { + npc.update(); + } + } + + if (event.getType() == UpdateType.SEC) + { + Iterator iterator = _logoutNpcs.iterator(); + + while (iterator.hasNext()) + { + CombatLogNPC npc = iterator.next(); + + if (Bukkit.getPlayer(npc.getPlayerInfo().getPlayerName()) != null) + { + System.out.println("{NPCMANAGER} ORIGINAL PLAYER ALIVE AND DESPAWNING"); + npc.despawn(); + iterator.remove(); + } + else if (!npc.isAlive()) + { + System.out.println("{NPCMANAGER} NOT ALIVE AND REMOVING"); + npc.remove(); + iterator.remove(); + } + else if (npc.getAliveDuation() > COMBAT_LOG_DURATION) + { + System.out.println("{NPCMANAGER} DESPAWNING"); + npc.despawn(); + iterator.remove(); + } + } + } + } + + private boolean isLogoutNpc(Entity entity) + { + return getLogoutNpc(entity) != null; + } + + private CombatLogNPC getLogoutNpc(Entity entity) + { + return getLogoutNpc(entity.getEntityId()); + } + + private CombatLogNPC getLogoutNpc(int entityId) + { + for (CombatLogNPC npc : _logoutNpcs) + { + if (npc.getEntityId() == entityId) + { + return npc; + } + } + + return null; + } +} \ No newline at end of file diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/PlayerInfo.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/PlayerInfo.java new file mode 100644 index 000000000..694606cab --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/npc/PlayerInfo.java @@ -0,0 +1,92 @@ +package mineplex.gemhunters.death.npc; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import mineplex.gemhunters.loot.InventoryModule; + +public class PlayerInfo +{ + private String _playerName; + private UUID _playerUuid; + private ItemStack[] _armor; + private List _items; + private Location _location; + + public PlayerInfo(Player player) + { + _playerName = player.getName(); + _playerUuid = player.getUniqueId(); + _armor = player.getInventory().getArmorContents(); + _items = fetchItems(player.getInventory()); + _location = player.getLocation(); + } + + public void dropItems(Location location) + { + World world = location.getWorld(); + for (ItemStack item : _items) + { + world.dropItemNaturally(location, item); + } + } + + public void restore() + { + Player player = getPlayer(); + + player.getInventory().clear(); + player.getInventory().setArmorContents(_armor); + player.getInventory().addItem(_items.toArray(new ItemStack[0])); + player.teleport(_location); + } + + public String getPlayerName() + { + return _playerName; + } + + public UUID getUniqueId() + { + return _playerUuid; + } + + public String getPlayerUuid() + { + return _playerUuid.toString(); + } + + public Player getPlayer() + { + return Bukkit.getPlayerExact(_playerName); + } + + private List fetchItems(PlayerInventory inventory) + { + List items = new ArrayList<>(); + + addItems(items, inventory.getContents()); + + return items; + } + + private void addItems(List items, ItemStack[] itemsToAdd) + { + for (ItemStack item : itemsToAdd) + { + if (item != null && item.getType() != Material.AIR && !item.isSimilar(InventoryModule.LOCKED)) + { + items.add(item); + } + } + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutModule.java new file mode 100644 index 000000000..1db9db186 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutModule.java @@ -0,0 +1,276 @@ +package mineplex.gemhunters.economy; + +import java.text.DecimalFormat; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilEvent; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.donation.DonationManager; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.portal.GenericServer; +import mineplex.core.portal.Intent; +import mineplex.core.portal.Portal; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.spawn.event.PlayerTeleportIntoMapEvent; + +@ReflectivelyCreateMiniPlugin +public class CashOutModule extends MiniPlugin +{ + + private static final DecimalFormat ARMOUR_STAND_FORMAT = new DecimalFormat("0.0"); + private static final ItemStack CASH_OUT_ITEM = new ItemBuilder(Material.EMERALD).setTitle(C.cGreen + "Cash Out").addLore("", C.cGray + "Click to begin the process to cash out.", C.cGray + "Cashing out saves your current loot.").build(); + + private static final int CASH_OUT_COOLDOWN = 10000; + private static final int CASH_OUT_MAX_MOVE_DISTANCE_SQUARED = 4; + + private final DonationManager _donation; + + private final Map _sessions; + + public CashOutModule() + { + super("Cash Out"); + + _donation = require(DonationManager.class); + + _sessions = new HashMap<>(); + } + + @EventHandler + public void teleportIn(PlayerTeleportIntoMapEvent event) + { + if (event.isCancelled()) + { + return; + } + + event.getPlayer().getInventory().setItem(7, CASH_OUT_ITEM); + } + + @EventHandler + public void playerInteract(PlayerInteractEvent event) + { + if (!UtilEvent.isAction(event, ActionType.R)) + { + return; + } + + Player player = event.getPlayer(); + ItemStack itemStack = player.getItemInHand(); + + if (itemStack == null) + { + return; + } + + if (!itemStack.isSimilar(CASH_OUT_ITEM)) + { + return; + } + + attemptCashOut(player); + } + + @EventHandler + public void itemDrop(PlayerDropItemEvent event) + { + if (event.getItemDrop().getItemStack().isSimilar(CASH_OUT_ITEM)) + { + event.getPlayer().sendMessage(F.main("Game", "You cannot drop the " + F.item("Cash Out Item") + ".")); + event.setCancelled(true); + } + } + + @EventHandler + public void inventoryClick(InventoryClickEvent event) + { + ItemStack itemStack = event.getCurrentItem(); + + if (itemStack == null) + { + return; + } + + if (!itemStack.isSimilar(CASH_OUT_ITEM)) + { + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + Iterator iterator = _sessions.keySet().iterator(); + + while (iterator.hasNext()) + { + UUID key = iterator.next(); + Player player = UtilPlayer.searchExact(key); + CashOutSession session = _sessions.get(key); + double current = session.getCurrent(); + ArmorStand stand = session.getArmourStand(); + String standName = ARMOUR_STAND_FORMAT.format(current); + + if (player == null) + { + session.endSession(); + iterator.remove(); + continue; + } + + UtilTextMiddle.display(C.cGreen + standName, UtilTextMiddle.progress((float) (1 - current / session.getMax())), 0, 10, 0, player); + stand.setCustomName(standName + " seconds"); + session.setCurrent(current - 0.05); + + if (session.getCurrent() <= 0) + { + PlayerCashOutCompleteEvent completeEvent = new PlayerCashOutCompleteEvent(player); + + UtilServer.CallEvent(completeEvent); + + _donation.rewardCurrencyUntilSuccess(GlobalCurrency.GEM, player, "Earned", completeEvent.getGems()); + + session.endSession(); + iterator.remove(); + Portal.getInstance().sendPlayerToGenericServer(player, GenericServer.BETA_HUB, Intent.FORCE_TRANSFER); + } + } + } + + @EventHandler + public void updateMove(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + for (UUID key : _sessions.keySet()) + { + Player player = UtilPlayer.searchExact(key); + CashOutSession session = _sessions.get(key); + + if (session.getLocation().distanceSquared(player.getLocation()) > CASH_OUT_MAX_MOVE_DISTANCE_SQUARED) + { + cancelCashOut(player, "You moved!"); + } + } + } + + @EventHandler + public void entityDamage(EntityDamageEvent event) + { + if (!(event.getEntity() instanceof Player)) + { + return; + } + + Player player = (Player) event.getEntity(); + + if (isCashingOut(player)) + { + cancelCashOut(player, "You took damage!"); + } + } + + @EventHandler + public void entityAttack(EntityDamageByEntityEvent event) + { + if (!(event.getDamager() instanceof Player) || event.getEntity() instanceof ArmorStand) + { + return; + } + + Player player = (Player) event.getDamager(); + + if (isCashingOut(player)) + { + cancelCashOut(player, "You attacked a player!"); + } + } + + public void attemptCashOut(Player player) + { + UUID key = player.getUniqueId(); + + if (_sessions.containsKey(key)) + { + player.sendMessage(F.main("Game", "You are already cashing out.")); + return; + } + + if (!Recharge.Instance.use(player, "Cash Out", CASH_OUT_COOLDOWN, true, false)) + { + return; + } + + // Test time + _sessions.put(key, new CashOutSession(player, 10)); + } + + public void cancelCashOut(Player player, String message) + { + UUID key = player.getUniqueId(); + CashOutSession session = _sessions.get(key); + + player.sendMessage(F.main("Game", message + " Your cash out has been cancelled.")); + session.endSession(); + _sessions.remove(key); + } + + public boolean isCashingOut(Player player) + { + return getCashOutSession(player) != null; + } + + public CashOutSession getCashOutSession(Player player) + { + for (UUID key : _sessions.keySet()) + { + if (key.equals(player.getUniqueId())) + { + return _sessions.get(key); + } + } + + return null; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutSession.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutSession.java new file mode 100644 index 000000000..b996183bf --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutSession.java @@ -0,0 +1,58 @@ +package mineplex.gemhunters.economy; + +import org.bukkit.Location; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; + +public class CashOutSession +{ + + private double _current; + private double _max; + private ArmorStand _stand; + private Location _location; + + public CashOutSession(Player player, double max) + { + _current = max; + _max = max; + _stand = player.getWorld().spawn(player.getLocation().add(0, 0.5, 0), ArmorStand.class); + + _stand.setCustomNameVisible(true); + _stand.setVisible(false); + _stand.setGravity(false); + + _location = player.getLocation(); + } + + public void endSession() + { + _stand.remove(); + } + + public void setCurrent(double current) + { + _current = current; + } + + public double getCurrent() + { + return _current; + } + + public double getMax() + { + return _max; + } + + public ArmorStand getArmourStand() + { + return _stand; + } + + public Location getLocation() + { + return _location; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/EconomyModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/EconomyModule.java new file mode 100644 index 000000000..a004700b6 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/EconomyModule.java @@ -0,0 +1,110 @@ +package mineplex.gemhunters.economy; + +import java.util.UUID; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.PlayerDeathEvent; + +import mineplex.core.MiniClientPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.F; +import mineplex.core.donation.DonationManager; +import mineplex.core.donation.Donor; +import mineplex.gemhunters.death.event.PlayerCustomRespawnEvent; +import mineplex.gemhunters.economy.command.GiveGemsCommand; +import mineplex.gemhunters.spawn.event.PlayerTeleportIntoMapEvent; + +@ReflectivelyCreateMiniPlugin +public class EconomyModule extends MiniClientPlugin +{ + + private static final float GEM_KILL_FACTOR = 0.5F; + private static final int GEM_START_COST = 100; + + private final DonationManager _donation; + + public EconomyModule() + { + super("Economy"); + + _donation = require(DonationManager.class); + } + + @Override + public void addCommands() + { + addCommand(new GiveGemsCommand(this)); + } + + @EventHandler + public void respawn(PlayerCustomRespawnEvent event) + { + addToStore(event.getPlayer(), null, GEM_START_COST); + } + + @EventHandler + public void teleportIn(PlayerTeleportIntoMapEvent event) + { + Player player = event.getPlayer(); + Donor donor = _donation.Get(event.getPlayer()); + + if (donor.getBalance(GlobalCurrency.GEM) >= GEM_START_COST) + { + _donation.purchaseUnknownSalesPackage(player, "Gem Hunters Access", GlobalCurrency.GEM, GEM_START_COST, false, null); + } + } + + @EventHandler + public void death(PlayerDeathEvent event) + { + Player player = event.getEntity(); + Entity killer = event.getEntity().getKiller(); + + int oldGems = getGems(player); + + if (killer instanceof Player) + { + Player killerPlayer = (Player) killer; + int newGems = (int) (oldGems * GEM_KILL_FACTOR); + + addToStore(killerPlayer, "Killing " + F.name(player.getName()), newGems); + } + + removeFromStore(player, oldGems); + } + + @EventHandler + public void cashOut(PlayerCashOutCompleteEvent event) + { + event.incrementGems(getGems(event.getPlayer())); + } + + public void addToStore(Player player, String reason, int gems) + { + Set(player, Get(player) + gems); + + if (reason != null) + { + player.sendMessage(F.main(_moduleName, "+" + F.currency(GlobalCurrency.GEM, gems) + " (" + reason + ").")); + } + } + + public void removeFromStore(Player player, int gems) + { + addToStore(player, null, -gems); + } + + public int getGems(Player player) + { + return Get(player); + } + + @Override + protected Integer addPlayer(UUID uuid) + { + return 0; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/PlayerCashOutCompleteEvent.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/PlayerCashOutCompleteEvent.java new file mode 100644 index 000000000..6862c5da0 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/PlayerCashOutCompleteEvent.java @@ -0,0 +1,44 @@ +package mineplex.gemhunters.economy; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class PlayerCashOutCompleteEvent extends PlayerEvent +{ + + private static final HandlerList HANDLERS = new HandlerList(); + + private int _gems; + + public PlayerCashOutCompleteEvent(Player player) + { + super(player); + } + + public void incrementGems(int gems) + { + _gems += gems; + } + + public void setGems(int gems) + { + _gems = gems; + } + + public int getGems() + { + return _gems; + } + + public HandlerList getHandlers() + { + return HANDLERS; + } + + public static HandlerList getHandlerList() + { + return HANDLERS; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/command/GiveGemsCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/command/GiveGemsCommand.java new file mode 100644 index 000000000..c658546d2 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/command/GiveGemsCommand.java @@ -0,0 +1,47 @@ +package mineplex.gemhunters.economy.command; + +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.gemhunters.economy.EconomyModule; + +public class GiveGemsCommand extends CommandBase +{ + + public GiveGemsCommand(EconomyModule plugin) + { + super(plugin, Rank.ADMIN, "givegems"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 2) + { + caller.sendMessage(F.help("/" + _aliasUsed + " ", "Adds an amount of gems to a player's gems earned.", Rank.ADMIN)); + return; + } + + Player target = UtilPlayer.searchOnline(caller, args[0], true); + + if (target == null) + { + return; + } + + try + { + int amount = Integer.parseInt(args[1]); + + Plugin.addToStore(target, "Given by " + F.name(caller.getName()), amount); + } + catch (NumberFormatException e) + { + caller.sendMessage(F.main(Plugin.getName(), "That is not a number.")); + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/ChestProperties.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/ChestProperties.java new file mode 100644 index 000000000..fe2ff3aa2 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/ChestProperties.java @@ -0,0 +1,107 @@ +package mineplex.gemhunters.loot; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Material; + +public class ChestProperties +{ + + private final String _name; + private final Material _blockMaterial; + private final String _dataKey; + private final int _minAmount; + private final int _maxAmount; + private final int _maxChestPerLoc; + private final int _spawnRate; + private final int _expireRate; + private final int _spawnRadius; + private final int _maxActive; + + private final Map _spawnedIndexes; + private long _lastSpawn; + + public ChestProperties(String name, Material blockMaterial, String dataKey, int minAmount, int maxAmount, int maxChestPerLoc, int spawnRate, int expireRate, int spawnRadius, int maxActive) + { + _name = name; + _blockMaterial = blockMaterial; + _dataKey = dataKey; + _minAmount = minAmount; + _maxAmount = maxAmount; + _maxChestPerLoc = maxChestPerLoc; + _spawnRate = spawnRate; + _expireRate = expireRate; + _spawnRadius = spawnRadius; + _maxActive = maxActive; + + _spawnedIndexes = new HashMap<>(); + setLastSpawn(); + } + + public final String getName() + { + return _name; + } + + public final Material getBlockMaterial() + { + return _blockMaterial; + } + + public final String getDataKey() + { + return _dataKey; + } + + public final int getMinAmount() + { + return _minAmount; + } + + public final int getMaxAmount() + { + return _maxAmount; + } + + public final int getMaxChestPerLocation() + { + return _maxChestPerLoc; + } + + public final int getSpawnRate() + { + return _spawnRate; + } + + public final int getExpireRate() + { + return _expireRate; + } + + public final int getSpawnRadius() + { + return _spawnRadius; + } + + public final int getMaxActive() + { + return _maxActive; + } + + public final Map getSpawnIndexes() + { + return _spawnedIndexes; + } + + public void setLastSpawn() + { + _lastSpawn = System.currentTimeMillis(); + } + + public long getLastSpawn() + { + return _lastSpawn; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/InventoryModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/InventoryModule.java new file mode 100644 index 000000000..f0c7e1e6b --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/InventoryModule.java @@ -0,0 +1,133 @@ +package mineplex.gemhunters.loot; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilEvent; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilInv; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.gemhunters.death.event.PlayerCustomRespawnEvent; + +@ReflectivelyCreateMiniPlugin +public class InventoryModule extends MiniPlugin +{ + + public static final ItemStack LOCKED = new ItemBuilder(Material.STAINED_GLASS_PANE, (byte) 15).setTitle(C.cGray + "Locked").build(); + private static final int START_INDEX = 9; + private static final String ITEM_METADATA = "UNLOCKER"; + + private final LootModule _loot; + + private final Map _slotsUnlocked; + + private InventoryModule() + { + super("Unlocker"); + + _loot = require(LootModule.class); + + _slotsUnlocked = new HashMap<>(); + } + + @EventHandler + public void respawn(PlayerCustomRespawnEvent event) + { + Player player = event.getPlayer(); + Inventory inv = player.getInventory(); + + _slotsUnlocked.put(player.getUniqueId(), 0); + + for (int i = START_INDEX; i < inv.getSize(); i++) + { + inv.setItem(i, LOCKED); + } + } + + @EventHandler + public void quit(PlayerQuitEvent event) + { + _slotsUnlocked.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler + public void inventoryClick(InventoryClickEvent event) + { + Player player = (Player) event.getWhoClicked(); + + if (event.getClickedInventory() == null || event.getCurrentItem() == null) + { + return; + } + + if (event.getCurrentItem().isSimilar(LOCKED)) + { + event.setCancelled(true); + player.playSound(player.getLocation(), Sound.ITEM_BREAK, 1, 0.6F); + } + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!UtilEvent.isAction(event, ActionType.R)) + { + return; + } + + Player player = event.getPlayer(); + ItemStack itemStack = player.getItemInHand(); + + if (itemStack == null) + { + return; + } + + LootItem lootItem = _loot.fromItemStack(itemStack); + + if (lootItem == null || lootItem.getMetadata() == null || !lootItem.getMetadata().equals(ITEM_METADATA)) + { + return; + } + + player.setItemInHand(UtilInv.decrement(itemStack)); + unlockSlots(player, itemStack.getType() == Material.CHEST ? 9 : 18); + } + + public void unlockSlots(Player player, int slots) + { + Inventory inv = player.getInventory(); + UUID key = player.getUniqueId(); + + int start = START_INDEX + _slotsUnlocked.get(key); + int end = Math.min(inv.getSize(), start + slots); + int delta = end - start; + + //DebugModule.getInstance().d("start=" + start); + //DebugModule.getInstance().d("end=" + end); + //DebugModule.getInstance().d("delta=" + delta); + + for (int i = start; i < end; i++) + { + inv.setItem(i, null); + } + + player.sendMessage(F.main(_moduleName, "You unlocked an additional " + F.count(String.valueOf(delta)) + " slots of your inventory!")); + _slotsUnlocked.put(key, _slotsUnlocked.get(key) + slots); + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootItem.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootItem.java new file mode 100644 index 000000000..74420cb75 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootItem.java @@ -0,0 +1,90 @@ +package mineplex.gemhunters.loot; + +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.UtilMath; + +/** + * Represents an item that can be contained in a chest inside the Gem Hunters + * world. + */ +public class LootItem +{ + + private final ItemStack _itemStack; + private final int _minAmount; + private final int _maxAmount; + private final double _probability; + private final String _metadata; + + public LootItem(ItemStack itemStack, int minAmount, int maxAmount, double probability, String metadata) + { + _itemStack = itemStack; + _minAmount = minAmount; + _maxAmount = maxAmount; + _probability = probability; + _metadata = metadata; + } + + /** + * Returns the Minecraft {@link ItemStack} bound to this + * {@link LootItem}.
+ * The {@link ItemStack} returned will have an amount/size between the + * minAmount and maxAmount integers (set within the constuctor's parameters) + * inclusively. + * + * @return + */ + public ItemStack getItemStack() + { + _itemStack.setAmount(_minAmount + UtilMath.r(_maxAmount - _minAmount + 1)); + + return _itemStack; + } + + /** + * The minimum amount or size an {@link ItemStack} of this {@link LootItem} + * can have. + * + * @return + */ + public int getMinAmount() + { + return _minAmount; + } + + /** + * The maximum amount or size an {@link ItemStack} of this {@link LootItem} + * can have. + * + * @return + */ + public int getMaxAmount() + { + return _maxAmount; + } + + /** + * The double value of the item's probability of being chosen to when + * picking an individual chest's loot. + * + * @return + */ + public double getProbability() + { + return _probability; + } + + /** + * Any metadata bound to a {@link LootItem}. Useful for determining if an + * item has a particular skill or ability attached to it which + * you can use in code. + * + * @return + */ + public String getMetadata() + { + return _metadata; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootModule.java new file mode 100644 index 000000000..bd179cc2a --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootModule.java @@ -0,0 +1,662 @@ +package mineplex.gemhunters.loot; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Bukkit; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.Chest; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilEvent; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilInv; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.google.GoogleSheetsManager; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.economy.EconomyModule; +import mineplex.gemhunters.economy.PlayerCashOutCompleteEvent; +import mineplex.gemhunters.loot.command.SpawnChestCommand; +import mineplex.gemhunters.loot.command.UpdateLootCommand; +import mineplex.gemhunters.loot.deserialisers.ChestPropertiesDeserialiser; +import mineplex.gemhunters.loot.deserialisers.LootItemDeserialiser; +import mineplex.gemhunters.loot.event.PlayerChestOpenEvent; +import mineplex.gemhunters.loot.rewards.LootChestReward; +import mineplex.gemhunters.loot.rewards.LootGadgetReward; +import mineplex.gemhunters.loot.rewards.LootItemReward; +import mineplex.gemhunters.loot.rewards.LootRankReward; +import mineplex.gemhunters.loot.rewards.LootShardReward; +import mineplex.gemhunters.safezone.SafezoneModule; +import mineplex.gemhunters.spawn.event.PlayerTeleportIntoMapEvent; +import mineplex.gemhunters.util.SlackSheetsBot; +import mineplex.gemhunters.world.WorldDataModule; + +@ReflectivelyCreateMiniPlugin +public class LootModule extends MiniPlugin +{ + + private static final String SHEET_FILE_NAME = "GEM_HUNTERS_CHESTS"; + private static final String CHEST_MASTER_SHEET_NAME = "CHEST_MASTER"; + private static final long CHEST_DESPAWN_TIME_OPENED = TimeUnit.SECONDS.toMillis(15); + private static final float CHESTS_ON_START_FACTOR = 0.333F; + private static final int MAX_SEARCH_ATTEMPTS = 40; + private static final int MAX_CHEST_CHECK_DISTANCE_SQUARED = 4; + private static final LootItemDeserialiser DESERIALISER = new LootItemDeserialiser(); + private static final ChestPropertiesDeserialiser CHEST_DESERIALISER = new ChestPropertiesDeserialiser(); + private static final ItemStack[] SPAWN_ITEMS = { + new ItemStack(Material.WOOD_SWORD), + new ItemStack(Material.APPLE, 3), + }; + private static final String GEM_METADATA = "GEM"; + + private final EconomyModule _economy; + private final GoogleSheetsManager _sheets; + private final SafezoneModule _safezone; + private final WorldDataModule _worldData; + + private final Map> _chestLoot; + private final Map _chestProperties; + private final Set _spawnedChest; + private final Set _itemRewards; + private final Set _shownPlayers; + + private LootModule() + { + super("Loot"); + + _economy = require(EconomyModule.class); + _sheets = require(GoogleSheetsManager.class); + _safezone = require(SafezoneModule.class); + _worldData = require(WorldDataModule.class); + _chestLoot = new HashMap<>(); + _chestProperties = new HashMap<>(); + _spawnedChest = new HashSet<>(); + _itemRewards = new HashSet<>(); + _shownPlayers = new HashSet<>(); + + runSyncLater(() -> { + + updateChestLoot(); + + // Spawn some chests + for (String key : _chestProperties.keySet()) + { + int max = _chestProperties.get(key).getMaxActive(); + + for (int i = 0; i < max * CHESTS_ON_START_FACTOR; i++) + { + addSpawnedChest(key, true); + } + } + + }, 20); + } + + @Override + public void addCommands() + { + addCommand(new UpdateLootCommand(this)); + addCommand(new SpawnChestCommand(this)); + } + + @EventHandler + public void updateSpawnChests(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + // Despawn opened chests + Iterator iterator = _spawnedChest.iterator(); + + while (iterator.hasNext()) + { + SpawnedChest chest = iterator.next(); + ChestProperties properties = chest.getProperties(); + + if (chest.isOpened() && UtilTime.elapsed(chest.getOpenedAt(), CHEST_DESPAWN_TIME_OPENED) || UtilTime.elapsed(chest.getSpawnedAt(), properties.getExpireRate())) + { + if (chest.getID() != -1) + { + properties.getSpawnIndexes().put(chest.getID(), properties.getSpawnIndexes().get(chest.getID()) - 1); + } + + Block block = chest.getLocation().getBlock(); + + if (block.getState() instanceof Chest) + { + ((Chest) block.getState()).getBlockInventory().clear(); + } + + block.getWorld().playEffect(chest.getLocation(), Effect.STEP_SOUND, block.getType()); + block.setType(Material.AIR); + iterator.remove(); + } + } + + // Spawn new chests + for (String key : _chestProperties.keySet()) + { + addSpawnedChest(key, false); + } + } + + public boolean isSuitable(Block block) + { + Block up = block.getRelative(BlockFace.UP); + Block down = block.getRelative(BlockFace.DOWN); + + if (block.getType() != Material.AIR || up.getType() != Material.AIR || down.getType() == Material.AIR || UtilBlock.liquid(down) || UtilBlock.liquid(up) || UtilBlock.liquid(block) || _safezone.isInSafeZone(block.getLocation())) + { + return false; + } + + return true; + } + + public void updateChestLoot() + { + log("Updating chest loot"); + Map>> map = _sheets.getSheetData(SHEET_FILE_NAME); + + for (String key : map.keySet()) + { + if (key.equals(CHEST_MASTER_SHEET_NAME)) + { + int row = 0; + + for (List rows : map.get(key)) + { + row++; + try + { + ChestProperties properties = CHEST_DESERIALISER.deserialise(rows.toArray(new String[0])); + _chestProperties.put(properties.getDataKey(), properties); + } + catch (Exception e) + { + if (row != 1) + { + SlackSheetsBot.reportParsingError(e, "Chest Loot", key, row); + } + + continue; + } + } + + continue; + } + + Set items = new HashSet<>(); + int row = 0; + + for (List rows : map.get(key)) + { + row++; + try + { + items.add(DESERIALISER.deserialise(rows.toArray(new String[0]))); + } + catch (Exception e) + { + if (row != 1) + { + SlackSheetsBot.reportParsingError(e, "Chest Loot", key, row); + } + + continue; + } + } + + _chestLoot.put(key, items); + } + + log("Finished updating chest loot"); + } + + public void addSpawnedChest(String key, boolean force) + { + if (key.equals("PURPLE") && Bukkit.getOnlinePlayers().size() < 10) + { + return; + } + + List locations = _worldData.getDataLocation(key); + ChestProperties properties = _chestProperties.get(key); + + if (!force && !UtilTime.elapsed(properties.getLastSpawn(), properties.getSpawnRate())) + { + return; + } + + properties.setLastSpawn(); + + // Only spawn more chests if we need to + int max = properties.getMaxActive(); + int spawned = 0; + + for (SpawnedChest chest : _spawnedChest) + { + if (chest.getProperties().getDataKey().equals(key)) + { + spawned++; + } + } + + // If there are too many chests of this type we can ignore it + if (spawned > max) + { + return; + } + + if (locations.isEmpty()) + { + return; + } + + Map spawnedIndexes = properties.getSpawnIndexes(); + Location randomLocation = null; + boolean found = false; + int attempts = 0; + int index = -1; + + while (index == -1 || !found && attempts < MAX_SEARCH_ATTEMPTS) + { + attempts++; + index = UtilMath.r(locations.size()); + + if (spawnedIndexes.getOrDefault(index, 0) >= properties.getMaxChestPerLocation()) + { + continue; + } + } + + if (index == -1) + { + return; + } + + spawnedIndexes.put(index, spawnedIndexes.getOrDefault(index, 0) + 1); + randomLocation = locations.get(index); + + int placeRadius = properties.getSpawnRadius(); + Location chestToPlace = UtilAlg.getRandomLocation(randomLocation, placeRadius, 0, placeRadius); + Block block = chestToPlace.getBlock(); + + attempts = 0; + boolean suitable = false; + + while (!suitable && attempts < MAX_SEARCH_ATTEMPTS) + { + chestToPlace = UtilAlg.getRandomLocation(randomLocation, placeRadius, 0, placeRadius); + block = chestToPlace.getBlock(); + suitable = isSuitable(block); + attempts++; + } + + if (!suitable) + { + return; + } + + //DebugModule.getInstance().d("Spawned at " + UtilWorld.blockToStrClean(block) + " with key=" + key + " and index=" + index + " and max=" + spawned + "/" + max); + _spawnedChest.add(new SpawnedChest(chestToPlace, properties, index)); + block.setType(properties.getBlockMaterial()); + } + + public void addSpawnedChest(Location location, String colour) + { + _spawnedChest.add(new SpawnedChest(location, _chestProperties.get(colour), -1)); + } + + public void fillChest(Player player, Block block, String key) + { + Set used = new HashSet<>(); + Set items = _chestLoot.get(key); + ChestProperties properties = _chestProperties.get(key); + + Inventory inventory = null; + + if (block.getType() == Material.ENDER_CHEST) + { + inventory = player.getEnderChest(); + } + else + { + BlockState state = block.getState(); + Chest chest = (Chest) state; + inventory = chest.getBlockInventory(); + } + + inventory.clear(); + + for (int i = 0; i < UtilMath.rRange(properties.getMinAmount(), properties.getMaxAmount()); i++) + { + LootItem lootItem = getRandomItem(items); + ItemStack itemStack = lootItem.getItemStack(); + int index = getFreeIndex(inventory.getSize(), used); + + inventory.setItem(index, itemStack); + } + } + + public LootItem getRandomItem(Set items) + { + double totalWeight = 0; + + for (LootItem item : items) + { + totalWeight += item.getProbability(); + } + + double select = Math.random() * totalWeight; + + for (LootItem item : items) + { + if ((select -= item.getProbability()) <= 0) + { + return item; + } + } + + return null; + } + + private int getFreeIndex(int endIndex, Set used) + { + int index = -1; + + while (index == -1 || used.contains(index)) + { + index = UtilMath.r(endIndex); + } + + used.add(index); + + return index; + } + + public LootItem fromItemStack(ItemStack itemStack) + { + if (itemStack == null) + { + return null; + } + + for (Set items : _chestLoot.values()) + { + for (LootItem item : items) + { + if (item.getItemStack().isSimilar(itemStack)) + { + return item; + } + } + } + + return null; + } + + public boolean hasChestBeenOpened(Location location) + { + for (SpawnedChest chest : _spawnedChest) + { + if (chest.getLocation().distanceSquared(location) < MAX_CHEST_CHECK_DISTANCE_SQUARED && chest.isOpened()) + { + return true; + } + } + + return false; + } + + @EventHandler + public void chestOpen(PlayerInteractEvent event) + { + if (event.isCancelled() || !UtilEvent.isAction(event, ActionType.R_BLOCK)) + { + return; + } + + Player player = event.getPlayer(); + Block block = event.getClickedBlock(); + + if (block.getType() != Material.CHEST && block.getType() != Material.ENDER_CHEST) + { + return; + } + + if (hasChestBeenOpened(block.getLocation())) + { + return; + } + + String key = null; + + for (SpawnedChest chest : _spawnedChest) + { + if (UtilMath.offsetSquared(chest.getLocation(), block.getLocation()) < MAX_CHEST_CHECK_DISTANCE_SQUARED) + { + key = chest.getProperties().getDataKey(); + chest.setOpened(); + break; + } + } + + if (key == null) + { + event.setCancelled(true); + return; + } + + PlayerChestOpenEvent openEvent = new PlayerChestOpenEvent(player, block, _chestProperties.get(key)); + UtilServer.CallEvent(openEvent); + + if (openEvent.isCancelled()) + { + event.setCancelled(true); + return; + } + + fillChest(player, block, key); + } + + @EventHandler + public void inventoryClick(InventoryClickEvent event) + { + if (event.getClickedInventory() == null) + { + return; + } + + ItemStack itemStack = event.getCurrentItem(); + + if (itemStack == null) + { + return; + } + + handleRewardItem((Player) event.getWhoClicked(), itemStack); + } + + @EventHandler + public void pickupItem(PlayerPickupItemEvent event) + { + if (event.getItem() == null) + { + return; + } + + handleRewardItem(event.getPlayer(), event.getItem().getItemStack()); + } + + public void handleRewardItem(Player player, ItemStack itemStack) + { + LootItem lootItem = fromItemStack(itemStack); + + if (lootItem == null || lootItem.getMetadata() == null) + { + return; + } + + LootItemReward reward = null; + + for (LootItemReward storedReward : _itemRewards) + { + if (storedReward.getItemStack().isSimilar(itemStack)) + { + reward = storedReward; + } + } + + if (reward == null) + { + String[] metadataSplit = lootItem.getMetadata().split(" "); + String key = metadataSplit[0]; + String[] values = new String[metadataSplit.length - 1]; + + for (int i = 1; i < metadataSplit.length; i++) + { + values[i - 1] = metadataSplit[i]; + } + + switch (key) + { + case "RANK_UPGRADE": + reward = new LootRankReward(itemStack); + break; + case "SHARD": + reward = new LootShardReward(Integer.parseInt(values[0]) * 1000, itemStack, Integer.parseInt(values[1])); + break; + case "CHEST": + reward = new LootChestReward(Integer.parseInt(values[0]) * 1000, itemStack, values[1], Integer.parseInt(values[2])); + break; + case "GADGET": + String gadget = ""; + + for (int i = 1; i < values.length; i++) + { + gadget += values[i] + " "; + } + + reward = new LootGadgetReward(Integer.parseInt(values[0]) * 1000, itemStack, gadget.trim()); + break; + default: + return; + } + + _itemRewards.add(reward); + } + + reward.collectItem(player); + } + + @EventHandler + public void gemClick(PlayerInteractEvent event) + { + if (!UtilEvent.isAction(event, ActionType.R)) + { + return; + } + + Player player = event.getPlayer(); + ItemStack itemStack = player.getItemInHand(); + + if (itemStack == null) + { + return; + } + + LootItem lootItem = fromItemStack(itemStack); + + if (lootItem == null || lootItem.getMetadata() == null || !lootItem.getMetadata().startsWith(GEM_METADATA)) + { + return; + } + + player.setItemInHand(UtilInv.decrement(itemStack)); + + int amount = Integer.parseInt(lootItem.getMetadata().split(" ")[1]); + + _economy.addToStore(player, "Gem Item", amount); + } + + @EventHandler + public void mapUpdate(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + _shownPlayers.clear(); + + for (Player player : Bukkit.getOnlinePlayers()) + { + UUID key = player.getUniqueId(); + + for (LootItemReward itemReward : _itemRewards) + { + if (itemReward.getPlayer().equals(player)) + { + _shownPlayers.add(key); + break; + } + } + } + } + + @EventHandler + public void mapTeleport(PlayerTeleportIntoMapEvent event) + { + event.getPlayer().getInventory().addItem(SPAWN_ITEMS); + } + + @EventHandler + public void cashOutComplete(PlayerCashOutCompleteEvent event) + { + Player player = event.getPlayer(); + Iterator iterator = _itemRewards.iterator(); + + while (iterator.hasNext()) + { + LootItemReward reward = iterator.next(); + + if (player.equals(reward.getPlayer())) + { + reward.success(); + iterator.remove(); + } + } + } + + public final Set getShownPlayers() + { + return _shownPlayers; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/SpawnedChest.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/SpawnedChest.java new file mode 100644 index 000000000..f0a8ae9dc --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/SpawnedChest.java @@ -0,0 +1,59 @@ +package mineplex.gemhunters.loot; + +import org.bukkit.Location; + +public class SpawnedChest +{ + + private Location _location; + private ChestProperties _properties; + private int _id; + private long _spawnedAt; + + private long _openedAt; + + public SpawnedChest(Location location, ChestProperties properties, int id) + { + _location = location; + _properties =properties; + _id = id; + _spawnedAt = System.currentTimeMillis(); + _openedAt = 0; + } + + public void setOpened() + { + _openedAt = System.currentTimeMillis(); + } + + public Location getLocation() + { + return _location; + } + + public ChestProperties getProperties() + { + return _properties; + } + + public int getID() + { + return _id; + } + + public long getSpawnedAt() + { + return _spawnedAt; + } + + public long getOpenedAt() + { + return _openedAt; + } + + public boolean isOpened() + { + return _openedAt != 0; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/command/SpawnChestCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/command/SpawnChestCommand.java new file mode 100644 index 000000000..9e0040952 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/command/SpawnChestCommand.java @@ -0,0 +1,47 @@ +package mineplex.gemhunters.loot.command; + +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.gemhunters.loot.LootModule; + +public class SpawnChestCommand extends CommandBase +{ + + public SpawnChestCommand(LootModule plugin) + { + super(plugin, Rank.ADMIN, "spawnchest"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length == 0) + { + caller.sendMessage(F.help("/" + _aliasUsed + " ", "Spawns a chest at your location.", GetRequiredRank())); + return; + } + + String colour = args[0].toUpperCase(); + + try + { + DyeColor.valueOf(colour); + } + catch (IllegalArgumentException e) + { + caller.sendMessage(F.main(Plugin.getName(), "That is not a valid colour.")); + return; + } + + caller.sendMessage(F.main(Plugin.getName(), "Spawned a " + colour + " chest at your location.")); + + caller.getLocation().getBlock().setType(Material.CHEST); + Plugin.addSpawnedChest(caller.getLocation(), colour); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/command/UpdateLootCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/command/UpdateLootCommand.java new file mode 100644 index 000000000..c556148a8 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/command/UpdateLootCommand.java @@ -0,0 +1,33 @@ +package mineplex.gemhunters.loot.command; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.gemhunters.loot.LootModule; + +/** + * An ADMIN command that allows users to retrieve the latest data from the + * google sheet and update all locally cached loot tables. + */ +public class UpdateLootCommand extends CommandBase +{ + + public UpdateLootCommand(LootModule plugin) + { + super(plugin, Rank.ADMIN, "updateloot"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length > 1) + { + // TODO send redis message + } + + caller.sendMessage(F.main(Plugin.getName(), "This command is currently disabled due to development issues.")); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/deserialisers/ChestPropertiesDeserialiser.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/deserialisers/ChestPropertiesDeserialiser.java new file mode 100644 index 000000000..15898b8fb --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/deserialisers/ChestPropertiesDeserialiser.java @@ -0,0 +1,43 @@ +package mineplex.gemhunters.loot.deserialisers; + +import org.bukkit.Material; + +import mineplex.core.google.SheetObjectDeserialiser; +import mineplex.gemhunters.loot.ChestProperties; + +public class ChestPropertiesDeserialiser implements SheetObjectDeserialiser +{ + + @Override + public ChestProperties deserialise(String[] values) throws ArrayIndexOutOfBoundsException + { + String name = values[0]; + Material blockMaterial = Material.valueOf(values[1]); + String dataKey = values[2]; + + int minAmount = 1; + int maxAmount = 1; + + String[] numbers = values[3].split("-"); + + if (numbers.length != 2) + { + minAmount = Integer.parseInt(String.valueOf(values[3])); + maxAmount = minAmount; + } + else + { + minAmount = Integer.parseInt(numbers[0]); + maxAmount = Integer.parseInt(numbers[1]); + } + + int spawnRate = Integer.parseInt(values[4]); + int expireRate = Integer.parseInt(values[5]); + int maxChestsPerLoc = Integer.parseInt(values[6]); + int spawnRadius = Integer.parseInt(values[7]); + int maxActive = Integer.parseInt(values[8]); + + return new ChestProperties(name, blockMaterial, dataKey, minAmount, maxAmount, maxChestsPerLoc, spawnRate, expireRate, spawnRadius, maxActive); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/deserialisers/LootItemDeserialiser.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/deserialisers/LootItemDeserialiser.java new file mode 100644 index 000000000..61fc76602 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/deserialisers/LootItemDeserialiser.java @@ -0,0 +1,100 @@ +package mineplex.gemhunters.loot.deserialisers; + +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; + +import mineplex.core.google.SheetObjectDeserialiser; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.gemhunters.loot.LootItem; +import net.md_5.bungee.api.ChatColor; + +/** + * This is a {@link LootItem} deserialiser for Google Sheet interpretation.
+ *
+ * Arguments should follow the form:
+ *
    + *
  • Material
  • + *
  • Material Data
  • + *
  • Max Durability
  • + *
  • Amount
  • + *
  • Item Name (optional)
  • + *
  • Item Lore (optional) each line separated by colons
  • + *
  • Enchantments (optional) Has a NAME:LEVEL format with multiple + * enchantments being separated by commas
  • + *
  • Probability
  • + *
  • Metadata (optional)
  • + *
+ * Thus derserialise is guaranteed to have at least 8 strings passed in.
+ * If an illegal argument is passed in, derserialise will throw an exception, + * these should be handled by the caller. + * + * @see SheetObjectDeserialiser + */ +public class LootItemDeserialiser implements SheetObjectDeserialiser +{ + + @Override + public LootItem deserialise(String[] values) throws ArrayIndexOutOfBoundsException, IllegalArgumentException, NumberFormatException + { + Material material = Material.valueOf(values[0]); + byte data = values[1].equals("") ? 0 : Byte.parseByte(values[1]); + int minAmount = 1; + int maxAmount = 1; + short durability = values[2].equals("") ? 0 : Short.valueOf(values[2]); + + String[] numbers = values[3].split("-"); + + if (numbers.length != 2) + { + minAmount = Integer.parseInt(values[3].equals("") ? "1" : values[3]); + maxAmount = minAmount; + } + else + { + minAmount = Integer.parseInt(numbers[0]); + maxAmount = Integer.parseInt(numbers[1]); + } + + ItemBuilder builder = new ItemBuilder(material, data); + + builder.setDurability(durability); + + String title = ChatColor.translateAlternateColorCodes('&', values[4]); + + builder.setTitle(title); + + if (!values[5].equals("")) + { + String[] lore = values[5].split(":"); + String[] colouredLore = new String[lore.length]; + + int loreIndex = 0; + for (String line : lore) + { + colouredLore[loreIndex++] = ChatColor.translateAlternateColorCodes('&', line); + } + + builder.setLore(colouredLore); + } + + String[] enchants = String.valueOf(values[6]).split(","); + + for (String enchant : enchants) + { + String[] enchantData = enchant.split(":"); + + if (enchantData.length < 2) + { + continue; + } + + builder.addEnchantment(Enchantment.getByName(enchantData[0]), Integer.parseInt(enchantData[1])); + } + + double proability = Double.parseDouble(values[7]); + String metadata = values.length > 8 ? values[8] : null; + + return new LootItem(builder.build(), minAmount, maxAmount, proability, metadata); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/event/PlayerChestOpenEvent.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/event/PlayerChestOpenEvent.java new file mode 100644 index 000000000..fb7d40583 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/event/PlayerChestOpenEvent.java @@ -0,0 +1,60 @@ +package mineplex.gemhunters.loot.event; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +import mineplex.gemhunters.loot.ChestProperties; + +public class PlayerChestOpenEvent extends PlayerEvent implements Cancellable +{ + + private static final HandlerList HANDLERS = new HandlerList(); + + private boolean _cancel; + private final Block _block; + private final ChestProperties _properties; + + public PlayerChestOpenEvent(Player who, Block block, ChestProperties properties) + { + super(who); + + _block = block; + _properties = properties; + } + + public Block getChest() + { + return _block; + } + + public ChestProperties getProperties() + { + return _properties; + } + + public HandlerList getHandlers() + { + return HANDLERS; + } + + public static HandlerList getHandlerList() + { + return HANDLERS; + } + + @Override + public boolean isCancelled() + { + return _cancel; + } + + @Override + public void setCancelled(boolean cancel) + { + _cancel = cancel; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootChestReward.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootChestReward.java new file mode 100644 index 000000000..5ef354ec1 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootChestReward.java @@ -0,0 +1,52 @@ +package mineplex.gemhunters.loot.rewards; + +import org.bukkit.inventory.ItemStack; + +import mineplex.core.Managers; +import mineplex.core.common.util.Callback; +import mineplex.core.inventory.InventoryManager; + +public class LootChestReward extends LootItemReward +{ + + private final InventoryManager _inventory; + + private final String _chestName; + private final int _amount; + + public LootChestReward(long cashOutDelay, ItemStack itemStack, String chestName, int amount) + { + super(chestName + " Chest", cashOutDelay, itemStack); + + _inventory = Managers.require(InventoryManager.class); + _chestName = chestName; + _amount = amount; + } + + @Override + public void onCollectItem() + { + + } + + @Override + public void onSuccessful() + { + _inventory.addItemToInventory(new Callback() + { + + @Override + public void run(Boolean success) + { + //DebugModule.getInstance().d("Success= " + success); + } + }, _player, _chestName + " Chest", _amount); + } + + @Override + public void onDeath() + { + + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootGadgetReward.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootGadgetReward.java new file mode 100644 index 000000000..59f9db30f --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootGadgetReward.java @@ -0,0 +1,54 @@ +package mineplex.gemhunters.loot.rewards; + +import org.bukkit.inventory.ItemStack; + +import mineplex.core.Managers; +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.donation.DonationManager; +import mineplex.core.donation.Donor; + +public class LootGadgetReward extends LootItemReward +{ + + private final DonationManager _donation; + + private final String _gadget; + + public LootGadgetReward(long cashOutDelay, ItemStack itemStack, String gadget) + { + super(gadget, cashOutDelay, itemStack); + + _donation = Managers.require(DonationManager.class); + _gadget = gadget; + } + + @Override + public void onCollectItem() + { + + } + + @Override + public void onSuccessful() + { + Donor donor = _donation.Get(_player); + + if (donor.ownsUnknownSalesPackage(_gadget)) + { + //DebugModule.getInstance().d("Shard duplicate"); + _donation.rewardCurrencyUntilSuccess(GlobalCurrency.TREASURE_SHARD, _player, "Earned", (int) (500 + 1000 * Math.random())); + } + else + { + //DebugModule.getInstance().d("Adding gadget"); + _donation.purchaseUnknownSalesPackage(_player, _gadget, GlobalCurrency.TREASURE_SHARD, 0, true, null); + } + } + + @Override + public void onDeath() + { + + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootItemReward.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootItemReward.java new file mode 100644 index 000000000..0ed3b9df2 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootItemReward.java @@ -0,0 +1,94 @@ +package mineplex.gemhunters.loot.rewards; + +import org.bukkit.entity.Player; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.recharge.Recharge; + +public abstract class LootItemReward +{ + + private String _name; + + private long _firstItemPickup; + private long _cashOutDelay; + + protected Player _player; + private ItemStack _itemStack; + + public LootItemReward(String name, long cashOutDelay, ItemStack itemStack) + { + _name = name; + _firstItemPickup = 0; + _cashOutDelay = cashOutDelay; + _itemStack = itemStack; + } + + public abstract void onCollectItem(); + + public abstract void onSuccessful(); + + public abstract void onDeath(); + + public final void collectItem(Player player) + { + if (player.equals(_player)) + { + return; + } + + if (_firstItemPickup == 0) + { + String title = C.cYellow + player.getName(); + String subtitle = C.cGray + "Collected a " + F.elem(_name) + " reward. Killing them will drop it!"; + String chatMessage = F.main("Game", title + " " + subtitle + " They will not be able to quit out of the game for " + F.time(UtilTime.MakeStr(_cashOutDelay) + ".")); + + UtilTextMiddle.display(title, subtitle, 20, 60, 20, UtilServer.getPlayers()); + UtilServer.broadcast(chatMessage); + + _firstItemPickup = System.currentTimeMillis(); + } + else + { + String message = F.main("Game", F.name(player.getName()) + " now has the " + F.elem(_name) + " reward!"); + + UtilServer.broadcast(message); + } + + Recharge.Instance.useForce(player, "Cash Out", _cashOutDelay, false); + _player = player; + onCollectItem(); + } + + public final void success() + { + //DebugModule.getInstance().d("Success"); + onSuccessful(); + } + + public final void death(PlayerDeathEvent event) + { + } + + public boolean isFirstPickup() + { + return _firstItemPickup == 0; + } + + public Player getPlayer() + { + return _player; + } + + public ItemStack getItemStack() + { + return _itemStack; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootRankReward.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootRankReward.java new file mode 100644 index 000000000..85ffc4e6d --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootRankReward.java @@ -0,0 +1,85 @@ +package mineplex.gemhunters.loot.rewards; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.inventory.ItemStack; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClient; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.Rank; +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.F; +import mineplex.core.donation.DonationManager; + +public class LootRankReward extends LootItemReward +{ + + private static final long CASH_OUT_DELAY = TimeUnit.MINUTES.toMillis(15); + private static final int CONSOLATION_PRICE = 10000; + + private final CoreClientManager _clientManager; + private final DonationManager _donation; + + public LootRankReward(ItemStack itemStack) + { + super("Rank", CASH_OUT_DELAY, itemStack); + + _clientManager = Managers.require(CoreClientManager.class); + _donation = Managers.require(DonationManager.class); + } + + @Override + public void onCollectItem() + { + } + + @Override + public void onSuccessful() + { + CoreClient client = _clientManager.Get(_player); + Rank rank = client.GetRank(); + Rank newRank = null; + + // I could have done this so it runs off the order of the Rank enum, + // however knowing some people that might get changed so I'm just going + // to hard code what you get. + + switch (rank) + { + case ALL: + newRank = Rank.ULTRA; + break; + case ULTRA: + newRank = Rank.HERO; + break; + case HERO: + newRank = Rank.LEGEND; + break; + case LEGEND: + newRank = Rank.TITAN; + break; + case TITAN: + newRank = Rank.ETERNAL; + break; + default: + break; + } + + // A suitable rank could not be found. + if (newRank == null) + { + _player.sendMessage(F.main("Loot", "Since you already have eternal ( You are lucky :) ). So instead you can have " + CONSOLATION_PRICE + " shards.")); + _donation.Get(_player).addBalance(GlobalCurrency.TREASURE_SHARD, CONSOLATION_PRICE); + return; + } + + client.SetRank(newRank, false); + _clientManager.getRepository().saveRank(null, _player.getName(), _player.getUniqueId(), newRank, true); + } + + @Override + public void onDeath() + { + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootShardReward.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootShardReward.java new file mode 100644 index 000000000..af1119a73 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootShardReward.java @@ -0,0 +1,42 @@ +package mineplex.gemhunters.loot.rewards; + +import org.bukkit.inventory.ItemStack; + +import mineplex.core.Managers; +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.donation.DonationManager; + +public class LootShardReward extends LootItemReward +{ + + private final DonationManager _donation; + + private final int _amount; + + public LootShardReward(long cashOutDelay, ItemStack itemStack, int amount) + { + super("Shard", cashOutDelay, itemStack); + + _donation = Managers.require(DonationManager.class); + _amount = amount; + } + + @Override + public void onCollectItem() + { + + } + + @Override + public void onSuccessful() + { + _donation.rewardCurrencyUntilSuccess(GlobalCurrency.TREASURE_SHARD, _player, "Earned", _amount); + } + + @Override + public void onDeath() + { + + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapModule.java new file mode 100644 index 000000000..b92d9fe61 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapModule.java @@ -0,0 +1,977 @@ +package mineplex.gemhunters.map; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map.Entry; + +import org.apache.commons.io.FileUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.util.LongHash; +import org.bukkit.craftbukkit.v1_8_R3.util.LongObjectHashMap; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.map.MapRenderer; +import org.bukkit.map.MapView; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multisets; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilEvent; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilInv; +import mineplex.core.common.util.UtilItem; +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.common.util.UtilTime.TimeUnit; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.portal.events.ServerTransferEvent; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.death.event.PlayerCustomRespawnEvent; +import net.minecraft.server.v1_8_R3.Block; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.Blocks; +import net.minecraft.server.v1_8_R3.Chunk; +import net.minecraft.server.v1_8_R3.ChunkProviderServer; +import net.minecraft.server.v1_8_R3.ChunkRegionLoader; +import net.minecraft.server.v1_8_R3.IBlockData; +import net.minecraft.server.v1_8_R3.MaterialMapColor; +import net.minecraft.server.v1_8_R3.PersistentCollection; +import net.minecraft.server.v1_8_R3.WorldServer; + +/** + * All item map code was adapted from Clans.
+ */ +@ReflectivelyCreateMiniPlugin +public class ItemMapModule extends MiniPlugin +{ + // Every BLOCK_SCAN_INTERVAL we add as a new region to scan + private static final int BLOCK_SCAN_INTERVAL = 16 * 3; + // 1536 is the width of the entire world from one borderland to the other + private static final int HALF_WORLD_SIZE = 768; + // This slot is where the Clans Map will go by default + private static final int CLANS_MAP_SLOT = 8; + + private static final String[] ZOOM_INFO; + + static + { + ZOOM_INFO = new String[4]; + for (int zoomLevel = 0; zoomLevel <= 3; zoomLevel++) + { + StringBuilder progressBar = new StringBuilder(C.cBlue); + + boolean colorChange = false; + for (int i = 2; i >= 0; i--) + { + if (!colorChange && i < zoomLevel) + { + progressBar.append(C.cGray); + colorChange = true; + } + char c; + switch (i) + { + case 0: + c = '█'; + break; + case 1: + c = '▆'; + break; + default: + c = '▄'; + break; + } + for (int a = 0; a < 4; a++) + { + progressBar.append(c); + } + + if (i > 0) + { + progressBar.append(" "); + } + } + ZOOM_INFO[zoomLevel] = progressBar.toString(); + } + } + + private Comparator> _comparator; + private int[][] _heightMap = new int[(HALF_WORLD_SIZE * 2) + 16][]; + private HashMap _map = new HashMap(); + private short _mapId = -1; + private HashMap _mapInfo = new HashMap(); + private HashMap _scale = new HashMap(); + // Use LinkedList because operations are either add(Entry) which is O(1) and remove(0) which is O(1) on LinkedList but O(n) on ArrayList + private LinkedList> _scanList = new LinkedList>(); + private World _world; + private WorldServer _nmsWorld; + private ChunkProviderServer _chunkProviderServer; + private ChunkRegionLoader _chunkRegionLoader; + + private ItemMapModule() + { + super("ItemMapManager"); + + _comparator = (o1, o2) -> + { + // Render the places outside the map first to speed up visual errors fixing + int outsideMap = Boolean.compare(o1.getValue() < -HALF_WORLD_SIZE, o2.getValue() < -HALF_WORLD_SIZE); + + if (outsideMap != 0) + { + return -outsideMap; + } + + double dist1 = 0; + double dist2 = 0; + + for (Player player : UtilServer.getPlayers()) + { + dist1 += getDistance(o1, player.getLocation().getX(), player.getLocation().getZ()); + dist2 += getDistance(o2, player.getLocation().getX(), player.getLocation().getZ()); + } + + if (dist1 != dist2) + { + return Double.compare(dist1, dist2); + } + + dist1 = getDistance(o1, 0, 0); + dist2 = getDistance(o2, 0, 0); + + return Double.compare(dist1, dist2); + + }; + + _scale.put(0, 1); + // _scale.put(1, 2); + _scale.put(1, 4); + _scale.put(2, 8); + _scale.put(3, 13); + // _scale.put(5, 16); + + for (Entry entry : _scale.entrySet()) + { + int size = (HALF_WORLD_SIZE * 2) / entry.getValue(); + Byte[][] bytes = new Byte[size][]; + + for (int i = 0; i < size; i++) + { + bytes[i] = new Byte[size]; + } + + _map.put(entry.getKey(), bytes); + } + + for (int i = 0; i < _heightMap.length; i++) + { + _heightMap[i] = new int[_heightMap.length]; + } + + _world = Bukkit.getWorld("world"); + + try + { + Field chunkLoader = ChunkProviderServer.class.getDeclaredField("chunkLoader"); + chunkLoader.setAccessible(true); + _nmsWorld = ((CraftWorld) _world).getHandle(); + _chunkProviderServer = _nmsWorld.chunkProviderServer; + _chunkRegionLoader = (ChunkRegionLoader) chunkLoader.get(_chunkProviderServer); + if (_chunkRegionLoader == null) + { + throw new RuntimeException("Did not expect null chunkLoader"); + } + } + catch (ReflectiveOperationException e) + { + throw new RuntimeException("Could not reflectively access ChunkRegionLoader", e); + } + + try + { + File file = new File("world/gem_hunters_map_id"); + File foundFile = null; + + for (File f : new File("world/data").listFiles()) + { + if (f.getName().startsWith("map_")) + { + foundFile = f; + break; + } + } + + if (foundFile == null) + { + PersistentCollection collection = ((CraftWorld) _world).getHandle().worldMaps; + Field f = collection.getClass().getDeclaredField("d"); + f.setAccessible(true); + ((HashMap) f.get(collection)).put("map", (short) 0); + } + + if (file.exists()) + { + BufferedReader br = new BufferedReader(new FileReader(file)); + _mapId = Short.parseShort(br.readLine()); + br.close(); + + if (foundFile == null) + { + _mapId = -1; + file.delete(); + } + else + { + for (int i = _mapId; i <= _mapId + 100; i++) + { + File file1 = new File("world/data/map_" + i + ".dat"); + + if (!file1.exists()) + { + FileUtils.copyFile(foundFile, file1); + } + + setupRenderer(Bukkit.getMap((short) i)); + } + } + } + + if (_mapId < 0) + { + MapView view = Bukkit.createMap(_world); + _mapId = view.getId(); + setupRenderer(view); + + for (int i = 0; i < 100; i++) + { + setupRenderer(Bukkit.createMap(_world));// Ensures the following 100 maps are unused + } + + file.createNewFile(); + + PrintWriter writer = new PrintWriter(file, "UTF-8"); + writer.print(_mapId); + writer.close(); + } + } + catch (Exception ex) + { + ex.printStackTrace(); + } + + rebuildScan(); + initialScan(); + } + + private void initialScan() + { + System.out.println("Beginning initial scan. There are " + _scanList.size() + " regions to scan"); + + // How many regions before logging an update (Currently set to every 20%) + int logPer = _scanList.size() / 5; + + while (!_scanList.isEmpty()) + { + Entry entry = _scanList.remove(0); + if (_scanList.size() % logPer == 0) + { + System.out.println("Running initial render... " + _scanList.size() + " sections to go"); + } + + int startingX = entry.getKey(); + int startingZ = entry.getValue(); + + boolean outsideMap = startingZ < -HALF_WORLD_SIZE; + + scanWorldMap(startingX, startingZ, !outsideMap, true); + + if (outsideMap) + { + continue; + } + + for (int scale = 1; scale < _scale.size(); scale++) + { + if (scale == 3) + continue; + + drawWorldScale(scale, startingX, startingZ); + colorWorldHeight(scale, startingX, startingZ); + } + + colorWorldHeight(0, startingX, startingZ); + } + + for (int x = -HALF_WORLD_SIZE; x < HALF_WORLD_SIZE; x += BLOCK_SCAN_INTERVAL) + { + for (int z = -HALF_WORLD_SIZE; z < HALF_WORLD_SIZE; z += BLOCK_SCAN_INTERVAL) + { + drawWorldScale(3, x, z); + colorWorldHeight(3, x, z); + } + } + + System.out.println("Finished first map scan and render"); + } + + private void setupRenderer(MapView view) + { + for (MapRenderer renderer : view.getRenderers()) + { + view.removeRenderer(renderer); + } + + view.addRenderer(new ItemMapRenderer()); + } + + /** + * Get the center of the map. + */ + public int calcMapCenter(int zoom, int cord) + { + int mapSize = HALF_WORLD_SIZE / zoom; // This is how large the map is in pixels + + int mapCord = cord / zoom; // This is pixels from true center of map, not held map + + int fDiff = mapSize - -mapCord; + int sDiff = mapSize - mapCord; + + double chunkBlock = cord & 0xF; + cord -= chunkBlock; + chunkBlock /= zoom; + + /*if ((fDiff < 64 || sDiff < 64) && (Math.abs(fDiff - sDiff) > 1)) + { + cord += (fDiff > sDiff ? Math.floor(chunkBlock) : Math.ceil(chunkBlock)); + } + else*/ + { + cord += (int) Math.floor(chunkBlock) * zoom; + } + + while ((fDiff < 64 || sDiff < 64) && (Math.abs(fDiff - sDiff) > 1)) + { + int change = (fDiff > sDiff ? -zoom : zoom); + cord += change; + + mapCord = cord / zoom; + + fDiff = mapSize - -mapCord; + sDiff = mapSize - mapCord; + } + + return cord; + } + + private void colorWorldHeight(int scale, int startingX, int startingZ) + { + Byte[][] map = _map.get(scale); + int zoom = getZoom(scale); + + for (int x = startingX; x < startingX + BLOCK_SCAN_INTERVAL; x += zoom) + { + double d0 = 0; + + // Prevents ugly lines for the first line of Z + + for (int addX = 0; addX < zoom; addX++) + { + for (int addZ = 0; addZ < zoom; addZ++) + { + int hX = x + addX + HALF_WORLD_SIZE; + int hZ = (startingZ - zoom) + addZ + HALF_WORLD_SIZE; + + if (hX >= HALF_WORLD_SIZE * 2 || hZ >= HALF_WORLD_SIZE * 2) + { + continue; + } + + d0 += _heightMap[hX + 16][hZ + 16] / (zoom * zoom); + } + } + + for (int z = startingZ; z < startingZ + BLOCK_SCAN_INTERVAL; z += zoom) + { + // Water depth colors not included + double d1 = 0; + + for (int addX = 0; addX < zoom; addX++) + { + for (int addZ = 0; addZ < zoom; addZ++) + { + int hX = x + addX + HALF_WORLD_SIZE; + int hZ = z + addZ + HALF_WORLD_SIZE; + + if (hX >= HALF_WORLD_SIZE * 2 || hZ >= HALF_WORLD_SIZE * 2) + { + continue; + } + + d1 += _heightMap[hX + 16][hZ + 16] / (zoom * zoom); + } + } + + double d2 = (d1 - d0) * 4.0D / (zoom + 4) + ((x + z & 0x1) - 0.5D) * 0.4D; + byte b0 = 1; + + d0 = d1; + + if (d2 > 0.6D) + { + b0 = 2; + } + else if (d2 > 1.2D) + { + b0 = 3; + } + else if (d2 < -0.6D) + { + b0 = 0; + } + + int origColor = map[(x + HALF_WORLD_SIZE) / zoom][(z + HALF_WORLD_SIZE) / zoom] - 1; + + /*if (color < 4) + { + d2 = waterDepth * 0.1D + (k1 + j2 & 0x1) * 0.2D; + b0 = 1; + if (d2 < 0.5D) + { + b0 = 2; + } + + if (d2 > 0.9D) + { + b0 = 0; + } + }*/ + + byte color = (byte) (origColor + b0); + if((color <= -113 || color >= 0) && color <= 127) + { + map[(x + HALF_WORLD_SIZE) / zoom][(z + HALF_WORLD_SIZE) / zoom] = color; + } + else + { +// System.out.println(String.format("Tried to set color to %s in colorWorldHeight scale: %s, sx: %s, sz: %s, x: %s, z: %s, zoom: %s", +// color, scale, startingX, startingZ, x, z, zoom)); + } + } + } + } + + private void drawWorldScale(int scale, int startingX, int startingZ) + { + Byte[][] first = _map.get(0); + Byte[][] second = _map.get(scale); + int zoom = getZoom(scale); + + for (int x = startingX; x < startingX + BLOCK_SCAN_INTERVAL; x += zoom) + { + for (int z = startingZ; z < startingZ + BLOCK_SCAN_INTERVAL; z += zoom) + { + HashMultiset hashmultiset = HashMultiset.create(); + + for (int addX = 0; addX < zoom; addX++) + { + for (int addZ = 0; addZ < zoom; addZ++) + { + int pX = x + addX + HALF_WORLD_SIZE; + int pZ = z + addZ + HALF_WORLD_SIZE; + + if (pX >= first.length || pZ >= first.length) + { + continue; + } + + Byte b = first[pX][pZ]; + + hashmultiset.add(b); + } + } + + Byte color; + try + { + color = Iterables.getFirst(Multisets.copyHighestCountFirst(hashmultiset), (byte) 0); + } + catch (Exception e) + { + color = (byte) 0; + } + second[(x + HALF_WORLD_SIZE) / zoom][(z + HALF_WORLD_SIZE) / zoom] = color; + } + } + } + + @EventHandler + public void dropItem(ItemSpawnEvent event) + { + if (isItemClansMap(event.getEntity().getItemStack())) + event.getEntity().remove(); + } + + public void removeMap(Player player) + { + for (int slot = 0; slot < player.getInventory().getSize(); slot++) + { + if (isItemClansMap(player.getInventory().getItem(slot))) + player.getInventory().setItem(slot, null); + } + } + + private double getDistance(double x1, double z1, double x2, double z2) + { + x1 = (x1 - x2); + z1 = (z1 - z2); + + return (x1 * x1) + (z1 * z1); + } + + private double getDistance(Entry entry, double x1, double z1) + { + return getDistance(x1, z1, entry.getKey() + (BLOCK_SCAN_INTERVAL / 2), entry.getValue() + (BLOCK_SCAN_INTERVAL / 2)); + } + + public Byte[][] getMap(int scale) + { + return _map.get(scale); + } + + public MapInfo getMap(Player player) + { + return _mapInfo.get(player.getName()); + } + + public int getMapSize() + { + return HALF_WORLD_SIZE; + } + + public int getZoom(int scale) + { + return _scale.get(scale); + } + + //fixme So what appears to happen is that after you die, if your map is is the same then the map is frozen + @EventHandler + public void onDeath(PlayerDeathEvent event) + { + MapInfo info = getMap(event.getEntity()); + + info.setMap(Math.min(_mapId + 100, info.getMap() + 1)); + } + + @EventHandler + public void onHotbarMove(PlayerItemHeldEvent event) + { + Player player = event.getPlayer(); + + if (!isItemClansMap(player.getInventory().getItem(event.getNewSlot()))) + return; + + showZoom(player, getMap(player)); + } + + @EventHandler + public void onInteract(PlayerInteractEvent event) + { + if (event.getAction() == Action.PHYSICAL) + return; + + if (!isItemClansMap(event.getItem())) + return; + + event.setCancelled(true); + + Player player = event.getPlayer(); + + MapInfo info = getMap(player); + + boolean zoomIn = UtilEvent.isAction(event, ActionType.L); + + if (!_scale.containsKey(info.getScale() + (zoomIn ? -1 : 1))) + { + return; + } + + if (!info.canZoom()) + { + long remainingTime = (info.getZoomCooldown() + 2500) - System.currentTimeMillis(); + + UtilPlayer.message( + player, + F.main("Recharge", + "You cannot use " + F.skill("Map Zoom") + " for " + + F.time(UtilTime.convertString((remainingTime), 1, TimeUnit.FIT)) + ".")); + return; + } + + info.addZoom(); + + if (zoomIn) + { + int newScale = info.getScale() - 1; + Location loc = player.getLocation(); + + int zoom = getZoom(newScale); + + info.setInfo(newScale, calcMapCenter(zoom, loc.getBlockX()), calcMapCenter(zoom, loc.getBlockZ())); + } + else + { + int newScale = info.getScale() + 1; + Location loc = player.getLocation(); + + int zoom = getZoom(newScale); + + info.setInfo(newScale, calcMapCenter(zoom, loc.getBlockX()), calcMapCenter(zoom, loc.getBlockZ())); + } + + showZoom(player, info); + } + + @EventHandler + public void teleportIn(PlayerCustomRespawnEvent event) + { + MapInfo info = new MapInfo(_mapId); + + Player player = event.getPlayer(); + Location loc = player.getLocation(); + + int zoom = getZoom(1); + + info.setInfo(1, calcMapCenter(zoom, loc.getBlockX()), calcMapCenter(zoom, loc.getBlockZ())); + _mapInfo.put(player.getName(), info); + setMap(player); + } + + @EventHandler + public void onWorldChange(PlayerTeleportEvent event) + { + if (event.getFrom().getWorld() != event.getTo().getWorld() && event.getTo().getWorld().equals("world")) + { + runSyncLater(new Runnable() + { + @Override + public void run() + { + setMap(event.getPlayer()); + } + }, 20); + } + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) + { + _mapInfo.remove(event.getPlayer().getName()); + } + + //@EventHandler + public void onServerTransfer(ServerTransferEvent event) + { + Player p = event.getPlayer(); + + p.sendMessage(C.cDRed + C.Bold + "WARNING!"); + p.sendMessage(C.cYellow + "There's a bug where switching servers will freeze the Clans Map!"); + p.sendMessage(C.cYellow + "If you want to play on Clans again, rejoin the Mineplex server!"); + } + + private void rebuildScan() + { + for (int x = -HALF_WORLD_SIZE; x < HALF_WORLD_SIZE; x += BLOCK_SCAN_INTERVAL) + { + for (int z = -HALF_WORLD_SIZE - 16; z < HALF_WORLD_SIZE; z += (z < -HALF_WORLD_SIZE ? 16 : BLOCK_SCAN_INTERVAL)) + { + _scanList.add(new HashMap.SimpleEntry<>(x, z)); + } + } + + Collections.sort(_scanList, _comparator); + } + + @EventHandler + public void recenterMap(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + for (Player player : Bukkit.getOnlinePlayers()) + { + MapInfo info = getMap(player); + + if (info == null || info.getScale() >= 3) + { + continue; + } + + Location l = player.getLocation(); + int zoom = getZoom(info.getScale()); + + double mapX = (l.getX() - info.getX()) / zoom; + double mapZ = (l.getZ() - info.getZ()) / zoom; + + if (Math.abs(mapX) > 22 || Math.abs(mapZ) > 22) + { + int newX = calcMapCenter(zoom, l.getBlockX()); + int newZ = calcMapCenter(zoom, l.getBlockZ()); + + if (Math.abs(mapX) > 22 ? newX != info.getX() : newZ != info.getZ()) + { + info.setInfo(newX, newZ); + } + } + } + } + + @EventHandler + public void renderMap(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + return; + + if (_scanList.isEmpty() && UtilServer.getPlayers().length > 0) + { + rebuildScan(); + } + + if (_scanList.size() % 20 == 0) + { + Collections.sort(_scanList, _comparator); + } + + if (_scanList.isEmpty()) + { + return; + } + + Entry entry = _scanList.remove(0); + + int startingX = entry.getKey(); + int startingZ = entry.getValue(); + + boolean outsideMap = startingZ < -HALF_WORLD_SIZE; + + scanWorldMap(startingX, startingZ, !outsideMap, false); + + if (outsideMap) + return; + + for (int scale = 1; scale < _scale.size(); scale++) + { + drawWorldScale(scale, startingX, startingZ); + colorWorldHeight(scale, startingX, startingZ); + } + + colorWorldHeight(0, startingX, startingZ); + } + + + // Let's not create hundreds of thousands of BlockPositions + // Single thread = should be thread safe + private BlockPosition.MutableBlockPosition _blockPosition = new BlockPosition.MutableBlockPosition(); + + // Maps the cached chunks which were loaded from disk to save IO operations + private LongObjectHashMap _chunkCache = new LongObjectHashMap<>(); + + /* + * Remove the cached chunks when the real chunks are loaded in + */ + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void LoadChunk(ChunkLoadEvent event) + { + _chunkCache.remove(LongHash.toLong(event.getChunk().getX(), event.getChunk().getZ())); + } + + /* + * Given a particular coordinate, this method will scan up to BLOCK_SCAN_INTERVAL and record the color of ever 16th block + * If a chunk has not been loaded, the following steps will be taken: + * * Attempt to load the chunk from disk. + * * If the chunk could not be loaded, generate it froms scratch + * Otherwise, the loaded chunk will be used + */ + public void scanWorldMap(int startingX, int startingZ, boolean setColors, boolean isFirstScan) + { + Byte[][] map = _map.get(0); + for (int beginX = startingX; beginX < startingX + BLOCK_SCAN_INTERVAL; beginX += 16) + { + for (int beginZ = startingZ - (startingZ > -HALF_WORLD_SIZE ? 16 : 0); beginZ < startingZ + + (setColors ? BLOCK_SCAN_INTERVAL : 16); beginZ += 16) + { + int chunkX = beginX / 16; + int chunkZ = beginZ / 16; + net.minecraft.server.v1_8_R3.Chunk nmsChunk = _chunkProviderServer.getChunkIfLoaded(chunkX, chunkZ); + if (nmsChunk == null) + { + long key = LongHash.toLong(chunkX, chunkZ); + nmsChunk = _chunkCache.get(key); + if (nmsChunk == null) + { + if (!isFirstScan) + { + continue; + } + try + { + Object[] data = _chunkRegionLoader.loadChunk(_nmsWorld, chunkX, chunkZ); + if (data == null) + { + // Something is wrong with the chunk + System.out.println("Chunk is not generated or missing level/block data. Regenerating (" + chunkX + "," + chunkZ + ")"); + nmsChunk = ((CraftChunk) _world.getChunkAt(chunkX, chunkZ)).getHandle(); + } + else + { + nmsChunk = (net.minecraft.server.v1_8_R3.Chunk) data[0]; + } + } + catch (IOException e) + { + throw new RuntimeException("Chunk is corrupt or not readable!", e); + } + _chunkCache.put(key, nmsChunk); + } + } + + if (!nmsChunk.isEmpty()) + { + for (int x = beginX; x < beginX + 16; x++) + { + for (int z = beginZ; z < beginZ + 16; z++) + { + int color = 0; + + int k3 = x & 0xF; + int l3 = z & 0xF; + + int l4 = nmsChunk.b(k3, l3) + 1; + IBlockData iblockdata = Blocks.AIR.getBlockData(); + + if (l4 > 1) + { + do + { + l4--; + _blockPosition.c(k3, l4, l3); + iblockdata = nmsChunk.getBlockData(_blockPosition); + } + while (iblockdata.getBlock().g(iblockdata) == MaterialMapColor.b && (l4 > 0)); + + if ((l4 > 0) && (iblockdata.getBlock().getMaterial().isLiquid())) + { + int j5 = l4 - 1; + Block block1; + do + { + _blockPosition.c(k3, j5--, l3); + block1 = nmsChunk.getType(_blockPosition); + } + while ((j5 > 0) && (block1.getMaterial().isLiquid())); + } + } + + _heightMap[x + HALF_WORLD_SIZE + 16][z + HALF_WORLD_SIZE + 16] = l4; + + if (setColors) + { + //color = block.f(i5).M; + _blockPosition.c(k3, l4, l3); + IBlockData data = nmsChunk.getBlockData(_blockPosition); + color = data.getBlock().g(data).M; + + color = (byte) ((color * 4) + 1); + } + + if (setColors && beginZ >= startingZ) + { + map[x + HALF_WORLD_SIZE][z + HALF_WORLD_SIZE] = (byte) color; + } + } + } + } + } + } + } + + public void setMap(Player player) + { + for (ItemStack item : UtilInv.getItems(player)) + { + if (isItemClansMap(item)) + { + return; + } + } + + ItemStack item = new ItemBuilder(Material.MAP, 1, (short) getMap(player).getMap()).setTitle(C.cGreen + "World Map").build(); + + int slot = CLANS_MAP_SLOT; + + ItemStack mapSlot = player.getInventory().getItem(slot); + if (mapSlot != null && mapSlot.getType() != Material.AIR) + { + + slot = player.getInventory().firstEmpty(); + } + + if (slot >= 0) + { + player.getInventory().setItem(slot, item); + } + } + + /* + * Displays the action bar to a player given their zoom level. Implementation may change + */ + private void showZoom(Player player, MapInfo info) + { + UtilTextBottom.display(ZOOM_INFO[info.getScale()], player); + } + + /* + * Check whether an {@link ItemStack} is also a Clans Map + * + * @param itemStack The {@link ItemStack} to check + * @returns Whether the {@link ItemStack} is also a Clans Map + */ + private boolean isItemClansMap(ItemStack itemStack) + { + return UtilItem.matchesMaterial(itemStack, Material.MAP) + && itemStack.getDurability() >= _mapId + && itemStack.getDurability() <= _mapId + 100; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapRenderer.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapRenderer.java new file mode 100644 index 000000000..69376dec1 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapRenderer.java @@ -0,0 +1,294 @@ +package mineplex.gemhunters.map; + +import java.awt.Color; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapCursor; +import org.bukkit.map.MapCursorCollection; +import org.bukkit.map.MapPalette; +import org.bukkit.map.MapRenderer; +import org.bukkit.map.MapView; + +import mineplex.core.Managers; +import mineplex.core.common.util.UtilTime; +import mineplex.core.party.Party; +import mineplex.core.party.PartyManager; +import mineplex.gemhunters.loot.LootModule; +import mineplex.gemhunters.safezone.SafezoneModule; +import mineplex.gemhunters.supplydrop.SupplyDrop; +import mineplex.gemhunters.supplydrop.SupplyDropModule; +import mineplex.gemhunters.worldevent.WorldEvent; +import mineplex.gemhunters.worldevent.WorldEventModule; + +/** + * All item map code was adapted from Clans.
+ */ +public class ItemMapRenderer extends MapRenderer +{ + + private static final int RENDER_COOLDOWN = 10000; + private static final int STANDARD_Y = 70; + + private final ItemMapModule _itemMap; + private final LootModule _loot; + private final SafezoneModule _safezone; + private final SupplyDropModule _supply; + private final WorldEventModule _worldEvent; + + private final PartyManager _party; + + public ItemMapRenderer() + { + super(true); + + _itemMap = Managers.require(ItemMapModule.class); + _loot = Managers.require(LootModule.class); + _safezone = Managers.require(SafezoneModule.class); + _supply = Managers.require(SupplyDropModule.class); + _worldEvent = Managers.require(WorldEventModule.class); + _party = Managers.require(PartyManager.class); + } + + @Override + public void render(MapView mapView, MapCanvas canvas, Player player) + { + try + { + renderNormalMap(mapView, canvas, player); + } + catch (Throwable t) + { + System.out.println("Error while rendering map"); + t.printStackTrace(); + } + } + + private void renderNormalMap(MapView mapView, MapCanvas canvas, Player player) + { + MapInfo info = _itemMap.getMap(player); + + if (info == null) + { + return; + } + + int scale = info.getScale(); + int zoom = _itemMap.getZoom(scale); + + Byte[][] map = _itemMap.getMap(scale); + + int centerX = info.getX() / zoom; + int centerZ = info.getZ() / zoom; + + // We have this cooldown to squeeze out every single bit of performance + // from the server. + if (UtilTime.elapsed(info.getLastRendered(), RENDER_COOLDOWN)) + { + info.setLastRendered(); + + for (int mapX = 0; mapX < 128; mapX++) + { + for (int mapZ = 0; mapZ < 128; mapZ++) + { + int blockX = centerX + (mapX - 64); + int blockZ = centerZ + (mapZ - 64); + + int pixelX = blockX + (map.length / 2); + int pixelZ = blockZ + (map.length / 2); + + Byte color; + + if (!(pixelX < 0 || pixelZ < 0 || pixelX >= map.length || pixelZ >= map.length) && map[pixelX][pixelZ] != null) + { + color = map[pixelX][pixelZ]; + + blockX *= zoom; + blockZ *= zoom; + + Location location = new Location(mapView.getWorld(), blockX, STANDARD_Y, blockZ); + + boolean safezone = _safezone.isInSafeZone(location); + + if (safezone) + { + boolean colorAll = scale > 0; + Color areaColor = Color.GREEN; + + if (areaColor != null) + { + if (!((color <= -113 || color >= 0) && color <= 127)) + { + color = (byte) 0; + System.out.println(String.format("Tried to draw invalid color %s, player: %s, mapX: %s, mapZ: %s", color, player.getName(), mapX, mapZ)); + } + else + { +// int chunkBX = blockX & 0xF; +// int chunkBZ = blockZ & 0xF; + + // Border + if ( + _safezone.isInSafeZone(new Location(mapView.getWorld(), blockX - 1, STANDARD_Y, blockZ)) || + _safezone.isInSafeZone(new Location(mapView.getWorld(), blockX, STANDARD_Y, blockZ - 1)) || + _safezone.isInSafeZone(new Location(mapView.getWorld(), blockX + 16, STANDARD_Y, blockZ)) || + _safezone.isInSafeZone(new Location(mapView.getWorld(), blockX, STANDARD_Y, blockZ + 1))) + { + Color cColor = MapPalette.getColor(color); + double clans = colorAll ? 1 : 0.8; + double base = 1 - clans; + + int r = (int) ((cColor.getRed() * base) + (areaColor.getRed() * clans)); + int b = (int) ((cColor.getBlue() * base) + (areaColor.getBlue() * clans)); + int g = (int) ((cColor.getGreen() * base) + (areaColor.getGreen() * clans)); + + color = MapPalette.matchColor(r, g, b); + } + + // Inside + else + { + Color cColor = MapPalette.getColor(color); + + double clans = 0.065; + + // Stripes + //boolean checker = (mapX + (mapZ % 4)) % 4 == 0; + double base = 1 - clans; + + int r = (int) ((cColor.getRed() * base) + (areaColor.getRed() * clans)); + int b = (int) ((cColor.getBlue() * base) + (areaColor.getBlue() * clans)); + int g = (int) ((cColor.getGreen() * base) + (areaColor.getGreen() * clans)); + + color = MapPalette.matchColor(r, g, b); + } + } + } + } + } + else + { + color = (byte) 0; + } + + canvas.setPixel(mapX, mapZ, color); + } + } + } + + if (info.isSendMap()) + { + player.sendMap(mapView); + } + + MapCursorCollection cursors = canvas.getCursors(); + + while (cursors.size() > 0) + { + cursors.removeCursor(cursors.getCursor(0)); + } + + for (WorldEvent event : _worldEvent.getActiveEvents()) + { + if (!event.isInProgress()) + { + continue; + } + + Location point = event.getCurrentLocation(); + double mapX = (point.getX() - info.getX()) / zoom; + double mapZ = (point.getZ() - info.getZ()) / zoom; + + // To make these appear at the edges of the map, just change it from + // 64 to something like 128 for double the map size + if (mapX > -64 && mapX < 64 && mapZ > -64 && mapZ < 64) + { + byte b0 = (byte) (int) Math.min(127, (double) (mapX * 2.0F) + 0.5D); + byte b1 = (byte) (int) Math.max(-127, (double) (mapZ * 2.0F) + 0.5D); + + byte cursorType = 5; // http://i.imgur.com/wpH6PT8.png + // Those are byte 5 and 6 + byte rotation = (byte) (int) ((point.getYaw() * 16D) / 360D); + + MapCursor cursor = new MapCursor(b0, b1, rotation, cursorType, true); + + cursors.addCursor(cursor); + } + } + + SupplyDrop supplyDrop = _supply.getActive(); + + if (_supply.isActive()) + { + Location point = supplyDrop.getCurrentLocation(); + double mapX = (point.getX() - info.getX()) / zoom; + double mapZ = (point.getZ() - info.getZ()) / zoom; + + // To make these appear at the edges of the map, just change it from + // 64 to something like 128 for double the map size + if (mapX > -64 && mapX < 64 && mapZ > -64 && mapZ < 64) + { + byte b0 = (byte) (int) Math.min(127, (double) (mapX * 2.0F) + 0.5D); + byte b1 = (byte) (int) Math.max(-127, (double) (mapZ * 2.0F) + 0.5D); + + byte cursorType = 4; // http://i.imgur.com/wpH6PT8.png + // Those are byte 5 and 6 + byte rotation = (byte) ((int) Math.floor(System.currentTimeMillis() / 1000D) % 16); + + MapCursor cursor = new MapCursor(b0, b1, rotation, cursorType, true); + + cursors.addCursor(cursor); + } + } + + Party party = _party.getPartyByPlayer(player); + Set shownPlayers = _loot.getShownPlayers(); + + for (Player other : Bukkit.getOnlinePlayers()) + { + if (player.canSee(other) && other.isValid()) + { + Location l = other.getLocation(); + + double mapX = (l.getX() - info.getX()) / zoom; + double mapZ = (l.getZ() - info.getZ()) / zoom; + + if (mapX > -64 && mapX < 64 && mapZ > -64 && mapZ < 64) + { + MapCursor.Type cursorDisplay = null; + + if (player.equals(other)) + { + cursorDisplay = MapCursor.Type.WHITE_POINTER; + } + else if (shownPlayers.contains(other.getUniqueId())) + { + cursorDisplay = MapCursor.Type.BLUE_POINTER; + } + else if (party != null && party.isMember(other)) + { + cursorDisplay = MapCursor.Type.GREEN_POINTER; + } + + if (cursorDisplay == null) + { + continue; + } + + byte b0 = (byte) (int) Math.min(127, (double) (mapX * 2.0F) + 0.5D); + byte b1 = (byte) (int) Math.max(-127, (double) (mapZ * 2.0F) + 0.5D); + + byte rotation = (byte) (int) ((l.getYaw() * 16D) / 360D); + + MapCursor cursor = new MapCursor(b0, b1, (byte) (rotation & 0xF), cursorDisplay.getValue(), true); + + cursors.addCursor(cursor); + } + } + } + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/MapInfo.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/MapInfo.java new file mode 100644 index 000000000..5af724e57 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/MapInfo.java @@ -0,0 +1,124 @@ +package mineplex.gemhunters.map; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import mineplex.core.common.util.UtilTime; + +public class MapInfo +{ + private int _scale; + private int _centerX; + private int _centerZ; + private long _lastRendered; + private boolean _sendMap; + private List _lastZooms = new ArrayList(); + private int _mapId; + + public MapInfo(int newId) + { + _mapId = newId; + } + + public int getMap() + { + return _mapId; + } + + public void setMap(int newId) + { + _mapId = newId; + } + + public boolean canZoom() + { + Iterator itel = _lastZooms.iterator(); + + while (itel.hasNext()) + { + long lastZoomed = itel.next(); + + if (UtilTime.elapsed(lastZoomed, 2500)) + { + itel.remove(); + } + } + + return _lastZooms.size() < 3; + } + + public void addZoom() + { + _lastZooms.add(System.currentTimeMillis()); + } + + public long getZoomCooldown() + { + long cooldown = 0; + + for (long zoomCooldown : _lastZooms) + { + if (cooldown == 0 || zoomCooldown < cooldown) + { + cooldown = zoomCooldown; + } + } + + return cooldown; + } + + public long getLastRendered() + { + return _lastRendered; + } + + public void setLastRendered() + { + _lastRendered = System.currentTimeMillis(); + } + + public void setInfo(int scale, int x, int z) + { + _lastRendered = 0; + _scale = scale; + _centerX = x; + _centerZ = z; + _sendMap = true; + } + + public void setInfo(int x, int z) + { + _lastRendered = 0; + _centerX = x; + _centerZ = z; + _sendMap = true; + } + + public boolean isSendMap() + { + if (_sendMap) + { + _sendMap = false; + return true; + } + + return false; + } + + public int getX() + { + return _centerX; + } + + public int getZ() + { + return _centerZ; + } + + public int getScale() + { + return _scale; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/MountData.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/MountData.java new file mode 100644 index 000000000..e8aaa9cc0 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/MountData.java @@ -0,0 +1,37 @@ +package mineplex.gemhunters.mount; + +import org.bukkit.entity.LivingEntity; + +import mineplex.core.gadget.gadgets.gamemodifiers.gemhunters.MountType; + +public class MountData +{ + + private MountType _mountType; + private LivingEntity _entity; + + public MountData() + { + + } + + public void setMountType(MountType mountType) + { + _mountType = mountType; + } + + public MountType getMountType() + { + return _mountType; + } + + public void setEntity(LivingEntity entity) + { + _entity = entity; + } + + public LivingEntity getEntity() + { + return _entity; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/MountModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/MountModule.java new file mode 100644 index 000000000..010dea756 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/MountModule.java @@ -0,0 +1,157 @@ +package mineplex.gemhunters.mount; + +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Horse; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Horse.Color; +import org.bukkit.entity.Horse.Style; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.MiniClientPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilEvent; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.gadget.GadgetManager; +import mineplex.core.gadget.gadgets.gamemodifiers.GameModifierType; +import mineplex.core.gadget.gadgets.gamemodifiers.gemhunters.GameModifierMount; +import mineplex.core.gadget.gadgets.gamemodifiers.gemhunters.MountType; +import mineplex.core.recharge.Recharge; +import mineplex.gemhunters.loot.LootItem; +import mineplex.gemhunters.loot.LootModule; + +@ReflectivelyCreateMiniPlugin +public class MountModule extends MiniClientPlugin +{ + + private static final String ITEM_METADATA = "MOUNT"; + + private final LootModule _loot; + private final GadgetManager _gadget; + + private MountModule() + { + super("Mount"); + + _loot = require(LootModule.class); + _gadget = require(GadgetManager.class); + } + + @Override + protected MountData addPlayer(UUID uuid) + { + return new MountData(); + } + + @EventHandler + public void playerInteract(PlayerInteractEvent event) + { + if (!UtilEvent.isAction(event, ActionType.R)) + { + return; + } + + Player player = event.getPlayer(); + ItemStack itemStack = player.getItemInHand(); + + if (itemStack == null) + { + return; + } + + LootItem lootItem = _loot.fromItemStack(itemStack); + + if (lootItem == null || lootItem.getMetadata() == null || !lootItem.getMetadata().startsWith(ITEM_METADATA)) + { + return; + } + + int cooldown = Integer.parseInt(lootItem.getMetadata().split(" ")[1]) * 1000; + + if (!Recharge.Instance.use(player, _moduleName, cooldown, true, true)) + { + return; + } + + spawnMount(player); + } + + public void spawnMount(Player player) + { + GameModifierMount mount = ((GameModifierMount) _gadget.getActiveGameModifier(player, GameModifierType.GemHunters, g -> g != null)); + MountType mountType = null; + + if (mount != null) + { + mountType = mount.getMountType(); + } + + player.sendMessage(F.main(_moduleName, "Mounts are currently disabled.")); + //spawnMount(player, mountType); + } + + public void spawnMount(Player player, MountType mountType) + { + MountData data = Get(player); + LivingEntity entity = data.getEntity(); + EntityType entityType = mountType == null ? EntityType.HORSE : mountType.getEntityType(); + + despawnMount(player); + + entity = (LivingEntity) player.getWorld().spawnEntity(player.getLocation().add(0, 1, 0), entityType); + + if (entity instanceof Tameable) + { + Tameable tameable = (Tameable) entity; + + tameable.setOwner(player); + } + + if (entity instanceof Horse) + { + Horse horse = (Horse) entity; + + horse.setAdult(); + horse.setAgeLock(true); + horse.setColor(Color.BROWN); + horse.setStyle(Style.NONE); + horse.setMaxDomestication(1); + horse.setJumpStrength(1); + horse.getInventory().setSaddle(new ItemStack(Material.SADDLE)); + } + + entity.setCustomName(player.getName() + "\'s Mount"); + entity.setCustomNameVisible(true); + entity.setCanPickupItems(false); + entity.setHealth(1); + entity.setMaxHealth(1); + + entity.setPassenger(player); + + data.setEntity(entity); + data.setMountType(mountType); + } + + public void despawnMount(Player player) + { + MountData data = Get(player); + LivingEntity entity = data.getEntity(); + + if (entity != null) + { + entity.remove(); + } + } + + public boolean isActive(Player player) + { + return Get(player).getEntity() != null; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/event/MountSpawnEvent.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/event/MountSpawnEvent.java new file mode 100644 index 000000000..0414b020f --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/mount/event/MountSpawnEvent.java @@ -0,0 +1,6 @@ +package mineplex.gemhunters.mount.event; + +public class MountSpawnEvent +{ + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/Quest.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/Quest.java new file mode 100644 index 000000000..91d6875d5 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/Quest.java @@ -0,0 +1,146 @@ +package mineplex.gemhunters.quest; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilServer; +import mineplex.core.donation.DonationManager; +import mineplex.gemhunters.economy.EconomyModule; +import mineplex.gemhunters.world.WorldDataModule; + +public abstract class Quest implements Listener +{ + + private final int _id; + private final String _name; + private final String _description; + private final int _startCost; + private final int _completeReward; + + protected final QuestModule _quest; + protected final CoreClientManager _clientManager; + protected final DonationManager _donation; + protected final EconomyModule _economy; + protected final WorldDataModule _worldData; + + private final Map _counter; + + public Quest(int id, String name, String description, int startCost, int completeReward) + { + _id = id; + _name = name; + _description = description; + _startCost = startCost; + _completeReward = completeReward; + + _quest = Managers.require(QuestModule.class); + _clientManager = Managers.require(CoreClientManager.class); + _donation = Managers.require(DonationManager.class); + _economy = Managers.require(EconomyModule.class); + _worldData = Managers.require(WorldDataModule.class); + + _counter = new HashMap<>(); + + UtilServer.getServer().getPluginManager().registerEvents(this, UtilServer.getPlugin()); + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + remove(event.getPlayer()); + } + + public void transfer(Player from, Player to) + { + // If the player has already been progressing this quest and is + // further than the other don't bother transferring their data. + if (get(to) >= get(from)) + { + return; + } + + set(to, get(from)); + } + + public void set(Player player, int amount) + { + _counter.put(player.getUniqueId(), amount); + } + + public int get(Player player) + { + return _counter.getOrDefault(player.getUniqueId(), 0); + } + + public int getAndIncrement(Player player, int amount) + { + int newAmount = get(player) + amount; + _counter.put(player.getUniqueId(), newAmount); + _quest.updateQuestItem(this, player); + + return newAmount; + } + + public void remove(Player player) + { + _counter.remove(player.getUniqueId()); + } + + public void onStart(Player player) + { + _economy.removeFromStore(player, _startCost); + } + + public void onReward(Player player) + { + _economy.addToStore(player, "Completing " + F.elem(_name), _completeReward); + remove(player); + _quest.completeQuest(this, player); + } + + public boolean isActive(Player player) + { + return _quest.isActive(this, player); + } + + public abstract float getProgress(Player player); + + public int getGoal() + { + return 1; + } + + public final int getId() + { + return _id; + } + + public final String getName() + { + return _name; + } + + public final String getDescription() + { + return _description; + } + + public final int getStartCost() + { + return _startCost; + } + + public final int getCompleteReward() + { + return _completeReward; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestModule.java new file mode 100644 index 000000000..ed4d72bac --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestModule.java @@ -0,0 +1,406 @@ +package mineplex.gemhunters.quest; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; + +import mineplex.core.MiniClientPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilItem; +import mineplex.core.common.util.UtilItem.ItemAttribute; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.menu.Menu; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.quest.types.ChestOpenerQuest; +import mineplex.gemhunters.quest.types.SamitoDQuest; +import mineplex.gemhunters.world.WorldDataModule; +import net.md_5.bungee.api.ChatColor; + +@ReflectivelyCreateMiniPlugin +public class QuestModule extends MiniClientPlugin +{ + + private static final int MAX_QUESTS = 5; + private static final long RESET_QUESTS_TIME = TimeUnit.MINUTES.toMillis(15); + private static final Material MATERIAL = Material.PAPER; + private static final String ITEM_METADATA = "quest"; + + private final Quest[] _quests = { + new ChestOpenerQuest(0, "Chest Opener", 100, 250, 5), + new ChestOpenerQuest(1, "Grand Chest Opener", 200, 500, 20), + new ChestOpenerQuest(2, "Superior Chest Opener", 500, 750, 40), + + new SamitoDQuest(3, "Give to the Homeless", "Donate " + F.count(String.valueOf(10)) + " gems to the Hobo.", 100, 300, 10) + }; + + private final WorldDataModule _worldData; + + private QuestModule() + { + super("Quest"); + + _worldData = require(WorldDataModule.class); + + Menu menu = new QuestUI(this); + + runSyncLater(() -> + { + + for (Location location : _worldData.getCustomLocation("QUEST_NPC")) + { + new QuestNPC(this, location, menu); + } + + }, 20); + } + + @Override + protected QuestPlayerData addPlayer(UUID uuid) + { + return new QuestPlayerData(); + } + + @EventHandler + public void playerJoin(PlayerJoinEvent event) + { + updateQuests(event.getPlayer()); + } + + //@EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.SLOW) + { + return; + } + + for (Player player : Bukkit.getOnlinePlayers()) + { + QuestPlayerData playerData = Get(player); + + if (!UtilTime.elapsed(playerData.getLastClear(), RESET_QUESTS_TIME)) + { + continue; + } + + player.sendMessage(F.main(C.cYellowB + "Quest Master", "I have " + F.count(String.valueOf(MAX_QUESTS)) + " new quests for you! Come and see me to start them!")); + + playerData.clear(); + updateQuests(player); + } + } + + @EventHandler + public void pickupItem(PlayerPickupItemEvent event) + { + if (event.isCancelled()) + { + return; + } + + Item item = event.getItem(); + Player player = event.getPlayer(); + Quest quest = fromItemStack(event.getItem().getItemStack()); + + if (quest == null) + { + return; + } + + if (!item.hasMetadata(ITEM_METADATA)) + { + return; + } + + if (!Recharge.Instance.use(event.getPlayer(), "Quest Pickup " + quest.getId(), 2000, false, false)) + { + event.setCancelled(true); + return; + } + + boolean able = startQuest(quest, player); + + if (!able) + { + event.setCancelled(true); + } + else + { + UUID owner = UUID.fromString(item.getMetadata(ITEM_METADATA).get(0).asString()); + Player other = UtilPlayer.searchExact(owner); + + /* + * Noting here that when a player leaves their quest progress is removed. + * However that means that if a new player picks up their quest item we + * run into a problem where that will be null. Thus the progress on that + * quest is lost. + * More complications are added when a player quits out and their NPC is + * there instead until they finally really really quit out. + * This is one massive headache in order to keep quests alive while not + * running into some serious memory leaks. + * Furthermore the time complications of this project mean that there isn't + * enough time right now to implement this (however a enough time for me + * to type this lengthy comment about it). So in true style I'm cutting + * corners and saying that if a player quits out then don't allow other + * players to be able to pickup the quest. + */ + if (other == null) + { + event.setCancelled(true); + return; + } + + + } + } + + @EventHandler + public void dropItem(PlayerDropItemEvent event) + { + if (event.isCancelled()) + { + return; + } + + Player player = event.getPlayer(); + Quest quest = fromItemStack(event.getItemDrop().getItemStack()); + + if (quest == null) + { + return; + } + + cancelQuest(quest, player); + handleDroppedQuest(event.getItemDrop(), player); + } + + public void handleDroppedQuest(Item item, Player player) + { + item.setMetadata(ITEM_METADATA, new FixedMetadataValue(_plugin, player.getUniqueId().toString())); + } + + public void updateQuests(Player player) + { + QuestPlayerData playerData = Get(player); + List quests = playerData.getPossibleQuests(); + + for (int i = 0; i < MAX_QUESTS; i++) + { + Quest quest = getRandomQuest(playerData, player); + + if (quest == null) + { + player.sendMessage(F.main(_moduleName, "It seems that there was some trouble finding you a new quest. Please try again later.")); + return; + } + + quests.add(quest.getId()); + } + } + + public boolean startQuest(Quest quest, Player player) + { + if (isActive(quest, player)) + { + player.sendMessage(F.main(_moduleName, "You have already accepted that quest.")); + return false; + } + else if (isComplete(quest, player)) + { + player.sendMessage(F.main(_moduleName, "You have already completed that quest.")); + return false; + } + + player.sendMessage(F.main(_moduleName, "Started " + F.name(quest.getName()) + ".")); + + QuestPlayerData playerData = Get(player); + playerData.getActiveQuests().add(quest.getId()); + + updateQuestItem(quest, player); + + return true; + } + + public void completeQuest(Quest quest, Player player) + { + if (!isActive(quest, player)) + { + player.sendMessage(F.main(_moduleName, "This quest is not active for you.")); + return; + } + + player.sendMessage(F.main(_moduleName, "Completed " + F.name(quest.getName()) + ".")); + + QuestPlayerData playerData = Get(player); + playerData.getActiveQuests().remove(Integer.valueOf(quest.getId())); + playerData.getCompletedQuests().add(quest.getId()); + + updateQuestItem(quest, player); + } + + public void cancelQuest(Quest quest, Player player) + { + if (!isActive(quest, player)) + { + player.sendMessage(F.main(_moduleName, "This quest is not active for you.")); + return; + } + + player.sendMessage(F.main(_moduleName, "Dropped " + F.name(quest.getName()) + ".")); + + QuestPlayerData playerData = Get(player); + playerData.getActiveQuests().remove(Integer.valueOf(quest.getId())); + } + + public Quest getRandomQuest(QuestPlayerData playerData, Player player) + { + int attempts = 0; + + while (attempts < _quests.length * 2) + { + attempts++; + + int index = UtilMath.r(_quests.length); + Quest quest = _quests[index]; + + if (isActive(quest, player) || isPossible(quest, player)) + { + continue; + } + + return quest; + } + + return null; + } + + public ItemStack getItemStack(Quest quest, Player player, boolean npc, boolean hasSpace) + { + ItemBuilder builder = new ItemBuilder(MATERIAL); + + builder.setTitle(C.cGreen + quest.getName()); + builder.addLore(C.blankLine, quest.getDescription(), C.blankLine); + + boolean active = isActive(quest, player); + boolean complete = isComplete(quest, player); + + if (npc) + { + if (active) + { + builder.setGlow(true); + builder.addLore(C.cRed + "You have already started this quest!"); + } + else if (complete) + { + builder.addLore(C.cRed + "You have already completed this quest!"); + } + else if (hasSpace) + { + builder.addLore(C.cGreen + "Click to start this quest!"); + } + else + { + builder.addLore(C.cRed + "You do not have enough space in your inventory!"); + } + } + else + { + builder.addLore(UtilTextMiddle.progress(quest.getProgress(player)) + C.mBody + " [" + C.cGreen + quest.get(player) + C.mBody + "/" + C.cGreen + quest.getGoal() + C.mBody + "]"); + } + + return builder.build(); + } + + public Quest fromItemStack(ItemStack itemStack) + { + Material material = itemStack.getType(); + ItemMeta meta = itemStack.getItemMeta(); + + if (material != MATERIAL || meta == null || !meta.hasLore()) + { + return null; + } + + String name = ChatColor.stripColor(meta.getDisplayName()); + + for (Quest quest : _quests) + { + if (!quest.getName().equals(name)) + { + continue; + } + + return quest; + } + + return null; + } + + public void updateQuestItem(Quest quest, Player player) + { + ItemStack itemStack = getItemStack(quest, player, false, true); + + for (ItemStack items : player.getInventory().getContents()) + { + if (UtilItem.isSimilar(itemStack, items, ItemAttribute.MATERIAL, ItemAttribute.NAME, ItemAttribute.DATA)) + { + player.getInventory().remove(items); + } + } + + if (isActive(quest, player)) + { + player.getInventory().addItem(itemStack); + } + } + + public boolean isPossible(Quest quest, Player player) + { + return Get(player).getPossibleQuests().contains(quest.getId()); + } + + public boolean isActive(Quest quest, Player player) + { + return Get(player).getActiveQuests().contains(quest.getId()); + } + + public boolean isComplete(Quest quest, Player player) + { + return Get(player).getCompletedQuests().contains(quest.getId()); + } + + public Quest getFromId(int id) + { + for (Quest quest : _quests) + { + if (quest.getId() == id) + { + return quest; + } + } + + return null; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestNPC.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestNPC.java new file mode 100644 index 000000000..33d61a47d --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestNPC.java @@ -0,0 +1,45 @@ +package mineplex.gemhunters.quest; + +import org.bukkit.Location; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Villager.Profession; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEntityEvent; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.menu.Menu; +import mineplex.gemhunters.util.SimpleNPC; + +public class QuestNPC extends SimpleNPC +{ + + private Menu _questMenu; + + public QuestNPC(QuestModule quest, Location spawn, Menu menu) + { + super(quest.getPlugin(), spawn, Villager.class, C.cYellowB + "Quest Master", null); + + _questMenu = menu; + + Villager villager = (Villager) _entity; + + villager.setProfession(Profession.LIBRARIAN); + } + + @Override + @EventHandler + public void npcClick(PlayerInteractEntityEvent event) + { + if (!event.getRightClicked().equals(_entity)) + { + return; + } + + event.setCancelled(true); + + event.getPlayer().sendMessage(F.main("Quest", "The Quest Master is currently disabled but will be avaiable to all players shortly.")); + //_questMenu.open(event.getPlayer());/ + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestPlayerData.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestPlayerData.java new file mode 100644 index 000000000..bf8af3e38 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestPlayerData.java @@ -0,0 +1,52 @@ +package mineplex.gemhunters.quest; + +import java.util.ArrayList; +import java.util.List; + +public class QuestPlayerData +{ + + private final List _possibleQuests; + private final List _activeQuests; + private final List _completedQuests; + + private long _lastClear; + + public QuestPlayerData() + { + _possibleQuests = new ArrayList<>(); + _activeQuests = new ArrayList<>(); + _completedQuests = new ArrayList<>(); + + _lastClear = System.currentTimeMillis(); + } + + public void clear() + { + _possibleQuests.clear(); + _completedQuests.clear(); + + _lastClear = System.currentTimeMillis(); + } + + public List getPossibleQuests() + { + return _possibleQuests; + } + + public List getActiveQuests() + { + return _activeQuests; + } + + public List getCompletedQuests() + { + return _completedQuests; + } + + public long getLastClear() + { + return _lastClear; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestUI.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestUI.java new file mode 100644 index 000000000..59face7bb --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestUI.java @@ -0,0 +1,60 @@ +package mineplex.gemhunters.quest; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.UtilInv; +import mineplex.core.common.util.UtilUI; +import mineplex.core.menu.Button; +import mineplex.core.menu.Menu; + +public class QuestUI extends Menu +{ + + public QuestUI(QuestModule plugin) + { + super("Quest Master", plugin); + } + + @Override + protected Button[] setUp(Player player) + { + Button[] buttons = new Button[21]; + QuestPlayerData playerData = getPlugin().Get(player); + + int i = 0; + int[] slots = UtilUI.getIndicesFor(playerData.getPossibleQuests().size(), 1); + for (Integer id : playerData.getPossibleQuests()) + { + Quest quest = getPlugin().getFromId(id); + ItemStack itemStack = getPlugin().getItemStack(quest, player, true, UtilInv.hasSpace(player, 1)); + + buttons[slots[i++]] = new QuestSelectButton(getPlugin(), itemStack, quest); + } + + return buttons; + } + + public class QuestSelectButton extends Button + { + + private final Quest _quest; + + public QuestSelectButton(QuestModule plugin, ItemStack itemStack, Quest quest) + { + super(itemStack, plugin); + + _quest = quest; + } + + @Override + public void onClick(Player player, ClickType clickType) + { + getPlugin().startQuest(_quest, player); + resetAndUpdate(); + } + + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/types/ChestOpenerQuest.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/types/ChestOpenerQuest.java new file mode 100644 index 000000000..ed1591623 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/types/ChestOpenerQuest.java @@ -0,0 +1,53 @@ +package mineplex.gemhunters.quest.types; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.F; +import mineplex.gemhunters.loot.event.PlayerChestOpenEvent; +import mineplex.gemhunters.quest.Quest; + +public class ChestOpenerQuest extends Quest +{ + + private final int _goal; + + public ChestOpenerQuest(int id, String name, int startCost, int completeReward, int goal) + { + super(id, name, "Open " + F.count(String.valueOf(goal)) + " Chests.", startCost, completeReward); + + _goal = goal; + } + + @Override + public float getProgress(Player player) + { + return (float) get(player) / (float) _goal; + } + + @Override + public int getGoal() + { + return _goal; + } + + @EventHandler + public void chestOpen(PlayerChestOpenEvent event) + { + //DebugModule.getInstance().d(event.getEventName()); + Player player = event.getPlayer(); + + if (!isActive(player)) + { + return; + } + + int amount = getAndIncrement(player, 1); + + if (amount >= _goal) + { + onReward(player); + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/types/SamitoDQuest.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/types/SamitoDQuest.java new file mode 100644 index 000000000..a44a6fabf --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/types/SamitoDQuest.java @@ -0,0 +1,82 @@ +package mineplex.gemhunters.quest.types; + +import org.bukkit.Color; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; + +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilMath; +import mineplex.gemhunters.quest.Quest; + +public class SamitoDQuest extends Quest +{ + + private static final String NPC_NAME = "Hobo"; + private static final String[] REACTIONS = { + "Well hello there folks and welcome... to... my... youtube channel", + "WILLIAMMMMMMM", + "ALEXXXXXXXXXX", + "CHISS", + "Rods and Gaps", + "Hit him with that w-tap", + "You're the one who wanted to bring out bows young man" + }; + + private final Location _pot; + private final int _gemsToDonate; + + public SamitoDQuest(int id, String name, String description, int startCost, int completeReward, int gemsToDonate) + { + super(id, name, description, startCost, completeReward); + + _pot = _worldData.getCustomLocation("QUEST_SAM").get(0); + _pot.getBlock().setType(Material.FLOWER_POT); + + _gemsToDonate = gemsToDonate; + } + + @Override + public float getProgress(Player player) + { + return 0; + } + + @EventHandler + public void onInteract(PlayerInteractEvent event) + { + Player player = event.getPlayer(); + + if (event.isCancelled() || !isActive(player)) + { + return; + } + + Block block = event.getClickedBlock(); + + if (block == null) + { + return; + } + + if (UtilMath.offsetSquared(block.getLocation(), _pot) < 4) + { + if (_economy.getGems(player) < _gemsToDonate) + { + player.sendMessage(F.main(NPC_NAME, "Awww come on man, even alex has more gems than you.")); + return; + } + + player.sendMessage(F.main(NPC_NAME, REACTIONS[UtilMath.random.nextInt(REACTIONS.length)])); + _economy.removeFromStore(player, _gemsToDonate); + UtilFirework.playFirework(_pot, Type.BURST, Color.GREEN, true, false); + onReward(player); + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/safezone/SafezoneModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/safezone/SafezoneModule.java new file mode 100644 index 000000000..fc9dc2b50 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/safezone/SafezoneModule.java @@ -0,0 +1,216 @@ +package mineplex.gemhunters.safezone; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.world.WorldDataModule; + +@ReflectivelyCreateMiniPlugin +public class SafezoneModule extends MiniPlugin +{ + + private static final String SAFEZONE_DATA_PREFIX = "SAFEZONE"; + private static final String SAFEZONE_DATA_IGNORE = "IGNORE"; + + private final WorldDataModule _worldData; + + private final Map _currentSafezone; + + private SafezoneModule() + { + super("Safezone"); + + _worldData = require(WorldDataModule.class); + + _currentSafezone = new HashMap<>(); + } + + @EventHandler + public void updateSafeZone(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + for (Player player : UtilServer.getPlayers()) + { + UUID key = player.getUniqueId(); + String oldSafezone = _currentSafezone.get(key); + boolean isInOldSafezone = oldSafezone != null; + String newSafezone = getSafezone(player.getLocation()); + boolean isInNewSafezone = newSafezone != null; + + // null -> not null + if (!isInOldSafezone && isInNewSafezone) + { + if (!newSafezone.contains(SAFEZONE_DATA_IGNORE)) + { + UtilTextMiddle.display("", C.cYellow + "Entering " + newSafezone, 10, 40, 10, player); + } + _currentSafezone.put(key, newSafezone); + } + // not null -> null + else if (isInOldSafezone && !isInNewSafezone) + { + if (!oldSafezone.contains(SAFEZONE_DATA_IGNORE)) + { + UtilTextMiddle.display("", C.cYellow + "Leaving " + oldSafezone, 10, 40, 10, player); + } + _currentSafezone.put(key, null); + } + } + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + + _currentSafezone.remove(player.getUniqueId()); + } + + @EventHandler + public void entityDamage(EntityDamageEvent event) + { + if (!(event.getEntity() instanceof Player)) + { + return; + } + + Player player = (Player) event.getEntity(); + + if (isInSafeZone(player.getLocation())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void entityAttack(EntityDamageByEntityEvent event) + { + // Handle people shooting arrows at people outside a safezone + if (event.getDamager() instanceof Projectile) + { + Projectile projectile = (Projectile) event.getDamager(); + + if (projectile.getShooter() instanceof LivingEntity) + { + LivingEntity entity = (LivingEntity) projectile.getShooter(); + + if (isInSafeZone(entity.getLocation())) + { + event.setCancelled(true); + return; + } + } + } + + if (!(event.getDamager() instanceof Player)) + { + return; + } + + Player player = (Player) event.getDamager(); + + if (isInSafeZone(player.getLocation())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void hungerChange(FoodLevelChangeEvent event) + { + if (isInSafeZone(event.getEntity().getLocation()) && event.getEntity() instanceof Player) + { + Player player = (Player) event.getEntity(); + + if (player.getFoodLevel() < event.getFoodLevel()) + { + return; + } + + event.setCancelled(true); + } + } + + public boolean isInSafeZone(Location location) + { + return getSafezone(location) != null; + } + + public boolean isInSafeZone(Location location, String safezone) + { + if (safezone == null) + { + return false; + } + + List bounds = _worldData.getCustomLocation(SAFEZONE_DATA_PREFIX + " " + safezone); + + if (bounds == null || bounds.size() != 2) + { + log("Error regarding safezone bounds for region " + safezone + " there are " + bounds.size() + " points instead of 2. Ignoring this safezone!"); + return false; + } + + return UtilAlg.inBoundingBox(location, bounds.get(0), bounds.get(1)); + } + + public String getSafezone(Location location) + { + Map> customLocations = _worldData.getAllCustomLocations(); + + for (String key : customLocations.keySet()) + { + if (!key.startsWith(SAFEZONE_DATA_PREFIX)) + { + continue; + } + + List bounds = customLocations.get(key); + + if (bounds.size() != 2) + { + log("Error regarding safezone bounds for region " + key + " there are " + bounds.size() + " points instead of 2. Ignoring this safezone!"); + continue; + } + + if (UtilAlg.inBoundingBox(location, bounds.get(0), bounds.get(1))) + { + String name = ""; + String[] split = key.split(" "); + + for (int i = 1; i < split.length; i++) + { + name += split[i] + " "; + } + + return name.trim(); + } + } + + return null; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/GemHuntersScoreboard.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/GemHuntersScoreboard.java new file mode 100644 index 000000000..4959f4a78 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/GemHuntersScoreboard.java @@ -0,0 +1,78 @@ +package mineplex.gemhunters.scoreboard; + +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTime; +import mineplex.core.scoreboard.WritableMineplexScoreboard; +import mineplex.gemhunters.economy.EconomyModule; +import mineplex.gemhunters.supplydrop.SupplyDropModule; +import mineplex.gemhunters.worldevent.WorldEvent; +import mineplex.gemhunters.worldevent.WorldEventModule; + +public class GemHuntersScoreboard extends WritableMineplexScoreboard +{ + + private final EconomyModule _economy; + private final WorldEventModule _worldEvent; + private final SupplyDropModule _supplyDrop; + + public GemHuntersScoreboard(Player player) + { + super(player); + + _economy = Managers.require(EconomyModule.class); + _worldEvent = Managers.require(WorldEventModule.class); + _supplyDrop = Managers.require(SupplyDropModule.class); + } + + public void writeContent(Player player) + { + writeNewLine(); + + write(C.cGreenB + "Gems Earned"); + write(String.valueOf(_economy.getGems(player))); + + writeNewLine(); + + write(C.cGoldB + "Supply Drop"); + if (_supplyDrop.isActive()) + { + write(_supplyDrop.getActive().getName() + " - " + (int) UtilMath.offset(player.getLocation(), _supplyDrop.getActive().getChestLocation()) + "m"); + } + else + { + write(UtilTime.MakeStr(_supplyDrop.getLastSupplyDrop() + _supplyDrop.getSequenceTimer() - System.currentTimeMillis())); + } + + writeNewLine(); + + write(C.cYellowB + "World Event"); + + if (!_worldEvent.isEventActive()) + { + write(UtilTime.MakeStr(_worldEvent.getLastEventComplete() + _worldEvent.getEventTimer() - System.currentTimeMillis())); + } + else + { + for (WorldEvent event : _worldEvent.getActiveEvents()) + { + write(event.getEventType().getName() + " (" + event.getEventState().getName() + ")"); + } + } + + writeNewLine(); + } + + public String getSuffix(Player perspective, Player subject) + { + return C.cGray + " " + perspective.getName(); + } + + public int getUndernameScore(Player player) + { + return _economy.getGems(player); + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/ScoreboardModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/ScoreboardModule.java new file mode 100644 index 000000000..42efc4a01 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/ScoreboardModule.java @@ -0,0 +1,204 @@ +package mineplex.gemhunters.scoreboard; + +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 org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Score; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.economy.EconomyModule; + +@ReflectivelyCreateMiniPlugin +public class ScoreboardModule extends MiniPlugin +{ + + private static final String PRIMARY_COLOUR = C.cGreenB; + private static final String SECONDARY_COLOUR = C.cWhiteB; + private static final String TRANSITION_COLOUR = C.cDGreenB; + private static final String SCOREBOARD_TITLE = " GEM HUNTERS "; + + private final EconomyModule _economy; + + private final Map _scoreboards; + + private int _shineIndex; + private boolean _shineDirection = true; + + public ScoreboardModule() + { + super("Scoreboard"); + + _economy = require(EconomyModule.class); + _scoreboards = new HashMap<>(); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() == UpdateType.FAST) + { + for (UUID key : _scoreboards.keySet()) + { + GemHuntersScoreboard scoreboard = _scoreboards.get(key); + Player player = UtilPlayer.searchExact(key); + + scoreboard.writeContent(player); + scoreboard.draw(); + } + } + else if (event.getType() == UpdateType.FASTEST) + { + updateTitles(); + } + } + + @EventHandler + public void playerJoin(PlayerJoinEvent event) + { + createPlayerScoreboard(event.getPlayer()); + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + + for (GemHuntersScoreboard scoreboard : _scoreboards.values()) + { + scoreboard.getHandle().getTeam(player.getName()).unregister(); + } + + _scoreboards.remove(player.getUniqueId()); + } + + @EventHandler + public void updateGemsCounter(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC_08) + { + return; + } + + for (Player player : Bukkit.getOnlinePlayers()) + { + int gems = _economy.getGems(player); + + for (GemHuntersScoreboard scoreboard : _scoreboards.values()) + { + Objective objective = scoreboard.getHandle().getObjective(DisplaySlot.BELOW_NAME); + Score score = objective.getScore(player.getName()); + + if (score.getScore() == gems) + { + continue; + } + + score.setScore(gems); + } + } + } + + public void createPlayerScoreboard(Player player) + { + if (!_scoreboards.containsKey(player.getUniqueId())) + { + GemHuntersScoreboard scoreboard = new GemHuntersScoreboard(player); + Scoreboard handle = scoreboard.getHandle(); + + _scoreboards.put(player.getUniqueId(), scoreboard); + + // Gem Counter Undername + Objective gemCounter = handle.registerNewObjective("Gems", "Gems"); + gemCounter.setDisplaySlot(DisplaySlot.BELOW_NAME); + + for (GemHuntersScoreboard other : _scoreboards.values()) + { + // Set the other player's name tag for the player joining + Player otherPlayer = other.getOwner(); + Team team = handle.registerNewTeam(otherPlayer.getName()); + + team.setPrefix(C.cYellow); + //team.setSuffix(scoreboard.getSuffix(player, otherPlayer)); + team.addEntry(otherPlayer.getName()); + + if (player.equals(otherPlayer)) + { + continue; + } + + // Set the player that is joining + Scoreboard otherHandle = other.getHandle(); + Team otherTeam = otherHandle.registerNewTeam(player.getName()); + + otherTeam.setPrefix(C.cYellow); + //otherTeam.setSuffix(other.getSuffix(other.getOwner(), player)); + otherTeam.addEntry(player.getName()); + } + + player.setScoreboard(scoreboard.getHandle()); + } + } + + public void updateTitles() + { + String out = (_shineDirection ? PRIMARY_COLOUR : SECONDARY_COLOUR); + + for (int i = 0; i < SCOREBOARD_TITLE.length(); i++) + { + char c = SCOREBOARD_TITLE.charAt(i); + + if (_shineDirection) + { + if (i == _shineIndex) + { + out += TRANSITION_COLOUR; + } + else if (i == _shineIndex + 1) + { + out += SECONDARY_COLOUR; + } + } + else + { + if (i == _shineIndex) + { + out += TRANSITION_COLOUR; + } + else if (i == _shineIndex + 1) + { + out += PRIMARY_COLOUR; + } + } + + out += c; + } + + for (GemHuntersScoreboard scoreboard : _scoreboards.values()) + { + scoreboard.setSidebarName(out); + } + + _shineIndex++; + + if (_shineIndex == SCOREBOARD_TITLE.length() * 2) + { + _shineIndex = 0; + _shineDirection = !_shineDirection; + } + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java new file mode 100644 index 000000000..96d41d9fa --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java @@ -0,0 +1,261 @@ +package mineplex.gemhunters.shop; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.entity.Villager; +import org.bukkit.event.EventHandler; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTime; +import mineplex.core.google.GoogleSheetsManager; +import mineplex.core.google.SheetObjectDeserialiser; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.loot.deserialisers.LootItemDeserialiser; +import mineplex.gemhunters.safezone.SafezoneModule; +import mineplex.gemhunters.shop.deserialisers.VillagerPropertiesDeserialiser; +import mineplex.gemhunters.util.SlackSheetsBot; +import mineplex.gemhunters.world.WorldDataModule; + +@ReflectivelyCreateMiniPlugin +public class ShopModule extends MiniPlugin +{ + + private static final String SHEET_FILE_NAME = "GEM_HUNTERS_SHOP"; + private static final String VILLAGER_MASTER_SHEET_NAME = "VILLAGER_MASTER"; + private static final VillagerPropertiesDeserialiser VILLAGER_PROPERTIES_DESERIALISER = new VillagerPropertiesDeserialiser(); + private static final LootItemDeserialiser DESERIALISER = new LootItemDeserialiser(); + private static final SheetObjectDeserialiser COST_DESERIALISER = new SheetObjectDeserialiser() + { + + @Override + public Integer deserialise(String[] values) throws ArrayIndexOutOfBoundsException, NumberFormatException + { + return Integer.parseInt(values[10]); + } + + }; + + private static final int MINIMUM_ITEMS = 1; + private static final int MAXIMUM_ITEMS = 5; + + private static final String[] NAMES = { + "Andrew", "Jon", "Bob", "Sam", "Ronan", "Alex", "Joe", "Emma", "Giovani", "Dean", "Josh", "Geoffrey", "Parker", "Spencer", "Luke", "Peter", "William", "Connor" + }; + + private final GoogleSheetsManager _sheets; + private final SafezoneModule _safezone; + private final WorldDataModule _worldData; + + private final Map> _trades; + private final Map _properties; + + private final List _npcs; + private final Map> _spawnedIndexes; + + private ShopModule() + { + super("Shop"); + + _sheets = require(GoogleSheetsManager.class); + _safezone = require(SafezoneModule.class); + _worldData = require(WorldDataModule.class); + + _trades = new HashMap<>(); + _properties = new HashMap<>(); + + _npcs = new ArrayList<>(); + _spawnedIndexes = new HashMap<>(); + + runSyncLater(() -> updateVillagerTrades(), 20); + } + + public void updateVillagerTrades() + { + log("Updating villager trades"); + Map>> map = _sheets.getSheetData(SHEET_FILE_NAME); + + for (String key : map.keySet()) + { + if (key.equals(VILLAGER_MASTER_SHEET_NAME)) + { + int row = 0; + + for (List rows : map.get(key)) + { + row++; + try + { + VillagerProperties properties = VILLAGER_PROPERTIES_DESERIALISER.deserialise(rows.toArray(new String[0])); + _properties.put(properties.getDataKey(), properties); + } + catch (Exception e) + { + if (row != 1) + { + SlackSheetsBot.reportParsingError(e, "Villager Trades", key, row); + } + + continue; + } + } + continue; + } + + Set items = new HashSet<>(); + int row = 0; + + for (List rows : map.get(key)) + { + row++; + try + { + String[] values = rows.toArray(new String[0]); + items.add(new TradeableItem(DESERIALISER.deserialise(values), COST_DESERIALISER.deserialise(values))); + } + catch (Exception e) + { + if (row != 1) + { + SlackSheetsBot.reportParsingError(e, "Villager Trades", key, row); + } + + continue; + } + } + + _trades.put(key, items); + } + + log("Finished updating villager trades"); + } + + @EventHandler + public void updateSpawnedVillagers(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + Iterator iterator = _npcs.iterator(); + + while (iterator.hasNext()) + { + TraderNPC npc = iterator.next(); + int expireTime = npc.getProperties().getExpireRate(); + + if (expireTime > 0 && UtilTime.elapsed(npc.getSpawnedAt(), expireTime)) + { + npc.getEntity().remove(); + iterator.remove(); + } + } + + for (String key : _properties.keySet()) + { + List locations = _worldData.getSpawnLocation(capitalise(key)); + VillagerProperties properties = _properties.get(key); + + if (!UtilTime.elapsed(properties.getLastSpawn(), properties.getSpawnRate())) + { + continue; + } + + properties.setLastSpawn(); + + // Only spawn more chests if we need to + int max = properties.getMax(); + int spawned = 0; + + for (TraderNPC npc : _npcs) + { + if (npc.getProperties().getDataKey().equals(key)) + { + spawned++; + } + } + + // If there are too many chests of this type we can ignore it + if (spawned > max) + { + continue; + } + + Set usedIndexes = _spawnedIndexes.get(key); + + if (usedIndexes == null) + { + _spawnedIndexes.put(key, new HashSet<>()); + usedIndexes = _spawnedIndexes.get(key); + } + + if (locations.size() == usedIndexes.size()) + { + continue; + } + + int index = getFreeIndex(locations.size(), usedIndexes); + + if (index == -1) + { + return; + } + + Location randomLocation = locations.get(index); + + randomLocation.setYaw(UtilMath.r(360)); + + usedIndexes.add(index); + + //DebugModule.getInstance().d("Trader at " + UtilWorld.locToStrClean(randomLocation) + " with key=" + key + " and index=" + index + " and max=" + spawned + "/" + max); + _npcs.add(new TraderNPC(_plugin, randomLocation, Villager.class, NAMES[UtilMath.r(NAMES.length)], _safezone.isInSafeZone(randomLocation), properties, getRandomItemSet(_trades.get(key)))); + } + } + + private int getFreeIndex(int endIndex, Set used) + { + int index = -1; + + while (index == -1 || used.contains(index)) + { + index = UtilMath.r(endIndex); + } + + used.add(index); + + return index; + } + + private Set getRandomItemSet(Set items) + { + int size = UtilMath.rRange(MINIMUM_ITEMS, MAXIMUM_ITEMS); + Set items2 = new HashSet<>(size); + + for (int i = 0; i < size; i++) + { + items2.add(UtilAlg.Random(items)); + } + + return items2; + } + + private final String capitalise(String s) + { + String right = s.toLowerCase().substring(1); + char left = Character.toUpperCase(s.charAt(0)); + + return left + right; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TradeableItem.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TradeableItem.java new file mode 100644 index 000000000..a43ab565c --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TradeableItem.java @@ -0,0 +1,27 @@ +package mineplex.gemhunters.shop; + +import mineplex.gemhunters.loot.LootItem; + +public class TradeableItem +{ + + private final LootItem _item; + private final int _cost; + + public TradeableItem(LootItem item, int cost) + { + _item = item; + _cost = cost; + } + + public LootItem getLootItem() + { + return _item; + } + + public int getCost() + { + return _cost; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TraderNPC.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TraderNPC.java new file mode 100644 index 000000000..a94690840 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TraderNPC.java @@ -0,0 +1,158 @@ +package mineplex.gemhunters.shop; + +import java.util.List; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.Managers; +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilInv; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.itemstack.ItemStackFactory; +import mineplex.gemhunters.economy.EconomyModule; +import mineplex.gemhunters.util.SimpleNPC; + +public class TraderNPC extends SimpleNPC +{ + private final EconomyModule _economy; + + private final VillagerProperties _properties; + private final Set _selling; + private final Inventory _inv; + + private final long _spawnedAt; + + public TraderNPC(JavaPlugin plugin, Location spawn, Class type, String name, boolean vegetated, VillagerProperties properties, Set selling) + { + super(plugin, spawn, type, name, null, vegetated); + + _economy = Managers.require(EconomyModule.class); + + _properties = properties; + _selling = selling; + _inv = plugin.getServer().createInventory(null, 9, name); + _spawnedAt = System.currentTimeMillis(); + + int index = 1; + + for (TradeableItem item : _selling) + { + ItemStack itemStack = new ItemBuilder(item.getLootItem().getItemStack()).addLore("Cost: " + F.currency(GlobalCurrency.GEM, item.getCost())).build(); + + _inv.setItem(index++, itemStack); + } + } + + @Override + @EventHandler + public void npcClick(PlayerInteractEntityEvent event) + { + super.npcClick(event); + + if (event.getRightClicked().equals(_entity)) + { + event.setCancelled(true); + event.getPlayer().openInventory(_inv); + } + } + + @EventHandler + public void inventoryClick(InventoryClickEvent event) + { + if (event.getInventory() == null) + { + return; + } + + if (!event.getInventory().equals(_inv)) + { + return; + } + + event.setCancelled(true); + + ItemStack itemStack = event.getCurrentItem(); + + if (itemStack == null) + { + return; + } + + Player player = (Player) event.getWhoClicked(); + int gems = _economy.getGems(player); + int cost = fromItemStack(itemStack); + + if (cost == 0) + { + return; + } + + if (cost > gems) + { + player.sendMessage(F.main(_entity.getCustomName(), "I'm sorry you don't have enough gems to purchase this.")); + player.playSound(player.getLocation(), Sound.ITEM_BREAK, 1, 0.6F); + return; + } + + if (!UtilInv.HasSpace(player, itemStack.getType(), itemStack.getAmount())) + { + player.sendMessage(F.main(_entity.getCustomName(), "I'm sorry you don't have enough space to hold that.")); + player.playSound(player.getLocation(), Sound.ITEM_BREAK, 1, 0.6F); + return; + } + + _economy.removeFromStore(player, cost); + + // Remove cost lore + ItemBuilder builder = new ItemBuilder(itemStack); + + List lore = builder.getLore(); + lore.remove(lore.size() - 1); + builder.setLore(lore.toArray(new String[0])); + + itemStack = builder.build(); + + String itemName = ItemStackFactory.Instance.GetName(itemStack, true); + + player.sendMessage(F.main(_entity.getCustomName(), "Purchased " + F.elem(itemName) + "!")); + player.playSound(player.getLocation(), Sound.NOTE_PLING, 1, 1.2F); + player.getInventory().addItem(itemStack); + } + + public int fromItemStack(ItemStack itemStack) + { + for (TradeableItem item : _selling) + { + ItemStack itemStack2 = item.getLootItem().getItemStack(); + + if (itemStack.getType() == itemStack2.getType()) + { + return item.getCost(); + } + } + + return 0; + } + + public final VillagerProperties getProperties() + { + return _properties; + } + + public final long getSpawnedAt() + { + return _spawnedAt; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/VillagerProperties.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/VillagerProperties.java new file mode 100644 index 000000000..bb94751ea --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/VillagerProperties.java @@ -0,0 +1,59 @@ +package mineplex.gemhunters.shop; + +public class VillagerProperties +{ + + private final String _name; + private final String _dataKey; + private final int _spawnRate; + private final int _expireRate; + private final int _max; + + private long _lastSpawn; + + public VillagerProperties(String name, String dataKey, int spawnRate, int expireRate, int max) + { + _name = name; + _dataKey = dataKey; + _spawnRate = spawnRate; + _expireRate = expireRate; + _max = max; + + setLastSpawn(); + } + + public final String getName() + { + return _name; + } + + public final String getDataKey() + { + return _dataKey; + } + + public final int getSpawnRate() + { + return _spawnRate; + } + + public final int getExpireRate() + { + return _expireRate; + } + + public final int getMax() + { + return _max; + } + + public void setLastSpawn() + { + _lastSpawn = System.currentTimeMillis(); + } + + public long getLastSpawn() + { + return _lastSpawn; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/deserialisers/VillagerPropertiesDeserialiser.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/deserialisers/VillagerPropertiesDeserialiser.java new file mode 100644 index 000000000..8d37883a9 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/deserialisers/VillagerPropertiesDeserialiser.java @@ -0,0 +1,23 @@ +package mineplex.gemhunters.shop.deserialisers; + +import mineplex.core.google.SheetObjectDeserialiser; +import mineplex.gemhunters.shop.VillagerProperties; + +public class VillagerPropertiesDeserialiser implements SheetObjectDeserialiser +{ + + @Override + public VillagerProperties deserialise(String[] values) throws ArrayIndexOutOfBoundsException + { + String name = values[0]; + String dataKey = values[1]; + + int spawnRate = Integer.parseInt(values[4]); + int expireRate = Integer.parseInt(values[5]); + + int max = Integer.parseInt(values[7]); + + return new VillagerProperties(name, dataKey, spawnRate, expireRate, max); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/SpawnModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/SpawnModule.java new file mode 100644 index 000000000..e2cc05ba2 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/SpawnModule.java @@ -0,0 +1,226 @@ +package mineplex.gemhunters.spawn; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.WorldBorder; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilServer; +import mineplex.core.portal.GenericServer; +import mineplex.core.portal.Intent; +import mineplex.core.portal.Portal; +import mineplex.gemhunters.death.npc.CombatLogNPC; +import mineplex.gemhunters.death.npc.NPCManager; +import mineplex.gemhunters.death.npc.PlayerInfo; +import mineplex.gemhunters.safezone.SafezoneModule; +import mineplex.gemhunters.spawn.event.PlayerTeleportIntoMapEvent; +import mineplex.gemhunters.util.ColouredTextAnimation; +import mineplex.gemhunters.util.SimpleNPC; +import mineplex.gemhunters.world.WorldDataModule; + +@ReflectivelyCreateMiniPlugin +public class SpawnModule extends MiniPlugin +{ + + public static final int WORLD_BORDER_RADIUS = 1024; + private static final int MAX_SPAWNING_Y = 73; + private static final int MIN_PLAYER_DISTANCE_SQUARED = 6400; + + private final SafezoneModule _safezone; + private final WorldDataModule _worldData; + + private Location _spawn; + private Location _center; + private boolean _npcsSpawned; + + private SpawnModule() + { + super("Spawn"); + + _safezone = require(SafezoneModule.class); + _worldData = require(WorldDataModule.class); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void playerJoin(PlayerJoinEvent event) + { + if (_spawn == null || _center == null) + { + _spawn = _worldData.getCustomLocation("PLAYER_SPAWN").get(0); + _center = new Location(_worldData.World, 0, 64, 0); + } + + Player player = event.getPlayer(); + NPCManager npcManager = NPCManager.getInstance(); + + if (npcManager.hasLogoutNpc(player)) + { + CombatLogNPC npc = npcManager.getLogoutNpc(player); + PlayerInfo info = npc.getPlayerInfo(); + + info.restore(); + return; + } + + player.teleport(_spawn); + player.setFoodLevel(20); + player.setExhaustion(0); + player.getInventory().clear(); + player.getInventory().setArmorContents(null); + player.updateInventory(); + + if (_npcsSpawned) + { + return; + } + + WorldBorder border = _spawn.getWorld().getWorldBorder(); + + border.setCenter(_spawn); + border.setSize(WORLD_BORDER_RADIUS * 2); + + _npcsSpawned = true; + + { + Location location = _worldData.getCustomLocation("TELEPORT_NPC").get(0); + + location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, _spawn))); + + new SimpleNPC(_plugin, location, Villager.class, C.cDRed + "! " + C.cRedB + "Enter The World" + C.cDRed + " !", clicker -> { + + Location toTeleport = getRandomLocation(); + + if (toTeleport == null) + { + clicker.sendMessage(F.main(_moduleName, "A suitable teleport location could not be found. Please try again in a few seconds.")); + return; + } + + PlayerTeleportIntoMapEvent teleportEvent = new PlayerTeleportIntoMapEvent(clicker, toTeleport); + + UtilServer.CallEvent(teleportEvent); + + if (teleportEvent.isCancelled()) + { + clicker.sendMessage(F.main(_moduleName, "Something went wrong there, sorry. Please try again in a few seconds.")); + return; + } + + clicker.teleport(toTeleport); + clicker.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 4 * 20, 9)); + clicker.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 4 * 20, 9)); + + ColouredTextAnimation animation = new ColouredTextAnimation("GEM HUNTERS", C.cGoldB + "M ", C.cGoldB + " M", new String[] { C.cDGreenB, C.cGreenB, C.cWhiteB }); + + runSyncTimer(new BukkitRunnable() + { + + @Override + public void run() + { + if (animation.displayAsTitle(clicker)) + { + cancel(); + } + } + }, 10, 4); + }); + } + { + Location location = _worldData.getCustomLocation("RETURN_TO_HUB").get(0); + + location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, _spawn))); + + new SimpleNPC(_plugin, location, Villager.class, C.cGoldB + "Return To Hub", clicker -> { + + Portal.getInstance().sendPlayerToGenericServer(clicker, GenericServer.BETA_HUB, Intent.PLAYER_REQUEST); + + }); + } + { + Location location = _worldData.getCustomLocation("TUTORIAL").get(0); + + location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, _spawn))); + + new SimpleNPC(_plugin, location, Villager.class, C.cGoldB + "Tutorial", clicker -> { + + clicker.sendMessage(F.main(_moduleName, "A tutorial will be coming soon.")); + + }); + } + } + + public void teleportToSpawn(Player player) + { + player.teleport(_spawn); + } + + public boolean isSuitable(Block block) + { + Block up = block.getRelative(BlockFace.UP); + Block down = block.getRelative(BlockFace.DOWN); + + if (block.getType() != Material.AIR || down.getType() == Material.AIR || UtilBlock.liquid(down) || UtilBlock.liquid(up) || UtilBlock.liquid(block) || _safezone.isInSafeZone(block.getLocation()) || block.getLocation().getBlockY() > MAX_SPAWNING_Y) + { + return false; + } + + for (Player player : Bukkit.getOnlinePlayers()) + { + if (_safezone.isInSafeZone(player.getLocation())) + { + continue; + } + + if (UtilMath.offsetSquared(player.getLocation(), block.getLocation()) < MIN_PLAYER_DISTANCE_SQUARED) + { + return false; + } + } + + return true; + } + + public Location getRandomLocation() + { + int attempts = 0; + double range = WORLD_BORDER_RADIUS * 0.5; + + while (attempts < 100) + { + Location possible = UtilBlock.getHighest(_worldData.World, UtilAlg.getRandomLocation(_center, range)).getLocation(); + + if (isSuitable(possible.getBlock())) + { + return possible.add(0, 1, 0); + } + + attempts++; + } + + return null; + } + + public Location getCenter() + { + return _center; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/event/PlayerTeleportIntoMapEvent.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/event/PlayerTeleportIntoMapEvent.java new file mode 100644 index 000000000..51b6e6d6f --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/event/PlayerTeleportIntoMapEvent.java @@ -0,0 +1,56 @@ +package mineplex.gemhunters.spawn.event; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class PlayerTeleportIntoMapEvent extends PlayerEvent implements Cancellable +{ + + private static final HandlerList HANDLERS = new HandlerList(); + + private boolean _cancel; + private Location _to; + + public PlayerTeleportIntoMapEvent(Player who, Location to) + { + super(who); + + _to = to; + } + + public void setTo(Location to) + { + _to = to; + } + + public Location getTo() + { + return _to; + } + + public HandlerList getHandlers() + { + return HANDLERS; + } + + public static HandlerList getHandlerList() + { + return HANDLERS; + } + + @Override + public boolean isCancelled() + { + return _cancel; + } + + @Override + public void setCancelled(boolean cancel) + { + _cancel = cancel; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/SupplyDrop.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/SupplyDrop.java new file mode 100644 index 000000000..8f2ca4203 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/SupplyDrop.java @@ -0,0 +1,225 @@ +package mineplex.gemhunters.supplydrop; + +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.FallingBlock; +import org.bukkit.util.BlockVector; + +import mineplex.core.common.block.schematic.Schematic; +import mineplex.core.common.block.schematic.SchematicData; +import mineplex.core.common.block.schematic.UtilSchematic; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilShapes; + +/** + * Represents an instance of a Supply Drop.
+ * A supply drop consists of a helicopter flying through the map from a one + * location to another. Upon reaching it's destination it will drop a loot chest + * which players can then fight over.
+ * The helicopter will then fly away towards a despawning location.
+ *
+ * The helicopter will be made up of a collection of blocks that are moved along + * a linear path. The look of this helicopter is saved in the map and is stored + * in internal memory on startup.
+ *
+ * The blades of the helicopter rotate, this is done within this class.
+ *
+ * {@link SupplyDropModule} handles when and where these supply drops will + * spawn. + */ +public class SupplyDrop +{ + + private static final String SCHEMATIC_PATH = ".." + File.separator + ".." + File.separator + "update" + File.separator + "files" + File.separator + "Helicopter.schematic"; + private static final int BLADE_LENGTH = 7; + + private final String _name; + private Location _destination; + private Location _despawn; + private Location _current; + private Location _blade; + + private Schematic _schematic; + private Set _lastHelicopter; + private Set _bladeBlocks; + private boolean _diagonal; + + public SupplyDrop(String name, Location spawn, Location destination, Location despawn) + { + _name = name; + _destination = destination.clone(); + _despawn = despawn.clone(); + _current = spawn.clone().add(-2, 0, 0); + + try + { + _schematic = UtilSchematic.loadSchematic(new File(SCHEMATIC_PATH)); + } + catch (IOException e) + { + e.printStackTrace(); + return; + } + + _lastHelicopter = new HashSet<>(100); + _bladeBlocks = new HashSet<>(20); + _diagonal = false; + } + + public boolean advancePath() + { + boolean done = moveHelicopter(); + + if (!done) + { + rotateBlades(); + } + + _current.add(0, 0, 1); + + return done; + } + + public boolean moveHelicopter() + { + _current.getChunk().load(); + + for (Block block : _lastHelicopter) + { + block.setType(Material.AIR); + } + + _lastHelicopter.clear(); + + if (_blade != null) + { + if (UtilMath.offset2d(_blade, _destination) < 1) + { + spawnLootChest(); + } + else if (UtilMath.offset2d(_blade, _despawn) < 1) + { + for (Block block : _bladeBlocks) + { + block.setType(Material.AIR); + } + + return true; + } + } + + SchematicData data = _schematic.paste(_current, true); + + _blade = data.getDataLocationMap().getIronLocations(DyeColor.RED).get(0); + + for (BlockVector vector : data.getBlocks()) + { + Location location = _current.add(vector); + + _lastHelicopter.add(location.getBlock()); + + _current.subtract(vector); + } + + return false; + } + + public void rotateBlades() + { + _diagonal = !_diagonal; + + for (Block block : _bladeBlocks) + { + block.setType(Material.AIR); + } + + _bladeBlocks.clear(); + + if (_diagonal) + { + for (int x = -1; x <= 1; x += 2) + { + for (int z = -1; z <= 1; z += 2) + { + for (Location location : UtilShapes.getLinesLimitedPoints(_blade, _blade.clone().add(x * BLADE_LENGTH, 0, z * BLADE_LENGTH), BLADE_LENGTH)) + { + Block block = location.getBlock(); + + _bladeBlocks.add(block); + block.setType(Material.STEP); + } + } + } + } + else + { + for (int x = -1; x <= 1; x += 2) + { + for (Location location : UtilShapes.getLinesLimitedPoints(_blade, _blade.clone().add(x * BLADE_LENGTH, 0, 0), BLADE_LENGTH)) + { + Block block = location.getBlock(); + + _bladeBlocks.add(block); + block.setType(Material.STEP); + } + } + + for (int z = -1; z <= 1; z += 2) + { + for (Location location : UtilShapes.getLinesLimitedPoints(_blade, _blade.clone().add(0, 0, z * BLADE_LENGTH), BLADE_LENGTH)) + { + Block block = location.getBlock(); + + _bladeBlocks.add(block); + block.setType(Material.STEP); + } + } + } + } + + public void stop() + { + for (Block block : _bladeBlocks) + { + block.setType(Material.AIR); + } + + for (Block block : _lastHelicopter) + { + block.setType(Material.AIR); + } + } + + public void spawnLootChest() + { + FallingBlock fallingBlock = _blade.getWorld().spawnFallingBlock(_blade.clone().subtract(0, 10, 0), Material.WOOD, (byte) 0); + + fallingBlock.setHurtEntities(false); + fallingBlock.setDropItem(false); + + UtilFirework.playFirework(fallingBlock.getLocation().add(0.5, 1, 0.5), UtilFirework.getRandomFireworkEffect(false, 2, 1)); + } + + public final String getName() + { + return _name; + } + + public final Location getCurrentLocation() + { + return _current; + } + + public final Location getChestLocation() + { + return _destination; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/SupplyDropModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/SupplyDropModule.java new file mode 100644 index 000000000..60c07c11a --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/SupplyDropModule.java @@ -0,0 +1,223 @@ +package mineplex.gemhunters.supplydrop; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.FallingBlock; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.ItemSpawnEvent; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.blockrestore.BlockRestore; +import mineplex.core.common.Pair; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.UtilWorld; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.loot.LootModule; +import mineplex.gemhunters.supplydrop.command.SupplyDropCommand; +import mineplex.gemhunters.world.WorldDataModule; + +@ReflectivelyCreateMiniPlugin +public class SupplyDropModule extends MiniPlugin +{ + + private static final long SEQUENCE_TIMER = TimeUnit.MINUTES.toMillis(15); + + private static final String CHEST_COLOUR = "RED"; + private static final String LOCATION_DATA = "SUPPLY_DROP"; + + private final BlockRestore _blockRestore; + private final LootModule _loot; + private final WorldDataModule _worldData; + + private final Set _beaconBlocks; + + private String[] _locationKeys; + private SupplyDrop _current; + + private long _lastSupplyDrop; + + private SupplyDropModule() + { + super("Supply Drop"); + + _blockRestore = require(BlockRestore.class); + _loot = require(LootModule.class); + _worldData = require(WorldDataModule.class); + + _beaconBlocks = new HashSet<>(); + + _lastSupplyDrop = System.currentTimeMillis(); + } + + @Override + public void addCommands() + { + addCommand(new SupplyDropCommand(this)); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + if (isActive()) + { + if (_current.advancePath()) + { + stopSequence(); + } + } + else if (UtilTime.elapsed(_lastSupplyDrop, SEQUENCE_TIMER)) + { + startSequence(); + } + } + + @EventHandler + public void itemSpawn(ItemSpawnEvent event) + { + // The Helicopter has a door. This stops it dropping items when it + // moves. + if (event.getEntity().getItemStack().getType() == Material.IRON_DOOR) + { + event.setCancelled(true); + } + } + + @EventHandler + public void fallingBlockChange(EntityChangeBlockEvent event) + { + if (event.getEntity() instanceof FallingBlock && event.getTo() == Material.WOOD && isActive() && UtilMath.offsetSquared(_current.getChestLocation(), event.getBlock().getLocation()) < 4) + { + Block block = event.getBlock(); + + block.setType(Material.CHEST); + + // Add location that the chest will appear at into the spawned + // chests list so that LootModule can populate it with loot. + _loot.addSpawnedChest(block.getLocation(), CHEST_COLOUR); + + // Remove beacon + for (Block beacon : _beaconBlocks) + { + _blockRestore.restore(beacon); + } + + _beaconBlocks.clear(); + + event.setCancelled(true); + } + } + + public void startSequence(String locationKey) + { + Location spawn = _worldData.getCustomLocation(LOCATION_DATA + " " + locationKey + " Start").get(0); + Location destination = _worldData.getCustomLocation(LOCATION_DATA + " " + locationKey + " Chest").get(0); + Location despawn = _worldData.getCustomLocation(LOCATION_DATA + " " + locationKey + " End").get(0); + + // Construct a beacon + for (Pair> pair : UtilBlock.getBeaconBlocks(destination, (byte) 0)) + { + // Look it's like a maze + _beaconBlocks.add(pair.getLeft().getBlock()); + _blockRestore.add(pair.getLeft().getBlock(), pair.getRight().getLeft().getId(), pair.getRight().getRight(), Long.MAX_VALUE); + } + + // Inform the masses + UtilTextMiddle.display(C.cYellow + locationKey, C.cGray + "A Supply Drop is spawning!", 10, 40, 10); + UtilServer.broadcast(F.main(_moduleName, "A Supply Drop is spawning at " + F.elem(locationKey) + " - " + C.cYellow + UtilWorld.locToStrClean(destination))); + + _lastSupplyDrop = System.currentTimeMillis(); + _current = new SupplyDrop(locationKey, spawn, destination, despawn); + } + + public void startSequence() + { + startSequence(getLocationKeys()[UtilMath.r(getLocationKeys().length)]); + } + + public void stopSequence() + { + // Remove beacon (only needed incase the command was executed) + for (Block block : _beaconBlocks) + { + _blockRestore.restore(block); + } + + _beaconBlocks.clear(); + _current.stop(); + _current = null; + } + + public boolean isActive() + { + return _current != null; + } + + public SupplyDrop getActive() + { + return _current; + } + + public long getLastSupplyDrop() + { + return _lastSupplyDrop; + } + + public long getSequenceTimer() + { + return SEQUENCE_TIMER; + } + + public String[] getLocationKeys() + { + if (_locationKeys == null) + { + List supplyDropKeys = new ArrayList<>(); + + for (String key : _worldData.getAllCustomLocations().keySet()) + { + if (key.startsWith(LOCATION_DATA)) + { + String[] split = key.split(" "); + String nameKey = ""; + + for (int i = 1; i < split.length - 1; i++) + { + nameKey += split[i] + " "; + } + + nameKey = nameKey.trim(); + + if (!supplyDropKeys.contains(nameKey)) + { + supplyDropKeys.add(nameKey); + } + } + } + + _locationKeys = supplyDropKeys.toArray(new String[0]); + } + + return _locationKeys; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/EndCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/EndCommand.java new file mode 100644 index 000000000..3265371b6 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/EndCommand.java @@ -0,0 +1,31 @@ +package mineplex.gemhunters.supplydrop.command; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.gemhunters.supplydrop.SupplyDropModule; + +public class EndCommand extends CommandBase +{ + + public EndCommand(SupplyDropModule plugin) + { + super(plugin, Rank.ADMIN, "stop"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (!Plugin.isActive()) + { + caller.sendMessage(F.main(Plugin.getName(), "There is no current supply drop.")); + return; + } + + caller.sendMessage(F.main(Plugin.getName(), "Stopping the current supply drop.")); + Plugin.stopSequence(); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/StartCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/StartCommand.java new file mode 100644 index 000000000..7887b5237 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/StartCommand.java @@ -0,0 +1,79 @@ +package mineplex.gemhunters.supplydrop.command; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.gemhunters.supplydrop.SupplyDropModule; + +public class StartCommand extends CommandBase +{ + + public StartCommand(SupplyDropModule plugin) + { + super(plugin, Rank.ADMIN, "start"); + } + + @Override + public void Execute(Player caller, String[] args) + { + boolean override = false; + + if (Plugin.isActive()) + { + for (String arg : args) + { + if (arg.equalsIgnoreCase("-f")) + { + override = true; + caller.sendMessage(F.main(Plugin.getName(), "Overriding the current supply drop. You know best.")); + Plugin.stopSequence(); + break; + } + } + + if (!override) + { + caller.sendMessage(F.main(Plugin.getName(), "Just saying there is another supply drop already running. If you really really want to override the current one. Add " + F.elem("-f") + " as an additional argument.")); + return; + } + } + + if (args.length == 0 || override && args.length == 1) + { + caller.sendMessage(F.main(Plugin.getName(), "Starting the supply drop sequence at one of the random locations.")); + Plugin.startSequence(); + } + else + { + String input = ""; + + for (int i = 0; i < args.length; i++) + { + input += args[i]; + } + + input = input.trim(); + + for (String key : Plugin.getLocationKeys()) + { + if (input.equalsIgnoreCase(key)) + { + caller.sendMessage(F.main(Plugin.getName(), "Starting the supply drop sequence at " + F.elem(key) + ".")); + Plugin.startSequence(key); + return; + } + } + + caller.sendMessage(F.main(Plugin.getName(), "I wasn\'t able to find a location key of the name " + F.elem(input) + ". Possible values:")); + + for (String key : Plugin.getLocationKeys()) + { + caller.sendMessage(C.cGray + "- " + F.elem(key)); + } + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/SupplyDropCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/SupplyDropCommand.java new file mode 100644 index 000000000..3e0db5ba7 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/supplydrop/command/SupplyDropCommand.java @@ -0,0 +1,29 @@ +package mineplex.gemhunters.supplydrop.command; + +import org.bukkit.entity.Player; + +import mineplex.core.command.MultiCommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.gemhunters.supplydrop.SupplyDropModule; + +public class SupplyDropCommand extends MultiCommandBase +{ + + public SupplyDropCommand(SupplyDropModule plugin) + { + super(plugin, Rank.ADMIN, "supplydrop", "supply", "sd"); + + AddCommand(new StartCommand(plugin)); + AddCommand(new EndCommand(plugin)); + } + + @Override + protected void Help(Player caller, String[] args) + { + caller.sendMessage(F.main(Plugin.getName(), "Command List:")); + caller.sendMessage(F.help("/" + _aliasUsed + " start [location]", "Starts the supply drop sequence at a certain location. Leaving [location] blank picks a random one.", Rank.ADMIN)); + caller.sendMessage(F.help("/" + _aliasUsed + " stop", "Stops the current supply drop.", Rank.ADMIN)); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/ColouredTextAnimation.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/ColouredTextAnimation.java new file mode 100644 index 000000000..fc7dbee75 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/ColouredTextAnimation.java @@ -0,0 +1,123 @@ +package mineplex.gemhunters.util; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.common.util.UtilTextMiddle; + +public class ColouredTextAnimation +{ + + private final String _text; + private final String _prefix; + private final String _suffix; + private final String[] _colours; + + private final double _colourChange; + private final double _colourRequirement; + + // Stage 0 + private int _lastIndex; + private double _colour; + private int _colourIndex; + + // Stage 1 + private int _iterations; + + // Stage 2 + private int _colourStage; + + private String _last; + + private int _stage; + + public ColouredTextAnimation(String text, String... colours) + { + this(text, null, null, colours); + } + + public ColouredTextAnimation(String text, String prefix, String suffix, String[] colours) + { + _text = text; + _prefix = prefix; + _suffix = suffix; + _colours = colours; + + _colourChange = (double) 1 / text.length() * 2; + _colourRequirement = (double) 1 / colours.length; + + _lastIndex = text.length() / 2; + _colour = 0; + _colourIndex = 0; + + _iterations = 0; + + _colourStage = 0; + + _stage = 0; + } + + public boolean displayAsTitle(Player... players) + { + String text = next(); + + UtilTextMiddle.display(text, null, 0, 20, 20, players); + + return _stage == -1; + } + + private String next() + { + String display = ""; + + switch (_stage) + { + case 0: + String text = _text.substring(_lastIndex, _text.length() - _lastIndex); + String colour = _colours[_colourIndex]; + + if (_colour >= _colourRequirement * (_colourIndex + 1)) + { + _colourIndex++; + } + + _colour += _colourChange; + _lastIndex--; + + if (_lastIndex == -1) + { + _stage++; + } + + display = colour + text; + break; + case 1: + _iterations++; + + if (_iterations > 4) + { + _stage++; + } + + display = _last; + break; + case 2: + _colourStage++; + + if (_colourStage > 10) + { + // Stop the cycle + _stage = -1; + } + + display = _colours[_colourStage % _colours.length] + ChatColor.stripColor(_last); + break; + default: + break; + } + + _last = display; + return _prefix + display + _suffix; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/SimpleNPC.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/SimpleNPC.java new file mode 100644 index 000000000..5e265998e --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/SimpleNPC.java @@ -0,0 +1,92 @@ +package mineplex.gemhunters.util; + +import java.util.function.Consumer; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.common.util.UtilEnt; + +public class SimpleNPC implements Listener +{ + + protected final LivingEntity _entity; + private final Consumer _clickEvent; + private final boolean _vegetated; + + public SimpleNPC(JavaPlugin plugin, Location spawn, Class type, String name, Consumer clickEvent) + { + this(plugin, spawn, type, name, clickEvent, true); + } + + public SimpleNPC(JavaPlugin plugin, Location spawn, Class type, String name, Consumer clickEvent, boolean vegetated) + { + spawn.getWorld().loadChunk(spawn.getChunk()); + _entity = spawn.getWorld().spawn(spawn, type); + + _entity.setRemoveWhenFarAway(false); + _entity.setCustomName(name); + _entity.setCustomNameVisible(true); + + UtilEnt.vegetate(_entity, true); + UtilEnt.ghost(_entity, true, false); + UtilEnt.setFakeHead(_entity, true); + + _clickEvent = clickEvent; + _vegetated = vegetated; + + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void npcClick(PlayerInteractEntityEvent event) + { + if (!event.getRightClicked().equals(_entity)) + { + return; + } + + event.setCancelled(true); + + if (_clickEvent != null) + { + _clickEvent.accept(event.getPlayer()); + } + } + + @EventHandler + public void npcDamage(EntityDamageEvent event) + { + if (!event.getEntity().equals(_entity) || !_vegetated) + { + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void npcDeath(EntityDeathEvent event) + { + if (!event.getEntity().equals(_entity) || !_vegetated) + { + return; + } + + HandlerList.unregisterAll(this); + } + + public final LivingEntity getEntity() + { + return _entity; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/SlackSheetsBot.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/SlackSheetsBot.java new file mode 100644 index 000000000..4523e1642 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/util/SlackSheetsBot.java @@ -0,0 +1,25 @@ +package mineplex.gemhunters.util; + +public class SlackSheetsBot +{ + + private static final String SLACK_CHANNEL_NAME = "#google-sheet-errors"; + private static final String SLACK_USERNAME = "Google Sheets"; + private static final String SLACK_ICON = "http://moppletop.github.io/mineplex/google-sheets-image.png"; + + public static final void reportParsingError(Exception exception, String spreadsheetName, String sheetName, int row) + { + String message = "A parsing error has occured on spreadsheet *" + spreadsheetName + "* sheet *" + sheetName + "* at row *" + row + "*.\n Details: " + exception.getMessage(); + + System.out.println(message); +// try +// { +// SlackAPI.getInstance().sendMessage(SlackTeam.DEVELOPER, SLACK_CHANNEL_NAME, new SlackMessage(SLACK_USERNAME, new URL(SLACK_ICON), message), true); +// } +// catch (MalformedURLException e) +// { +// e.printStackTrace(); +// } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/DebugListeners.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/DebugListeners.java new file mode 100644 index 000000000..8e59d81e4 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/DebugListeners.java @@ -0,0 +1,30 @@ +package mineplex.gemhunters.world; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.plugin.java.JavaPlugin; + +public class DebugListeners implements Listener +{ + + private static final String[] OPS = { "Moppletop" }; + + public DebugListeners(JavaPlugin plugin) + { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void autoOp(PlayerJoinEvent event) + { + for (String s : OPS) + { + if (s.equals(event.getPlayer().getName())) + { + event.getPlayer().setOp(true); + } + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/TimeCycle.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/TimeCycle.java new file mode 100644 index 000000000..a3a61a617 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/TimeCycle.java @@ -0,0 +1,92 @@ +package mineplex.gemhunters.world; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.Managers; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; + +public class TimeCycle implements Listener +{ + + private static final int TICKS_DAY = 1; + private static final int TICKS_NIGHT = 2; + + private final WorldDataModule _worldData; + private World _world; + + private boolean _night; + + public TimeCycle(JavaPlugin plugin) + { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + + _worldData = Managers.get(WorldDataModule.class); + } + + public void setStreetLights() + { + Bukkit.broadcastMessage("Set " + _night + " " + _worldData.getCustomLocation("123").size()); + for (Location location : _worldData.getCustomLocation("123")) + { + Block block = location.getBlock().getRelative(BlockFace.UP); + + Bukkit.broadcastMessage("set"); + block.setType(_night ? Material.REDSTONE_BLOCK : Material.STONE_SLAB2); + } + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + if (_world == null) + { + _world = _worldData.World; + return; + } + + if (!_night && _world.getTime() > 12000) + { + _night = true; + //setStreetLights(); + } + + if (_world.getTime() >= 23900) + { + _world.setTime(0); + _night = false; + //setStreetLights(); + } + + _world.setTime(_world.getTime() + (isNight() ? TICKS_NIGHT : TICKS_DAY)); + } + + //@EventHandler + public void test(PlayerCommandPreprocessEvent event) { + if (event.getMessage().startsWith("/lamp")) + { + event.setCancelled(true); + event.getPlayer().getLocation().getBlock().setType(Material.REDSTONE_LAMP_ON); + } + } + + public boolean isNight() + { + return _world.getTime() > 12000; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/UndergroundMobs.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/UndergroundMobs.java new file mode 100644 index 000000000..2369868f1 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/UndergroundMobs.java @@ -0,0 +1,102 @@ +package mineplex.gemhunters.world; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Skeleton; +import org.bukkit.entity.Spider; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.Managers; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; + +public class UndergroundMobs implements Listener +{ + + private static final int MAX_MOBS = 500; + private static final String SEWER_KEY = "SEWER_MOB"; + private static final String SUBWAY_KEY = "SUBWAY_MOBS"; + + private final WorldDataModule _worldData; + + private final World _world; + private final Set _entities; + + public UndergroundMobs(JavaPlugin plugin) + { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + + _worldData = Managers.require(WorldDataModule.class); + + _world = Bukkit.getWorlds().get(0); + _entities = new HashSet<>(); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC_20) + { + return; + } + + Iterator iterator = _entities.iterator(); + + while (iterator.hasNext()) + { + Entity entity = iterator.next(); + + if (entity.isDead() || !entity.isValid()) + { + entity.remove(); + iterator.remove(); + } + } + + //DebugModule.getInstance().d("Spawning mobs " + _entities.size()); + + for (int i = 0; i < 10; i++) + { + if (_entities.size() >= MAX_MOBS) + { + break; + } + + { + Location location = UtilAlg.Random(_worldData.getCustomLocation(SEWER_KEY)).clone().add(0, 1, 0); + Class clazz = UtilMath.random.nextBoolean() ? Zombie.class : Skeleton.class; + Entity entity = _world.spawn(location, clazz); + _entities.add(entity); + } + { + Location location = UtilAlg.Random(_worldData.getCustomLocation(SUBWAY_KEY)).clone().add(0, 1, 0); + Class clazz = Spider.class; + Entity entity = _world.spawn(location, clazz); + _entities.add(entity); + } + } + } + + @EventHandler + public void cancelSuffication(EntityDamageEvent event) + { + if (event.getCause() == DamageCause.SUFFOCATION && _entities.contains(event.getEntity())) + { + event.setCancelled(true); + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/WorldDataModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/WorldDataModule.java new file mode 100644 index 000000000..9aafe307d --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/WorldDataModule.java @@ -0,0 +1,298 @@ +package mineplex.gemhunters.world; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.Difficulty; +import org.bukkit.Location; +import org.bukkit.World; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.timing.TimingManager; + +@ReflectivelyCreateMiniPlugin +public class WorldDataModule extends MiniPlugin +{ + + public World World; + public int MinX = 0; + public int MinZ = 0; + public int MaxX = 0; + public int MaxZ = 0; + + public int MinY = -1; + public int MaxY = 256; + + private final Map> SPAWN_LOCATIONS = new LinkedHashMap<>(); + private final Map> DATA_LOCATIONS = new LinkedHashMap<>(); + private final Map> CUSTOM_LOCAITONS = new LinkedHashMap<>(); + + private WorldDataModule() + { + super("World Data"); + + initialize(); + } + + public void initialize() + { + final WorldDataModule worldData = this; + + World = Bukkit.getWorlds().get(0); + + World.setDifficulty(Difficulty.EASY); + World.setGameRuleValue("showDeathMessages", "false"); + + TimingManager.start("WorldData loading WorldConfig."); + worldData.loadWorldConfig(); + TimingManager.stop("WorldData loading WorldConfig."); + } + + public String getFolder() + { + return "world"; + } + + public void loadWorldConfig() + { + // Load Track Data + String line = null; + + try + { + FileInputStream fstream = new FileInputStream(getFolder() + File.separator + "WorldConfig.dat"); + DataInputStream in = new DataInputStream(fstream); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + + List currentTeam = null; + List currentData = null; + + int currentDirection = 0; + + while ((line = br.readLine()) != null) + { + String[] tokens = line.split(":"); + + if (tokens.length < 2) + { + continue; + } + + String key = tokens[0]; + String value = tokens[1]; + + if (key.length() == 0) + { + continue; + } + + // Spawn Locations + if (key.equalsIgnoreCase("TEAM_NAME")) + { + SPAWN_LOCATIONS.put(value, new ArrayList()); + currentTeam = SPAWN_LOCATIONS.get(value); + currentDirection = 0; + } + else if (key.equalsIgnoreCase("TEAM_DIRECTION")) + { + currentDirection = Integer.parseInt(value); + } + else if (key.equalsIgnoreCase("TEAM_SPAWNS")) + { + for (int i = 1; i < tokens.length; i++) + { + Location loc = stringToLocation(tokens[i]); + if (loc == null) + continue; + + loc.setYaw(currentDirection); + + currentTeam.add(loc); + } + } + + // Data Locations + else if (key.equalsIgnoreCase("DATA_NAME")) + { + DATA_LOCATIONS.put(value, new ArrayList()); + currentData = DATA_LOCATIONS.get(value); + } + else if (key.equalsIgnoreCase("DATA_LOCS")) + { + for (int i = 1; i < tokens.length; i++) + { + Location loc = stringToLocation(tokens[i]); + if (loc == null) + continue; + + currentData.add(loc); + } + } + + // Custom Locations + else if (key.equalsIgnoreCase("CUSTOM_NAME")) + { + CUSTOM_LOCAITONS.put(value, new ArrayList()); + currentData = CUSTOM_LOCAITONS.get(value); + } + else if (key.equalsIgnoreCase("CUSTOM_LOCS")) + { + for (int i = 1; i < tokens.length; i++) + { + Location loc = stringToLocation(tokens[i]); + if (loc == null) + continue; + + currentData.add(loc); + } + } + + // Map Bounds + else if (key.equalsIgnoreCase("MIN_X")) + { + try + { + MinX = Integer.parseInt(value); + } + catch (Exception e) + { + System.out.println("World Data Read Error: Invalid MinX [" + value + "]"); + } + + } + else if (key.equalsIgnoreCase("MAX_X")) + { + try + { + MaxX = Integer.parseInt(value); + } + catch (Exception e) + { + System.out.println("World Data Read Error: Invalid MaxX [" + value + "]"); + } + } + else if (key.equalsIgnoreCase("MIN_Z")) + { + try + { + MinZ = Integer.parseInt(value); + } + catch (Exception e) + { + System.out.println("World Data Read Error: Invalid MinZ [" + value + "]"); + } + } + else if (key.equalsIgnoreCase("MAX_Z")) + { + try + { + MaxZ = Integer.parseInt(value); + } + catch (Exception e) + { + System.out.println("World Data Read Error: Invalid MaxZ [" + value + "]"); + } + } + else if (key.equalsIgnoreCase("MIN_Y")) + { + try + { + MinY = Integer.parseInt(value); + } + catch (Exception e) + { + System.out.println("World Data Read Error: Invalid MinY [" + value + "]"); + } + } + else if (key.equalsIgnoreCase("MAX_Y")) + { + try + { + MaxY = Integer.parseInt(value); + } + catch (Exception e) + { + System.out.println("World Data Read Error: Invalid MaxY [" + value + "]"); + } + } + } + + in.close(); + } + catch (Exception e) + { + e.printStackTrace(); + System.err.println("Line: " + line); + } + } + + private Location stringToLocation(String loc) + { + String[] coords = loc.split(","); + + try + { + return new Location(World, Integer.valueOf(coords[0]) + 0.5, Integer.valueOf(coords[1]), Integer.valueOf(coords[2]) + 0.5); + } + catch (Exception e) + { + System.out.println("World Data Read Error: Invalid Location String [" + loc + "]"); + } + + return null; + } + + public List getSpawnLocation(String colour) + { + if (!SPAWN_LOCATIONS.containsKey(colour)) + { + return new ArrayList(); + } + + return SPAWN_LOCATIONS.get(colour); + } + + public List getDataLocation(String colour) + { + if (!DATA_LOCATIONS.containsKey(colour)) + { + return new ArrayList(); + } + + return DATA_LOCATIONS.get(colour); + } + + public List getCustomLocation(String id) + { + if (!CUSTOM_LOCAITONS.containsKey(id)) + { + return new ArrayList(); + } + + return CUSTOM_LOCAITONS.get(id); + } + + public Map> getAllSpawnLocations() + { + return SPAWN_LOCATIONS; + } + + public Map> getAllCustomLocations() + { + return CUSTOM_LOCAITONS; + } + + public Map> getAllDataLocations() + { + return DATA_LOCATIONS; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/WorldListeners.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/WorldListeners.java new file mode 100644 index 000000000..436c63cf7 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/WorldListeners.java @@ -0,0 +1,209 @@ +package mineplex.gemhunters.world; + +import java.io.File; +import java.util.UUID; + +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockFadeEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.LeavesDecayEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.hanging.HangingBreakEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.player.PlayerArmorStandManipulateEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.weather.WeatherChangeEvent; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.inventory.BeaconInventory; +import org.bukkit.inventory.BrewerInventory; +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.common.util.UtilWorld; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class WorldListeners implements Listener +{ + + private final JavaPlugin _plugin; + + public WorldListeners(JavaPlugin plugin) + { + _plugin = plugin; + + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + //@EventHandler + public void deletePlayerData(PlayerQuitEvent event) + { + _plugin.getServer().getScheduler().runTaskLater(_plugin, () -> { + World world = event.getPlayer().getWorld(); + UUID uuid = event.getPlayer().getUniqueId(); + new File(world.getWorldFolder().getPath() + File.separator + "playerdata" + File.separator + uuid + ".dat").delete(); + new File(world.getWorldFolder().getPath() + File.separator + "stats" + File.separator + uuid + ".json").delete(); + }, 20); + } + + @EventHandler + public void customDamage(CustomDamageEvent event) + { + event.SetDamageToLevel(false); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void blockBreak(BlockBreakEvent event) + { + if (shouldBlock(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void blockPlace(BlockPlaceEvent event) + { + if (event.getBlockPlaced().getType() != Material.CAKE_BLOCK && shouldBlock(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void armorStandEdit(PlayerArmorStandManipulateEvent event) + { + if (shouldBlock(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void entityDestory(PlayerInteractAtEntityEvent event) + { + if (shouldBlock(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void entityDamage(EntityDamageEvent event) + { + if (event.getEntity() instanceof ArmorStand || event.getEntity() instanceof ItemFrame) + { + event.setCancelled(true); + } + } + + @EventHandler + public void paintings(HangingBreakEvent event) + { + event.setCancelled(true); + } + + @EventHandler + public void itemFrames(PlayerInteractEntityEvent event) + { + if (event.getRightClicked() instanceof ItemFrame) + { + event.setCancelled(true); + } + } + + @EventHandler + public void inventoryOpen(InventoryOpenEvent event) + { + if (event.getInventory() instanceof BrewerInventory || event.getInventory() instanceof BeaconInventory) + { + event.setCancelled(true); + } + } + + @EventHandler + public void chunkUnload(ChunkUnloadEvent event) + { + if (!UtilWorld.inWorldBorder(new Location(event.getWorld(), event.getChunk().getX(), 0, event.getChunk().getZ()))) + { + return; + } + + if (event.getChunk().getEntities().length == 0) + { + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void fireSpread(BlockIgniteEvent event) + { + if (event.getCause() == IgniteCause.FLINT_AND_STEEL) + { + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void fireSpread(BlockBurnEvent event) + { + event.setCancelled(true); + } + + @EventHandler + public void blockDecay(BlockFadeEvent event) + { + event.setCancelled(true); + } + + @EventHandler + public void leavesDecay(LeavesDecayEvent event) + { + event.setCancelled(true); + } + + @EventHandler + public void hungerChange(FoodLevelChangeEvent event) + { + Player player = (Player) event.getEntity(); + + //DebugModule.getInstance().d(player.getName() + " hunger " + player.getFoodLevel() + " -> " + event.getFoodLevel()); + // Some witchcraft from the arcade, seems to make hunger not ridiculous. + player.setSaturation(3.8F); + } + + @EventHandler + public void weather(WeatherChangeEvent event) + { + if (event.toWeatherState()) + { + //DebugModule.getInstance().d("Cancelling a weather change"); + event.setCancelled(true); + event.getWorld().setStorm(false); + } + } + + public boolean shouldBlock(Player player) + { + return player.getGameMode() != GameMode.CREATIVE; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEvent.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEvent.java new file mode 100644 index 000000000..c83973f2e --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEvent.java @@ -0,0 +1,137 @@ +package mineplex.gemhunters.worldevent; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import mineplex.core.Managers; +import mineplex.core.common.util.UtilServer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.world.WorldDataModule; + +public abstract class WorldEvent implements Listener +{ + + private final WorldEventType _eventType; + + private WorldEventState _eventState; + + protected final WorldDataModule _worldData; + protected final WorldEventModule _worldEvent; + + protected final Set _entities; + + protected final long _start; + private long _complete; + + public WorldEvent(WorldEventType eventType) + { + _eventType = eventType; + _eventState = null; + + _worldData = Managers.get(WorldDataModule.class); + _worldEvent = Managers.get(WorldEventModule.class); + + _entities = new HashSet<>(); + _start = System.currentTimeMillis(); + + _worldEvent.registerEvents(this); + } + + public abstract void onStart(); + + public abstract boolean checkToEnd(); + + public abstract void onEnd(); + + public abstract Location getCurrentLocation(); + + public final void start() + { + onStart(); + } + + public final void end() + { + _complete = System.currentTimeMillis(); + + for (LivingEntity entity : _entities) + { + entity.damage(Double.MAX_VALUE); + } + + UtilServer.Unregister(this); + + onEnd(); + } + + @EventHandler + public void updateEntities(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + Iterator iterator = _entities.iterator(); + + while (iterator.hasNext()) + { + Entity entity = iterator.next(); + + if (entity.isDead() || !entity.isValid()) + { + entity.remove(); + iterator.remove(); + } + } + } + + public void addEntity(LivingEntity entity) + { + _entities.add(entity); + } + + public WorldEventType getEventType() + { + return _eventType; + } + + public void setEventState(WorldEventState eventState) + { + _eventState = eventState; + + switch (eventState) + { + case WARMUP: + start(); + break; + case COMPLETE: + end(); + default: + break; + } + } + + public boolean isInProgress() + { + return _eventState == WorldEventState.WARMUP || _eventState == WorldEventState.LIVE; + } + + public WorldEventState getEventState() + { + return _eventState; + } + + public long getCompleteTime() + { + return _complete; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventModule.java new file mode 100644 index 000000000..521714db6 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventModule.java @@ -0,0 +1,142 @@ +package mineplex.gemhunters.worldevent; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.bukkit.event.EventHandler; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.worldevent.command.WorldEventCommand; + +@ReflectivelyCreateMiniPlugin +public class WorldEventModule extends MiniPlugin +{ + + private static final long EVENT_TIMER = TimeUnit.MINUTES.toMillis(30); + private static final long EVENT_COOLDOWN_TIMER = TimeUnit.MINUTES.toMillis(20); + private static final long COMPLETE_TIMER = TimeUnit.SECONDS.toMillis(30); + + private final List _events; + private long _lastEventComplete; + + private WorldEventModule() + { + super("World Event"); + + _events = new ArrayList<>(); + _lastEventComplete = System.currentTimeMillis(); + } + + @Override + public void addCommands() + { + addCommand(new WorldEventCommand(this)); + } + + public void startEvent(WorldEventType eventType) + { + WorldEvent event = eventType.createInstance(); + + _events.add(event); + + event.setEventState(WorldEventState.WARMUP); + } + + public void startRandomEvent() + { + WorldEventType[] eventTypes = WorldEventType.values(); + + Set possibleWorldEvents = new HashSet<>(); + + for (WorldEventType eventType : eventTypes) + { + if (UtilTime.elapsed(eventType.getLast(), EVENT_COOLDOWN_TIMER)) + { + continue; + } + + possibleWorldEvents.add(eventType); + } + + if (possibleWorldEvents.isEmpty()) + { + return; + } + + startEvent(UtilAlg.Random(possibleWorldEvents)); + } + + @EventHandler + public void checkNextEvent(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + Iterator iterator = _events.iterator(); + + while (iterator.hasNext()) + { + WorldEvent worldEvent = iterator.next(); + + if (worldEvent.getEventState() == WorldEventState.COMPLETE && UtilTime.elapsed(worldEvent.getCompleteTime(), COMPLETE_TIMER)) + { + iterator.remove(); + } + + if (worldEvent.getEventState() == WorldEventState.LIVE && worldEvent.checkToEnd()) + { + _lastEventComplete = System.currentTimeMillis(); + worldEvent.setEventState(WorldEventState.COMPLETE); + } + } + + if (!isEventActive() && UtilTime.elapsed(_lastEventComplete, EVENT_TIMER)) + { + startRandomEvent(); + } + } + + public boolean isEventActive() + { + return !_events.isEmpty(); + } + + public boolean isGlboalEventActive() + { + for (WorldEvent event : _events) + { + if (event.getEventType().getPriority() == WorldEventPriority.GLOBAL) + { + return true; + } + } + + return false; + } + + public List getActiveEvents() + { + return _events; + } + + public long getLastEventComplete() + { + return _lastEventComplete; + } + + public long getEventTimer() + { + return EVENT_TIMER; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventPriority.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventPriority.java new file mode 100644 index 000000000..8aba307b8 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventPriority.java @@ -0,0 +1,8 @@ +package mineplex.gemhunters.worldevent; + +public enum WorldEventPriority +{ + + GLOBAL, TRIGGERED + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventState.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventState.java new file mode 100644 index 000000000..81e322a47 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventState.java @@ -0,0 +1,15 @@ +package mineplex.gemhunters.worldevent; + +public enum WorldEventState +{ + + WARMUP, + LIVE, + COMPLETE; + + public String getName() + { + return Character.toUpperCase(name().charAt(0)) + name().substring(1); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventType.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventType.java new file mode 100644 index 000000000..aade4f095 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventType.java @@ -0,0 +1,54 @@ +package mineplex.gemhunters.worldevent; + +import mineplex.gemhunters.worldevent.giant.GiantWorldEvent; + +public enum WorldEventType +{ + + GIANT("Zombie Awakening", GiantWorldEvent.class, WorldEventPriority.GLOBAL), + ; + + private String _name; + private Class _clazz; + private WorldEventPriority _priority; + private long _last; + + private WorldEventType(String name, Class clazz, WorldEventPriority priority) + { + _name = name; + _clazz = clazz; + _priority = priority; + _last = 0; + } + + @SuppressWarnings("unchecked") + public T createInstance() + { + try + { + _last = System.currentTimeMillis(); + return (T) _clazz.getConstructor(this.getClass()).newInstance(this); + } + catch (Exception e) + { + e.printStackTrace(); + } + + return null; + } + + public String getName() + { + return _name; + } + + public WorldEventPriority getPriority() + { + return _priority; + } + + public long getLast() + { + return _last; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/StartCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/StartCommand.java new file mode 100644 index 000000000..6290b4ee5 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/StartCommand.java @@ -0,0 +1,48 @@ +package mineplex.gemhunters.worldevent.command; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.gemhunters.worldevent.WorldEventModule; +import mineplex.gemhunters.worldevent.WorldEventType; + +public class StartCommand extends CommandBase +{ + + public StartCommand(WorldEventModule plugin) + { + super(plugin, Rank.ADMIN, "start"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length == 0) + { + caller.sendMessage(F.main(Plugin.getName(), "Starting a random world event.")); + Plugin.startRandomEvent(); + return; + } + + for (WorldEventType eventType : WorldEventType.values()) + { + if (args[0].equalsIgnoreCase(eventType.name())) + { + caller.sendMessage(F.main(Plugin.getName(), "Starting the " + F.elem(eventType.name()) + " world event.")); + Plugin.startEvent(eventType); + return; + } + } + + caller.sendMessage(F.main(Plugin.getName(), "I wasn\'t able to find a world event by the name " + F.elem(args[0]) + ". Possible values:")); + + for (WorldEventType eventType : WorldEventType.values()) + { + caller.sendMessage(C.cGray + "- " + F.elem(eventType.name())); + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/StopCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/StopCommand.java new file mode 100644 index 000000000..0c2887354 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/StopCommand.java @@ -0,0 +1,53 @@ +package mineplex.gemhunters.worldevent.command; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.gemhunters.worldevent.WorldEvent; +import mineplex.gemhunters.worldevent.WorldEventModule; +import mineplex.gemhunters.worldevent.WorldEventState; + +public class StopCommand extends CommandBase +{ + + public StopCommand(WorldEventModule plugin) + { + super(plugin, Rank.ADMIN, "stop"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length == 0) + { + caller.sendMessage(F.main(Plugin.getName(), "Stopping all world events.")); + + for (WorldEvent event : Plugin.getActiveEvents()) + { + event.setEventState(WorldEventState.COMPLETE); + } + return; + } + + for (WorldEvent event : Plugin.getActiveEvents()) + { + if (args[0].equalsIgnoreCase(event.getEventType().name()) && event.getEventState() != WorldEventState.COMPLETE) + { + caller.sendMessage(F.main(Plugin.getName(), "Stopping " + F.elem(event.getEventType().name()) + ".")); + event.setEventState(WorldEventState.COMPLETE); + return; + } + } + + caller.sendMessage(F.main(Plugin.getName(), "I wasn\'t able to find an active world event by the name " + F.elem(args[0]) + ". Possible values:")); + + for (WorldEvent event : Plugin.getActiveEvents()) + { + caller.sendMessage(C.cGray + "- " + F.elem(event.getEventType().name())); + } + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/WorldEventCommand.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/WorldEventCommand.java new file mode 100644 index 000000000..9669379b4 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/command/WorldEventCommand.java @@ -0,0 +1,29 @@ +package mineplex.gemhunters.worldevent.command; + +import org.bukkit.entity.Player; + +import mineplex.core.command.MultiCommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.gemhunters.worldevent.WorldEventModule; + +public class WorldEventCommand extends MultiCommandBase +{ + + public WorldEventCommand(WorldEventModule plugin) + { + super(plugin, Rank.ADMIN, "worldevent", "we"); + + AddCommand(new StartCommand(plugin)); + AddCommand(new StopCommand(plugin)); + } + + @Override + protected void Help(Player caller, String[] args) + { + caller.sendMessage(F.main(Plugin.getName(), "Command List:")); + caller.sendMessage(F.help("/" + _aliasUsed + " start [name]", "Starts a world event. Leaving [name] blank picks a random one.", Rank.ADMIN)); + caller.sendMessage(F.help("/" + _aliasUsed + " stop [name]", "Stops a world event. Leaving [name] blank stops all events.", Rank.ADMIN)); + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/giant/CustomGiant.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/giant/CustomGiant.java new file mode 100644 index 000000000..f5ffdc10f --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/giant/CustomGiant.java @@ -0,0 +1,167 @@ +package mineplex.gemhunters.worldevent.giant; + +import java.util.ArrayList; +import java.util.Collection; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Giant; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.util.Vector; + +import mineplex.core.Managers; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +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.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.safezone.SafezoneModule; +import mineplex.gemhunters.spawn.SpawnModule; + +public class CustomGiant implements Listener +{ + + private static final int GIANT_HEALTH = 100; + private static final int GIANT_WIDTH = 5; + private static final int GIANT_HEIGHT = 13; + private static final float DESTORY_FALLING_BLOCK_CHANCE = 0.04F; + private static final float MOVE_FACTOR = 0.3F; + private static final int MAX_SEARCH_DISTANCE_SQUARED = 2500; + private static final int TOO_CLOSE_DISTANCE_SQUARED = 625; + + private final SafezoneModule _safezone; + + private final Monster _giant; + + private final Location _fallback; + private Location _target; + + public CustomGiant(Location spawn) + { + _safezone = Managers.get(SafezoneModule.class); + + _giant = spawn.getWorld().spawn(spawn, Giant.class); + + _giant.setMaxHealth(GIANT_HEALTH); + _giant.setHealth(_giant.getMaxHealth()); + _giant.setRemoveWhenFarAway(false); + + UtilEnt.vegetate(_giant); + UtilEnt.ghost(_giant, true, false); + UtilEnt.setFakeHead(_giant, true); + + _fallback = Managers.get(SpawnModule.class).getCenter(); + } + + @EventHandler + public void updateMovement(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST || Bukkit.getOnlinePlayers().isEmpty()) + { + if (event.getType() == UpdateType.SEC) + { + _target = acquireTarget(); + } + + return; + } + + if (_target == null) + { + return; + } + + if (_target.equals(_fallback) && UtilMath.offsetSquared(_giant.getLocation(), _fallback) < TOO_CLOSE_DISTANCE_SQUARED) + { + return; + } + + if (_safezone.isInSafeZone(_giant.getLocation())) + { + _target = _fallback; + } + + Vector direction = UtilAlg.getTrajectory2d(_giant.getLocation(), _target).multiply(MOVE_FACTOR); + Location toTeleport = _giant.getLocation().add(direction); + + toTeleport.setYaw(UtilAlg.GetYaw(direction)); + toTeleport.setPitch(UtilAlg.GetPitch(direction)); + + _giant.teleport(toTeleport); + } + + @EventHandler + public void updateBlockDestrory(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + for (Block block : UtilBlock.getInBoundingBox(_giant.getLocation().subtract(GIANT_WIDTH, 0, GIANT_WIDTH), _giant.getLocation().add(GIANT_WIDTH, GIANT_HEIGHT, GIANT_WIDTH))) + { + if (_safezone.isInSafeZone(block.getLocation())) + { + continue; + } + + if (Math.random() < DESTORY_FALLING_BLOCK_CHANCE) + { + FallingBlock fallingBlock = block.getWorld().spawnFallingBlock(block.getLocation(), block.getType(), block.getData()); + + fallingBlock.setDropItem(false); + fallingBlock.setHurtEntities(false); + fallingBlock.setVelocity(new Vector(UtilMath.random(-1, 1), UtilMath.random(0.5, 1), UtilMath.random(-1, 1))); + } + + block.setType(Material.AIR); + } + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + if (event.getPlayer().equals(_target)) + { + _target = acquireTarget(); + } + } + + public Location acquireTarget() + { + Collection ignore = new ArrayList<>(); + + for (Player player : UtilServer.getPlayers()) + { + if (UtilPlayer.isSpectator(player) || _safezone.isInSafeZone(player.getLocation())) + { + ignore.add(player); + } + } + + Player player = UtilPlayer.getClosest(_giant.getLocation(), ignore); + + if (player == null) + { + return _fallback; + } + + return UtilMath.offsetSquared(_giant, player) > MAX_SEARCH_DISTANCE_SQUARED ? _fallback : player.getLocation(); + } + + public Monster getGiant() + { + return _giant; + } + +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/giant/GiantWorldEvent.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/giant/GiantWorldEvent.java new file mode 100644 index 000000000..bbda270b5 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/giant/GiantWorldEvent.java @@ -0,0 +1,100 @@ +package mineplex.gemhunters.worldevent.giant; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.worldevent.WorldEvent; +import mineplex.gemhunters.worldevent.WorldEventState; +import mineplex.gemhunters.worldevent.WorldEventType; + +public class GiantWorldEvent extends WorldEvent +{ + + private static final int MINI_ZOMBIES = 10; + private static final int MINI_ZOMBIES_MAX_DISTANCE_SQUARED = 2500; + private static final long MAX_TIME = TimeUnit.MINUTES.toMillis(5); + + private CustomGiant _giant; + + public GiantWorldEvent(WorldEventType eventType) + { + super(eventType); + } + + @Override + public void onStart() + { + _giant = new CustomGiant(_worldData.getCustomLocation("GIANT_SPAWN").get(0)); + addEntity(_giant.getGiant()); + + _worldEvent.registerEvents(_giant); + + setEventState(WorldEventState.LIVE); + } + + @Override + public boolean checkToEnd() + { + return UtilTime.elapsed(_start, MAX_TIME) || _giant.getGiant().isDead() || !_giant.getGiant().isValid(); + } + + @Override + public void onEnd() + { + } + + @Override + public Location getCurrentLocation() + { + return _giant.getGiant().getLocation(); + } + + @EventHandler + public void zombieCombust(EntityCombustEvent event) + { + if (_entities.contains(event.getEntity())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || _giant == null) + { + return; + } + + for (Entity entity : _entities) + { + if (UtilMath.offsetSquared(entity, _giant.getGiant()) > MINI_ZOMBIES_MAX_DISTANCE_SQUARED) + { + entity.teleport(_giant.getGiant()); + } + } + + // -1 for the giant + if (_entities.size() - 1 < MINI_ZOMBIES) + { + Zombie zombie = _worldData.World.spawn(_giant.getGiant().getLocation(), Zombie.class); + + zombie.setRemoveWhenFarAway(false); + zombie.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 1)); + + addEntity(zombie); + } + } + +} diff --git a/Plugins/mineplex-google-sheets/pom.xml b/Plugins/mineplex-google-sheets/pom.xml new file mode 100644 index 000000000..864b42200 --- /dev/null +++ b/Plugins/mineplex-google-sheets/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + + + com.mineplex + mineplex-plugin + dev-SNAPSHOT + ../plugin.xml + + + Google Sheets + mineplex-google-sheets + + + + org.json + json + 20160212 + compile + + + com.google.api-client + google-api-client + 1.22.0 + compile + + + com.google.oauth-client + google-oauth-client-jetty + 1.22.0 + compile + + + com.google.apis + google-api-services-sheets + v4-rev20-1.22.0 + compile + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + lib/ + mineplex.googlesheets.GoogleSheetController + + + + + + + + \ No newline at end of file diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/GoogleSheetController.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/GoogleSheetController.java new file mode 100644 index 000000000..f6244df65 --- /dev/null +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/GoogleSheetController.java @@ -0,0 +1,63 @@ +package mineplex.googlesheets; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.json.JSONObject; + +public class GoogleSheetController +{ + + private static final int SLEEP_TIME = 1000; + private static final String DATA_STORE_DIR = ".." + File.separatorChar + ".." + File.separatorChar + "update" + File.separatorChar + "files"; + + public static void main(String[] args) throws InterruptedException + { + System.out.println("Loading Sheet Provider"); + SheetProvider provider = new SheetProvider(); + System.out.println("Loaded Sheet Provider"); + + for (SpreadsheetType type : SpreadsheetType.values()) + { + System.out.println("Sleeping..."); + Thread.sleep(SLEEP_TIME); + System.out.println("Getting data for " + type.name() + " (" + type.getID() + ")"); + + JSONObject object = provider.asJSONObject(type); + + System.out.println("Done"); + System.out.println("Saving to file..."); + + File dir = new File(DATA_STORE_DIR); + File file = new File(dir + File.separator + type.name() + ".json"); + + if (!dir.exists()) + { + System.out.println("mkdir"); + dir.mkdirs(); + } + + try + { + System.out.println("Deleting"); + file.delete(); + System.out.println("new File"); + file.createNewFile(); + + FileWriter writer = new FileWriter(file); + + System.out.println("Writing"); + writer.write(object.toString()); + + System.out.println("Closing..."); + writer.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } + +} diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SheetProvider.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SheetProvider.java new file mode 100644 index 000000000..7d7859c49 --- /dev/null +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SheetProvider.java @@ -0,0 +1,160 @@ +package mineplex.googlesheets; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; + +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp; +import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; +import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.util.store.FileDataStoreFactory; +import com.google.api.services.sheets.v4.Sheets; +import com.google.api.services.sheets.v4.SheetsScopes; +import com.google.api.services.sheets.v4.model.Sheet; +import com.google.api.services.sheets.v4.model.Spreadsheet; + +public class SheetProvider +{ + + /** Application name. */ + private static final String APPLICATION_NAME = "Mineplex Google Sheets"; + + /** Directory to store user credentials for this application. */ + private static final File DATA_STORE_DIR = new File(".." + File.separatorChar + ".." + File.separatorChar + "update" + File.separatorChar + "files"); + + /** Global instance of the {@link FileDataStoreFactory}. */ + private static FileDataStoreFactory DATA_STORE_FACTORY; + + /** Global instance of the JSON factory. */ + private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); + + /** Global instance of the HTTP transport. */ + private static HttpTransport HTTP_TRANSPORT; + + private static final List SCOPES = Arrays.asList(SheetsScopes.SPREADSHEETS); + + private Sheets _service; + private Credential _credential; + + static + { + try + { + HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport(); + DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR); + } + catch (Throwable t) + { + t.printStackTrace(); + } + } + + public SheetProvider() + { + try + { + _credential = authorize(); + _service = getSheetsService(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + /** + * Creates an authorized Credential object. + * + * @return an authorized Credential object. + * @throws IOException + */ + public Credential authorize() throws IOException + { + // Load client secrets. + InputStream in = new FileInputStream(DATA_STORE_DIR + File.separator + "client_secret.json"); + GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in)); + + // Build flow and trigger user authorization request. + GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES).setDataStoreFactory(DATA_STORE_FACTORY).setAccessType("offline").build(); + Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user"); + return credential; + } + + /** + * Build and return an authorized Sheets API client service. + * + * @return an authorized Sheets API client service + * @throws IOException + */ + public Sheets getSheetsService() + { + return new Sheets.Builder(HTTP_TRANSPORT, JSON_FACTORY, _credential).setApplicationName(APPLICATION_NAME).build(); + } + + public JSONObject asJSONObject(SpreadsheetType spreadsheet) + { + JSONObject parent = new JSONObject(); + JSONArray array = new JSONArray(); + Map>> valuesMap = get(spreadsheet); + + for (String sheetName : valuesMap.keySet()) + { + List> values = valuesMap.get(sheetName); + + JSONObject object = new JSONObject(); + + object.put("name", sheetName); + object.put("values", values); + + array.put(object); + } + + parent.put("data", array); + return parent; + } + + public Map>> get(SpreadsheetType spreadsheet) + { + try + { + Spreadsheet googleSpreadsheet = _service.spreadsheets().get(spreadsheet.getID()).execute(); + Map>> valuesMap = new HashMap<>(googleSpreadsheet.getSheets().size() - 1); + + for (Sheet sheet : googleSpreadsheet.getSheets()) + { + String name = sheet.getProperties().getTitle(); + + valuesMap.put(name, get(spreadsheet, name)); + } + + return valuesMap; + } + catch (IOException e) + { + e.printStackTrace(); + } + + return null; + } + + public List> get(SpreadsheetType spreadsheet, String sheetName) throws IOException + { + return _service.spreadsheets().values().get(spreadsheet.getID(), sheetName).execute().getValues(); + } + +} diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java new file mode 100644 index 000000000..af2acf11c --- /dev/null +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java @@ -0,0 +1,25 @@ +package mineplex.googlesheets; + +/** + * An enum containing all the google spreadsheet links relating to Mineplex.
+ */ +public enum SpreadsheetType +{ + + GEM_HUNTERS_CHESTS("11Noztgbpu_gUKkc5F4evKKfyxS-Jv1coE0IrBToX_gg"), + GEM_HUNTERS_SHOP("1OcYktxVZaW6Fm29Zh6w4Lb-UVyuN8r1x-TFb_3USYYI"), + ; + + private String _id; + + private SpreadsheetType(String id) + { + _id = id; + } + + public String getID() + { + return _id; + } + +} diff --git a/Plugins/pom.xml b/Plugins/pom.xml index a6713cf43..0eb37a3d5 100644 --- a/Plugins/pom.xml +++ b/Plugins/pom.xml @@ -40,6 +40,8 @@ Nautilus.Game.Arcade.UHC.WorldGen mavericks-review-hub + mineplex-game-gemhunters + mineplex-google-sheets