mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-20 15:39:22 +00:00
Merge remote-tracking branch 'refs/remotes/upstream/dev' into dev
# Conflicts: # bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java # bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java # bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
package net.momirealms.craftengine.bukkit.entity.data;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||||
|
|
||||||
|
public class PlayerData<T> extends LivingEntityData<T> {
|
||||||
|
public static final PlayerData<Float> PlayerAbsorption = new PlayerData<>(PlayerData.class, EntityDataValue.Serializers$FLOAT, 0.0f);
|
||||||
|
public static final PlayerData<Integer> Score = new PlayerData<>(PlayerData.class, EntityDataValue.Serializers$INT, 0);
|
||||||
|
public static final PlayerData<Byte> PlayerModeCustomisation = new PlayerData<>(PlayerData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
|
||||||
|
public static final PlayerData<Byte> PlayerMainHand = new PlayerData<>(PlayerData.class, EntityDataValue.Serializers$BYTE, (byte) 1);
|
||||||
|
public static final PlayerData<Object> ShoulderLeft = new PlayerData<>(PlayerData.class, EntityDataValue.Serializers$COMPOUND_TAG, CoreReflections.instance$CompoundTag$Empty);
|
||||||
|
public static final PlayerData<Object> ShoulderRight = new PlayerData<>(PlayerData.class, EntityDataValue.Serializers$COMPOUND_TAG, CoreReflections.instance$CompoundTag$Empty);
|
||||||
|
|
||||||
|
public PlayerData(Class<?> clazz, Object serializer, T defaultValue) {
|
||||||
|
super(clazz, serializer, defaultValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,11 +3,15 @@ package net.momirealms.craftengine.bukkit.entity.furniture;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
|
import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.furniture.seat.BukkitSeatEntity;
|
||||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||||
import net.momirealms.craftengine.bukkit.util.EntityUtils;
|
import net.momirealms.craftengine.bukkit.util.EntityUtils;
|
||||||
import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils;
|
import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils;
|
||||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.PlayerUtils;
|
||||||
import net.momirealms.craftengine.core.entity.furniture.*;
|
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||||
import net.momirealms.craftengine.core.util.ArrayUtils;
|
import net.momirealms.craftengine.core.util.ArrayUtils;
|
||||||
@@ -17,6 +21,7 @@ import net.momirealms.craftengine.core.util.VersionHelper;
|
|||||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.attribute.Attribute;
|
import org.bukkit.attribute.Attribute;
|
||||||
import org.bukkit.entity.*;
|
import org.bukkit.entity.*;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
@@ -28,6 +33,7 @@ import org.joml.Vector3f;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class BukkitFurniture implements Furniture {
|
public class BukkitFurniture implements Furniture {
|
||||||
private final Key id;
|
private final Key id;
|
||||||
@@ -50,7 +56,7 @@ public class BukkitFurniture implements Furniture {
|
|||||||
private final boolean hasExternalModel;
|
private final boolean hasExternalModel;
|
||||||
// seats
|
// seats
|
||||||
private final Set<Vector3f> occupiedSeats = Collections.synchronizedSet(new HashSet<>());
|
private final Set<Vector3f> occupiedSeats = Collections.synchronizedSet(new HashSet<>());
|
||||||
private final Vector<WeakReference<Entity>> seats = new Vector<>();
|
private final Map<Integer, BukkitSeatEntity> seats = Collections.synchronizedMap(new HashMap<>());
|
||||||
// cached spawn packet
|
// cached spawn packet
|
||||||
private Object cachedSpawnPacket;
|
private Object cachedSpawnPacket;
|
||||||
private Object cachedMinimizedSpawnPacket;
|
private Object cachedMinimizedSpawnPacket;
|
||||||
@@ -190,24 +196,13 @@ public class BukkitFurniture implements Furniture {
|
|||||||
if (entity != null)
|
if (entity != null)
|
||||||
entity.destroy();
|
entity.destroy();
|
||||||
}
|
}
|
||||||
for (WeakReference<Entity> r : this.seats) {
|
destroySeats();
|
||||||
Entity entity = r.get();
|
|
||||||
if (entity == null) continue;
|
|
||||||
for (Entity passenger : entity.getPassengers()) {
|
|
||||||
entity.removePassenger(passenger);
|
|
||||||
}
|
|
||||||
entity.remove();
|
|
||||||
}
|
|
||||||
this.seats.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroySeats() {
|
public void destroySeats() {
|
||||||
for (WeakReference<Entity> entity : this.seats) {
|
for (BukkitSeatEntity seat : this.seats.values()) {
|
||||||
Entity e = entity.get();
|
seat.destroy();
|
||||||
if (e != null) {
|
|
||||||
e.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.seats.clear();
|
this.seats.clear();
|
||||||
}
|
}
|
||||||
@@ -295,7 +290,17 @@ public class BukkitFurniture implements Furniture {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnSeatEntityForPlayer(net.momirealms.craftengine.core.entity.player.Player player, Seat seat) {
|
public void spawnSeatEntityForPlayer(net.momirealms.craftengine.core.entity.player.Player player, Seat seat) {
|
||||||
spawnSeatEntityForPlayer((Player) player.platformPlayer(), seat);
|
BukkitSeatEntity seatEntity = (BukkitSeatEntity) seat.spawn(player, this);
|
||||||
|
if (seatEntity == null) {
|
||||||
|
this.removeOccupiedSeat(seat.offset());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.seats.put(seatEntity.playerID(), seatEntity);
|
||||||
|
player.setSeat(seatEntity);
|
||||||
|
BukkitServerPlayer serverPlayer = (BukkitServerPlayer) player;
|
||||||
|
for (Player p : PlayerUtils.getTrackedBy(serverPlayer.platformPlayer())) {
|
||||||
|
BukkitNetworkManager.instance().getOnlineUser(p).entityPacketHandlers().put(seatEntity.playerID(), seatEntity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -318,10 +323,31 @@ public class BukkitFurniture implements Furniture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) {
|
public Location calculateSeatLocation(Seat seat) {
|
||||||
Location location = this.calculateSeatLocation(seat);
|
Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate().transform(new Vector3f(seat.offset()));
|
||||||
Entity seatEntity = seat.limitPlayerRotation() ?
|
double yaw = seat.yaw() + this.location.getYaw();
|
||||||
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> {
|
if (yaw < -180) yaw += 360;
|
||||||
|
Location newLocation = this.location.clone();
|
||||||
|
newLocation.setYaw((float) yaw);
|
||||||
|
newLocation.add(offset.x, offset.y + 0.6, -offset.z);
|
||||||
|
return newLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BukkitSeatEntity seatByPlayerId(int playerId) {
|
||||||
|
return this.seats.get(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSeatEntity(int playerId) {
|
||||||
|
this.seats.remove(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Entity spawnSeatEntity(Furniture furniture, World world, Location loc, boolean limitPlayerRotation, Consumer<Entity> function) {
|
||||||
|
EntityType type;
|
||||||
|
if (limitPlayerRotation) {
|
||||||
|
type = EntityType.ARMOR_STAND;
|
||||||
|
loc = VersionHelper.isOrAbove1_20_2() ? loc.subtract(0,0.9875,0) : loc.subtract(0,0.990625,0);
|
||||||
|
if (function == null) {
|
||||||
|
function = entity -> {
|
||||||
ArmorStand armorStand = (ArmorStand) entity;
|
ArmorStand armorStand = (ArmorStand) entity;
|
||||||
if (VersionHelper.isOrAbove1_21_3()) {
|
if (VersionHelper.isOrAbove1_21_3()) {
|
||||||
Objects.requireNonNull(armorStand.getAttribute(Attribute.MAX_HEALTH)).setBaseValue(0.01);
|
Objects.requireNonNull(armorStand.getAttribute(Attribute.MAX_HEALTH)).setBaseValue(0.01);
|
||||||
@@ -337,29 +363,22 @@ public class BukkitFurniture implements Furniture {
|
|||||||
armorStand.setAI(false);
|
armorStand.setAI(false);
|
||||||
armorStand.setGravity(false);
|
armorStand.setGravity(false);
|
||||||
armorStand.setPersistent(false);
|
armorStand.setPersistent(false);
|
||||||
armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId());
|
armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, furniture.baseEntityId());
|
||||||
armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z);
|
//armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z);
|
||||||
}) :
|
};
|
||||||
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location : location.subtract(0,0.25,0), EntityType.ITEM_DISPLAY, entity -> {
|
}
|
||||||
|
} else {
|
||||||
|
type = EntityType.ITEM_DISPLAY;
|
||||||
|
loc = VersionHelper.isOrAbove1_20_2() ? loc : loc.subtract(0,0.25,0);
|
||||||
|
if (function == null) {
|
||||||
|
function = entity -> {
|
||||||
ItemDisplay itemDisplay = (ItemDisplay) entity;
|
ItemDisplay itemDisplay = (ItemDisplay) entity;
|
||||||
itemDisplay.setPersistent(false);
|
itemDisplay.setPersistent(false);
|
||||||
itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId());
|
itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, furniture.baseEntityId());
|
||||||
itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z);
|
//itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z);
|
||||||
});
|
};
|
||||||
this.seats.add(new WeakReference<>(seatEntity));
|
}
|
||||||
if (!seatEntity.addPassenger(player)) {
|
|
||||||
seatEntity.remove();
|
|
||||||
this.removeOccupiedSeat(seat.offset());
|
|
||||||
}
|
}
|
||||||
}
|
return EntityUtils.spawnEntity(world, loc, type, function);
|
||||||
|
|
||||||
private Location calculateSeatLocation(Seat seat) {
|
|
||||||
Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate().transform(new Vector3f(seat.offset()));
|
|
||||||
double yaw = seat.yaw() + this.location.getYaw();
|
|
||||||
if (yaw < -180) yaw += 360;
|
|
||||||
Location newLocation = this.location.clone();
|
|
||||||
newLocation.setYaw((float) yaw);
|
|
||||||
newLocation.add(offset.x, offset.y + 0.6, -offset.z);
|
|
||||||
return newLocation;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package net.momirealms.craftengine.bukkit.entity.furniture;
|
package net.momirealms.craftengine.bukkit.entity.furniture;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
|
||||||
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBox;
|
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBox;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.furniture.seat.BukkitSeatEntity;
|
||||||
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
|
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
|
||||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||||
@@ -10,10 +12,10 @@ import net.momirealms.craftengine.bukkit.util.EntityUtils;
|
|||||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||||
import net.momirealms.craftengine.core.entity.furniture.*;
|
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||||
import net.momirealms.craftengine.core.sound.SoundData;
|
import net.momirealms.craftengine.core.sound.SoundData;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
|
||||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -23,7 +25,6 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -37,7 +38,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
|||||||
public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY);
|
public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY);
|
||||||
public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_EXTRA_DATA_KEY);
|
public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_EXTRA_DATA_KEY);
|
||||||
public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY);
|
public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY);
|
||||||
public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY);
|
|
||||||
public static final NamespacedKey FURNITURE_COLLISION = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_COLLISION);
|
public static final NamespacedKey FURNITURE_COLLISION = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_COLLISION);
|
||||||
public static Class<?> COLLISION_ENTITY_CLASS = Interaction.class;
|
public static Class<?> COLLISION_ENTITY_CLASS = Interaction.class;
|
||||||
public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.INTERACTION;
|
public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.INTERACTION;
|
||||||
@@ -336,20 +336,32 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void tryLeavingSeat(@NotNull Player player, @NotNull Entity vehicle) {
|
protected void tryLeavingSeat(@NotNull Player player, @NotNull Entity vehicle) {
|
||||||
Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
|
net.momirealms.craftengine.core.entity.player.Player serverPlayer = BukkitAdaptors.adapt(player);
|
||||||
if (baseFurniture == null) return;
|
if (serverPlayer == null) {
|
||||||
vehicle.remove();
|
Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||||
BukkitFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture);
|
if (baseFurniture == null) return;
|
||||||
|
BukkitFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture);
|
||||||
|
if (furniture == null) {
|
||||||
|
vehicle.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SeatEntity seatEntity = furniture.seatByPlayerId(player.getEntityId());
|
||||||
|
if (seatEntity != null && !seatEntity.destroyed()) {
|
||||||
|
seatEntity.destroy();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BukkitSeatEntity seatEntity = (BukkitSeatEntity) serverPlayer.seat();
|
||||||
|
if (seatEntity == null || seatEntity.literalObject() != vehicle) return;
|
||||||
|
|
||||||
|
BukkitFurniture furniture = seatEntity.furniture();
|
||||||
if (furniture == null) {
|
if (furniture == null) {
|
||||||
|
seatEntity.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String vector3f = vehicle.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING);
|
|
||||||
if (vector3f == null) {
|
seatEntity.dismount(serverPlayer);
|
||||||
plugin.logger().warn("Failed to get vector3f for player " + player.getName() + "'s seat");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Vector3f seatPos = MiscUtils.getAsVector3f(vector3f, "seat");
|
|
||||||
furniture.removeOccupiedSeat(seatPos);
|
|
||||||
|
|
||||||
if (player.getVehicle() != null) return;
|
if (player.getVehicle() != null) return;
|
||||||
Location vehicleLocation = vehicle.getLocation();
|
Location vehicleLocation = vehicle.getLocation();
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package net.momirealms.craftengine.bukkit.entity.furniture;
|
|||||||
|
|
||||||
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
|
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
|
||||||
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
|
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
|
||||||
|
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||||
import org.bukkit.entity.ArmorStand;
|
import org.bukkit.entity.ArmorStand;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.ItemDisplay;
|
import org.bukkit.entity.ItemDisplay;
|
||||||
@@ -10,7 +12,9 @@ import org.bukkit.event.EventHandler;
|
|||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
import org.bukkit.event.player.PlayerAnimationEvent;
|
||||||
|
import org.bukkit.event.player.PlayerArmorStandManipulateEvent;
|
||||||
|
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||||
import org.bukkit.event.world.EntitiesLoadEvent;
|
import org.bukkit.event.world.EntitiesLoadEvent;
|
||||||
@@ -123,12 +127,30 @@ public class FurnitureEventListener implements Listener {
|
|||||||
|
|
||||||
// do not allow players to put item on seats
|
// do not allow players to put item on seats
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
public void onInteractArmorStand(PlayerInteractAtEntityEvent event) {
|
public void onInteractArmorStand(PlayerArmorStandManipulateEvent event) {
|
||||||
Entity clicked = event.getRightClicked();
|
ArmorStand clicked = event.getRightClicked();
|
||||||
if (clicked instanceof ArmorStand armorStand) {
|
Integer baseFurniture = clicked.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||||
Integer baseFurniture = armorStand.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
|
if (baseFurniture == null) return;
|
||||||
if (baseFurniture == null) return;
|
event.setCancelled(true);
|
||||||
event.setCancelled(true);
|
}
|
||||||
}
|
|
||||||
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||||
|
public void onMainHandChange(PlayerItemHeldEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (player.getVehicle() == null) return;
|
||||||
|
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
|
||||||
|
if (serverPlayer.seat() == null) return;
|
||||||
|
|
||||||
|
serverPlayer.seat().event(serverPlayer, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void onPlayerAnimation(PlayerAnimationEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (player.getVehicle() == null) return;
|
||||||
|
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
|
||||||
|
if (serverPlayer.seat() == null) return;
|
||||||
|
|
||||||
|
serverPlayer.seat().event(serverPlayer, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package net.momirealms.craftengine.bukkit.entity.furniture.seat;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||||
|
import net.momirealms.craftengine.core.entity.furniture.Furniture;
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
|
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
public abstract class BukkitSeatEntity extends BukkitEntity implements SeatEntity {
|
||||||
|
private final BukkitFurniture furniture;
|
||||||
|
private final Vector3f vector3f;
|
||||||
|
private final int playerID;
|
||||||
|
private boolean destroyed = false;
|
||||||
|
|
||||||
|
public BukkitSeatEntity(Entity entity, Furniture furniture, Vector3f vector3f, int playerID) {
|
||||||
|
super(entity);
|
||||||
|
this.furniture = (BukkitFurniture) furniture;
|
||||||
|
this.vector3f = vector3f;
|
||||||
|
this.playerID = playerID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(NetWorkUser to) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dismount(Player player) {
|
||||||
|
if (player == null) return;
|
||||||
|
player.setSeat(null);
|
||||||
|
onDismount(player);
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismount(Player player) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void event(Player player, Object event) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
if (destroyed) return;
|
||||||
|
destroyed = true;
|
||||||
|
|
||||||
|
org.bukkit.entity.Entity entity = this.literalObject();
|
||||||
|
if (entity == null) return;
|
||||||
|
|
||||||
|
for (org.bukkit.entity.Entity passenger : entity.getPassengers()) {
|
||||||
|
entity.removePassenger(passenger);
|
||||||
|
if (passenger instanceof org.bukkit.entity.Player p && p.getEntityId() == this.playerID) {
|
||||||
|
Player cePlayer = BukkitAdaptors.adapt(p);
|
||||||
|
dismount(cePlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entity.remove();
|
||||||
|
furniture.removeSeatEntity(playerID());
|
||||||
|
furniture.removeOccupiedSeat(vector3f());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean destroyed() {
|
||||||
|
return destroyed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BukkitFurniture furniture() {
|
||||||
|
return this.furniture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector3f vector3f() {
|
||||||
|
return this.vector3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int playerID() {
|
||||||
|
return this.playerID;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package net.momirealms.craftengine.bukkit.entity.furniture.seat;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.entity.furniture.SeatType;
|
||||||
|
|
||||||
|
public class BukkitSeatTypes extends SeatType {
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
register(SIT, SitSeat.FACTORY);
|
||||||
|
register(LAY, LaySeat.FACTORY);
|
||||||
|
register(CRAWL, CrawlSeat.FACTORY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
package net.momirealms.craftengine.bukkit.entity.furniture.seat;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.data.PlayerData;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.data.ShulkerData;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||||
|
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.PlayerUtils;
|
||||||
|
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
|
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||||
|
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
||||||
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
|
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||||
|
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Pose;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class CrawlSeat extends AbstractSeat {
|
||||||
|
public static final SeatFactory FACTORY = new Factory();
|
||||||
|
private static final List<Object> visualData = new ArrayList<>();
|
||||||
|
private final boolean limitPlayerRotation;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ShulkerData.NoGravity.addEntityDataIfNotDefaultValue(true, visualData);
|
||||||
|
ShulkerData.Silent.addEntityDataIfNotDefaultValue(true, visualData);
|
||||||
|
ShulkerData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, visualData);
|
||||||
|
ShulkerData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, visualData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrawlSeat(Vector3f offset, float yaw, boolean limitPlayerRotation) {
|
||||||
|
super(offset, yaw);
|
||||||
|
this.limitPlayerRotation = limitPlayerRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SeatEntity spawn(Player player, Furniture furniture) {
|
||||||
|
return spawn((org.bukkit.entity.Player) player.platformPlayer(), furniture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeatEntity spawn(org.bukkit.entity.Player player, Furniture furniture) {
|
||||||
|
Location location = ((BukkitFurniture) furniture).calculateSeatLocation(this);
|
||||||
|
|
||||||
|
org.bukkit.entity.Entity seatEntity = BukkitFurniture.spawnSeatEntity(furniture, player.getWorld(), location, this.limitPlayerRotation, null);
|
||||||
|
if (!seatEntity.addPassenger(player)) {
|
||||||
|
seatEntity.remove();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix Rider Pose
|
||||||
|
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
|
||||||
|
List<Object> packets = new ArrayList<>();
|
||||||
|
packets.add(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(entityId, UUID.randomUUID(), location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw(),
|
||||||
|
MEntityTypes.SHULKER, 0, CoreReflections.instance$Vec3$Zero, 0));
|
||||||
|
packets.add(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, List.copyOf(visualData)));
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (VersionHelper.isOrAbove1_20_5()) {
|
||||||
|
Object attributeInstance = CoreReflections.constructor$AttributeInstance.newInstance(MAttributeHolders.SCALE, (Consumer<?>) (o) -> {});
|
||||||
|
CoreReflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, 0.6);
|
||||||
|
packets.add(
|
||||||
|
NetworkReflections.constructor$ClientboundUpdateAttributesPacket0
|
||||||
|
.newInstance(entityId, Collections.singletonList(attributeInstance))
|
||||||
|
);
|
||||||
|
packets.add(FastNMS.INSTANCE.constructor$ClientboundSetPassengersPacket(seatEntity.getEntityId(), entityId));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to add crawl seat attributes", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
|
||||||
|
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
|
||||||
|
serverPlayer.sendPacket(bundle, true);
|
||||||
|
|
||||||
|
// Sync Pose
|
||||||
|
player.setPose(Pose.SWIMMING, true);
|
||||||
|
Object syncPosePacket = null;
|
||||||
|
try {
|
||||||
|
Object playerData = CoreReflections.method$Entity$getEntityData.invoke(serverPlayer.serverPlayer());
|
||||||
|
Object dataItem = CoreReflections.method$SynchedEntityData$getItem.invoke(playerData, PlayerData.Pose.entityDataAccessor());
|
||||||
|
Object dataValue = CoreReflections.method$SynchedEntityData$DataItem$value.invoke(dataItem);
|
||||||
|
syncPosePacket = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(serverPlayer.entityID(), List.of(dataValue));
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to construct sync pose packet", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object finalSyncPosePacket = syncPosePacket;
|
||||||
|
BukkitCraftEngine.instance().scheduler().sync().runLater(() -> {
|
||||||
|
serverPlayer.sendPacket(finalSyncPosePacket, true);
|
||||||
|
for (org.bukkit.entity.Player p : PlayerUtils.getTrackedBy(player)) {
|
||||||
|
BukkitNetworkManager.instance().sendPacket(BukkitAdaptors.adapt(p), finalSyncPosePacket, true);
|
||||||
|
}
|
||||||
|
}, 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||||
|
|
||||||
|
return new CrawlEntity(seatEntity, furniture, offset(), player.getEntityId(), entityId, syncPosePacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CrawlEntity extends BukkitSeatEntity {
|
||||||
|
private final int entityId;
|
||||||
|
private final Object syncPosePacket;
|
||||||
|
|
||||||
|
|
||||||
|
public CrawlEntity(Entity entity, Furniture furniture, Vector3f vector3f, int playerID, int entityId, Object fixPosePacket) {
|
||||||
|
super(entity, furniture, vector3f, playerID);
|
||||||
|
this.entityId = entityId;
|
||||||
|
this.syncPosePacket = fixPosePacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(NetWorkUser to) {
|
||||||
|
to.sendPacket(syncPosePacket, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismount(Player player) {
|
||||||
|
if (player == null) return;
|
||||||
|
org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) player.platformPlayer();
|
||||||
|
bukkitPlayer.setPose(Pose.STANDING, false);
|
||||||
|
try {
|
||||||
|
Object packet = NetworkReflections.constructor$ClientboundRemoveEntitiesPacket.newInstance((Object) new int[]{entityId});
|
||||||
|
player.sendPacket(packet, false);
|
||||||
|
} catch (Exception e) {
|
||||||
|
BukkitCraftEngine.instance().logger().warn("Failed to dismount from CrawlEntity", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Key type() {
|
||||||
|
return SeatType.CRAWL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory implements SeatFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Seat create(List<String> args) {
|
||||||
|
if (args.size() == 1) return new CrawlSeat(MiscUtils.getAsVector3f(args.getFirst(), "seats"), 0, false);
|
||||||
|
return new CrawlSeat(MiscUtils.getAsVector3f(args.getFirst(), "seats"), Float.parseFloat(args.get(1)), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,698 @@
|
|||||||
|
package net.momirealms.craftengine.bukkit.entity.furniture.seat;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.data.LivingEntityData;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.data.PlayerData;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||||
|
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MItems;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.scheduler.impl.FoliaTask;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.*;
|
||||||
|
import net.momirealms.craftengine.core.entity.EquipmentSlot;
|
||||||
|
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
|
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||||
|
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
|
||||||
|
import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent;
|
||||||
|
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
||||||
|
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask;
|
||||||
|
import net.momirealms.craftengine.core.util.*;
|
||||||
|
import net.momirealms.craftengine.core.world.BlockPos;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Statistic;
|
||||||
|
import org.bukkit.attribute.Attribute;
|
||||||
|
import org.bukkit.attribute.AttributeInstance;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
|
import org.bukkit.event.player.PlayerAnimationEvent;
|
||||||
|
import org.bukkit.event.player.PlayerAnimationType;
|
||||||
|
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||||
|
import org.bukkit.inventory.EntityEquipment;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static net.momirealms.craftengine.core.plugin.network.ProtocolVersion.V1_21_2;
|
||||||
|
|
||||||
|
public class LaySeat extends AbstractSeat {
|
||||||
|
public static final SeatFactory FACTORY = new Factory();
|
||||||
|
private static final List<Pair<Object, Object>> emptyEquipments;
|
||||||
|
private static final List<Pair<Object, ItemStack>> emptyBukkitEquipments;
|
||||||
|
private static Method method$InventoryView$convertSlot;
|
||||||
|
private static Method method$InventoryView$getTopInventory;
|
||||||
|
private static Method method$InventoryView$getType;
|
||||||
|
private final Direction facing;
|
||||||
|
private final boolean sleep;
|
||||||
|
private final boolean phantom;
|
||||||
|
|
||||||
|
static {
|
||||||
|
if (!VersionHelper.isOrAbove1_21_1()) {
|
||||||
|
method$InventoryView$convertSlot = ReflectionUtils.getMethod(InventoryView.class, new String[]{"convertSlot"}, int.class);
|
||||||
|
method$InventoryView$getTopInventory = ReflectionUtils.getMethod(InventoryView.class, new String[]{"getTopInventory"});
|
||||||
|
method$InventoryView$getType = ReflectionUtils.getMethod(Inventory.class, new String[]{"getType"});
|
||||||
|
}
|
||||||
|
emptyEquipments = List.of(
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$MAINHAND, MItems.AIR$Item),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, MItems.AIR$Item),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$HEAD, MItems.AIR$Item),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$CHEST, MItems.AIR$Item),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$LEGS, MItems.AIR$Item),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$FEET, MItems.AIR$Item)
|
||||||
|
);
|
||||||
|
emptyBukkitEquipments = List.of(
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$MAINHAND, ItemUtils.AIR),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, ItemUtils.AIR),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$HEAD, ItemUtils.AIR),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$CHEST, ItemUtils.AIR),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$LEGS, ItemUtils.AIR),
|
||||||
|
Pair.of(CoreReflections.instance$EquipmentSlot$FEET, ItemUtils.AIR)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LaySeat(Vector3f offset, Direction facing, boolean sleep, boolean phantom) {
|
||||||
|
super(offset, 0);
|
||||||
|
this.facing = facing;
|
||||||
|
this.sleep = sleep;
|
||||||
|
this.phantom = phantom;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
public SeatEntity spawn(Player cePlayer, Furniture furniture) {
|
||||||
|
Location loc = ((BukkitFurniture) furniture).calculateSeatLocation(this);
|
||||||
|
|
||||||
|
org.bukkit.entity.Player player = (org.bukkit.entity.Player) cePlayer.platformPlayer();
|
||||||
|
Object serverPlayer = cePlayer.serverPlayer();
|
||||||
|
|
||||||
|
// Pose offset nearly same as vanilla
|
||||||
|
AttributeInstance attribute = VersionHelper.isOrAbove1_21_2() ? player.getAttribute(Attribute.SCALE) : null;
|
||||||
|
double scale = attribute == null ? 1 : attribute.getValue();
|
||||||
|
loc.add(0, 0.08525 * scale, 0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<Object> packets = new ArrayList<>();
|
||||||
|
// NPC
|
||||||
|
Object server = CoreReflections.method$MinecraftServer$getServer.invoke(null);
|
||||||
|
Object level = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld());
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
Object npcProfile = CoreReflections.constructor$GameProfile.newInstance(uuid, player.getName());
|
||||||
|
Object playerProfile = CoreReflections.method$ServerPlayer$getGameProfile.invoke(serverPlayer);
|
||||||
|
|
||||||
|
Multimap<String, Object> properties = (Multimap<String, Object>) CoreReflections.method$GameProfile$getProperties.invoke(npcProfile);
|
||||||
|
properties.putAll((Multimap<String, Object>) CoreReflections.method$GameProfile$getProperties.invoke(playerProfile));
|
||||||
|
|
||||||
|
Object npc;
|
||||||
|
if (VersionHelper.isOrAbove1_20_2()) {
|
||||||
|
Object clientInfo = CoreReflections.method$ServerPlayer$clientInformation.invoke(serverPlayer);
|
||||||
|
npc = CoreReflections.constructor$ServerPlayer.newInstance(server, level, npcProfile, clientInfo);
|
||||||
|
} else {
|
||||||
|
npc = CoreReflections.constructor$ServerPlayer.newInstance(server, level, npcProfile);
|
||||||
|
}
|
||||||
|
int npcId = FastNMS.INSTANCE.method$Entity$getId(npc);
|
||||||
|
CoreReflections.method$Entity$absSnapTo.invoke(npc, loc.getX(), loc.getY(), loc.getZ(), 0, 0);
|
||||||
|
Object npcSpawnPacket;
|
||||||
|
if (!VersionHelper.isOrAbove1_20_2()) {
|
||||||
|
npcSpawnPacket = NetworkReflections.constructor$ClientboundAddPlayerPacket.newInstance(npc);
|
||||||
|
} else {
|
||||||
|
npcSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(npcId, uuid,
|
||||||
|
loc.getX(), loc.getY(), loc.getZ(), 0, 0,
|
||||||
|
MEntityTypes.PLAYER, 0, CoreReflections.instance$Vec3$Zero, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info
|
||||||
|
EnumSet enumSet = EnumSet.noneOf((Class<? extends Enum>) NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket$Action);
|
||||||
|
enumSet.add(NetworkReflections.instance$ClientboundPlayerInfoUpdatePacket$Action$ADD_PLAYER);
|
||||||
|
Object entry;
|
||||||
|
if (VersionHelper.isOrAbove1_21_4()) {
|
||||||
|
entry = NetworkReflections.constructor$ClientBoundPlayerInfoUpdatePacket$Entry.newInstance(
|
||||||
|
uuid, npcProfile, false, 0, CoreReflections.instance$GameType$SURVIVAL, null, true, 0, null);
|
||||||
|
} else if (VersionHelper.isOrAbove1_21_3()) {
|
||||||
|
entry = NetworkReflections.constructor$ClientBoundPlayerInfoUpdatePacket$Entry.newInstance(
|
||||||
|
uuid, npcProfile, false, 0, CoreReflections.instance$GameType$SURVIVAL, null, 0, null);
|
||||||
|
} else {
|
||||||
|
entry = NetworkReflections.constructor$ClientBoundPlayerInfoUpdatePacket$Entry.newInstance(
|
||||||
|
uuid, npcProfile, false, 0, CoreReflections.instance$GameType$SURVIVAL, null, null);
|
||||||
|
}
|
||||||
|
Object npcInfoPacket = FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket(enumSet, Collections.singletonList(entry));
|
||||||
|
|
||||||
|
// Bed
|
||||||
|
Direction bedDir = Direction.fromYaw(loc.getYaw() + Direction.getYaw(facing));
|
||||||
|
if (bedDir == Direction.EAST || bedDir == Direction.WEST) bedDir = bedDir.opposite();
|
||||||
|
BlockData bedData = Material.WHITE_BED.createBlockData("[facing=" + bedDir.name().toLowerCase() + ",part=head]");
|
||||||
|
Location bedLoc = loc.clone();
|
||||||
|
bedLoc.setY(bedLoc.getWorld().getMinHeight());
|
||||||
|
Object bedPos = LocationUtils.toBlockPos(new BlockPos(bedLoc.getBlockX(), bedLoc.getBlockY(), bedLoc.getBlockZ()));
|
||||||
|
Object blockState = BlockStateUtils.blockDataToBlockState(bedData);
|
||||||
|
Object bedPacket = NetworkReflections.constructor$ClientboundBlockUpdatePacket.newInstance(bedPos, blockState);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
Object npcData = CoreReflections.method$Entity$getEntityData.invoke(npc);
|
||||||
|
Object playerData = CoreReflections.method$Entity$getEntityData.invoke(serverPlayer);
|
||||||
|
CoreReflections.method$Entity$setInvisible.invoke(serverPlayer, true);
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(npcData, PlayerData.Pose.entityDataAccessor(), CoreReflections.instance$Pose$SLEEPING);
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(npcData, LivingEntityData.SleepingPos.entityDataAccessor(), Optional.of(bedPos));
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(npcData, PlayerData.PlayerModeCustomisation.entityDataAccessor(), CoreReflections.method$SynchedEntityData$get.invoke(playerData, PlayerData.PlayerModeCustomisation.entityDataAccessor()));
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(npcData, PlayerData.PlayerMainHand.entityDataAccessor(), CoreReflections.method$SynchedEntityData$get.invoke(playerData, PlayerData.PlayerMainHand.entityDataAccessor()));
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(npcData, PlayerData.ShoulderLeft.entityDataAccessor(), CoreReflections.method$SynchedEntityData$get.invoke(playerData, PlayerData.ShoulderLeft.entityDataAccessor()));
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(npcData, PlayerData.ShoulderRight.entityDataAccessor(), CoreReflections.method$SynchedEntityData$get.invoke(playerData, PlayerData.ShoulderRight.entityDataAccessor()));
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(playerData, PlayerData.ShoulderLeft.entityDataAccessor(), CoreReflections.instance$CompoundTag$Empty);
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(playerData, PlayerData.ShoulderRight.entityDataAccessor(), CoreReflections.instance$CompoundTag$Empty);
|
||||||
|
|
||||||
|
// SetData
|
||||||
|
CoreReflections.method$Entity$setInvisible.invoke(serverPlayer, true);
|
||||||
|
Object npcDataPacket = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(
|
||||||
|
npcId, (List) CoreReflections.method$SynchedEntityData$packDirty.invoke(npcData)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove
|
||||||
|
Object npcRemovePacket = NetworkReflections.constructor$ClientboundRemoveEntitiesPacket.newInstance((Object) new int[]{npcId});
|
||||||
|
|
||||||
|
// TP
|
||||||
|
Object npcTeleportPacket;
|
||||||
|
if (VersionHelper.isOrAbove1_21_3()) {
|
||||||
|
Object positionMoveRotation = CoreReflections.method$PositionMoveRotation$of.invoke(null, npc);
|
||||||
|
npcTeleportPacket = NetworkReflections.constructor$ClientboundTeleportEntityPacket.newInstance(npcId, positionMoveRotation, Set.of(), false);
|
||||||
|
} else {
|
||||||
|
npcTeleportPacket = NetworkReflections.constructor$ClientboundTeleportEntityPacket.newInstance(npc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equipment
|
||||||
|
Object emptyEquipPacket = NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance(player.getEntityId(), emptyEquipments);
|
||||||
|
|
||||||
|
Map<EquipmentSlot, ItemStack> equipments = new HashMap<>();
|
||||||
|
EntityEquipment equipment = player.getEquipment();
|
||||||
|
for (org.bukkit.inventory.EquipmentSlot slot : org.bukkit.inventory.EquipmentSlot.values()) {
|
||||||
|
if ((!slot.isHand() && !slot.isArmor())
|
||||||
|
|| (VersionHelper.isOrAbove1_20_5() && slot == org.bukkit.inventory.EquipmentSlot.BODY)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EquipmentSlot slotId = EntityUtils.toCEEquipmentSlot(slot);
|
||||||
|
ItemStack item = equipment.getItem(slot);
|
||||||
|
equipments.put(slotId, item);
|
||||||
|
}
|
||||||
|
List<Pair<Object, Object>> npcSlots = new ArrayList<>();
|
||||||
|
equipments.forEach((slot, item) -> npcSlots.add(Pair.of(EntityUtils.fromEquipmentSlot(slot), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(item))));
|
||||||
|
Object fullEquipPacket = NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance(npcId, npcSlots);
|
||||||
|
|
||||||
|
// Animation
|
||||||
|
Object npcLeftAnimatePacket = NetworkReflections.constructor$ClientboundAnimatePacket.newInstance(npc, 0);
|
||||||
|
Object npcRightAnimatePacket = NetworkReflections.constructor$ClientboundAnimatePacket.newInstance(npc, 3);
|
||||||
|
|
||||||
|
packets.add(npcInfoPacket);
|
||||||
|
packets.add(npcSpawnPacket);
|
||||||
|
packets.add(bedPacket);
|
||||||
|
packets.add(npcDataPacket);
|
||||||
|
packets.add(npcTeleportPacket);
|
||||||
|
packets.add(emptyEquipPacket);
|
||||||
|
packets.add(npcLeftAnimatePacket);
|
||||||
|
Object npcInitPackets = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
|
||||||
|
|
||||||
|
// Spawn
|
||||||
|
org.bukkit.entity.Entity seatEntity = BukkitFurniture.spawnSeatEntity(furniture, player.getWorld(), loc, false, null);
|
||||||
|
if (!seatEntity.addPassenger(player)) { // 0.5 higher
|
||||||
|
seatEntity.remove();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cePlayer.sendPacket(npcInitPackets, true);
|
||||||
|
cePlayer.sendPacket(fullEquipPacket, true);
|
||||||
|
if (player.getY() > 0 && cePlayer.protocolVersion().isVersionNewerThan(V1_21_2)) {
|
||||||
|
BukkitCraftEngine.instance().scheduler().asyncLater(() -> cePlayer.sendPacket(npcTeleportPacket, true),
|
||||||
|
50, TimeUnit.MILLISECONDS); // over height 0 cost 2 npcTeleportPacket
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<NetWorkUser> trackers = new HashSet<>();
|
||||||
|
for (org.bukkit.entity.Player o : PlayerUtils.getTrackedBy(player)) {
|
||||||
|
NetWorkUser tracker = BukkitNetworkManager.instance().getOnlineUser(o);
|
||||||
|
tracker.sendPacket(npcInitPackets, false);
|
||||||
|
tracker.sendPacket(fullEquipPacket, false);
|
||||||
|
if (player.getY() > 0 && tracker.protocolVersion().isVersionNewerThan(V1_21_2)) {
|
||||||
|
BukkitCraftEngine.instance().scheduler().asyncLater(() -> tracker.sendPacket(npcTeleportPacket, false),
|
||||||
|
50, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
trackers.add(tracker);
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeadRot
|
||||||
|
Direction npcDir = bedDir.opposite();
|
||||||
|
|
||||||
|
if (sleep) {
|
||||||
|
player.setSleepingIgnored(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phantom) {
|
||||||
|
player.setStatistic(Statistic.TIME_SINCE_REST, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LayEntity(
|
||||||
|
seatEntity,
|
||||||
|
furniture,
|
||||||
|
this.offset(),
|
||||||
|
npcInitPackets,
|
||||||
|
npcRemovePacket,
|
||||||
|
npcTeleportPacket,
|
||||||
|
npcLeftAnimatePacket,
|
||||||
|
npcRightAnimatePacket,
|
||||||
|
(BukkitServerPlayer) cePlayer,
|
||||||
|
trackers,
|
||||||
|
bedLoc,
|
||||||
|
npc,
|
||||||
|
npcId,
|
||||||
|
npcDir,
|
||||||
|
equipments,
|
||||||
|
emptyEquipPacket,
|
||||||
|
fullEquipPacket,
|
||||||
|
sleep
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to spawn LaySeat", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LayEntity extends BukkitSeatEntity {
|
||||||
|
private final Object npcInitPackets;
|
||||||
|
private final Object npcRemovePacket;
|
||||||
|
private final Object npcTPPacket;
|
||||||
|
private final Object npcLeftAnimatePacket;
|
||||||
|
private final Object npcRightAnimatePacket;
|
||||||
|
private final BukkitServerPlayer serverPlayer;
|
||||||
|
private final Object npc;
|
||||||
|
private final Location bedLoc;
|
||||||
|
private final int npcID;
|
||||||
|
private final Direction npcDir;
|
||||||
|
private final Set<NetWorkUser> trackers;
|
||||||
|
|
||||||
|
// Equipment
|
||||||
|
private final PlayerMonitorTask task;
|
||||||
|
private final Map<EquipmentSlot, ItemStack> equipments;
|
||||||
|
private final Object emptyEquipPacket;
|
||||||
|
private Object updateEquipPacket;
|
||||||
|
private Object fullEquipPacket;
|
||||||
|
|
||||||
|
private final boolean sleep;
|
||||||
|
private Object npcRotHeadPacket;
|
||||||
|
private Object npcDataPacket;
|
||||||
|
|
||||||
|
public LayEntity(
|
||||||
|
org.bukkit.entity.Entity entity,
|
||||||
|
Furniture furniture,
|
||||||
|
Vector3f vector,
|
||||||
|
Object npcInitPackets,
|
||||||
|
Object npcRemovePacket,
|
||||||
|
Object npcTPPacket,
|
||||||
|
Object npcLeftAnimatePacket,
|
||||||
|
Object npcRightAnimatePacket,
|
||||||
|
BukkitServerPlayer serverPlayer,
|
||||||
|
Set<NetWorkUser> trackers,
|
||||||
|
Location bedLoc,
|
||||||
|
Object npc,
|
||||||
|
int npcID,
|
||||||
|
Direction npcDir,
|
||||||
|
Map<EquipmentSlot, ItemStack> equipments,
|
||||||
|
Object emptyEquipPacket,
|
||||||
|
Object fullEquipPacket,
|
||||||
|
boolean sleep
|
||||||
|
) {
|
||||||
|
super(entity, furniture, vector, serverPlayer.entityID());
|
||||||
|
this.npcInitPackets = npcInitPackets;
|
||||||
|
this.npcRemovePacket = npcRemovePacket;
|
||||||
|
this.npcTPPacket = npcTPPacket;
|
||||||
|
this.npcLeftAnimatePacket = npcLeftAnimatePacket;
|
||||||
|
this.npcRightAnimatePacket = npcRightAnimatePacket;
|
||||||
|
this.serverPlayer = serverPlayer;
|
||||||
|
this.trackers = trackers;
|
||||||
|
this.bedLoc = bedLoc;
|
||||||
|
this.npc = npc;
|
||||||
|
this.npcID = npcID;
|
||||||
|
this.npcDir = npcDir;
|
||||||
|
|
||||||
|
this.task = new PlayerMonitorTask();
|
||||||
|
this.equipments = equipments;
|
||||||
|
this.emptyEquipPacket = emptyEquipPacket;
|
||||||
|
this.fullEquipPacket = fullEquipPacket;
|
||||||
|
|
||||||
|
this.sleep = sleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(NetWorkUser to) {
|
||||||
|
to.sendPacket(this.npcInitPackets, false);
|
||||||
|
to.sendPacket(this.fullEquipPacket, false);
|
||||||
|
to.sendPacket(this.npcRotHeadPacket, false);
|
||||||
|
if (npcDataPacket != null) to.sendPacket(this.npcDataPacket, false);
|
||||||
|
if (serverPlayer.y() > 0 && to.protocolVersion().isVersionNewerThan(V1_21_2)) {
|
||||||
|
BukkitCraftEngine.instance().scheduler().asyncLater(() ->
|
||||||
|
to.sendPacket(this.npcTPPacket, false), 50, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
trackers.add(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handleEntitiesRemove(NetWorkUser user, IntList entityIds) {
|
||||||
|
entityIds.add(npcID);
|
||||||
|
trackers.remove(user);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dismount(Player player) {
|
||||||
|
super.dismount(player);
|
||||||
|
if (player != null) return;
|
||||||
|
try { // for disconnect recover
|
||||||
|
Object blockPos = LocationUtils.toBlockPos(bedLoc.getBlockX(), bedLoc.getBlockY(), bedLoc.getBlockZ());
|
||||||
|
Object blockState = BlockStateUtils.blockDataToBlockState(bedLoc.getBlock().getBlockData());
|
||||||
|
Object blockRecoverPacket = NetworkReflections.constructor$ClientboundBlockUpdatePacket.newInstance(blockPos, blockState);
|
||||||
|
for (NetWorkUser tracker : trackers) {
|
||||||
|
tracker.sendPacket(blockRecoverPacket, false);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to dismount player", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismount(Player player) {
|
||||||
|
this.task.task.cancel();
|
||||||
|
|
||||||
|
org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) player.platformPlayer();
|
||||||
|
Object blockPos = LocationUtils.toBlockPos(bedLoc.getBlockX(), bedLoc.getBlockY(), bedLoc.getBlockZ());
|
||||||
|
Object blockState = BlockStateUtils.blockDataToBlockState(bedLoc.getBlock().getBlockData());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object blockRecoverPacket = NetworkReflections.constructor$ClientboundBlockUpdatePacket.newInstance(blockPos, blockState);
|
||||||
|
player.sendPacket(this.npcRemovePacket, true);
|
||||||
|
player.sendPacket(blockRecoverPacket, true);
|
||||||
|
|
||||||
|
if (bukkitPlayer.getPotionEffect(PotionEffectType.INVISIBILITY) == null) {
|
||||||
|
CoreReflections.method$Entity$setInvisible.invoke(serverPlayer.serverPlayer(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object npcData = CoreReflections.method$Entity$getEntityData.invoke(npc);
|
||||||
|
Object playerData = CoreReflections.method$Entity$getEntityData.invoke(serverPlayer.serverPlayer());
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(
|
||||||
|
playerData,
|
||||||
|
PlayerData.ShoulderLeft.entityDataAccessor(),
|
||||||
|
CoreReflections.method$SynchedEntityData$get.invoke(npcData, PlayerData.ShoulderLeft.entityDataAccessor())
|
||||||
|
);
|
||||||
|
CoreReflections.method$SynchedEntityData$set.invoke(
|
||||||
|
playerData,
|
||||||
|
PlayerData.ShoulderRight.entityDataAccessor(),
|
||||||
|
CoreReflections.method$SynchedEntityData$get.invoke(npcData, PlayerData.ShoulderRight.entityDataAccessor())
|
||||||
|
);
|
||||||
|
|
||||||
|
bukkitPlayer.updateInventory();
|
||||||
|
|
||||||
|
if (sleep) {
|
||||||
|
bukkitPlayer.setSleepingIgnored(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object fullSlots = NetworkReflections.method$ClientboundSetEquipmentPacket$getSlots.invoke(this.fullEquipPacket);
|
||||||
|
Object recoverEquip = NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance(bukkitPlayer.getEntityId(), fullSlots);
|
||||||
|
|
||||||
|
for (NetWorkUser tracker : trackers) {
|
||||||
|
tracker.sendPacket(this.npcRemovePacket, false);
|
||||||
|
tracker.sendPacket(blockRecoverPacket, false);
|
||||||
|
tracker.sendPacket(recoverEquip, false);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to dismount from LayEntity", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void equipmentChange(Map<EquipmentSlot, ItemStack> equipmentChanges, int previousSlot) {
|
||||||
|
org.bukkit.entity.Player player = serverPlayer.platformPlayer();
|
||||||
|
List<Pair<Object, Object>> changedSlots = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Map.Entry<EquipmentSlot, ItemStack> entry : equipmentChanges.entrySet()) {
|
||||||
|
Object slotId = EntityUtils.fromEquipmentSlot(entry.getKey());
|
||||||
|
Object itemStack = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(entry.getValue());
|
||||||
|
changedSlots.add(Pair.of(slotId, itemStack));
|
||||||
|
}
|
||||||
|
this.equipments.putAll(equipmentChanges);
|
||||||
|
|
||||||
|
List<Pair<Object, Object>> allSlots = new ArrayList<>();
|
||||||
|
equipments.forEach((slot, item) ->
|
||||||
|
allSlots.add(Pair.of(EntityUtils.fromEquipmentSlot(slot), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(item))));
|
||||||
|
try {
|
||||||
|
this.updateEquipPacket = NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance(npcID, changedSlots);
|
||||||
|
this.fullEquipPacket = NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance(npcID, allSlots);
|
||||||
|
if (previousSlot != -1) {
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to handle equipmentChange", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
serverPlayer.sendPacket(this.emptyEquipPacket, false);
|
||||||
|
serverPlayer.sendPacket(this.updateEquipPacket, false);
|
||||||
|
|
||||||
|
for (NetWorkUser tracker : trackers) {
|
||||||
|
tracker.sendPacket(this.updateEquipPacket, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleSetEquipment(NetWorkUser user, ByteBufPacketEvent event, Object slots) {
|
||||||
|
if (emptyBukkitEquipments.equals(slots)) return;
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleContainerSetSlot(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||||
|
try {
|
||||||
|
int slot = (int) NetworkReflections.method$ClientboundContainerSetSlotPacket$getSlot.invoke(packet);
|
||||||
|
org.bukkit.entity.Player player = (org.bukkit.entity.Player) user.platformPlayer();
|
||||||
|
|
||||||
|
int convertSlot;
|
||||||
|
boolean isPlayerInv;
|
||||||
|
|
||||||
|
if (!VersionHelper.isOrAbove1_21_1()) {
|
||||||
|
Object openInventory = player.getOpenInventory();
|
||||||
|
convertSlot = (int) method$InventoryView$convertSlot.invoke(openInventory, slot);
|
||||||
|
Object topInventory = method$InventoryView$getTopInventory.invoke(openInventory);
|
||||||
|
Object type = method$InventoryView$getType.invoke(topInventory);
|
||||||
|
isPlayerInv = type == InventoryType.CRAFTING;
|
||||||
|
} else {
|
||||||
|
convertSlot = player.getOpenInventory().convertSlot(slot);
|
||||||
|
isPlayerInv = player.getOpenInventory().getTopInventory().getType() == InventoryType.CRAFTING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(convertSlot == player.getInventory().getHeldItemSlot() || (isPlayerInv && (slot == 45 || (slot >= 5 && slot <= 8)))))
|
||||||
|
return;
|
||||||
|
int containerId = (int) NetworkReflections.method$ClientboundContainerSetSlotPacket$getContainerId.invoke(packet);
|
||||||
|
int stateId = (int) NetworkReflections.method$ClientboundContainerSetSlotPacket$getStateId.invoke(packet);
|
||||||
|
Object replacePacket = NetworkReflections.constructor$ClientboundContainerSetSlotPacket.newInstance(containerId, stateId, slot, MItems.AIR$Item);
|
||||||
|
event.replacePacket(replacePacket);
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to handleContainerSetSlotPacket", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void event(Player player, Object event) {
|
||||||
|
if (event instanceof PlayerAnimationEvent e) {
|
||||||
|
try {
|
||||||
|
Object animatePacket;
|
||||||
|
if (e.getAnimationType() == PlayerAnimationType.ARM_SWING) {
|
||||||
|
animatePacket = npcLeftAnimatePacket;
|
||||||
|
} else {
|
||||||
|
animatePacket = npcRightAnimatePacket;
|
||||||
|
}
|
||||||
|
serverPlayer.sendPacket(animatePacket, true);
|
||||||
|
for (NetWorkUser tracker : trackers) {
|
||||||
|
tracker.sendPacket(animatePacket, true);
|
||||||
|
}
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to handle PlayerAnimationEvent", exception);
|
||||||
|
}
|
||||||
|
} else if (event instanceof PlayerItemHeldEvent e) {
|
||||||
|
ItemStack item = e.getPlayer().getInventory().getItem(e.getNewSlot());
|
||||||
|
if (item == null) item = ItemUtils.AIR;
|
||||||
|
|
||||||
|
equipmentChange(Map.of(EquipmentSlot.MAIN_HAND, item), e.getPreviousSlot());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Key type() {
|
||||||
|
return SeatType.LAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PlayerMonitorTask implements Runnable {
|
||||||
|
|
||||||
|
private final SchedulerTask task;
|
||||||
|
private float lastYaw;
|
||||||
|
|
||||||
|
private PlayerMonitorTask() {
|
||||||
|
org.bukkit.entity.Player p = serverPlayer.platformPlayer();
|
||||||
|
BukkitCraftEngine plugin = BukkitCraftEngine.instance();
|
||||||
|
if (VersionHelper.isFolia()) {
|
||||||
|
this.task = new FoliaTask(p.getScheduler().runAtFixedRate(plugin.javaPlugin(), (t) -> this.run(), () -> {
|
||||||
|
}, 1, 1));
|
||||||
|
} else {
|
||||||
|
this.task = plugin.scheduler().sync().runRepeating(this, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
org.bukkit.entity.Player player = serverPlayer.platformPlayer();
|
||||||
|
if (player == null || !player.isValid()) {
|
||||||
|
this.task.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invisible
|
||||||
|
updateNpcInvisible();
|
||||||
|
try {
|
||||||
|
if (!player.isInvisible())
|
||||||
|
CoreReflections.method$Entity$setInvisible.invoke(serverPlayer.serverPlayer(), true);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to set shared flag", exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync Rotation
|
||||||
|
float playerYaw = player.getYaw();
|
||||||
|
if (lastYaw != playerYaw) {
|
||||||
|
updateNpcYaw(playerYaw);
|
||||||
|
serverPlayer.sendPacket(npcRotHeadPacket, false);
|
||||||
|
for (NetWorkUser tracker : trackers) {
|
||||||
|
tracker.sendPacket(npcRotHeadPacket, true);
|
||||||
|
}
|
||||||
|
this.lastYaw = playerYaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync Equipment
|
||||||
|
Map<EquipmentSlot, ItemStack> newEquipments = new HashMap<>();
|
||||||
|
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
||||||
|
if (!slot.isHand() && !slot.isPlayerArmor()) continue;
|
||||||
|
ItemStack newItem = player.getEquipment().getItem(EntityUtils.toBukkitEquipmentSlot(slot));
|
||||||
|
try {
|
||||||
|
ItemStack item = equipments.get(slot);
|
||||||
|
boolean isChange = !newItem.equals(item);
|
||||||
|
if (isChange) {
|
||||||
|
newEquipments.put(slot, newItem);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to monitor equipments change", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newEquipments.isEmpty()) {
|
||||||
|
equipmentChange(newEquipments, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
serverPlayer.sendPacket(emptyEquipPacket, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateNpcYaw(float playerYaw) {
|
||||||
|
byte packYaw = getRot(playerYaw);
|
||||||
|
try {
|
||||||
|
this.npcRotHeadPacket = NetworkReflections.constructor$ClientboundRotateHeadPacket.newInstance(npc, packYaw);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to sync NPC yaw", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte getRot(float playerYaw) {
|
||||||
|
float npcYaw = Direction.getYaw(npcDir);
|
||||||
|
float centerYaw = normalizeYaw(npcYaw);
|
||||||
|
float playerYawNorm = normalizeYaw(playerYaw);
|
||||||
|
|
||||||
|
float deltaYaw = normalizeYaw(playerYawNorm - centerYaw);
|
||||||
|
boolean isBehind = Math.abs(deltaYaw) > 90;
|
||||||
|
|
||||||
|
float mappedYaw;
|
||||||
|
if (isBehind) {
|
||||||
|
float rel = Math.abs(deltaYaw) - 180;
|
||||||
|
mappedYaw = rel * (deltaYaw > 0 ? -1 : 1);
|
||||||
|
} else {
|
||||||
|
mappedYaw = deltaYaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
float finalYaw = Math.max(-45, Math.min(45, mappedYaw));
|
||||||
|
return MCUtils.packDegrees(finalYaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float normalizeYaw(float yaw) {
|
||||||
|
yaw %= 360.0f;
|
||||||
|
if (yaw < -180.0f) yaw += 360.0f;
|
||||||
|
if (yaw >= 180.0f) yaw -= 360.0f;
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateNpcInvisible() {
|
||||||
|
try {
|
||||||
|
org.bukkit.entity.Player player = serverPlayer.platformPlayer();
|
||||||
|
if (player.getPotionEffect(PotionEffectType.INVISIBILITY) == null && npcDataPacket != null) {
|
||||||
|
npcDataPacket = null;
|
||||||
|
CoreReflections.method$Entity$setInvisible.invoke(npc, false);
|
||||||
|
Object npcData = CoreReflections.method$Entity$getEntityData.invoke(npc);
|
||||||
|
Object dataItem = CoreReflections.method$SynchedEntityData$getItem.invoke(npcData, PlayerData.SharedFlags.entityDataAccessor());
|
||||||
|
Object dataValue = CoreReflections.method$SynchedEntityData$DataItem$value.invoke(dataItem);
|
||||||
|
Object packet = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(npcID, List.of(dataValue));
|
||||||
|
serverPlayer.sendPacket(packet, false);
|
||||||
|
for (NetWorkUser tracker : trackers) {
|
||||||
|
tracker.sendPacket(packet, false);
|
||||||
|
}
|
||||||
|
} else if (player.getPotionEffect(PotionEffectType.INVISIBILITY) != null && npcDataPacket == null) {
|
||||||
|
CoreReflections.method$Entity$setInvisible.invoke(npc, true);
|
||||||
|
Object npcData = CoreReflections.method$Entity$getEntityData.invoke(npc);
|
||||||
|
Object dataItem = CoreReflections.method$SynchedEntityData$getItem.invoke(npcData, PlayerData.SharedFlags.entityDataAccessor());
|
||||||
|
Object dataValue = CoreReflections.method$SynchedEntityData$DataItem$value.invoke(dataItem);
|
||||||
|
npcDataPacket = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(npcID, List.of(dataValue));
|
||||||
|
serverPlayer.sendPacket(npcDataPacket, false);
|
||||||
|
for (NetWorkUser tracker : trackers) {
|
||||||
|
tracker.sendPacket(npcDataPacket, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to updateNpcInvisible", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory implements SeatFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Seat create(List<String> args) {
|
||||||
|
Vector3f offset = MiscUtils.getAsVector3f(args.get(0), "seats");
|
||||||
|
Direction facing = args.size() > 1 ? parseFacing(args.get(1)) : Direction.SOUTH;
|
||||||
|
boolean sleep = args.size() > 2 && Boolean.parseBoolean(args.get(2));
|
||||||
|
boolean phantom = args.size() > 4 && Boolean.parseBoolean(args.get(3));
|
||||||
|
|
||||||
|
if (facing == Direction.NORTH || facing == Direction.SOUTH) {
|
||||||
|
float temp = offset.x;
|
||||||
|
offset.x = offset.z;
|
||||||
|
offset.z = temp;
|
||||||
|
}
|
||||||
|
return new LaySeat(offset, facing, sleep, phantom);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Direction parseFacing(String facing) {
|
||||||
|
return switch (facing.toLowerCase()) {
|
||||||
|
case "back" -> Direction.NORTH;
|
||||||
|
case "left" -> Direction.WEST;
|
||||||
|
case "right" -> Direction.EAST;
|
||||||
|
default -> Direction.SOUTH;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package net.momirealms.craftengine.bukkit.entity.furniture.seat;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||||
|
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
|
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SitSeat extends AbstractSeat {
|
||||||
|
public static final SeatFactory FACTORY = new Factory();
|
||||||
|
private final boolean limitPlayerRotation;
|
||||||
|
|
||||||
|
public SitSeat(Vector3f offset, float yaw, boolean limitPlayerRotation) {
|
||||||
|
super(offset, yaw);
|
||||||
|
this.limitPlayerRotation = limitPlayerRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SeatEntity spawn(Player player, Furniture furniture) {
|
||||||
|
return spawn((org.bukkit.entity.Player) player.platformPlayer(), furniture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeatEntity spawn(org.bukkit.entity.Player player, Furniture furniture) {
|
||||||
|
Location location = ((BukkitFurniture) furniture).calculateSeatLocation(this);
|
||||||
|
org.bukkit.entity.Entity seatEntity = BukkitFurniture.spawnSeatEntity(furniture, player.getWorld(), location, this.limitPlayerRotation, null);
|
||||||
|
if (!seatEntity.addPassenger(player)) {
|
||||||
|
seatEntity.remove();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new SitEntity(seatEntity, furniture, offset(), player.getEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SitEntity extends BukkitSeatEntity {
|
||||||
|
|
||||||
|
public SitEntity(Entity entity, Furniture furniture, Vector3f vector3f, int playerID) {
|
||||||
|
super(entity, furniture, vector3f, playerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Key type() {
|
||||||
|
return SeatType.SIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory implements SeatFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Seat create(List<String> args) {
|
||||||
|
if (args.size() == 1) return new SitSeat(MiscUtils.getAsVector3f(args.getFirst(), "seats"), 0, false);
|
||||||
|
return new SitSeat(MiscUtils.getAsVector3f(args.getFirst(), "seats"), Float.parseFloat(args.get(1)), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors;
|
|||||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
|
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
|
||||||
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes;
|
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes;
|
||||||
import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager;
|
import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager;
|
||||||
|
import net.momirealms.craftengine.bukkit.entity.furniture.seat.BukkitSeatTypes;
|
||||||
import net.momirealms.craftengine.bukkit.font.BukkitFontManager;
|
import net.momirealms.craftengine.bukkit.font.BukkitFontManager;
|
||||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||||
import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors;
|
import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors;
|
||||||
@@ -186,6 +187,7 @@ public class BukkitCraftEngine extends CraftEngine {
|
|||||||
BukkitItemBehaviors.init();
|
BukkitItemBehaviors.init();
|
||||||
BukkitHitBoxTypes.init();
|
BukkitHitBoxTypes.init();
|
||||||
PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize());
|
PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize());
|
||||||
|
BukkitSeatTypes.init();
|
||||||
super.packManager = new BukkitPackManager(this);
|
super.packManager = new BukkitPackManager(this);
|
||||||
super.senderFactory = new BukkitSenderFactory(this);
|
super.senderFactory = new BukkitSenderFactory(this);
|
||||||
super.itemManager = new BukkitItemManager(this);
|
super.itemManager = new BukkitItemManager(this);
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos);
|
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos);
|
||||||
registerNMSPacketConsumer(PacketConsumers.ROTATE_HEAD, NetworkReflections.clazz$ClientboundRotateHeadPacket);
|
registerNMSPacketConsumer(PacketConsumers.ROTATE_HEAD, NetworkReflections.clazz$ClientboundRotateHeadPacket);
|
||||||
registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_MOTION, NetworkReflections.clazz$ClientboundSetEntityMotionPacket);
|
registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_MOTION, NetworkReflections.clazz$ClientboundSetEntityMotionPacket);
|
||||||
|
registerNMSPacketConsumer(PacketConsumers.SET_CONTAINER_SLOT, NetworkReflections.clazz$ClientboundContainerSetSlotPacket);
|
||||||
registerNMSPacketConsumer(PacketConsumers.CLIENT_INFO, NetworkReflections.clazz$ServerboundClientInformationPacket);
|
registerNMSPacketConsumer(PacketConsumers.CLIENT_INFO, NetworkReflections.clazz$ServerboundClientInformationPacket);
|
||||||
registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
|
registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
|
||||||
registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
|
registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
|
||||||
@@ -299,7 +300,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
}
|
}
|
||||||
|
|
||||||
public NetWorkUser getOnlineUser(Player player) {
|
public NetWorkUser getOnlineUser(Player player) {
|
||||||
return this.onlineUsers.get(player.getUniqueId());
|
return this.getOnlineUser(player.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetWorkUser getOnlineUser(UUID uuid) {
|
||||||
|
return onlineUsers.get(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Channel getChannel(Player player) {
|
public Channel getChannel(Player player) {
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
|||||||
import net.momirealms.craftengine.bukkit.util.*;
|
import net.momirealms.craftengine.bukkit.util.*;
|
||||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
import net.momirealms.craftengine.core.font.FontManager;
|
import net.momirealms.craftengine.core.font.FontManager;
|
||||||
import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult;
|
import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult;
|
||||||
import net.momirealms.craftengine.core.item.CustomItem;
|
import net.momirealms.craftengine.core.item.CustomItem;
|
||||||
@@ -180,6 +182,17 @@ public class PacketConsumers {
|
|||||||
user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE);
|
user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
ADD_ENTITY_HANDLERS[MEntityTypes.PLAYER$registryId] = (user, event) -> {
|
||||||
|
FriendlyByteBuf buf = event.getBuffer();
|
||||||
|
buf.readVarInt();
|
||||||
|
UUID uuid = buf.readUUID();
|
||||||
|
BukkitServerPlayer player = (BukkitServerPlayer) BukkitCraftEngine.instance().networkManager().getOnlineUser(uuid);
|
||||||
|
if (player == null) return;
|
||||||
|
SeatEntity seat = player.seat();
|
||||||
|
if (seat == null) return;
|
||||||
|
user.entityPacketHandlers().put(seat.playerID(), seat);
|
||||||
|
seat.add(user);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BukkitNetworkManager.Handlers simpleAddEntityHandler(EntityPacketHandler handler) {
|
private static BukkitNetworkManager.Handlers simpleAddEntityHandler(EntityPacketHandler handler) {
|
||||||
@@ -1499,7 +1512,7 @@ public class PacketConsumers {
|
|||||||
for (int i = 0, size = intList.size(); i < size; i++) {
|
for (int i = 0, size = intList.size(); i < size; i++) {
|
||||||
int entityId = intList.getInt(i);
|
int entityId = intList.getInt(i);
|
||||||
EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId);
|
EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId);
|
||||||
if (handler != null && handler.handleEntitiesRemove(intList)) {
|
if (handler != null && handler.handleEntitiesRemove(user, intList)) {
|
||||||
isChange = true;
|
isChange = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1649,6 +1662,8 @@ public class PacketConsumers {
|
|||||||
if (!serverPlayer.isSecondaryUseActive()) {
|
if (!serverPlayer.isSecondaryUseActive()) {
|
||||||
furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> {
|
furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> {
|
||||||
if (furniture.tryOccupySeat(seatPos)) {
|
if (furniture.tryOccupySeat(seatPos)) {
|
||||||
|
SeatEntity currentSeat = serverPlayer.seat();
|
||||||
|
if (currentSeat != null) currentSeat.dismount(serverPlayer);
|
||||||
furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos);
|
furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1915,6 +1930,10 @@ public class PacketConsumers {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> SET_ENTITY_DATA = (user, event) -> {
|
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> SET_ENTITY_DATA = (user, event) -> {
|
||||||
try {
|
try {
|
||||||
|
SeatEntity seat = ((BukkitServerPlayer)user).seat();
|
||||||
|
if (seat != null) {
|
||||||
|
seat.handleSetEntityData(user, event);
|
||||||
|
}
|
||||||
FriendlyByteBuf buf = event.getBuffer();
|
FriendlyByteBuf buf = event.getBuffer();
|
||||||
int id = buf.readVarInt();
|
int id = buf.readVarInt();
|
||||||
EntityPacketHandler handler = user.entityPacketHandlers().get(id);
|
EntityPacketHandler handler = user.entityPacketHandlers().get(id);
|
||||||
@@ -2179,6 +2198,10 @@ public class PacketConsumers {
|
|||||||
FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond());
|
FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EntityPacketHandler handler = user.entityPacketHandlers().get(entity);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.handleSetEquipment(user, event, slots);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEquipmentPacket", e);
|
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEquipmentPacket", e);
|
||||||
}
|
}
|
||||||
@@ -2417,6 +2440,15 @@ public class PacketConsumers {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> SET_CONTAINER_SLOT = (user, event, packet) -> {
|
||||||
|
try {
|
||||||
|
SeatEntity seat = ((BukkitServerPlayer) user).seat();
|
||||||
|
if (seat != null) seat.handleContainerSetSlot(user, event, packet);
|
||||||
|
} catch (Exception e) {
|
||||||
|
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEquipmentPacket", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CLIENT_INFO = (user, event, packet) -> {
|
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CLIENT_INFO = (user, event, packet) -> {
|
||||||
try {
|
try {
|
||||||
Map<String, Object> information = FastNMS.INSTANCE.method$ServerboundClientInformationPacket$information(packet);
|
Map<String, Object> information = FastNMS.INSTANCE.method$ServerboundClientInformationPacket$information(packet);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class FurniturePacketHandler implements EntityPacketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handleEntitiesRemove(IntList entityIds) {
|
public boolean handleEntitiesRemove(NetWorkUser user, IntList entityIds) {
|
||||||
entityIds.addAll(this.fakeEntities);
|
entityIds.addAll(this.fakeEntities);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
||||||
|
|
||||||
|
import com.google.common.collect.ForwardingMultimap;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
@@ -3504,6 +3505,155 @@ public final class CoreReflections {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Method method$Entity$setInvisible = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$Entity, new String[]{"j", "setInvisible"}, boolean.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$GameProfile = requireNonNull(
|
||||||
|
ReflectionUtils.getClazz("com.mojang.authlib.GameProfile")
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Constructor<?> constructor$GameProfile = requireNonNull(
|
||||||
|
ReflectionUtils.getConstructor(
|
||||||
|
clazz$GameProfile, 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$GameProfile$getProperties = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$GameProfile, ForwardingMultimap.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Constructor<?> constructor$ServerPlayer = requireNonNull(
|
||||||
|
ReflectionUtils.getConstructor(
|
||||||
|
clazz$ServerPlayer, 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$ServerPlayer$getGameProfile = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$ServerPlayer, clazz$GameProfile, 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1.20.2 +
|
||||||
|
public static final Method method$ServerPlayer$clientInformation = Optional.ofNullable(clazz$ClientInformation)
|
||||||
|
.map(it -> ReflectionUtils.getMethod(clazz$ServerPlayer, it, 0))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$CompoundTag = requireNonNull(
|
||||||
|
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||||
|
"nbt.NBTTagCompound",
|
||||||
|
"nbt.CompoundTag"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Object instance$CompoundTag$Empty;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
instance$CompoundTag$Empty = CoreReflections.clazz$CompoundTag.getConstructor().newInstance();
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException("Failed to instantiate empty CompoundTag", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Method method$Entity$getEntityData = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$Entity, clazz$SynchedEntityData, 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$SynchedEntityData$set = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$SynchedEntityData, void.class, clazz$EntityDataAccessor, Object.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$SynchedEntityData$isDirty = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$SynchedEntityData, boolean.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$SynchedEntityData$packDirty = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$SynchedEntityData, List.class, new String[]{"b", "packDirty"}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$SynchedEntityData$DataItem = requireNonNull(
|
||||||
|
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||||
|
"network.syncher.DataWatcher$Item",
|
||||||
|
"network.syncher.SynchedEntityData$DataItem"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$SynchedEntityData$getItem = requireNonNull(
|
||||||
|
ReflectionUtils.getDeclaredMethod(
|
||||||
|
clazz$SynchedEntityData, clazz$SynchedEntityData$DataItem, clazz$EntityDataAccessor)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$SynchedEntityData$DataItem$value = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$SynchedEntityData$DataItem, clazz$SynchedEntityData$DataValue, 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$RemoteChatSession$Data = requireNonNull(
|
||||||
|
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||||
|
"network.chat.RemoteChatSession$a",
|
||||||
|
"network.chat.RemoteChatSession$Data"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$GameType$values = requireNonNull(
|
||||||
|
ReflectionUtils.getStaticMethod(
|
||||||
|
clazz$GameType, clazz$GameType.arrayType()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Object instance$GameType$SURVIVAL;
|
||||||
|
public static final Object instance$GameType$CREATIVE;
|
||||||
|
public static final Object instance$GameType$ADVENTURE;
|
||||||
|
public static final Object instance$GameType$SPECTATOR;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Object[] values = (Object[]) method$GameType$values.invoke(null);
|
||||||
|
instance$GameType$SURVIVAL = values[0];
|
||||||
|
instance$GameType$CREATIVE = values[1];
|
||||||
|
instance$GameType$ADVENTURE = values[2];
|
||||||
|
instance$GameType$SPECTATOR = values[3];
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.21.3 +
|
||||||
|
public static final Class<?> clazz$PositionMoveRotation = ReflectionUtils.getClazz(
|
||||||
|
BukkitReflectionUtils.assembleMCClass("world.entity.PositionMoveRotation")
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$PositionMoveRotation$of = Optional.ofNullable(clazz$PositionMoveRotation)
|
||||||
|
.map(it -> ReflectionUtils.getStaticMethod(it, it, clazz$Entity))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
public static final Method method$Entity$absSnapTo = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$Entity, void.class, double.class, double.class, double.class, float.class, float.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$Entity$setSharedFlag = requireNonNull(
|
||||||
|
ReflectionUtils.getDeclaredMethod(
|
||||||
|
clazz$Entity, void.class, int.class, boolean.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
public static final Method method$Level$destroyBlock = requireNonNull(
|
public static final Method method$Level$destroyBlock = requireNonNull(
|
||||||
ReflectionUtils.getDeclaredMethod(
|
ReflectionUtils.getDeclaredMethod(
|
||||||
clazz$Level, boolean.class, clazz$BlockPos, boolean.class, clazz$Entity, int.class
|
clazz$Level, boolean.class, clazz$BlockPos, boolean.class, clazz$Entity, int.class
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
|||||||
|
|
||||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
|
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
||||||
|
|
||||||
public final class MItems {
|
public final class MItems {
|
||||||
private MItems() {}
|
private MItems() {}
|
||||||
@@ -22,4 +23,6 @@ public final class MItems {
|
|||||||
throw new ReflectionInitException("Failed to init Items", e);
|
throw new ReflectionInitException("Failed to init Items", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Object AIR$Item = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(ItemUtils.AIR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,6 +178,10 @@ public final class NetworkReflections {
|
|||||||
"network.protocol.game.ClientboundAddPlayerPacket"
|
"network.protocol.game.ClientboundAddPlayerPacket"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public static final Constructor<?> constructor$ClientboundAddPlayerPacket = Optional.ofNullable(clazz$ClientboundAddPlayerPacket)
|
||||||
|
.map(it -> ReflectionUtils.getConstructor(clazz$ClientboundAddPlayerPacket, CoreReflections.clazz$Player))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
public static final Class<?> clazz$ClientboundRemoveEntitiesPacket = requireNonNull(
|
public static final Class<?> clazz$ClientboundRemoveEntitiesPacket = requireNonNull(
|
||||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||||
"network.protocol.game.PacketPlayOutEntityDestroy",
|
"network.protocol.game.PacketPlayOutEntityDestroy",
|
||||||
@@ -382,12 +386,30 @@ public final class NetworkReflections {
|
|||||||
ReflectionUtils.getStaticMethod(clazz$ClientboundPlayerInfoUpdatePacket$Action, clazz$ClientboundPlayerInfoUpdatePacket$Action.arrayType())
|
ReflectionUtils.getStaticMethod(clazz$ClientboundPlayerInfoUpdatePacket$Action, clazz$ClientboundPlayerInfoUpdatePacket$Action.arrayType())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$ADD_PLAYER;
|
||||||
|
public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$INITIALIZE_CHAT;
|
||||||
|
public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_GAME_MODE;
|
||||||
|
public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_LISTED;
|
||||||
|
public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_LATENCY;
|
||||||
public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME;
|
public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME;
|
||||||
|
//public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_LIST_ORDER;
|
||||||
|
//public static final Object instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_HAT;
|
||||||
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
Object[] values = (Object[]) method$ClientboundPlayerInfoUpdatePacket$Action$values.invoke(null);
|
Object[] values = (Object[]) method$ClientboundPlayerInfoUpdatePacket$Action$values.invoke(null);
|
||||||
|
instance$ClientboundPlayerInfoUpdatePacket$Action$ADD_PLAYER = values[0];
|
||||||
|
instance$ClientboundPlayerInfoUpdatePacket$Action$INITIALIZE_CHAT = values[1];
|
||||||
|
instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_GAME_MODE = values[2];
|
||||||
|
instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_LISTED = values[3];
|
||||||
|
instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_LATENCY = values[4];
|
||||||
instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME = values[5];
|
instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME = values[5];
|
||||||
|
//1.21.3
|
||||||
|
//instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_LIST_ORDER = values[6];
|
||||||
|
//1.21.4
|
||||||
|
//instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_HAT = values[7];
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -1476,4 +1498,78 @@ public final class NetworkReflections {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static final Class<?> clazz$ClientBoundPlayerInfoUpdatePacket$Entry = requireNonNull(
|
||||||
|
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||||
|
"network.protocol.game.ClientboundPlayerInfoUpdatePacket$b",
|
||||||
|
"network.protocol.game.ClientboundPlayerInfoUpdatePacket$Entry"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Constructor<?> constructor$ClientBoundPlayerInfoUpdatePacket$Entry = requireNonNull(
|
||||||
|
VersionHelper.isOrAbove1_21_3()
|
||||||
|
? VersionHelper.isOrAbove1_21_4()
|
||||||
|
? ReflectionUtils.getConstructor(clazz$ClientBoundPlayerInfoUpdatePacket$Entry, UUID.class, CoreReflections.clazz$GameProfile, boolean.class, int.class, CoreReflections.clazz$GameType, CoreReflections.clazz$Component, boolean.class, int.class, CoreReflections.clazz$RemoteChatSession$Data)
|
||||||
|
: ReflectionUtils.getConstructor(clazz$ClientBoundPlayerInfoUpdatePacket$Entry, UUID.class, CoreReflections.clazz$GameProfile, boolean.class, int.class, CoreReflections.clazz$GameType, CoreReflections.clazz$Component, int.class, CoreReflections.clazz$RemoteChatSession$Data)
|
||||||
|
: ReflectionUtils.getConstructor(clazz$ClientBoundPlayerInfoUpdatePacket$Entry, UUID.class, CoreReflections.clazz$GameProfile, boolean.class, int.class, CoreReflections.clazz$GameType, CoreReflections.clazz$Component, CoreReflections.clazz$RemoteChatSession$Data)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$ClientboundTeleportEntityPacket = requireNonNull(
|
||||||
|
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||||
|
"network.protocol.game.PacketPlayOutEntityTeleport",
|
||||||
|
"network.protocol.game.ClientboundTeleportEntityPacket"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Constructor<?> constructor$ClientboundTeleportEntityPacket = requireNonNull(
|
||||||
|
VersionHelper.isOrAbove1_21_3()
|
||||||
|
? ReflectionUtils.getConstructor(clazz$ClientboundTeleportEntityPacket, int.class, CoreReflections.clazz$PositionMoveRotation, Set.class, boolean.class)
|
||||||
|
: ReflectionUtils.getConstructor(clazz$ClientboundTeleportEntityPacket, CoreReflections.clazz$Entity)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$ClientboundSetEquipmentPacket$getEntity = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
NetworkReflections.clazz$ClientboundSetEquipmentPacket, int.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$ClientboundSetEquipmentPacket$getSlots = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
NetworkReflections.clazz$ClientboundSetEquipmentPacket, List.class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$ClientboundContainerSetSlotPacket$getContainerId = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$ClientboundContainerSetSlotPacket, int.class, new String[]{"a", "getContainerId"}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$ClientboundContainerSetSlotPacket$getSlot = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$ClientboundContainerSetSlotPacket, int.class, new String[]{"c", "d", "getSlot"}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$ClientboundContainerSetSlotPacket$getStateId = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$ClientboundContainerSetSlotPacket, int.class, new String[]{"e", "f", "getStateId"}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$ClientboundAnimatePacket = requireNonNull(
|
||||||
|
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||||
|
"network.protocol.game.PacketPlayOutAnimation",
|
||||||
|
"network.protocol.game.ClientboundAnimatePacket")
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Constructor<?> constructor$ClientboundAnimatePacket = requireNonNull(
|
||||||
|
ReflectionUtils.getConstructor(clazz$ClientboundAnimatePacket, CoreReflections.clazz$Entity, int.class)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Constructor<?> constructor$ClientboundRotateHeadPacket = requireNonNull(
|
||||||
|
ReflectionUtils.getDeclaredConstructor(
|
||||||
|
clazz$ClientboundRotateHeadPacket, CoreReflections.clazz$Entity, byte.class
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
|||||||
import net.momirealms.craftengine.core.entity.player.GameMode;
|
import net.momirealms.craftengine.core.entity.player.GameMode;
|
||||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||||
import net.momirealms.craftengine.core.entity.player.Player;
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
import net.momirealms.craftengine.core.item.Item;
|
import net.momirealms.craftengine.core.item.Item;
|
||||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||||
@@ -110,6 +111,8 @@ public class BukkitServerPlayer extends Player {
|
|||||||
private double cachedInteractionRange;
|
private double cachedInteractionRange;
|
||||||
// cooldown data
|
// cooldown data
|
||||||
private CooldownData cooldownData;
|
private CooldownData cooldownData;
|
||||||
|
// cache seat
|
||||||
|
private SeatEntity seatEntity;
|
||||||
|
|
||||||
private final Map<Integer, EntityPacketHandler> entityTypeView = new ConcurrentHashMap<>();
|
private final Map<Integer, EntityPacketHandler> entityTypeView = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@@ -976,4 +979,14 @@ public class BukkitServerPlayer extends Player {
|
|||||||
public CooldownData cooldown() {
|
public CooldownData cooldown() {
|
||||||
return this.cooldownData;
|
return this.cooldownData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSeat(SeatEntity seatEntity) {
|
||||||
|
this.seatEntity = seatEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SeatEntity seat() {
|
||||||
|
return this.seatEntity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.util;
|
|||||||
|
|
||||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||||
|
import net.momirealms.craftengine.core.entity.EquipmentSlot;
|
||||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||||
import net.momirealms.craftengine.core.world.BlockPos;
|
import net.momirealms.craftengine.core.world.BlockPos;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -13,6 +14,9 @@ import org.bukkit.event.entity.CreatureSpawnEvent;
|
|||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static net.momirealms.craftengine.core.entity.EquipmentSlot.BODY;
|
||||||
|
import static net.momirealms.craftengine.core.entity.EquipmentSlot.MAIN_HAND;
|
||||||
|
|
||||||
public class EntityUtils {
|
public class EntityUtils {
|
||||||
|
|
||||||
private EntityUtils() {}
|
private EntityUtils() {}
|
||||||
@@ -34,4 +38,41 @@ public class EntityUtils {
|
|||||||
return LegacyEntityUtils.spawnEntity(world, loc, type, function);
|
return LegacyEntityUtils.spawnEntity(world, loc, type, function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static org.bukkit.inventory.EquipmentSlot toBukkitEquipmentSlot(EquipmentSlot slot) {
|
||||||
|
return switch (slot) {
|
||||||
|
case MAIN_HAND -> org.bukkit.inventory.EquipmentSlot.HAND;
|
||||||
|
case OFF_HAND -> org.bukkit.inventory.EquipmentSlot.OFF_HAND;
|
||||||
|
case HEAD -> org.bukkit.inventory.EquipmentSlot.HEAD;
|
||||||
|
case CHEST -> org.bukkit.inventory.EquipmentSlot.CHEST;
|
||||||
|
case LEGS -> org.bukkit.inventory.EquipmentSlot.LEGS;
|
||||||
|
case FEET -> org.bukkit.inventory.EquipmentSlot.FEET;
|
||||||
|
default -> org.bukkit.inventory.EquipmentSlot.BODY;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EquipmentSlot toCEEquipmentSlot(org.bukkit.inventory.EquipmentSlot slot) {
|
||||||
|
return switch (slot) {
|
||||||
|
case HAND -> MAIN_HAND;
|
||||||
|
case OFF_HAND -> EquipmentSlot.OFF_HAND;
|
||||||
|
case HEAD -> EquipmentSlot.HEAD;
|
||||||
|
case CHEST -> EquipmentSlot.CHEST;
|
||||||
|
case LEGS -> EquipmentSlot.LEGS;
|
||||||
|
case FEET -> EquipmentSlot.FEET;
|
||||||
|
case BODY -> EquipmentSlot.BODY;
|
||||||
|
default -> BODY;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object fromEquipmentSlot(EquipmentSlot slot) {
|
||||||
|
return switch (slot) {
|
||||||
|
case MAIN_HAND -> CoreReflections.instance$EquipmentSlot$MAINHAND;
|
||||||
|
case OFF_HAND -> CoreReflections.instance$EquipmentSlot$OFFHAND;
|
||||||
|
case HEAD -> CoreReflections.instance$EquipmentSlot$HEAD;
|
||||||
|
case CHEST -> CoreReflections.instance$EquipmentSlot$CHEST;
|
||||||
|
case LEGS -> CoreReflections.instance$EquipmentSlot$LEGS;
|
||||||
|
case FEET -> CoreReflections.instance$EquipmentSlot$FEET;
|
||||||
|
default -> new Object();
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import org.jetbrains.annotations.Contract;
|
|||||||
|
|
||||||
public class ItemUtils {
|
public class ItemUtils {
|
||||||
|
|
||||||
|
public static final ItemStack AIR = new ItemStack(Material.AIR);
|
||||||
|
|
||||||
private ItemUtils() {}
|
private ItemUtils() {}
|
||||||
|
|
||||||
@Contract("null -> true")
|
@Contract("null -> true")
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager;
|
|||||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||||
import net.momirealms.craftengine.core.util.RandomUtils;
|
import net.momirealms.craftengine.core.util.RandomUtils;
|
||||||
|
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Item;
|
import org.bukkit.entity.Item;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -20,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
@@ -174,4 +176,8 @@ public final class PlayerUtils {
|
|||||||
BukkitCraftEngine.instance().logger().warn("Failed to send totem animation");
|
BukkitCraftEngine.instance().logger().warn("Failed to send totem animation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<Player> getTrackedBy(Player player) {
|
||||||
|
return VersionHelper.isOrAbove1_20_2() ? player.getTrackedBy() : player.getTrackedPlayers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ warning.config.furniture.element.missing_item: "<yellow>Issue found in file <arg
|
|||||||
warning.config.furniture.settings.unknown: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an unknown setting type '<arg:2>'.</yellow>"
|
warning.config.furniture.settings.unknown: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an unknown setting type '<arg:2>'.</yellow>"
|
||||||
warning.config.furniture.hitbox.invalid_type: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an invalid hitbox type '<arg:2>'.</yellow>"
|
warning.config.furniture.hitbox.invalid_type: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an invalid hitbox type '<arg:2>'.</yellow>"
|
||||||
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using a custom hitbox with invalid entity type '<arg:2>'.</yellow>"
|
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using a custom hitbox with invalid entity type '<arg:2>'.</yellow>"
|
||||||
|
warning.config.furniture.seat.invalid_type: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an invalid seat type '<arg:2>'.</yellow>"
|
||||||
warning.config.item.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated item '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
warning.config.item.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated item '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||||
warning.config.item.settings.unknown: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an unknown setting type '<arg:2>'.</yellow>"
|
warning.config.item.settings.unknown: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an unknown setting type '<arg:2>'.</yellow>"
|
||||||
warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an unknown damage source '<arg:2>'. Allowed sources: [<arg:3>].</yellow>"
|
warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an unknown damage source '<arg:2>'. Allowed sources: [<arg:3>].</yellow>"
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ command.send_resource_pack.success.single: "<white>发送资源包给 <arg:0></w
|
|||||||
command.send_resource_pack.success.multiple: "<white>发送资源包给 <arg:0> 个玩家</white>"
|
command.send_resource_pack.success.multiple: "<white>发送资源包给 <arg:0> 个玩家</white>"
|
||||||
warning.config.pack.duplicated_files: "</red>发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决</red>"
|
warning.config.pack.duplicated_files: "</red>发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决</red>"
|
||||||
warning.config.yaml.duplicated_key: "<red>在文件 <arg:0> 发现问题 - 在第<arg:2>行发现重复的键 '<arg:1>', 这可能会导致一些意料之外的问题.</red>"
|
warning.config.yaml.duplicated_key: "<red>在文件 <arg:0> 发现问题 - 在第<arg:2>行发现重复的键 '<arg:1>', 这可能会导致一些意料之外的问题.</red>"
|
||||||
|
warning.config.yaml.key_path_conflict: "<red>在文件 <arg:0> 发现问题 - 在第<arg:2>行发现重复且值类型不同的键 '<arg:1>', 这可能会导致一些意料之外的问题.</red>"
|
||||||
warning.config.type.int: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为整数类型 (选项 '<arg:3>')</yellow>"
|
warning.config.type.int: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为整数类型 (选项 '<arg:3>')</yellow>"
|
||||||
warning.config.type.float: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为浮点数类型 (选项 '<arg:3>')</yellow>"
|
warning.config.type.float: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为浮点数类型 (选项 '<arg:3>')</yellow>"
|
||||||
warning.config.type.boolean: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为布尔类型 (选项 '<arg:3>')</yellow>"
|
warning.config.type.boolean: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为布尔类型 (选项 '<arg:3>')</yellow>"
|
||||||
@@ -152,6 +153,7 @@ warning.config.furniture.element.missing_item: "<yellow>在文件 <arg:0> 发现
|
|||||||
warning.config.furniture.settings.unknown: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了未知的设置类型 '<arg:2>'</yellow>"
|
warning.config.furniture.settings.unknown: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了未知的设置类型 '<arg:2>'</yellow>"
|
||||||
warning.config.furniture.hitbox.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了无效的碰撞箱类型 '<arg:2>'</yellow>"
|
warning.config.furniture.hitbox.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了无效的碰撞箱类型 '<arg:2>'</yellow>"
|
||||||
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 的自定义碰撞箱使用了无效的实体类型 '<arg:2>'</yellow>"
|
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 的自定义碰撞箱使用了无效的实体类型 '<arg:2>'</yellow>"
|
||||||
|
warning.config.furniture.seat.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了无效的座椅类型 '<arg:2>'</yellow>"
|
||||||
warning.config.item.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的物品 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
|
warning.config.item.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的物品 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
|
||||||
warning.config.item.settings.unknown: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了未知的设置类型 '<arg:2>'</yellow>"
|
warning.config.item.settings.unknown: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了未知的设置类型 '<arg:2>'</yellow>"
|
||||||
warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 物品使用了未知的伤害来源类型 '<arg:2>' 允许的来源: [<arg:3>]</yellow>"
|
warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 物品使用了未知的伤害来源类型 '<arg:2>' 允许的来源: [<arg:3>]</yellow>"
|
||||||
|
|||||||
@@ -8,5 +8,13 @@ public enum EquipmentSlot {
|
|||||||
BODY,
|
BODY,
|
||||||
MAIN_HAND,
|
MAIN_HAND,
|
||||||
OFF_HAND,
|
OFF_HAND,
|
||||||
SADDLE
|
SADDLE;
|
||||||
|
|
||||||
|
public boolean isHand() {
|
||||||
|
return this == MAIN_HAND || this == OFF_HAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPlayerArmor() {
|
||||||
|
return this == HEAD || this == CHEST || this == LEGS || this == FEET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package net.momirealms.craftengine.core.entity.furniture;
|
||||||
|
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public abstract class AbstractSeat implements Seat {
|
||||||
|
protected final Vector3f offset;
|
||||||
|
protected final float yaw;
|
||||||
|
|
||||||
|
public AbstractSeat(Vector3f offset, float yaw) {
|
||||||
|
this.offset = offset;
|
||||||
|
this.yaw = yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector3f offset() {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float yaw() {
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof AbstractSeat seat)) return false;
|
||||||
|
return Float.compare(yaw, seat.yaw()) == 0 && offset.equals(seat.offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = Objects.hash(offset);
|
||||||
|
result = 31 * result + Float.hashCode(yaw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,11 +13,7 @@ public interface HitBoxFactory {
|
|||||||
static Seat[] getSeats(Map<String, Object> arguments) {
|
static Seat[] getSeats(Map<String, Object> arguments) {
|
||||||
List<String> seats = (List<String>) arguments.getOrDefault("seats", List.of());
|
List<String> seats = (List<String>) arguments.getOrDefault("seats", List.of());
|
||||||
return seats.stream()
|
return seats.stream()
|
||||||
.map(arg -> {
|
.map(SeatType::fromString)
|
||||||
String[] split = arg.split(" ");
|
|
||||||
if (split.length == 1) return new Seat(MiscUtils.getAsVector3f(split[0], "seats"), 0, false);
|
|
||||||
return new Seat(MiscUtils.getAsVector3f(split[0], "seats"), Float.parseFloat(split[1]), true);
|
|
||||||
})
|
|
||||||
.toArray(Seat[]::new);
|
.toArray(Seat[]::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,14 @@
|
|||||||
package net.momirealms.craftengine.core.entity.furniture;
|
package net.momirealms.craftengine.core.entity.furniture;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
import java.util.Objects;
|
public interface Seat {
|
||||||
|
|
||||||
public record Seat(Vector3f offset, float yaw, boolean limitPlayerRotation) {
|
SeatEntity spawn(Player player, Furniture furniture);
|
||||||
|
|
||||||
@Override
|
Vector3f offset();
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (!(o instanceof Seat seat)) return false;
|
|
||||||
return Float.compare(yaw, seat.yaw) == 0 && Objects.equals(offset, seat.offset) && limitPlayerRotation == seat.limitPlayerRotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
float yaw();
|
||||||
public int hashCode() {
|
|
||||||
int result = Objects.hashCode(offset);
|
|
||||||
result = 31 * result + Float.hashCode(yaw);
|
|
||||||
result = 31 * result + Boolean.hashCode(limitPlayerRotation);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package net.momirealms.craftengine.core.entity.furniture;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface SeatFactory {
|
||||||
|
|
||||||
|
Seat create(List<String> args);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package net.momirealms.craftengine.core.entity.furniture;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||||
|
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||||
|
import net.momirealms.craftengine.core.registry.Holder;
|
||||||
|
import net.momirealms.craftengine.core.registry.Registries;
|
||||||
|
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||||
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
|
import net.momirealms.craftengine.core.util.ResourceKey;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SeatType {
|
||||||
|
public static final Key SIT = Key.of("craftengine:sit");
|
||||||
|
public static final Key LAY = Key.of("craftengine:lay");
|
||||||
|
public static final Key CRAWL = Key.of("craftengine:crawl");
|
||||||
|
|
||||||
|
public static void register(Key key, SeatFactory factory) {
|
||||||
|
Holder.Reference<SeatFactory> holder = ((WritableRegistry<SeatFactory>) BuiltInRegistries.SEAT_FACTORY)
|
||||||
|
.registerForHolder(new ResourceKey<>(Registries.SEAT_FACTORY.location(), key));
|
||||||
|
holder.bindValue(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Seat fromString(String s) {
|
||||||
|
int lastSpaceIndex = s.lastIndexOf(' ');
|
||||||
|
|
||||||
|
Key type = SIT;
|
||||||
|
SeatFactory factory;
|
||||||
|
String numericPart;
|
||||||
|
|
||||||
|
if (lastSpaceIndex != -1) {
|
||||||
|
numericPart = s.substring(lastSpaceIndex + 1);
|
||||||
|
try {
|
||||||
|
Float.parseFloat(numericPart);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
type = Key.withDefaultNamespace(numericPart, "craftengine");
|
||||||
|
s = s.substring(0, lastSpaceIndex);
|
||||||
|
lastSpaceIndex = s.lastIndexOf(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> split = new ArrayList<>();
|
||||||
|
int start = 0;
|
||||||
|
while (lastSpaceIndex != -1) {
|
||||||
|
split.add(s.substring(start, lastSpaceIndex));
|
||||||
|
start = lastSpaceIndex + 1;
|
||||||
|
lastSpaceIndex = s.indexOf(' ', start);
|
||||||
|
}
|
||||||
|
if (start < s.length()) {
|
||||||
|
split.add(s.substring(start));
|
||||||
|
}
|
||||||
|
|
||||||
|
factory = BuiltInRegistries.SEAT_FACTORY.getValue(type);
|
||||||
|
if (factory == null) {
|
||||||
|
throw new LocalizedResourceConfigException("warning.config.furniture.seat.invalid_type", type.toString());
|
||||||
|
}
|
||||||
|
return factory.create(split);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.entity.player;
|
|||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.momirealms.craftengine.core.entity.AbstractEntity;
|
import net.momirealms.craftengine.core.entity.AbstractEntity;
|
||||||
|
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||||
import net.momirealms.craftengine.core.item.Item;
|
import net.momirealms.craftengine.core.item.Item;
|
||||||
import net.momirealms.craftengine.core.plugin.context.CooldownData;
|
import net.momirealms.craftengine.core.plugin.context.CooldownData;
|
||||||
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
||||||
@@ -140,4 +141,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
|
|||||||
public abstract void clearPotionEffects();
|
public abstract void clearPotionEffects();
|
||||||
|
|
||||||
public abstract CooldownData cooldown();
|
public abstract CooldownData cooldown();
|
||||||
|
|
||||||
|
public abstract void setSeat(SeatEntity seatEntity);
|
||||||
|
|
||||||
|
public abstract SeatEntity seat();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package net.momirealms.craftengine.core.entity.seat;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.entity.furniture.Furniture;
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
|
||||||
|
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
public interface SeatEntity extends EntityPacketHandler {
|
||||||
|
|
||||||
|
void add(NetWorkUser to);
|
||||||
|
|
||||||
|
void dismount(Player player);
|
||||||
|
|
||||||
|
void onDismount(Player player);
|
||||||
|
|
||||||
|
void event(Player player, Object event);
|
||||||
|
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
boolean destroyed();
|
||||||
|
|
||||||
|
Furniture furniture();
|
||||||
|
|
||||||
|
Vector3f vector3f();
|
||||||
|
|
||||||
|
int playerID();
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
package net.momirealms.craftengine.core.plugin.config;
|
package net.momirealms.craftengine.core.plugin.config;
|
||||||
|
|
||||||
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
|
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
|
||||||
@@ -49,17 +50,15 @@ public class StringKeyConstructor extends SafeConstructor {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object constructObject(Node node) {
|
public Object constructObject(Node node) {
|
||||||
if (node instanceof MappingNode mappingNode) {
|
if (node instanceof MappingNode mappingNode && isValueSelectorNode(mappingNode)) {
|
||||||
if (isValueSelectorNode(mappingNode)) {
|
return constructVersionedValue(mappingNode);
|
||||||
// 场景B: 这是一个值选择器,解析它以获得单个值
|
|
||||||
return constructVersionedValue(mappingNode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 对于所有其他情况 (包括需要合并的Map),使用默认的构造逻辑
|
// 对于所有其他情况 (包括需要合并的Map),使用默认的构造逻辑
|
||||||
// super.constructObject 会最终调用我们重写的 constructMapping
|
// super.constructObject 会最终调用我们重写的 constructMapping
|
||||||
return super.constructObject(node);
|
return super.constructObject(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 场景A (块合并与路径展开): 构造一个Map,同时处理其中的版本化块合并和 `::` 分隔的深层键。
|
* 场景A (块合并与路径展开): 构造一个Map,同时处理其中的版本化块合并和 `::` 分隔的深层键。
|
||||||
*/
|
*/
|
||||||
@@ -67,66 +66,124 @@ public class StringKeyConstructor extends SafeConstructor {
|
|||||||
@Override
|
@Override
|
||||||
protected Map<Object, Object> constructMapping(MappingNode node) {
|
protected Map<Object, Object> constructMapping(MappingNode node) {
|
||||||
Map<Object, Object> map = new LinkedHashMap<>();
|
Map<Object, Object> map = new LinkedHashMap<>();
|
||||||
|
|
||||||
for (NodeTuple tuple : node.getValue()) {
|
for (NodeTuple tuple : node.getValue()) {
|
||||||
Node keyNode = tuple.getKeyNode();
|
Node keyNode = tuple.getKeyNode();
|
||||||
if (!(keyNode instanceof ScalarNode)) continue;
|
if (!(keyNode instanceof ScalarNode)) continue;
|
||||||
|
|
||||||
String key = constructScalar((ScalarNode) keyNode);
|
|
||||||
Node valueNode = tuple.getValueNode();
|
Node valueNode = tuple.getValueNode();
|
||||||
|
|
||||||
if (key.startsWith(VERSION_PREFIX)) {
|
String key = constructScalar((ScalarNode) keyNode);
|
||||||
// 处理版本化块合并
|
|
||||||
String versionSpec = key.substring(VERSION_PREFIX.length());
|
|
||||||
if (isVersionMatch(versionSpec)) {
|
|
||||||
if (valueNode instanceof MappingNode) {
|
|
||||||
// 将版本匹配的map内容合并到当前map
|
|
||||||
map.putAll(constructMapping((MappingNode) valueNode));
|
|
||||||
} else {
|
|
||||||
logWarning("versioned_key_not_a_map", key, valueNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (key.contains(DEEP_KEY_SEPARATOR)) {
|
|
||||||
// 处理 '::' 分隔的深层键
|
|
||||||
String[] parts = key.split(DEEP_KEY_SEPARATOR);
|
|
||||||
Object value = constructObject(valueNode);
|
|
||||||
Map<Object, Object> currentMap = map;
|
|
||||||
|
|
||||||
// 遍历除最后一个部分外的所有路径,创建嵌套的map
|
// 处理 版本化块.
|
||||||
for (int i = 0; i < parts.length - 1; i++) {
|
if (key.startsWith(VERSION_PREFIX)) processVersionedBlock(map, key, valueNode);
|
||||||
String part = parts[i];
|
// 处理 深层键 -> {a::b::c: value} 和 {a::b: {c: value}}.
|
||||||
Object nextObject = currentMap.get(part);
|
else if (key.contains(DEEP_KEY_SEPARATOR)) processDeepKey(map, key, valueNode, keyNode);
|
||||||
if (nextObject instanceof Map) {
|
// 处理 正常键.
|
||||||
currentMap = (Map<Object, Object>) nextObject;
|
else processRegularKey(map, key, valueNode, keyNode);
|
||||||
} else {
|
|
||||||
// 如果路径中存在一个非map的值,发出警告并覆盖它
|
|
||||||
if (nextObject != null) {
|
|
||||||
logWarning("key_path_conflict", part, keyNode);
|
|
||||||
}
|
|
||||||
Map<Object, Object> newMap = new LinkedHashMap<>();
|
|
||||||
currentMap.put(part, newMap);
|
|
||||||
currentMap = newMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在最深层的map中设置最终的键值对
|
|
||||||
String finalKey = parts[parts.length - 1];
|
|
||||||
Object previous = currentMap.put(finalKey, value);
|
|
||||||
if (previous != null) {
|
|
||||||
// 使用完整的原始键来报告重复键,更清晰
|
|
||||||
logWarning("duplicated_key", key, keyNode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 原始逻辑:处理普通键
|
|
||||||
Object value = constructObject(valueNode);
|
|
||||||
Object previous = map.put(key, value);
|
|
||||||
if (previous != null) {
|
|
||||||
logWarning("duplicated_key", key, keyNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 处理版本化块合并
|
||||||
|
private void processVersionedBlock(Map<Object, Object> targetMap, String key, Node valueNode) {
|
||||||
|
String versionSpec = key.substring(VERSION_PREFIX.length());
|
||||||
|
|
||||||
|
if (isVersionMatch(versionSpec)) {
|
||||||
|
if (valueNode instanceof MappingNode mappingNode) {
|
||||||
|
Map<Object, Object> versionedMap = constructMapping(mappingNode);
|
||||||
|
mergeMap(targetMap, versionedMap, "", valueNode);
|
||||||
|
} else {
|
||||||
|
logWarning("versioned_key_not_a_map", key, valueNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理深层键
|
||||||
|
private void processDeepKey(Map<Object, Object> rootMap, String fullKey, Node valueNode, Node keyNode) {
|
||||||
|
// 分割出不同的层级
|
||||||
|
String[] keyParts = fullKey.split(DEEP_KEY_SEPARATOR);
|
||||||
|
Map<Object, Object> currentMap = rootMap;
|
||||||
|
|
||||||
|
// 创建必要的的中间层级(最后一个key不应遍历, 如aa::bb::cc, 只应创建aa和bb.)
|
||||||
|
for (int i = 0; i < keyParts.length - 1; i++) {
|
||||||
|
String keyPart = keyParts[i];
|
||||||
|
Object existingValue = currentMap.get(keyPart);
|
||||||
|
|
||||||
|
// 路径中的值
|
||||||
|
if (existingValue instanceof Map) {
|
||||||
|
currentMap = (Map<Object, Object>) existingValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果路径中存在一个非map的值, 这意味着
|
||||||
|
// 当存在了 {aa: bb}, 又想要写入 {aa::bb::c: value} 时, 会触发这个警告, 然后会覆盖之前的.
|
||||||
|
if (existingValue != null) logWarning("key_path_conflict", keyPart, keyNode);
|
||||||
|
|
||||||
|
// 创建层级
|
||||||
|
Map<Object, Object> newMap = new LinkedHashMap<>();
|
||||||
|
currentMap.put(keyPart, newMap);
|
||||||
|
currentMap = newMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这里再处理最后的 cc key.
|
||||||
|
String finalKey = keyParts[keyParts.length - 1];
|
||||||
|
Object newValue = constructObject(valueNode);
|
||||||
|
String keyPath = String.join(DEEP_KEY_SEPARATOR, keyParts); // 构建完整的键路径字符串
|
||||||
|
|
||||||
|
setValueWithDuplicationCheck(currentMap, finalKey, newValue, keyPath, keyNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理普通键
|
||||||
|
private void processRegularKey(Map<Object, Object> targetMap, String key, Node valueNode, Node keyNode) {
|
||||||
|
Object newValue = constructObject(valueNode);
|
||||||
|
setValueWithDuplicationCheck(targetMap, key, newValue, key, keyNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 设置值并检查重复键
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void setValueWithDuplicationCheck(Map<Object, Object> targetMap, String key, Object newValue, String fullKeyPath, Node keyNode) {
|
||||||
|
Object existingValue = targetMap.get(key);
|
||||||
|
|
||||||
|
if (existingValue == null) {
|
||||||
|
// 键不存在,直接设置.
|
||||||
|
targetMap.put(key, newValue);
|
||||||
|
} else if (existingValue instanceof Map && newValue instanceof Map) {
|
||||||
|
// 两个都是Map,直接合并.
|
||||||
|
mergeMap((Map<Object, Object>) existingValue, (Map<Object, Object>) newValue, fullKeyPath, keyNode);
|
||||||
|
} else {
|
||||||
|
// 存在重复键(至少一个不是Map)
|
||||||
|
logWarning("duplicated_key", fullKeyPath, keyNode);
|
||||||
|
targetMap.put(key, newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 合并两个Map并检查重复键
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void mergeMap(Map<Object, Object> target, Map<Object, Object> source, String parentPath, Node sourceNode) {
|
||||||
|
for (Map.Entry<Object, Object> entry : source.entrySet()) {
|
||||||
|
String key = entry.getKey().toString();
|
||||||
|
Object sourceValue = entry.getValue();
|
||||||
|
Object targetValue = target.get(key);
|
||||||
|
String currentPath = parentPath.isEmpty() ? key : parentPath + DEEP_KEY_SEPARATOR + key;
|
||||||
|
|
||||||
|
// Map不存在该键,直接添加喵.
|
||||||
|
if (targetValue == null) target.put(key, sourceValue);
|
||||||
|
// 两个值都是Map,还需继续合并.
|
||||||
|
else if (targetValue instanceof Map && sourceValue instanceof Map)
|
||||||
|
mergeMap((Map<Object, Object>) targetValue, (Map<Object, Object>) sourceValue, currentPath, sourceNode);
|
||||||
|
// 发现重复的键, 爆炸了喵.
|
||||||
|
else {
|
||||||
|
logWarning("duplicated_key", currentPath, sourceNode);
|
||||||
|
target.put(key, sourceValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查一个MappingNode是否是“值选择器”(即所有键都以 '$$' 开头)。
|
* 检查一个MappingNode是否是“值选择器”(即所有键都以 '$$' 开头)。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import it.unimi.dsi.fastutil.ints.IntList;
|
|||||||
|
|
||||||
public interface EntityPacketHandler {
|
public interface EntityPacketHandler {
|
||||||
|
|
||||||
default boolean handleEntitiesRemove(IntList entityIds) {
|
default boolean handleEntitiesRemove(NetWorkUser user, IntList entityIds) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,4 +19,10 @@ public interface EntityPacketHandler {
|
|||||||
|
|
||||||
default void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
default void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void handleSetEquipment(NetWorkUser user, ByteBufPacketEvent event, Object slots) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void handleContainerSetSlot(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.block.CustomBlock;
|
|||||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||||
import net.momirealms.craftengine.core.block.properties.PropertyFactory;
|
import net.momirealms.craftengine.core.block.properties.PropertyFactory;
|
||||||
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory;
|
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory;
|
||||||
|
import net.momirealms.craftengine.core.entity.furniture.SeatFactory;
|
||||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||||
import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe;
|
import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe;
|
||||||
import net.momirealms.craftengine.core.item.recipe.RecipeFactory;
|
import net.momirealms.craftengine.core.item.recipe.RecipeFactory;
|
||||||
@@ -68,6 +69,7 @@ public class BuiltInRegistries {
|
|||||||
public static final Registry<FunctionFactory<PlayerOptionalContext>> EVENT_FUNCTION_FACTORY = createRegistry(Registries.EVENT_FUNCTION_FACTORY);
|
public static final Registry<FunctionFactory<PlayerOptionalContext>> EVENT_FUNCTION_FACTORY = createRegistry(Registries.EVENT_FUNCTION_FACTORY);
|
||||||
public static final Registry<ConditionFactory<PlayerOptionalContext>> EVENT_CONDITION_FACTORY = createRegistry(Registries.EVENT_CONDITION_FACTORY);
|
public static final Registry<ConditionFactory<PlayerOptionalContext>> EVENT_CONDITION_FACTORY = createRegistry(Registries.EVENT_CONDITION_FACTORY);
|
||||||
public static final Registry<PlayerSelectorFactory<?>> PLAYER_SELECTOR_FACTORY = createRegistry(Registries.PLAYER_SELECTOR_FACTORY);
|
public static final Registry<PlayerSelectorFactory<?>> PLAYER_SELECTOR_FACTORY = createRegistry(Registries.PLAYER_SELECTOR_FACTORY);
|
||||||
|
public static final Registry<SeatFactory> SEAT_FACTORY = createRegistry(Registries.SEAT_FACTORY);
|
||||||
|
|
||||||
private static <T> Registry<T> createRegistry(ResourceKey<? extends Registry<T>> key) {
|
private static <T> Registry<T> createRegistry(ResourceKey<? extends Registry<T>> key) {
|
||||||
return new MappedRegistry<>(key);
|
return new MappedRegistry<>(key);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.block.CustomBlock;
|
|||||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||||
import net.momirealms.craftengine.core.block.properties.PropertyFactory;
|
import net.momirealms.craftengine.core.block.properties.PropertyFactory;
|
||||||
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory;
|
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory;
|
||||||
|
import net.momirealms.craftengine.core.entity.furniture.SeatFactory;
|
||||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||||
import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe;
|
import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe;
|
||||||
import net.momirealms.craftengine.core.item.recipe.RecipeFactory;
|
import net.momirealms.craftengine.core.item.recipe.RecipeFactory;
|
||||||
@@ -69,4 +70,5 @@ public class Registries {
|
|||||||
public static final ResourceKey<Registry<FunctionFactory<PlayerOptionalContext>>> EVENT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("event_function_factory"));
|
public static final ResourceKey<Registry<FunctionFactory<PlayerOptionalContext>>> EVENT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("event_function_factory"));
|
||||||
public static final ResourceKey<Registry<ConditionFactory<PlayerOptionalContext>>> EVENT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("event_condition_factory"));
|
public static final ResourceKey<Registry<ConditionFactory<PlayerOptionalContext>>> EVENT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("event_condition_factory"));
|
||||||
public static final ResourceKey<Registry<PlayerSelectorFactory<?>>> PLAYER_SELECTOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_selector"));
|
public static final ResourceKey<Registry<PlayerSelectorFactory<?>>> PLAYER_SELECTOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_selector"));
|
||||||
|
public static final ResourceKey<Registry<SeatFactory>> SEAT_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("seat_factory"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user