diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index fdf4e1613..7dbe7a78a 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -111,6 +111,13 @@ list_resource: - /craftengine resource list - /ce resource list +set_max_visible_furniture: + enable: true + permission: ce.command.player.set_max_visible_furniture + usage: + - /craftengine feature set-max-visible-furniture + - /ce feature set-max-visible-furniture + # Debug commands debug_set_block: enable: true diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java index c1f1c3f39..40cbc68ee 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java @@ -52,7 +52,8 @@ public class BukkitCommandManager extends AbstractCommandManager new DisableResourceCommand(this, plugin), new ListResourceCommand(this, plugin), new UploadPackCommand(this, plugin), - new SendResourcePackCommand(this, plugin) + new SendResourcePackCommand(this, plugin), + new SetMaxVisibleFurnitureCommand(this, plugin) )); final LegacyPaperCommandManager manager = (LegacyPaperCommandManager) getCommandManager(); manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java new file mode 100644 index 000000000..e07630d36 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java @@ -0,0 +1,36 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.parser.standard.IntegerParser; + +public class SetMaxVisibleFurnitureCommand extends BukkitCommandFeature { + + public SetMaxVisibleFurnitureCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .senderType(Player.class) + .required("max", IntegerParser.integerParser(1)) + .handler(context -> { + // 需要找一个更好的存储方案 + BukkitServerPlayer cePlayer = plugin().adapt(context.sender()); + Integer max = context.get("max"); + cePlayer.setMaxVisibleFurniture(max, true); + }); + } + + @Override + public String getFeatureID() { + return "set_max_visible_furniture"; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 33a9ac417..8ce4d7495 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -52,15 +52,16 @@ public class TestCommand extends BukkitCommandFeature { .handler(context -> { Player player = context.sender(); BukkitServerPlayer cePlayer = plugin().adapt(player); - player.sendMessage("visualFurnitureView1: " + cePlayer.visualFurnitureView().getTotalMembers()); - cePlayer.visualFurnitureView().getAllElements().forEach(element -> { - LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); - if (furniture == null || !player.canSee(furniture.baseEntity())) { - cePlayer.visualFurnitureView().removeByEntityId(element.entityId()); - player.sendMessage("remove: " + element.entityId()); - } - }); - player.sendMessage("visualFurnitureView2: " + cePlayer.visualFurnitureView().getTotalMembers()); + player.sendMessage("visualFurnitureView: " + cePlayer.visualFurnitureView().getTotalMembers()); + player.sendMessage(cePlayer.visualFurnitureView() + "\n==============================="); + // cePlayer.visualFurnitureView().getAllElements().forEach(element -> { + // LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); + // if (furniture == null || !player.canSee(furniture.baseEntity())) { + // cePlayer.visualFurnitureView().removeByEntityId(element.entityId()); + // player.sendMessage("remove: " + element.entityId()); + // } + // }); + // player.sendMessage("visualFurnitureView2: " + cePlayer.visualFurnitureView().getTotalMembers()); }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 65cb5f409..301b54540 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1605,12 +1605,13 @@ public class PacketConsumers { if (user.visualFurnitureView().getTotalMembers() <= Config.maxVisibleFurniture()) { user.sendPacket(furniture.spawnPacket(player), false); } - int[] entityIdsArray = new int[fakeEntityIds.size() + 1]; - entityIdsArray[0] = entityId; + int[] entityIdsArray = new int[fakeEntityIds.size() + 2]; + entityIdsArray[0] = -114514; + entityIdsArray[1] = entityId; for (int i = 0; i < fakeEntityIds.size(); i++) { - entityIdsArray[i + 1] = fakeEntityIds.get(i); + entityIdsArray[i + 2] = fakeEntityIds.get(i); } - double distance = player.getLocation().distance(furniture.location()); + double distance = furniture.location().distanceSquared(player.getLocation()); Object removePacket = Reflections.constructor$ClientboundRemoveEntitiesPacket.newInstance(entityIdsArray); DynamicPriorityTracker.UpdateResult result = user.visualFurnitureView().addOrUpdateElement(new DynamicPriorityTracker.Element(entityId, distance, removePacket)); for (DynamicPriorityTracker.Element element : result.getEntered()) { @@ -1665,12 +1666,24 @@ public class PacketConsumers { FriendlyByteBuf buf = event.getBuffer(); boolean isChange = false; IntList intList = buf.readIntIdList(); + int first = intList.getFirst(); for (int i = 0, size = intList.size(); i < size; i++) { int entityId = intList.getInt(i); - EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); - if (handler != null && handler.handleEntitiesRemove(intList)) { - // user.visualFurnitureView().removeByEntityId(entityId); - isChange = true; + if (first != -114514) { + EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); + if (handler != null && handler.handleEntitiesRemove(intList)) { + user.visualFurnitureView().removeByEntityId(entityId); + isChange = true; + } + } else { + if (entityId == first) { + intList.removeFirst(); + isChange = true; + } + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null && handler.handleEntitiesRemove(intList)) { + isChange = true; + } } } if (isChange) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 8e30e0dca..090cfbb82 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -31,16 +31,14 @@ import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; -import org.bukkit.FluidCollisionMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.SoundCategory; +import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.RayTraceResult; import org.jetbrains.annotations.Nullable; @@ -50,6 +48,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class BukkitServerPlayer extends Player { + public static final NamespacedKey MAX_VISIBLE_FURNITURE_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:max_visible_furniture")); private final BukkitCraftEngine plugin; // handshake private ProtocolVersion protocolVersion = ProtocolVersion.UNKNOWN; @@ -98,6 +97,7 @@ public class BukkitServerPlayer extends Player { // cache interaction range here private int lastUpdateInteractionRangeTick; private double cachedInteractionRange; + private Integer maxVisibleFurniture = -1; private final Map entityTypeView = new ConcurrentHashMap<>(); private final DynamicPriorityTracker visualFurnitureView = new DynamicPriorityTracker(); @@ -112,6 +112,9 @@ public class BukkitServerPlayer extends Player { this.serverPlayerRef = new WeakReference<>(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)); this.uuid = player.getUniqueId(); this.name = player.getName(); + this.maxVisibleFurniture = player.getPersistentDataContainer() + .getOrDefault(MAX_VISIBLE_FURNITURE_KEY, PersistentDataType.INTEGER, -1); + this.visualFurnitureView.setMaxVisibleFurniture(this.maxVisibleFurniture); } @Override @@ -348,11 +351,11 @@ public class BukkitServerPlayer extends Player { } if (this.gameTicks % 30 == 0) { this.updateGUI(); - this.updateVisualFurnitureView(); } if (this.isDestroyingBlock) { this.tickBlockDestroy(); } + this.updateVisualFurnitureView(); if (Config.predictBreaking() && !this.isDestroyingCustomBlock) { // if it's not destroying blocks, we do predict if ((gameTicks() + entityID()) % Config.predictBreakingInterval() == 0) { @@ -379,7 +382,7 @@ public class BukkitServerPlayer extends Player { for (DynamicPriorityTracker.Element element : visualFurnitureView().getAllElements()) { LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); if (furniture == null || !furniture.isValid()) continue; - double distance = platformPlayer().getLocation().distance(furniture.location()); + double distance = furniture.location().distanceSquared(platformPlayer().getLocation()); DynamicPriorityTracker.Element newElement = new DynamicPriorityTracker.Element(element.entityId(), distance, element.removePacket()); DynamicPriorityTracker.UpdateResult result = visualFurnitureView().addOrUpdateElement(newElement); for (DynamicPriorityTracker.Element resultElement : result.getEntered()) { @@ -768,6 +771,18 @@ public class BukkitServerPlayer extends Player { return this.visualFurnitureView; } + @Override + public void setMaxVisibleFurniture(int maxVisibleFurniture, boolean fromCommand) { + if (fromCommand) { + platformPlayer().getPersistentDataContainer() + .set(MAX_VISIBLE_FURNITURE_KEY, PersistentDataType.INTEGER, maxVisibleFurniture); + this.maxVisibleFurniture = maxVisibleFurniture; + } + this.visualFurnitureView.setMaxVisibleFurniture( + this.maxVisibleFurniture == -1 ? maxVisibleFurniture : this.maxVisibleFurniture + ); + } + public void setResendSound() { resentSoundTick = gameTicks(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 53f8b5da5..f04069413 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.plugin; import net.momirealms.craftengine.core.advancement.AdvancementManager; import net.momirealms.craftengine.core.block.BlockManager; import net.momirealms.craftengine.core.entity.furniture.FurnitureManager; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; @@ -131,6 +132,9 @@ public abstract class CraftEngine implements Plugin { long time1 = System.currentTimeMillis(); // firstly reload main config this.config.load(); + for (Player player : this.networkManager().onlineUsers()) { + player.setMaxVisibleFurniture(Config.maxVisibleFurniture(), false); + } // reset debugger this.debugger = Config.debug() ? (s) -> logger.info("[Debug] " + s.get()) : (s) -> {}; // now we reload the translations diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index d442edb97..a0283efab 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -46,6 +46,8 @@ public interface NetWorkUser { DynamicPriorityTracker visualFurnitureView(); + void setMaxVisibleFurniture(int maxVisibleFurniture, boolean fromCommand); + boolean clientModEnabled(); void setClientModState(boolean enable); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java index 50ebee72d..f538a6269 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java @@ -31,6 +31,15 @@ public class DynamicPriorityTracker { public Object removePacket() { return removePacket; } + + @Override + public String toString() { + return "Element{" + + "entityId=" + entityId + + ", distance=" + distance + + ", removePacket=" + removePacket + + '}'; + } } public static class UpdateResult { @@ -50,17 +59,31 @@ public class DynamicPriorityTracker { void addExited(Element e) { exited.add(e); } + + @Override + public String toString() { + return "UpdateResult{" + + "entered=" + entered + + ", exited=" + exited + + '}'; + } } + private Integer maxVisibleFurniture; private final PriorityQueue maxHeap; private final Map elementMap = new ConcurrentHashMap<>(); private final Set inHeapSet = ConcurrentHashMap.newKeySet(); private final ReentrantLock heapLock = new ReentrantLock(); public DynamicPriorityTracker() { + this.maxVisibleFurniture = Config.maxVisibleFurniture(); this.maxHeap = new PriorityQueue<>((a, b) -> Double.compare(b.distance, a.distance)); } + public void setMaxVisibleFurniture(int maxVisibleFurniture) { + this.maxVisibleFurniture = maxVisibleFurniture; + } + public UpdateResult addOrUpdateElement(Element newElement) { UpdateResult result = new UpdateResult(); heapLock.lock(); @@ -80,7 +103,7 @@ public class DynamicPriorityTracker { private UpdateResult handleNewElement(Element newElement, UpdateResult result) { elementMap.put(newElement.entityId, newElement); - if (maxHeap.size() < Config.maxVisibleFurniture()) { + if (maxHeap.size() < maxVisibleFurniture) { maxHeap.offer(newElement); inHeapSet.add(newElement.entityId); result.addEntered(newElement); @@ -106,7 +129,7 @@ public class DynamicPriorityTracker { maxHeap.remove(existing); maxHeap.offer(existing); } else if (nowInHeap) { - if (maxHeap.size() < Config.maxVisibleFurniture()) { + if (maxHeap.size() < maxVisibleFurniture) { maxHeap.offer(existing); inHeapSet.add(existing.entityId); result.addEntered(existing); @@ -124,7 +147,7 @@ public class DynamicPriorityTracker { } private boolean checkIfShouldBeInHeap(double distance) { - if (maxHeap.size() < Config.maxVisibleFurniture()) return true; + if (maxHeap.size() < maxVisibleFurniture) return true; return maxHeap.peek() != null && distance < maxHeap.peek().distance; } @@ -146,16 +169,26 @@ public class DynamicPriorityTracker { } } - public Element removeByEntityId(int entityId) { + public void removeByEntityId(int entityId) { heapLock.lock(); try { Element removed = elementMap.remove(entityId); if (removed != null) { maxHeap.remove(removed); + inHeapSet.remove(entityId); } - return removed; } finally { heapLock.unlock(); } } + + @Override + public String toString() { + return "DynamicPriorityTracker{" + + "maxHeap=" + maxHeap + + ", elementMap=" + elementMap + + ", inHeapSet=" + inHeapSet + + ", heapLock=" + heapLock + + '}'; + } } diff --git a/gradle.properties b/gradle.properties index a350543e3..a493a2f38 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.54.2 -config_version=33 +config_version=34 lang_version=13 project_group=net.momirealms latest_supported_version=1.21.5