9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-28 19:39:11 +00:00
This commit is contained in:
XiaoMoMi
2025-04-07 04:17:16 +08:00
parent 84ecde8b82
commit e6a0430d65
6 changed files with 135 additions and 61 deletions

View File

@@ -32,12 +32,14 @@ import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class BukkitFurnitureManager extends AbstractFurnitureManager {
public static final NamespacedKey FURNITURE_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:furniture_id"));
public static final NamespacedKey FURNITURE_ANCHOR_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:anchor_type"));
public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_to_base_entity"));
public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_vector"));
public static final NamespacedKey FURNITURE_COLLISION = Objects.requireNonNull(NamespacedKey.fromString("craftengine:collision"));
private static BukkitFurnitureManager instance;
private final BukkitCraftEngine plugin;
private final FurnitureParser furnitureParser;
@@ -57,6 +59,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
this.furnitureParser = new FurnitureParser();
this.furnitureEventListener = new FurnitureEventListener(this);
this.dismountListener = VersionHelper.isVersionNewerThan1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount);
plugin.scheduler().asyncRepeating(() -> {
System.out.println("数量" + furnitureByRealEntityId.size());
}, 3, 3, TimeUnit.SECONDS);
}
@Override
@@ -73,7 +78,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
ItemDisplay display = (ItemDisplay) entity;
display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_KEY, PersistentDataType.STRING, furniture.id().toString());
display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_ANCHOR_KEY, PersistentDataType.STRING, finalAnchorType.name());
handleEntityLoadEarly(display);
handleBaseEntityLoadEarly(display);
});
if (playSound) {
SoundData data = furniture.settings().sounds().placeSound();
@@ -214,7 +219,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
for (World world : Bukkit.getWorlds()) {
List<Entity> entities = world.getEntities();
for (Entity entity : entities) {
handleEntityLoadEarly(entity);
if (entity instanceof ItemDisplay display) {
handleBaseEntityLoadEarly(display);
}
}
}
}
@@ -249,7 +256,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
return this.furnitureByEntityId.get(entityId);
}
protected void handleBaseFurnitureUnload(Entity entity, boolean unloadColliders) {
protected void handleBaseEntityUnload(Entity entity) {
int id = entity.getEntityId();
LoadedFurniture furniture = this.furnitureByRealEntityId.remove(id);
if (furniture != null) {
@@ -261,57 +268,97 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
for (int sub : furniture.entityIds()) {
this.furnitureByEntityId.remove(sub);
}
for (CollisionEntity collision : furniture.collisionEntities()) {
if (unloadColliders) {
this.furnitureByRealEntityId.remove(FastNMS.INSTANCE.method$Entity$getId(collision));
}
if (!isPreventing) collision.destroy();
}
// for (CollisionEntity collision : furniture.collisionEntities()) {
// this.furnitureByRealEntityId.remove(FastNMS.INSTANCE.method$Entity$getId(collision));
// if (!isPreventing) collision.destroy();
// }
}
}
protected void handleCollisionEntityUnload(Entity entity) {
int id = entity.getEntityId();
this.furnitureByRealEntityId.remove(id);
}
@SuppressWarnings("deprecation") // just a misleading name `getTrackedPlayers`
protected void handleEntityLoadLate(Entity entity) {
if (entity instanceof ItemDisplay display) {
String id = entity.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING);
if (id == null) return;
Key key = Key.of(id);
Optional<CustomFurniture> optionalFurniture = furnitureById(key);
if (optionalFurniture.isEmpty()) return;
CustomFurniture customFurniture = optionalFurniture.get();
LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
if (previous != null) return;
Location location = entity.getLocation();
if (FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4)) {
return;
}
LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(entity, customFurniture));
protected void handleBaseEntityLoadLate(ItemDisplay display, int depth) {
// must be a furniture item
String id = display.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING);
if (id == null) return;
Key key = Key.of(id);
Optional<CustomFurniture> optionalFurniture = furnitureById(key);
if (optionalFurniture.isEmpty()) return;
CustomFurniture customFurniture = optionalFurniture.get();
LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
if (previous != null) return;
Location location = display.getLocation();
if (!FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4)) {
LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(display, customFurniture));
for (Player player : display.getTrackedPlayers()) {
this.plugin.adapt(player).furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.fakeEntityIds());
this.plugin.networkManager().sendPacket(player, furniture.spawnPacket(player));
}
return;
}
if (depth > 2) return;
this.plugin.scheduler().sync().runLater(() -> {
handleBaseEntityLoadLate(display, depth + 1);
}, 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
protected void handleCollisionEntityLoadLate(Shulker shulker, int depth) {
// remove the shulker if it's not a collision entity, it might be wrongly copied by WorldEdit
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(shulker) instanceof CollisionEntity) {
return;
}
Byte flag = shulker.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE);
if (flag != null && flag == 1) {
return;
}
Location location = shulker.getLocation();
World world = location.getWorld();
int chunkX = location.getBlockX() >> 4;
int chunkZ = location.getBlockZ() >> 4;
if (!FastNMS.INSTANCE.isPreventingStatusUpdates(world, chunkX, chunkZ)) {
shulker.remove();
return;
}
if (depth > 2) return;
plugin.scheduler().sync().runLater(() -> {
handleCollisionEntityLoadLate(shulker, depth + 1);
}, 1, world, chunkX, chunkZ);
}
public void handleBaseEntityLoadEarly(ItemDisplay display) {
String id = display.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING);
if (id == null) return;
Key key = Key.of(id);
Optional<CustomFurniture> optionalFurniture = furnitureById(key);
if (optionalFurniture.isPresent()) {
CustomFurniture customFurniture = optionalFurniture.get();
LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
if (previous != null) return;
addNewFurniture(display, customFurniture, getAnchorType(display, customFurniture));
return;
}
// Remove the entity if it's not a valid furniture
if (Config.removeInvalidFurniture()) {
if (Config.furnitureToRemove().isEmpty() || Config.furnitureToRemove().contains(id)) {
display.remove();
}
}
}
public void handleEntityLoadEarly(Entity entity) {
if (entity instanceof ItemDisplay display) {
String id = entity.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING);
if (id == null) return;
Key key = Key.of(id);
Optional<CustomFurniture> optionalFurniture = furnitureById(key);
if (optionalFurniture.isPresent()) {
CustomFurniture customFurniture = optionalFurniture.get();
LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
if (previous != null) return;
addNewFurniture(display, customFurniture, getAnchorType(entity, customFurniture));
return;
}
// Remove the entity if it's not a valid furniture
if (Config.removeInvalidFurniture()) {
if (Config.furnitureToRemove().isEmpty() || Config.furnitureToRemove().contains(id)) {
entity.remove();
}
}
public void handleCollisionEntityLoadOnEntitiesLoad(Shulker shulker) {
// remove the shulker if it's on chunk load stage
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(shulker) instanceof CollisionEntity) {
shulker.remove();
}
}

View File

@@ -2,10 +2,7 @@ package net.momirealms.craftengine.bukkit.entity.furniture;
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Player;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -34,7 +31,11 @@ public class FurnitureEventListener implements Listener {
public void onEntitiesLoadEarly(EntitiesLoadEvent event) {
List<Entity> entities = event.getEntities();
for (Entity entity : entities) {
this.manager.handleEntityLoadEarly(entity);
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay);
} else if (entity instanceof Shulker shulker) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(shulker);
}
}
}
@@ -42,13 +43,20 @@ public class FurnitureEventListener implements Listener {
public void onWorldLoad(WorldLoadEvent event) {
List<Entity> entities = event.getWorld().getEntities();
for (Entity entity : entities) {
this.manager.handleEntityLoadEarly(entity);
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay);
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onEntityLoad(EntityAddToWorldEvent event) {
this.manager.handleEntityLoadLate(event.getEntity());
Entity entity = event.getEntity();
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadLate(itemDisplay, 0);
} else if (entity instanceof Shulker shulker) {
this.manager.handleCollisionEntityLoadLate(shulker, 0);
}
}
/*
@@ -59,7 +67,9 @@ public class FurnitureEventListener implements Listener {
Entity[] entities = event.getChunk().getEntities();
for (Entity entity : entities) {
if (entity instanceof ItemDisplay) {
this.manager.handleBaseFurnitureUnload(entity, true);
this.manager.handleBaseEntityUnload(entity);
} else if (entity instanceof Shulker) {
this.manager.handleCollisionEntityUnload(entity);
}
}
}
@@ -69,15 +79,20 @@ public class FurnitureEventListener implements Listener {
List<Entity> entities = event.getWorld().getEntities();
for (Entity entity : entities) {
if (entity instanceof ItemDisplay) {
this.manager.handleBaseFurnitureUnload(entity, true);
this.manager.handleBaseEntityUnload(entity);
} else if (entity instanceof Shulker) {
this.manager.handleCollisionEntityUnload(entity);
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityUnload(EntityRemoveFromWorldEvent event) {
if (event.getEntity() instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseFurnitureUnload(itemDisplay, false);
Entity entity = event.getEntity();
if (entity instanceof ItemDisplay) {
this.manager.handleBaseEntityUnload(entity);
} else if (entity instanceof Shulker) {
this.manager.handleCollisionEntityUnload(entity);
}
}

View File

@@ -44,7 +44,6 @@ public class LoadedFurniture implements Furniture {
private final Map<Integer, HitBox> hitBoxes;
private final boolean minimized;
private final boolean hasExternalModel;
private final CustomFurniture.Placement placement;
// seats
private final Set<Vector3f> occupiedSeats = Collections.synchronizedSet(new HashSet<>());
private final Vector<Entity> seats = new Vector<>();
@@ -68,7 +67,6 @@ public class LoadedFurniture implements Furniture {
mainEntityIds.add(this.baseEntityId);
CustomFurniture.Placement placement = furniture.getPlacement(anchorType);
this.placement = placement;
// bind external furniture
Optional<ExternalModel> optionalExternal = placement.externalModel();
if (optionalExternal.isPresent()) {
@@ -152,6 +150,8 @@ public class LoadedFurniture implements Furniture {
Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld());
for (CollisionEntity entity : this.collisionEntities) {
FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(world, entity);
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity);
bukkitEntity.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_COLLISION, PersistentDataType.BYTE, (byte) 1);
}
}

View File

@@ -1,13 +1,18 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import java.util.Collection;
public class TestCommand extends BukkitCommandFeature<CommandSender> {
public TestCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
@@ -22,7 +27,14 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
Player player = context.sender();
Location location = player.getLocation();
try {
Collection<Entity> entities = player.getLocation().getNearbyEntities(2,2,2);
for (Entity entity : entities) {
System.out.println(entity.getType());
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(entity) instanceof CollisionEntity) {
System.out.println(entity.getEntityId());
System.out.println(entity.getUniqueId());
}
}
} catch (Exception e) {
e.printStackTrace();
}