diff --git a/buildSrc/src/main/kotlin/buildlogic.java-conventions.gradle.kts b/buildSrc/src/main/kotlin/buildlogic.java-conventions.gradle.kts index 8f7b86a2..4e019ca8 100644 --- a/buildSrc/src/main/kotlin/buildlogic.java-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/buildlogic.java-conventions.gradle.kts @@ -16,10 +16,10 @@ repositories { maven("https://repo.pgm.fyi/snapshots") // Sportpaper & other pgm-specific stuff maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot repo maven("https://repo.aikar.co/content/groups/aikar/") // aikar repo + maven("https://jitpack.io") // Backup: jitpack } dependencies { - implementation("tc.oc.pgm:util:0.16-SNAPSHOT") { isTransitive = false } implementation("com.zaxxer:HikariCP:2.4.1") { isTransitive = false } implementation("fr.minuskube.inv:smart-invs:1.2.7") { isTransitive = false } @@ -29,13 +29,22 @@ dependencies { implementation("net.kyori:adventure-api:4.17.0") implementation("net.kyori:adventure-text-serializer-plain:4.17.0") implementation("net.kyori:adventure-platform-bukkit:4.3.4") + implementation("org.reflections:reflections:0.10.2") - compileOnly("app.ashcon:sportpaper:1.8.8-R0.1-SNAPSHOT") compileOnly("tc.oc.pgm:core:0.16-SNAPSHOT") + compileOnly("tc.oc.pgm:util:0.16-SNAPSHOT") compileOnly("tc.oc.occ:AFK:1.0.0-SNAPSHOT") compileOnly("tc.oc.occ:Environment:1.0.0-SNAPSHOT") compileOnly("org.incendo:cloud-annotations:2.0.0") compileOnly("org.jetbrains:annotations:22.0.0") + compileOnly("com.github.dmulloy2:ProtocolLib:5.3.0") + + // Minecraft includes these (or equivalents) + compileOnly("com.mojang:authlib:6.0.54") + compileOnly("it.unimi.dsi:fastutil:8.1.0") + compileOnly("com.google.guava:guava:17.0") + compileOnly("com.google.code.gson:gson:2.10.1") + compileOnly("commons-lang:commons-lang:2.6") } group = "dev.pgm.community" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 75eeec83..5dd088b5 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -6,12 +6,25 @@ plugins { id("com.gradleup.shadow") } +dependencies { + compileOnly("dev.pgm.paper:paper-api:1.8_1.21.1-SNAPSHOT") + + implementation(project(":util")) + + runtimeOnly(project(":platform-sportpaper")) { exclude("*") } + runtimeOnly(project(":platform-modern")) { exclude("*") } +} + tasks.named("shadowJar") { archiveFileName = "Community.jar" archiveClassifier.set("") destinationDirectory = rootProject.projectDir.resolve("build/libs") - minimize() + minimize { + // Exclude from minimization as they're required at runtime + exclude(project(":platform-sportpaper")) + exclude(project(":platform-modern")) + } dependencies { exclude(dependency("org.jetbrains:annotations")) diff --git a/core/src/main/java/dev/pgm/community/Community.java b/core/src/main/java/dev/pgm/community/Community.java index ac5dce94..576086f9 100644 --- a/core/src/main/java/dev/pgm/community/Community.java +++ b/core/src/main/java/dev/pgm/community/Community.java @@ -6,9 +6,11 @@ import dev.pgm.community.feature.FeatureManager; import dev.pgm.community.squads.SquadChannel; import dev.pgm.community.text.TextTranslations; +import dev.pgm.community.util.Platform; import dev.pgm.community.utils.PGMUtils; import fr.minuskube.inv.InventoryManager; import java.util.Random; +import java.util.logging.Level; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.event.Listener; @@ -46,6 +48,14 @@ public void onEnable() { BukkitUtils.PLUGIN.set(this); } + // Sanity test PGM is running on a supported version before doing any work + try { + Platform.init(); + } catch (Throwable t) { + getLogger().log(Level.SEVERE, "Failed to initialize Community platform", t); + getServer().getPluginManager().disablePlugin(this); + } + this.setupConfig(); this.setupDatabase(); this.setupFeatures(); @@ -90,6 +100,7 @@ private void setupTranslations() { } public void registerListener(Listener listener) { + Platform.MANIFEST.onEnable(this); getServer().getPluginManager().registerEvents(listener, this); } @@ -139,7 +150,7 @@ public void callEvent(CommunityEvent event) { // REMOVE WHEN NOT IN DEV public static void log(String format, Object... objects) { Bukkit.getConsoleSender() - .sendMessage(ChatColor.translateAlternateColorCodes( + .sendRawMessage(ChatColor.translateAlternateColorCodes( '&', String.format("&7[&4Community&7]&r " + format, objects))); } } diff --git a/core/src/main/java/dev/pgm/community/mobs/MobFeature.java b/core/src/main/java/dev/pgm/community/mobs/MobFeature.java index 6f8ccebd..ae12f014 100644 --- a/core/src/main/java/dev/pgm/community/mobs/MobFeature.java +++ b/core/src/main/java/dev/pgm/community/mobs/MobFeature.java @@ -1,5 +1,7 @@ package dev.pgm.community.mobs; +import static dev.pgm.community.util.EntityUtils.ENTITY_UTILS; + import com.google.common.collect.Maps; import com.google.common.collect.Sets; import dev.pgm.community.Community; @@ -11,11 +13,8 @@ import java.util.UUID; import java.util.logging.Logger; import java.util.stream.Collectors; -import net.minecraft.server.v1_8_R3.EntityInsentient; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.configuration.Configuration; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.entity.Creature; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -50,11 +49,10 @@ public MobFeature(Configuration config, Logger logger) { @Override public void enable() { super.enable(); - this.task = - Community.get() - .getServer() - .getScheduler() - .runTaskTimer(Community.get(), this::updateFollows, 0L, 10L); + this.task = Community.get() + .getServer() + .getScheduler() + .runTaskTimer(Community.get(), this::updateFollows, 0L, 10L); } @Override @@ -81,24 +79,19 @@ public void onDamage(EntityDamageByEntityEvent event) { } public void updateFollows() { - this.followTargets - .entrySet() - .forEach( - entry -> { - Player owner = Bukkit.getPlayer(entry.getKey()); - Player target = Bukkit.getPlayer(entry.getValue()); - if (owner != null && target != null) { - this.getOwnedMobs(owner) - .forEach( - mob -> { - follow(mob, target.getLocation()); - if (mob instanceof Creature && attackers.contains(owner.getUniqueId())) { - Creature creature = (Creature) mob; - creature.setTarget(target); - } - }); - } - }); + this.followTargets.entrySet().forEach(entry -> { + Player owner = Bukkit.getPlayer(entry.getKey()); + Player target = Bukkit.getPlayer(entry.getValue()); + if (owner != null && target != null) { + this.getOwnedMobs(owner).forEach(mob -> { + ENTITY_UTILS.follow(mob, target.getLocation(), speed); + if (mob instanceof Creature && attackers.contains(owner.getUniqueId())) { + Creature creature = (Creature) mob; + creature.setTarget(target); + } + }); + } + }); } public boolean isFollower(UUID playerId) { @@ -121,11 +114,6 @@ public void setTarget(Player player, Player target) { } } - private void follow(LivingEntity mob, Location location) { - EntityInsentient nmsMob = ((EntityInsentient) ((CraftEntity) mob).getHandle()); - nmsMob.getNavigation().a(location.getX(), location.getY(), location.getZ(), speed); - } - public MobConfig getMobConfig() { return (MobConfig) getConfig(); } @@ -152,15 +140,13 @@ public void spawn(Player sender, EntityType type, boolean canDie) { public List getOwnedMobs(Player sender) { return sender.getWorld().getLivingEntities().stream() .filter(le -> le.hasMetadata("owner")) - .filter( - le -> { - List values = le.getMetadata("owner"); - Optional value = - values.stream() - .filter(mv -> mv.getOwningPlugin().equals(Community.get())) - .findAny(); - return value.isPresent() && value.get().asString().equalsIgnoreCase(sender.getName()); - }) + .filter(le -> { + List values = le.getMetadata("owner"); + Optional value = values.stream() + .filter(mv -> mv.getOwningPlugin().equals(Community.get())) + .findAny(); + return value.isPresent() && value.get().asString().equalsIgnoreCase(sender.getName()); + }) .collect(Collectors.toList()); } diff --git a/core/src/main/java/dev/pgm/community/mutations/types/items/BreadMutation.java b/core/src/main/java/dev/pgm/community/mutations/types/items/BreadMutation.java index de634345..c5741160 100644 --- a/core/src/main/java/dev/pgm/community/mutations/types/items/BreadMutation.java +++ b/core/src/main/java/dev/pgm/community/mutations/types/items/BreadMutation.java @@ -1,5 +1,7 @@ package dev.pgm.community.mutations.types.items; +import static dev.pgm.community.util.InventoryUtils.INVENTORY_UTILS; + import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -7,6 +9,7 @@ import dev.pgm.community.mutations.Mutation; import dev.pgm.community.mutations.MutationType; import dev.pgm.community.mutations.types.KitMutationBase; +import dev.pgm.community.utils.compatibility.Enchantments; import dev.pgm.community.utils.compatibility.PotionEffects; import java.util.HashMap; import java.util.HashSet; @@ -103,7 +106,8 @@ static ImmutableMap getBreadsMap() { ItemStack ironBread = preventSharing( new ItemBuilder(new ItemStack(Material.BREAD)).name("Iron Bread").build()); ItemMeta ironBreadMeta = ironBread.getItemMeta(); - ironBreadMeta.addAttributeModifier( + INVENTORY_UTILS.addAttributeModifier( + ironBreadMeta, Attribute.GENERIC_KNOCKBACK_RESISTANCE, new AttributeModifier( Attribute.GENERIC_KNOCKBACK_RESISTANCE.name(), @@ -114,7 +118,8 @@ static ImmutableMap getBreadsMap() { ItemStack fastBread = preventSharing( new ItemBuilder(new ItemStack(Material.BREAD)).name("Fast Bread").build()); ItemMeta speedBreadMeta = fastBread.getItemMeta(); - speedBreadMeta.addAttributeModifier( + INVENTORY_UTILS.addAttributeModifier( + speedBreadMeta, Attribute.GENERIC_MOVEMENT_SPEED, new AttributeModifier( Attribute.GENERIC_MOVEMENT_SPEED.name(), 0.3, AttributeModifier.Operation.ADD_SCALAR)); @@ -123,7 +128,8 @@ static ImmutableMap getBreadsMap() { ItemStack veryFastBread = preventSharing( new ItemBuilder(new ItemStack(Material.BREAD)).name("Very Fast Bread").build()); ItemMeta veryFastBreadMeta = veryFastBread.getItemMeta(); - veryFastBreadMeta.addAttributeModifier( + INVENTORY_UTILS.addAttributeModifier( + veryFastBreadMeta, Attribute.GENERIC_MOVEMENT_SPEED, new AttributeModifier( Attribute.GENERIC_MOVEMENT_SPEED.name(), 1, AttributeModifier.Operation.ADD_SCALAR)); @@ -138,7 +144,7 @@ static ImmutableMap getBreadsMap() { 20.0) .put( preventSharing(new ItemBuilder(new ItemStack(Material.BREAD)) - .enchant(Enchantment.DAMAGE_ALL, 5) + .enchant(Enchantments.SHARPNESS, 5) .name("Sharp Bread") .build()), 20.0) @@ -156,7 +162,7 @@ static ImmutableMap getBreadsMap() { .put(veryFastBread, 3.0) .put( preventSharing(new ItemBuilder(new ItemStack(Material.BREAD)) - .enchant(Enchantment.DAMAGE_ALL, 10) + .enchant(Enchantments.SHARPNESS, 10) .name("Very Sharp Bread") .build()), 3.0) @@ -174,7 +180,7 @@ static ImmutableMap getBreadsMap() { 1.0) .put( preventSharing(new ItemBuilder(new ItemStack(Material.BREAD)) - .enchant(Enchantment.DAMAGE_ALL, 20) + .enchant(Enchantments.SHARPNESS, 20) .name("Insanely Sharp Bread") .build()), 1.0) @@ -203,7 +209,7 @@ static ImmutableMap getBadBreadsMap() { 20.0) .put( preventSharing(new ItemBuilder(new ItemStack(Material.BREAD)) - .enchant(Enchantment.DAMAGE_ALL, 5) + .enchant(Enchantments.SHARPNESS, 5) .name("Sharp Bread") .build()), 20.0) diff --git a/core/src/main/java/dev/pgm/community/mutations/types/items/ExplosionMutation.java b/core/src/main/java/dev/pgm/community/mutations/types/items/ExplosionMutation.java index f5608f16..136962dc 100644 --- a/core/src/main/java/dev/pgm/community/mutations/types/items/ExplosionMutation.java +++ b/core/src/main/java/dev/pgm/community/mutations/types/items/ExplosionMutation.java @@ -1,5 +1,6 @@ package dev.pgm.community.mutations.types.items; +import static dev.pgm.community.util.Effects.EFFECTS; import static tc.oc.pgm.util.bukkit.BukkitUtils.colorize; import com.google.common.collect.Lists; @@ -21,7 +22,6 @@ import java.util.UUID; import java.util.stream.Collectors; import org.bukkit.Bukkit; -import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -217,8 +217,7 @@ private void explode(Block block) { world.createExplosion(loc, 3.3f); - for (int i = 0; i < 5; i++) - world.spigot().playEffect(loc, Effect.LAVA_POP, 0, 0, 0, 0, 0, 0, 15, 50); + for (int i = 0; i < 5; i++) EFFECTS.explosionEffect(loc); } private static Kit getRandomKit() { diff --git a/core/src/main/java/dev/pgm/community/mutations/types/items/GrapplingHookMutation.java b/core/src/main/java/dev/pgm/community/mutations/types/items/GrapplingHookMutation.java index e0cbbba8..d9923a5d 100644 --- a/core/src/main/java/dev/pgm/community/mutations/types/items/GrapplingHookMutation.java +++ b/core/src/main/java/dev/pgm/community/mutations/types/items/GrapplingHookMutation.java @@ -1,5 +1,8 @@ package dev.pgm.community.mutations.types.items; +import static dev.pgm.community.util.Effects.EFFECTS; +import static dev.pgm.community.util.EventUtils.EVENT_UTILS; + import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; @@ -16,7 +19,6 @@ import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Sound; import org.bukkit.entity.FishHook; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -43,10 +45,9 @@ public class GrapplingHookMutation extends KitMutationBase { public GrapplingHookMutation(Match match) { super(match, MutationType.GRAPPLING_HOOK); - cooldowns = - CacheBuilder.newBuilder() - .expireAfterWrite(COOLDOWN_MILISECONDS, TimeUnit.MILLISECONDS) - .build(); + cooldowns = CacheBuilder.newBuilder() + .expireAfterWrite(COOLDOWN_MILISECONDS, TimeUnit.MILLISECONDS) + .build(); } @Override @@ -60,14 +61,13 @@ public List getKits() { } public ItemStack getGrappleHook() { - ItemStack grapple = - new ItemBuilder() - .material(Material.FISHING_ROD) - .name(ChatColor.GREEN + "Grappling Hook") - .lore(ChatColor.GRAY + "Launch, anchor, conquer!") - .flags(ItemFlag.values()) - .unbreakable(true) - .build(); + ItemStack grapple = new ItemBuilder() + .material(Material.FISHING_ROD) + .name(ChatColor.GREEN + "Grappling Hook") + .lore(ChatColor.GRAY + "Launch, anchor, conquer!") + .flags(ItemFlag.values()) + .unbreakable(true) + .build(); ItemTags.PREVENT_SHARING.set(grapple, true); GRAPPLE_META_TAG.set(grapple, true); @@ -77,29 +77,32 @@ public ItemStack getGrappleHook() { @EventHandler(ignoreCancelled = true) public void onPlayerFishEvent(PlayerFishEvent event) { - if (!GRAPPLE_META_TAG.has(event.getPlayer().getItemInHand())) return; + Player player = event.getPlayer(); + if (!GRAPPLE_META_TAG.has(player.getItemInHand())) return; // Set the hooks meta if the player has thrown the line if (event.getState() == PlayerFishEvent.State.FISHING) { - event.getHook().setMetadata(GRAPPLE_META, new FixedMetadataValue(Community.get(), true)); + EVENT_UTILS + .getFishHook(event) + .setMetadata(GRAPPLE_META, new FixedMetadataValue(Community.get(), true)); } // Only pull the player when reeling back in if (!(event.getState() == PlayerFishEvent.State.IN_GROUND || event.getState() == PlayerFishEvent.State.FAILED_ATTEMPT)) return; - if (isPlayerOnCooldown(event.getPlayer())) return; + if (isPlayerOnCooldown(player)) return; // Calculate velocity to apply to player - Location hookLocation = event.getHook().getLocation(); - Location playerLocation = event.getPlayer().getLocation(); + Location hookLocation = EVENT_UTILS.getFishHook(event).getLocation(); + Location playerLocation = player.getLocation(); Vector direction = hookLocation.toVector().subtract(playerLocation.toVector()); direction.multiply(0.5).setY(1); - event.getPlayer().setVelocity(direction); - event.getPlayer().playSound(playerLocation, Sound.BAT_TAKEOFF, 2, 1.2f); + player.setVelocity(direction); + EFFECTS.batTakeoffSound(player); - cooldowns.put(event.getPlayer().getUniqueId(), Instant.now()); + cooldowns.put(player.getUniqueId(), Instant.now()); } @EventHandler(ignoreCancelled = true) diff --git a/core/src/main/java/dev/pgm/community/mutations/types/items/PotionMutation.java b/core/src/main/java/dev/pgm/community/mutations/types/items/PotionMutation.java index 667ca2d4..7a1b15ec 100644 --- a/core/src/main/java/dev/pgm/community/mutations/types/items/PotionMutation.java +++ b/core/src/main/java/dev/pgm/community/mutations/types/items/PotionMutation.java @@ -1,5 +1,7 @@ package dev.pgm.community.mutations.types.items; +import static dev.pgm.community.util.InventoryUtils.INVENTORY_UTILS; + import com.google.common.collect.Lists; import com.google.common.collect.Maps; import dev.pgm.community.Community; @@ -7,27 +9,18 @@ import dev.pgm.community.mutations.MutationType; import dev.pgm.community.mutations.types.KitMutationBase; import java.util.List; -import java.util.Random; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.entity.ThrownPotion; import org.bukkit.event.EventHandler; import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.potion.Potion; -import org.bukkit.potion.PotionType; import tc.oc.pgm.api.match.Match; import tc.oc.pgm.kits.ItemKit; import tc.oc.pgm.kits.Kit; import tc.oc.pgm.kits.tag.ItemTags; -import tc.oc.pgm.util.bukkit.BukkitUtils; /** PotionMutation - Random potions given on spawn and when mining blocks * */ public class PotionMutation extends KitMutationBase { @@ -65,30 +58,11 @@ private static Kit getRandomPotionKit() { } public static ItemStack getRandomPotionItem(boolean splash) { - return getPotionItem(getRandomPotion(splash)); - } - - private static ItemStack getPotionItem(Potion potion) { - ItemStack item = new ItemStack(Material.POTION); - potion.apply(item); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(BukkitUtils.colorize("&d&lMystery Potion")); - meta.addItemFlags(ItemFlag.values()); - item.setItemMeta(meta); + ItemStack item = INVENTORY_UTILS.getRandomPotion(splash, Community.get().getRandom()); ItemTags.PREVENT_SHARING.set(item, true); return item; } - private static Potion getRandomPotion(boolean splash) { - Random random = Community.get().getRandom(); - List safeTypes = - Stream.of(PotionType.values()) - .filter(p -> p != PotionType.WATER) // No water lol - .collect(Collectors.toList()); - PotionType randomType = safeTypes.get(random.nextInt(safeTypes.size())); - return new Potion(randomType, 1, splash); - } - @Override public boolean canEnable(Set existing) { return true; diff --git a/core/src/main/java/dev/pgm/community/mutations/types/mechanics/MobMutation.java b/core/src/main/java/dev/pgm/community/mutations/types/mechanics/MobMutation.java index 490f71c3..7df6708f 100644 --- a/core/src/main/java/dev/pgm/community/mutations/types/mechanics/MobMutation.java +++ b/core/src/main/java/dev/pgm/community/mutations/types/mechanics/MobMutation.java @@ -1,5 +1,7 @@ package dev.pgm.community.mutations.types.mechanics; +import static dev.pgm.community.util.Effects.EFFECTS; + import com.google.common.collect.Lists; import com.google.common.collect.Sets; import dev.pgm.community.Community; @@ -14,7 +16,6 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -150,7 +151,7 @@ public void run() { for (int total = getTotalSpawned(); total < TOTAL_MOBS.getValue(); total++) { Location loc = provider.getPoint(match, null); if (loc != null) { - loc.getWorld().spigot().playEffect(loc, Effect.FLAME, 0, 0, 0, 0, 0, 0, 5, 100); + EFFECTS.mobSpawnEffect(loc); spawnMob(loc, getRandomType()); } } diff --git a/core/src/main/java/dev/pgm/community/mutations/types/world/TNTRainMutation.java b/core/src/main/java/dev/pgm/community/mutations/types/world/TNTRainMutation.java index cb4326fc..bf06564d 100644 --- a/core/src/main/java/dev/pgm/community/mutations/types/world/TNTRainMutation.java +++ b/core/src/main/java/dev/pgm/community/mutations/types/world/TNTRainMutation.java @@ -1,5 +1,7 @@ package dev.pgm.community.mutations.types.world; +import static dev.pgm.community.util.Effects.EFFECTS; + import com.google.common.collect.Lists; import dev.pgm.community.Community; import dev.pgm.community.mutations.Mutation; @@ -7,7 +9,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; -import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.entity.Creature; import org.bukkit.entity.Entity; @@ -91,9 +92,7 @@ public void onTNTExplode(EntityExplodeEvent event) { .forEach(ent -> fakeKnockback(ent, tnt.getLocation())); } - tnt.getWorld() - .spigot() - .playEffect(tnt.getLocation(), Effect.LAVA_POP, 0, 0, 0, 0, 0, 1, 10, 50); + EFFECTS.tntRainExplode(tnt); } } } diff --git a/core/src/main/java/dev/pgm/community/nick/skin/SkinCache.java b/core/src/main/java/dev/pgm/community/nick/skin/SkinCache.java index 042467d9..2d3a97cb 100644 --- a/core/src/main/java/dev/pgm/community/nick/skin/SkinCache.java +++ b/core/src/main/java/dev/pgm/community/nick/skin/SkinCache.java @@ -1,5 +1,7 @@ package dev.pgm.community.nick.skin; +import static dev.pgm.community.util.PlayerUtils.PLAYER_UTILS; + import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Maps; @@ -12,7 +14,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.bukkit.Bukkit; -import org.bukkit.Skin; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -24,11 +25,14 @@ import tc.oc.pgm.api.event.NameDecorationChangeEvent; import tc.oc.pgm.api.integration.Integration; import tc.oc.pgm.api.player.MatchPlayer; +import tc.oc.pgm.util.skin.Skin; public class SkinCache implements Listener { - private final Cache offlineSkins = - CacheBuilder.newBuilder().maximumSize(500).expireAfterWrite(6, TimeUnit.HOURS).build(); + private final Cache offlineSkins = CacheBuilder.newBuilder() + .maximumSize(500) + .expireAfterWrite(6, TimeUnit.HOURS) + .build(); private final Random random = new Random(); private final Map customSkins = Maps.newHashMap(); @@ -58,7 +62,7 @@ private boolean canUseSkin(Player player) { public void onPlayerQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); if (canUseSkin(player)) { - offlineSkins.put(player.getUniqueId(), player.getSkin()); + offlineSkins.put(player.getUniqueId(), PLAYER_UTILS.getPlayerSkin(player)); } } @@ -84,10 +88,9 @@ private void refreshPlayer(Player player) { if (matchPlayer == null) return; // Update displayname - player.setDisplayName( - PGM.get() - .getNameDecorationRegistry() - .getDecoratedName(player, matchPlayer.getParty().getColor())); + player.setDisplayName(PGM.get() + .getNameDecorationRegistry() + .getDecoratedName(player, matchPlayer.getParty().getColor())); // for all other online players, refresh their views refreshAllViewers(player); @@ -107,24 +110,20 @@ private void refreshSelfView(Player viewer) { private void refreshFakeName(Player player, Player viewer) { boolean nicked = Integration.getNick(player) != null; boolean areFriends = Integration.isFriend(player, viewer); - boolean canOverride = - viewer.hasPermission(Permissions.STAFF) - || viewer.hasPermission(CommunityPermissions.NICKNAME_VIEW); + boolean canOverride = viewer.hasPermission(Permissions.STAFF) + || viewer.hasPermission(CommunityPermissions.NICKNAME_VIEW); boolean canSeeRealName = (canOverride || player == viewer || areFriends); if (nicked && !canSeeRealName) { String nick = Integration.getNick(player); MatchPlayer matchPlayer = PGM.get().getMatchManager().getPlayer(player); - String displayName = - PGM.get() - .getNameDecorationRegistry() - .getDecoratedName(player, matchPlayer.getParty().getColor()); - player.setFakeDisplayName(viewer, displayName); - player.setFakeNameAndSkin(viewer, nick, getSkin(player)); + String displayName = PGM.get() + .getNameDecorationRegistry() + .getDecoratedName(player, matchPlayer.getParty().getColor()); + PLAYER_UTILS.setFakeNameAndSkin(player, viewer, displayName, nick, getSkin(player)); } else { - player.setFakeDisplayName(viewer, null); - player.setFakeNameAndSkin(viewer, null, null); + PLAYER_UTILS.setFakeNameAndSkin(player, viewer, null, null, null); } } diff --git a/core/src/main/java/dev/pgm/community/nick/skin/SkinManager.java b/core/src/main/java/dev/pgm/community/nick/skin/SkinManager.java index c42634e9..406e52af 100644 --- a/core/src/main/java/dev/pgm/community/nick/skin/SkinManager.java +++ b/core/src/main/java/dev/pgm/community/nick/skin/SkinManager.java @@ -1,8 +1,8 @@ package dev.pgm.community.nick.skin; import dev.pgm.community.Community; -import org.bukkit.Skin; import org.bukkit.entity.Player; +import tc.oc.pgm.util.skin.Skin; public class SkinManager { diff --git a/core/src/main/java/dev/pgm/community/party/MapPartyCommands.java b/core/src/main/java/dev/pgm/community/party/MapPartyCommands.java index 9e3fa961..77b8434d 100644 --- a/core/src/main/java/dev/pgm/community/party/MapPartyCommands.java +++ b/core/src/main/java/dev/pgm/community/party/MapPartyCommands.java @@ -40,6 +40,7 @@ public void menu(CommandAudience viewer, Player sender) { new MapPartyMainMenu(party, sender); } else { if (isPartyMissing(viewer)) return; + party.sendPartyWelcome(sender); } } @@ -160,21 +161,18 @@ public void addHost(CommandAudience viewer, @Argument("targets") String targets) if (isPartyMissing(viewer)) return; MapPartyHosts hosts = party.getParty().getHosts(); PlayerSelection selection = getPlayers(viewer, targets); - selection - .getPlayers() - .forEach( - player -> { - if (!party.canHost(player)) { - viewer.sendWarning(MapPartyMessages.getAddHostError(player)); - return; - } - - if (hosts.isHost(player.getUniqueId())) { - viewer.sendWarning(MapPartyMessages.getExistingHostError(player)); - return; - } - hosts.addSubHost(player); - }); + selection.getPlayers().forEach(player -> { + if (!party.canHost(player)) { + viewer.sendWarning(MapPartyMessages.getAddHostError(player)); + return; + } + + if (hosts.isHost(player.getUniqueId())) { + viewer.sendWarning(MapPartyMessages.getExistingHostError(player)); + return; + } + hosts.addSubHost(player); + }); } @Command("hosts remove ") @@ -183,11 +181,10 @@ public void removeHost(CommandAudience viewer, @Argument("target") TargetPlayer if (isPartyMissing(viewer)) return; MapPartyHosts hosts = party.getParty().getHosts(); if (!hosts.removeSubHost(target.getIdentifier())) { - viewer.sendWarning( - text() - .append(text(target.getIdentifier(), NamedTextColor.DARK_AQUA)) - .append(text(" is not a party host")) - .build()); + viewer.sendWarning(text() + .append(text(target.getIdentifier(), NamedTextColor.DARK_AQUA)) + .append(text(" is not a party host")) + .build()); } } @@ -204,11 +201,10 @@ public void transferHost(CommandAudience viewer, @Argument("target") Player targ } if (hosts.isMainHost(target.getUniqueId())) { - viewer.sendWarning( - text() - .append(player(target, NameStyle.FANCY)) - .append(text(" is already the main party host")) - .build()); + viewer.sendWarning(text() + .append(player(target, NameStyle.FANCY)) + .append(text(" is already the main party host")) + .build()); return; } diff --git a/core/src/main/java/dev/pgm/community/party/settings/MapPartySettings.java b/core/src/main/java/dev/pgm/community/party/settings/MapPartySettings.java index fb887c50..839e8054 100644 --- a/core/src/main/java/dev/pgm/community/party/settings/MapPartySettings.java +++ b/core/src/main/java/dev/pgm/community/party/settings/MapPartySettings.java @@ -15,7 +15,7 @@ public MapPartySettings(MapPartyConfig config) { "Login Message", "Display a login welcome when party is active", config.showLoginMessage(), - Material.SIGN, + Materials.SIGN, Material.BARRIER); this.showPartyNotifications = new PartyBooleanSetting( "Notification", diff --git a/core/src/main/java/dev/pgm/community/users/listeners/UserProfileLoginListener.java b/core/src/main/java/dev/pgm/community/users/listeners/UserProfileLoginListener.java index 69703137..c1495138 100644 --- a/core/src/main/java/dev/pgm/community/users/listeners/UserProfileLoginListener.java +++ b/core/src/main/java/dev/pgm/community/users/listeners/UserProfileLoginListener.java @@ -11,6 +11,8 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; +import tc.oc.pgm.util.Audience; +import tc.oc.pgm.util.text.TextParser; public class UserProfileLoginListener implements Listener { @@ -33,24 +35,20 @@ public void onPostLoginEvent(UserProfileLoadEvent event) { // Custom messages / commands executed when joins server for the first time if (event.getUser().getJoinCount() <= 1) { - config - .getFirstJoinCommands() - .forEach( - command -> { - command = - command - .replace("%uuid%", player.getUniqueId().toString()) - .replace("%name%", player.getName()); - boolean message = command.startsWith("!send"); - if (message) { - String msg = command.substring(5, command.length()); - player.sendMessage(MessageUtils.format(msg)); - } else { - Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command); - Community.log( - "&7First join command (&6%s&7) executed for &b%s", command, player.getName()); - } - }); + config.getFirstJoinCommands().forEach(command -> { + command = command + .replace("%uuid%", player.getUniqueId().toString()) + .replace("%name%", player.getName()); + boolean message = command.startsWith("!send"); + if (message) { + String msg = command.substring(5, command.length()); + Audience.get(player).sendMessage(TextParser.parseComponent(MessageUtils.format(msg))); + } else { + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command); + Community.log( + "&7First join command (&6%s&7) executed for &b%s", command, player.getName()); + } + }); } } } diff --git a/core/src/main/java/dev/pgm/community/utils/WebUtils.java b/core/src/main/java/dev/pgm/community/utils/WebUtils.java index 41d55ee5..4c8d271d 100644 --- a/core/src/main/java/dev/pgm/community/utils/WebUtils.java +++ b/core/src/main/java/dev/pgm/community/utils/WebUtils.java @@ -17,8 +17,8 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import org.bukkit.Skin; import org.jetbrains.annotations.Nullable; +import tc.oc.pgm.util.skin.Skin; public class WebUtils { diff --git a/core/src/main/java/dev/pgm/community/utils/compatibility/Enchantments.java b/core/src/main/java/dev/pgm/community/utils/compatibility/Enchantments.java index fa14a44b..35028d4b 100644 --- a/core/src/main/java/dev/pgm/community/utils/compatibility/Enchantments.java +++ b/core/src/main/java/dev/pgm/community/utils/compatibility/Enchantments.java @@ -6,6 +6,7 @@ public interface Enchantments { Enchantment INFINITY = parse("ARROW_INFINITE", "infinity"); Enchantment LUCK_OF_THE_SEA = parse("LUCK", "luck_of_the_sea"); + Enchantment SHARPNESS = parse("DAMAGE_ALL", "sharpness"); private static Enchantment parse(String... names) { return BukkitUtils.parse(Enchantment::getByName, names); diff --git a/platform/platform-modern/build.gradle.kts b/platform/platform-modern/build.gradle.kts new file mode 100644 index 00000000..20311202 --- /dev/null +++ b/platform/platform-modern/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("buildlogic.java-conventions") + id("io.papermc.paperweight.userdev") version "1.7.4" +} + +dependencies { + implementation(project(":util")) + paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT") +} + +paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION diff --git a/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEffects.java b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEffects.java new file mode 100644 index 00000000..1ae4e348 --- /dev/null +++ b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEffects.java @@ -0,0 +1,37 @@ +package dev.pgm.community.platform.modern; + +import static dev.pgm.community.util.Supports.Variant.PAPER; + +import dev.pgm.community.util.Effects; +import dev.pgm.community.util.Supports; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; + +@Supports(value = PAPER, minVersion = "1.20.6") +public class ModernEffects implements Effects { + @Override + public void dummy() {} + + @Override + public void tntRainExplode(TNTPrimed tnt) { + tnt.getWorld().spawnParticle(Particle.LAVA, tnt.getLocation(), 10, 1); + } + + @Override + public void mobSpawnEffect(Location loc) { + loc.getWorld().spawnParticle(Particle.FLAME, loc, 10, 1); + } + + @Override + public void explosionEffect(Location loc) { + loc.getWorld().spawnParticle(Particle.LAVA, loc, 15); + } + + @Override + public void batTakeoffSound(Player player) { + player.playSound(player.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 2, 1.2f); + } +} diff --git a/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEntityUtils.java b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEntityUtils.java new file mode 100644 index 00000000..6e8bd1d7 --- /dev/null +++ b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEntityUtils.java @@ -0,0 +1,24 @@ +package dev.pgm.community.platform.modern; + +import static dev.pgm.community.util.Supports.Variant.PAPER; + +import dev.pgm.community.util.EntityUtils; +import dev.pgm.community.util.Supports; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PathfinderMob; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.entity.LivingEntity; + +@Supports(value = PAPER, minVersion = "1.20.6") +public class ModernEntityUtils implements EntityUtils { + @Override + public void follow(LivingEntity mob, Location location, float speed) { + Entity handle = ((CraftEntity) mob).getHandle(); + if (handle instanceof PathfinderMob pathfinderMob) { + pathfinderMob + .getNavigation() + .moveTo(location.getX(), location.getY(), location.getZ(), speed); + } + } +} diff --git a/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEventUtils.java b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEventUtils.java new file mode 100644 index 00000000..1f8ddaf8 --- /dev/null +++ b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernEventUtils.java @@ -0,0 +1,16 @@ +package dev.pgm.community.platform.modern; + +import static dev.pgm.community.util.Supports.Variant.PAPER; + +import dev.pgm.community.util.EventUtils; +import dev.pgm.community.util.Supports; +import org.bukkit.entity.FishHook; +import org.bukkit.event.player.PlayerFishEvent; + +@Supports(value = PAPER, minVersion = "1.20.6") +public class ModernEventUtils implements EventUtils { + @Override + public FishHook getFishHook(PlayerFishEvent fishEvent) { + return fishEvent.getHook(); + } +} diff --git a/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernInventoryUtils.java b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernInventoryUtils.java new file mode 100644 index 00000000..2b6bda4b --- /dev/null +++ b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernInventoryUtils.java @@ -0,0 +1,51 @@ +package dev.pgm.community.platform.modern; + +import static dev.pgm.community.util.Supports.Variant.PAPER; + +import dev.pgm.community.util.InventoryUtils; +import dev.pgm.community.util.Supports; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionType; +import tc.oc.pgm.kits.tag.ItemTags; +import tc.oc.pgm.util.bukkit.BukkitUtils; + +@Supports(value = PAPER, minVersion = "1.20.6") +public class ModernInventoryUtils implements InventoryUtils { + @Override + public void addAttributeModifier(ItemMeta meta, Attribute attribute, AttributeModifier modifier) { + meta.addAttributeModifier(attribute, modifier); + } + + @Override + public ItemStack getRandomPotion(boolean splash, Random random) { + List safeTypes = Stream.of(PotionType.values()) + .filter(p -> switch (p) { + case WATER, MUNDANE, THICK, AWKWARD, WEAVING, OOZING, INFESTED -> false; + default -> true; + }) + .collect(Collectors.toList()); + PotionType randomType = safeTypes.get(random.nextInt(safeTypes.size())); + ItemStack item = new ItemStack(splash ? Material.SPLASH_POTION : Material.POTION); + if (item.getItemMeta() instanceof PotionMeta meta) { + meta.setBasePotionType(randomType); + item.setItemMeta(meta); + } + + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName(BukkitUtils.colorize("&d&lMystery Potion")); + meta.addItemFlags(ItemFlag.values()); + item.setItemMeta(meta); + ItemTags.PREVENT_SHARING.set(item, true); + return item; + } +} diff --git a/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernPlatform.java b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernPlatform.java new file mode 100644 index 00000000..36d2e795 --- /dev/null +++ b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernPlatform.java @@ -0,0 +1,16 @@ +package dev.pgm.community.platform.modern; + +import static dev.pgm.community.util.Supports.Priority.HIGHEST; +import static dev.pgm.community.util.Supports.Variant.PAPER; + +import dev.pgm.community.util.Platform; +import dev.pgm.community.util.Supports; +import org.bukkit.plugin.Plugin; + +@Supports(value = PAPER, minVersion = "1.20.6", priority = HIGHEST) +public class ModernPlatform implements Platform.Manifest { + @Override + public void onEnable(Plugin plugin) { + new PacketManipulations(plugin); + } +} diff --git a/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernPlayerUtils.java b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernPlayerUtils.java new file mode 100644 index 00000000..b2eb37ec --- /dev/null +++ b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/ModernPlayerUtils.java @@ -0,0 +1,74 @@ +package dev.pgm.community.platform.modern; + +import static dev.pgm.community.util.Supports.Variant.PAPER; + +import dev.pgm.community.util.PlayerUtils; +import dev.pgm.community.util.Supports; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import tc.oc.pgm.platform.modern.util.Skins; +import tc.oc.pgm.util.skin.Skin; + +@Supports(value = PAPER, minVersion = "1.20.6") +public class ModernPlayerUtils implements PlayerUtils { + @Override + public Skin getPlayerSkin(Player player) { + CraftPlayer craftPlayer = (CraftPlayer) player; + return Skins.fromProfile(craftPlayer.getProfile()); + } + + private final Map> playerSkins = new HashMap<>(); + private final Map> playerNames = new HashMap<>(); + private final Map> playerDisplayNames = new HashMap<>(); + + @Override + public void setFakeNameAndSkin( + Player player, Player viewer, String displayName, String nick, Skin skin) { + playerSkins + .computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()) + .put(viewer.getUniqueId(), skin); + playerNames + .computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()) + .put(viewer.getUniqueId(), nick); + playerDisplayNames + .computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()) + .put(viewer.getUniqueId(), displayName); + } + + @Override + public String getPlayerDisplayName(Player player, Player viewer) { + if (playerDisplayNames.containsKey(player.getUniqueId())) { + Map uuidStringMap = playerDisplayNames.get(player.getUniqueId()); + String displayName = uuidStringMap.get(viewer.getUniqueId()); + return displayName == null ? player.getDisplayName() : displayName; + } + return player.getDisplayName(); + } + + @Override + public String getPlayerName(Player player, Player viewer) { + if (playerNames.containsKey(player.getUniqueId())) { + Map uuidStringMap = playerNames.get(player.getUniqueId()); + String name = uuidStringMap.get(viewer.getUniqueId()); + return name == null ? player.getName() : name; + } + return player.getName(); + } + + @Override + public Skin getPlayerSkin(Player player, Player viewer) { + return null; + // if (playerSkins.containsKey(player.getUniqueId())) { + // Map uuidSkinMap = playerSkins.get(player.getUniqueId()); + // Skin skin = uuidSkinMap.get(viewer.getUniqueId()); + // if (skin == null) { + // return new Skin(player.getPlayerProfile().getTextures()) + // } + // return skin == null ? Skin.EMPTY : skin; + // } + // return Skin.EMPTY; + } +} diff --git a/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/PacketManipulations.java b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/PacketManipulations.java new file mode 100644 index 00000000..f8d2824f --- /dev/null +++ b/platform/platform-modern/src/main/java/dev/pgm/community/platform/modern/PacketManipulations.java @@ -0,0 +1,70 @@ +package dev.pgm.community.platform.modern; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.wrappers.EnumWrappers; +import com.comphenix.protocol.wrappers.PlayerInfoData; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import dev.pgm.community.util.PlayerUtils; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import tc.oc.pgm.platform.modern.packets.PacketSender; +import tc.oc.pgm.platform.modern.util.Packets; + +public class PacketManipulations implements PacketSender { + + public PacketManipulations(Plugin plugin) { + Packets.register( + plugin, + ListenerPriority.LOWEST, + Map.of(PacketType.Play.Server.PLAYER_INFO, this::handlePlayerInfo)); + } + + private void handlePlayerInfo(PacketEvent event) { + Player viewer = event.getPlayer(); + + if (event + .getPacket() + .getPlayerInfoActions() + .read(0) + .contains(EnumWrappers.PlayerInfoAction.ADD_PLAYER)) { + List infoList = event.getPacket().getPlayerInfoDataLists().read(1); + event + .getPacket() + .getPlayerInfoDataLists() + .write( + 1, + infoList.stream() + .map((playerInfoData -> { + UUID playerId = playerInfoData.getProfileId(); + Player player = Bukkit.getPlayer(playerId); + if (player == null || player.equals(viewer) || !player.isOnline()) { + return playerInfoData; + } + + String playerDisplayName = + PlayerUtils.PLAYER_UTILS.getPlayerDisplayName(player, viewer); + String playerName = PlayerUtils.PLAYER_UTILS.getPlayerName(player, viewer); + + if (StringUtils.isBlank(playerName) || StringUtils.isBlank(playerDisplayName)) { + return playerInfoData; + } + + return new PlayerInfoData( + playerId, + playerInfoData.getLatency(), + playerInfoData.isListed(), + playerInfoData.getGameMode(), + playerInfoData.getProfile().withName(playerName), + WrappedChatComponent.fromLegacyText(playerDisplayName)); + })) + .toList()); + } + } +} diff --git a/platform/platform-sportpaper/build.gradle.kts b/platform/platform-sportpaper/build.gradle.kts new file mode 100644 index 00000000..6af8a21a --- /dev/null +++ b/platform/platform-sportpaper/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + id("buildlogic.java-conventions") +} + +dependencies { + implementation(project(":util")) + compileOnly("app.ashcon:sportpaper:1.8.8-R0.1-SNAPSHOT") +} diff --git a/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEffects.java b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEffects.java new file mode 100644 index 00000000..3c2c3b6e --- /dev/null +++ b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEffects.java @@ -0,0 +1,39 @@ +package dev.pgm.community.platform.sportpaper; + +import static dev.pgm.community.util.Supports.Variant.SPORTPAPER; + +import dev.pgm.community.util.Effects; +import dev.pgm.community.util.Supports; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; + +@Supports(SPORTPAPER) +public class SpEffects implements Effects { + @Override + public void dummy() {} + + @Override + public void tntRainExplode(TNTPrimed tnt) { + tnt.getWorld() + .spigot() + .playEffect(tnt.getLocation(), Effect.LAVA_POP, 0, 0, 0, 0, 0, 1, 10, 50); + } + + @Override + public void mobSpawnEffect(Location loc) { + loc.getWorld().spigot().playEffect(loc, Effect.FLAME, 0, 0, 0, 0, 0, 0, 5, 100); + } + + @Override + public void explosionEffect(Location loc) { + loc.getWorld().spigot().playEffect(loc, Effect.LAVA_POP, 0, 0, 0, 0, 0, 0, 15, 50); + } + + @Override + public void batTakeoffSound(Player player) { + player.playSound(player.getLocation(), Sound.BAT_TAKEOFF, 2, 1.2f); + } +} diff --git a/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEntityUtils.java b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEntityUtils.java new file mode 100644 index 00000000..a14fcca8 --- /dev/null +++ b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEntityUtils.java @@ -0,0 +1,19 @@ +package dev.pgm.community.platform.sportpaper; + +import static dev.pgm.community.util.Supports.Variant.SPORTPAPER; + +import dev.pgm.community.util.EntityUtils; +import dev.pgm.community.util.Supports; +import net.minecraft.server.v1_8_R3.EntityInsentient; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; +import org.bukkit.entity.LivingEntity; + +@Supports(SPORTPAPER) +public class SpEntityUtils implements EntityUtils { + @Override + public void follow(LivingEntity mob, Location location, float speed) { + EntityInsentient nmsMob = ((EntityInsentient) ((CraftEntity) mob).getHandle()); + nmsMob.getNavigation().a(location.getX(), location.getY(), location.getZ(), speed); + } +} diff --git a/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEventUtils.java b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEventUtils.java new file mode 100644 index 00000000..e2a36dac --- /dev/null +++ b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpEventUtils.java @@ -0,0 +1,16 @@ +package dev.pgm.community.platform.sportpaper; + +import static dev.pgm.community.util.Supports.Variant.SPORTPAPER; + +import dev.pgm.community.util.EventUtils; +import dev.pgm.community.util.Supports; +import org.bukkit.entity.FishHook; +import org.bukkit.event.player.PlayerFishEvent; + +@Supports(SPORTPAPER) +public class SpEventUtils implements EventUtils { + @Override + public FishHook getFishHook(PlayerFishEvent fishEvent) { + return fishEvent.getHook(); + } +} diff --git a/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpInventoryUtils.java b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpInventoryUtils.java new file mode 100644 index 00000000..c2c865aa --- /dev/null +++ b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpInventoryUtils.java @@ -0,0 +1,45 @@ +package dev.pgm.community.platform.sportpaper; + +import static dev.pgm.community.util.Supports.Variant.SPORTPAPER; + +import dev.pgm.community.util.InventoryUtils; +import dev.pgm.community.util.Supports; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.potion.Potion; +import org.bukkit.potion.PotionType; +import tc.oc.pgm.kits.tag.ItemTags; +import tc.oc.pgm.util.bukkit.BukkitUtils; + +@Supports(SPORTPAPER) +public class SpInventoryUtils implements InventoryUtils { + @Override + public void addAttributeModifier(ItemMeta meta, Attribute attribute, AttributeModifier modifier) { + meta.addAttributeModifier(attribute, modifier); + } + + @Override + public ItemStack getRandomPotion(boolean splash, Random random) { + List safeTypes = Stream.of(PotionType.values()) + .filter(p -> p != PotionType.WATER) // No water lol + .collect(Collectors.toList()); + PotionType randomType = safeTypes.get(random.nextInt(safeTypes.size())); + Potion potion = new Potion(randomType, 1, splash); + ItemStack item = new ItemStack(Material.POTION); + potion.apply(item); + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName(BukkitUtils.colorize("&d&lMystery Potion")); + meta.addItemFlags(ItemFlag.values()); + item.setItemMeta(meta); + ItemTags.PREVENT_SHARING.set(item, true); + return item; + } +} diff --git a/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpPlatform.java b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpPlatform.java new file mode 100644 index 00000000..ffe9a911 --- /dev/null +++ b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpPlatform.java @@ -0,0 +1,14 @@ +package dev.pgm.community.platform.sportpaper; + +import static dev.pgm.community.util.Supports.Priority.HIGHEST; +import static dev.pgm.community.util.Supports.Variant.SPORTPAPER; + +import dev.pgm.community.util.Platform; +import dev.pgm.community.util.Supports; +import org.bukkit.plugin.Plugin; + +@Supports(value = SPORTPAPER, priority = HIGHEST) +public class SpPlatform implements Platform.Manifest { + @Override + public void onEnable(Plugin plugin) {} +} diff --git a/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpPlayerUtils.java b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpPlayerUtils.java new file mode 100644 index 00000000..b6568aaa --- /dev/null +++ b/platform/platform-sportpaper/src/main/java/dev/pgm/community/platform/sportpaper/SpPlayerUtils.java @@ -0,0 +1,43 @@ +package dev.pgm.community.platform.sportpaper; + +import static dev.pgm.community.util.Supports.Variant.SPORTPAPER; + +import dev.pgm.community.util.PlayerUtils; +import dev.pgm.community.util.Supports; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; +import tc.oc.pgm.platform.sportpaper.utils.Skins; +import tc.oc.pgm.util.skin.Skin; + +@Supports(SPORTPAPER) +public class SpPlayerUtils implements PlayerUtils { + + @Override + public Skin getPlayerSkin(Player player) { + CraftPlayer craftPlayer = (CraftPlayer) player; + return Skins.fromProfile(craftPlayer.getProfile()); + } + + @Override + public void setFakeNameAndSkin( + Player player, Player viewer, String displayName, String nick, Skin skin) { + player.setFakeDisplayName(viewer, displayName); + player.setFakeNameAndSkin(viewer, nick, player.getSkin(viewer)); + } + + @Override + public String getPlayerDisplayName(Player player, Player viewer) { + return player.getDisplayName(viewer); + } + + @Override + public String getPlayerName(Player player, Player viewer) { + return player.getName(viewer); + } + + @Override + public Skin getPlayerSkin(Player player, Player viewer) { + org.bukkit.Skin skin = player.getSkin(viewer); + return new Skin(skin.getData(), skin.getSignature()); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index f8c25375..aa316d5d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,9 @@ rootProject.name = "community" +include(":util") +include(":platform-sportpaper") +include(":platform-modern") include(":core") + +project(":platform-sportpaper").projectDir = file("platform/platform-sportpaper") +project(":platform-modern").projectDir = file("platform/platform-modern") \ No newline at end of file diff --git a/util/build.gradle.kts b/util/build.gradle.kts new file mode 100644 index 00000000..c9152201 --- /dev/null +++ b/util/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("buildlogic.java-conventions") +} + +dependencies { + compileOnly("dev.pgm.paper:paper-api:1.8_1.21.1-SNAPSHOT") +} \ No newline at end of file diff --git a/util/src/main/java/dev/pgm/community/util/Effects.java b/util/src/main/java/dev/pgm/community/util/Effects.java new file mode 100644 index 00000000..8a4c31c5 --- /dev/null +++ b/util/src/main/java/dev/pgm/community/util/Effects.java @@ -0,0 +1,19 @@ +package dev.pgm.community.util; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; + +public interface Effects { + Effects EFFECTS = Platform.get(Effects.class); + + void dummy(); + + void tntRainExplode(TNTPrimed tnt); + + void mobSpawnEffect(Location loc); + + void explosionEffect(Location loc); + + void batTakeoffSound(Player player); +} diff --git a/util/src/main/java/dev/pgm/community/util/EntityUtils.java b/util/src/main/java/dev/pgm/community/util/EntityUtils.java new file mode 100644 index 00000000..46885b19 --- /dev/null +++ b/util/src/main/java/dev/pgm/community/util/EntityUtils.java @@ -0,0 +1,10 @@ +package dev.pgm.community.util; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; + +public interface EntityUtils { + EntityUtils ENTITY_UTILS = Platform.get(EntityUtils.class); + + void follow(LivingEntity mob, Location location, float speed); +} diff --git a/util/src/main/java/dev/pgm/community/util/EventUtils.java b/util/src/main/java/dev/pgm/community/util/EventUtils.java new file mode 100644 index 00000000..6166f9d3 --- /dev/null +++ b/util/src/main/java/dev/pgm/community/util/EventUtils.java @@ -0,0 +1,10 @@ +package dev.pgm.community.util; + +import org.bukkit.entity.FishHook; +import org.bukkit.event.player.PlayerFishEvent; + +public interface EventUtils { + EventUtils EVENT_UTILS = Platform.get(EventUtils.class); + + FishHook getFishHook(PlayerFishEvent fishEvent); +} diff --git a/util/src/main/java/dev/pgm/community/util/InventoryUtils.java b/util/src/main/java/dev/pgm/community/util/InventoryUtils.java new file mode 100644 index 00000000..cb043cdb --- /dev/null +++ b/util/src/main/java/dev/pgm/community/util/InventoryUtils.java @@ -0,0 +1,15 @@ +package dev.pgm.community.util; + +import java.util.Random; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public interface InventoryUtils { + InventoryUtils INVENTORY_UTILS = Platform.get(InventoryUtils.class); + + void addAttributeModifier(ItemMeta meta, Attribute attribute, AttributeModifier modifier); + + ItemStack getRandomPotion(boolean splash, Random random); +} diff --git a/util/src/main/java/dev/pgm/community/util/Platform.java b/util/src/main/java/dev/pgm/community/util/Platform.java new file mode 100644 index 00000000..b922044f --- /dev/null +++ b/util/src/main/java/dev/pgm/community/util/Platform.java @@ -0,0 +1,85 @@ +package dev.pgm.community.util; + +import static org.reflections.scanners.Scanners.TypesAnnotated; + +import dev.pgm.community.util.Supports.Variant; +import java.util.Arrays; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.reflections.Reflections; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; +import tc.oc.pgm.util.Version; +import tc.oc.pgm.util.reflect.ReflectionUtils; +import tc.oc.pgm.util.text.TextParser; + +@SuppressWarnings("unchecked") +public abstract class Platform { + private static final Reflections REFLECTIONS = new Reflections(new ConfigurationBuilder() + .addUrls(ClasspathHelper.forPackage("dev.pgm.community", Platform.class.getClassLoader())) + .forPackage("dev.pgm.community.platform") + .setScanners(TypesAnnotated)); + + public static final Version MINECRAFT_VERSION; + public static final Variant VARIANT; + + static { + var sv = Bukkit.getServer(); + MINECRAFT_VERSION = TextParser.parseVersion(sv.getBukkitVersion().split("-")[0]); + VARIANT = Arrays.stream(Supports.Variant.values()) + .filter(v -> v.matcher.test(sv)) + .findFirst() + .orElse(null); + } + + public static final @NotNull Manifest MANIFEST = get(Manifest.class); + + /** + * Do a minimum sanity-check of the platform's viability and early-load some codepaths + * + * @throws Throwable could throw even class not found issues if loading in the wrong version + */ + public static void init() throws Throwable { + Effects.EFFECTS.dummy(); + } + + public static @NotNull T get(Class clazz) { + return (T) Platform.getBestSupported(clazz); + } + + private static Iterable> getSupported(Class parent) { + return REFLECTIONS.get(TypesAnnotated.with(Supports.class, Supports.List.class) + .asClass() + .filter(parent::isAssignableFrom)); + } + + private static Object getBestSupported(Class parent) { + Class result = null; + Supports.Priority priority = null; + for (Class clazz : getSupported(parent)) { + Supports[] supportList = clazz.getDeclaredAnnotationsByType(Supports.class); + for (Supports sup : supportList) { + if (VARIANT != sup.value()) continue; + if (!sup.minVersion().isEmpty() + && MINECRAFT_VERSION.isOlderThan(TextParser.parseVersion(sup.minVersion()))) continue; + if (!sup.maxVersion().isEmpty() + && TextParser.parseVersion(sup.maxVersion()).isOlderThan(MINECRAFT_VERSION)) continue; + + if (priority == null || priority.compareTo(sup.priority()) < 0) { + priority = sup.priority(); + result = clazz; + } + } + } + if (result == null) + throw new UnsupportedOperationException( + "Current server software platform does not have an impl for: " + parent.getSimpleName()); + + return ReflectionUtils.callConstructor(ReflectionUtils.getConstructor(result)); + } + + public interface Manifest { + void onEnable(Plugin plugin); + } +} diff --git a/util/src/main/java/dev/pgm/community/util/PlayerUtils.java b/util/src/main/java/dev/pgm/community/util/PlayerUtils.java new file mode 100644 index 00000000..aa797659 --- /dev/null +++ b/util/src/main/java/dev/pgm/community/util/PlayerUtils.java @@ -0,0 +1,18 @@ +package dev.pgm.community.util; + +import org.bukkit.entity.Player; +import tc.oc.pgm.util.skin.Skin; + +public interface PlayerUtils { + PlayerUtils PLAYER_UTILS = Platform.get(PlayerUtils.class); + + Skin getPlayerSkin(Player player); + + void setFakeNameAndSkin(Player player, Player viewer, String displayName, String nick, Skin skin); + + String getPlayerDisplayName(Player player, Player viewer); + + String getPlayerName(Player player, Player viewer); + + Skin getPlayerSkin(Player player, Player viewer); +} diff --git a/util/src/main/java/dev/pgm/community/util/Supports.java b/util/src/main/java/dev/pgm/community/util/Supports.java new file mode 100644 index 00000000..8a563d9e --- /dev/null +++ b/util/src/main/java/dev/pgm/community/util/Supports.java @@ -0,0 +1,43 @@ +package dev.pgm.community.util; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.function.Predicate; +import org.bukkit.Server; + +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(Supports.List.class) +public @interface Supports { + Supports.Variant value(); + + String minVersion() default ""; + + String maxVersion() default ""; + + Supports.Priority priority() default Supports.Priority.MEDIUM; + + enum Variant { + SPORTPAPER(sv -> sv.getVersion().contains("SportPaper")), + PAPER(sv -> sv.getName().equalsIgnoreCase("Paper")); + + public final Predicate matcher; + + Variant(Predicate matches) { + this.matcher = matches; + } + } + + enum Priority { + LOWEST, + LOW, + MEDIUM, + HIGH, + HIGHEST + } + + @Retention(RetentionPolicy.RUNTIME) + @interface List { + Supports[] value(); + } +}