diff --git a/build.gradle.kts b/build.gradle.kts index 554834a5..b7962048 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -97,6 +97,7 @@ dependencies { implementation(project(path = ":v1_19_R2", configuration = "reobf")) implementation(project(path = ":v1_19_R3", configuration = "reobf")) implementation(project(path = ":v1_20_R1", configuration = "reobf")) + implementation(project(path = ":v1_20_R2", configuration = "reobf")) //compileOnly("com.github.Fisher2911:FisherLib:master-SNAPSHOT") implementation("net.kyori:adventure-api:4.11.0") @@ -129,7 +130,7 @@ tasks { } runServer { - minecraftVersion("1.20.1") + minecraftVersion("1.20.2") } shadowJar { @@ -138,6 +139,7 @@ tasks { dependsOn(":v1_19_R2:reobfJar") dependsOn(":v1_19_R3:reobfJar") dependsOn(":v1_20_R1:reobfJar") + dependsOn(":v1_20_R2:reobfJar") mergeServiceFiles() relocate("dev.triumphteam.gui", "com.hisbiscusmc.hmccosmetics.gui") diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/HMCCosmeticsPlugin.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/HMCCosmeticsPlugin.java index 12e5e076..19a8f333 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/HMCCosmeticsPlugin.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/HMCCosmeticsPlugin.java @@ -98,7 +98,7 @@ public final class HMCCosmeticsPlugin extends JavaPlugin { if (!emoteFile.exists()) emoteFile.mkdir(); // Player Animator - PlayerAnimatorImpl.initialize(this); + if (Settings.isEmotesEnabled() && !NMSHandlers.getVersion().contains("v1_20_R2")) PlayerAnimatorImpl.initialize(this); // PlayerAnimator does not support 1.20.2 yet // Configuration Sync final File configFile = Path.of(getInstance().getDataFolder().getPath(), "config.yml").toFile(); @@ -252,7 +252,7 @@ public final class HMCCosmeticsPlugin extends JavaPlugin { } } - EmoteManager.loadEmotes(); + if (Settings.isEmotesEnabled() && !NMSHandlers.getVersion().contains("v1_20_R2")) EmoteManager.loadEmotes(); // PlayerAnimator does not support 1.20.2 yet getInstance().getLogger().info("Successfully Enabled HMCCosmetics"); getInstance().getLogger().info(Cosmetics.values().size() + " Cosmetics Successfully Setup"); diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/config/Settings.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/config/Settings.java index 95a82d3f..91ad46a0 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/config/Settings.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/config/Settings.java @@ -33,6 +33,7 @@ public class Settings { private static final String HOOK_WORLDGUARD_PATH = "worldguard"; private static final String HOOK_WG_MOVE_CHECK_PATH = "player-move-check"; private static final String HOOK_WG_MOVE_CHECK_PATH_LEGACY = "player_move_check"; + private static final String COSMETIC_EMOTE_ENABLE = "emote-enable"; private static final String COSMETIC_EMOTE_CHECK_PATH = "emote-block-check"; private static final String COSMETIC_EMOTE_AIR_CHECK_PATH = "emote-air-check"; private static final String COSMETIC_EMOTE_DAMAGE_PATH = "emote-damage-leave"; @@ -107,6 +108,8 @@ public class Settings { @Getter private static boolean cosmeticForceOffhandCosmeticShow; @Getter + private static boolean emotesEnabled; + @Getter private static int viewDistance; @Getter private static int tickPeriod; @@ -164,6 +167,7 @@ public class Settings { unapplyOnDeath = cosmeticSettings.node(UNAPPLY_DEATH_PATH).getBoolean(false); forcePermissionJoin = cosmeticSettings.node(FORCE_PERMISSION_JOIN_PATH).getBoolean(false); forceShowOnJoin = cosmeticSettings.node(FORCE_SHOW_COSMETICS_PATH).getBoolean(false); + emotesEnabled = cosmeticSettings.node(COSMETIC_EMOTE_ENABLE).getBoolean(true); emoteDistance = cosmeticSettings.node(EMOTE_DISTANCE_PATH).getDouble(-3); cosmeticEmoteBlockCheck = cosmeticSettings.node(COSMETIC_EMOTE_CHECK_PATH).getBoolean(true); emoteAirCheck = cosmeticSettings.node(COSMETIC_EMOTE_AIR_CHECK_PATH).getBoolean(true); diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/nms/NMSHandlers.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/nms/NMSHandlers.java index c5edb863..60aab9bd 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/nms/NMSHandlers.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/nms/NMSHandlers.java @@ -9,7 +9,7 @@ import java.util.logging.Level; public class NMSHandlers { - private static final String[] SUPPORTED_VERSION = new String[]{"v1_18_R2", "v1_19_R1", "v1_19_R2", "v1_19_R3", "v1_20_R1"}; + private static final String[] SUPPORTED_VERSION = new String[]{"v1_18_R2", "v1_19_R1", "v1_19_R2", "v1_19_R3", "v1_20_R1", "v1_20_R2"}; private static NMSHandler handler; @Getter private static String version; diff --git a/common/src/main/resources/config.yml b/common/src/main/resources/config.yml index 28f6c829..34c5a1d0 100644 --- a/common/src/main/resources/config.yml +++ b/common/src/main/resources/config.yml @@ -24,6 +24,8 @@ cosmetic-settings: force-permission-join: true # Checks a player permission if they can have a cosmetic when they join the server. force-show-join: false # If the plugin should force show a player's cosmetics when they join the server. + # This disables the entire internal emote system within the plugin. This option requires a restart. + emote-enable: true emote-distance: -3 # This shows how far away the camera should be while a player is doing an emote. Negative is behind player. emote-block-check: true # If the server should check if the block is open where the camera is placed (prevents players viewing through blocks) emote-air-check: true # Check if there is air under a player, if there is, don't play emote diff --git a/settings.gradle.kts b/settings.gradle.kts index b23a5056..1a7658e9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,4 +13,5 @@ include( "v1_19_R2", "v1_19_R3", "v1_20_R1", + "v1_20_R2" ) diff --git a/v1_20_R2/build.gradle.kts b/v1_20_R2/build.gradle.kts new file mode 100644 index 00000000..360c4ece --- /dev/null +++ b/v1_20_R2/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + id("java") + id("io.papermc.paperweight.userdev") version "1.5.1" +} + +dependencies { + paperDevBundle("1.20.2-R0.1-SNAPSHOT") + implementation(project(":common")) +} + +tasks { + + build { + dependsOn(reobfJar) + } + + compileJava { + options.encoding = Charsets.UTF_8.name() + options.release.set(17) + } + javadoc { + options.encoding = Charsets.UTF_8.name() + } + processResources { + filteringCharset = Charsets.UTF_8.name() + } +} \ No newline at end of file diff --git a/v1_20_R2/src/main/java/com/hibiscusmc/hmccosmetics/nms/v1_20_R2/MEGEntity.java b/v1_20_R2/src/main/java/com/hibiscusmc/hmccosmetics/nms/v1_20_R2/MEGEntity.java new file mode 100644 index 00000000..4f635bde --- /dev/null +++ b/v1_20_R2/src/main/java/com/hibiscusmc/hmccosmetics/nms/v1_20_R2/MEGEntity.java @@ -0,0 +1,30 @@ +package com.hibiscusmc.hmccosmetics.nms.v1_20_R2; + +import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin; +import com.hibiscusmc.hmccosmetics.util.MessagesUtil; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.persistence.PersistentDataType; + +public class MEGEntity extends ArmorStand { + public MEGEntity(Location loc) { + super(EntityType.ARMOR_STAND, ((CraftWorld) loc.getWorld()).getHandle()); + this.setPos(loc.getX(), loc.getY(), loc.getZ()); + + MessagesUtil.sendDebugMessages("Spawned MEGEntity at " + loc); + setInvisible(true); + setNoGravity(true); + setSilent(true); + setInvulnerable(true); + setSmall(true); + setMarker(true); + + persist = false; + getBukkitEntity().getPersistentDataContainer().set(new NamespacedKey(HMCCosmeticsPlugin.getInstance(), "cosmeticMob"), PersistentDataType.SHORT, Short.valueOf("1")); + + ((CraftWorld) loc.getWorld()).getHandle().addFreshEntity(this); + } +} diff --git a/v1_20_R2/src/main/java/com/hibiscusmc/hmccosmetics/nms/v1_20_R2/NMSHandler.java b/v1_20_R2/src/main/java/com/hibiscusmc/hmccosmetics/nms/v1_20_R2/NMSHandler.java new file mode 100644 index 00000000..f1985bac --- /dev/null +++ b/v1_20_R2/src/main/java/com/hibiscusmc/hmccosmetics/nms/v1_20_R2/NMSHandler.java @@ -0,0 +1,170 @@ +package com.hibiscusmc.hmccosmetics.nms.v1_20_R2; + +import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType; +import com.hibiscusmc.hmccosmetics.user.CosmeticUser; +import com.hibiscusmc.hmccosmetics.user.manager.UserBalloonManager; +import com.hibiscusmc.hmccosmetics.util.MessagesUtil; +import com.mojang.datafixers.util.Pair; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; +import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.entity.Display; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.scores.PlayerTeam; +import net.minecraft.world.scores.Team; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_20_R2.CraftEquipmentSlot; +import org.bukkit.craftbukkit.v1_20_R2.CraftServer; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R2.scoreboard.CraftScoreboard; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class NMSHandler implements com.hibiscusmc.hmccosmetics.nms.NMSHandler { + @Override + public int getNextEntityId() { + return net.minecraft.world.entity.Entity.nextEntityId(); + } + + @Override + public org.bukkit.entity.Entity getEntity(int entityId) { + net.minecraft.world.entity.Entity entity = getNMSEntity(entityId); + if (entity == null) return null; + return entity.getBukkitEntity(); + } + + private net.minecraft.world.entity.Entity getNMSEntity(int entityId) { + for (ServerLevel world : ((CraftServer) Bukkit.getServer()).getHandle().getServer().getAllLevels()) { + net.minecraft.world.entity.Entity entity = world.getEntity(entityId); + if (entity == null) continue; + return entity; + } + return null; + } + + @Override + public ArmorStand getMEGEntity(Location loc) { + return (ArmorStand) new MEGEntity(loc).getBukkitEntity(); + } + + @Override + public org.bukkit.entity.Entity spawnDisplayEntity(Location location, String text) { + Display.TextDisplay entity = new Display.TextDisplay(net.minecraft.world.entity.EntityType.TEXT_DISPLAY, ((CraftWorld) location.getWorld()).getHandle()); + entity.setPos(location.getX(), location.getY(), location.getZ()); + entity.persist = false; + //entity.setText(net.minecraft.network.chat.Component.literal("TEST!")); + entity.setCustomNameVisible(true); + entity.setCustomName(Component.literal(text)); + MessagesUtil.sendDebugMessages("spawnDisplayEntity - " + entity); + ((CraftWorld) location.getWorld()).getHandle().addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + return entity.getBukkitEntity(); + } + + @Override + public UserBalloonManager spawnBalloon(CosmeticUser user, CosmeticBalloonType cosmeticBalloonType) { + org.bukkit.entity.Entity entity = user.getEntity(); + + UserBalloonManager userBalloonManager1 = new UserBalloonManager(user, entity.getLocation()); + userBalloonManager1.getModelEntity().teleport(entity.getLocation().add(cosmeticBalloonType.getBalloonOffset())); + + userBalloonManager1.spawnModel(cosmeticBalloonType, user.getCosmeticColor(cosmeticBalloonType.getSlot())); + userBalloonManager1.addPlayerToModel(user, cosmeticBalloonType, user.getCosmeticColor(cosmeticBalloonType.getSlot())); + + return userBalloonManager1; + } + + + @Override + public void equipmentSlotUpdate( + int entityId, + org.bukkit.inventory.EquipmentSlot slot, + ItemStack item, + List sendTo + ) { + + EquipmentSlot nmsSlot = null; + net.minecraft.world.item.ItemStack nmsItem = null; + + // Converting EquipmentSlot and ItemStack to NMS ones. + nmsSlot = CraftEquipmentSlot.getNMS(slot); + nmsItem = CraftItemStack.asNMSCopy(item); + + if (nmsSlot == null) return; + + Pair pair = new Pair<>(nmsSlot, nmsItem); + + List> pairs = Collections.singletonList(pair); + + ClientboundSetEquipmentPacket packet = new ClientboundSetEquipmentPacket(entityId, pairs); + for (Player p : sendTo) sendPacket(p, packet); + } + + + @Override + public void slotUpdate( + Player player, + int slot + ) { + int index = 0; + + ServerPlayer player1 = ((CraftPlayer) player).getHandle(); + + if (index < Inventory.getSelectionSize()) { + index += 36; + } else if (index > 39) { + index += 5; // Off hand + } else if (index > 35) { + index = 8 - (index - 36); + } + ItemStack item = player.getInventory().getItem(slot); + + Packet packet = new ClientboundContainerSetSlotPacket(player1.inventoryMenu.containerId, player1.inventoryMenu.incrementStateId(), index, CraftItemStack.asNMSCopy(item)); + sendPacket(player, packet); + } + + public void hideNPCName(Player player, String NPCName) { + //Creating the team + PlayerTeam team = new PlayerTeam(((CraftScoreboard) Bukkit.getScoreboardManager().getMainScoreboard()).getHandle(), NPCName); + + //Setting name visibility + team.setNameTagVisibility(Team.Visibility.NEVER); + + //Remove the Team (i assume so if it exists) + ClientboundSetPlayerTeamPacket removeTeamPacket = ClientboundSetPlayerTeamPacket.createRemovePacket(team); + sendPacket(player, removeTeamPacket); + //Creating the Team + ClientboundSetPlayerTeamPacket createTeamPacket = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true); + sendPacket(player, createTeamPacket); + //Adding players to the team (You have to use the NPC's name, and add it to a list) + ClientboundSetPlayerTeamPacket createPlayerTeamPacket = ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, new ArrayList() {{ + add(NPCName); + }}, ClientboundSetPlayerTeamPacket.Action.ADD); + sendPacket(player, createPlayerTeamPacket); + } + + public void sendPacket(Player player, Packet packet) { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + ServerPlayerConnection connection = serverPlayer.connection; + connection.send(packet); + } + + @Override + public boolean getSupported() { + return true; + } +}