Added command /etf check, and change entity id with uuid for persistence

This commit is contained in:
Esmorall 2019-09-06 18:35:08 -03:00
parent b0440f6b40
commit 582dd0a451
10 changed files with 185 additions and 41 deletions

View File

@ -1,6 +1,8 @@
name: EntityTrackerFixer name: EntityTrackerFixer
main: net.minemora.entitytrackerfixer.EntityTrackerFixer main: net.minemora.entitytrackerfixer.EntityTrackerFixer
version: 1.0.9 version: 1.1
api-version: 1.14 api-version: 1.14
author: Esmorall author: Esmorall
commands: commands:
etf:
usage: /<command>

View File

@ -5,6 +5,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -41,34 +42,35 @@ public class CheckTask extends BukkitRunnable {
WorldServer ws = ((CraftWorld)Bukkit.getWorld(worldName)).getHandle(); WorldServer ws = ((CraftWorld)Bukkit.getWorld(worldName)).getHandle();
ChunkProviderServer cps = ws.getChunkProvider(); ChunkProviderServer cps = ws.getChunkProvider();
Set<UntrackedEntity> toRemove = new HashSet<>(); Set<UUID> toRemove = new HashSet<>();
Set<net.minecraft.server.v1_14_R1.Entity> trackAgain = new HashSet<>(); Set<net.minecraft.server.v1_14_R1.Entity> trackAgain = new HashSet<>();
Iterator<UntrackedEntity> it = UntrackedEntitiesCache.getInstance().getCache(worldName).iterator(); Iterator<UntrackedEntity> it = UntrackedEntitiesCache.getInstance().getCache(worldName).values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
UntrackedEntity ute = it.next(); UntrackedEntity ute = it.next();
net.minecraft.server.v1_14_R1.Entity nmsEnt = ute.getEntity(); net.minecraft.server.v1_14_R1.Entity nmsEnt = ute.getEntity();
UUID uid = nmsEnt.getUniqueID();
if(cps.playerChunkMap.trackedEntities.containsKey(nmsEnt.getId())) { if(cps.playerChunkMap.trackedEntities.containsKey(nmsEnt.getId())) {
//System.out.println("removed (et contains): " + nmsEnt.getBukkitEntity().getType().name()); //System.out.println("removed (et contains): " + nmsEnt.getBukkitEntity().getType().name());
toRemove.add(ute); toRemove.add(uid);
continue; continue;
} }
World world = nmsEnt.getBukkitEntity().getWorld(); World world = nmsEnt.getBukkitEntity().getWorld();
Location loc = nmsEnt.getBukkitEntity().getLocation(); Location loc = nmsEnt.getBukkitEntity().getLocation();
if(!Util.isChunkLoaded(ws, loc.getBlockX() >> 4, loc.getBlockZ() >> 4)) { if(!Util.isChunkLoaded(ws, loc.getBlockX() >> 4, loc.getBlockZ() >> 4)) {
//System.out.println("removed (unloaded chunk x:"+(loc.getBlockX() >> 4)+" z:"+(loc.getBlockZ() >> 4)+"): " + nmsEnt.getBukkitEntity().getType().name()); //System.out.println("removed (unloaded chunk x:"+(loc.getBlockX() >> 4)+" z:"+(loc.getBlockZ() >> 4)+"): " + nmsEnt.getBukkitEntity().getType().name());
UntrackedEntitiesCache.getInstance().addUFC(worldName, nmsEnt.getId()); UntrackedEntitiesCache.getInstance().addUFC(worldName, uid);
toRemove.add(ute); toRemove.add(uid);
continue; continue;
} }
if(!worldName.equals(world.getName())) { if(!worldName.equals(world.getName())) {
//System.out.println("removed (different world): " + nmsEnt.getBukkitEntity().getType().name()); //System.out.println("removed (different world): " + nmsEnt.getBukkitEntity().getType().name());
toRemove.add(ute); toRemove.add(uid);
continue; continue;
} }
if(nmsEnt.getBukkitEntity().isDead()) { if(nmsEnt.getBukkitEntity().isDead()) {
//System.out.println("removed (is dead): " + nmsEnt.getBukkitEntity().getType().name()); //System.out.println("removed (is dead): " + nmsEnt.getBukkitEntity().getType().name());
toRemove.add(ute); toRemove.add(uid);
continue; continue;
} }
boolean track = false; boolean track = false;
@ -94,7 +96,6 @@ public class CheckTask extends BukkitRunnable {
} }
} }
if(track) { if(track) {
//System.out.println("tracked again: " + nmsEnt.getBukkitEntity().getType().name());
trackAgain.add(nmsEnt); trackAgain.add(nmsEnt);
} }
} }

View File

@ -2,6 +2,7 @@ package net.minemora.entitytrackerfixer;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import net.minemora.entitytrackerfixer.commands.CommandETF;
import net.minemora.entitytrackerfixer.config.ConfigMain; import net.minemora.entitytrackerfixer.config.ConfigMain;
import net.minemora.entitytrackerfixer.listener.ChunkEventListener; import net.minemora.entitytrackerfixer.listener.ChunkEventListener;
@ -16,5 +17,6 @@ public class EntityTrackerFixer extends JavaPlugin {
new UntrackerTask().runTaskTimer(this, ConfigMain.getUntrackTicks(), ConfigMain.getUntrackTicks()); new UntrackerTask().runTaskTimer(this, ConfigMain.getUntrackTicks(), ConfigMain.getUntrackTicks());
new CheckTask().runTaskTimerAsynchronously(this, ConfigMain.getUntrackTicks() + 1, ConfigMain.getCheckFrequency()); new CheckTask().runTaskTimerAsynchronously(this, ConfigMain.getUntrackTicks() + 1, ConfigMain.getCheckFrequency());
getServer().getPluginManager().registerEvents(new ChunkEventListener(), this); getServer().getPluginManager().registerEvents(new ChunkEventListener(), this);
this.getCommand("etf").setExecutor(new CommandETF());
} }
} }

View File

@ -1,51 +1,57 @@
package net.minemora.entitytrackerfixer; package net.minemora.entitytrackerfixer;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class TrackedWorld { public class TrackedWorld {
private final String worldName; private final String worldName;
private Set<UntrackedEntity> cache = ConcurrentHashMap.newKeySet(); private Map<UUID,UntrackedEntity> cache = new ConcurrentHashMap<>();
private Set<Integer> unloadedFromChunkCache = ConcurrentHashMap.newKeySet(); private Set<UUID> unloadedFromChunkCache = ConcurrentHashMap.newKeySet();
public TrackedWorld(String worldName) { public TrackedWorld(String worldName) {
this.worldName = worldName; this.worldName = worldName;
} }
public void add(net.minecraft.server.v1_14_R1.Entity entity) { public void add(net.minecraft.server.v1_14_R1.Entity entity) {
cache.add(new UntrackedEntity(entity)); cache.put(entity.getUniqueID(), new UntrackedEntity(entity));
} }
public void remove(UntrackedEntity ute) { public void remove(UntrackedEntity ute) {
cache.remove(ute); cache.remove(ute.getUniqueID());
} }
public void removeAll(Set<UntrackedEntity> toRemove) { public boolean contains(UUID uid) {
cache.removeAll(toRemove); return cache.containsKey(uid);
}
public void removeAll(Set<UUID> toRemove) {
cache.keySet().removeAll(toRemove);
} }
public boolean isEmpty(String worldName) { public boolean isEmpty(String worldName) {
return cache.isEmpty(); return cache.isEmpty();
} }
public Set<UntrackedEntity> getCache() { public Map<UUID,UntrackedEntity> getCache() {
return cache; return cache;
} }
public void addUFC(int i) { public void addUFC(UUID uid) {
unloadedFromChunkCache.add(i); unloadedFromChunkCache.add(uid);
} }
public void removeUFC(int i) { public void removeUFC(UUID uid) {
unloadedFromChunkCache.remove(i); unloadedFromChunkCache.remove(uid);
} }
public boolean containsUFC(int i) { public boolean containsUFC(UUID uid) {
return unloadedFromChunkCache.contains(i); return unloadedFromChunkCache.contains(uid);
} }
public Set<Integer> getUnloadedFromChunkCache() { public Set<UUID> getUnloadedFromChunkCache() {
return unloadedFromChunkCache; return unloadedFromChunkCache;
} }

View File

@ -1,8 +1,10 @@
package net.minemora.entitytrackerfixer; package net.minemora.entitytrackerfixer;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import net.minemora.entitytrackerfixer.config.ConfigMain; import net.minemora.entitytrackerfixer.config.ConfigMain;
@ -37,7 +39,15 @@ public final class UntrackedEntitiesCache {
tw.remove(ute); tw.remove(ute);
} }
public void removeAll(Set<UntrackedEntity> toRemove, String worldName) { public boolean contains(UUID uid, String worldName) {
if(!trackedWorlds.containsKey(worldName)) {
return false;
}
TrackedWorld tw = trackedWorlds.get(worldName);
return tw.contains(uid);
}
public void removeAll(Set<UUID> toRemove, String worldName) {
if(!trackedWorlds.containsKey(worldName)) { if(!trackedWorlds.containsKey(worldName)) {
return; return;
} }
@ -52,40 +62,40 @@ public final class UntrackedEntitiesCache {
return getCache(worldName).isEmpty(); return getCache(worldName).isEmpty();
} }
public Set<UntrackedEntity> getCache(String worldName) { public Map<UUID,UntrackedEntity> getCache(String worldName) {
if(!trackedWorlds.containsKey(worldName)) { if(!trackedWorlds.containsKey(worldName)) {
return new HashSet<UntrackedEntity>(); return new HashMap<>();
} }
TrackedWorld tw = trackedWorlds.get(worldName); TrackedWorld tw = trackedWorlds.get(worldName);
return tw.getCache(); return tw.getCache();
} }
public void addUFC(String worldName, int i) { public void addUFC(String worldName, UUID uid) {
if(!trackedWorlds.containsKey(worldName)) { if(!trackedWorlds.containsKey(worldName)) {
return; return;
} }
TrackedWorld tw = trackedWorlds.get(worldName); TrackedWorld tw = trackedWorlds.get(worldName);
tw.addUFC(i); tw.addUFC(uid);
} }
public void removeUFC(String worldName, int i) { public void removeUFC(String worldName, UUID uid) {
if(!trackedWorlds.containsKey(worldName)) { if(!trackedWorlds.containsKey(worldName)) {
return; return;
} }
TrackedWorld tw = trackedWorlds.get(worldName); TrackedWorld tw = trackedWorlds.get(worldName);
tw.removeUFC(i); tw.removeUFC(uid);
} }
public boolean containsUFC(String worldName, int i) { public boolean containsUFC(String worldName, UUID uid) {
if(!trackedWorlds.containsKey(worldName)) { if(!trackedWorlds.containsKey(worldName)) {
return true; return false;
} }
return getUnloadedFromChunkCache(worldName).contains(i); return getUnloadedFromChunkCache(worldName).contains(uid);
} }
public Set<Integer> getUnloadedFromChunkCache(String worldName) { public Set<UUID> getUnloadedFromChunkCache(String worldName) {
if(!trackedWorlds.containsKey(worldName)) { if(!trackedWorlds.containsKey(worldName)) {
return new HashSet<Integer>(); return new HashSet<UUID>();
} }
TrackedWorld tw = trackedWorlds.get(worldName); TrackedWorld tw = trackedWorlds.get(worldName);
return tw.getUnloadedFromChunkCache(); return tw.getUnloadedFromChunkCache();

View File

@ -1,12 +1,16 @@
package net.minemora.entitytrackerfixer; package net.minemora.entitytrackerfixer;
import java.util.UUID;
public class UntrackedEntity { public class UntrackedEntity {
private final net.minecraft.server.v1_14_R1.Entity entity; private final net.minecraft.server.v1_14_R1.Entity entity;
private final int id; private final UUID uniqueID;
private int id;
public UntrackedEntity(net.minecraft.server.v1_14_R1.Entity entity) { public UntrackedEntity(net.minecraft.server.v1_14_R1.Entity entity) {
this.entity = entity; this.entity = entity;
this.uniqueID = entity.getUniqueID();
this.id = entity.getId(); this.id = entity.getId();
} }
@ -14,7 +18,11 @@ public class UntrackedEntity {
return entity; return entity;
} }
public int getId() { public UUID getUniqueID() {
return uniqueID;
}
private int getId() {
return id; return id;
} }

View File

@ -82,7 +82,7 @@ public class UntrackerTask extends BukkitRunnable {
} }
Location loc = nmsEnt.getBukkitEntity().getLocation(); Location loc = nmsEnt.getBukkitEntity().getLocation();
if(!Util.isChunkLoaded(ws, loc.getBlockX() >> 4, loc.getBlockZ() >> 4)) { if(!Util.isChunkLoaded(ws, loc.getBlockX() >> 4, loc.getBlockZ() >> 4)) {
UntrackedEntitiesCache.getInstance().addUFC(worldName, nmsEnt.getId()); UntrackedEntitiesCache.getInstance().addUFC(worldName, nmsEnt.getUniqueID());
} }
if(remove) { if(remove) {
//System.out.println("untracked: " + nmsEnt.getBukkitEntity().getType().name()); //System.out.println("untracked: " + nmsEnt.getBukkitEntity().getType().name());
@ -111,6 +111,8 @@ public class UntrackerTask extends BukkitRunnable {
if(ConfigMain.isLogToConsole()) { if(ConfigMain.isLogToConsole()) {
EntityTrackerFixer.plugin.getLogger().info("Untracked " + removed + " entities in " + worldName); EntityTrackerFixer.plugin.getLogger().info("Untracked " + removed + " entities in " + worldName);
} }
//System.out.println("cache now contains " + UntrackedEntitiesCache.getInstance().getCache(worldName).size() + " entities");
} }
public static boolean isRunning() { public static boolean isRunning() {

View File

@ -0,0 +1,69 @@
package net.minemora.entitytrackerfixer.commands;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import net.minecraft.server.v1_14_R1.ChunkProviderServer;
import net.minecraft.server.v1_14_R1.WorldServer;
import net.minemora.entitytrackerfixer.UntrackedEntitiesCache;
import net.minemora.entitytrackerfixer.util.ChatUtils;
public class CommandETF implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("etf.command")) {
return true;
}
if(args.length < 2) {
return true;
//TODO command list
}
if(args[0].equalsIgnoreCase("check")) {
if (!sender.hasPermission("etf.command.check")) {
return true;
}
if (!(sender instanceof Player)) {
sender.sendMessage(ChatUtils.format("&cOnly players can use this command"));
return true;
}
int r;
try {
r = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
sender.sendMessage(ChatUtils.format("&4" + args[1] + " &cis not a number"));
return true;
}
Player player = (Player)sender;
WorldServer ws = ((CraftWorld)player.getWorld()).getHandle();
ChunkProviderServer cps = ws.getChunkProvider();
int trackedCount = 0;
int untrackedCount = 0;
int cachedCount = 0;
for(Entity ent : player.getNearbyEntities(r, r, r)) {
if(cps.playerChunkMap.trackedEntities.containsKey(ent.getEntityId())) {
trackedCount++;
}
else {
untrackedCount++;
}
if(UntrackedEntitiesCache.getInstance().contains(ent.getUniqueId(), ent.getWorld().getName())) {
cachedCount++;
}
}
player.sendMessage(ChatUtils.format(new String[] {
"&bChecking entities in radius &f" + r,
" &f> &9Tracked Entities: &a" + trackedCount,
" &f> &9Untracked Entities &c" + untrackedCount,
" &f> &9Cached Entities &e" + cachedCount,
"&7(Untracked and cache should be the same number)"
}));
}
return true;
}
}

View File

@ -19,9 +19,9 @@ public class ChunkEventListener implements Listener {
return; return;
} }
for(Entity entity : ch.getEntities()) { for(Entity entity : ch.getEntities()) {
if(UntrackedEntitiesCache.getInstance().containsUFC(ch.getWorld().getName(), entity.getEntityId())) { if(UntrackedEntitiesCache.getInstance().containsUFC(ch.getWorld().getName(), entity.getUniqueId())) {
UntrackedEntitiesCache.getInstance().add(((CraftEntity)entity).getHandle()); UntrackedEntitiesCache.getInstance().add(((CraftEntity)entity).getHandle());
UntrackedEntitiesCache.getInstance().removeUFC(ch.getWorld().getName(), entity.getEntityId()); UntrackedEntitiesCache.getInstance().removeUFC(ch.getWorld().getName(), entity.getUniqueId());
} }
} }
} }

View File

@ -0,0 +1,44 @@
package net.minemora.entitytrackerfixer.util;
import java.util.List;
import java.util.stream.Collectors;
import org.bukkit.ChatColor;
import org.bukkit.Location;
public interface ChatUtils {
static String format(String m) {
return ChatColor.translateAlternateColorCodes('&', m);
}
static String[] format(String[] m) {
String[] result;
result = new String[m.length];
for (int i = 0; i < m.length; i++) {
result[i] = ChatColor.translateAlternateColorCodes('&', m[i]);
}
return result;
}
static String[] format(List<String> m) {
String[] result;
result = new String[m.size()];
for (int i = 0; i < m.size(); i++) {
result[i] = ChatColor.translateAlternateColorCodes('&', m.get(i));
}
return result;
}
static List<String> formatList(List<String> m) {
return m.stream().map(s -> ChatColor.translateAlternateColorCodes('&', s)).collect(Collectors.toList());
}
static String formatTime(int seconds) {
return String.format("%02d:%02d", seconds / 60, seconds % 60);
}
static String formatLocation(Location loc) {
return "[x:" + loc.getBlockX() + ", y:" + loc.getBlockY() + ", z:" + loc.getBlockZ() + "]";
}
}