Reimplement hologram display entities using interaction entities as suggested by Owen1212055

This commit is contained in:
fullwall 2023-08-28 01:49:14 +08:00
parent c447b0d277
commit db6058bbd0
10 changed files with 105 additions and 34 deletions

View File

@ -166,6 +166,9 @@ public class Settings {
"Minecraft will pick a 'close-enough' location when pathfinding to a block if it can't find a direct path<br>Disabled by default", "Minecraft will pick a 'close-enough' location when pathfinding to a block if it can't find a direct path<br>Disabled by default",
"npc.pathfinding.disable-mc-fallback-navigation", true), "npc.pathfinding.disable-mc-fallback-navigation", true),
DISABLE_TABLIST("Whether to remove NPCs from the tablist", "npc.tablist.disable", true), DISABLE_TABLIST("Whether to remove NPCs from the tablist", "npc.tablist.disable", true),
DISPLAY_ENTITY_HOLOGRAMS(
"Whether to use display entities for holograms by default. In theory more performant than armor stands. Requires 1.19.4 or above. Defaults to false",
"npc.hologram.use-display-entities", false),
ENTITY_SPAWN_WAIT_DURATION( ENTITY_SPAWN_WAIT_DURATION(
"Entities are no longer spawned until the chunks are loaded from disk<br>Wait for chunk loading for one second by default, increase if your disk is slow", "Entities are no longer spawned until the chunks are loaded from disk<br>Wait for chunk loading for one second by default, increase if your disk is slow",
"general.entity-spawn-wait-ticks", "general.wait-for-entity-spawn", "1s"), "general.entity-spawn-wait-ticks", "general.wait-for-entity-spawn", "1s"),

View File

@ -39,9 +39,9 @@ public class BoundingBoxExaminer implements BlockExaminer {
if (above == null || below == null) if (above == null || below == null)
return PassableState.IGNORE; return PassableState.IGNORE;
float height = (float) (above.minY - below.maxY); float height = (float) (above.minY - below.maxY);
if (height < this.height) { if (height < this.height)
return PassableState.UNPASSABLE; return PassableState.UNPASSABLE;
}
} }
return PassableState.IGNORE; return PassableState.IGNORE;
} }

View File

@ -12,11 +12,10 @@ import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Display.Billboard;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Interaction;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.TextDisplay;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -55,7 +54,7 @@ public class HologramTrait extends Trait {
private HologramLine nameLine; private HologramLine nameLine;
private final NPCRegistry registry = CitizensAPI.createCitizensBackedNPCRegistry(new MemoryNPCDataStore()); private final NPCRegistry registry = CitizensAPI.createCitizensBackedNPCRegistry(new MemoryNPCDataStore());
private int t; private int t;
private boolean useTextDisplay; private boolean useDisplayEntities = Setting.DISPLAY_ENTITY_HOLOGRAMS.asBoolean();
public HologramTrait() { public HologramTrait() {
super("hologramtrait"); super("hologramtrait");
@ -99,9 +98,10 @@ public class HologramTrait extends Trait {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private NPC createHologram(String line, double heightOffset) { private NPC createHologram(String line, double heightOffset) {
NPC hologramNPC = null; NPC hologramNPC = null;
if (useTextDisplay) { if (useDisplayEntities) {
hologramNPC = registry.createNPC(EntityType.TEXT_DISPLAY, line); hologramNPC = registry.createNPC(EntityType.INTERACTION, line);
hologramNPC.addTrait(new ClickRedirectTrait(npc)); hologramNPC.addTrait(new ClickRedirectTrait(npc));
hologramNPC.data().set(NPC.Metadata.NAMEPLATE_VISIBLE, true);
} else { } else {
hologramNPC = registry.createNPC(EntityType.ARMOR_STAND, line); hologramNPC = registry.createNPC(EntityType.ARMOR_STAND, line);
hologramNPC.getOrAddTrait(ArmorStandTrait.class).setAsHelperEntityWithName(npc); hologramNPC.getOrAddTrait(ArmorStandTrait.class).setAsHelperEntityWithName(npc);
@ -116,9 +116,9 @@ public class HologramTrait extends Trait {
+ (direction == HologramDirection.BOTTOM_UP ? heightOffset : getMaxHeight() - heightOffset), + (direction == HologramDirection.BOTTOM_UP ? heightOffset : getMaxHeight() - heightOffset),
0)); 0));
if (useTextDisplay) { if (useDisplayEntities) {
((TextDisplay) hologramNPC.getEntity()).setBillboard(Billboard.CENTER); ((Interaction) hologramNPC.getEntity()).setInteractionWidth(0);
((TextDisplay) hologramNPC.getEntity()).setInterpolationDelay(0); NMS.updateMountedInteractionHeight(hologramNPC.getEntity(), npc.getEntity(), heightOffset);
} }
Matcher itemMatcher = ITEM_MATCHER.matcher(line); Matcher itemMatcher = ITEM_MATCHER.matcher(line);
@ -159,7 +159,7 @@ public class HologramTrait extends Trait {
} }
private double getEntityHeight() { private double getEntityHeight() {
return NMS.getHeight(npc.getEntity()) + (useTextDisplay ? 0.27 : 0); return NMS.getHeight(npc.getEntity());
} }
private double getHeight(int lineNumber) { private double getHeight(int lineNumber) {
@ -320,7 +320,7 @@ public class HologramTrait extends Trait {
} }
if (nameLine != null && nameLine.hologram.isSpawned()) { if (nameLine != null && nameLine.hologram.isSpawned()) {
if (updatePosition) { if (updatePosition && !useDisplayEntities) {
nameLine.hologram.teleport(currentLoc.clone().add(0, getEntityHeight(), 0), TeleportCause.PLUGIN); nameLine.hologram.teleport(currentLoc.clone().add(0, getEntityHeight(), 0), TeleportCause.PLUGIN);
} }
if (updateName) { if (updateName) {
@ -334,7 +334,7 @@ public class HologramTrait extends Trait {
if (hologramNPC == null || !hologramNPC.isSpawned()) if (hologramNPC == null || !hologramNPC.isSpawned())
continue; continue;
if (updatePosition) { if (updatePosition && !useDisplayEntities) {
Location tp = currentLoc.clone().add(0, lastEntityHeight Location tp = currentLoc.clone().add(0, lastEntityHeight
+ (direction == HologramDirection.BOTTOM_UP ? getHeight(i) : getMaxHeight() - getHeight(i)), 0); + (direction == HologramDirection.BOTTOM_UP ? getHeight(i) : getMaxHeight() - getHeight(i)), 0);
hologramNPC.teleport(tp, TeleportCause.PLUGIN); hologramNPC.teleport(tp, TeleportCause.PLUGIN);
@ -443,8 +443,8 @@ public class HologramTrait extends Trait {
this.customHologramSupplier = nameSupplier; this.customHologramSupplier = nameSupplier;
} }
public void setUseTextDisplay(boolean use) { public void setUseDisplayEntities(boolean use) {
this.useTextDisplay = use; this.useDisplayEntities = use;
reloadLineHolograms(); reloadLineHolograms();
} }

View File

@ -71,6 +71,9 @@ public class MountTrait extends Trait {
public void setMountedOn(UUID uuid) { public void setMountedOn(UUID uuid) {
this.uuid = uuid; this.uuid = uuid;
if (npc.isSpawned()) {
checkMounted();
}
} }
public void unmount() { public void unmount() {

View File

@ -270,6 +270,22 @@ public class LinearWaypointProvider implements EnumerableWaypointProvider {
this.markers = new EntityMarkers<Waypoint>(); this.markers = new EntityMarkers<Waypoint>();
} }
private void addWaypoint(Location at) {
Waypoint element = new Waypoint(at);
int idx = waypoints.size();
if (waypoints.indexOf(selectedWaypoint) != -1) {
idx = waypoints.indexOf(selectedWaypoint);
waypoints.add(idx, element);
} else {
waypoints.add(element);
}
if (showingMarkers) {
markers.createMarker(element, element.getLocation().clone());
}
Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_ADDED_WAYPOINT, formatLoc(at), waypoints.size());
}
@Override @Override
public void begin() { public void begin() {
Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_BEGIN); Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_BEGIN);
@ -369,6 +385,10 @@ public class LinearWaypointProvider implements EnumerableWaypointProvider {
Messaging.sendTr(event.getPlayer(), cycle ? Messages.LINEAR_WAYPOINT_EDITOR_CYCLE_SET Messaging.sendTr(event.getPlayer(), cycle ? Messages.LINEAR_WAYPOINT_EDITOR_CYCLE_SET
: Messages.LINEAR_WAYPOINT_EDITOR_CYCLE_UNSET); : Messages.LINEAR_WAYPOINT_EDITOR_CYCLE_UNSET);
}); });
} else if (message.equalsIgnoreCase("here")) {
event.setCancelled(true);
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
() -> addWaypoint(player.getLocation()));
} }
} }
@ -394,20 +414,7 @@ public class LinearWaypointProvider implements EnumerableWaypointProvider {
} }
} }
Waypoint element = new Waypoint(at); addWaypoint(at);
int idx = waypoints.size();
if (waypoints.indexOf(selectedWaypoint) != -1) {
idx = waypoints.indexOf(selectedWaypoint);
waypoints.add(idx, element);
} else {
waypoints.add(element);
}
if (showingMarkers) {
markers.createMarker(element, element.getLocation().clone());
}
Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_ADDED_WAYPOINT, formatLoc(at),
waypoints.size());
} else if (waypoints.size() > 0 && !event.getPlayer().isSneaking()) { } else if (waypoints.size() > 0 && !event.getPlayer().isSneaking()) {
event.setCancelled(true); event.setCancelled(true);

View File

@ -868,6 +868,10 @@ public class NMS {
BRIDGE.updateInventoryTitle(player, view, newTitle); BRIDGE.updateInventoryTitle(player, view, newTitle);
} }
public static void updateMountedInteractionHeight(Entity entity, Entity mount, double height) {
BRIDGE.updateMountedInteractionHeight(entity, mount, height);
}
public static void updateNavigationWorld(org.bukkit.entity.Entity entity, org.bukkit.World world) { public static void updateNavigationWorld(org.bukkit.entity.Entity entity, org.bukkit.World world) {
BRIDGE.updateNavigationWorld(entity, world); BRIDGE.updateNavigationWorld(entity, world);
} }
@ -879,7 +883,6 @@ public class NMS {
private static Method ADD_OPENS; private static Method ADD_OPENS;
private static NMSBridge BRIDGE; private static NMSBridge BRIDGE;
private static Method GET_MODULE; private static Method GET_MODULE;
private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static Field MODIFIERS_FIELD; private static Field MODIFIERS_FIELD;
@ -894,6 +897,7 @@ public class NMS {
private static MethodHandle UNSAFE_PUT_LONG; private static MethodHandle UNSAFE_PUT_LONG;
private static MethodHandle UNSAFE_PUT_OBJECT; private static MethodHandle UNSAFE_PUT_OBJECT;
private static MethodHandle UNSAFE_STATIC_FIELD_OFFSET; private static MethodHandle UNSAFE_STATIC_FIELD_OFFSET;
static { static {
try { try {
Class.forName("com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent"); Class.forName("com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent");

View File

@ -260,7 +260,10 @@ public interface NMSBridge {
public void updateInventoryTitle(Player player, InventoryView view, String newTitle); public void updateInventoryTitle(Player player, InventoryView view, String newTitle);
public default void updateMountedInteractionHeight(Entity entity, Entity mount, double height) {
}
public void updateNavigationWorld(Entity entity, World world); public void updateNavigationWorld(Entity entity, World world);
public void updatePathfindingRange(NPC npc, float pathfindingRange); public void updatePathfindingRange(NPC npc, float pathfindingRange);;
} }

View File

@ -280,10 +280,12 @@ import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket; import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
import net.minecraft.network.protocol.game.VecDeltaCodec; import net.minecraft.network.protocol.game.VecDeltaCodec;
import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerAdvancements; import net.minecraft.server.PlayerAdvancements;
@ -304,6 +306,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Entity.RemovalReason; import net.minecraft.world.entity.Entity.RemovalReason;
import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Interaction;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.MoverType;
@ -1795,6 +1798,22 @@ public class NMSImpl implements NMSBridge {
player.updateInventory(); player.updateInventory();
} }
@Override
public void updateMountedInteractionHeight(org.bukkit.entity.Entity entity, org.bukkit.entity.Entity mount,
double offset) {
Interaction handle = (Interaction) getHandle(entity);
offset += -0.5 + getHandle(mount).getPassengersRidingOffset();
((org.bukkit.entity.Interaction) entity).setInteractionHeight((float) offset);
mount.addPassenger(entity);
handle.setPose(Pose.SNIFFING);
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), () -> {
if (!entity.isValid())
return;
sendPacketNearby(null, entity.getLocation(), new ClientboundSetEntityDataPacket(handle.getId(),
List.of(new SynchedEntityData.DataItem<>(INTERACTION_HEIGHT, 999999f).value())));
});
}
@Override @Override
public void updateNavigationWorld(org.bukkit.entity.Entity entity, World world) { public void updateNavigationWorld(org.bukkit.entity.Entity entity, World world) {
if (NAVIGATION_WORLD_FIELD == null) if (NAVIGATION_WORLD_FIELD == null)
@ -2547,6 +2566,7 @@ public class NMSImpl implements NMSBridge {
private static final MethodHandle HEAD_HEIGHT = NMS.getSetter(Entity.class, "bf"); private static final MethodHandle HEAD_HEIGHT = NMS.getSetter(Entity.class, "bf");
private static final MethodHandle HEAD_HEIGHT_METHOD = NMS.getFirstMethodHandle(Entity.class, true, Pose.class, private static final MethodHandle HEAD_HEIGHT_METHOD = NMS.getFirstMethodHandle(Entity.class, true, Pose.class,
EntityDimensions.class); EntityDimensions.class);
private static EntityDataAccessor<Float> INTERACTION_HEIGHT = null;
private static final MethodHandle JUMP_FIELD = NMS.getGetter(LivingEntity.class, "bi"); private static final MethodHandle JUMP_FIELD = NMS.getGetter(LivingEntity.class, "bi");
private static final MethodHandle LOOK_CONTROL_SETTER = NMS.getFirstSetter(Mob.class, LookControl.class); private static final MethodHandle LOOK_CONTROL_SETTER = NMS.getFirstSetter(Mob.class, LookControl.class);
private static final MethodHandle MAKE_REQUEST = NMS.getMethodHandle(YggdrasilAuthenticationService.class, private static final MethodHandle MAKE_REQUEST = NMS.getMethodHandle(YggdrasilAuthenticationService.class,
@ -2602,5 +2622,10 @@ public class NMSImpl implements NMSBridge {
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
try {
INTERACTION_HEIGHT = (EntityDataAccessor<Float>) NMS.getGetter(Interaction.class, "d").invoke();
} catch (Throwable e) {
e.printStackTrace();
}
} }
} }

View File

@ -279,10 +279,12 @@ import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket; import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
import net.minecraft.network.protocol.game.VecDeltaCodec; import net.minecraft.network.protocol.game.VecDeltaCodec;
import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerAdvancements; import net.minecraft.server.PlayerAdvancements;
@ -303,6 +305,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Entity.RemovalReason; import net.minecraft.world.entity.Entity.RemovalReason;
import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Interaction;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.MoverType;
@ -395,7 +398,7 @@ public class NMSImpl implements NMSBridge {
e.printStackTrace(); e.printStackTrace();
} }
return success; return success;
} };
@Override @Override
public void addOrRemoveFromPlayerList(org.bukkit.entity.Entity entity, boolean remove) { public void addOrRemoveFromPlayerList(org.bukkit.entity.Entity entity, boolean remove) {
@ -1795,6 +1798,22 @@ public class NMSImpl implements NMSBridge {
player.updateInventory(); player.updateInventory();
} }
@Override
public void updateMountedInteractionHeight(org.bukkit.entity.Entity entity, org.bukkit.entity.Entity mount,
double offset) {
Interaction handle = (Interaction) getHandle(entity);
offset += -0.5 + getHandle(mount).getPassengersRidingOffset();
((org.bukkit.entity.Interaction) entity).setInteractionHeight((float) offset);
mount.addPassenger(entity);
handle.setPose(Pose.SNIFFING);
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), () -> {
if (!entity.isValid())
return;
sendPacketNearby(null, entity.getLocation(), new ClientboundSetEntityDataPacket(handle.getId(),
List.of(new SynchedEntityData.DataItem<>(INTERACTION_HEIGHT, 999999f).value())));
});
}
@Override @Override
public void updateNavigationWorld(org.bukkit.entity.Entity entity, World world) { public void updateNavigationWorld(org.bukkit.entity.Entity entity, World world) {
if (NAVIGATION_WORLD_FIELD == null) if (NAVIGATION_WORLD_FIELD == null)
@ -2509,6 +2528,7 @@ public class NMSImpl implements NMSBridge {
private static final MethodHandle ADVANCEMENTS_PLAYER_SETTER = NMS.getFirstFinalSetter(ServerPlayer.class, private static final MethodHandle ADVANCEMENTS_PLAYER_SETTER = NMS.getFirstFinalSetter(ServerPlayer.class,
PlayerAdvancements.class); PlayerAdvancements.class);
private static final MethodHandle ATTRIBUTE_PROVIDER_MAP = NMS.getFirstGetter(AttributeSupplier.class, Map.class); 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, private static final MethodHandle ATTRIBUTE_PROVIDER_MAP_SETTER = NMS.getFirstFinalSetter(AttributeSupplier.class,
Map.class); Map.class);
@ -2548,6 +2568,7 @@ public class NMSImpl implements NMSBridge {
private static final MethodHandle HEAD_HEIGHT = NMS.getSetter(Entity.class, "bi"); private static final MethodHandle HEAD_HEIGHT = NMS.getSetter(Entity.class, "bi");
private static final MethodHandle HEAD_HEIGHT_METHOD = NMS.getFirstMethodHandle(Entity.class, true, Pose.class, private static final MethodHandle HEAD_HEIGHT_METHOD = NMS.getFirstMethodHandle(Entity.class, true, Pose.class,
EntityDimensions.class); EntityDimensions.class);
private static EntityDataAccessor<Float> INTERACTION_HEIGHT = null;
private static final MethodHandle JUMP_FIELD = NMS.getGetter(LivingEntity.class, "bk"); private static final MethodHandle JUMP_FIELD = NMS.getGetter(LivingEntity.class, "bk");
private static final MethodHandle LOOK_CONTROL_SETTER = NMS.getFirstSetter(Mob.class, LookControl.class); private static final MethodHandle LOOK_CONTROL_SETTER = NMS.getFirstSetter(Mob.class, LookControl.class);
private static final MethodHandle MAKE_REQUEST = NMS.getMethodHandle(YggdrasilAuthenticationService.class, private static final MethodHandle MAKE_REQUEST = NMS.getMethodHandle(YggdrasilAuthenticationService.class,
@ -2603,5 +2624,10 @@ public class NMSImpl implements NMSBridge {
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
try {
INTERACTION_HEIGHT = (EntityDataAccessor<Float>) NMS.getGetter(Interaction.class, "d").invoke();
} catch (Throwable e) {
e.printStackTrace();
}
} }
} }