Misc.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package com.gmail.nossr50.util;
  2. import com.gmail.nossr50.api.ItemSpawnReason;
  3. import com.neetgames.mcmmo.player.OnlineMMOPlayer;
  4. import com.gmail.nossr50.events.items.McMMOItemSpawnEvent;
  5. import com.gmail.nossr50.mcMMO;
  6. import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
  7. import com.google.common.collect.ImmutableSet;
  8. import org.bukkit.Location;
  9. import org.bukkit.Material;
  10. import org.bukkit.World;
  11. import org.bukkit.block.BlockState;
  12. import org.bukkit.entity.*;
  13. import org.bukkit.inventory.ItemStack;
  14. import org.bukkit.scheduler.BukkitRunnable;
  15. import org.bukkit.util.Vector;
  16. import org.jetbrains.annotations.NotNull;
  17. import org.jetbrains.annotations.Nullable;
  18. import java.util.Collection;
  19. import java.util.Locale;
  20. import java.util.Random;
  21. import java.util.Set;
  22. public final class Misc {
  23. private static final @NotNull Random random = new Random();
  24. public static final int TIME_CONVERSION_FACTOR = 1000;
  25. public static final int TICK_CONVERSION_FACTOR = 20;
  26. public static final int PLAYER_RESPAWN_COOLDOWN_SECONDS = 5;
  27. public static final double SKILL_MESSAGE_MAX_SENDING_DISTANCE = 10.0;
  28. // Sound Pitches & Volumes from CB
  29. /* public static final float ANVIL_USE_PITCH = 0.3F; // Not in CB directly, I went off the place sound values
  30. public static final float ANVIL_USE_VOLUME = 1.0F * Config.getInstance().getMasterVolume(); // Not in CB directly, I went off the place sound values
  31. public static final float FIZZ_VOLUME = 0.5F * Config.getInstance().getMasterVolume();
  32. public static final float POP_VOLUME = 0.2F * Config.getInstance().getMasterVolume();
  33. public static final float BAT_VOLUME = 1.0F * Config.getInstance().getMasterVolume();
  34. public static final float BAT_PITCH = 0.6F;
  35. public static final float GHAST_VOLUME = 1.0F * Config.getInstance().getMasterVolume();
  36. public static final float LEVELUP_PITCH = 0.5F; // Reduced to differentiate between vanilla level-up
  37. public static final float LEVELUP_VOLUME = 0.75F * Config.getInstance().getMasterVolume(); // Use max volume always*/
  38. public static final @NotNull Set<String> modNames = ImmutableSet.of("LOTR", "BUILDCRAFT", "ENDERIO", "ENHANCEDBIOMES", "IC2", "METALLURGY", "FORESTRY", "GALACTICRAFT", "RAILCRAFT", "TWILIGHTFOREST", "THAUMCRAFT", "GRAVESTONEMOD", "GROWTHCRAFT", "ARCTICMOBS", "DEMONMOBS", "INFERNOMOBS", "SWAMPMOBS", "MARICULTURE", "MINESTRAPPOLATION");
  39. private Misc() {}
  40. /**
  41. * Determines if an entity is an NPC but not a villager
  42. * This method aims to establish compatibility between mcMMO and other plugins which create "NPCs"
  43. *
  44. * It does this by checking the following
  45. * 1) The entity is not a Villager
  46. * 2) The entity can be considered an NPC
  47. *
  48. * In this context, an NPC is a bit hard to define. Various plugins determine what an NPC is in different ways.
  49. * @see Misc::isNPCIncludingVillagers
  50. * @param entity target entity
  51. * @return true if the entity is not a Villager and is not a "NPC"
  52. */
  53. public static boolean isNPCEntityExcludingVillagers(@NotNull Entity entity) {
  54. return (!isVillager(entity)
  55. && isNPCIncludingVillagers(entity)); //Compatibility with some mod..
  56. }
  57. public static boolean isNPCClassType(Entity entity) {
  58. return entity instanceof NPC;
  59. }
  60. public static boolean hasNPCMetadataTag(Entity entity) {
  61. return entity.hasMetadata("NPC");
  62. }
  63. public static boolean isVillager(Entity entity) {
  64. String entityType = entity.getType().toString();
  65. //This weird code is for 1.13 & 1.14 compatibility
  66. return entityType.equalsIgnoreCase("wandering_trader") || entity instanceof Villager;
  67. }
  68. public static boolean isNPCIncludingVillagers(@Nullable Entity entity) {
  69. return (entity == null
  70. || (hasNPCMetadataTag(entity))
  71. || (isNPCClassType(entity))
  72. || entity.getClass().getName().equalsIgnoreCase("cofh.entity.PlayerFake"));
  73. }
  74. /**
  75. * Determine if two locations are near each other.
  76. *
  77. * @param first The first location
  78. * @param second The second location
  79. * @param maxDistance The max distance apart
  80. * @return true if the distance between {@code first} and {@code second} is less than {@code maxDistance}, false otherwise
  81. */
  82. public static boolean isNear(@NotNull Location first, @NotNull Location second, double maxDistance) {
  83. return (first.getWorld() == second.getWorld()) && (first.distanceSquared(second) < (maxDistance * maxDistance) || maxDistance == 0);
  84. }
  85. /**
  86. * Get the center of the given block.
  87. *
  88. * @param blockState The {@link BlockState} of the block
  89. * @return A {@link Location} lying at the center of the block
  90. */
  91. public static Location getBlockCenter(BlockState blockState) {
  92. return blockState.getLocation().add(0.5, 0.5, 0.5);
  93. }
  94. public static void spawnItemsFromCollection(@NotNull Location location, @NotNull Collection<ItemStack> drops, @NotNull ItemSpawnReason itemSpawnReason) {
  95. for (ItemStack drop : drops) {
  96. spawnItem(location, drop, itemSpawnReason);
  97. }
  98. }
  99. /**
  100. * Drops only the first n items in a collection
  101. * Size should always be a positive integer above 0
  102. *
  103. * @param location target drop location
  104. * @param drops collection to iterate over
  105. * @param sizeLimit the number of drops to process
  106. */
  107. public static void spawnItemsFromCollection(@NotNull Location location, @NotNull Collection<ItemStack> drops, @NotNull ItemSpawnReason itemSpawnReason, int sizeLimit) {
  108. ItemStack[] arrayDrops = drops.toArray(new ItemStack[0]);
  109. for(int i = 0; i < sizeLimit-1; i++) {
  110. spawnItem(location, arrayDrops[i], itemSpawnReason);
  111. }
  112. }
  113. /**
  114. * Drop items at a given location.
  115. *
  116. * @param location The location to drop the items at
  117. * @param is The items to drop
  118. * @param quantity The amount of items to drop
  119. */
  120. public static void spawnItems(@NotNull Location location, @NotNull ItemStack is, int quantity, @NotNull ItemSpawnReason itemSpawnReason) {
  121. for (int i = 0; i < quantity; i++) {
  122. spawnItem(location, is, itemSpawnReason);
  123. }
  124. }
  125. /**
  126. * Drop an item at a given location.
  127. *
  128. * @param location The location to drop the item at
  129. * @param itemStack The item to drop
  130. * @param itemSpawnReason the reason for the item drop
  131. * @return Dropped Item entity or null if invalid or cancelled
  132. */
  133. public static @Nullable Item spawnItem(@NotNull Location location, @NotNull ItemStack itemStack, @NotNull ItemSpawnReason itemSpawnReason) {
  134. if (itemStack.getType() == Material.AIR || location.getWorld() == null) {
  135. return null;
  136. }
  137. // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event.
  138. McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack, itemSpawnReason);
  139. mcMMO.p.getServer().getPluginManager().callEvent(event);
  140. if (event.isCancelled()) {
  141. return null;
  142. }
  143. return location.getWorld().dropItem(location, itemStack);
  144. }
  145. /**
  146. * Drop an item at a given location.
  147. *
  148. * @param location The location to drop the item at
  149. * @param itemStack The item to drop
  150. * @param itemSpawnReason the reason for the item drop
  151. * @return Dropped Item entity or null if invalid or cancelled
  152. */
  153. public static @Nullable Item spawnItemNaturally(@NotNull Location location, @NotNull ItemStack itemStack, @NotNull ItemSpawnReason itemSpawnReason) {
  154. if (itemStack.getType() == Material.AIR || location.getWorld() == null) {
  155. return null;
  156. }
  157. // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event.
  158. McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack, itemSpawnReason);
  159. mcMMO.p.getServer().getPluginManager().callEvent(event);
  160. if (event.isCancelled()) {
  161. return null;
  162. }
  163. return location.getWorld().dropItemNaturally(location, itemStack);
  164. }
  165. /**
  166. * Drop items at a given location.
  167. *
  168. * @param fromLocation The location to drop the items at
  169. * @param is The items to drop
  170. * @param speed the speed that the item should travel
  171. * @param quantity The amount of items to drop
  172. */
  173. public static void spawnItemsTowardsLocation(@NotNull Location fromLocation, @NotNull Location toLocation, @NotNull ItemStack is, int quantity, double speed, @NotNull ItemSpawnReason itemSpawnReason) {
  174. for (int i = 0; i < quantity; i++) {
  175. spawnItemTowardsLocation(fromLocation, toLocation, is, speed, itemSpawnReason);
  176. }
  177. }
  178. /**
  179. * Drop an item at a given location.
  180. * This method is fairly expensive as it creates clones of everything passed to itself since they are mutable objects
  181. *
  182. * @param fromLocation The location to drop the item at
  183. * @param toLocation The location the item will travel towards
  184. * @param itemToSpawn The item to spawn
  185. * @param speed the speed that the item should travel
  186. * @return Dropped Item entity or null if invalid or cancelled
  187. */
  188. public static @Nullable Item spawnItemTowardsLocation(@NotNull Location fromLocation, @NotNull Location toLocation, @NotNull ItemStack itemToSpawn, double speed, @NotNull ItemSpawnReason itemSpawnReason) {
  189. if (itemToSpawn.getType() == Material.AIR) {
  190. return null;
  191. }
  192. //Work with fresh copies of everything
  193. ItemStack clonedItem = itemToSpawn.clone();
  194. Location spawnLocation = fromLocation.clone();
  195. Location targetLocation = toLocation.clone();
  196. if(spawnLocation.getWorld() == null)
  197. return null;
  198. // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event.
  199. McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(spawnLocation, clonedItem, itemSpawnReason);
  200. mcMMO.p.getServer().getPluginManager().callEvent(event);
  201. //Something cancelled the event so back out
  202. if (event.isCancelled()) {
  203. return null;
  204. }
  205. //Use the item from the event
  206. Item spawnedItem = spawnLocation.getWorld().dropItem(spawnLocation, clonedItem);
  207. Vector vecFrom = spawnLocation.clone().toVector().clone();
  208. Vector vecTo = targetLocation.clone().toVector().clone();
  209. //Vector which is pointing towards out target location
  210. Vector direction = vecTo.subtract(vecFrom).normalize();
  211. //Modify the speed of the vector
  212. direction = direction.multiply(speed);
  213. spawnedItem.setVelocity(direction);
  214. return spawnedItem;
  215. }
  216. public static void profileCleanup(@NotNull String playerName) {
  217. Player player = mcMMO.p.getServer().getPlayerExact(playerName);
  218. if (player != null) {
  219. mcMMO.getUserManager().remove(player);
  220. new PlayerProfileLoadingTask(player).runTaskLaterAsynchronously(mcMMO.p, 1); // 1 Tick delay to ensure the player is marked as online before we begin loading
  221. }
  222. }
  223. public static int getWorldMinCompat(World world)
  224. {
  225. // TODO this method should access the world min variable in a version safe manner so that we don't restrict usage to new versions of spigot only
  226. return 0;
  227. }
  228. public static void printProgress(int convertedUsers, int progressInterval, long startMillis) {
  229. if ((convertedUsers % progressInterval) == 0) {
  230. mcMMO.p.getLogger().info(String.format("Conversion progress: %d users at %.2f users/second", convertedUsers, convertedUsers / (double) ((System.currentTimeMillis() - startMillis) / TIME_CONVERSION_FACTOR)));
  231. }
  232. }
  233. public static String getModName(@NotNull String materialName) {
  234. for (String mod : modNames) {
  235. if (materialName.contains(mod)) {
  236. return mod;
  237. }
  238. }
  239. String[] materialSplit = materialName.split("_");
  240. if (materialSplit.length > 1) {
  241. return materialSplit[0].toLowerCase(Locale.ENGLISH);
  242. }
  243. return "UnknownMods";
  244. }
  245. /**
  246. * Gets a random location near the specified location
  247. */
  248. public static Location getLocationOffset(@NotNull Location location, double strength) {
  249. double blockX = location.getBlockX();
  250. double blockZ = location.getBlockZ();
  251. double distance;
  252. distance = strength * random.nextDouble();
  253. blockX = (random.nextBoolean()) ? blockX + (distance) : blockX - (distance);
  254. distance = strength * random.nextDouble();
  255. blockZ = (random.nextBoolean()) ? blockZ + (distance) : blockZ - (distance);
  256. return new Location(location.getWorld(), blockX, location.getY(), blockZ);
  257. }
  258. public static @NotNull Random getRandom() {
  259. return random;
  260. }
  261. /**
  262. * Whether or not a player is the party leader of a party
  263. *
  264. * @param mmoPlayer target player
  265. * @return true if the player is the party leader
  266. */
  267. public static boolean isPartyLeader(@NotNull OnlineMMOPlayer mmoPlayer) {
  268. return mcMMO.getPartyManager().queryParty(mmoPlayer.getUUID()).getPartyMemberManager().getPartyLeader().getUniqueId().equals(mmoPlayer.getUUID());
  269. }
  270. // public static void spawnExperienceOrb(@NotNull Location location, int orbAmount, int experienceValue) {
  271. // for (int i = 0; i < orbAmount; i++) {
  272. // new SpawnOrbTask(location, experienceValue).runTaskLater(mcMMO.p, 20);
  273. // }
  274. // }
  275. public static void spawnExperienceOrb(@NotNull Location location, int experienceValue) {
  276. if(location.getWorld() == null)
  277. return;
  278. ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB);
  279. experienceOrb.setExperience(experienceValue);
  280. }
  281. public static @NotNull Player adaptPlayer(@NotNull OnlineMMOPlayer onlineMMOPlayer) {
  282. return (Player) onlineMMOPlayer.getServerAPIPlayerImpl();
  283. }
  284. private static class SpawnOrbTask extends BukkitRunnable {
  285. private final Location location;
  286. private int orbExpValue;
  287. private SpawnOrbTask(Location location, int orbExpValue) {
  288. this.location = location;
  289. this.orbExpValue = orbExpValue;
  290. }
  291. @Override
  292. public void run() {
  293. if(location == null || location.getWorld() == null)
  294. return;
  295. ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB);
  296. experienceOrb.setExperience(orbExpValue);
  297. }
  298. }
  299. }