CoreEntity #220
@ -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) {
|
||||
Lixfel markierte diese Unterhaltung als gelöst
Veraltet
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
72
SpigotCore_18/src/de/steamwar/core/ProtocolWrapper18.java
Normale Datei
72
SpigotCore_18/src/de/steamwar/core/ProtocolWrapper18.java
Normale Datei
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<List> 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<Integer> spawnLivingType = Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
|
||||
@Override
|
||||
public void setSpawnPacketType(Object packet, EntityType type) {
|
||||
Lixfel markierte diese Unterhaltung als gelöst
YoyoNow
hat
Könnte ich im gleichen Schritt auch hier Maps bekommen? Damit ich im LobbySystem die Maps endlich anpassen kann. Könnte ich im gleichen Schritt auch hier Maps bekommen? Damit ich im LobbySystem die Maps endlich anpassen kann.
|
||||
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);
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
71
SpigotCore_19/src/de/steamwar/core/ProtocolWrapper19.java
Normale Datei
71
SpigotCore_19/src/de/steamwar/core/ProtocolWrapper19.java
Normale Datei
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<List> 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);
|
||||
}
|
||||
}
|
@ -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<Class<?>, 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<Integer> posX = Reflection.getField(packetClass, int.class, fieldOffset8);
|
||||
Reflection.FieldAccessor<Integer> posY = Reflection.getField(packetClass, int.class, fieldOffset8+1);
|
||||
Reflection.FieldAccessor<Integer> 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) -> {};
|
||||
}
|
||||
}
|
||||
|
@ -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 : "";
|
||||
}
|
||||
}
|
||||
|
82
SpigotCore_8/src/de/steamwar/core/ProtocolWrapper8.java
Normale Datei
82
SpigotCore_8/src/de/steamwar/core/ProtocolWrapper8.java
Normale Datei
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Integer> spawnLivingType = Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
|
||||
private static final Map<EntityType, Object> 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);
|
||||
}
|
||||
}
|
@ -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<Double> posX = Reflection.getField(packetClass, double.class, 0);
|
||||
Reflection.FieldAccessor<Double> posY = Reflection.getField(packetClass, double.class, 1);
|
||||
Reflection.FieldAccessor<Double> 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<UUID> uuidField = Reflection.getField(packetClass, UUID.class, 0);
|
||||
|
||||
return uuidField::set;
|
||||
}
|
||||
}
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
48
SpigotCore_Main/src/de/steamwar/core/ProtocolWrapper.java
Normale Datei
48
SpigotCore_Main/src/de/steamwar/core/ProtocolWrapper.java
Normale Datei
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
}
|
76
SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java
Normale Datei
76
SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java
Normale Datei
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Object> packetSink) {
|
||||
super.spawn(packetSink);
|
||||
packetSink.accept(getDataWatcherPacket(sizeWatcher, size.value));
|
||||
}
|
||||
|
||||
public enum Size {
|
||||
NORMAL((byte) 0x00),
|
||||
SMALL((byte) 0x01),
|
||||
MARKER((byte) 0x10);
|
||||
|
||||
private final byte value;
|
||||
|
||||
Size(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
341
SpigotCore_Main/src/de/steamwar/entity/REntity.java
Normale Datei
341
SpigotCore_Main/src/de/steamwar/entity/REntity.java
Normale Datei
@ -0,0 +1,341 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import com.comphenix.tinyprotocol.Reflection;
|
||||
import de.steamwar.core.*;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class REntity {
|
||||
|
||||
private static final Object entityStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(0, Byte.class);
|
||||
private static final Object sneakingDataWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 6 : 0, FlatteningWrapper.impl.getPose(FlatteningWrapper.EntityPose.NORMAL).getClass());
|
||||
private static final Object bowDrawnWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 7 : 6, Byte.class);
|
||||
private static final Object nameWatcher = BountifulWrapper.impl.getDataWatcherObject(2, Core.getVersion() > 12 ? Optional.class : String.class); // Optional<IChatBaseComponent>
|
||||
private static final Object nameVisibleWatcher = BountifulWrapper.impl.getDataWatcherObject(3, Boolean.class);
|
||||
|
||||
private static int entityIdCounter = -1;
|
||||
private static final Random random = new Random();
|
||||
|
||||
private final REntityServer server;
|
||||
private final EntityType entityType;
|
||||
protected final int entityId;
|
||||
protected final UUID uuid;
|
||||
|
||||
protected double x;
|
||||
protected double y;
|
||||
protected double z;
|
||||
private byte yaw;
|
||||
private byte pitch;
|
||||
private byte headYaw;
|
||||
|
||||
private boolean invisible;
|
||||
private FlatteningWrapper.EntityPose pose;
|
||||
private boolean bowDrawn;
|
||||
private int fireTick;
|
||||
private String displayName;
|
||||
protected final Map<Object, ItemStack> itemSlots;
|
||||
|
||||
public REntity(REntityServer server, EntityType entityType, Location location) {
|
||||
this(server, entityType, new UUID(random.nextLong() & -61441L | 16384L, random.nextLong() & 4611686018427387903L | -9223372036854775808L), location);
|
||||
}
|
||||
|
||||
protected REntity(REntityServer server, EntityType entityType, UUID uuid, Location location) {
|
||||
this.server = server;
|
||||
this.entityType = entityType;
|
||||
this.entityId = entityIdCounter--;
|
||||
this.uuid = uuid;
|
||||
|
||||
this.x = location.getX();
|
||||
this.y = location.getY();
|
||||
this.z = location.getZ();
|
||||
this.headYaw = this.yaw = rotToByte(location.getYaw());
|
||||
this.pitch = rotToByte(location.getPitch());
|
||||
|
||||
this.itemSlots = entityType == EntityType.PLAYER ? new HashMap<>() : null;
|
||||
|
||||
server.addEntity(this);
|
||||
}
|
||||
|
||||
public void move(double locX, double locY, double locZ, float pitch, float yaw, byte headYaw) {
|
||||
server.preEntityMove(this, locX, locZ);
|
||||
double fromX = this.x;
|
||||
double fromZ = this.z;
|
||||
this.x = locX;
|
||||
this.y = locY;
|
||||
this.z = locZ;
|
||||
this.yaw = rotToByte(yaw);
|
||||
this.pitch = rotToByte(pitch);
|
||||
server.updateEntity(this, getTeleportPacket());
|
||||
if(this.headYaw != headYaw) {
|
||||
this.headYaw = headYaw;
|
||||
server.updateEntity(this, getHeadRotationPacket());
|
||||
}
|
||||
server.postEntityMove(this, fromX, fromZ);
|
||||
}
|
||||
|
||||
private static final Class<?> animationPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutAnimation");
|
||||
private static final Reflection.FieldAccessor<Integer> animationEntity = Reflection.getField(animationPacket, int.class, Core.getVersion() > 15 ? 6 : 0);
|
||||
private static final Reflection.FieldAccessor<Integer> animationAnimation = Reflection.getField(animationPacket, int.class, Core.getVersion() > 15 ? 7 : 1);
|
||||
public void showAnimation(byte animation) {
|
||||
Object packet = Reflection.newInstance(animationPacket);
|
||||
animationEntity.set(packet, entityId);
|
||||
animationAnimation.set(packet, (int) animation);
|
||||
server.updateEntity(this, packet);
|
||||
}
|
||||
|
||||
private static final Class<?> velocityPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityVelocity");
|
||||
private static final Reflection.FieldAccessor<Integer> velocityEntity = Reflection.getField(velocityPacket, int.class, 0);
|
||||
private static final Reflection.FieldAccessor<Integer> velocityX = Reflection.getField(velocityPacket, int.class, 1);
|
||||
private static final Reflection.FieldAccessor<Integer> velocityY = Reflection.getField(velocityPacket, int.class, 2);
|
||||
private static final Reflection.FieldAccessor<Integer> velocityZ = Reflection.getField(velocityPacket, int.class, 3);
|
||||
public void setVelocity(double dX, double dY, double dZ) {
|
||||
Object packet = Reflection.newInstance(velocityPacket);
|
||||
velocityEntity.set(packet, entityId);
|
||||
velocityX.set(packet, calcVelocity(dX));
|
||||
velocityY.set(packet, calcVelocity(dY));
|
||||
velocityZ.set(packet, calcVelocity(dZ));
|
||||
server.updateEntity(this, packet);
|
||||
}
|
||||
|
||||
private static final Class<?> statusPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityStatus");
|
||||
private static final Reflection.FieldAccessor<Integer> statusEntity = Reflection.getField(statusPacket, int.class, 0);
|
||||
private static final Reflection.FieldAccessor<Byte> statusStatus = Reflection.getField(statusPacket, byte.class, 0);
|
||||
public void showDamage() {
|
||||
Object packet = Reflection.newInstance(statusPacket);
|
||||
statusEntity.set(packet, entityId);
|
||||
statusStatus.set(packet, (byte) 2);
|
||||
server.updateEntity(this, packet);
|
||||
}
|
||||
|
||||
public void setPose(FlatteningWrapper.EntityPose pose) {
|
||||
this.pose = pose;
|
||||
if(Core.getVersion() > 12) {
|
||||
server.updateEntity(this, getDataWatcherPacket(sneakingDataWatcher, FlatteningWrapper.impl.getPose(pose)));
|
||||
} else {
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnFire(boolean perma) {
|
||||
fireTick = perma ? -1 : 21;
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
|
||||
public void setInvisible(boolean invisible) {
|
||||
this.invisible = invisible;
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
|
||||
public void setBowDrawn(boolean drawn, boolean offHand) {
|
||||
bowDrawn = drawn;
|
||||
if(Core.getVersion() > 8){
|
||||
server.updateEntity(this, getDataWatcherPacket(bowDrawnWatcher, (byte) ((drawn ? 1 : 0) + (offHand ? 2 : 0))));
|
||||
}else{
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
server.updateEntity(this, getDataWatcherPacket(
|
||||
nameWatcher, FlatteningWrapper.impl.formatDisplayName(displayName),
|
||||
nameVisibleWatcher, displayName != null
|
||||
));
|
||||
}
|
||||
|
||||
public void setItem(Object slot, ItemStack stack) {
|
||||
itemSlots.put(slot, stack);
|
||||
server.updateEntity(this, getEquipmentPacket(slot, stack));
|
||||
}
|
||||
|
||||
public void die() {
|
||||
server.removeEntity(this);
|
||||
}
|
||||
|
||||
private static final Function<REntity, Object> livingSpawnPacketGenerator = entitySpawnPacketGenerator(ProtocolWrapper.spawnLivingPacket, 2);
|
||||
private static final Function<REntity, Object> spawnPacketGenerator = entitySpawnPacketGenerator(ProtocolWrapper.spawnPacket, 1);
|
||||
void spawn(Consumer<Object> packetSink) {
|
||||
if(entityType.isAlive()) {
|
||||
packetSink.accept(livingSpawnPacketGenerator.apply(this));
|
||||
} else {
|
||||
packetSink.accept(spawnPacketGenerator.apply(this));
|
||||
}
|
||||
|
||||
postSpawn(packetSink);
|
||||
}
|
||||
|
||||
protected void postSpawn(Consumer<Object> packetSink) {
|
||||
if(headYaw != 0) {
|
||||
packetSink.accept(getHeadRotationPacket());
|
||||
}
|
||||
|
||||
if(Core.getVersion() > 12 && pose != FlatteningWrapper.EntityPose.NORMAL) {
|
||||
packetSink.accept(getDataWatcherPacket(sneakingDataWatcher, FlatteningWrapper.impl.getPose(pose)));
|
||||
}
|
||||
|
||||
byte status = getEntityStatus();
|
||||
if(status != 0) {
|
||||
packetSink.accept(getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
|
||||
if(displayName != null) {
|
||||
packetSink.accept(getDataWatcherPacket(nameWatcher, FlatteningWrapper.impl.formatDisplayName(displayName), nameVisibleWatcher, true));
|
||||
}
|
||||
}
|
||||
|
||||
void tick() {
|
||||
if(fireTick > 0) {
|
||||
fireTick--;
|
||||
if(fireTick == 0) {
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> destroyPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityDestroy");
|
||||
private static final Reflection.FieldAccessor<?> destroyEntities;
|
||||
static {
|
||||
if(Core.getVersion() > 15)
|
||||
destroyEntities = Reflection.getField(destroyPacket, IntList.class, 0);
|
||||
else
|
||||
destroyEntities = Reflection.getField(destroyPacket, int[].class, 0);
|
||||
}
|
||||
void despawn(Consumer<Object> packetSink){
|
||||
Object packet = Reflection.newInstance(destroyPacket);
|
||||
destroyEntities.set(packet, Core.getVersion() > 15 ? new IntArrayList(new int[]{entityId}) : new int[]{entityId});
|
||||
packetSink.accept(packet);
|
||||
}
|
||||
|
||||
double x() {
|
||||
return x;
|
||||
}
|
||||
|
||||
double z() {
|
||||
return z;
|
||||
}
|
||||
|
||||
private byte getEntityStatus() {
|
||||
byte status = 0;
|
||||
|
||||
if(fireTick != 0)
|
||||
status |= 1;
|
||||
if(pose == FlatteningWrapper.EntityPose.SNEAKING)
|
||||
status |= 2;
|
||||
if(Core.getVersion() == 8 && bowDrawn)
|
||||
status |= 0x10;
|
||||
if(invisible)
|
||||
status |= 0x20;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
private static final Class<?> metadataPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityMetadata");
|
||||
private static final Reflection.FieldAccessor<Integer> metadataEntity = Reflection.getField(metadataPacket, int.class, 0);
|
||||
private static final Reflection.FieldAccessor<List> metadataMetadata = Reflection.getField(metadataPacket, List.class, 0);
|
||||
|
||||
protected Object getDataWatcherPacket(Object... dataWatcherKeyValues) {
|
||||
Object packet = Reflection.newInstance(metadataPacket);
|
||||
metadataEntity.set(packet, entityId);
|
||||
|
||||
ArrayList<Object> nativeWatchers = new ArrayList<>(1);
|
||||
for(int i = 0; i < dataWatcherKeyValues.length; i+=2) {
|
||||
nativeWatchers.add(BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i+1]));
|
||||
}
|
||||
metadataMetadata.set(packet, nativeWatchers);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final Class<?> teleportPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityTeleport");
|
||||
private static final Reflection.FieldAccessor<Integer> teleportEntity = Reflection.getField(teleportPacket, int.class, 0);
|
||||
private static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, 1);
|
||||
private static final Reflection.FieldAccessor<Byte> teleportYaw = Reflection.getField(teleportPacket, byte.class, 0);
|
||||
private static final Reflection.FieldAccessor<Byte> teleportPitch = Reflection.getField(teleportPacket, byte.class, 1);
|
||||
private Object getTeleportPacket(){
|
||||
Object packet = Reflection.newInstance(teleportPacket);
|
||||
teleportEntity.set(packet, entityId);
|
||||
teleportPosition.set(packet, x, y, z);
|
||||
teleportYaw.set(packet, yaw);
|
||||
teleportPitch.set(packet, pitch);
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final Class<?> headRotationPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityHeadRotation");
|
||||
private static final Reflection.FieldAccessor<Integer> headRotationEntity = Reflection.getField(headRotationPacket, int.class, 0);
|
||||
private static final Reflection.FieldAccessor<Byte> headRotationYaw = Reflection.getField(headRotationPacket, byte.class, 0);
|
||||
private Object getHeadRotationPacket(){
|
||||
Object packet = Reflection.newInstance(headRotationPacket);
|
||||
headRotationEntity.set(packet, entityId);
|
||||
headRotationYaw.set(packet, headYaw);
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final Reflection.FieldAccessor<Integer> equipmentEntity = Reflection.getField(ProtocolWrapper.equipmentPacket, int.class, 0);
|
||||
|
||||
private static final Class<?> craftItemStack = Reflection.getClass("{obc}.inventory.CraftItemStack");
|
||||
private static final Reflection.MethodInvoker asNMSCopy = Reflection.getTypedMethod(REntity.craftItemStack, "asNMSCopy", ProtocolWrapper.itemStack, ItemStack.class);
|
||||
protected Object getEquipmentPacket(Object slot, ItemStack stack){
|
||||
Object packet = Reflection.newInstance(ProtocolWrapper.equipmentPacket);
|
||||
equipmentEntity.set(packet, entityId);
|
||||
ProtocolWrapper.impl.setEquipmentPacketStack(packet, slot, asNMSCopy.invoke(null, stack));
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static Function<REntity, Object> entitySpawnPacketGenerator(Class<?> spawnPacket, int posOffset8) {
|
||||
BountifulWrapper.UUIDSetter uuid = BountifulWrapper.impl.getUUIDSetter(spawnPacket);
|
||||
Function<REntity, Object> packetGenerator = spawnPacketGenerator(spawnPacket, posOffset8);
|
||||
|
||||
return entity -> {
|
||||
Object packet = packetGenerator.apply(entity);
|
||||
uuid.set(packet, entity.uuid);
|
||||
ProtocolWrapper.impl.setSpawnPacketType(packet, entity.entityType);
|
||||
return packet;
|
||||
};
|
||||
}
|
||||
|
||||
protected static Function<REntity, Object> spawnPacketGenerator(Class<?> spawnPacket, int posOffset8) {
|
||||
Reflection.FieldAccessor<Integer> entityId = Reflection.getField(spawnPacket, int.class, 0);
|
||||
BountifulWrapper.PositionSetter position = BountifulWrapper.impl.getPositionSetter(spawnPacket, posOffset8);
|
||||
|
||||
return entity -> {
|
||||
Object packet = Reflection.newInstance(spawnPacket);
|
||||
entityId.set(packet, entity.entityId);
|
||||
position.set(packet, entity.x, entity.y, entity.z);
|
||||
return packet;
|
||||
};
|
||||
}
|
||||
|
||||
private byte rotToByte(float rot) {
|
||||
return (byte)((int)(rot * 256.0F / 360.0F));
|
||||
}
|
||||
|
||||
private int calcVelocity(double value) {
|
||||
return (int)(Math.max(-3.9, Math.min(value, 3.9)) * 8000);
|
||||
}
|
||||
}
|
212
SpigotCore_Main/src/de/steamwar/entity/REntityServer.java
Normale Datei
212
SpigotCore_Main/src/de/steamwar/entity/REntityServer.java
Normale Datei
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.core.Core;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
public class REntityServer implements Listener {
|
||||
|
||||
private static final HashSet<REntity> emptyEntities = new HashSet<>(0);
|
||||
private static final HashSet<Player> emptyPlayers = new HashSet<>(0);
|
||||
|
||||
private final HashMap<Long, HashSet<REntity>> entities = new HashMap<>();
|
||||
private final HashMap<Long, HashSet<Player>> players = new HashMap<>();
|
||||
private final HashMap<Player, Location> lastLocation = new HashMap<>();
|
||||
|
||||
public REntityServer() {
|
||||
Core.getInstance().getServer().getPluginManager().registerEvents(this, Core.getInstance());
|
||||
}
|
||||
|
||||
public void addPlayer(Player player) {
|
||||
Location location = player.getLocation();
|
||||
lastLocation.put(player, location);
|
||||
forChunkInView(player, location, (x, z) -> addPlayerToChunk(player, x, z));
|
||||
}
|
||||
|
||||
public void removePlayer(Player player) {
|
||||
Location location = lastLocation.remove(player);
|
||||
forChunkInView(player, location, (x, z) -> removePlayerFromChunk(player, x, z));
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for(Player player : lastLocation.keySet().toArray(new Player[0])) {
|
||||
removePlayer(player);
|
||||
}
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
void addEntity(REntity entity) {
|
||||
entities.computeIfAbsent(entityToId(entity), i -> new HashSet<>()).add(entity);
|
||||
entity.spawn(packet -> updateEntity(entity, packet));
|
||||
}
|
||||
|
||||
void preEntityMove(REntity entity, double toX, double toZ) {
|
||||
long fromId = entityToId(entity);
|
||||
long toId = posToId(toX, toZ);
|
||||
if(fromId == toId)
|
||||
return;
|
||||
|
||||
onMissing(players.get(fromId), players.get(toId), entity::despawn);
|
||||
}
|
||||
|
||||
void postEntityMove(REntity entity, double fromX, double fromZ) {
|
||||
long fromId = posToId(fromX, fromZ);
|
||||
long toId = entityToId(entity);
|
||||
if(fromId == toId)
|
||||
return;
|
||||
|
||||
onMissing(players.get(toId), players.get(fromId), entity::spawn);
|
||||
}
|
||||
|
||||
void updateEntity(REntity entity, Object packet) {
|
||||
for(Player player : players.getOrDefault(entityToId(entity), emptyPlayers)) {
|
||||
TinyProtocol.instance.sendPacket(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
void removeEntity(REntity entity) {
|
||||
entity.despawn(packet -> updateEntity(entity, packet));
|
||||
long id = entityToId(entity);
|
||||
HashSet<REntity> entitiesInChunk = entities.get(id);
|
||||
entitiesInChunk.remove(entity);
|
||||
if(entitiesInChunk.isEmpty())
|
||||
entities.remove(id);
|
||||
}
|
||||
|
||||
//TODO on settings, on respawn? on boatmove?
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onMove(PlayerMoveEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
Location from = lastLocation.get(player);
|
||||
Location to = e.getTo();
|
||||
if(from == null || to == null)
|
||||
return;
|
||||
|
||||
int fromX = posToChunk(from.getX());
|
||||
int fromZ = posToChunk(from.getZ());
|
||||
int toX = posToChunk(to.getX());
|
||||
int toZ = posToChunk(to.getZ());
|
||||
if(fromX == toX && fromZ == toZ)
|
||||
return;
|
||||
|
||||
int viewDistance = viewRadius(player);
|
||||
forChunkInView(player, from, (x, z) -> {
|
||||
if(Math.abs(x - toX) > viewDistance || Math.abs(z - toX) > viewDistance) {
|
||||
removePlayerFromChunk(player, x, z);
|
||||
}
|
||||
});
|
||||
forChunkInView(player, to, (x, z) -> {
|
||||
if(Math.abs(x - fromX) > viewDistance || Math.abs(z - fromZ) > viewDistance) {
|
||||
addPlayerToChunk(player, x, z);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
Location location = lastLocation.remove(player);
|
||||
if(location == null)
|
||||
return;
|
||||
|
||||
forChunkInView(player, location, (x, z) -> players.get(chunkToId(x, z)).remove(player));
|
||||
}
|
||||
|
||||
private void onMissing(HashSet<Player> of, HashSet<Player> in, Consumer<Consumer<Object>> packetProvider) {
|
||||
for(Player player : of) {
|
||||
if(!in.contains(player)) {
|
||||
packetProvider.accept(packet -> TinyProtocol.instance.sendPacket(player, packet)); //TODO multi packet generation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void forChunkInView(Player player, Location location, BiConsumer<Integer, Integer> func) {
|
||||
int chunkX = posToChunk(location.getX());
|
||||
int chunkZ = posToChunk(location.getZ());
|
||||
int viewDistance = viewRadius(player);
|
||||
|
||||
for(int x = chunkX - viewDistance; x <= chunkX + viewDistance; x++) {
|
||||
for(int z = chunkZ - viewDistance; z <= chunkZ + viewDistance; z++) {
|
||||
func.accept(x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPlayerToChunk(Player player, int x, int z) {
|
||||
long id = chunkToId(x, z);
|
||||
players.computeIfAbsent(id, i -> new HashSet<>()).add(player);
|
||||
for(REntity entity : entities.getOrDefault(id, emptyEntities)) {
|
||||
entity.spawn(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
}
|
||||
}
|
||||
|
||||
private void removePlayerFromChunk(Player player, int x, int z) {
|
||||
long id = chunkToId(x, z);
|
||||
players.get(id).remove(player);
|
||||
for(REntity entity : entities.getOrDefault(id, emptyEntities)) {
|
||||
entity.despawn(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
}
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
for(HashSet<REntity> entitiesInChunk : entities.values()) {
|
||||
for(REntity entity : entitiesInChunk) {
|
||||
entity.tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int posToChunk(double coord) {
|
||||
return (int)(coord / 16) - (coord < 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
private int viewRadius(Player player) {
|
||||
return player.getClientViewDistance() / 2;
|
||||
}
|
||||
|
||||
private long entityToId(REntity entity) {
|
||||
return posToId(entity.x(), entity.z());
|
||||
}
|
||||
|
||||
private long posToId(double x, double z) {
|
||||
return chunkToId(posToChunk(x), posToChunk(z));
|
||||
}
|
||||
|
||||
private long chunkToId(int x, int z) {
|
||||
//TODO negative coord clash?
|
||||
return (long) x << 32 + z;
|
||||
}
|
||||
}
|
126
SpigotCore_Main/src/de/steamwar/entity/RPlayer.java
Normale Datei
126
SpigotCore_Main/src/de/steamwar/entity/RPlayer.java
Normale Datei
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import com.comphenix.tinyprotocol.Reflection;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.FlatteningWrapper;
|
||||
import de.steamwar.core.ProtocolWrapper;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class RPlayer extends REntity {
|
||||
|
||||
/*
|
||||
private static final String SCOREBOARD_TEAMNAME = "Replay";
|
||||
private static final Team team;
|
||||
|
||||
static {
|
||||
if(FightScoreboard.getBukkit().getTeam(SCOREBOARD_TEAMNAME) == null)
|
||||
team = FightScoreboard.getBukkit().registerNewTeam(SCOREBOARD_TEAMNAME);
|
||||
else
|
||||
team = FightScoreboard.getBukkit().getTeam(SCOREBOARD_TEAMNAME);
|
||||
team.setNameTagVisibility(NameTagVisibility.NEVER);
|
||||
}
|
||||
*/
|
||||
|
||||
private static int skinPartsIndex() {
|
||||
switch(Core.getVersion()) {
|
||||
case 8:
|
||||
return 10;
|
||||
case 9:
|
||||
return 12;
|
||||
case 10:
|
||||
case 12:
|
||||
return 13;
|
||||
case 14:
|
||||
return 15;
|
||||
case 15:
|
||||
return 16;
|
||||
case 18:
|
||||
case 19:
|
||||
default:
|
||||
return 17;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(skinPartsIndex(), Byte.class);
|
||||
|
||||
private final String name;
|
||||
|
||||
public RPlayer(REntityServer server, UUID uuid, String name, Location location) {
|
||||
super(server, EntityType.PLAYER, uuid, location);
|
||||
this.name = name;
|
||||
//team.addEntry(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
void spawn(Consumer<Object> packetSink) {
|
||||
packetSink.accept(getPlayerInfoPacket(addPlayer));
|
||||
packetSink.accept(getNamedSpawnPacket());
|
||||
packetSink.accept(getDataWatcherPacket(skinPartsDataWatcher, (byte) 0x7F));
|
||||
|
||||
for (Map.Entry<Object, ItemStack> entry : itemSlots.entrySet()) {
|
||||
packetSink.accept(getEquipmentPacket(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
|
||||
postSpawn(packetSink);
|
||||
}
|
||||
|
||||
@Override
|
||||
void despawn(Consumer<Object> packetSink) {
|
||||
//team.removeEntry(name);
|
||||
super.despawn(packetSink);
|
||||
packetSink.accept(getPlayerInfoPacket(removePlayer));
|
||||
}
|
||||
|
||||
private static final Class<?> playerInfoActionClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo$EnumPlayerInfoAction");
|
||||
private static final Object addPlayer = playerInfoActionClass.getEnumConstants()[0];
|
||||
private static final Reflection.FieldAccessor<?> playerInfoAction = Reflection.getField(ProtocolWrapper.playerInfoPacket, playerInfoActionClass, 0);
|
||||
private static final Object removePlayer = playerInfoActionClass.getEnumConstants()[4];
|
||||
private static final Reflection.FieldAccessor<List> playerInfoData = Reflection.getField(ProtocolWrapper.playerInfoPacket, List.class, 0);
|
||||
private static final Object creative = ProtocolWrapper.enumGamemode.getEnumConstants()[Core.getVersion() > 15 ? 1 : 2];
|
||||
private Object getPlayerInfoPacket(Object action){
|
||||
Object packet = Reflection.newInstance(ProtocolWrapper.playerInfoPacket);
|
||||
playerInfoAction.set(packet, action);
|
||||
playerInfoData.set(packet, Collections.singletonList(ProtocolWrapper.impl.playerInfoDataConstructor(packet, new GameProfile(uuid, name), creative)));
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final Class<?> namedSpawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutNamedEntitySpawn");
|
||||
private static final Function<REntity, Object> namedSpawnPacketGenerator = spawnPacketGenerator(namedSpawnPacket, 1);
|
||||
private static final Reflection.FieldAccessor<UUID> namedSpawnUUID = Reflection.getField(namedSpawnPacket, UUID.class, 0);
|
||||
private Object getNamedSpawnPacket() {
|
||||
Object packet = namedSpawnPacketGenerator.apply(this);
|
||||
namedSpawnUUID.set(packet, uuid);
|
||||
FlatteningWrapper.impl.setNamedSpawnPacketDataWatcher(packet);
|
||||
return packet;
|
||||
}
|
||||
}
|
In neuem Issue referenzieren
Einen Benutzer sperren
Kannst du neben standing und sneaking bitte noch swimming hinzufügen? Das ist etwas was besonders in Replays und dem FightSystem, eine Sache hinzufügt, womit wir schon 1 oder 2 mal Probleme bekommen haben wegen Reports.