Viewer Rules

This commit is contained in:
= 2024-10-26 22:51:15 +03:00
parent 6849d6ec6c
commit ee554d66b4
5 changed files with 202 additions and 0 deletions

View file

@ -1,5 +1,6 @@
package me.tofaa.entitylib.utils; package me.tofaa.entitylib.utils;
import com.github.retrooper.packetevents.protocol.world.Location;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -15,6 +16,12 @@ public final class Check {
private Check() {} private Check() {}
public static boolean inChunk(Location location, int cx, int cz) {
// Assumes each chunk is 16x
int lx = ((int) Math.floor(location.getX())) >> 4;
int lz = ((int) Math.floor(location.getZ())) >> 4;
return cx == lx && cz == lz;
}
public static <T> void arrayLength(List<T> lines, int index, T e) { public static <T> void arrayLength(List<T> lines, int index, T e) {
if (index >= lines.size()) { if (index >= lines.size()) {

View file

@ -0,0 +1,86 @@
package me.tofaa.entitylib.ve;
import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.wrapper.WrapperEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class ViewerEngine {
private final List<ViewerRule> globalRules;
private final Set<WrapperEntity> tracked;
private final ViewerEngineListener listener;
private Executor executor;
public ViewerEngine() {
this.globalRules = new CopyOnWriteArrayList<>();
this.tracked = Collections.newSetFromMap(new WeakHashMap<>());
this.executor = Executors.newSingleThreadExecutor();
this.listener = new ViewerEngineListener(this);
}
public void enable() {
EntityLib.getApi().getPacketEvents().getEventManager().registerListener(listener);
}
public void disable() {
EntityLib.getApi().getPacketEvents().getEventManager().unregisterListener(listener);
}
public Executor getExecutor() {
return executor;
}
public void setExecutor(Executor executor) {
this.executor = executor;
}
public void track(@NotNull WrapperEntity entity) {
tracked.add(entity);
}
public void clearTracked() {
tracked.clear();
}
public @UnmodifiableView Collection<WrapperEntity> getTracked() {
return Collections.unmodifiableCollection(tracked);
}
Set<WrapperEntity> getTracked0() {
return tracked;
}
public void addViewerRule(@NotNull ViewerRule rule) {
this.globalRules.add(rule);
}
public void removeViewerRule(@NotNull ViewerRule rule) {
this.globalRules.remove(rule);
}
public void removeViewerRule(int index) {
this.globalRules.remove(index);
}
public void clearViewerRules() {
this.globalRules.clear();
}
public @UnmodifiableView Collection<ViewerRule> getViewerRules() {
return Collections.unmodifiableCollection(globalRules);
}
public @Nullable ViewerRule getViewerRule(int index) {
if (this.globalRules.size() >= index - 1) return null;
if (index < 0) return null;
return globalRules.get(index);
}
}

View file

@ -0,0 +1,60 @@
package me.tofaa.entitylib.ve;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUnloadChunk;
import me.tofaa.entitylib.utils.Check;
import java.util.concurrent.atomic.AtomicBoolean;
final class ViewerEngineListener extends PacketListenerAbstract {
private final ViewerEngine engine;
ViewerEngineListener(ViewerEngine engine) {
this.engine = engine;
}
@Override
public void onPacketSend(PacketSendEvent event) {
PacketTypeCommon type = event.getPacketType();
if (type == PacketType.Play.Server.UNLOAD_CHUNK) {
PacketSendEvent copy = event.clone();
engine.getExecutor().execute(() -> {
WrapperPlayServerUnloadChunk packet = new WrapperPlayServerUnloadChunk(event);
int chunkX = packet.getChunkX();
int chunkZ = packet.getChunkZ();
engine.getTracked0().forEach(entity -> {
if (!Check.inChunk(entity.getLocation(), chunkX, chunkZ)) return;
entity.removeViewer(event.getUser());
});
copy.cleanUp();
});
}
if (type == PacketType.Play.Server.CHUNK_DATA) {
PacketSendEvent copy = event.clone();
engine.getExecutor().execute(() -> {
WrapperPlayServerUnloadChunk packet = new WrapperPlayServerUnloadChunk(event);
int chunkX = packet.getChunkX();
int chunkZ = packet.getChunkZ();
engine.getTracked0().forEach(entity -> {
if (!Check.inChunk(entity.getLocation(), chunkX, chunkZ)) return;
if (entity.hasViewer(event.getUser())) return;
AtomicBoolean pass = new AtomicBoolean(false);
entity.getViewerRules().forEach(rule -> {
pass.set(rule.shouldSee(event.getUser()));
});
engine.getViewerRules().forEach(rule -> {
pass.set(rule.shouldSee(event.getUser()));
});
if (!pass.get()) return;
entity.addViewer(event.getUser());
});
copy.cleanUp();
});
}
}
}

View file

@ -0,0 +1,11 @@
package me.tofaa.entitylib.ve;
import com.github.retrooper.packetevents.protocol.player.User;
@FunctionalInterface
public interface ViewerRule {
boolean shouldSee(User user);
}

View file

@ -12,12 +12,15 @@ import me.tofaa.entitylib.container.EntityContainer;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import me.tofaa.entitylib.meta.types.ObjectData; import me.tofaa.entitylib.meta.types.ObjectData;
import me.tofaa.entitylib.tick.Tickable; import me.tofaa.entitylib.tick.Tickable;
import me.tofaa.entitylib.ve.ViewerRule;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer; import java.util.function.Consumer;
public class WrapperEntity implements Tickable, TrackedEntity { public class WrapperEntity implements Tickable, TrackedEntity {
@ -36,6 +39,7 @@ public class WrapperEntity implements Tickable, TrackedEntity {
private int riding = -1; private int riding = -1;
private final Set<Integer> passengers; private final Set<Integer> passengers;
private EntityContainer parent; private EntityContainer parent;
private final List<ViewerRule> viewerRules;
public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) { public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
this.entityId = entityId; this.entityId = entityId;
@ -46,6 +50,7 @@ public class WrapperEntity implements Tickable, TrackedEntity {
this.viewers = ConcurrentHashMap.newKeySet(); this.viewers = ConcurrentHashMap.newKeySet();
this.passengers = ConcurrentHashMap.newKeySet(); this.passengers = ConcurrentHashMap.newKeySet();
this.location = new Location(0, 0, 0, 0, 0); this.location = new Location(0, 0, 0, 0, 0);
this.viewerRules = new CopyOnWriteArrayList<>();
} }
public WrapperEntity(int entityId, EntityType entityType) { public WrapperEntity(int entityId, EntityType entityType) {
@ -353,6 +358,31 @@ public class WrapperEntity implements Tickable, TrackedEntity {
return new WrapperPlayServerSetPassengers(entityId, passengers.stream().mapToInt(i -> i).toArray()); return new WrapperPlayServerSetPassengers(entityId, passengers.stream().mapToInt(i -> i).toArray());
} }
public @UnmodifiableView Collection<ViewerRule> getViewerRules() {
return Collections.unmodifiableCollection(viewerRules);
}
public void addViewerRule(@NotNull ViewerRule rule) {
this.viewerRules.add(rule);
}
public void removeViewerRule(@NotNull ViewerRule rule) {
this.viewerRules.remove(rule);
}
public void removeViewerRule(int index) {
this.viewerRules.remove(index);
}
public void clearViewerRules() {
this.viewerRules.clear();
}
public @Nullable ViewerRule getViewerRule(int index) {
if (this.viewerRules.size() >= index - 1) return null;
if (index < 0) return null;
return viewerRules.get(index);
}
private WrapperPlayServerEntityVelocity getVelocityPacket() { private WrapperPlayServerEntityVelocity getVelocityPacket() {
Vector3d velocity = this.velocity.multiply(8000.0f / 20.0f); Vector3d velocity = this.velocity.multiply(8000.0f / 20.0f);
@ -578,6 +608,14 @@ public class WrapperEntity implements Tickable, TrackedEntity {
return Collections.unmodifiableSet(viewers); return Collections.unmodifiableSet(viewers);
} }
public boolean hasViewer(UUID uuid) {
return viewers.contains(uuid);
}
public boolean hasViewer(User user) {
return hasViewer(user.getUUID());
}
public Location getLocation() { public Location getLocation() {
return location; return location;
} }