mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-22 16:39:28 +00:00
初步完成自定义弹射物
This commit is contained in:
@@ -4,9 +4,9 @@ import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||
import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement;
|
||||
import net.momirealms.craftengine.core.entity.Billboard;
|
||||
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
|
||||
import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
package net.momirealms.craftengine.bukkit.entity.projectile;
|
||||
|
||||
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||
import net.momirealms.craftengine.core.entity.projectile.CustomProjectile;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileManager;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.ThrowableProjectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.event.world.EntitiesLoadEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
private static BukkitProjectileManager instance;
|
||||
@@ -50,6 +56,24 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onProjectileLaunch(ProjectileLaunchEvent event) {
|
||||
Projectile projectile = event.getEntity();
|
||||
handleProjectileLoad(projectile, true);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onEntitiesLoad(EntitiesLoadEvent event) {
|
||||
for (Entity entity : event.getEntities()) {
|
||||
if (entity instanceof Projectile projectile) {
|
||||
handleProjectileLoad(projectile, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
|
||||
public void onEntityRemove(EntityRemoveFromWorldEvent event) {
|
||||
this.projectiles.remove(event.getEntity().getEntityId());
|
||||
}
|
||||
|
||||
private void handleProjectileLoad(Projectile projectile, boolean delay) {
|
||||
ItemStack projectileItem;
|
||||
if (projectile instanceof ThrowableProjectile throwableProjectile) {
|
||||
projectileItem = throwableProjectile.getItem();
|
||||
@@ -58,21 +82,50 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
System.out.println("发射");
|
||||
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(projectileItem);
|
||||
if (wrapped == null) return;
|
||||
wrapped.getCustomItem().ifPresent(it -> {
|
||||
ProjectileMeta meta = it.settings().projectileMeta();
|
||||
if (meta != null) {
|
||||
System.out.println("来啦");
|
||||
this.projectiles.put(projectile.getEntityId(), new BukkitCustomProjectile(meta, projectile, wrapped));
|
||||
ProjectileInjectTask task = new ProjectileInjectTask(projectile);
|
||||
if (!delay) {
|
||||
task.run();
|
||||
} else if (VersionHelper.isFolia()) {
|
||||
projectile.getScheduler().run(plugin.bootstrap(), (t) -> task.run(), () -> {});
|
||||
} else {
|
||||
plugin.scheduler().sync().runDelayed(task);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
|
||||
public void onEntityRemove(EntityRemoveEvent event) {
|
||||
this.projectiles.remove(event.getEntity().getEntityId());
|
||||
public class ProjectileInjectTask implements Runnable {
|
||||
private final Projectile projectile;
|
||||
|
||||
public ProjectileInjectTask(Projectile projectile) {
|
||||
this.projectile = projectile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(this.projectile);
|
||||
Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity);
|
||||
if (trackedEntity == null) {
|
||||
plugin.logger().warn("Failed to update server entity tracking interval due to missing tracked entity");
|
||||
return;
|
||||
}
|
||||
Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity);
|
||||
if (serverEntity == null) {
|
||||
plugin.logger().warn("Failed to update server entity tracking interval due to missing server entity");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Reflections.field$ServerEntity$updateInterval.set(serverEntity, 1);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to update server entity tracking interval", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static BukkitProjectileManager instance() {
|
||||
|
||||
@@ -23,16 +23,12 @@ import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.ThrowableProjectile;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@@ -139,7 +139,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
registerNMSPacketConsumer(PacketConsumers.RESPAWN, Reflections.clazz$ClientboundRespawnPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.INTERACT_ENTITY, Reflections.clazz$ServerboundInteractPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.SYNC_ENTITY_POSITION, Reflections.clazz$ClientboundEntityPositionSyncPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$Pos);
|
||||
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$Pos);
|
||||
registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, Reflections.clazz$ServerboundPickItemFromEntityPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket);
|
||||
@@ -150,7 +150,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, Reflections.clazz$ServerboundLoginAcknowledgedPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.MOVE_AND_ROTATE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$PosRot);
|
||||
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$PosRot);
|
||||
registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
|
||||
registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
|
||||
registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
|
||||
|
||||
@@ -1611,8 +1611,9 @@ public class PacketConsumers {
|
||||
}
|
||||
} else {
|
||||
BukkitProjectileManager.instance().projectileByEntityId(entityId).ifPresent(customProjectile -> {
|
||||
event.replacePacket(ProjectilePacketHandler.convertAddCustomProjectPacket(packet));
|
||||
user.entityPacketHandlers().put(entityId, new ProjectilePacketHandler(customProjectile));
|
||||
ProjectilePacketHandler handler = new ProjectilePacketHandler(customProjectile, entityId);
|
||||
event.replacePacket(handler.convertAddCustomProjectilePacket(packet));
|
||||
user.entityPacketHandlers().put(entityId, handler);
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -1633,17 +1634,6 @@ public class PacketConsumers {
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_ENTITY = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet);
|
||||
if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$Pos", e);
|
||||
}
|
||||
};
|
||||
|
||||
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> REMOVE_ENTITY = (user, event) -> {
|
||||
try {
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
@@ -2215,7 +2205,18 @@ public class PacketConsumers {
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_AND_ROTATE_ENTITY = (user, event, packet) -> {
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_POS_ENTITY = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet);
|
||||
if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_POS_AND_ROTATE_ENTITY = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet);
|
||||
EntityPacketHandler handler = user.entityPacketHandlers().get(entityId);
|
||||
|
||||
@@ -26,22 +26,24 @@ import java.util.UUID;
|
||||
|
||||
public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
private final CustomProjectile projectile;
|
||||
private final Object cachedPacket;
|
||||
private final List<Object> cachedData;
|
||||
|
||||
public ProjectilePacketHandler(CustomProjectile projectile) {
|
||||
public ProjectilePacketHandler(CustomProjectile projectile, int entityId) {
|
||||
this.projectile = projectile;
|
||||
this.cachedData = createCustomProjectileEntityDataValues();
|
||||
this.cachedPacket = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, this.cachedData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) {
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
int id = buf.readVarInt();
|
||||
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
|
||||
List<Object> newPackedItems = convertCustomProjectileSetEntityDataPacket(packedItems);
|
||||
event.setChanged(true);
|
||||
buf.clear();
|
||||
buf.writeVarInt(event.packetID());
|
||||
buf.writeVarInt(id);
|
||||
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(newPackedItems, buf);
|
||||
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(this.cachedData, buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,11 +54,15 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
|
||||
@Override
|
||||
public void handleMoveAndRotate(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||
Object converted = convertCustomProjectileMovePacket(packet);
|
||||
event.replacePacket(converted);
|
||||
int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet);
|
||||
Object converted = convertCustomProjectileMovePacket(packet, entityId);
|
||||
event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundBundlePacket(List.of(
|
||||
this.cachedPacket,
|
||||
converted
|
||||
)));
|
||||
}
|
||||
|
||||
public static Object convertAddCustomProjectPacket(Object packet) {
|
||||
public Object convertAddCustomProjectilePacket(Object packet) {
|
||||
int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet);
|
||||
UUID uuid = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$uuid(packet);
|
||||
double x = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$x(packet);
|
||||
@@ -70,11 +76,7 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
double ya = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$ya(packet);
|
||||
double za = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$za(packet);
|
||||
double yHeadRot = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$yHeadRot(packet);
|
||||
return FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId, uuid, x, y, z,
|
||||
MCUtils.clamp(-xRot, -90.0F, 90.0F), -yRot,
|
||||
type, data, FastNMS.INSTANCE.constructor$Vec3(xa, ya, za), yHeadRot
|
||||
);
|
||||
return FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(entityId, uuid, x, y, z, MCUtils.clamp(-xRot, -90.0F, 90.0F), -yRot, type, data, FastNMS.INSTANCE.constructor$Vec3(xa, ya, za), yHeadRot);
|
||||
}
|
||||
|
||||
private Object convertCustomProjectilePositionSyncPacket(Object packet) {
|
||||
@@ -89,24 +91,11 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
return FastNMS.INSTANCE.constructor$ClientboundEntityPositionSyncPacket(entityId, newPositionMoveRotation, onGround);
|
||||
}
|
||||
|
||||
// 将原有的投掷物的entity data转化为展示实体的数据包
|
||||
public List<Object> convertCustomProjectileSetEntityDataPacket(List<Object> packedItems) {
|
||||
List<Object> newPackedItems = new ArrayList<>();
|
||||
for (Object packedItem : packedItems) {
|
||||
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
|
||||
if (entityDataId < 8) {
|
||||
newPackedItems.add(packedItem);
|
||||
}
|
||||
}
|
||||
newPackedItems.addAll(createCustomProjectileEntityDataValues());
|
||||
return newPackedItems;
|
||||
}
|
||||
|
||||
private List<Object> createCustomProjectileEntityDataValues() {
|
||||
public List<Object> createCustomProjectileEntityDataValues() {
|
||||
List<Object> itemDisplayValues = new ArrayList<>();
|
||||
Optional<CustomItem<ItemStack>> customItem = BukkitItemManager.instance().getCustomItem(this.projectile.metadata().item());
|
||||
if (customItem.isEmpty()) return itemDisplayValues;
|
||||
ProjectileMeta meta = projectile.metadata();
|
||||
ProjectileMeta meta = this.projectile.metadata();
|
||||
Item<?> displayedItem = customItem.get().buildItem(ItemBuildContext.EMPTY);
|
||||
// 我们应当使用新的展示物品的组件覆盖原物品的组件,以完成附魔,附魔光效等组件的继承
|
||||
displayedItem = this.projectile.item().mergeCopy(displayedItem);
|
||||
@@ -114,18 +103,17 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(meta.translation(), itemDisplayValues);
|
||||
ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(meta.rotation(), itemDisplayValues);
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues);
|
||||
ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues);
|
||||
ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(1, itemDisplayValues);
|
||||
ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(1, itemDisplayValues);
|
||||
} else {
|
||||
ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues);
|
||||
ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(1, itemDisplayValues);
|
||||
}
|
||||
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(displayedItem.getLiteralObject(), itemDisplayValues);
|
||||
ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(meta.displayType().id(), itemDisplayValues);
|
||||
return itemDisplayValues;
|
||||
}
|
||||
|
||||
private static Object convertCustomProjectileMovePacket(Object packet) {
|
||||
int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet);
|
||||
private Object convertCustomProjectileMovePacket(Object packet, int entityId) {
|
||||
short xa = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xa(packet);
|
||||
short ya = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$ya(packet);
|
||||
short za = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$za(packet);
|
||||
|
||||
@@ -6634,4 +6634,15 @@ public class Reflections {
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$ServerEntity = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"server.level.EntityTrackerEntry",
|
||||
"server.level.ServerEntity")
|
||||
);
|
||||
|
||||
public static final Field field$ServerEntity$updateInterval = requireNonNull(
|
||||
ReflectionUtils.getInstanceDeclaredField(
|
||||
clazz$ServerEntity, int.class, 0
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.momirealms.craftengine.core.item;
|
||||
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
|
||||
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
|
||||
import net.momirealms.craftengine.core.item.modifier.EquippableModifier;
|
||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||
import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration;
|
||||
|
||||
Reference in New Issue
Block a user