Replace entity tracked fields as well as chunk map ones

This commit is contained in:
fullwall 2024-07-12 17:25:26 +08:00
parent ec51df24b5
commit 6d18bc16c7
8 changed files with 100 additions and 57 deletions

View File

@ -912,8 +912,8 @@ public class NPCCommands {
for (String part : parts) {
if (part.contains(":")) {
int idx = part.indexOf(':');
Template template = templateRegistry.getTemplateByKey(
new NamespacedKey(part.substring(0, idx), part.substring(idx + 1).toLowerCase(Locale.US)));
Template template = templateRegistry.getTemplateByKey(new NamespacedKey(part.substring(0, idx),
part.substring(idx + 1).toLowerCase(Locale.ROOT)));
if (template == null)
continue;
template.apply(npc);
@ -1263,7 +1263,7 @@ public class NPCCommands {
@Command(
aliases = { "npc" },
usage = "hologram add [text] | set [line #] [text] | remove [line #] | bgcolor [line #] (color) | clear | lineheight [height] | viewrange [range] | margintop [line #] [margin] | marginbottom [line #] [margin]",
usage = "hologram add [text] | set [line #] [text] | remove [line #] | bgcolor [line #] (red,green,blue(,alpha)) | clear | lineheight [height] | viewrange [range] | margintop [line #] [margin] | marginbottom [line #] [margin]",
desc = "",
modifiers = { "hologram" },
min = 1,
@ -3661,7 +3661,7 @@ public class NPCCommands {
trait.setInterested(!trait.isInterested());
}
if (variant != null) {
variant = variant.toUpperCase(Locale.US);
variant = variant.toUpperCase(Locale.ROOT);
try {
Wolf.Variant.class.getField(variant);
} catch (Throwable t) {

View File

@ -44,7 +44,7 @@ public class TemplateCommands {
if (templateKey.contains(":")) {
int idx = templateKey.indexOf(':');
template = registry.getTemplateByKey(new NamespacedKey(templateKey.substring(0, idx),
templateKey.substring(idx + 1).toLowerCase(Locale.US)));
templateKey.substring(idx + 1).toLowerCase(Locale.ROOT)));
} else {
Collection<Template> templates = registry.getTemplates(templateKey);
if (templates.isEmpty())
@ -73,9 +73,9 @@ public class TemplateCommands {
@Arg(value = 1, completionsProvider = TemplateCompletions.class) String templateName)
throws CommandException {
int idx = templateName.indexOf(':');
NamespacedKey key = idx == -1 ? new NamespacedKey("generated", templateName.toLowerCase(Locale.US))
NamespacedKey key = idx == -1 ? new NamespacedKey("generated", templateName.toLowerCase(Locale.ROOT))
: new NamespacedKey(templateName.substring(0, idx),
templateName.substring(idx + 1).toLowerCase(Locale.US));
templateName.substring(idx + 1).toLowerCase(Locale.ROOT));
if (registry.getTemplateByKey(key) != null)
throw new CommandException(Messages.TEMPLATE_CONFLICT);
registry.generateTemplateFromNPC(key, npc);

View File

@ -20,7 +20,7 @@ import org.bukkit.scheduler.BukkitRunnable;
import com.google.common.base.Throwables;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.SetMultimap;
import net.citizensnpcs.NPCNeedsRespawnEvent;
@ -381,7 +381,8 @@ public class CitizensNPC extends AbstractNPC {
return;
}
navigator.onSpawn();
for (Trait trait : Iterables.toArray(traits.values(), Trait.class)) {
for (Trait trait : traits.values().toArray(ObjectArrays.newArray(Trait.class, traits.size()))) {
try {
trait.onSpawn();
} catch (Throwable ex) {
@ -389,7 +390,6 @@ public class CitizensNPC extends AbstractNPC {
ex.printStackTrace();
}
}
// Replace the entity tracker
NMS.replaceTracker(getEntity());
EntityType type = getEntity().getType();
if (type.isAlive()) {
@ -479,21 +479,21 @@ public class CitizensNPC extends AbstractNPC {
resetCachedCoord();
return;
}
Location loc = getEntity().getLocation();
if (data().has(NPC.Metadata.ACTIVATION_RANGE)) {
int range = data().get(NPC.Metadata.ACTIVATION_RANGE);
if (range == -1 || CitizensAPI.getLocationLookup().getNearbyPlayers(getStoredLocation(), range)
.iterator().hasNext()) {
if (range == -1 || CitizensAPI.getLocationLookup().getNearbyPlayers(loc, range).iterator().hasNext()) {
NMS.activate(getEntity());
}
}
boolean shouldSwim = data().get(NPC.Metadata.SWIM, SwimmingExaminer.isWaterMob(getEntity()))
&& MinecraftBlockExaminer.isLiquid(getEntity().getLocation().getBlock().getType());
&& MinecraftBlockExaminer.isLiquid(loc.getBlock().getType());
if (navigator.isNavigating()) {
if (shouldSwim) {
getEntity().setVelocity(getEntity().getVelocity().multiply(
data().get(NPC.Metadata.WATER_SPEED_MODIFIER, Setting.NPC_WATER_SPEED_MODIFIER.asFloat())));
Location currentDest = navigator.getPathStrategy().getCurrentDestination();
if (currentDest == null || currentDest.getY() > getStoredLocation().getY()) {
if (currentDest == null || currentDest.getY() > loc.getY()) {
NMS.trySwim(getEntity());
}
}
@ -504,23 +504,15 @@ public class CitizensNPC extends AbstractNPC {
}
}
if (SUPPORT_GLOWING && data().has(NPC.Metadata.GLOWING)) {
try {
getEntity().setGlowing(data().get(NPC.Metadata.GLOWING, false));
} catch (NoSuchMethodError e) {
SUPPORT_GLOWING = false;
}
getEntity().setGlowing(data().get(NPC.Metadata.GLOWING, false));
}
if (SUPPORT_SILENT && data().has(NPC.Metadata.SILENT)) {
try {
getEntity().setSilent(Boolean.parseBoolean(data().get(NPC.Metadata.SILENT).toString()));
} catch (NoSuchMethodError e) {
SUPPORT_SILENT = false;
}
getEntity().setSilent(Boolean.parseBoolean(data().get(NPC.Metadata.SILENT).toString()));
}
boolean isLiving = getEntity() instanceof LivingEntity;
if (isUpdating(NPCUpdate.PACKET)) {
if (data().get(NPC.Metadata.KEEP_CHUNK_LOADED, Setting.KEEP_CHUNKS_LOADED.asBoolean())) {
ChunkCoord currentCoord = new ChunkCoord(getStoredLocation());
ChunkCoord currentCoord = new ChunkCoord(loc);
if (!currentCoord.equals(cachedCoord)) {
resetCachedCoord();
currentCoord.setForceLoaded(true);
@ -538,11 +530,7 @@ public class CitizensNPC extends AbstractNPC {
if (isLiving) {
NMS.setKnockbackResistance((LivingEntity) getEntity(), isProtected() ? 1D : 0D);
if (SUPPORT_PICKUP_ITEMS) {
try {
((LivingEntity) getEntity()).setCanPickupItems(data().get(NPC.Metadata.PICKUP_ITEMS, false));
} catch (Throwable t) {
SUPPORT_PICKUP_ITEMS = false;
}
((LivingEntity) getEntity()).setCanPickupItems(data().get(NPC.Metadata.PICKUP_ITEMS, false));
}
if (getEntity() instanceof Player) {
updateUsingItemState((Player) getEntity());
@ -622,9 +610,31 @@ public class CitizensNPC extends AbstractNPC {
}
private static SetMultimap<ChunkCoord, NPC> CHUNK_LOADERS = HashMultimap.create();
private static boolean SUPPORT_GLOWING = true;
private static boolean SUPPORT_NODAMAGE_TICKS = true;
private static boolean SUPPORT_PICKUP_ITEMS = true;
private static boolean SUPPORT_SILENT = true;
private static boolean SUPPORT_GLOWING = false;
private static boolean SUPPORT_NODAMAGE_TICKS = false;
private static boolean SUPPORT_PICKUP_ITEMS = false;
private static boolean SUPPORT_SILENT = false;
private static boolean SUPPORT_USE_ITEM = true;
static {
try {
Entity.class.getMethod("setNoDamageTicks", int.class);
SUPPORT_NODAMAGE_TICKS = true;
} catch (NoSuchMethodException | SecurityException e) {
}
try {
Entity.class.getMethod("setGlowing", boolean.class);
SUPPORT_GLOWING = true;
} catch (NoSuchMethodException | SecurityException e) {
}
try {
Entity.class.getMethod("setSilent", boolean.class);
SUPPORT_SILENT = true;
} catch (NoSuchMethodException | SecurityException e) {
}
try {
LivingEntity.class.getMethod("setCanPickupItems", boolean.class);
SUPPORT_PICKUP_ITEMS = true;
} catch (NoSuchMethodException | SecurityException e) {
}
}
}

View File

@ -177,7 +177,7 @@ public class CitizensTraitFactory implements TraitFactory {
@Override
@SuppressWarnings("unchecked")
public <T extends Trait> T getTrait(String name) {
TraitInfo info = registered.get(name.toLowerCase(Locale.US));
TraitInfo info = registered.get(name.toLowerCase(Locale.ROOT));
if (info == null)
return null;
return (T) create(info);
@ -185,7 +185,7 @@ public class CitizensTraitFactory implements TraitFactory {
@Override
public Class<? extends Trait> getTraitClass(String name) {
TraitInfo info = registered.get(name.toLowerCase(Locale.US));
TraitInfo info = registered.get(name.toLowerCase(Locale.ROOT));
return info == null ? null : info.getTraitClass();
}

View File

@ -1,7 +1,5 @@
package net.citizensnpcs.trait;
import java.lang.invoke.MethodHandle;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Horse.Color;
@ -111,22 +109,19 @@ public class HorseModifiers extends Trait {
horse.getInventory().setArmor(armor);
horse.getInventory().setSaddle(saddle);
}
if (CARRYING_CHEST_METHOD == null)
return;
if (npc.getEntity() instanceof ChestedHorse) {
try {
CARRYING_CHEST_METHOD.invoke(npc.getEntity(), carryingChest);
} catch (Throwable e) {
}
if (SUPPORTS_CARRYING_CHEST && npc.getEntity() instanceof ChestedHorse) {
((ChestedHorse) npc.getEntity()).setCarryingChest(carryingChest);
}
}
private static MethodHandle CARRYING_CHEST_METHOD;
private static boolean SUPPORTS_CARRYING_CHEST;
static {
try {
CARRYING_CHEST_METHOD = NMS.getMethodHandle(Class.forName("org.bukkit.entity.ChestedHorse"),
"setCarryingChest", false, boolean.class);
if (NMS.getMethodHandle(Class.forName("org.bukkit.entity.ChestedHorse"), "setCarryingChest", false,
boolean.class) != null) {
SUPPORTS_CARRYING_CHEST = true;
}
} catch (Throwable e) {
}
}

View File

@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ -273,7 +274,7 @@ public class NMS {
public static List<MethodHandle> getFieldsOfType(Class<?> clazz, Class<?> type) {
List<Field> found = getFieldsMatchingType(clazz, type, false);
if (found.isEmpty())
return null;
return Collections.emptyList();
return found.stream().map(f -> {
try {
return LOOKUP.unreflectGetter(f);
@ -585,6 +586,20 @@ public class NMS {
return null;
}
public static Collection<MethodHandle> getSettersOfType(Class<?> clazz, Class<?> fieldType) {
List<Field> found = getFieldsMatchingType(clazz, fieldType, false);
if (found.isEmpty())
return Collections.emptyList();
return found.stream().map(f -> {
try {
return LOOKUP.unreflectSetter(f);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}).filter(f -> f != null).collect(Collectors.toList());
}
public static String getSoundPath(Sound flag) throws CommandException {
return BRIDGE.getSoundPath(flag);
}
@ -988,7 +1003,6 @@ public class NMS {
private static MethodHandle UNSAFE_PUT_INT;
private static MethodHandle UNSAFE_PUT_LONG;
private static MethodHandle UNSAFE_PUT_OBJECT;
private static MethodHandle UNSAFE_STATIC_FIELD_OFFSET;
static {

View File

@ -333,7 +333,7 @@ public class Util {
}
public static String listValuesPretty(Object[] values) {
return "<yellow>" + Joiner.on("<green>, <yellow>").join(values).replace('_', ' ').toLowerCase(Locale.US);
return "<yellow>" + Joiner.on("<green>, <yellow>").join(values).replace('_', ' ').toLowerCase(Locale.ROOT);
}
public static <T extends Enum<?>> T matchEnum(T[] values, String toMatch) {
@ -345,7 +345,7 @@ public class Util {
}
for (T check : values) {
String name = check.name().toLowerCase(Locale.US);
String name = check.name().toLowerCase(Locale.ROOT);
if (name.replace("_", "").equals(toMatch) || name.startsWith(toMatch))
return check;
@ -422,7 +422,7 @@ public class Util {
}
public static String prettyEnum(Enum<?> e) {
return e.name().toLowerCase(Locale.US).replace('_', ' ');
return e.name().toLowerCase(Locale.ROOT).replace('_', ' ');
}
public static String prettyPrintLocation(Location to) {

View File

@ -626,9 +626,19 @@ public class NMSImpl implements NMSBridge {
@Override
public EntityPacketTracker getPacketTracker(org.bukkit.entity.Entity entity) {
ServerLevel server = (ServerLevel) getHandle(entity).level();
TrackedEntity entry = server.getChunkSource().chunkMap.entityMap.get(entity.getEntityId());
if (entry == null)
TrackedEntity tracked = null;
if (TRACKED_ENTITY_GETTER != null) {
try {
tracked = (TrackedEntity) TRACKED_ENTITY_GETTER.invoke(getHandle(entity));
} catch (Throwable e) {
e.printStackTrace();
}
} else {
tracked = server.getChunkSource().chunkMap.entityMap.get(entity.getEntityId());
}
if (tracked == null)
return null;
TrackedEntity entry = tracked;
return new EntityPacketTracker() {
@Override
public void link(Player player) {
@ -1335,7 +1345,16 @@ public class NMSImpl implements NMSBridge {
@Override
public void replaceTrackerEntry(org.bukkit.entity.Entity entity) {
ServerLevel server = (ServerLevel) getHandle(entity).level();
Entity handle = getHandle(entity);
ServerLevel server = (ServerLevel) handle.level();
for (MethodHandle setter : TRACKED_ENTITY_SETTERS) {
try {
setter.invoke(handle, new CitizensEntityTracker(server.getChunkSource().chunkMap,
(TrackedEntity) TRACKED_ENTITY_GETTER.invoke(handle)));
} catch (Throwable e) {
e.printStackTrace();
}
}
TrackedEntity entry = server.getChunkSource().chunkMap.entityMap.get(entity.getEntityId());
if (entry == null)
return;
@ -2520,7 +2539,9 @@ public class NMSImpl implements NMSBridge {
private static final MethodHandle ADVANCEMENTS_PLAYER_SETTER = NMS.getFirstFinalSetter(ServerPlayer.class,
PlayerAdvancements.class);
private static final MethodHandle ARMADILLO_SCUTE_TIME = NMS.getSetter(Armadillo.class, "cn");
private static final MethodHandle ATTRIBUTE_PROVIDER_MAP = NMS.getFirstGetter(AttributeSupplier.class, Map.class);
private static final MethodHandle ATTRIBUTE_PROVIDER_MAP_SETTER = NMS.getFirstFinalSetter(AttributeSupplier.class,
Map.class);
@ -2572,10 +2593,10 @@ public class NMSImpl implements NMSBridge {
private static final MethodHandle NAVIGATION_CREATE_PATHFINDER = NMS
.getFirstMethodHandleWithReturnType(PathNavigation.class, true, PathFinder.class, int.class);
private static final MethodHandle NAVIGATION_PATH = NMS.getFirstGetter(PathNavigation.class, Path.class);
private static final MethodHandle NAVIGATION_PATHFINDER = NMS.getFirstFinalSetter(PathNavigation.class,
PathFinder.class);
private static final MethodHandle NAVIGATION_WORLD_FIELD = NMS.getFirstSetter(PathNavigation.class, Level.class);
private static final MethodHandle PLAYER_INFO_ENTRIES_LIST = NMS
.getFirstFinalSetter(ClientboundPlayerInfoUpdatePacket.class, List.class);
private static final MethodHandle PLAYERINFO_ENTRIES = PLAYER_INFO_ENTRIES_LIST;
@ -2592,6 +2613,9 @@ public class NMSImpl implements NMSBridge {
private static final MethodHandle SIZE_FIELD_SETTER = NMS.getFirstSetter(Entity.class, EntityDimensions.class);
private static MethodHandle SKULL_META_PROFILE;
private static MethodHandle TEAM_FIELD;
private static final MethodHandle TRACKED_ENTITY_GETTER = NMS.getFirstGetter(Entity.class, TrackedEntity.class);
private static final Collection<MethodHandle> TRACKED_ENTITY_SETTERS = NMS.getSettersOfType(Entity.class,
TrackedEntity.class);
static {
try {
ENTITY_REGISTRY = new CustomEntityRegistry(BuiltInRegistries.ENTITY_TYPE);