diff --git a/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java b/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java
index 1844eba..84a4dc6 100644
--- a/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java
+++ b/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java
@@ -27,6 +27,7 @@ import org.bukkit.inventory.meta.SkullMeta;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper {
@@ -294,4 +295,31 @@ public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper
head.setItemMeta(headmeta);
return head;
}
+
+ private static final Class> entityPose = Reflection.getClass("{nms.world.entity}.EntityPose");
+ private static final Object standing = entityPose.getEnumConstants()[0];
+ private static final Object swimming = entityPose.getEnumConstants()[3];
+ private static final Object sneaking = entityPose.getEnumConstants()[5];
+ @Override
+ public Object getPose(FlatteningWrapper.EntityPose pose) {
+ switch (pose) {
+ case SNEAKING:
+ return sneaking;
+ case SWIMMING:
+ return swimming;
+ case NORMAL:
+ default:
+ return standing;
+ }
+ }
+
+ @Override
+ public void setNamedSpawnPacketDataWatcher(Object packet) {
+ // field not present
+ }
+
+ @Override
+ public Object formatDisplayName(String displayName) {
+ return displayName != null ? Optional.of(ChatWrapper.impl.stringToChatComponent(displayName)) : Optional.empty();
+ }
}
diff --git a/SpigotCore_18/src/de/steamwar/core/ProtocolWrapper18.java b/SpigotCore_18/src/de/steamwar/core/ProtocolWrapper18.java
new file mode 100644
index 0000000..2a88cb4
--- /dev/null
+++ b/SpigotCore_18/src/de/steamwar/core/ProtocolWrapper18.java
@@ -0,0 +1,72 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.mojang.authlib.GameProfile;
+import com.mojang.datafixers.util.Pair;
+import net.minecraft.world.entity.EntityTypes;
+import org.bukkit.entity.EntityType;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ProtocolWrapper18 implements ProtocolWrapper {
+
+ private static final Reflection.FieldAccessor equipmentStack = Reflection.getField(equipmentPacket, List.class, 0);
+ @Override
+ public void setEquipmentPacketStack(Object packet, Object slot, Object stack) {
+ equipmentStack.set(packet, Collections.singletonList(new Pair<>(slot, stack)));
+ }
+
+ private static final Reflection.FieldAccessor> spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, EntityTypes.class, 0);
+ private static final Reflection.FieldAccessor spawnLivingType = Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
+ @Override
+ public void setSpawnPacketType(Object packet, EntityType type) {
+ switch(type) {
+ case PRIMED_TNT:
+ spawnType.set(packet, EntityTypes.as);
+ break;
+ case ARROW:
+ spawnType.set(packet, EntityTypes.d);
+ break;
+ case FIREBALL:
+ spawnType.set(packet, EntityTypes.S);
+ break;
+ case ITEM_FRAME:
+ spawnType.set(packet, EntityTypes.R);
+ break;
+ case FALLING_BLOCK:
+ spawnType.set(packet, EntityTypes.C);
+ break;
+ case ARMOR_STAND:
+ spawnLivingType.set(packet, 1);
+ break;
+ default:
+ throw new IllegalArgumentException(type.name() + " is not implemented");
+ }
+ }
+
+ private static final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClass, GameProfile.class, int.class, enumGamemode, iChatBaseComponent);
+ @Override
+ public Object playerInfoDataConstructor(Object packet, GameProfile profile, Object mode) {
+ return playerInfoDataConstructor.invoke(profile, 0, mode, null);
+ }
+}
diff --git a/SpigotCore_19/build.gradle b/SpigotCore_19/build.gradle
index 6f8f9d6..3a3e5d2 100644
--- a/SpigotCore_19/build.gradle
+++ b/SpigotCore_19/build.gradle
@@ -52,5 +52,6 @@ dependencies {
compileOnly 'org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT'
compileOnly 'com.mojang:brigadier:1.0.18'
compileOnly 'com.mojang:datafixerupper:4.0.26'
+ compileOnly 'com.mojang:authlib:1.5.25'
compileOnly swdep("Spigot-1.19")
}
diff --git a/SpigotCore_19/src/de/steamwar/core/ProtocolWrapper19.java b/SpigotCore_19/src/de/steamwar/core/ProtocolWrapper19.java
new file mode 100644
index 0000000..66cc47c
--- /dev/null
+++ b/SpigotCore_19/src/de/steamwar/core/ProtocolWrapper19.java
@@ -0,0 +1,71 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.mojang.authlib.GameProfile;
+import com.mojang.datafixers.util.Pair;
+import net.minecraft.world.entity.EntityTypes;
+import org.bukkit.entity.EntityType;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ProtocolWrapper19 implements ProtocolWrapper {
+
+ private static final Reflection.FieldAccessor equipmentStack = Reflection.getField(equipmentPacket, List.class, 0);
+ @Override
+ public void setEquipmentPacketStack(Object packet, Object slot, Object stack) {
+ equipmentStack.set(packet, Collections.singletonList(new Pair<>(slot, stack)));
+ }
+
+ private static final Reflection.FieldAccessor> spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, EntityTypes.class, 0);
+ @Override
+ public void setSpawnPacketType(Object packet, EntityType type) {
+ switch(type) {
+ case PRIMED_TNT:
+ spawnType.set(packet, EntityTypes.av);
+ break;
+ case ARROW:
+ spawnType.set(packet, EntityTypes.e);
+ break;
+ case FIREBALL:
+ spawnType.set(packet, EntityTypes.V);
+ break;
+ case ITEM_FRAME:
+ spawnType.set(packet, EntityTypes.U);
+ break;
+ case ARMOR_STAND:
+ spawnType.set(packet, EntityTypes.d);
+ break;
+ case FALLING_BLOCK:
+ spawnType.set(packet, EntityTypes.E);
+ break;
+ default:
+ throw new IllegalArgumentException(type.name() + " is not implemented");
+ }
+ }
+
+ private static final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClass, GameProfile.class, int.class, enumGamemode, iChatBaseComponent, Reflection.getClass("net.minecraft.world.entity.player.ProfilePublicKey$a"));
+ @Override
+ public Object playerInfoDataConstructor(Object packet, GameProfile profile, Object mode) {
+ return playerInfoDataConstructor.invoke(profile, 0, mode, null, null);
+ }
+}
diff --git a/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java b/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java
index 8c08082..3a0ee7a 100644
--- a/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java
+++ b/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java
@@ -19,14 +19,19 @@
package de.steamwar.core;
+import com.comphenix.tinyprotocol.Reflection;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import net.minecraft.server.v1_8_R3.ChatComponentText;
+import net.minecraft.server.v1_8_R3.MathHelper;
import net.minecraft.server.v1_8_R3.PacketPlayOutChat;
import org.bukkit.Sound;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
+import java.util.HashMap;
+import java.util.Map;
+
public class BountifulWrapper8 implements BountifulWrapper.IBountifulWrapper {
@Override
@@ -38,4 +43,43 @@ public class BountifulWrapper8 implements BountifulWrapper.IBountifulWrapper {
public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
((CraftPlayer) player).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(new ChatComponentText(BaseComponent.toLegacyText(msg)), (byte)type.ordinal()));
}
+
+ @Override
+ public Object getDataWatcherObject(int index, Class> type) {
+ return index;
+ }
+
+ private static final Class> watchableObject = Reflection.getClass("{nms}.DataWatcher$WatchableObject");
+ private static final Reflection.ConstructorInvoker watchableObjectConstructor = Reflection.getConstructor(watchableObject, int.class, int.class, Object.class);
+ private static final Map, Integer> watchableDatatypes = new HashMap<>();
+ static {
+ watchableDatatypes.put(byte.class, 0);
+ watchableDatatypes.put(short.class, 1);
+ watchableDatatypes.put(int.class, 2);
+ watchableDatatypes.put(float.class, 3);
+ watchableDatatypes.put(String.class, 4);
+ }
+
+ @Override
+ public Object getDataWatcherItem(Object dwo, Object value) {
+ return watchableObjectConstructor.invoke(watchableDatatypes.get(value.getClass()), dwo, value);
+ }
+
+ @Override
+ public BountifulWrapper.PositionSetter getPositionSetter(Class> packetClass, int fieldOffset8) {
+ Reflection.FieldAccessor posX = Reflection.getField(packetClass, int.class, fieldOffset8);
+ Reflection.FieldAccessor posY = Reflection.getField(packetClass, int.class, fieldOffset8+1);
+ Reflection.FieldAccessor posZ = Reflection.getField(packetClass, int.class, fieldOffset8+2);
+
+ return (packet, x, y, z) -> {
+ posX.set(packet, MathHelper.floor(x * 32));
+ posY.set(packet, MathHelper.floor(y * 32));
+ posZ.set(packet, MathHelper.floor(z * 32));
+ };
+ }
+
+ @Override
+ public BountifulWrapper.UUIDSetter getUUIDSetter(Class> packetClass) {
+ return (packet, uuid) -> {};
+ }
}
diff --git a/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java b/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java
index ca0a636..44f5c1a 100644
--- a/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java
+++ b/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java
@@ -64,4 +64,24 @@ public class FlatteningWrapper8 implements FlatteningWrapper.IFlatteningWrapper
head.setItemMeta(headmeta);
return head;
}
+
+ @Override
+ public Object getPose(FlatteningWrapper.EntityPose pose) {
+ return Byte.valueOf((byte)(pose == FlatteningWrapper.EntityPose.SNEAKING ? 2 : 0));
+ }
+
+ private static final Class> dataWatcher = Reflection.getClass("{nms}.DataWatcher");
+ private static final Class> namedSpawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutNamedEntitySpawn");
+ private static final Reflection.FieldAccessor> namedSpawnDataWatcher = Reflection.getField(namedSpawnPacket, dataWatcher, 0);
+ private static final Class> entity = Reflection.getClass("{nms}.Entity");
+ private static final Reflection.ConstructorInvoker dataWatcherConstructor = Reflection.getConstructor(dataWatcher, entity);
+ @Override
+ public void setNamedSpawnPacketDataWatcher(Object packet) {
+ namedSpawnDataWatcher.set(packet, dataWatcherConstructor.invoke((Object) null));
+ }
+
+ @Override
+ public Object formatDisplayName(String displayName) {
+ return displayName != null ? displayName : "";
+ }
}
diff --git a/SpigotCore_8/src/de/steamwar/core/ProtocolWrapper8.java b/SpigotCore_8/src/de/steamwar/core/ProtocolWrapper8.java
new file mode 100644
index 0000000..d0e0e03
--- /dev/null
+++ b/SpigotCore_8/src/de/steamwar/core/ProtocolWrapper8.java
@@ -0,0 +1,82 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.mojang.authlib.GameProfile;
+import org.bukkit.entity.EntityType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ProtocolWrapper8 implements ProtocolWrapper {
+
+ private static final Reflection.FieldAccessor> equipmentSlot;
+ static {
+ if(Core.getVersion() == 8) {
+ equipmentSlot = Reflection.getField(equipmentPacket, int.class, 1);
+ } else {
+ Class> enumItemSlot = Reflection.getClass("{nms.world.entity}.EnumItemSlot");
+ equipmentSlot = Reflection.getField(equipmentPacket, enumItemSlot, 0);
+ }
+ }
+
+ private static final Reflection.FieldAccessor> equipmentStack = Reflection.getField(equipmentPacket, itemStack, 0);
+ @Override
+ public void setEquipmentPacketStack(Object packet, Object slot, Object stack) {
+ equipmentSlot.set(packet, slot);
+ equipmentStack.set(packet, stack);
+ }
+
+ private static final Reflection.FieldAccessor> spawnType;
+ private static final Reflection.FieldAccessor spawnLivingType = Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
+ private static final Map types = new HashMap<>();
+
+ static {
+ if(Core.getVersion() < 14) {
+ spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, int.class, Core.getVersion() > 8 ? 6 : 9);
+ types.put(EntityType.PRIMED_TNT, 50);
+ types.put(EntityType.ARMOR_STAND, 30);
+ types.put(EntityType.ARROW, 60);
+ types.put(EntityType.FIREBALL, 63);
+ types.put(EntityType.ITEM_FRAME, 18);
+ types.put(EntityType.FALLING_BLOCK, 21);
+ } else {
+ Class> entityTypes = Reflection.getClass("{nms.world.entity}.EntityTypes");
+ spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, entityTypes, 0);
+ types.put(EntityType.ARMOR_STAND, 1);
+ for(EntityType type : new EntityType[]{EntityType.PRIMED_TNT, EntityType.ARROW, EntityType.FIREBALL, EntityType.ITEM_FRAME, EntityType.FALLING_BLOCK})
+ types.put(type, Reflection.getField(entityTypes, type.name(), entityTypes).get(null));
+ }
+ }
+ @Override
+ public void setSpawnPacketType(Object packet, EntityType type) {
+ if(type.isAlive())
+ spawnLivingType.set(packet, types.get(type));
+ else
+ spawnType.set(packet, types.get(type));
+ }
+
+ private static final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClass, playerInfoPacket, GameProfile.class, int.class, enumGamemode, iChatBaseComponent);
+ @Override
+ public Object playerInfoDataConstructor(Object packet, GameProfile profile, Object mode) {
+ return playerInfoDataConstructor.invoke(packet, profile, 0, mode, null);
+ }
+}
diff --git a/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java b/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java
index d12a37d..dc7c774 100644
--- a/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java
+++ b/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java
@@ -19,11 +19,14 @@
package de.steamwar.core;
+import com.comphenix.tinyprotocol.Reflection;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
+import java.util.UUID;
+
public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper {
@Override
@@ -35,4 +38,40 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper {
public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
player.spigot().sendMessage(type, msg);
}
+
+ private static final Class> dataWatcherObject = Reflection.getClass("{nms.network.syncher}.DataWatcherObject");
+ private static final Class> dataWatcherRegistry = Reflection.getClass("{nms.network.syncher}.DataWatcherRegistry");
+ private static final Class> dataWatcherSerializer = Reflection.getClass("{nms.network.syncher}.DataWatcherSerializer");
+ private static final Reflection.ConstructorInvoker dataWatcherObjectConstructor = Reflection.getConstructor(dataWatcherObject, int.class, dataWatcherSerializer);
+ @Override
+ public Object getDataWatcherObject(int index, Class> type) {
+ return dataWatcherObjectConstructor.invoke(index, Reflection.getField(dataWatcherRegistry, dataWatcherSerializer, 0, type).get(null));
+ }
+
+ private static final Class> item = Reflection.getClass("{nms.network.syncher}.DataWatcher$Item");
+ private static final Reflection.ConstructorInvoker itemConstructor = Reflection.getConstructor(item, dataWatcherObject, Object.class);
+ @Override
+ public Object getDataWatcherItem(Object dwo, Object value) {
+ return itemConstructor.invoke(dwo, value);
+ }
+
+ @Override
+ public BountifulWrapper.PositionSetter getPositionSetter(Class> packetClass, int fieldOffset8) {
+ Reflection.FieldAccessor posX = Reflection.getField(packetClass, double.class, 0);
+ Reflection.FieldAccessor posY = Reflection.getField(packetClass, double.class, 1);
+ Reflection.FieldAccessor posZ = Reflection.getField(packetClass, double.class, 2);
+
+ return (packet, x, y, z) -> {
+ posX.set(packet, x);
+ posY.set(packet, y);
+ posZ.set(packet, z);
+ };
+ }
+
+ @Override
+ public BountifulWrapper.UUIDSetter getUUIDSetter(Class> packetClass) {
+ Reflection.FieldAccessor uuidField = Reflection.getField(packetClass, UUID.class, 0);
+
+ return uuidField::set;
+ }
}
diff --git a/SpigotCore_Main/build.gradle b/SpigotCore_Main/build.gradle
index a8b5675..c225092 100644
--- a/SpigotCore_Main/build.gradle
+++ b/SpigotCore_Main/build.gradle
@@ -48,6 +48,7 @@ dependencies {
compileOnly 'com.mojang:authlib:1.5.25'
compileOnly 'mysql:mysql-connector-java:5.1.49'
compileOnly 'com.viaversion:viaversion-api:4.3.1'
+ compileOnly 'it.unimi.dsi:fastutil:8.5.6'
compileOnly swdep("WorldEdit-1.12")
implementation 'net.wesjd:anvilgui:1.5.3-SNAPSHOT'
diff --git a/SpigotCore_Main/src/de/steamwar/core/BountifulWrapper.java b/SpigotCore_Main/src/de/steamwar/core/BountifulWrapper.java
index 8b22c31..f71d234 100644
--- a/SpigotCore_Main/src/de/steamwar/core/BountifulWrapper.java
+++ b/SpigotCore_Main/src/de/steamwar/core/BountifulWrapper.java
@@ -23,6 +23,8 @@ import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.entity.Player;
+import java.util.UUID;
+
public class BountifulWrapper {
private BountifulWrapper() {}
@@ -32,5 +34,19 @@ public class BountifulWrapper {
void playPling(Player player);
void sendMessage(Player player, ChatMessageType type, BaseComponent... msg);
+
+ Object getDataWatcherObject(int index, Class> type);
+ Object getDataWatcherItem(Object dataWatcherObject, Object value);
+
+ PositionSetter getPositionSetter(Class> packetClass, int fieldOffset8);
+ UUIDSetter getUUIDSetter(Class> packetClass);
+ }
+
+ public interface PositionSetter {
+ void set(Object packet, double x, double y, double z);
+ }
+
+ public interface UUIDSetter {
+ void set(Object packet, UUID uuid);
}
}
diff --git a/SpigotCore_Main/src/de/steamwar/core/FlatteningWrapper.java b/SpigotCore_Main/src/de/steamwar/core/FlatteningWrapper.java
index 9da4b20..3f5f205 100644
--- a/SpigotCore_Main/src/de/steamwar/core/FlatteningWrapper.java
+++ b/SpigotCore_Main/src/de/steamwar/core/FlatteningWrapper.java
@@ -38,5 +38,15 @@ public class FlatteningWrapper {
Material getMaterial(String material);
Material getDye(int colorCode);
ItemStack setSkullOwner(String player);
+
+ Object getPose(EntityPose pose);
+ void setNamedSpawnPacketDataWatcher(Object packet);
+ Object formatDisplayName(String displayName);
+ }
+
+ public enum EntityPose {
+ NORMAL,
+ SNEAKING,
+ SWIMMING;
}
}
diff --git a/SpigotCore_Main/src/de/steamwar/core/ProtocolWrapper.java b/SpigotCore_Main/src/de/steamwar/core/ProtocolWrapper.java
new file mode 100644
index 0000000..a1f219b
--- /dev/null
+++ b/SpigotCore_Main/src/de/steamwar/core/ProtocolWrapper.java
@@ -0,0 +1,48 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.mojang.authlib.GameProfile;
+import org.bukkit.entity.EntityType;
+
+public interface ProtocolWrapper {
+
+ Class> itemStack = Reflection.getClass("{nms.world.item}.ItemStack");
+ Class> spawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutSpawnEntity");
+ Class> spawnLivingPacket = Core.getVersion() > 18 ? ProtocolWrapper.spawnPacket : Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutSpawnEntityLiving");
+ Class> equipmentPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityEquipment");
+ Class> playerInfoPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo");
+ Class> playerInfoDataClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo$PlayerInfoData");
+ Class> enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "{nms.world.level}.EnumGamemode" : "{nms}.WorldSettings$EnumGamemode");
+ Class> iChatBaseComponent = Reflection.getClass("{nms.network.chat}.IChatBaseComponent");
+
+ // 0: hand, 1: offhand, 2: feet, 3: legs, 4: chest, 5: head
+ Object[] itemSlots = Core.getVersion() > 8 ? Reflection.getClass("{nms.world.entity}.EnumItemSlot").getEnumConstants() : new Integer[]{0, 0, 1, 2, 3, 4};
+
+ ProtocolWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
+
+ void setEquipmentPacketStack(Object packet, Object slot, Object stack);
+
+ void setSpawnPacketType(Object packet, EntityType type);
+
+ Object playerInfoDataConstructor(Object packet, GameProfile profile, Object mode);
+
+}
diff --git a/SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java b/SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java
new file mode 100644
index 0000000..7e0e7a7
--- /dev/null
+++ b/SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java
@@ -0,0 +1,76 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.entity;
+
+import de.steamwar.core.BountifulWrapper;
+import de.steamwar.core.Core;
+import org.bukkit.Location;
+import org.bukkit.entity.EntityType;
+
+import java.util.function.Consumer;
+
+public class RArmorStand extends REntity {
+
+ private static int sizeIndex() {
+ switch(Core.getVersion()) {
+ case 8:
+ case 9:
+ return 10;
+ case 10:
+ case 12:
+ return 11;
+ case 14:
+ return 13;
+ case 15:
+ return 14;
+ case 18:
+ case 19:
+ default:
+ return 15;
+ }
+ }
+
+ private static final Object sizeWatcher = BountifulWrapper.impl.getDataWatcherObject(sizeIndex(), Byte.class);
+
+ private final Size size;
+
+ public RArmorStand(REntityServer server, Location location, Size size) {
+ super(server, EntityType.ARMOR_STAND, location);
+ this.size = size;
+ }
+
+ @Override
+ void spawn(Consumer