CoreEntity #220
@ -294,4 +294,17 @@ 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 sneaking = entityPose.getEnumConstants()[5];
|
||||
@Override
|
||||
public Object getPose(boolean isSneaking) {
|
||||
return isSneaking ? sneaking : standing;
|
||||
}
|
||||
Lixfel markierte diese Unterhaltung als gelöst
Veraltet
|
||||
|
||||
@Override
|
||||
public void setNamedSpawnPacketDataWatcher(Object packet) {
|
||||
// field not present
|
||||
}
|
||||
}
|
||||
|
63
SpigotCore_18/src/de/steamwar/core/ProtocolWrapper18.java
Normale Datei
63
SpigotCore_18/src/de/steamwar/core/ProtocolWrapper18.java
Normale Datei
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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);
|
||||
@Override
|
||||
public void setSpawnPacketType(Object packet, EntityType type) {
|
||||
switch(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.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> playerInfoDataClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo$PlayerInfoData");
|
||||
private static final Class<?> enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "{nms.world.level}.EnumGamemode" : "{nms}.WorldSettings$EnumGamemode");
|
||||
private static final Class<?> iChatBaseComponent = Reflection.getClass("{nms.network.chat}.IChatBaseComponent");
|
||||
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")
|
||||
}
|
||||
|
63
SpigotCore_19/src/de/steamwar/core/ProtocolWrapper19.java
Normale Datei
63
SpigotCore_19/src/de/steamwar/core/ProtocolWrapper19.java
Normale Datei
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> playerInfoDataClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo$PlayerInfoData");
|
||||
private static final Class<?> enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "{nms.world.level}.EnumGamemode" : "{nms}.WorldSettings$EnumGamemode");
|
||||
private static final Class<?> iChatBaseComponent = Reflection.getClass("{nms.network.chat}.IChatBaseComponent");
|
||||
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,20 @@
|
||||
|
||||
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;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BountifulWrapper8 implements BountifulWrapper.IBountifulWrapper {
|
||||
|
||||
@Override
|
||||
@ -38,4 +44,52 @@ 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);
|
||||
}
|
||||
|
||||
private static final Class<?> teleportPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityTeleport");
|
||||
private static final Reflection.FieldAccessor<Integer> teleportX = Reflection.getField(teleportPacket, int.class, 1);
|
||||
private static final Reflection.FieldAccessor<Integer> teleportY = Reflection.getField(teleportPacket, int.class, 2);
|
||||
private static final Reflection.FieldAccessor<Integer> teleportZ = Reflection.getField(teleportPacket, int.class, 3);
|
||||
@Override
|
||||
public void setTeleportPacketPosition(Object packet, double x, double y, double z) {
|
||||
teleportX.set(packet, MathHelper.floor(x * 32));
|
||||
teleportY.set(packet, MathHelper.floor(y * 32));
|
||||
teleportZ.set(packet, MathHelper.floor(z * 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpawnPacketUUID(Object packet, UUID uuid) {
|
||||
// field not present
|
||||
}
|
||||
|
||||
private static final Class<?> namedSpawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutNamedEntitySpawn");
|
||||
private static final Reflection.FieldAccessor<Integer> namedSpawnX = Reflection.getField(namedSpawnPacket, int.class, 0);
|
||||
private static final Reflection.FieldAccessor<Integer> namedSpawnY = Reflection.getField(namedSpawnPacket, int.class, 1);
|
||||
private static final Reflection.FieldAccessor<Integer> namedSpawnZ = Reflection.getField(namedSpawnPacket, int.class, 2);
|
||||
@Override
|
||||
public void setNamedSpawnPosition(Object packet, double x, double y, double z) {
|
||||
namedSpawnX.set(packet, MathHelper.floor(x * 32));
|
||||
namedSpawnY.set(packet, MathHelper.floor(y * 32));
|
||||
namedSpawnZ.set(packet, MathHelper.floor(z * 32));
|
||||
}
|
||||
}
|
||||
|
@ -64,4 +64,19 @@ public class FlatteningWrapper8 implements FlatteningWrapper.IFlatteningWrapper
|
||||
head.setItemMeta(headmeta);
|
||||
return head;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPose(boolean sneaking) {
|
||||
return Byte.valueOf((byte)(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));
|
||||
}
|
||||
}
|
||||
|
87
SpigotCore_8/src/de/steamwar/core/ProtocolWrapper8.java
Normale Datei
87
SpigotCore_8/src/de/steamwar/core/ProtocolWrapper8.java
Normale Datei
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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 Object tnt;
|
||||
private static final Object arrow;
|
||||
private static final Object fireball;
|
||||
static {
|
||||
if(Core.getVersion() < 14) {
|
||||
spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, int.class, Core.getVersion() > 8 ? 6 : 9);
|
||||
tnt = 50;
|
||||
arrow = 60;
|
||||
fireball = 63;
|
||||
} else {
|
||||
Class<?> entityTypes = Reflection.getClass("{nms.world.entity}.EntityTypes");
|
||||
spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, entityTypes, 0);
|
||||
tnt = Reflection.getField(entityTypes, "TNT", entityTypes).get(null);
|
||||
arrow = Reflection.getField(entityTypes, "ARROW", entityTypes).get(null);
|
||||
fireball = Reflection.getField(entityTypes, "FIREBALL", entityTypes).get(null);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void setSpawnPacketType(Object packet, EntityType type) {
|
||||
switch(type) {
|
||||
case PRIMED_TNT:
|
||||
spawnType.set(packet, tnt);
|
||||
break;
|
||||
case ARROW:
|
||||
spawnType.set(packet, arrow);
|
||||
break;
|
||||
case FIREBALL:
|
||||
spawnType.set(packet, fireball);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> playerInfoDataClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo$PlayerInfoData");
|
||||
private static final Class<?> playerInfoPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo");
|
||||
private static final Class<?> enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "{nms.world.level}.EnumGamemode" : "{nms}.WorldSettings$EnumGamemode");
|
||||
private static final Class<?> iChatBaseComponent = Reflection.getClass("{nms.network.chat}.IChatBaseComponent");
|
||||
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,49 @@ 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);
|
||||
}
|
||||
|
||||
private static final Class<?> teleportPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityTeleport");
|
||||
private static final Reflection.FieldAccessor<Double> teleportX = Reflection.getField(teleportPacket, double.class, 0);
|
||||
private static final Reflection.FieldAccessor<Double> teleportY = Reflection.getField(teleportPacket, double.class, 1);
|
||||
private static final Reflection.FieldAccessor<Double> teleportZ = Reflection.getField(teleportPacket, double.class, 2);
|
||||
@Override
|
||||
public void setTeleportPacketPosition(Object packet, double x, double y, double z) {
|
||||
teleportX.set(packet, x);
|
||||
teleportY.set(packet, y);
|
||||
teleportZ.set(packet, z);
|
||||
}
|
||||
|
||||
private static final Class<?> spawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutSpawnEntity");
|
||||
private static final Reflection.FieldAccessor<UUID> spawnUUID = Reflection.getField(spawnPacket, UUID.class, 0);
|
||||
@Override
|
||||
public void setSpawnPacketUUID(Object packet, UUID uuid) {
|
||||
spawnUUID.set(packet, uuid);
|
||||
}
|
||||
|
||||
private static final Class<?> namedSpawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutNamedEntitySpawn");
|
||||
private static final Reflection.FieldAccessor<Double> namedSpawnX = Reflection.getField(namedSpawnPacket, double.class, 0);
|
||||
private static final Reflection.FieldAccessor<Double> namedSpawnY = Reflection.getField(namedSpawnPacket, double.class, 1);
|
||||
private static final Reflection.FieldAccessor<Double> namedSpawnZ = Reflection.getField(namedSpawnPacket, double.class, 2);
|
||||
@Override
|
||||
public void setNamedSpawnPosition(Object packet, double x, double y, double z) {
|
||||
namedSpawnX.set(packet, x);
|
||||
namedSpawnY.set(packet, y);
|
||||
namedSpawnZ.set(packet, z);
|
||||
}
|
||||
}
|
||||
|
@ -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,11 @@ 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);
|
||||
void setTeleportPacketPosition(Object packet, double x, double y, double z);
|
||||
void setSpawnPacketUUID(Object packet, UUID uuid);
|
||||
void setNamedSpawnPosition(Object packet, double x, double y, double z);
|
||||
}
|
||||
}
|
||||
|
@ -38,5 +38,8 @@ public class FlatteningWrapper {
|
||||
Material getMaterial(String material);
|
||||
Material getDye(int colorCode);
|
||||
ItemStack setSkullOwner(String player);
|
||||
|
||||
Object getPose(boolean sneaking);
|
||||
void setNamedSpawnPacketDataWatcher(Object packet);
|
||||
}
|
||||
}
|
||||
|
43
SpigotCore_Main/src/de/steamwar/core/ProtocolWrapper.java
Normale Datei
43
SpigotCore_Main/src/de/steamwar/core/ProtocolWrapper.java
Normale Datei
@ -0,0 +1,43 @@
|
||||
/*
|
||||
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<?> equipmentPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityEquipment");
|
||||
|
||||
// 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);
|
||||
|
||||
}
|
420
SpigotCore_Main/src/de/steamwar/entity/REntity.java
Normale Datei
420
SpigotCore_Main/src/de/steamwar/entity/REntity.java
Normale Datei
@ -0,0 +1,420 @@
|
||||
/*
|
||||
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 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 it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
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(true).getClass());
|
||||
private static final Object bowDrawnWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 7 : 6, Byte.class);
|
||||
private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(16, Byte.class); //TODO multiversioning
|
||||
private static final Object nameWatcher = BountifulWrapper.impl.getDataWatcherObject(2, Optional.class); // Optional<IChatBaseComponent>, first optional //TODO multiversioning (dataWatcherRegistry.getFields()[fieldIndex].get(null))
|
||||
private static final Object nameVisibleWatcher = BountifulWrapper.impl.getDataWatcherObject(3, Boolean.class); //TODO multiversioning
|
||||
private static final Object sizeWatcher = BountifulWrapper.impl.getDataWatcherObject(14, Byte.class); //TODO multiversioning
|
||||
|
||||
/*
|
||||
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 entityIdCounter = -1;
|
||||
private static final Random random = new Random();
|
||||
|
||||
private final REntityServer server;
|
||||
private final EntityType entityType;
|
||||
private final int entityId;
|
||||
private final UUID uuid;
|
||||
private final String name;
|
||||
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
private byte yaw;
|
||||
private byte pitch;
|
||||
private byte headYaw;
|
||||
|
||||
private boolean invisible;
|
||||
private boolean sneaks;
|
||||
private int fireTick;
|
||||
private String displayName;
|
||||
private final Map<Object, ItemStack> itemSlots;
|
||||
|
||||
//TODO packet caching
|
||||
public REntity(REntityServer server, UUID uuid, String name, Location location) {
|
||||
this(server, EntityType.PLAYER, uuid, name, location);
|
||||
//team.addEntry(name);
|
||||
}
|
||||
|
||||
public REntity(REntityServer server, EntityType entityType, Location location) {
|
||||
this(server, entityType, new UUID(random.nextLong() & -61441L | 16384L, random.nextLong() & 4611686018427387903L | -9223372036854775808L), null, location);
|
||||
}
|
||||
|
||||
private REntity(REntityServer server, EntityType entityType, UUID uuid, String name, Location location) {
|
||||
this.server = server;
|
||||
this.entityType = entityType;
|
||||
this.entityId = entityIdCounter--;
|
||||
this.uuid = uuid;
|
||||
this.name = name;
|
||||
|
||||
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);
|
||||
this.headYaw = headYaw;
|
||||
server.updateEntity(this, getTeleportPacket());
|
||||
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 sneak(boolean sneaking) {
|
||||
sneaks = sneaking;
|
||||
server.updateEntity(this, getDataWatcherPacket(sneakingDataWatcher, FlatteningWrapper.impl.getPose(sneaking))); //TODO entityStatusData in 1.8!
|
||||
}
|
||||
|
||||
public void setOnFire(boolean perma) {
|
||||
fireTick = perma ? -1 : 21;
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, (byte) 1));
|
||||
}
|
||||
|
||||
public void setInvisible(boolean invisible) {
|
||||
this.invisible = invisible;
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, (byte) 0x20));
|
||||
}
|
||||
|
||||
public void setBowDrawn(boolean drawn, boolean offHand) {
|
||||
if(Core.getVersion() > 8){
|
||||
server.updateEntity(this, getDataWatcherPacket(bowDrawnWatcher, (byte) ((drawn ? 1 : 0) + (offHand ? 2 : 0))));
|
||||
}else{
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, (byte)0x10));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> chatComponentText = Reflection.getClass("{nms}.ChatComponentText"); //TODO multiversioning
|
||||
private static final Reflection.ConstructorInvoker chatComponentTextConstructor = Reflection.getConstructor(chatComponentText, String.class); //TODO multiversioning
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
server.updateEntity(this, getDataWatcherPacket(nameWatcher, displayName != null ? Optional.of(chatComponentTextConstructor.invoke(displayName)) : Optional.empty()));
|
||||
server.updateEntity(this, getDataWatcherPacket(nameVisibleWatcher, displayName != null));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
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);
|
||||
|
||||
switch(slot){
|
||||
case "HEAD":
|
||||
setItem(ProtocolWrapper.itemSlots[5], stack);
|
||||
break;
|
||||
case "CHEST":
|
||||
setItem(ProtocolWrapper.itemSlots[4], stack);
|
||||
break;
|
||||
case "LEGS":
|
||||
setItem(ProtocolWrapper.itemSlots[3], stack);
|
||||
break;
|
||||
case "FEET":
|
||||
setItem(ProtocolWrapper.itemSlots[2], stack);
|
||||
break;
|
||||
case "OFFHAND":
|
||||
setItem(ProtocolWrapper.itemSlots[1], stack);
|
||||
break;
|
||||
case "MAINHAND":
|
||||
default:
|
||||
setItem(ProtocolWrapper.itemSlots[0], stack);
|
||||
}
|
||||
}
|
||||
|
||||
public void setItem(Object slot, ItemStack stack) {
|
||||
itemSlots.put(slot, stack);
|
||||
server.updateEntity(this, getEquipmentPacket(slot, stack));
|
||||
}
|
||||
|
||||
public void close() {
|
||||
server.removeEntity(this);
|
||||
}
|
||||
|
||||
void spawn(Consumer<Object> packetSink) {
|
||||
if(entityType == EntityType.PLAYER){
|
||||
packetSink.accept(getPlayerInfoPacket(addPlayer));
|
||||
packetSink.accept(getNamedSpawnPacket());
|
||||
for (Map.Entry<Object, ItemStack> entry : itemSlots.entrySet()) {
|
||||
packetSink.accept(getEquipmentPacket(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
packetSink.accept(getDataWatcherPacket(skinPartsDataWatcher, (byte) 0x7F)); //TODO multiversioning
|
||||
} else if(entityType == EntityType.ARMOR_STAND) {
|
||||
packetSink.accept(getSpawnLivingEntityPacket());
|
||||
packetSink.accept(getDataWatcherPacket(sizeWatcher, (byte) 0x10)); // small size //TODO multiversioning
|
||||
for (Map.Entry<Object, ItemStack> entry : itemSlots.entrySet()) {
|
||||
packetSink.accept(getEquipmentPacket(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
} else {
|
||||
packetSink.accept(getSpawnEntityPacket());
|
||||
}
|
||||
packetSink.accept(getTeleportPacket()); //TODO teleport necessary
|
||||
packetSink.accept(getHeadRotationPacket()); //TODO head rotation for all types?
|
||||
|
||||
//TODO merge MetadataPacket (DataWatcherPackets)
|
||||
|
||||
if(sneaks) {
|
||||
packetSink.accept(getDataWatcherPacket(entityStatusWatcher, FlatteningWrapper.impl.getPose(true)));
|
||||
}
|
||||
|
||||
if(fireTick != 0) {
|
||||
packetSink.accept(getDataWatcherPacket(sneakingDataWatcher, getDataWatcherPacket(entityStatusWatcher, (byte)1)));
|
||||
}
|
||||
|
||||
if(invisible) {
|
||||
packetSink.accept(getDataWatcherPacket(entityStatusWatcher, (byte) 0x20));
|
||||
}
|
||||
|
||||
if(displayName != null) {
|
||||
packetSink.accept(getDataWatcherPacket(nameWatcher, Optional.of(chatComponentTextConstructor.invoke(displayName))));
|
||||
packetSink.accept(getDataWatcherPacket(nameVisibleWatcher, true));
|
||||
}
|
||||
}
|
||||
|
||||
void tick() {
|
||||
if(fireTick > 0) {
|
||||
fireTick--;
|
||||
if(fireTick == 0) {
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, (byte)0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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){
|
||||
if(entityType == EntityType.PLAYER){
|
||||
packetSink.accept(getPlayerInfoPacket(removePlayer));
|
||||
//team.removeEntry(name);
|
||||
}
|
||||
|
||||
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 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... 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 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, 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);
|
||||
private 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)); //TODO grouped send (1.8 incompatible)
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final Class<?> playerInfoPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo");
|
||||
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(playerInfoPacket, playerInfoActionClass, 0);
|
||||
private static final Object removePlayer = playerInfoActionClass.getEnumConstants()[4];
|
||||
private static final Reflection.FieldAccessor<List> playerInfoData = Reflection.getField(playerInfoPacket, List.class, 0);
|
||||
private static final Class<?> enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "{nms.world.level}.EnumGamemode" : "{nms}.WorldSettings$EnumGamemode");
|
||||
private static final Object creative = enumGamemode.getEnumConstants()[Core.getVersion() > 15 ? 1 : 2];
|
||||
private Object getPlayerInfoPacket(Object action){
|
||||
Object packet = Reflection.newInstance(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 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, x, y, z);
|
||||
FlatteningWrapper.impl.setNamedSpawnPacketDataWatcher(packet);
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final Class<?> spawnLivingPacket = Reflection.getClass("{nms}.PacketPlayOutSpawnEntityLiving"); //TODO multiversioning
|
||||
private static final Reflection.ConstructorInvoker spawnLivingPacketConstructor = Reflection.getConstructor(spawnLivingPacket); //TODO multiversioning
|
||||
private static final Reflection.FieldAccessor<Integer> spawnLivingEntityId = Reflection.getField(spawnLivingPacket, int.class, 0); //TODO multiversioning
|
||||
private static final Reflection.FieldAccessor<UUID> spawnLivingUUID = Reflection.getField(spawnLivingPacket, UUID.class, 0); //TODO multiversioning
|
||||
private static final Reflection.FieldAccessor<Integer> spawnLivingEntityType = Reflection.getField(spawnLivingPacket, int.class, 1); //TODO multiversioning
|
||||
private static final Reflection.FieldAccessor<Double> spawnLivingEntityX = Reflection.getField(spawnLivingPacket, double.class, 0); //TODO multiversioning
|
||||
private static final Reflection.FieldAccessor<Double> spawnLivingEntityY = Reflection.getField(spawnLivingPacket, double.class, 1); //TODO multiversioning
|
||||
private static final Reflection.FieldAccessor<Double> spawnLivingEntityZ = Reflection.getField(spawnLivingPacket, double.class, 2); //TODO multiversioning
|
||||
private Object getSpawnLivingEntityPacket() {
|
||||
Object packet = spawnLivingPacketConstructor.invoke();
|
||||
spawnLivingEntityId.set(packet, entityId);
|
||||
spawnLivingUUID.set(packet, uuid);
|
||||
spawnLivingEntityType.set(packet, 1); //TODO set correct type
|
||||
spawnLivingEntityX.set(packet, x);
|
||||
spawnLivingEntityY.set(packet, y);
|
||||
spawnLivingEntityZ.set(packet, z);
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
||||
private static final Reflection.FieldAccessor<Integer> spawnEntity = Reflection.getField(ProtocolWrapper.spawnPacket, int.class, 0);
|
||||
private Object getSpawnEntityPacket() {
|
||||
Object packet = Reflection.newInstance(ProtocolWrapper.spawnPacket);
|
||||
spawnEntity.set(packet, entityId);
|
||||
BountifulWrapper.impl.setSpawnPacketUUID(packet, uuid);
|
||||
ProtocolWrapper.impl.setSpawnPacketType(packet, entityType);
|
||||
//TODO set position
|
||||
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);
|
||||
}
|
||||
}
|
217
SpigotCore_Main/src/de/steamwar/entity/REntityServer.java
Normale Datei
217
SpigotCore_Main/src/de/steamwar/entity/REntityServer.java
Normale Datei
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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 org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
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<>();
|
||||
|
||||
private final BukkitTask tickTask;
|
||||
|
||||
public REntityServer() {
|
||||
Core.getInstance().getServer().getPluginManager().registerEvents(this, Core.getInstance());
|
||||
tickTask = Core.getInstance().getServer().getScheduler().runTaskTimer(Core.getInstance(), this::tick, 1, 1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
tickTask.cancel();
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
}
|
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.