Lixfel
46325c0049
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Signed-off-by: Lixfel <agga-games@gmx.de>
349 Zeilen
16 KiB
Java
349 Zeilen
16 KiB
Java
/*
|
|
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.fightsystem.record;
|
|
|
|
import com.comphenix.tinyprotocol.Reflection;
|
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
|
import com.mojang.authlib.GameProfile;
|
|
import de.steamwar.core.Core;
|
|
import de.steamwar.fightsystem.FightSystem;
|
|
import de.steamwar.fightsystem.fight.Fight;
|
|
import de.steamwar.fightsystem.listener.FightScoreboard;
|
|
import de.steamwar.fightsystem.utils.*;
|
|
import de.steamwar.sql.SteamwarUser;
|
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
|
import it.unimi.dsi.fastutil.ints.IntList;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.enchantments.Enchantment;
|
|
import org.bukkit.entity.EntityType;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.scoreboard.NameTagVisibility;
|
|
import org.bukkit.scoreboard.Team;
|
|
|
|
import java.util.*;
|
|
import java.util.logging.Level;
|
|
|
|
public class REntity {
|
|
|
|
private static final Map<Integer, REntity> entities = new HashMap<>();
|
|
|
|
public static REntity getEntity(int internalId){
|
|
return entities.get(internalId);
|
|
}
|
|
|
|
private static Object entityStatusWatcher;
|
|
private static Object sneakingDataWatcher;
|
|
private static Object bowDrawnWatcher;
|
|
public static void initWatchers() {
|
|
// not during <clinit> to prevent cyclic class init.
|
|
entityStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(0, Byte.class);
|
|
sneakingDataWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 6 : 0, BlockIdWrapper.impl.getPose(true).getClass());
|
|
bowDrawnWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 7 : 6, Byte.class);
|
|
}
|
|
|
|
|
|
public static void tickFire() {
|
|
entities.forEach((integer, entity) -> {
|
|
if(entity.fireTick > 0) {
|
|
entity.fireTick--;
|
|
if(entity.fireTick == 0) {
|
|
ProtocolAPI.broadcastPacket(entity.getDataWatcherPacket(entityStatusWatcher, (byte)0));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void playerJoins(Player player) {
|
|
for(REntity entity : entities.values()){
|
|
if(entity.entityType == EntityType.PLAYER){
|
|
TinyProtocol.instance.sendPacket(player, entity.getPlayerInfoPacket());
|
|
TinyProtocol.instance.sendPacket(player, entity.getNamedSpawnPacket());
|
|
for (Map.Entry<String, ItemStack> entry : entity.itemSlots.entrySet()) {
|
|
TinyProtocol.instance.sendPacket(player, entity.getEquipmentPacket(entry.getKey(), entry.getValue()));
|
|
}
|
|
}else{
|
|
TinyProtocol.instance.sendPacket(player, entity.getSpawnEntityPacket());
|
|
}
|
|
TinyProtocol.instance.sendPacket(player, entity.getTeleportPacket());
|
|
TinyProtocol.instance.sendPacket(player, entity.getHeadRotationPacket());
|
|
|
|
if(entity.fireTick != 0) {
|
|
TinyProtocol.instance.sendPacket(player, entity.getDataWatcherPacket(entityStatusWatcher, (byte) 1));
|
|
}
|
|
if(entity.sneaks) {
|
|
TinyProtocol.instance.sendPacket(player, entity.getDataWatcherPacket(sneakingDataWatcher, BlockIdWrapper.impl.getPose(true)));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void dieAll(){
|
|
entities.forEach((id, entity) -> entity.broadcastDeath());
|
|
entities.clear();
|
|
}
|
|
|
|
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 entityCount = Integer.MAX_VALUE;
|
|
private static final Random random = new Random();
|
|
|
|
private final int internalId;
|
|
private final int entityId;
|
|
private final UUID uuid;
|
|
private final EntityType entityType;
|
|
private final String name;
|
|
private final Map<String, ItemStack> itemSlots = new HashMap<>();
|
|
|
|
private double locX;
|
|
private double locY;
|
|
private double locZ;
|
|
private byte yaw;
|
|
private byte pitch;
|
|
private byte headYaw;
|
|
private int fireTick;
|
|
private boolean sneaks;
|
|
|
|
private boolean playerSpawned = false;
|
|
|
|
public REntity(int internalId, int userId){
|
|
this.internalId = internalId;
|
|
this.entityType = EntityType.PLAYER;
|
|
this.entityId = entityCount--;
|
|
|
|
SteamwarUser user;
|
|
try {
|
|
user = SteamwarUser.get(userId);
|
|
} catch (SecurityException e) {
|
|
FightSystem.getPlugin().getLogger().log(Level.SEVERE, "Could not load user " + userId);
|
|
throw e;
|
|
}
|
|
|
|
this.uuid = user.getUUID();
|
|
this.name = user.getUserName();
|
|
entities.put(internalId, this);
|
|
|
|
ProtocolAPI.broadcastPacket(getPlayerInfoPacket());
|
|
team.addEntry(name);
|
|
}
|
|
|
|
public REntity(int internalId, EntityType entityType){
|
|
this.internalId = internalId;
|
|
this.entityType = entityType;
|
|
this.entityId = entityCount--;
|
|
this.name = null;
|
|
this.uuid = new UUID(random.nextLong() & -61441L | 16384L, random.nextLong() & 4611686018427387903L | -9223372036854775808L);
|
|
entities.put(internalId, this);
|
|
|
|
ProtocolAPI.broadcastPacket(getSpawnEntityPacket());
|
|
}
|
|
|
|
public void move(double locX, double locY, double locZ, float pitch, float yaw, byte headYaw){
|
|
this.locX = locX;
|
|
this.locY = locY;
|
|
this.locZ = locZ;
|
|
if(entityType == EntityType.PLAYER && !playerSpawned) {
|
|
ProtocolAPI.broadcastPacket(getNamedSpawnPacket());
|
|
playerSpawned = true;
|
|
}
|
|
|
|
this.yaw = (byte)((int)(yaw * 256.0F / 360.0F));
|
|
this.pitch = (byte)((int)(pitch * 256.0F / 360.0F));
|
|
this.headYaw = headYaw;
|
|
ProtocolAPI.broadcastPacket(getTeleportPacket());
|
|
ProtocolAPI.broadcastPacket(getHeadRotationPacket());
|
|
}
|
|
|
|
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 animation(byte animation) {
|
|
Object packet = Reflection.newInstance(animationPacket);
|
|
animationEntity.set(packet, entityId);
|
|
animationAnimation.set(packet, (int) animation);
|
|
ProtocolAPI.broadcastPacket(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));
|
|
ProtocolAPI.broadcastPacket(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 damage() {
|
|
Object packet = Reflection.newInstance(statusPacket);
|
|
statusEntity.set(packet, entityId);
|
|
statusStatus.set(packet, (byte) 2);
|
|
ProtocolAPI.broadcastPacket(packet);
|
|
}
|
|
|
|
public void sneak(boolean sneaking) {
|
|
sneaks = sneaking;
|
|
ProtocolAPI.broadcastPacket(getDataWatcherPacket(sneakingDataWatcher, BlockIdWrapper.impl.getPose(sneaking)));
|
|
}
|
|
|
|
public void setOnFire(boolean perma) {
|
|
if(!perma) {
|
|
fireTick = 21;
|
|
} else {
|
|
fireTick = -1;
|
|
}
|
|
|
|
ProtocolAPI.broadcastPacket(getDataWatcherPacket(entityStatusWatcher, (byte) 1));
|
|
}
|
|
|
|
public void setBowDrawn(boolean drawn, boolean offHand) {
|
|
if(Core.getVersion() > 8){
|
|
ProtocolAPI.broadcastPacket(getDataWatcherPacket(bowDrawnWatcher, (byte) ((drawn ? 1 : 0) + (offHand ? 2 : 0))));
|
|
}else{
|
|
ProtocolAPI.broadcastPacket(getDataWatcherPacket(entityStatusWatcher, (byte)0x10));
|
|
}
|
|
}
|
|
|
|
public void setItem(String item, boolean enchanted, String slot) {
|
|
ItemStack stack = new ItemStack(Material.valueOf(item.replace("minecraft:", "").toUpperCase()), 1);
|
|
if(enchanted)
|
|
stack.addUnsafeEnchantment(Enchantment.DURABILITY, 1);
|
|
itemSlots.put(slot, stack);
|
|
|
|
ProtocolAPI.broadcastPacket(getEquipmentPacket(slot, stack));
|
|
}
|
|
|
|
public void die(){
|
|
broadcastDeath();
|
|
entities.remove(internalId);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
private void broadcastDeath(){
|
|
if(entityType == EntityType.PLAYER){
|
|
ProtocolAPI.broadcastPacket(Fight.playerInfoPacket(Fight.removePlayer, new GameProfile(uuid, name), Fight.creative));
|
|
team.removeEntry(name);
|
|
}
|
|
|
|
Object packet = Reflection.newInstance(destroyPacket);
|
|
destroyEntities.set(packet, Core.getVersion() > 15 ? new IntArrayList(new int[]{entityId}) : new int[]{entityId});
|
|
ProtocolAPI.broadcastPacket(packet);
|
|
}
|
|
|
|
private int calcVelocity(double value) {
|
|
return (int)(Math.max(-3.9, Math.min(value, 3.9)) * 8000);
|
|
}
|
|
|
|
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);
|
|
private Object getDataWatcherPacket(Object dataWatcherObject, Object value) {
|
|
Object packet = Reflection.newInstance(metadataPacket);
|
|
metadataEntity.set(packet, entityId);
|
|
metadataMetadata.set(packet, Collections.singletonList(BountifulWrapper.impl.getDataWatcherItem(dataWatcherObject, value)));
|
|
return packet;
|
|
}
|
|
|
|
public 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 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);
|
|
BountifulWrapper.impl.setTeleportPacketPosition(packet, locX, locY, locZ);
|
|
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;
|
|
}
|
|
|
|
public static final Class<?> spawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutSpawnEntity");
|
|
private static final Reflection.FieldAccessor<Integer> spawnEntity = Reflection.getField(spawnPacket, int.class, 0);
|
|
private Object getSpawnEntityPacket(){
|
|
Object packet = Reflection.newInstance(spawnPacket);
|
|
spawnEntity.set(packet, entityId);
|
|
BountifulWrapper.impl.setSpawnPacketUUID(packet, uuid);
|
|
ProtocolWrapper.impl.setSpawnPacketType(packet, entityType);
|
|
return packet;
|
|
}
|
|
|
|
public static final Class<?> equipmentPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityEquipment");
|
|
private static final Reflection.FieldAccessor<Integer> equipmentEntity = Reflection.getField(equipmentPacket, int.class, 0);
|
|
|
|
public static final Class<?> itemStack = Reflection.getClass("{nms.world.item}.ItemStack");
|
|
private static final Class<?> craftItemStack = Reflection.getClass("{obc}.inventory.CraftItemStack");
|
|
private static final Reflection.MethodInvoker asNMSCopy = Reflection.getTypedMethod(REntity.craftItemStack, "asNMSCopy", REntity.itemStack, ItemStack.class);
|
|
private Object getEquipmentPacket(String slot, ItemStack stack){
|
|
Object packet = Reflection.newInstance(equipmentPacket);
|
|
equipmentEntity.set(packet, entityId);
|
|
ProtocolWrapper.impl.setEquipmentPacketStack(packet, slot, asNMSCopy.invoke(null, stack));
|
|
return packet;
|
|
}
|
|
|
|
private Object getPlayerInfoPacket(){
|
|
return Fight.playerInfoPacket(Fight.addPlayer, new GameProfile(uuid, name), Fight.creative);
|
|
}
|
|
|
|
public static final Class<?> namedSpawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutNamedEntitySpawn");
|
|
private static final Reflection.FieldAccessor<Integer> namedSpawnEntity = Reflection.getField(namedSpawnPacket, int.class, 0);
|
|
private static final Reflection.FieldAccessor<UUID> namedSpawnUUID = Reflection.getField(namedSpawnPacket, UUID.class, 0);
|
|
private Object getNamedSpawnPacket(){
|
|
Object packet = Reflection.newInstance(namedSpawnPacket);
|
|
namedSpawnEntity.set(packet, entityId);
|
|
namedSpawnUUID.set(packet, uuid);
|
|
BountifulWrapper.impl.setNamedSpawnPosition(packet, locX, locY, locZ);
|
|
FlatteningWrapper.impl.setNamedSpawnPacketDataWatcher(packet);
|
|
return packet;
|
|
}
|
|
}
|