mirror of
https://github.com/HibiscusMC/HibiscusCommons.git
synced 2025-12-19 15:09:26 +00:00
feat: add 1.21.10 support
This commit is contained in:
@@ -11,7 +11,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "me.lojosho"
|
group = "me.lojosho"
|
||||||
version = "0.8.0${getGitCommitHash()}"
|
version = "0.8.1${getGitCommitHash()}"
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
apply(plugin = "java")
|
apply(plugin = "java")
|
||||||
@@ -130,6 +130,7 @@ dependencies {
|
|||||||
implementation(project(path = ":v1_21_R3", configuration = "reobf"))
|
implementation(project(path = ":v1_21_R3", configuration = "reobf"))
|
||||||
implementation(project(path = ":v1_21_R4", configuration = "reobf"))
|
implementation(project(path = ":v1_21_R4", configuration = "reobf"))
|
||||||
implementation(project(path = ":v1_21_R5", configuration = "reobf"))
|
implementation(project(path = ":v1_21_R5", configuration = "reobf"))
|
||||||
|
implementation(project(path = ":v1_21_R6", configuration = "reobf"))
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
@@ -164,6 +165,7 @@ tasks {
|
|||||||
dependsOn(":v1_21_R3:reobfJar")
|
dependsOn(":v1_21_R3:reobfJar")
|
||||||
dependsOn(":v1_21_R4:reobfJar")
|
dependsOn(":v1_21_R4:reobfJar")
|
||||||
dependsOn(":v1_21_R5:reobfJar")
|
dependsOn(":v1_21_R5:reobfJar")
|
||||||
|
dependsOn(":v1_21_R6:reobfJar")
|
||||||
mergeServiceFiles()
|
mergeServiceFiles()
|
||||||
|
|
||||||
relocate("org.bstats", "me.lojosho.shaded.bstats")
|
relocate("org.bstats", "me.lojosho.shaded.bstats")
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ public enum MinecraftVersion {
|
|||||||
v1_21_6,
|
v1_21_6,
|
||||||
v1_21_7,
|
v1_21_7,
|
||||||
v1_21_8,
|
v1_21_8,
|
||||||
|
v1_21_9,
|
||||||
|
v1_21_10,
|
||||||
;
|
;
|
||||||
|
|
||||||
public boolean isHigher(MinecraftVersion other) {
|
public boolean isHigher(MinecraftVersion other) {
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public class NMSHandlers {
|
|||||||
put(MinecraftVersion.v1_21_6, new MinecraftVersionInformation("v1_21_R5", false));
|
put(MinecraftVersion.v1_21_6, new MinecraftVersionInformation("v1_21_R5", false));
|
||||||
put(MinecraftVersion.v1_21_7, new MinecraftVersionInformation("v1_21_R5", false));
|
put(MinecraftVersion.v1_21_7, new MinecraftVersionInformation("v1_21_R5", false));
|
||||||
put(MinecraftVersion.v1_21_8, new MinecraftVersionInformation("v1_21_R5", true));
|
put(MinecraftVersion.v1_21_8, new MinecraftVersionInformation("v1_21_R5", true));
|
||||||
|
put(MinecraftVersion.v1_21_9, new MinecraftVersionInformation("v1_21_R6", false));
|
||||||
|
put(MinecraftVersion.v1_21_10, new MinecraftVersionInformation("v1_21_R6", true));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
private static NMSHandler handler;
|
private static NMSHandler handler;
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ include(
|
|||||||
"v1_21_R3",
|
"v1_21_R3",
|
||||||
"v1_21_R4",
|
"v1_21_R4",
|
||||||
"v1_21_R5",
|
"v1_21_R5",
|
||||||
|
"v1_21_R6",
|
||||||
)
|
)
|
||||||
30
v1_21_R6/build.gradle.kts
Normal file
30
v1_21_R6/build.gradle.kts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
plugins {
|
||||||
|
id("java")
|
||||||
|
id("io.papermc.paperweight.userdev")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
paperweight.paperDevBundle("1.21.10-R0.1-SNAPSHOT")
|
||||||
|
implementation(project(":common"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
|
||||||
|
build {
|
||||||
|
dependsOn(reobfJar)
|
||||||
|
}
|
||||||
|
|
||||||
|
compileJava {
|
||||||
|
options.encoding = Charsets.UTF_8.name()
|
||||||
|
}
|
||||||
|
java {
|
||||||
|
toolchain.languageVersion.set(JavaLanguageVersion.of(21));
|
||||||
|
}
|
||||||
|
|
||||||
|
javadoc {
|
||||||
|
options.encoding = Charsets.UTF_8.name()
|
||||||
|
}
|
||||||
|
processResources {
|
||||||
|
filteringCharset = Charsets.UTF_8.name()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package me.lojosho.hibiscuscommons.nms.v1_21_R6;
|
||||||
|
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerConnection;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class NMSCommon {
|
||||||
|
|
||||||
|
public void sendPacket(Player player, Packet packet) {
|
||||||
|
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||||
|
ServerPlayerConnection connection = serverPlayer.connection;
|
||||||
|
connection.send(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
package me.lojosho.hibiscuscommons.nms.v1_21_R6;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelPromise;
|
||||||
|
import lombok.Getter;
|
||||||
|
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
|
||||||
|
import me.lojosho.hibiscuscommons.packets.PacketAction;
|
||||||
|
import me.lojosho.hibiscuscommons.packets.wrapper.*;
|
||||||
|
import me.lojosho.hibiscuscommons.plugins.SubPlugins;
|
||||||
|
import me.lojosho.hibiscuscommons.util.MessagesUtil;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.*;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
|
import net.minecraft.world.inventory.ClickType;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.bukkit.craftbukkit.CraftEquipmentSlot;
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class NMSPacketChannel extends ChannelDuplexHandler {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
public NMSPacketChannel(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||||
|
if (!(msg instanceof Packet packet)) {
|
||||||
|
super.write(ctx, msg, promise);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (packet) {
|
||||||
|
case ClientboundContainerSetContentPacket setContentPacket -> msg = handleMenuChange(setContentPacket);
|
||||||
|
case ClientboundContainerSetSlotPacket setSlotPacket -> msg = handleSlotChange(setSlotPacket);
|
||||||
|
case ClientboundSetEquipmentPacket equipmentPacket -> msg = handlePlayerEquipment(equipmentPacket);
|
||||||
|
case ClientboundSetPassengersPacket passengerPacket -> msg = handlePassengerSet(passengerPacket);
|
||||||
|
case ClientboundUpdateAttributesPacket attributesPacket -> msg = handleScaleChange(attributesPacket);
|
||||||
|
default -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg == null) return;
|
||||||
|
else super.write(ctx, msg, promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handleMenuChange(@NotNull ClientboundContainerSetContentPacket packet) {
|
||||||
|
MessagesUtil.sendDebugMessages("ClientboundContainerSetContentPacket");
|
||||||
|
MessagesUtil.sendDebugMessages("Menu Initial ");
|
||||||
|
|
||||||
|
Integer windowId = packet.containerId();
|
||||||
|
List<ItemStack> slotData = packet.items();
|
||||||
|
|
||||||
|
List<org.bukkit.inventory.ItemStack> bukkitItems = new ArrayList<>();
|
||||||
|
for (ItemStack nmsItem : slotData) {
|
||||||
|
if (nmsItem == null) {
|
||||||
|
slotData.add(null);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bukkitItems.add(CraftItemStack.asBukkitCopy(nmsItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
ContainerContentWrapper wrapper = new ContainerContentWrapper(windowId, bukkitItems);
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().writeContainerContent(player, wrapper);
|
||||||
|
if (pluginAction != PacketAction.NOTHING) action.set(pluginAction);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
if (action.get() == PacketAction.NOTHING) return packet;
|
||||||
|
|
||||||
|
List<ItemStack> nmsItems = new ArrayList<>();
|
||||||
|
for (org.bukkit.inventory.ItemStack bukkitItem : bukkitItems) {
|
||||||
|
if (bukkitItem == null) {
|
||||||
|
slotData.add(null);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nmsItems.add(CraftItemStack.asNMSCopy(bukkitItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ClientboundContainerSetContentPacket(wrapper.getWindowId(), packet.stateId(), nmsItems, packet.carriedItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handleSlotChange(@NotNull ClientboundContainerSetSlotPacket packet) {
|
||||||
|
MessagesUtil.sendDebugMessages("ClientboundContainerSetSlotPacket");
|
||||||
|
|
||||||
|
final int windowId = packet.getContainerId();
|
||||||
|
final int slot = packet.getSlot();
|
||||||
|
final ItemStack item = packet.getItem();
|
||||||
|
|
||||||
|
org.bukkit.inventory.ItemStack bukkitItem = CraftItemStack.asBukkitCopy(item);
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
SlotContentWrapper wrapper = new SlotContentWrapper(windowId, slot, bukkitItem);
|
||||||
|
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().writeSlotContent(player, wrapper);
|
||||||
|
if (pluginAction != PacketAction.NOTHING) action.set(pluginAction);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
if (action.get() == PacketAction.NOTHING) return packet;
|
||||||
|
|
||||||
|
final ItemStack nmsItem = CraftItemStack.asNMSCopy(wrapper.getItemStack());
|
||||||
|
|
||||||
|
return new ClientboundContainerSetSlotPacket(packet.getContainerId(), packet.getStateId(), wrapper.getSlot(), nmsItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handlePlayerEquipment(@NotNull ClientboundSetEquipmentPacket packet) {
|
||||||
|
MessagesUtil.sendDebugMessages("ClientboundSetEquipmentPacket");
|
||||||
|
final List<Pair<net.minecraft.world.entity.EquipmentSlot, ItemStack>> nmsArmor = packet.getSlots();
|
||||||
|
final int entity = packet.getEntity();
|
||||||
|
HashMap<EquipmentSlot, org.bukkit.inventory.ItemStack> bukkitArmor = new HashMap<>();
|
||||||
|
for (Pair<net.minecraft.world.entity.EquipmentSlot, ItemStack> piece : nmsArmor) {
|
||||||
|
EquipmentSlot slot = CraftEquipmentSlot.getSlot(piece.getFirst());
|
||||||
|
org.bukkit.inventory.ItemStack itemStack = CraftItemStack.asBukkitCopy(piece.getSecond());
|
||||||
|
bukkitArmor.put(slot, itemStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
EntityEquipmentWrapper wrapper = new EntityEquipmentWrapper(entity, bukkitArmor);
|
||||||
|
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().writeEquipmentContent(player, wrapper);
|
||||||
|
if (pluginAction != PacketAction.NOTHING) action.set(pluginAction);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
if (action.get() == PacketAction.NOTHING) return packet;
|
||||||
|
|
||||||
|
List<Pair<net.minecraft.world.entity.EquipmentSlot, ItemStack>> newArmor = new ArrayList<>();
|
||||||
|
for (Map.Entry<EquipmentSlot, org.bukkit.inventory.ItemStack> entry : wrapper.getArmor().entrySet()) {
|
||||||
|
net.minecraft.world.entity.EquipmentSlot slot = CraftEquipmentSlot.getNMS(entry.getKey());
|
||||||
|
ItemStack itemStack = CraftItemStack.asNMSCopy(entry.getValue());
|
||||||
|
newArmor.add(new Pair<>(slot, itemStack));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ClientboundSetEquipmentPacket(packet.getEntity(), newArmor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handlePassengerSet(@NotNull ClientboundSetPassengersPacket packet) {
|
||||||
|
MessagesUtil.sendDebugMessages("ClientboundSetPassengersPacket");
|
||||||
|
int ownerId = packet.getVehicle();
|
||||||
|
List<Integer> passengers = Arrays.stream(packet.getPassengers()).boxed().collect(Collectors.toList());
|
||||||
|
MessagesUtil.sendDebugMessages("Mount Packet Sent - Read - EntityID: " + ownerId);
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
PassengerWrapper wrapper = new PassengerWrapper(ownerId, passengers);
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().writePassengerContent(player, wrapper);
|
||||||
|
if (pluginAction != PacketAction.NOTHING) {
|
||||||
|
action.set(pluginAction);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
if (action.get() == PacketAction.NOTHING) return packet;
|
||||||
|
return (Packet<?>) NMSHandlers.getHandler().getPacketHandler().createMountPacket(ownerId, passengers.stream().mapToInt(Integer::intValue).toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handleScaleChange(@NotNull ClientboundUpdateAttributesPacket packet) {
|
||||||
|
final List<ClientboundUpdateAttributesPacket.AttributeSnapshot> nmsAttributes = packet.getValues();
|
||||||
|
final ClientboundUpdateAttributesPacket.AttributeSnapshot nmsScaleAttribute = nmsAttributes.stream()
|
||||||
|
.filter(attribute -> attribute.attribute().equals(Attributes.SCALE))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (nmsScaleAttribute == null) {
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
|
||||||
|
final double base = nmsScaleAttribute.base();
|
||||||
|
double total = base;
|
||||||
|
|
||||||
|
for (AttributeModifier modifier : nmsScaleAttribute.modifiers()) {
|
||||||
|
switch (modifier.operation()) {
|
||||||
|
case ADD_VALUE -> total += modifier.amount();
|
||||||
|
case ADD_MULTIPLIED_BASE -> total += modifier.amount() * nmsScaleAttribute.base();
|
||||||
|
case ADD_MULTIPLIED_TOTAL -> total += modifier.amount() * total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PlayerScaleWrapper wrapper = new PlayerScaleWrapper(packet.getEntityId(), base, total);
|
||||||
|
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().readPlayerScale(player, wrapper);
|
||||||
|
if (pluginAction != PacketAction.NOTHING) action.set(pluginAction);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
if (action.get() == PacketAction.NOTHING) return packet;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
if (!(msg instanceof Packet packet)) {
|
||||||
|
super.channelRead(ctx, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (packet) {
|
||||||
|
case ServerboundContainerClickPacket clickPacket -> msg = handleInventoryClick(clickPacket);
|
||||||
|
case ServerboundPlayerActionPacket playerActionPacket -> msg = handlePlayerAction(playerActionPacket);
|
||||||
|
case ServerboundSwingPacket swingPacket -> msg = handlePlayerArm(swingPacket);
|
||||||
|
case ServerboundInteractPacket interactPacket -> msg = handleInteract(interactPacket);
|
||||||
|
default -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg == null) return;
|
||||||
|
else super.channelRead(ctx, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handleInventoryClick(@NotNull ServerboundContainerClickPacket packet) {
|
||||||
|
MessagesUtil.sendDebugMessages("ServerboundContainerClickPacket");
|
||||||
|
ClickType clickType = packet.clickType();
|
||||||
|
int slotClicked = packet.slotNum();
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().readInventoryClick(player, new InventoryClickWrapper(clickType.id(), slotClicked));
|
||||||
|
if (pluginAction != PacketAction.NOTHING) action.set(pluginAction);
|
||||||
|
|
||||||
|
});
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handlePlayerAction(ServerboundPlayerActionPacket packet) {
|
||||||
|
MessagesUtil.sendDebugMessages("ServerboundPlayerActionPacket");
|
||||||
|
ServerboundPlayerActionPacket.Action playerAction = packet.getAction();
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().readPlayerAction(player, new PlayerActionWrapper(playerAction.name()));
|
||||||
|
if (pluginAction != PacketAction.NOTHING) action.set(pluginAction);
|
||||||
|
|
||||||
|
});
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handlePlayerArm(@NotNull ServerboundSwingPacket packet) {
|
||||||
|
MessagesUtil.sendDebugMessages("ServerboundSwingPacket");
|
||||||
|
PlayerSwingWrapper wrapper = new PlayerSwingWrapper(packet.getHand().name());
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().readPlayerArm(player, wrapper);
|
||||||
|
if (pluginAction != PacketAction.NOTHING) action.set(pluginAction);
|
||||||
|
|
||||||
|
});
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Packet<?> handleInteract(@NotNull ServerboundInteractPacket packet) {
|
||||||
|
MessagesUtil.sendDebugMessages("ServerboundInteractPacket");
|
||||||
|
|
||||||
|
PlayerInteractWrapper wrapper = new PlayerInteractWrapper(packet.getEntityId());
|
||||||
|
|
||||||
|
AtomicReference<PacketAction> action = new AtomicReference<>(PacketAction.NOTHING);
|
||||||
|
SubPlugins.getSubPlugins().forEach(plugin -> {
|
||||||
|
|
||||||
|
PacketAction pluginAction = plugin.getPacketInterface().readEntityHandle(player, wrapper);
|
||||||
|
if (pluginAction != PacketAction.NOTHING) action.set(pluginAction);
|
||||||
|
|
||||||
|
});
|
||||||
|
if (action.get() == PacketAction.CANCELLED) return null;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,564 @@
|
|||||||
|
package me.lojosho.hibiscuscommons.nms.v1_21_R6;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.JsonOps;
|
||||||
|
import io.papermc.paper.adventure.PaperAdventure;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin;
|
||||||
|
import me.lojosho.hibiscuscommons.util.AdventureUtils;
|
||||||
|
import me.lojosho.hibiscuscommons.util.MessagesUtil;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
|
import net.minecraft.advancements.Advancement;
|
||||||
|
import net.minecraft.advancements.AdvancementHolder;
|
||||||
|
import net.minecraft.commands.arguments.EntityAnchorArgument;
|
||||||
|
import net.minecraft.network.chat.RemoteChatSession;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.*;
|
||||||
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EquipmentSlot;
|
||||||
|
import net.minecraft.world.entity.PositionMoveRotation;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
|
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.level.GameType;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.scores.PlayerTeam;
|
||||||
|
import net.minecraft.world.scores.Team;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.craftbukkit.CraftEquipmentSlot;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftEntityType;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.craftbukkit.scoreboard.CraftScoreboard;
|
||||||
|
import org.bukkit.entity.*;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.inventory.meta.components.CustomModelDataComponent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets {
|
||||||
|
|
||||||
|
private static ServerLevel level = MinecraftServer.getServer().overworld();
|
||||||
|
private static final Map<Integer, Number> CLOUD_EFFECT_INVISIBLE_DATA_VALUES = Map.of(0, (byte) 0x20, 8, 0f); // For cloud effects
|
||||||
|
private static final Map<Integer, Number> GENERIC_INVISIBLE_DATA_VALUES = Map.of(0, (byte) 0x20); // For most entities if you just need genericaly invisible
|
||||||
|
private static Entity fakeNmsEntity = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level);
|
||||||
|
|
||||||
|
@Override @SuppressWarnings("unchecked")
|
||||||
|
public void sendSharedEntityData(int entityId, Map<Integer, Number> dataValues, List<Player> sendTo) {
|
||||||
|
ClientboundSetEntityDataPacket packet = getSharedEntityPacket(entityId, dataValues);
|
||||||
|
for (Player player : sendTo) sendPacket(player, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientboundSetEntityDataPacket getSharedEntityPacket(int entityId, Map<Integer, Number> dataValues) {
|
||||||
|
List<SynchedEntityData.DataValue<?>> nmsDataValues = dataValues.entrySet().stream().map(entry -> {
|
||||||
|
int index = entry.getKey();
|
||||||
|
Number value = entry.getValue();
|
||||||
|
return switch (value) {
|
||||||
|
case Byte byteVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.BYTE, byteVal);
|
||||||
|
case Float floatVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.FLOAT, floatVal);
|
||||||
|
case Integer intVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.INT, intVal);
|
||||||
|
default ->
|
||||||
|
throw new IllegalArgumentException("Unsupported data value type: " + value.getClass().getSimpleName());
|
||||||
|
};
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
return new ClientboundSetEntityDataPacket(entityId, nmsDataValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendFakePlayerInfoPacket(
|
||||||
|
final Player skinnedPlayer,
|
||||||
|
final int entityId,
|
||||||
|
final UUID uuid,
|
||||||
|
final String npcName,
|
||||||
|
final List<Player> sendTo
|
||||||
|
) {
|
||||||
|
ServerPlayer player = ((CraftPlayer) skinnedPlayer).getHandle();
|
||||||
|
String name = npcName;
|
||||||
|
if (name.length() > 15) name = name.substring(0, 15);
|
||||||
|
Property property = ((CraftPlayer) skinnedPlayer).getProfile().properties().get("textures").stream().findAny().orElse(null);
|
||||||
|
|
||||||
|
GameProfile profile = new GameProfile(uuid, name);
|
||||||
|
if (property != null) profile.properties().put("textures", property);
|
||||||
|
|
||||||
|
Component component = AdventureUtils.MINI_MESSAGE.deserialize(name);
|
||||||
|
net.minecraft.network.chat.Component nmsComponent = HibiscusCommonsPlugin.isOnPaper() ? PaperAdventure.asVanilla(component) : net.minecraft.network.chat.Component.literal(name);
|
||||||
|
|
||||||
|
RemoteChatSession.Data chatData = null;
|
||||||
|
RemoteChatSession session = player.getChatSession();
|
||||||
|
if (session != null) chatData = player.getChatSession().asData();
|
||||||
|
|
||||||
|
ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(uuid, profile, false, 0, GameType.CREATIVE, nmsComponent, true, player.listOrder, chatData);
|
||||||
|
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER);
|
||||||
|
ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, entry);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPlayerInfoRemovePacket(final UUID uuid, final List<Player> sendTo) {
|
||||||
|
ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(uuid));
|
||||||
|
for (Player player : sendTo) sendPacket(player, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMovePacket(
|
||||||
|
final int entityId,
|
||||||
|
final @NotNull Location from,
|
||||||
|
final @NotNull Location to,
|
||||||
|
final boolean onGround,
|
||||||
|
@NotNull List<Player> sendTo
|
||||||
|
) {
|
||||||
|
byte dx = (byte) (to.getX() - from.getX());
|
||||||
|
byte dy = (byte) (to.getY() - from.getY());
|
||||||
|
byte dz = (byte) (to.getZ() - from.getZ());
|
||||||
|
|
||||||
|
ClientboundMoveEntityPacket.Pos packet = new ClientboundMoveEntityPacket.Pos(entityId, dx, dy, dz, onGround);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendGamemodeChange(Player player, GameMode gameMode) {
|
||||||
|
ClientboundGameEventPacket.Type type = ClientboundGameEventPacket.CHANGE_GAME_MODE;
|
||||||
|
float param = gameMode.getValue();
|
||||||
|
|
||||||
|
ClientboundGameEventPacket packet = new ClientboundGameEventPacket(type, param);
|
||||||
|
sendPacket(player, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendLookAtPacket(int entityId, Location location, List<Player> sendTo) {
|
||||||
|
fakeNmsEntity.setId(entityId);
|
||||||
|
fakeNmsEntity.getBukkitEntity().teleport(location);
|
||||||
|
ClientboundPlayerLookAtPacket packet = new ClientboundPlayerLookAtPacket(EntityAnchorArgument.Anchor.EYES, fakeNmsEntity, EntityAnchorArgument.Anchor.EYES);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendRotateHeadPacket(int entityId, Location location, List<Player> sendTo) {
|
||||||
|
fakeNmsEntity.setId(entityId);
|
||||||
|
byte headRot = (byte) (location.getYaw() * 256.0F / 360.0F);
|
||||||
|
|
||||||
|
ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(fakeNmsEntity, headRot);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendRotationPacket(int entityId, float originalYaw, float pitch, boolean onGround, List<Player> sendTo) {
|
||||||
|
float ROTATION_FACTOR = 256.0F / 360.0F;
|
||||||
|
byte yaw = (byte) (originalYaw * ROTATION_FACTOR);
|
||||||
|
pitch = (byte) (pitch * ROTATION_FACTOR);
|
||||||
|
MessagesUtil.sendDebugMessages("sendRotationPacket. Original: " + originalYaw + " modified: " + yaw);
|
||||||
|
ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, (byte) yaw, (byte) pitch, onGround);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendRotationPacket(int entityId, Location location, boolean onGround, List<Player> sendTo) {
|
||||||
|
float ROTATION_FACTOR = 256.0F / 360.0F;
|
||||||
|
byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR);
|
||||||
|
byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR);
|
||||||
|
ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, yaw, pitch, onGround);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendEquipmentSlotUpdate(
|
||||||
|
int entityId,
|
||||||
|
org.bukkit.inventory.EquipmentSlot slot,
|
||||||
|
ItemStack item,
|
||||||
|
List<Player> 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<EquipmentSlot, net.minecraft.world.item.ItemStack> pair = new Pair<>(nmsSlot, nmsItem);
|
||||||
|
|
||||||
|
List<Pair<EquipmentSlot, net.minecraft.world.item.ItemStack>> pairs = Collections.singletonList(pair);
|
||||||
|
|
||||||
|
ClientboundSetEquipmentPacket packet = new ClientboundSetEquipmentPacket(entityId, pairs);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendEquipmentSlotUpdate(
|
||||||
|
int entityId,
|
||||||
|
HashMap<org.bukkit.inventory.EquipmentSlot, ItemStack> equipment,
|
||||||
|
List<Player> sendTo
|
||||||
|
) {
|
||||||
|
|
||||||
|
List<Pair<EquipmentSlot, net.minecraft.world.item.ItemStack>> pairs = new ArrayList<>();
|
||||||
|
|
||||||
|
for (org.bukkit.inventory.EquipmentSlot slot : equipment.keySet()) {
|
||||||
|
EquipmentSlot nmsSlot = CraftEquipmentSlot.getNMS(slot);
|
||||||
|
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(equipment.get(slot));
|
||||||
|
|
||||||
|
Pair<EquipmentSlot, net.minecraft.world.item.ItemStack> pair = new Pair<>(nmsSlot, nmsItem);
|
||||||
|
pairs.add(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientboundSetEquipmentPacket packet = new ClientboundSetEquipmentPacket(entityId, pairs);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendSlotUpdate(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendScoreboardHideNamePacket(Player player, String name) {
|
||||||
|
//Creating the team
|
||||||
|
PlayerTeam team = new PlayerTeam(((CraftScoreboard) Bukkit.getScoreboardManager().getMainScoreboard()).getHandle(), name);
|
||||||
|
|
||||||
|
//Setting name visibility
|
||||||
|
team.setNameTagVisibility(Team.Visibility.NEVER);
|
||||||
|
|
||||||
|
//Remove the Team (i assume so if it exists)
|
||||||
|
ClientboundSetPlayerTeamPacket removeTeamPacket = ClientboundSetPlayerTeamPacket.createRemovePacket(team);
|
||||||
|
//Creating the Team
|
||||||
|
ClientboundSetPlayerTeamPacket createTeamPacket = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true);
|
||||||
|
//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<String>() {{
|
||||||
|
add(name);
|
||||||
|
add(player.getName());
|
||||||
|
}}, ClientboundSetPlayerTeamPacket.Action.ADD);
|
||||||
|
|
||||||
|
ClientboundBundlePacket bundlePacket = new ClientboundBundlePacket(List.of(removeTeamPacket, createTeamPacket, createPlayerTeamPacket));
|
||||||
|
sendPacket(player, bundlePacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMountPacket(int mountId, int[] passengerIds, List<Player> sendTo) {
|
||||||
|
List<Entity> passengers = Arrays.stream(passengerIds).mapToObj(id -> {
|
||||||
|
Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level);
|
||||||
|
passenger.setId(id);
|
||||||
|
return passenger;
|
||||||
|
}).toList();
|
||||||
|
fakeNmsEntity.setId(mountId);
|
||||||
|
fakeNmsEntity.passengers = ImmutableList.copyOf(passengers);
|
||||||
|
ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity);
|
||||||
|
fakeNmsEntity.passengers = ImmutableList.of();
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendLeashPacket(int leashEntity, int entityId, List<Player> sendTo) {
|
||||||
|
// Fake entities just to avoid reflection
|
||||||
|
ServerLevel level = MinecraftServer.getServer().overworld();
|
||||||
|
Entity entity1 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level);
|
||||||
|
Entity entity2 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level);
|
||||||
|
entity1.setId(leashEntity);
|
||||||
|
entity2.setId(entityId);
|
||||||
|
|
||||||
|
ClientboundSetEntityLinkPacket packet = new ClientboundSetEntityLinkPacket(entity1, entity2);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendTeleportPacket(
|
||||||
|
int entityId,
|
||||||
|
double x,
|
||||||
|
double y,
|
||||||
|
double z,
|
||||||
|
float yaw,
|
||||||
|
float pitch,
|
||||||
|
boolean onGround,
|
||||||
|
List<Player> sendTo
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
ClientboundTeleportEntityPacket packet = ClientboundTeleportEntityPacket.teleport(entityId, new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yaw, pitch), Set.of(), onGround);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendCameraPacket(int entityId, List<Player> sendTo) {
|
||||||
|
fakeNmsEntity.setId(entityId);
|
||||||
|
|
||||||
|
ClientboundSetCameraPacket packet = new ClientboundSetCameraPacket(fakeNmsEntity);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendSpawnEntityPacket(int entityId, UUID uuid, EntityType entityType, Location location, List<Player> sendTo) {
|
||||||
|
net.minecraft.world.entity.EntityType<?> nmsEntityType = CraftEntityType.bukkitToMinecraft(entityType);
|
||||||
|
double x = location.getX();
|
||||||
|
double y = location.getY();
|
||||||
|
double z = location.getZ();
|
||||||
|
float yaw = location.getYaw();
|
||||||
|
float pitch = location.getPitch();
|
||||||
|
Vec3 velocity = Vec3.ZERO;
|
||||||
|
float headYaw = 0f;
|
||||||
|
|
||||||
|
ClientboundAddEntityPacket packet = new ClientboundAddEntityPacket(entityId, uuid, x, y, z, yaw, pitch, nmsEntityType, 0, velocity, headYaw);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendEntityDestroyPacket(IntList entityIds, List<Player> sendTo) {
|
||||||
|
ClientboundRemoveEntitiesPacket packet = new ClientboundRemoveEntitiesPacket(entityIds);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendEntityScalePacket(int entityId, double scale, List<Player> sendTo) {
|
||||||
|
AttributeInstance attribute = new AttributeInstance(
|
||||||
|
Attributes.SCALE,
|
||||||
|
(ignored) -> {}
|
||||||
|
);
|
||||||
|
attribute.setBaseValue(scale);
|
||||||
|
|
||||||
|
ClientboundUpdateAttributesPacket packet = new ClientboundUpdateAttributesPacket(entityId, List.of(attribute));
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendItemDisplayMetadata(int entityId,
|
||||||
|
Vector3f translation,
|
||||||
|
Vector3f scale,
|
||||||
|
Quaternionf rotationLeft,
|
||||||
|
Quaternionf rotationRight,
|
||||||
|
Display.Billboard billboard,
|
||||||
|
int blockLight, int skyLight, float viewRange, float width, float height,
|
||||||
|
ItemDisplay.ItemDisplayTransform transform, ItemStack itemStack,
|
||||||
|
List<Player> sendTo) {
|
||||||
|
|
||||||
|
List<SynchedEntityData.DataValue<?>> dataValues = new ArrayList<>();
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(10, EntityDataSerializers.INT, POSITION_INTERPOLATION_DURATION));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(11, EntityDataSerializers.VECTOR3, translation));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(12, EntityDataSerializers.VECTOR3, scale));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(13, EntityDataSerializers.QUATERNION, rotationLeft));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(14, EntityDataSerializers.QUATERNION, rotationRight));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(15, EntityDataSerializers.BYTE, (byte) billboard.ordinal()));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(16, EntityDataSerializers.INT, (blockLight << 4 | skyLight << 20)));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(17, EntityDataSerializers.FLOAT, viewRange));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(20, EntityDataSerializers.FLOAT, width));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(21, EntityDataSerializers.FLOAT, height));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(23, EntityDataSerializers.ITEM_STACK, CraftItemStack.asNMSCopy(itemStack)));
|
||||||
|
dataValues.add(new SynchedEntityData.DataValue<>(24, EntityDataSerializers.BYTE, (byte) transform.ordinal()));
|
||||||
|
|
||||||
|
ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, dataValues);
|
||||||
|
for (Player p : sendTo) sendPacket(p, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendToastPacket(Player player, ItemStack icon, Component title, Component description) {
|
||||||
|
final var key = ResourceLocation.fromNamespaceAndPath("hibiscuscommons", UUID.randomUUID().toString());
|
||||||
|
|
||||||
|
JsonObject json = new JsonObject();
|
||||||
|
|
||||||
|
// Creating the "criteria" object
|
||||||
|
JsonObject impossibleCriteria = new JsonObject();
|
||||||
|
JsonObject impossible = new JsonObject();
|
||||||
|
impossible.addProperty("trigger", "minecraft:impossible");
|
||||||
|
impossibleCriteria.add("impossible", impossible);
|
||||||
|
json.add("criteria", impossibleCriteria);
|
||||||
|
|
||||||
|
// Creating the "display" object
|
||||||
|
JsonObject display = new JsonObject();
|
||||||
|
JsonObject iconObj = new JsonObject();
|
||||||
|
iconObj.addProperty("id", icon.getType().getKey().toString());
|
||||||
|
|
||||||
|
if (icon.hasItemMeta()) {
|
||||||
|
ItemMeta meta = icon.getItemMeta();
|
||||||
|
JsonObject components = new JsonObject();
|
||||||
|
|
||||||
|
if (!meta.getEnchants().isEmpty()) {
|
||||||
|
components.addProperty("minecraft:enchantment_glint_override", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.hasCustomModelData()) {
|
||||||
|
CustomModelDataComponent customModelDataComponent = meta.getCustomModelDataComponent();
|
||||||
|
JsonObject customModelDataComponentJson = new JsonObject();
|
||||||
|
|
||||||
|
List<Float> floats = customModelDataComponent.getFloats();
|
||||||
|
if (!floats.isEmpty()) {
|
||||||
|
JsonArray floatsArray = new JsonArray();
|
||||||
|
floats.forEach(floatsArray::add);
|
||||||
|
customModelDataComponentJson.add("floats", floatsArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Boolean> flags = customModelDataComponent.getFlags();
|
||||||
|
if (!flags.isEmpty()) {
|
||||||
|
JsonArray flagsArray = new JsonArray();
|
||||||
|
flags.forEach(flagsArray::add);
|
||||||
|
customModelDataComponentJson.add("flags", flagsArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> strings = customModelDataComponent.getStrings();
|
||||||
|
if (!strings.isEmpty()) {
|
||||||
|
JsonArray stringsArray = new JsonArray();
|
||||||
|
strings.forEach(stringsArray::add);
|
||||||
|
customModelDataComponentJson.add("strings", stringsArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Color> colors = customModelDataComponent.getColors();
|
||||||
|
if (!colors.isEmpty()) {
|
||||||
|
JsonArray colorsArray = new JsonArray();
|
||||||
|
colors.forEach(color -> colorsArray.add(color.asRGB()));
|
||||||
|
customModelDataComponentJson.add("colors", colorsArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
components.add("minecraft:custom_model_data", customModelDataComponentJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
NamespacedKey itemModel = meta.getItemModel();
|
||||||
|
if (itemModel != null) {
|
||||||
|
components.addProperty("minecraft:item_model", itemModel.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
iconObj.add("components", components);
|
||||||
|
}
|
||||||
|
|
||||||
|
display.add("icon", iconObj);
|
||||||
|
display.add("title", GsonComponentSerializer.gson().serializeToTree(title));
|
||||||
|
display.add("description", GsonComponentSerializer.gson().serializeToTree(description));
|
||||||
|
display.addProperty("description", "Toast Description");
|
||||||
|
display.addProperty("frame", "task");
|
||||||
|
display.addProperty("announce_to_chat", false);
|
||||||
|
display.addProperty("show_toast", true);
|
||||||
|
display.addProperty("hidden", true);
|
||||||
|
|
||||||
|
json.add("display", display);
|
||||||
|
|
||||||
|
final var advancement = Advancement.CODEC.parse(MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE), json);
|
||||||
|
final var advancementHolder = new AdvancementHolder(key, advancement.result().orElseThrow());
|
||||||
|
|
||||||
|
final var nmsPlayer = ((CraftPlayer) player).getHandle();
|
||||||
|
final var progress = nmsPlayer.getAdvancements().getOrStartProgress(advancementHolder);
|
||||||
|
MinecraftServer.getServer().getAdvancements().tree().addAll(Set.of(advancementHolder));
|
||||||
|
progress.getRemainingCriteria().forEach(criteria -> nmsPlayer.getAdvancements().award(advancementHolder, criteria));
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskLater(HibiscusCommonsPlugin.getInstance(), () -> {
|
||||||
|
progress.getRemainingCriteria().forEach(criteria -> nmsPlayer.getAdvancements().revoke(advancementHolder, criteria));
|
||||||
|
MinecraftServer.getServer().getAdvancements().tree().remove(Set.of(key));
|
||||||
|
|
||||||
|
// Remove the advancement from the player's client to prevent it from being displayed again
|
||||||
|
// Was not working without this?
|
||||||
|
ClientboundUpdateAdvancementsPacket removePacket = new ClientboundUpdateAdvancementsPacket(
|
||||||
|
false,
|
||||||
|
Collections.emptyList(),
|
||||||
|
Set.of(key),
|
||||||
|
Map.of(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
sendPacket(player, removePacket);
|
||||||
|
}, 2L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object createMountPacket(int entityId, int[] passengerIds) {
|
||||||
|
fakeNmsEntity.setId(entityId);
|
||||||
|
List<Entity> passengers = Arrays.stream(passengerIds).mapToObj(id -> {
|
||||||
|
Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level);
|
||||||
|
passenger.setId(id);
|
||||||
|
return passenger;
|
||||||
|
}).toList();
|
||||||
|
fakeNmsEntity.passengers = ImmutableList.copyOf(passengers);
|
||||||
|
ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity);
|
||||||
|
fakeNmsEntity.passengers = ImmutableList.of();
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendInvisibleParticleCloud(int entityId, Location location, UUID uuid, List<Player> sendTo) {
|
||||||
|
net.minecraft.world.entity.EntityType<?> nmsEntityType = net.minecraft.world.entity.EntityType.AREA_EFFECT_CLOUD;
|
||||||
|
double x = location.getX();
|
||||||
|
double y = location.getY();
|
||||||
|
double z = location.getZ();
|
||||||
|
float yaw = location.getYaw();
|
||||||
|
float pitch = location.getPitch();
|
||||||
|
Vec3 velocity = Vec3.ZERO;
|
||||||
|
float headYaw = 0f;
|
||||||
|
|
||||||
|
ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket(entityId, uuid, x, y, z, yaw, pitch, nmsEntityType, 0, velocity, headYaw);
|
||||||
|
ClientboundSetEntityDataPacket dataPacket = getSharedEntityPacket(entityId, CLOUD_EFFECT_INVISIBLE_DATA_VALUES);
|
||||||
|
|
||||||
|
ClientboundBundlePacket bundlePacket = new ClientboundBundlePacket(List.of(spawnPacket, dataPacket));
|
||||||
|
for (Player p : sendTo) sendPacket(p, bundlePacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendInvisibleArmorstand(int entityId, Location location, UUID uuid, byte mask, List<Player> sendTo) {
|
||||||
|
net.minecraft.world.entity.EntityType<?> nmsEntityType = net.minecraft.world.entity.EntityType.ARMOR_STAND;
|
||||||
|
double x = location.getX();
|
||||||
|
double y = location.getY();
|
||||||
|
double z = location.getZ();
|
||||||
|
float yaw = location.getYaw();
|
||||||
|
float pitch = location.getPitch();
|
||||||
|
Vec3 velocity = Vec3.ZERO;
|
||||||
|
float headYaw = 0f;
|
||||||
|
|
||||||
|
final ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket(entityId, uuid, x, y, z, yaw, pitch, nmsEntityType, 0, velocity, headYaw);
|
||||||
|
|
||||||
|
final Map<Integer, Number> dataValues = Map.of(0, mask, 15, (byte) 0x10);
|
||||||
|
final ClientboundSetEntityDataPacket dataPacket = getSharedEntityPacket(entityId, dataValues);
|
||||||
|
|
||||||
|
ClientboundBundlePacket bundlePacket = new ClientboundBundlePacket(List.of(spawnPacket, dataPacket));
|
||||||
|
for (Player p : sendTo) sendPacket(p, bundlePacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendInvisibleEntity(int entityId, EntityType type, Location location, UUID uuid, List<Player> sendTo) {
|
||||||
|
net.minecraft.world.entity.EntityType<?> nmsEntityType = CraftEntityType.bukkitToMinecraft(type);
|
||||||
|
double x = location.getX();
|
||||||
|
double y = location.getY();
|
||||||
|
double z = location.getZ();
|
||||||
|
float yaw = location.getYaw();
|
||||||
|
float pitch = location.getPitch();
|
||||||
|
Vec3 velocity = Vec3.ZERO;
|
||||||
|
float headYaw = 0f;
|
||||||
|
|
||||||
|
final ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket(entityId, uuid, x, y, z, yaw, pitch, nmsEntityType, 0, velocity, headYaw);
|
||||||
|
final ClientboundSetEntityDataPacket dataPacket = getSharedEntityPacket(entityId, GENERIC_INVISIBLE_DATA_VALUES);
|
||||||
|
|
||||||
|
ClientboundBundlePacket bundlePacket = new ClientboundBundlePacket(List.of(spawnPacket, dataPacket));
|
||||||
|
for (Player p : sendTo) sendPacket(p, bundlePacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package me.lojosho.hibiscuscommons.nms.v1_21_R6;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.item.alchemy.PotionContents;
|
||||||
|
import net.minecraft.world.item.component.DyedItemColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.craftbukkit.CraftServer;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.PotionMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class NMSUtils extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSUtils {
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Color getColor(ItemStack itemStack) {
|
||||||
|
if (itemStack == null) return null;
|
||||||
|
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
|
||||||
|
if (nmsItem == null) return null;
|
||||||
|
|
||||||
|
DyedItemColor color = nmsItem.get(DataComponents.DYED_COLOR);
|
||||||
|
if (color == null) return null;
|
||||||
|
return Color.fromRGB(color.rgb());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack setColor(@NotNull ItemStack itemStack, @NotNull Color color) {
|
||||||
|
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||||
|
// Potions needs a bit extra to get the color working properly
|
||||||
|
if (itemStack.getType() == Material.POTION) {
|
||||||
|
nmsStack.set(DataComponents.POTION_CONTENTS, new PotionContents(
|
||||||
|
Optional.empty(),
|
||||||
|
Optional.of(color.asRGB()),
|
||||||
|
List.of(),
|
||||||
|
Optional.empty())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
nmsStack.set(DataComponents.DYED_COLOR, new DyedItemColor(color.asRGB()));
|
||||||
|
return CraftItemStack.asBukkitCopy(nmsStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 void handleChannelOpen(@NotNull Player player) {
|
||||||
|
Channel channel = ((CraftPlayer) player).getHandle().connection.connection.channel;
|
||||||
|
ChannelPipeline pipeline = channel.pipeline();
|
||||||
|
|
||||||
|
NMSPacketChannel channelHandler = new NMSPacketChannel(player);
|
||||||
|
for (String key : pipeline.toMap().keySet()) {
|
||||||
|
if (!(pipeline.get(key) instanceof Connection)) continue;
|
||||||
|
pipeline.addBefore(key, "hibiscus_channel_handler", channelHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user