mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-29 11:59:11 +00:00
feat(bukkit): 添加限制可视家具数量
This commit is contained in:
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.plugin.network;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import net.momirealms.craftengine.core.plugin.Plugin;
|
||||
import net.momirealms.craftengine.core.util.DynamicPriorityTracker;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@@ -43,6 +44,8 @@ public interface NetWorkUser {
|
||||
|
||||
Map<Integer, EntityPacketHandler> entityPacketHandlers();
|
||||
|
||||
DynamicPriorityTracker visualFurnitureView();
|
||||
|
||||
boolean clientModEnabled();
|
||||
|
||||
void setClientModState(boolean enable);
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
package net.momirealms.craftengine.core.util;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class DynamicPriorityTracker {
|
||||
|
||||
public static class Element {
|
||||
private final int entityId;
|
||||
private volatile double distance;
|
||||
private final Object removePacket;
|
||||
|
||||
public Element(int entityId, double distance, Object removePacket) {
|
||||
this.entityId = entityId;
|
||||
this.distance = distance;
|
||||
this.removePacket = removePacket;
|
||||
}
|
||||
|
||||
public int entityId() {
|
||||
return entityId;
|
||||
}
|
||||
public double distance() {
|
||||
return distance;
|
||||
}
|
||||
public void setDistance(double distance) {
|
||||
this.distance = distance;
|
||||
}
|
||||
public Object removePacket() {
|
||||
return removePacket;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdateResult {
|
||||
private final List<Element> entered = new ArrayList<>();
|
||||
private final List<Element> exited = new ArrayList<>();
|
||||
|
||||
public List<Element> getEntered() {
|
||||
return entered;
|
||||
}
|
||||
public List<Element> getExited() {
|
||||
return exited;
|
||||
}
|
||||
|
||||
void addEntered(Element e) {
|
||||
entered.add(e);
|
||||
}
|
||||
void addExited(Element e) {
|
||||
exited.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final int capacity;
|
||||
private final PriorityQueue<Element> maxHeap;
|
||||
private final Map<Integer, Element> elementMap = new ConcurrentHashMap<>();
|
||||
private final Set<Integer> inHeapSet = ConcurrentHashMap.newKeySet();
|
||||
private final ReentrantLock heapLock = new ReentrantLock();
|
||||
|
||||
public DynamicPriorityTracker(int capacity) {
|
||||
this.capacity = capacity;
|
||||
this.maxHeap = new PriorityQueue<>((a, b) -> Double.compare(b.distance, a.distance));
|
||||
}
|
||||
|
||||
public UpdateResult addOrUpdateElement(Element newElement) {
|
||||
UpdateResult result = new UpdateResult();
|
||||
heapLock.lock();
|
||||
try {
|
||||
Element existing = elementMap.get(newElement.entityId);
|
||||
|
||||
if (existing != null) {
|
||||
return handleExistingElement(existing, newElement, result);
|
||||
} else {
|
||||
return handleNewElement(newElement, result);
|
||||
}
|
||||
} finally {
|
||||
heapLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private UpdateResult handleNewElement(Element newElement, UpdateResult result) {
|
||||
elementMap.put(newElement.entityId, newElement);
|
||||
|
||||
if (maxHeap.size() < capacity) {
|
||||
maxHeap.offer(newElement);
|
||||
inHeapSet.add(newElement.entityId);
|
||||
result.addEntered(newElement);
|
||||
} else if (maxHeap.peek() != null && newElement.distance < maxHeap.peek().distance) {
|
||||
Element removed = maxHeap.poll();
|
||||
inHeapSet.remove(removed.entityId);
|
||||
result.addExited(removed);
|
||||
|
||||
maxHeap.offer(newElement);
|
||||
inHeapSet.add(newElement.entityId);
|
||||
result.addEntered(newElement);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private UpdateResult handleExistingElement(Element existing, Element newElement, UpdateResult result) {
|
||||
existing.setDistance(newElement.distance);
|
||||
|
||||
boolean wasInHeap = inHeapSet.contains(existing.entityId);
|
||||
boolean nowInHeap = checkIfShouldBeInHeap(existing.distance);
|
||||
|
||||
if (wasInHeap) {
|
||||
maxHeap.remove(existing);
|
||||
maxHeap.offer(existing);
|
||||
} else if (nowInHeap) {
|
||||
if (maxHeap.size() < capacity) {
|
||||
maxHeap.offer(existing);
|
||||
inHeapSet.add(existing.entityId);
|
||||
result.addEntered(existing);
|
||||
} else if (maxHeap.peek() != null && existing.distance < maxHeap.peek().distance) {
|
||||
Element removed = maxHeap.poll();
|
||||
inHeapSet.remove(removed.entityId);
|
||||
result.addExited(removed);
|
||||
|
||||
maxHeap.offer(existing);
|
||||
inHeapSet.add(existing.entityId);
|
||||
result.addEntered(existing);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean checkIfShouldBeInHeap(double distance) {
|
||||
if (maxHeap.size() < capacity) return true;
|
||||
return maxHeap.peek() != null && distance < maxHeap.peek().distance;
|
||||
}
|
||||
|
||||
public int getTotalMembers() {
|
||||
heapLock.lock();
|
||||
try {
|
||||
return elementMap.size();
|
||||
} finally {
|
||||
heapLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Element> getAllElements() {
|
||||
heapLock.lock();
|
||||
try {
|
||||
return List.copyOf(elementMap.values());
|
||||
} finally {
|
||||
heapLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Element removeByEntityId(int entityId) {
|
||||
heapLock.lock();
|
||||
try {
|
||||
Element removed = elementMap.remove(entityId);
|
||||
if (removed != null) {
|
||||
maxHeap.remove(removed);
|
||||
}
|
||||
return removed;
|
||||
} finally {
|
||||
heapLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user