diff --git a/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch b/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch deleted file mode 100644 index 0ec2d97..0000000 --- a/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch +++ /dev/null @@ -1,1372 +0,0 @@ -Index: src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine;\r\n\r\nimport com.github.retrooper.packetevents.PacketEvents;\r\nimport com.github.retrooper.packetevents.event.PacketListenerPriority;\r\nimport dev.jorel.commandapi.CommandAPI;\r\nimport dev.jorel.commandapi.CommandAPIBukkitConfig;\r\nimport io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;\r\nimport org.bstats.bukkit.Metrics;\r\nimport org.bukkit.Bukkit;\r\nimport org.bukkit.plugin.java.JavaPlugin;\r\nimport re.imc.geysermodelengine.listener.ModelListener;\r\nimport re.imc.geysermodelengine.listener.MountPacketListener;\r\nimport re.imc.geysermodelengine.managers.ConfigManager;\r\nimport re.imc.geysermodelengine.managers.commands.CommandManager;\r\nimport re.imc.geysermodelengine.managers.model.EntityTaskManager;\r\nimport re.imc.geysermodelengine.managers.model.ModelManager;\r\nimport re.imc.geysermodelengine.runnables.BedrockMountControlRunnable;\r\nimport re.imc.geysermodelengine.runnables.UpdateTaskRunnable;\r\n\r\nimport java.util.concurrent.*;\r\n\r\npublic class GeyserModelEngine extends JavaPlugin {\r\n\r\n private ConfigManager configManager;\r\n\r\n private CommandManager commandManager;\r\n\r\n private ModelManager modelManager;\r\n private EntityTaskManager entityTaskManager;\r\n\r\n private ScheduledExecutorService schedulerPool;\r\n\r\n @Override\r\n public void onLoad() {\r\n PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));\r\n PacketEvents.getAPI().load();\r\n\r\n CommandAPI.onLoad(new CommandAPIBukkitConfig(this));\r\n }\r\n\r\n @Override\r\n public void onEnable() {\r\n loadHooks();\r\n loadManagers();\r\n loadRunnables();\r\n\r\n loadBStats();\r\n\r\n PacketEvents.getAPI().getEventManager().registerListener(new MountPacketListener(this), PacketListenerPriority.NORMAL);\r\n\r\n Bukkit.getPluginManager().registerEvents(new ModelListener(this), this);\r\n }\r\n\r\n @Override\r\n public void onDisable() {\r\n PacketEvents.getAPI().terminate();\r\n\r\n this.modelManager.removeEntities();\r\n\r\n CommandAPI.onDisable();\r\n }\r\n\r\n private void loadHooks() {\r\n PacketEvents.getAPI().init();\r\n CommandAPI.onEnable();\r\n }\r\n\r\n private void loadBStats() {\r\n if (configManager.getConfig().getBoolean(\"bstats\", true)) new Metrics(this, 26981);\r\n }\r\n\r\n private void loadManagers() {\r\n this.configManager = new ConfigManager(this);\r\n\r\n this.commandManager = new CommandManager(this);\r\n\r\n this.modelManager = new ModelManager(this);\r\n this.entityTaskManager = new EntityTaskManager(this);\r\n }\r\n\r\n private void loadRunnables() {\r\n this.schedulerPool = Executors.newScheduledThreadPool(configManager.getConfig().getInt(\"thread-pool-size\", 4));\r\n\r\n Bukkit.getAsyncScheduler().runAtFixedRate(this, new UpdateTaskRunnable(this), 10, configManager.getConfig().getLong(\"entity-position-update-period\", 35), TimeUnit.MILLISECONDS);\r\n Bukkit.getAsyncScheduler().runAtFixedRate(this, new BedrockMountControlRunnable(this), 1, 1, TimeUnit.MILLISECONDS);\r\n }\r\n\r\n public ConfigManager getConfigManager() {\r\n return configManager;\r\n }\r\n\r\n public CommandManager getCommandManager() {\r\n return commandManager;\r\n }\r\n\r\n public ModelManager getModelManager() {\r\n return modelManager;\r\n }\r\n\r\n public EntityTaskManager getEntityTaskManager() {\r\n return entityTaskManager;\r\n }\r\n\r\n public ScheduledExecutorService getSchedulerPool() {\r\n return schedulerPool;\r\n }\r\n}\r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java ---- a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java (date 1757196497524) -@@ -55,7 +55,7 @@ - public void onDisable() { - PacketEvents.getAPI().terminate(); - -- this.modelManager.removeEntities(); -+ this.modelManager.getModelHandler().removeEntities(this); - - CommandAPI.onDisable(); - } -Index: src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine.runnables;\r\n\r\nimport com.google.common.cache.Cache;\r\nimport com.google.common.cache.CacheBuilder;\r\nimport com.ticxo.modelengine.api.animation.BlueprintAnimation;\r\nimport com.ticxo.modelengine.api.animation.handler.AnimationHandler;\r\nimport com.ticxo.modelengine.api.generator.blueprint.BlueprintBone;\r\nimport com.ticxo.modelengine.api.model.ActiveModel;\r\nimport com.ticxo.modelengine.api.model.ModeledEntity;\r\nimport com.ticxo.modelengine.api.model.bone.ModelBone;\r\nimport me.zimzaza4.geyserutils.spigot.api.EntityUtils;\r\nimport org.bukkit.entity.Player;\r\nimport re.imc.geysermodelengine.GeyserModelEngine;\r\nimport re.imc.geysermodelengine.managers.model.data.ModelEntityData;\r\nimport re.imc.geysermodelengine.packet.entity.PacketEntity;\r\nimport re.imc.geysermodelengine.util.BooleanPacker;\r\n\r\nimport java.awt.*;\r\nimport java.util.*;\r\nimport java.util.List;\r\nimport java.util.concurrent.ConcurrentHashMap;\r\nimport java.util.concurrent.ScheduledFuture;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class EntityTaskRunnable {\r\n\r\n private final GeyserModelEngine plugin;\r\n\r\n private final ModelEntityData model;\r\n\r\n private int tick = 0;\r\n private int syncTick = 0;\r\n\r\n private float lastScale = -1.0f;\r\n private Color lastColor = null;\r\n\r\n private boolean removed = false;\r\n\r\n private final ConcurrentHashMap lastIntSet = new ConcurrentHashMap<>();\r\n private final Cache lastPlayedAnim = CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MILLISECONDS).build();\r\n\r\n private final BooleanPacker booleanPacker = new BooleanPacker();\r\n\r\n private final ScheduledFuture scheduledFuture;\r\n\r\n public EntityTaskRunnable(GeyserModelEngine plugin, ModelEntityData model) {\r\n this.plugin = plugin;\r\n\r\n this.model = model;\r\n\r\n plugin.getEntityTaskManager().sendHitBoxToAll(model);\r\n\r\n scheduledFuture = plugin.getSchedulerPool().scheduleAtFixedRate(this::runAsync, 0, 20, TimeUnit.MILLISECONDS);\r\n }\r\n\r\n public void runAsync() {\r\n plugin.getEntityTaskManager().checkViewers(model, model.getViewers());\r\n\r\n PacketEntity entity = model.getEntity();\r\n if (entity.isDead()) return;\r\n\r\n model.teleportToModel();\r\n\r\n Set viewers = model.getViewers();\r\n ActiveModel activeModel = model.getActiveModel();\r\n ModeledEntity modeledEntity = model.getModeledEntity();\r\n\r\n if (activeModel.isDestroyed() || activeModel.isRemoved()) {\r\n removed = true;\r\n entity.remove();\r\n\r\n plugin.getModelManager().getEntitiesCache().remove(modeledEntity.getBase().getEntityId());\r\n plugin.getModelManager().getModelEntitiesCache().remove(entity.getEntityId());\r\n cancel();\r\n return;\r\n }\r\n\r\n if (tick % 5 == 0) {\r\n if (tick % 40 == 0) {\r\n for (Player viewer : Set.copyOf(viewers)) {\r\n if (!plugin.getEntityTaskManager().canSee(viewer, model.getEntity())) {\r\n viewers.remove(viewer);\r\n }\r\n }\r\n }\r\n }\r\n\r\n tick ++;\r\n if (tick > 400) {\r\n tick = 0;\r\n plugin.getEntityTaskManager().sendHitBoxToAll(model);\r\n }\r\n\r\n if (viewers.isEmpty()) return;\r\n\r\n plugin.getEntityTaskManager().sendScale(model, viewers, lastScale, false);\r\n plugin.getEntityTaskManager().sendColor(model, viewers, lastColor, false);\r\n }\r\n\r\n public void cancel() {\r\n scheduledFuture.cancel(true);\r\n }\r\n\r\n public void sendEntityData(ModelEntityData model, Player player, int delay) {\r\n EntityUtils.setCustomEntity(player, model.getEntity().getEntityId(), plugin.getConfigManager().getConfig().getString(\"namespace\") + \":\" + model.getActiveModel().getBlueprint().getName().toLowerCase());\r\n\r\n plugin.getSchedulerPool().schedule(() -> {\r\n model.getEntity().sendSpawnPacket(Collections.singletonList(player));\r\n\r\n plugin.getSchedulerPool().schedule(() -> {\r\n plugin.getEntityTaskManager().sendHitBox(model, player);\r\n plugin.getEntityTaskManager().sendScale(model, Collections.singleton(player), lastScale, true);\r\n plugin.getEntityTaskManager().sendColor(model, Collections.singleton(player), lastColor, true);\r\n\r\n updateEntityProperties(model, Collections.singleton(player), true);\r\n }, 500, TimeUnit.MILLISECONDS);\r\n }, delay * 50L, TimeUnit.MILLISECONDS);\r\n }\r\n\r\n public void updateEntityProperties(ModelEntityData model, Collection players, boolean firstSend, String... forceAnims) {\r\n int entity = model.getEntity().getEntityId();\r\n Set forceAnimSet = Set.of(forceAnims);\r\n\r\n Map boneUpdates = new HashMap<>();\r\n Map animUpdates = new HashMap<>();\r\n Set anims = new HashSet<>();\r\n\r\n model.getActiveModel().getBlueprint().getBones().forEach((s, bone) -> processBone(model, bone, boneUpdates));\r\n\r\n AnimationHandler handler = model.getActiveModel().getAnimationHandler();\r\n Set priority = model.getActiveModel().getBlueprint().getAnimationDescendingPriority();\r\n for (String animId : priority) {\r\n if (handler.isPlayingAnimation(animId)) {\r\n BlueprintAnimation anim = model.getActiveModel().getBlueprint().getAnimations().get(animId);\r\n\r\n anims.add(animId);\r\n if (anim.isOverride() && anim.getLoopMode() == BlueprintAnimation.LoopMode.ONCE) {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n for (String id : priority) {\r\n if (anims.contains(id)) {\r\n animUpdates.put(id, true);\r\n } else {\r\n animUpdates.put(id, false);\r\n }\r\n }\r\n\r\n Set lastPlayed = new HashSet<>(lastPlayedAnim.asMap().keySet());\r\n\r\n for (Map.Entry anim : animUpdates.entrySet()) {\r\n if (anim.getValue()) {\r\n lastPlayedAnim.put(anim.getKey(), true);\r\n }\r\n }\r\n\r\n for (String anim : lastPlayed) animUpdates.put(anim, true);\r\n\r\n if (boneUpdates.isEmpty() && animUpdates.isEmpty()) return;\r\n\r\n Map intUpdates = new HashMap<>();\r\n int i = 0;\r\n\r\n for (Integer integer : booleanPacker.mapBooleansToInts(boneUpdates)) {\r\n intUpdates.put(plugin.getConfigManager().getConfig().getString(\"namespace\") + \":bone\" + i, integer);\r\n i++;\r\n }\r\n\r\n i = 0;\r\n for (Integer integer : booleanPacker.mapBooleansToInts(animUpdates)) {\r\n intUpdates.put(plugin.getConfigManager().getConfig().getString(\"namespace\") + \":anim\" + i, integer);\r\n i++;\r\n }\r\n\r\n if (!firstSend) {\r\n if (intUpdates.equals(lastIntSet)) {\r\n return;\r\n } else {\r\n lastIntSet.clear();\r\n lastIntSet.putAll(intUpdates);\r\n }\r\n }\r\n\r\n if (plugin.getConfigManager().getConfig().getBoolean(\"debug\")) plugin.getLogger().info(animUpdates.toString());\r\n\r\n List list = new ArrayList<>(boneUpdates.keySet());\r\n Collections.sort(list);\r\n\r\n for (Player player : players) {\r\n EntityUtils.sendIntProperties(player, entity, intUpdates);\r\n }\r\n }\r\n\r\n private void processBone(ModelEntityData model, BlueprintBone bone, Map map) {\r\n String name = plugin.getEntityTaskManager().unstripName(bone).toLowerCase();\r\n if (name.equals(\"hitbox\") ||\r\n name.equals(\"shadow\") ||\r\n name.equals(\"mount\") ||\r\n name.startsWith(\"p_\") ||\r\n name.startsWith(\"b_\") ||\r\n name.startsWith(\"ob_\")) {\r\n return;\r\n }\r\n\r\n for (BlueprintBone blueprintBone : bone.getChildren().values()) processBone(model, blueprintBone, map);\r\n\r\n ModelBone activeBone = model.getActiveModel().getBones().get(bone.getName());\r\n\r\n boolean visible = false;\r\n if (activeBone != null) visible = activeBone.isVisible();\r\n\r\n map.put(name, visible);\r\n }\r\n\r\n public void setTick(int tick) {\r\n this.tick = tick;\r\n }\r\n\r\n public void setSyncTick(int syncTick) {\r\n this.syncTick = syncTick;\r\n }\r\n\r\n public void setRemoved(boolean removed) {\r\n this.removed = removed;\r\n }\r\n\r\n public void setLastScale(float lastScale) {\r\n this.lastScale = lastScale;\r\n }\r\n\r\n public int getTick() {\r\n return tick;\r\n }\r\n\r\n public int getSyncTick() {\r\n return syncTick;\r\n }\r\n\r\n public void setLastColor(Color lastColor) {\r\n this.lastColor = lastColor;\r\n }\r\n\r\n public float getLastScale() {\r\n return lastScale;\r\n }\r\n\r\n public Color getLastColor() {\r\n return lastColor;\r\n }\r\n\r\n public boolean isRemoved() {\r\n return removed;\r\n }\r\n\r\n public ConcurrentHashMap getLastIntSet() {\r\n return lastIntSet;\r\n }\r\n\r\n public Cache getLastPlayedAnim() {\r\n return lastPlayedAnim;\r\n }\r\n\r\n public ScheduledFuture getScheduledFuture() {\r\n return scheduledFuture;\r\n }\r\n}\r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java b/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java ---- a/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java (date 1757189940025) -@@ -11,7 +11,7 @@ - import me.zimzaza4.geyserutils.spigot.api.EntityUtils; - import org.bukkit.entity.Player; - import re.imc.geysermodelengine.GeyserModelEngine; --import re.imc.geysermodelengine.managers.model.data.ModelEntityData; -+import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; - import re.imc.geysermodelengine.packet.entity.PacketEntity; - import re.imc.geysermodelengine.util.BooleanPacker; - -@@ -26,7 +26,7 @@ - - private final GeyserModelEngine plugin; - -- private final ModelEntityData model; -+ private final ModelEngineEntityData model; - - private int tick = 0; - private int syncTick = 0; -@@ -39,11 +39,9 @@ - private final ConcurrentHashMap lastIntSet = new ConcurrentHashMap<>(); - private final Cache lastPlayedAnim = CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MILLISECONDS).build(); - -- private final BooleanPacker booleanPacker = new BooleanPacker(); -- - private final ScheduledFuture scheduledFuture; - -- public EntityTaskRunnable(GeyserModelEngine plugin, ModelEntityData model) { -+ public EntityTaskRunnable(GeyserModelEngine plugin, ModelEngineEntityData model) { - this.plugin = plugin; - - this.model = model; -@@ -70,7 +68,8 @@ - entity.remove(); - - plugin.getModelManager().getEntitiesCache().remove(modeledEntity.getBase().getEntityId()); -- plugin.getModelManager().getModelEntitiesCache().remove(entity.getEntityId()); -+ plugin.getModelManager().getModelEntitiesCache().remove(modeledEntity.getBase().getEntityId()); -+ - cancel(); - return; - } -@@ -93,31 +92,32 @@ - - if (viewers.isEmpty()) return; - -- plugin.getEntityTaskManager().sendScale(model, viewers, lastScale, false); -- plugin.getEntityTaskManager().sendColor(model, viewers, lastColor, false); -+ plugin.getEntityTaskManager().getPropertyHandler().sendScale(model, viewers, lastScale, false); -+ plugin.getEntityTaskManager().getPropertyHandler().sendColor(model, viewers, lastColor, false); - } - - public void cancel() { - scheduledFuture.cancel(true); - } - -- public void sendEntityData(ModelEntityData model, Player player, int delay) { -+ public void sendEntityData(ModelEngineEntityData model, Player player, int delay) { - EntityUtils.setCustomEntity(player, model.getEntity().getEntityId(), plugin.getConfigManager().getConfig().getString("namespace") + ":" + model.getActiveModel().getBlueprint().getName().toLowerCase()); - - plugin.getSchedulerPool().schedule(() -> { - model.getEntity().sendSpawnPacket(Collections.singletonList(player)); - - plugin.getSchedulerPool().schedule(() -> { -- plugin.getEntityTaskManager().sendHitBox(model, player); -- plugin.getEntityTaskManager().sendScale(model, Collections.singleton(player), lastScale, true); -- plugin.getEntityTaskManager().sendColor(model, Collections.singleton(player), lastColor, true); -+ plugin.getEntityTaskManager().getPropertyHandler().sendHitBox(model, player); -+ -+ plugin.getEntityTaskManager().getPropertyHandler().sendScale(model, Collections.singleton(player), lastScale, true); -+ plugin.getEntityTaskManager().getPropertyHandler().sendColor(model, Collections.singleton(player), lastColor, true); - - updateEntityProperties(model, Collections.singleton(player), true); - }, 500, TimeUnit.MILLISECONDS); - }, delay * 50L, TimeUnit.MILLISECONDS); - } - -- public void updateEntityProperties(ModelEntityData model, Collection players, boolean firstSend, String... forceAnims) { -+ public void updateEntityProperties(ModelEngineEntityData model, Collection players, boolean firstSend, String... forceAnims) { - int entity = model.getEntity().getEntityId(); - Set forceAnimSet = Set.of(forceAnims); - -@@ -163,13 +163,13 @@ - Map intUpdates = new HashMap<>(); - int i = 0; - -- for (Integer integer : booleanPacker.mapBooleansToInts(boneUpdates)) { -+ for (Integer integer : BooleanPacker.mapBooleansToInts(boneUpdates)) { - intUpdates.put(plugin.getConfigManager().getConfig().getString("namespace") + ":bone" + i, integer); - i++; - } - - i = 0; -- for (Integer integer : booleanPacker.mapBooleansToInts(animUpdates)) { -+ for (Integer integer : BooleanPacker.mapBooleansToInts(animUpdates)) { - intUpdates.put(plugin.getConfigManager().getConfig().getString("namespace") + ":anim" + i, integer); - i++; - } -@@ -193,7 +193,7 @@ - } - } - -- private void processBone(ModelEntityData model, BlueprintBone bone, Map map) { -+ private void processBone(ModelEngineEntityData model, BlueprintBone bone, Map map) { - String name = plugin.getEntityTaskManager().unstripName(bone).toLowerCase(); - if (name.equals("hitbox") || - name.equals("shadow") || -Index: src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine.managers.model;\r\n\r\nimport com.ticxo.modelengine.api.animation.BlueprintAnimation;\r\nimport com.ticxo.modelengine.api.generator.blueprint.BlueprintBone;\r\nimport com.ticxo.modelengine.api.model.ActiveModel;\r\nimport com.ticxo.modelengine.api.model.render.DisplayRenderer;\r\nimport me.zimzaza4.geyserutils.spigot.api.EntityUtils;\r\nimport org.bukkit.Bukkit;\r\nimport org.bukkit.Location;\r\nimport org.bukkit.entity.Player;\r\nimport org.geysermc.floodgate.api.FloodgateApi;\r\nimport org.joml.Vector3fc;\r\nimport re.imc.geysermodelengine.GeyserModelEngine;\r\nimport re.imc.geysermodelengine.managers.model.data.ModelEntityData;\r\nimport re.imc.geysermodelengine.packet.entity.PacketEntity;\r\nimport re.imc.geysermodelengine.runnables.EntityTaskRunnable;\r\n\r\nimport java.awt.*;\r\nimport java.lang.reflect.Method;\r\nimport java.util.*;\r\n\r\npublic class EntityTaskManager {\r\n\r\n private final GeyserModelEngine plugin;\r\n\r\n private final Method scaleMethod;\r\n\r\n public EntityTaskManager(GeyserModelEngine plugin) {\r\n this.plugin = plugin;\r\n\r\n try {\r\n this.scaleMethod = ActiveModel.class.getMethod(\"getScale\");\r\n } catch (NoSuchMethodException err) {\r\n throw new RuntimeException(err);\r\n }\r\n }\r\n\r\n public String unstripName(BlueprintBone bone) {\r\n String name = bone.getName();\r\n if (bone.getBehaviors().get(\"head\") != null) {\r\n if (!bone.getBehaviors().get(\"head\").isEmpty()) return \"hi_\" + name;\r\n return \"h_\" + name;\r\n }\r\n\r\n return name;\r\n }\r\n\r\n public void sendScale(ModelEntityData model, Collection players, float lastScale, boolean firstSend) {\r\n try {\r\n if (players.isEmpty()) return;\r\n\r\n Vector3fc scale = (Vector3fc) scaleMethod.invoke(model.getActiveModel());\r\n\r\n float average = (scale.x() + scale.y() + scale.z()) / 3;\r\n\r\n if (!firstSend) {\r\n if (average == lastScale) return;\r\n }\r\n\r\n for (Player player : players) {\r\n EntityUtils.sendCustomScale(player, model.getEntity().getEntityId(), average);\r\n }\r\n } catch (Throwable ignored) {}\r\n }\r\n\r\n public void sendColor(ModelEntityData model, Collection players, Color lastColor, boolean firstSend) {\r\n if (players.isEmpty()) return;\r\n\r\n Color color = new Color(model.getActiveModel().getDefaultTint().asARGB());\r\n if (model.getActiveModel().isMarkedHurt()) color = new Color(model.getActiveModel().getDamageTint().asARGB());\r\n\r\n if (firstSend) {\r\n if (color.equals(lastColor)) return;\r\n }\r\n\r\n for (Player player : players) {\r\n EntityUtils.sendCustomColor(player, model.getEntity().getEntityId(), color);\r\n }\r\n }\r\n\r\n public void checkViewers(ModelEntityData model, Set viewers) {\r\n for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {\r\n if (!FloodgateApi.getInstance().isFloodgatePlayer(onlinePlayer.getUniqueId())) continue;\r\n\r\n if (canSee(onlinePlayer, model.getEntity())) {\r\n if (!viewers.contains(onlinePlayer)) {\r\n sendSpawnPacket(model, onlinePlayer);\r\n viewers.add(onlinePlayer);\r\n }\r\n } else {\r\n if (viewers.contains(onlinePlayer)) {\r\n model.getEntity().sendEntityDestroyPacket(Collections.singletonList(onlinePlayer));\r\n viewers.remove(onlinePlayer);\r\n }\r\n }\r\n }\r\n }\r\n\r\n private void sendSpawnPacket(ModelEntityData model, Player onlinePlayer) {\r\n EntityTaskRunnable task = model.getEntityTask();\r\n boolean firstJoined = !plugin.getModelManager().getPlayerJoinedCache().contains(onlinePlayer.getUniqueId());\r\n\r\n if (firstJoined) {\r\n task.sendEntityData(model, onlinePlayer, plugin.getConfigManager().getConfig().getInt(\"join-send-delay\") / 50);\r\n } else {\r\n task.sendEntityData(model, onlinePlayer, 5);\r\n }\r\n }\r\n\r\n public boolean canSee(Player player, PacketEntity entity) {\r\n if (!player.isOnline()) return false;\r\n if (!plugin.getModelManager().getPlayerJoinedCache().contains(player.getUniqueId())) return false;\r\n\r\n Location playerLocation = player.getLocation().clone();\r\n Location entityLocation = entity.getLocation().clone();\r\n playerLocation.setY(0);\r\n entityLocation.setY(0);\r\n\r\n if (playerLocation.getWorld() != entityLocation.getWorld()) return false;\r\n if (playerLocation.distanceSquared(entityLocation) > player.getSendViewDistance() * player.getSendViewDistance() * 48) return false;\r\n\r\n return true;\r\n }\r\n\r\n public void sendHitBoxToAll(ModelEntityData model) {\r\n for (Player viewer : model.getViewers()) {\r\n EntityUtils.sendCustomHitBox(viewer, model.getEntity().getEntityId(), 0.01f, 0.01f);\r\n }\r\n }\r\n\r\n public void sendHitBox(ModelEntityData model, Player viewer) {\r\n float w = 0;\r\n\r\n if (model.getActiveModel().isShadowVisible()) {\r\n if (model.getActiveModel().getModelRenderer() instanceof DisplayRenderer displayRenderer) {\r\n // w = displayRenderer.getHitbox().getShadowRadius().get();\r\n }\r\n }\r\n\r\n EntityUtils.sendCustomHitBox(viewer, model.getEntity().getEntityId(), 0.02f, w);\r\n }\r\n\r\n public boolean hasAnimation(ModelEntityData model, String animation) {\r\n ActiveModel activeModel = model.getActiveModel();\r\n BlueprintAnimation animationProperty = activeModel.getBlueprint().getAnimations().get(animation);\r\n return !(animationProperty == null);\r\n }\r\n\r\n public Method getScaleMethod() {\r\n return scaleMethod;\r\n }\r\n}\r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java b/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java ---- a/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java (date 1757189954000) -@@ -9,29 +9,35 @@ - import org.bukkit.Location; - import org.bukkit.entity.Player; - import org.geysermc.floodgate.api.FloodgateApi; --import org.joml.Vector3fc; - import re.imc.geysermodelengine.GeyserModelEngine; --import re.imc.geysermodelengine.managers.model.data.ModelEntityData; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.propertyhandler.BetterModelPropertyHandler; -+import re.imc.geysermodelengine.managers.model.propertyhandler.ModelEnginePropertyHandler; -+import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; -+import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; - import re.imc.geysermodelengine.packet.entity.PacketEntity; - import re.imc.geysermodelengine.runnables.EntityTaskRunnable; - --import java.awt.*; --import java.lang.reflect.Method; - import java.util.*; - - public class EntityTaskManager { - - private final GeyserModelEngine plugin; - -- private final Method scaleMethod; -+ private PropertyHandler propertyHandler; - - public EntityTaskManager(GeyserModelEngine plugin) { - this.plugin = plugin; - -- try { -- this.scaleMethod = ActiveModel.class.getMethod("getScale"); -- } catch (NoSuchMethodException err) { -- throw new RuntimeException(err); -+ if (Bukkit.getPluginManager().getPlugin("ModelEngine") != null) { -+ this.propertyHandler = new ModelEnginePropertyHandler(); -+ plugin.getLogger().info("Using ModelEngine property handler!"); -+ } else if (Bukkit.getPluginManager().getPlugin("BetterModel") != null) { -+ this.propertyHandler = new BetterModelPropertyHandler(); -+ plugin.getLogger().info("Using BetterModel property handler!"); -+ } else { -+ plugin.getLogger().severe("No supported model engine found!"); -+ plugin.getServer().getPluginManager().disablePlugin(plugin); - } - } - -@@ -45,40 +51,7 @@ - return name; - } - -- public void sendScale(ModelEntityData model, Collection players, float lastScale, boolean firstSend) { -- try { -- if (players.isEmpty()) return; -- -- Vector3fc scale = (Vector3fc) scaleMethod.invoke(model.getActiveModel()); -- -- float average = (scale.x() + scale.y() + scale.z()) / 3; -- -- if (!firstSend) { -- if (average == lastScale) return; -- } -- -- for (Player player : players) { -- EntityUtils.sendCustomScale(player, model.getEntity().getEntityId(), average); -- } -- } catch (Throwable ignored) {} -- } -- -- public void sendColor(ModelEntityData model, Collection players, Color lastColor, boolean firstSend) { -- if (players.isEmpty()) return; -- -- Color color = new Color(model.getActiveModel().getDefaultTint().asARGB()); -- if (model.getActiveModel().isMarkedHurt()) color = new Color(model.getActiveModel().getDamageTint().asARGB()); -- -- if (firstSend) { -- if (color.equals(lastColor)) return; -- } -- -- for (Player player : players) { -- EntityUtils.sendCustomColor(player, model.getEntity().getEntityId(), color); -- } -- } -- -- public void checkViewers(ModelEntityData model, Set viewers) { -+ public void checkViewers(EntityData model, Set viewers) { - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - if (!FloodgateApi.getInstance().isFloodgatePlayer(onlinePlayer.getUniqueId())) continue; - -@@ -96,14 +69,14 @@ - } - } - -- private void sendSpawnPacket(ModelEntityData model, Player onlinePlayer) { -+ private void sendSpawnPacket(EntityData model, Player onlinePlayer) { - EntityTaskRunnable task = model.getEntityTask(); - boolean firstJoined = !plugin.getModelManager().getPlayerJoinedCache().contains(onlinePlayer.getUniqueId()); - - if (firstJoined) { -- task.sendEntityData(model, onlinePlayer, plugin.getConfigManager().getConfig().getInt("join-send-delay") / 50); -+ task.sendEntityData((ModelEngineEntityData) model, onlinePlayer, plugin.getConfigManager().getConfig().getInt("join-send-delay") / 50); - } else { -- task.sendEntityData(model, onlinePlayer, 5); -+ task.sendEntityData((ModelEngineEntityData) model, onlinePlayer, 5); - } - } - -@@ -122,13 +95,13 @@ - return true; - } - -- public void sendHitBoxToAll(ModelEntityData model) { -+ public void sendHitBoxToAll(ModelEngineEntityData model) { - for (Player viewer : model.getViewers()) { - EntityUtils.sendCustomHitBox(viewer, model.getEntity().getEntityId(), 0.01f, 0.01f); - } - } - -- public void sendHitBox(ModelEntityData model, Player viewer) { -+ public void sendHitBox(ModelEngineEntityData model, Player viewer) { - float w = 0; - - if (model.getActiveModel().isShadowVisible()) { -@@ -140,13 +113,13 @@ - EntityUtils.sendCustomHitBox(viewer, model.getEntity().getEntityId(), 0.02f, w); - } - -- public boolean hasAnimation(ModelEntityData model, String animation) { -+ public boolean hasAnimation(ModelEngineEntityData model, String animation) { - ActiveModel activeModel = model.getActiveModel(); - BlueprintAnimation animationProperty = activeModel.getBlueprint().getAnimations().get(animation); - return !(animationProperty == null); - } - -- public Method getScaleMethod() { -- return scaleMethod; -+ public PropertyHandler getPropertyHandler() { -+ return propertyHandler; - } - } -Index: build.gradle.kts -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>plugins {\r\n id(\"java\")\r\n id(\"io.github.goooler.shadow\") version \"8.1.8\"\r\n}\r\n\r\ngroup = \"re.imc\"\r\nversion = \"1.0.0\"\r\n\r\nrepositories {\r\n mavenCentral()\r\n maven(\"https://repo.papermc.io/repository/maven-public/\")\r\n maven(\"https://central.sonatype.com/repository/maven-snapshots/\")\r\n\r\n maven(\"https://mvn.lumine.io/repository/maven-public/\")\r\n\r\n maven(\"https://repo.opencollab.dev/main/\")\r\n\r\n maven(\"https://repo.codemc.io/repository/maven-public/\")\r\n maven(\"https://repo.codemc.io/repository/maven-releases/\")\r\n}\r\n\r\ndependencies {\r\n compileOnly(\"io.papermc.paper:paper-api:1.21.8-R0.1-SNAPSHOT\")\r\n implementation(\"dev.jorel:commandapi-bukkit-shade-mojang-mapped:10.1.2\")\r\n\r\n compileOnly(\"com.ticxo.modelengine:ModelEngine:R4.0.9\")\r\n\r\n compileOnly(files(\"libs/geyserutils-spigot-1.0-SNAPSHOT.jar\"))\r\n compileOnly(\"org.geysermc.floodgate:api:2.2.4-SNAPSHOT\")\r\n\r\n implementation(\"com.github.retrooper:packetevents-spigot:2.9.5\")\r\n implementation(\"org.bstats:bstats-bukkit:3.0.2\")\r\n\r\n implementation(\"org.reflections:reflections:0.10.2\")\r\n}\r\n\r\njava {\r\n toolchain.languageVersion.set(JavaLanguageVersion.of(21))\r\n}\r\n\r\ntasks.compileJava {\r\n options.encoding = \"UTF-8\"\r\n}\r\n\r\ntasks.shadowJar {\r\n archiveFileName.set(\"${rootProject.name}-${version}.jar\")\r\n\r\n relocate(\"dev.jorel.commandapi\", \"re.imc.geysermodelengine.libs.commandapi\")\r\n\r\n relocate(\"com.github.retrooper\", \"re.imc.geysermodelengine.libs.com.github.retrooper.packetevents\")\r\n relocate(\"io.github.retrooper\", \"re.imc.geysermodelengine.libs.io.github.retrooper.packetevents\")\r\n\r\n relocate(\"org.bstats\", \"re.imc.geysermodelengine.libs.bstats\")\r\n\r\n relocate(\"org.reflections\", \"re.imc.geysermodelengine.libs.reflections\")\r\n}\r\n\r\ntasks.build {\r\n dependsOn(\"shadowJar\")\r\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/build.gradle.kts b/build.gradle.kts ---- a/build.gradle.kts (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/build.gradle.kts (date 1757071880379) -@@ -24,6 +24,7 @@ - implementation("dev.jorel:commandapi-bukkit-shade-mojang-mapped:10.1.2") - - compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.9") -+ compileOnly("io.github.toxicity188:bettermodel:1.11.4") - - compileOnly(files("libs/geyserutils-spigot-1.0-SNAPSHOT.jar")) - compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT") -Index: src/main/java/re/imc/geysermodelengine/listener/ModelListener.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine.listener;\r\n\r\nimport com.ticxo.modelengine.api.events.*;\r\nimport com.ticxo.modelengine.api.model.ActiveModel;\r\nimport org.apache.commons.lang3.tuple.Pair;\r\nimport org.bukkit.Bukkit;\r\nimport org.bukkit.World;\r\nimport org.bukkit.entity.Player;\r\nimport org.bukkit.event.EventHandler;\r\nimport org.bukkit.event.EventPriority;\r\nimport org.bukkit.event.Listener;\r\nimport org.bukkit.event.player.PlayerJoinEvent;\r\nimport org.bukkit.event.player.PlayerQuitEvent;\r\nimport org.bukkit.event.world.WorldInitEvent;\r\nimport org.geysermc.floodgate.api.FloodgateApi;\r\nimport re.imc.geysermodelengine.GeyserModelEngine;\r\nimport re.imc.geysermodelengine.managers.model.data.ModelEntityData;\r\n\r\nimport java.util.Map;\r\n\r\npublic class ModelListener implements Listener {\r\n\r\n private final GeyserModelEngine plugin;\r\n\r\n public ModelListener(GeyserModelEngine plugin) {\r\n this.plugin = plugin;\r\n }\r\n\r\n @EventHandler(priority = EventPriority.MONITOR)\r\n public void onAddModel(AddModelEvent event) {\r\n if (event.isCancelled()) return;\r\n plugin.getModelManager().create(event.getTarget(), event.getModel());\r\n }\r\n\r\n @EventHandler(priority = EventPriority.MONITOR)\r\n public void onModelMount(ModelMountEvent event) {\r\n Map map = plugin.getModelManager().getEntitiesCache().get(event.getVehicle().getModeledEntity().getBase().getEntityId());\r\n if (!event.isDriver()) return;\r\n\r\n ModelEntityData model = map.get(event.getVehicle());\r\n\r\n if (model != null && event.getPassenger() instanceof Player player) {\r\n plugin.getModelManager().getDriversCache().put(player.getUniqueId(), Pair.of(event.getVehicle(), event.getSeat()));\r\n }\r\n }\r\n\r\n @EventHandler(priority = EventPriority.MONITOR)\r\n public void onModelDismount(ModelDismountEvent event) {\r\n if (event.getPassenger() instanceof Player player) {\r\n plugin.getModelManager().getDriversCache().remove(player.getUniqueId());\r\n }\r\n }\r\n\r\n /*\r\n / xSquishyLiam:\r\n / I'm wondering if we could move this to more of a player loading chunks instead of checking all worlds via PlayerChunkLoadEvent?\r\n */\r\n @EventHandler\r\n public void onWorldInit(WorldInitEvent event) {\r\n World world = event.getWorld();\r\n world.getEntities().forEach(entity -> plugin.getModelManager().processEntities(entity));\r\n }\r\n\r\n /*\r\n / xSquishyLiam - conclusion:\r\n / I'm assuming when a player joins the server the packet for mob spawning is instant so the client resyncs itself\r\n / hence why the pig is shown instead of going invisible and not displaying the texture of the modeled mob\r\n */\r\n @EventHandler\r\n public void onPlayerJoin(PlayerJoinEvent event) {\r\n Player player = event.getPlayer();\r\n if (!FloodgateApi.getInstance().isFloodgatePlayer(player.getUniqueId())) return;\r\n Bukkit.getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> plugin.getModelManager().getPlayerJoinedCache().add(player.getUniqueId()), 10);\r\n }\r\n\r\n @EventHandler\r\n public void onPlayerQuit(PlayerQuitEvent event) {\r\n Player player = event.getPlayer();\r\n if (!FloodgateApi.getInstance().isFloodgatePlayer(player.getUniqueId())) return;\r\n plugin.getModelManager().getPlayerJoinedCache().remove(player.getUniqueId());\r\n }\r\n}\r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java ---- a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java (date 1757122148283) -@@ -1,22 +1,15 @@ - package re.imc.geysermodelengine.listener; - --import com.ticxo.modelengine.api.events.*; --import com.ticxo.modelengine.api.model.ActiveModel; --import org.apache.commons.lang3.tuple.Pair; - import org.bukkit.Bukkit; - import org.bukkit.World; - import org.bukkit.entity.Player; - import org.bukkit.event.EventHandler; --import org.bukkit.event.EventPriority; - import org.bukkit.event.Listener; - import org.bukkit.event.player.PlayerJoinEvent; - import org.bukkit.event.player.PlayerQuitEvent; - import org.bukkit.event.world.WorldInitEvent; - import org.geysermc.floodgate.api.FloodgateApi; - import re.imc.geysermodelengine.GeyserModelEngine; --import re.imc.geysermodelengine.managers.model.data.ModelEntityData; -- --import java.util.Map; - - public class ModelListener implements Listener { - -@@ -26,45 +19,19 @@ - this.plugin = plugin; - } - -- @EventHandler(priority = EventPriority.MONITOR) -- public void onAddModel(AddModelEvent event) { -- if (event.isCancelled()) return; -- plugin.getModelManager().create(event.getTarget(), event.getModel()); -- } -- -- @EventHandler(priority = EventPriority.MONITOR) -- public void onModelMount(ModelMountEvent event) { -- Map map = plugin.getModelManager().getEntitiesCache().get(event.getVehicle().getModeledEntity().getBase().getEntityId()); -- if (!event.isDriver()) return; -- -- ModelEntityData model = map.get(event.getVehicle()); -- -- if (model != null && event.getPassenger() instanceof Player player) { -- plugin.getModelManager().getDriversCache().put(player.getUniqueId(), Pair.of(event.getVehicle(), event.getSeat())); -- } -- } -- -- @EventHandler(priority = EventPriority.MONITOR) -- public void onModelDismount(ModelDismountEvent event) { -- if (event.getPassenger() instanceof Player player) { -- plugin.getModelManager().getDriversCache().remove(player.getUniqueId()); -- } -- } -- - /* - / xSquishyLiam: -- / I'm wondering if we could move this to more of a player loading chunks instead of checking all worlds via PlayerChunkLoadEvent? -+ / May change this into a better system? - */ - @EventHandler - public void onWorldInit(WorldInitEvent event) { - World world = event.getWorld(); -- world.getEntities().forEach(entity -> plugin.getModelManager().processEntities(entity)); -+ world.getEntities().forEach(entity -> plugin.getModelManager().getModelHandler().processEntities(plugin, entity)); - } - - /* -- / xSquishyLiam - conclusion: -- / I'm assuming when a player joins the server the packet for mob spawning is instant so the client resyncs itself -- / hence why the pig is shown instead of going invisible and not displaying the texture of the modeled mob -+ / xSquishyLiam: -+ / A runDelay make sures the client doesn't see pigs on login due to the client resyncing themselves back to normal - */ - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { -Index: src/main/resources/paper-plugin.yml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>main: re.imc.geysermodelengine.GeyserModelEngine\r\nname: GeyserModelEngine\r\nversion: '1.0.0'\r\napi-version: '1.21'\r\n\r\nauthors:\r\n - zimzaza4\r\n - willem.dev\r\n\r\nload: STARTUP\r\n\r\ndependencies:\r\n server:\r\n GeyserUtils:\r\n required: true\r\n packetevents:\r\n required: true\r\n ModelEngine:\r\n required: true\r\n floodgate:\r\n required: true -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml ---- a/src/main/resources/paper-plugin.yml (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/resources/paper-plugin.yml (date 1757196356991) -@@ -15,7 +15,11 @@ - required: true - packetevents: - required: true -- ModelEngine: -- required: true - floodgate: -- required: true -\ No newline at end of file -+ required: true -+ ModelEngine: -+ required: false -+ join-classpath: true -+ BetterModel: -+ required: false -+ join-classpath: true -\ No newline at end of file -Index: src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine.managers.model;\r\n\r\nimport com.ticxo.modelengine.api.ModelEngineAPI;\r\nimport com.ticxo.modelengine.api.model.ActiveModel;\r\nimport com.ticxo.modelengine.api.model.ModeledEntity;\r\nimport com.ticxo.modelengine.api.model.bone.type.Mount;\r\nimport org.apache.commons.lang3.tuple.Pair;\r\nimport org.bukkit.entity.Entity;\r\nimport re.imc.geysermodelengine.GeyserModelEngine;\r\nimport re.imc.geysermodelengine.managers.model.data.ModelEntityData;\r\n\r\nimport java.util.*;\r\nimport java.util.concurrent.ConcurrentHashMap;\r\n\r\npublic class ModelManager {\r\n\r\n private final GeyserModelEngine plugin;\r\n\r\n private final HashSet playerJoinedCache = new HashSet<>();\r\n\r\n private final ConcurrentHashMap> entitiesCache = new ConcurrentHashMap<>();\r\n private final ConcurrentHashMap modelEntitiesCache = new ConcurrentHashMap<>();\r\n\r\n private final ConcurrentHashMap> driversCache = new ConcurrentHashMap<>();\r\n\r\n public ModelManager(GeyserModelEngine plugin) {\r\n this.plugin = plugin;\r\n }\r\n\r\n public void create(ModeledEntity entity, ActiveModel model) {\r\n ModelEntityData modelEntity = new ModelEntityData(plugin, entity, model);\r\n int id = entity.getBase().getEntityId();\r\n\r\n Map map = entitiesCache.computeIfAbsent(id, k -> new HashMap<>());\r\n\r\n for (Map.Entry entry : map.entrySet()) {\r\n if (entry.getKey() != model && entry.getKey().getBlueprint().getName().equals(model.getBlueprint().getName())) {\r\n return;\r\n }\r\n }\r\n\r\n map.put(model, modelEntity);\r\n }\r\n\r\n public void processEntities(Entity entity) {\r\n if (entitiesCache.containsKey(entity.getEntityId())) return;\r\n\r\n ModeledEntity modeledEntity = ModelEngineAPI.getModeledEntity(entity);\r\n if (modeledEntity == null) return;\r\n\r\n Optional model = modeledEntity.getModels().values().stream().findFirst();\r\n model.ifPresent(m -> create(modeledEntity, m));\r\n }\r\n\r\n public void removeEntities() {\r\n for (Map entities : entitiesCache.values()) {\r\n entities.forEach((model, modelEntity) -> modelEntity.getEntity().remove());\r\n }\r\n }\r\n\r\n public HashSet getPlayerJoinedCache() {\r\n return playerJoinedCache;\r\n }\r\n\r\n public ConcurrentHashMap> getEntitiesCache() {\r\n return entitiesCache;\r\n }\r\n\r\n public ConcurrentHashMap getModelEntitiesCache() {\r\n return modelEntitiesCache;\r\n }\r\n\r\n public ConcurrentHashMap> getDriversCache() {\r\n return driversCache;\r\n }\r\n}\r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java b/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java ---- a/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java (date 1757180623200) -@@ -1,13 +1,15 @@ - package re.imc.geysermodelengine.managers.model; - --import com.ticxo.modelengine.api.ModelEngineAPI; - import com.ticxo.modelengine.api.model.ActiveModel; --import com.ticxo.modelengine.api.model.ModeledEntity; - import com.ticxo.modelengine.api.model.bone.type.Mount; - import org.apache.commons.lang3.tuple.Pair; --import org.bukkit.entity.Entity; -+import org.bukkit.Bukkit; - import re.imc.geysermodelengine.GeyserModelEngine; --import re.imc.geysermodelengine.managers.model.data.ModelEntityData; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.model.Model; -+import re.imc.geysermodelengine.managers.model.modelhandler.BetterModelHandler; -+import re.imc.geysermodelengine.managers.model.modelhandler.ModelEngineHandler; -+import re.imc.geysermodelengine.managers.model.modelhandler.ModelHandler; - - import java.util.*; - import java.util.concurrent.ConcurrentHashMap; -@@ -16,57 +18,47 @@ - - private final GeyserModelEngine plugin; - -+ private ModelHandler modelHandler; -+ - private final HashSet playerJoinedCache = new HashSet<>(); - -- private final ConcurrentHashMap> entitiesCache = new ConcurrentHashMap<>(); -- private final ConcurrentHashMap modelEntitiesCache = new ConcurrentHashMap<>(); -+ private final ConcurrentHashMap modelEntitiesCache = new ConcurrentHashMap<>(); -+ private final ConcurrentHashMap> entitiesCache = new ConcurrentHashMap<>(); - -+ // MEG ONLY - private final ConcurrentHashMap> driversCache = new ConcurrentHashMap<>(); - - public ModelManager(GeyserModelEngine plugin) { - this.plugin = plugin; -- } -- -- public void create(ModeledEntity entity, ActiveModel model) { -- ModelEntityData modelEntity = new ModelEntityData(plugin, entity, model); -- int id = entity.getBase().getEntityId(); - -- Map map = entitiesCache.computeIfAbsent(id, k -> new HashMap<>()); -- -- for (Map.Entry entry : map.entrySet()) { -- if (entry.getKey() != model && entry.getKey().getBlueprint().getName().equals(model.getBlueprint().getName())) { -- return; -- } -+ if (Bukkit.getPluginManager().getPlugin("ModelEngine") != null) { -+ this.modelHandler = new ModelEngineHandler(); -+ plugin.getLogger().info("Using ModelEngine handler!"); -+ } else if (Bukkit.getPluginManager().getPlugin("BetterModel") != null) { -+ this.modelHandler = new BetterModelHandler(); -+ plugin.getLogger().info("Using BetterModel handler!"); -+ } else { -+ plugin.getLogger().severe("No supported model engine found!"); -+ plugin.getServer().getPluginManager().disablePlugin(plugin); -+ return; - } -- -- map.put(model, modelEntity); -- } -- -- public void processEntities(Entity entity) { -- if (entitiesCache.containsKey(entity.getEntityId())) return; - -- ModeledEntity modeledEntity = ModelEngineAPI.getModeledEntity(entity); -- if (modeledEntity == null) return; -- -- Optional model = modeledEntity.getModels().values().stream().findFirst(); -- model.ifPresent(m -> create(modeledEntity, m)); -+ modelHandler.loadListeners(plugin); - } - -- public void removeEntities() { -- for (Map entities : entitiesCache.values()) { -- entities.forEach((model, modelEntity) -> modelEntity.getEntity().remove()); -- } -+ public ModelHandler getModelHandler() { -+ return modelHandler; - } - - public HashSet getPlayerJoinedCache() { - return playerJoinedCache; - } - -- public ConcurrentHashMap> getEntitiesCache() { -+ public ConcurrentHashMap> getEntitiesCache() { - return entitiesCache; - } - -- public ConcurrentHashMap getModelEntitiesCache() { -+ public ConcurrentHashMap getModelEntitiesCache() { - return modelEntitiesCache; - } - -Index: src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine.runnables;\r\n\r\nimport com.ticxo.modelengine.api.model.ActiveModel;\r\nimport io.papermc.paper.threadedregions.scheduler.ScheduledTask;\r\nimport re.imc.geysermodelengine.GeyserModelEngine;\r\nimport re.imc.geysermodelengine.managers.model.data.ModelEntityData;\r\n\r\nimport java.util.Map;\r\nimport java.util.function.Consumer;\r\n\r\npublic class UpdateTaskRunnable implements Consumer {\r\n\r\n private final GeyserModelEngine plugin;\r\n\r\n public UpdateTaskRunnable(GeyserModelEngine plugin) {\r\n this.plugin = plugin;\r\n }\r\n\r\n @Override\r\n public void accept(ScheduledTask scheduledTask) {\r\n try {\r\n for (Map models : plugin.getModelManager().getEntitiesCache().values()) {\r\n models.values().forEach(model -> model.getEntityTask().updateEntityProperties(model, model.getViewers(), false));\r\n }\r\n } catch (Throwable err) {\r\n throw new RuntimeException(err);\r\n }\r\n }\r\n}\r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java b/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java ---- a/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java (date 1757196082553) -@@ -1,9 +1,10 @@ - package re.imc.geysermodelengine.runnables; - --import com.ticxo.modelengine.api.model.ActiveModel; - import io.papermc.paper.threadedregions.scheduler.ScheduledTask; - import re.imc.geysermodelengine.GeyserModelEngine; --import re.imc.geysermodelengine.managers.model.data.ModelEntityData; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; -+import re.imc.geysermodelengine.managers.model.model.Model; - - import java.util.Map; - import java.util.function.Consumer; -@@ -19,8 +20,8 @@ - @Override - public void accept(ScheduledTask scheduledTask) { - try { -- for (Map models : plugin.getModelManager().getEntitiesCache().values()) { -- models.values().forEach(model -> model.getEntityTask().updateEntityProperties(model, model.getViewers(), false)); -+ for (Map models : plugin.getModelManager().getEntitiesCache().values()) { -+ models.values().forEach(model -> model.getEntityTask().updateEntityProperties((ModelEngineEntityData) model, model.getViewers(), false)); - } - } catch (Throwable err) { - throw new RuntimeException(err); -Index: src/main/java/re/imc/geysermodelengine/managers/model/data/ModelEntityData.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/data/ModelEntityData.java b/src/main/java/re/imc/geysermodelengine/managers/model/entity/ModelEngineEntityData.java -rename from src/main/java/re/imc/geysermodelengine/managers/model/data/ModelEntityData.java -rename to src/main/java/re/imc/geysermodelengine/managers/model/entity/ModelEngineEntityData.java ---- a/src/main/java/re/imc/geysermodelengine/managers/model/data/ModelEntityData.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/entity/ModelEngineEntityData.java (date 1757181577504) -@@ -1,4 +1,4 @@ --package re.imc.geysermodelengine.managers.model.data; -+package re.imc.geysermodelengine.managers.model.entity; - - import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; - import com.google.common.collect.Sets; -@@ -7,16 +7,17 @@ - import org.bukkit.Location; - import org.bukkit.entity.Player; - import re.imc.geysermodelengine.GeyserModelEngine; -+import re.imc.geysermodelengine.managers.model.model.Model; - import re.imc.geysermodelengine.packet.entity.PacketEntity; - import re.imc.geysermodelengine.runnables.EntityTaskRunnable; - - import java.util.Set; - --public class ModelEntityData { -+public class ModelEngineEntityData implements EntityData { - - private final GeyserModelEngine plugin; - -- private PacketEntity entity; -+ private final PacketEntity entity; - - private final Set viewers = Sets.newConcurrentHashSet(); - -@@ -26,38 +27,46 @@ - - private EntityTaskRunnable entityTask; - -- public ModelEntityData(GeyserModelEngine plugin, ModeledEntity modeledEntity, ActiveModel model) { -+ public ModelEngineEntityData(GeyserModelEngine plugin, ModeledEntity modeledEntity, ActiveModel activeModel) { - this.plugin = plugin; - - this.modeledEntity = modeledEntity; -- this.activeModel = model; -- this.entity = spawnEntity(); -+ this.activeModel = activeModel; -+ this.entity = new PacketEntity(EntityTypes.PIG, viewers, modeledEntity.getBase().getLocation()); - - runEntityTask(); - } - -+ @Override - public void teleportToModel() { - Location location = modeledEntity.getBase().getLocation(); - entity.teleport(location); - } - -- public PacketEntity spawnEntity() { -- entity = new PacketEntity(EntityTypes.PIG, viewers, modeledEntity.getBase().getLocation()); -- return entity; -- } -- - public void runEntityTask() { - entityTask = new EntityTaskRunnable(plugin, this); - } - -+ @Override - public PacketEntity getEntity() { - return entity; - } - -+ @Override - public Set getViewers() { - return viewers; - } - -+ @Override -+ public void remove() { -+ -+ } -+ -+ @Override -+ public EntityTaskRunnable getEntityTask() { -+ return entityTask; -+ } -+ - public ModeledEntity getModeledEntity() { - return modeledEntity; - } -@@ -65,8 +74,4 @@ - public ActiveModel getActiveModel() { - return activeModel; - } -- -- public EntityTaskRunnable getEntityTask() { -- return entityTask; -- } - } -Index: src/main/java/re/imc/geysermodelengine/listener/ModelEngineListener.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/listener/ModelEngineListener.java b/src/main/java/re/imc/geysermodelengine/listener/ModelEngineListener.java -new file mode 100644 ---- /dev/null (date 1757189911404) -+++ b/src/main/java/re/imc/geysermodelengine/listener/ModelEngineListener.java (date 1757189911404) -@@ -0,0 +1,60 @@ -+package re.imc.geysermodelengine.listener; -+ -+import com.ticxo.modelengine.api.events.*; -+import com.ticxo.modelengine.api.model.ActiveModel; -+import kr.toxicity.model.api.data.raw.ModelData; -+import org.apache.commons.lang3.tuple.Pair; -+import org.bukkit.entity.Player; -+import org.bukkit.event.EventHandler; -+import org.bukkit.event.EventPriority; -+import org.bukkit.event.Listener; -+import re.imc.geysermodelengine.GeyserModelEngine; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; -+import re.imc.geysermodelengine.managers.model.model.Model; -+ -+import java.util.Map; -+ -+public class ModelEngineListener implements Listener { -+ -+ private final GeyserModelEngine plugin; -+ -+ public ModelEngineListener(GeyserModelEngine plugin) { -+ this.plugin = plugin; -+ } -+ -+ @EventHandler(priority = EventPriority.MONITOR) -+ public void onAddModel(AddModelEvent event) { -+ if (event.isCancelled()) return; -+ plugin.getModelManager().getModelHandler().createModel(plugin, event.getTarget(), event.getModel()); -+ } -+ -+ // Needs Testing -+ @EventHandler(priority = EventPriority.MONITOR) -+ public void onModelMount(ModelMountEvent event) { -+ if (!event.isDriver()) return; -+ -+ ActiveModel activeModel = event.getVehicle(); -+ if (activeModel == null) return; -+ -+ int entityID = activeModel.getModeledEntity().getBase().getEntityId(); -+ -+ Map entityDataCache = plugin.getModelManager().getEntitiesCache().get(entityID); -+ if (entityDataCache == null) return; -+ -+ Model model = plugin.getModelManager().getModelEntitiesCache().get(entityID); -+ -+ EntityData entityData = entityDataCache.get(model); -+ -+ if (entityData != null && event.getPassenger() instanceof Player player) { -+ plugin.getModelManager().getDriversCache().put(player.getUniqueId(), Pair.of(event.getVehicle(), event.getSeat())); -+ } -+ } -+ -+ @EventHandler(priority = EventPriority.MONITOR) -+ public void onModelDismount(ModelDismountEvent event) { -+ if (event.getPassenger() instanceof Player player) { -+ plugin.getModelManager().getDriversCache().remove(player.getUniqueId()); -+ } -+ } -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/model/BetterModelModel.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/model/BetterModelModel.java b/src/main/java/re/imc/geysermodelengine/managers/model/model/BetterModelModel.java -new file mode 100644 ---- /dev/null (date 1757182859144) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/model/BetterModelModel.java (date 1757182859144) -@@ -0,0 +1,28 @@ -+package re.imc.geysermodelengine.managers.model.model; -+ -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.modelhandler.ModelHandler; -+import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; -+ -+public class BetterModelModel implements Model { -+ -+ @Override -+ public String getName() { -+ return ""; -+ } -+ -+ @Override -+ public ModelHandler getModelHandler() { -+ return null; -+ } -+ -+ @Override -+ public EntityData getEntityData() { -+ return null; -+ } -+ -+ @Override -+ public PropertyHandler getPropertyHandler() { -+ return null; -+ } -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/entity/BetterModelEntityData.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/entity/BetterModelEntityData.java b/src/main/java/re/imc/geysermodelengine/managers/model/entity/BetterModelEntityData.java -new file mode 100644 ---- /dev/null (date 1757165576991) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/entity/BetterModelEntityData.java (date 1757165576991) -@@ -0,0 +1,4 @@ -+package re.imc.geysermodelengine.managers.model.entity; -+ -+public class BetterModelEntityData { -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/model/Model.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/model/Model.java b/src/main/java/re/imc/geysermodelengine/managers/model/model/Model.java -new file mode 100644 ---- /dev/null (date 1757182859294) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/model/Model.java (date 1757182859294) -@@ -0,0 +1,14 @@ -+package re.imc.geysermodelengine.managers.model.model; -+ -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.modelhandler.ModelHandler; -+import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; -+ -+public interface Model { -+ -+ String getName(); -+ -+ ModelHandler getModelHandler(); -+ EntityData getEntityData(); -+ PropertyHandler getPropertyHandler(); -+} -Index: src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine.managers.commands;\r\n\r\nimport org.reflections.Reflections;\r\nimport re.imc.geysermodelengine.GeyserModelEngine;\r\n\r\nimport java.lang.reflect.InvocationTargetException;\r\nimport java.util.HashMap;\r\n\r\npublic class CommandManager {\r\n\r\n private final GeyserModelEngine plugin;\r\n\r\n private final HashMap commandManagersCache = new HashMap<>();\r\n\r\n public CommandManager(GeyserModelEngine plugin) {\r\n this.plugin = plugin;\r\n load(\"re.imc.geysermodelengine.managers.commands.managers\");\r\n }\r\n\r\n private void load(String path) {\r\n for (Class clazz : new Reflections(path).getSubTypesOf(CommandManagers.class)) {\r\n try {\r\n CommandManagers commandManager = (CommandManagers) clazz.getDeclaredConstructor(GeyserModelEngine.class).newInstance(plugin);\r\n plugin.getLogger().warning(\"Loading Command Manager - \" + commandManager.name());\r\n commandManagersCache.put(commandManager.name(), commandManager);\r\n } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException err) {\r\n plugin.getLogger().severe(\"Failed to load Command Manager \" + clazz.getName());\r\n throw new RuntimeException(err);\r\n }\r\n }\r\n }\r\n\r\n public HashMap getCommandManagersCache() {\r\n return commandManagersCache;\r\n }\r\n}\r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java b/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java ---- a/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java (date 1757123367316) -@@ -21,7 +21,7 @@ - for (Class clazz : new Reflections(path).getSubTypesOf(CommandManagers.class)) { - try { - CommandManagers commandManager = (CommandManagers) clazz.getDeclaredConstructor(GeyserModelEngine.class).newInstance(plugin); -- plugin.getLogger().warning("Loading Command Manager - " + commandManager.name()); -+ plugin.getLogger().info("Loading Command Manager - " + commandManager.name()); - commandManagersCache.put(commandManager.name(), commandManager); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException err) { - plugin.getLogger().severe("Failed to load Command Manager " + clazz.getName()); -Index: src/main/java/re/imc/geysermodelengine/managers/model/model/ModelEngineModel.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/model/ModelEngineModel.java b/src/main/java/re/imc/geysermodelengine/managers/model/model/ModelEngineModel.java -new file mode 100644 ---- /dev/null (date 1757181527994) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/model/ModelEngineModel.java (date 1757181527994) -@@ -0,0 +1,45 @@ -+package re.imc.geysermodelengine.managers.model.model; -+ -+import com.ticxo.modelengine.api.model.ActiveModel; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.modelhandler.ModelHandler; -+import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; -+ -+public class ModelEngineModel implements Model { -+ -+ private final ActiveModel activeModel; -+ private final ModelHandler modelHandler; -+ private final EntityData entityData; -+ private final PropertyHandler propertyHandler; -+ -+ public ModelEngineModel(ActiveModel activeModel, ModelHandler modelHandler, EntityData entityData, PropertyHandler propertyHandler) { -+ this.activeModel = activeModel; -+ this.modelHandler = modelHandler; -+ this.entityData = entityData; -+ this.propertyHandler = propertyHandler; -+ } -+ -+ @Override -+ public String getName() { -+ return activeModel.getBlueprint().getName(); -+ } -+ -+ @Override -+ public ModelHandler getModelHandler() { -+ return modelHandler; -+ } -+ -+ @Override -+ public EntityData getEntityData() { -+ return entityData; -+ } -+ -+ @Override -+ public PropertyHandler getPropertyHandler() { -+ return propertyHandler; -+ } -+ -+ public ActiveModel getActiveModel() { -+ return activeModel; -+ } -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/entity/EntityData.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/entity/EntityData.java b/src/main/java/re/imc/geysermodelengine/managers/model/entity/EntityData.java -new file mode 100644 ---- /dev/null (date 1757181577485) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/entity/EntityData.java (date 1757181577485) -@@ -0,0 +1,20 @@ -+package re.imc.geysermodelengine.managers.model.entity; -+ -+import org.bukkit.entity.Player; -+import re.imc.geysermodelengine.managers.model.model.Model; -+import re.imc.geysermodelengine.packet.entity.PacketEntity; -+import re.imc.geysermodelengine.runnables.EntityTaskRunnable; -+ -+import java.util.Set; -+ -+public interface EntityData { -+ -+ PacketEntity getEntity(); -+ Set getViewers(); -+ -+ void teleportToModel(); -+ -+ void remove(); -+ -+ EntityTaskRunnable getEntityTask(); -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/PropertyHandler.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/PropertyHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/PropertyHandler.java -new file mode 100644 ---- /dev/null (date 1757165735079) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/PropertyHandler.java (date 1757165735079) -@@ -0,0 +1,16 @@ -+package re.imc.geysermodelengine.managers.model.propertyhandler; -+ -+import org.bukkit.entity.Player; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+ -+import java.awt.*; -+import java.util.Collection; -+ -+public interface PropertyHandler { -+ -+ void sendScale(EntityData modelData, Collection players, float lastScale, boolean firstSend); -+ void sendColor(EntityData modelData, Collection players, Color lastColor, boolean firstSend); -+ void sendHitBox(EntityData modelData, Player player); -+ -+ -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/BetterModelPropertyHandler.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/BetterModelPropertyHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/BetterModelPropertyHandler.java -new file mode 100644 ---- /dev/null (date 1757165735065) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/BetterModelPropertyHandler.java (date 1757165735065) -@@ -0,0 +1,25 @@ -+package re.imc.geysermodelengine.managers.model.propertyhandler; -+ -+import org.bukkit.entity.Player; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+ -+import java.awt.*; -+import java.util.Collection; -+ -+public class BetterModelPropertyHandler implements PropertyHandler { -+ -+ @Override -+ public void sendScale(EntityData modelData, Collection players, float lastScale, boolean firstSend) { -+ -+ } -+ -+ @Override -+ public void sendColor(EntityData modelData, Collection players, Color lastColor, boolean firstSend) { -+ -+ } -+ -+ @Override -+ public void sendHitBox(EntityData modelData, Player player) { -+ -+ } -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelHandler.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelHandler.java -new file mode 100644 ---- /dev/null (date 1757185216413) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelHandler.java (date 1757185216413) -@@ -0,0 +1,16 @@ -+package re.imc.geysermodelengine.managers.model.modelhandler; -+ -+import org.bukkit.entity.Entity; -+import re.imc.geysermodelengine.GeyserModelEngine; -+ -+public interface ModelHandler { -+ -+ // Might do a hashmap way tbf -+ void createModel(GeyserModelEngine plugin, Object modeledEntity, Object activeModel); -+ -+ void processEntities(GeyserModelEngine plugin, Entity entity); -+ -+ void removeEntities(GeyserModelEngine plugin); -+ -+ void loadListeners(GeyserModelEngine plugin); -+} -Index: src/main/java/re/imc/geysermodelengine/listener/BetterModelListener.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/listener/BetterModelListener.java b/src/main/java/re/imc/geysermodelengine/listener/BetterModelListener.java -new file mode 100644 ---- /dev/null (date 1757164238078) -+++ b/src/main/java/re/imc/geysermodelengine/listener/BetterModelListener.java (date 1757164238078) -@@ -0,0 +1,20 @@ -+package re.imc.geysermodelengine.listener; -+ -+import kr.toxicity.model.api.event.CreateTrackerEvent; -+import org.bukkit.event.EventHandler; -+import org.bukkit.event.Listener; -+import re.imc.geysermodelengine.GeyserModelEngine; -+ -+public class BetterModelListener implements Listener { -+ -+ private final GeyserModelEngine plugin; -+ -+ public BetterModelListener(GeyserModelEngine plugin) { -+ this.plugin = plugin; -+ } -+ -+ @EventHandler -+ public void onModelSpawn(CreateTrackerEvent event) { -+ plugin.getLogger().info(event.getTracker().name()); -+ } -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/ModelEnginePropertyHandler.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/ModelEnginePropertyHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/ModelEnginePropertyHandler.java -new file mode 100644 ---- /dev/null (date 1757165735124) -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/ModelEnginePropertyHandler.java (date 1757165735124) -@@ -0,0 +1,71 @@ -+package re.imc.geysermodelengine.managers.model.propertyhandler; -+ -+import com.ticxo.modelengine.api.model.ActiveModel; -+import me.zimzaza4.geyserutils.spigot.api.EntityUtils; -+import org.bukkit.entity.Player; -+import org.joml.Vector3fc; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; -+ -+import java.awt.*; -+import java.lang.reflect.Method; -+import java.util.Collection; -+ -+public class ModelEnginePropertyHandler implements PropertyHandler { -+ -+ private final Method scaleMethod; -+ -+ public ModelEnginePropertyHandler() { -+ try { -+ this.scaleMethod = ActiveModel.class.getMethod("getScale"); -+ } catch (NoSuchMethodException err) { -+ throw new RuntimeException(err); -+ } -+ } -+ -+ @Override -+ public void sendScale(EntityData modelData, Collection players, float lastScale, boolean firstSend) { -+ try { -+ if (players.isEmpty()) return; -+ -+ ModelEngineEntityData modelEngineEntityData = (ModelEngineEntityData) modelData; -+ -+ Vector3fc scale = (Vector3fc) scaleMethod.invoke(modelEngineEntityData.getActiveModel()); -+ -+ float average = (scale.x() + scale.y() + scale.z()) / 3; -+ -+ if (!firstSend) { -+ if (average == lastScale) return; -+ } -+ -+ for (Player player : players) { -+ EntityUtils.sendCustomScale(player, modelEngineEntityData.getEntity().getEntityId(), average); -+ } -+ } catch (Throwable ignored) {} -+ } -+ -+ @Override -+ public void sendColor(EntityData modelData, Collection players, Color lastColor, boolean firstSend) { -+ if (players.isEmpty()) return; -+ -+ ModelEngineEntityData modelEngineEntityData = (ModelEngineEntityData) modelData; -+ -+ Color color = new Color(modelEngineEntityData.getActiveModel().getDefaultTint().asARGB()); -+ if (modelEngineEntityData.getActiveModel().isMarkedHurt()) color = new Color(modelEngineEntityData.getActiveModel().getDamageTint().asARGB()); -+ -+ if (firstSend) { -+ if (color.equals(lastColor)) return; -+ } -+ -+ for (Player player : players) { -+ EntityUtils.sendCustomColor(player, modelEngineEntityData.getEntity().getEntityId(), color); -+ } -+ } -+ -+ @Override -+ public void sendHitBox(EntityData modelData, Player player) { -+ for (Player viewer : modelData.getViewers()) { -+ EntityUtils.sendCustomHitBox(viewer, modelData.getEntity().getEntityId(), 0.01f, 0.01f); -+ } -+ } -+} -Index: .idea/workspace.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {\r\n "associatedIndex": 8\r\n}\r\n \r\n \r\n \r\n \r\n \r\n \r\n {\r\n "keyToString": {\r\n "Gradle.Download Sources.executor": "Run",\r\n "Gradle.GeyserModelEngine [build].executor": "Run",\r\n "Gradle.GeyserModelEngine [jar].executor": "Run",\r\n "Maven.GeyserModelEngine [install...].executor": "Run",\r\n "Maven.GeyserModelEngine [install].executor": "Run",\r\n "ModuleVcsDetector.initialDetectionPerformed": "true",\r\n "RunOnceActivity.ShowReadmeOnStart": "true",\r\n "RunOnceActivity.git.unshallow": "true",\r\n "git-widget-placeholder": "main",\r\n "kotlin-language-version-configured": "true",\r\n "last_opened_file_path": "D:/Coding/Forks/Minecraft/GeyserModelEngine",\r\n "project.structure.last.edited": "Project",\r\n "project.structure.proportion": "0.0",\r\n "project.structure.side.proportion": "0.2",\r\n "settings.editor.selected.configurable": "reference.settings.project.maven.runner"\r\n }\r\n}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n true\r\n true\r\n false\r\n false\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n true\r\n true\r\n false\r\n false\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n 1748302633990\r\n \r\n \r\n \r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/.idea/workspace.xml b/.idea/workspace.xml ---- a/.idea/workspace.xml (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/.idea/workspace.xml (date 1757196821488) -@@ -5,7 +5,32 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - - -+ - - -@@ -87,7 +117,7 @@ - "ModuleVcsDetector.initialDetectionPerformed": "true", - "RunOnceActivity.ShowReadmeOnStart": "true", - "RunOnceActivity.git.unshallow": "true", -- "git-widget-placeholder": "main", -+ "git-widget-placeholder": "bettermodel-support-dev", - "kotlin-language-version-configured": "true", - "last_opened_file_path": "D:/Coding/Forks/Minecraft/GeyserModelEngine", - "project.structure.last.edited": "Project", -Index: src/main/java/re/imc/geysermodelengine/Events/GeyserModelEngineModelSpawn.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine.Events;\r\n\r\npublic class GeyserModelEngineModelSpawn {\r\n\r\n //Spawn Event\r\n}\r\n -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/Events/GeyserModelEngineModelSpawn.java b/src/main/java/re/imc/geysermodelengine/events/GeyserModelEngineModelSpawn.java -rename from src/main/java/re/imc/geysermodelengine/Events/GeyserModelEngineModelSpawn.java -rename to src/main/java/re/imc/geysermodelengine/events/GeyserModelEngineModelSpawn.java ---- a/src/main/java/re/imc/geysermodelengine/Events/GeyserModelEngineModelSpawn.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/events/GeyserModelEngineModelSpawn.java -@@ -1,6 +1,25 @@ --package re.imc.geysermodelengine.Events; -+package re.imc.geysermodelengine.events; -+ -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; - --public class GeyserModelEngineModelSpawn { -+public class GeyserModelEngineModelSpawn extends Event { -+ -+ private static final HandlerList handlers = new HandlerList(); - - //Spawn Event -+ -+ public GeyserModelEngineModelSpawn() { -+ -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } - } -Index: src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelEngineHandler.java -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelEngineHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelEngineHandler.java -new file mode 100644 ---- /dev/null -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelEngineHandler.java -@@ -0,0 +1,69 @@ -+package re.imc.geysermodelengine.managers.model.modelhandler; -+ -+import com.ticxo.modelengine.api.ModelEngineAPI; -+import com.ticxo.modelengine.api.model.ActiveModel; -+import com.ticxo.modelengine.api.model.ModeledEntity; -+import kr.toxicity.model.api.data.raw.ModelData; -+import org.bukkit.Bukkit; -+import org.bukkit.entity.Entity; -+import re.imc.geysermodelengine.GeyserModelEngine; -+import re.imc.geysermodelengine.listener.ModelEngineListener; -+import re.imc.geysermodelengine.managers.model.entity.EntityData; -+import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; -+import re.imc.geysermodelengine.managers.model.model.Model; -+import re.imc.geysermodelengine.managers.model.model.ModelEngineModel; -+import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; -+ -+import java.util.HashMap; -+import java.util.Map; -+import java.util.Optional; -+ -+public class ModelEngineHandler implements ModelHandler { -+ -+ @Override -+ public void createModel(GeyserModelEngine plugin, Object modeledEntity, Object activeModel) { -+ ModeledEntity megEntity = (ModeledEntity) modeledEntity; -+ ActiveModel megActiveModel = (ActiveModel) activeModel; -+ -+ int entityID = megEntity.getBase().getEntityId(); -+ -+ PropertyHandler propertyHandler = plugin.getEntityTaskManager().getPropertyHandler(); -+ EntityData entityData = new ModelEngineEntityData(plugin, megEntity, megActiveModel); -+ -+ Model model = new ModelEngineModel(megActiveModel, this, entityData, propertyHandler); -+ -+ Map entityDataCache = plugin.getModelManager().getEntitiesCache().computeIfAbsent(entityID, k -> new HashMap<>()); -+ -+ for (Map.Entry entry : entityDataCache.entrySet()) { -+ if (entry.getKey() != model && entry.getKey().getName().equals(megActiveModel.getBlueprint().getName())) { -+ return; -+ } -+ } -+ -+ plugin.getModelManager().getModelEntitiesCache().put(entityID, model); -+ entityDataCache.put(model, entityData); -+ } -+ -+ @Override -+ public void processEntities(GeyserModelEngine plugin, Entity entity) { -+ if (plugin.getModelManager().getEntitiesCache().containsKey(entity.getEntityId())) return; -+ -+ ModeledEntity modeledEntity = ModelEngineAPI.getModeledEntity(entity); -+ if (modeledEntity == null) return; -+ -+ Optional model = modeledEntity.getModels().values().stream().findFirst(); -+ model.ifPresent(m -> createModel(plugin, modeledEntity, m)); -+ } -+ -+ @Override -+ public void removeEntities(GeyserModelEngine plugin) { -+ for (Map entities : plugin.getModelManager().getEntitiesCache().values()) { -+ entities.forEach((model, modelEntity) -> modelEntity.getEntity().remove()); -+ } -+ } -+ -+ @Override -+ public void loadListeners(GeyserModelEngine plugin) { -+ Bukkit.getPluginManager().registerEvents(new ModelEngineListener(plugin), plugin); -+ } -+} -Index: src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/BetterModelHandler.java -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/BetterModelHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/BetterModelHandler.java -new file mode 100644 ---- /dev/null -+++ b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/BetterModelHandler.java -@@ -0,0 +1,29 @@ -+package re.imc.geysermodelengine.managers.model.modelhandler; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.entity.Entity; -+import re.imc.geysermodelengine.GeyserModelEngine; -+import re.imc.geysermodelengine.listener.BetterModelListener; -+ -+public class BetterModelHandler implements ModelHandler { -+ -+ @Override -+ public void createModel(GeyserModelEngine plugin, Object modeledEntity, Object activeModel) { -+ -+ } -+ -+ @Override -+ public void processEntities(GeyserModelEngine plugin, Entity entity) { -+ -+ } -+ -+ @Override -+ public void removeEntities(GeyserModelEngine plugin) { -+ -+ } -+ -+ @Override -+ public void loadListeners(GeyserModelEngine plugin) { -+ Bukkit.getPluginManager().registerEvents(new BetterModelListener(plugin), plugin); -+ } -+} -Index: src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package re.imc.geysermodelengine.util;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\npublic class BooleanPacker {\r\n\r\n private final int MAX_BOOLEANS = 24;\r\n\r\n public int booleansToInt(List booleans) {\r\n int result = 0;\r\n int i = 1;\r\n\r\n for (boolean b : booleans) {\r\n if (b) {\r\n result += i;\r\n }\r\n i *= 2;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n public int mapBooleansToInt(Map booleanMap) {\r\n int result = 0;\r\n int i = 1;\r\n\r\n List keys = new ArrayList<>(booleanMap.keySet());\r\n Collections.sort(keys);\r\n\r\n for (String key : keys) {\r\n if (booleanMap.get(key)) {\r\n result += i;\r\n }\r\n i *= 2;\r\n }\r\n return result;\r\n }\r\n\r\n public List booleansToInts(List booleans) {\r\n List results = new ArrayList<>();\r\n int result = 0;\r\n int i = 1;\r\n int i1 = 1;\r\n\r\n for (boolean b : booleans) {\r\n if (b) {\r\n result += i;\r\n }\r\n if (i1 % MAX_BOOLEANS == 0 || i1 == booleans.size()) {\r\n results.add(result);\r\n result = 0;\r\n i = 1;\r\n } else {\r\n i *= 2;\r\n }\r\n i1++;\r\n }\r\n\r\n return results;\r\n }\r\n\r\n public List mapBooleansToInts(Map booleanMap) {\r\n List keys = new ArrayList<>(booleanMap.keySet());\r\n List booleans = new ArrayList<>();\r\n\r\n Collections.sort(keys);\r\n\r\n for (String key : keys) {\r\n booleans.add(booleanMap.get(key));\r\n }\r\n return booleansToInts(booleans);\r\n }\r\n}\r\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java b/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java ---- a/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java (revision b6425ffa51b4e18318b1d2318db705909064ac55) -+++ b/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java (date 1757196821539) -@@ -7,9 +7,9 @@ - - public class BooleanPacker { - -- private final int MAX_BOOLEANS = 24; -+ private static final int MAX_BOOLEANS = 24; - -- public int booleansToInt(List booleans) { -+ public static int booleansToInt(List booleans) { - int result = 0; - int i = 1; - -@@ -23,7 +23,7 @@ - return result; - } - -- public int mapBooleansToInt(Map booleanMap) { -+ public static int mapBooleansToInt(Map booleanMap) { - int result = 0; - int i = 1; - -@@ -39,7 +39,7 @@ - return result; - } - -- public List booleansToInts(List booleans) { -+ public static List booleansToInts(List booleans) { - List results = new ArrayList<>(); - int result = 0; - int i = 1; -@@ -62,7 +62,7 @@ - return results; - } - -- public List mapBooleansToInts(Map booleanMap) { -+ public static List mapBooleansToInts(Map booleanMap) { - List keys = new ArrayList<>(booleanMap.keySet()); - List booleans = new ArrayList<>(); - diff --git a/.idea/shelf/Uncommitted_changes_before_rebase__Changes_.xml b/.idea/shelf/Uncommitted_changes_before_rebase__Changes_.xml deleted file mode 100644 index cb7eb92..0000000 --- a/.idea/shelf/Uncommitted_changes_before_rebase__Changes_.xml +++ /dev/null @@ -1,4 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/shelf/Uncommitted_changes_before_rebase__Changes_1.xml b/.idea/shelf/Uncommitted_changes_before_rebase__Changes_1.xml deleted file mode 100644 index 555848b..0000000 --- a/.idea/shelf/Uncommitted_changes_before_rebase__Changes_1.xml +++ /dev/null @@ -1,4 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index fccca5b..7891eaa 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,7 +5,35 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - { - "keyToString": { - "Gradle.Download Sources.executor": "Run", - "Gradle.GeyserModelEngine [build].executor": "Run", - "Gradle.GeyserModelEngine [jar].executor": "Run", - "Maven.GeyserModelEngine [install...].executor": "Run", - "Maven.GeyserModelEngine [install].executor": "Run", - "ModuleVcsDetector.initialDetectionPerformed": "true", - "RunOnceActivity.ShowReadmeOnStart": "true", - "RunOnceActivity.git.unshallow": "true", - "git-widget-placeholder": "bettermodel-support-dev", - "kotlin-language-version-configured": "true", - "last_opened_file_path": "D:/Coding/Forks/Minecraft/GeyserModelEngine", - "project.structure.last.edited": "Project", - "project.structure.proportion": "0.0", - "project.structure.side.proportion": "0.2", - "settings.editor.selected.configurable": "reference.settings.project.maven.runner" + +}]]> diff --git a/build.gradle.kts b/build.gradle.kts index 7a5020c..c3db598 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,6 +24,7 @@ dependencies { implementation("dev.jorel:commandapi-bukkit-shade-mojang-mapped:10.1.2") compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.9") + compileOnly("io.github.toxicity188:bettermodel:1.11.4") compileOnly(files("libs/geyserutils-spigot-1.0-SNAPSHOT.jar")) compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT") diff --git a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java index 549c415..3c1b083 100644 --- a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java +++ b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java @@ -55,7 +55,7 @@ public class GeyserModelEngine extends JavaPlugin { public void onDisable() { PacketEvents.getAPI().terminate(); - this.modelManager.removeEntities(); + this.modelManager.getModelHandler().removeEntities(this); CommandAPI.onDisable(); } diff --git a/src/main/java/re/imc/geysermodelengine/listener/BetterModelListener.java b/src/main/java/re/imc/geysermodelengine/listener/BetterModelListener.java new file mode 100644 index 0000000..d60c5fb --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/listener/BetterModelListener.java @@ -0,0 +1,20 @@ +package re.imc.geysermodelengine.listener; + +import kr.toxicity.model.api.event.CreateTrackerEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import re.imc.geysermodelengine.GeyserModelEngine; + +public class BetterModelListener implements Listener { + + private final GeyserModelEngine plugin; + + public BetterModelListener(GeyserModelEngine plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onModelSpawn(CreateTrackerEvent event) { + plugin.getLogger().info(event.getTracker().name()); + } +} diff --git a/src/main/java/re/imc/geysermodelengine/listener/ModelEngineListener.java b/src/main/java/re/imc/geysermodelengine/listener/ModelEngineListener.java new file mode 100644 index 0000000..4081231 --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/listener/ModelEngineListener.java @@ -0,0 +1,60 @@ +package re.imc.geysermodelengine.listener; + +import com.ticxo.modelengine.api.events.*; +import com.ticxo.modelengine.api.model.ActiveModel; +import kr.toxicity.model.api.data.raw.ModelData; +import org.apache.commons.lang3.tuple.Pair; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import re.imc.geysermodelengine.GeyserModelEngine; +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; +import re.imc.geysermodelengine.managers.model.model.Model; + +import java.util.Map; + +public class ModelEngineListener implements Listener { + + private final GeyserModelEngine plugin; + + public ModelEngineListener(GeyserModelEngine plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onAddModel(AddModelEvent event) { + if (event.isCancelled()) return; + plugin.getModelManager().getModelHandler().createModel(plugin, event.getTarget(), event.getModel()); + } + + // Needs Testing + @EventHandler(priority = EventPriority.MONITOR) + public void onModelMount(ModelMountEvent event) { + if (!event.isDriver()) return; + + ActiveModel activeModel = event.getVehicle(); + if (activeModel == null) return; + + int entityID = activeModel.getModeledEntity().getBase().getEntityId(); + + Map entityDataCache = plugin.getModelManager().getEntitiesCache().get(entityID); + if (entityDataCache == null) return; + + Model model = plugin.getModelManager().getModelEntitiesCache().get(entityID); + + EntityData entityData = entityDataCache.get(model); + + if (entityData != null && event.getPassenger() instanceof Player player) { + plugin.getModelManager().getDriversCache().put(player.getUniqueId(), Pair.of(event.getVehicle(), event.getSeat())); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onModelDismount(ModelDismountEvent event) { + if (event.getPassenger() instanceof Player player) { + plugin.getModelManager().getDriversCache().remove(player.getUniqueId()); + } + } +} diff --git a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java index dc94a0f..1a2d009 100644 --- a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java +++ b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java @@ -1,22 +1,15 @@ package re.imc.geysermodelengine.listener; -import com.ticxo.modelengine.api.events.*; -import com.ticxo.modelengine.api.model.ActiveModel; -import org.apache.commons.lang3.tuple.Pair; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.world.WorldInitEvent; import org.geysermc.floodgate.api.FloodgateApi; import re.imc.geysermodelengine.GeyserModelEngine; -import re.imc.geysermodelengine.managers.model.data.ModelEntityData; - -import java.util.Map; public class ModelListener implements Listener { @@ -26,45 +19,19 @@ public class ModelListener implements Listener { this.plugin = plugin; } - @EventHandler(priority = EventPriority.MONITOR) - public void onAddModel(AddModelEvent event) { - if (event.isCancelled()) return; - plugin.getModelManager().create(event.getTarget(), event.getModel()); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onModelMount(ModelMountEvent event) { - Map map = plugin.getModelManager().getEntitiesCache().get(event.getVehicle().getModeledEntity().getBase().getEntityId()); - if (!event.isDriver()) return; - - ModelEntityData model = map.get(event.getVehicle()); - - if (model != null && event.getPassenger() instanceof Player player) { - plugin.getModelManager().getDriversCache().put(player.getUniqueId(), Pair.of(event.getVehicle(), event.getSeat())); - } - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onModelDismount(ModelDismountEvent event) { - if (event.getPassenger() instanceof Player player) { - plugin.getModelManager().getDriversCache().remove(player.getUniqueId()); - } - } - /* / xSquishyLiam: - / I'm wondering if we could move this to more of a player loading chunks instead of checking all worlds via PlayerChunkLoadEvent? + / May change this into a better system? */ @EventHandler public void onWorldInit(WorldInitEvent event) { World world = event.getWorld(); - world.getEntities().forEach(entity -> plugin.getModelManager().processEntities(entity)); + world.getEntities().forEach(entity -> plugin.getModelManager().getModelHandler().processEntities(plugin, entity)); } /* - / xSquishyLiam - conclusion: - / I'm assuming when a player joins the server the packet for mob spawning is instant so the client resyncs itself - / hence why the pig is shown instead of going invisible and not displaying the texture of the modeled mob + / xSquishyLiam: + / A runDelay make sures the client doesn't see pigs on login due to the client resyncing themselves back to normal */ @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { diff --git a/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java b/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java index fe46a7a..a0353f9 100644 --- a/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java +++ b/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java @@ -21,7 +21,7 @@ public class CommandManager { for (Class clazz : new Reflections(path).getSubTypesOf(CommandManagers.class)) { try { CommandManagers commandManager = (CommandManagers) clazz.getDeclaredConstructor(GeyserModelEngine.class).newInstance(plugin); - plugin.getLogger().warning("Loading Command Manager - " + commandManager.name()); + plugin.getLogger().info("Loading Command Manager - " + commandManager.name()); commandManagersCache.put(commandManager.name(), commandManager); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException err) { plugin.getLogger().severe("Failed to load Command Manager " + clazz.getName()); diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java b/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java index 26d5eed..92a5a97 100644 --- a/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java +++ b/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java @@ -9,29 +9,35 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.geysermc.floodgate.api.FloodgateApi; -import org.joml.Vector3fc; import re.imc.geysermodelengine.GeyserModelEngine; -import re.imc.geysermodelengine.managers.model.data.ModelEntityData; +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.propertyhandler.BetterModelPropertyHandler; +import re.imc.geysermodelengine.managers.model.propertyhandler.ModelEnginePropertyHandler; +import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; +import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; import re.imc.geysermodelengine.packet.entity.PacketEntity; import re.imc.geysermodelengine.runnables.EntityTaskRunnable; -import java.awt.*; -import java.lang.reflect.Method; import java.util.*; public class EntityTaskManager { private final GeyserModelEngine plugin; - private final Method scaleMethod; + private PropertyHandler propertyHandler; public EntityTaskManager(GeyserModelEngine plugin) { this.plugin = plugin; - try { - this.scaleMethod = ActiveModel.class.getMethod("getScale"); - } catch (NoSuchMethodException err) { - throw new RuntimeException(err); + if (Bukkit.getPluginManager().getPlugin("ModelEngine") != null) { + this.propertyHandler = new ModelEnginePropertyHandler(); + plugin.getLogger().info("Using ModelEngine property handler!"); + } else if (Bukkit.getPluginManager().getPlugin("BetterModel") != null) { + this.propertyHandler = new BetterModelPropertyHandler(); + plugin.getLogger().info("Using BetterModel property handler!"); + } else { + plugin.getLogger().severe("No supported model engine found!"); + plugin.getServer().getPluginManager().disablePlugin(plugin); } } @@ -45,40 +51,7 @@ public class EntityTaskManager { return name; } - public void sendScale(ModelEntityData model, Collection players, float lastScale, boolean firstSend) { - try { - if (players.isEmpty()) return; - - Vector3fc scale = (Vector3fc) scaleMethod.invoke(model.getActiveModel()); - - float average = (scale.x() + scale.y() + scale.z()) / 3; - - if (!firstSend) { - if (average == lastScale) return; - } - - for (Player player : players) { - EntityUtils.sendCustomScale(player, model.getEntity().getEntityId(), average); - } - } catch (Throwable ignored) {} - } - - public void sendColor(ModelEntityData model, Collection players, Color lastColor, boolean firstSend) { - if (players.isEmpty()) return; - - Color color = new Color(model.getActiveModel().getDefaultTint().asARGB()); - if (model.getActiveModel().isMarkedHurt()) color = new Color(model.getActiveModel().getDamageTint().asARGB()); - - if (firstSend) { - if (color.equals(lastColor)) return; - } - - for (Player player : players) { - EntityUtils.sendCustomColor(player, model.getEntity().getEntityId(), color); - } - } - - public void checkViewers(ModelEntityData model, Set viewers) { + public void checkViewers(EntityData model, Set viewers) { for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { if (!FloodgateApi.getInstance().isFloodgatePlayer(onlinePlayer.getUniqueId())) continue; @@ -96,14 +69,14 @@ public class EntityTaskManager { } } - private void sendSpawnPacket(ModelEntityData model, Player onlinePlayer) { + private void sendSpawnPacket(EntityData model, Player onlinePlayer) { EntityTaskRunnable task = model.getEntityTask(); boolean firstJoined = !plugin.getModelManager().getPlayerJoinedCache().contains(onlinePlayer.getUniqueId()); if (firstJoined) { - task.sendEntityData(model, onlinePlayer, plugin.getConfigManager().getConfig().getInt("join-send-delay") / 50); + task.sendEntityData((ModelEngineEntityData) model, onlinePlayer, plugin.getConfigManager().getConfig().getInt("join-send-delay") / 50); } else { - task.sendEntityData(model, onlinePlayer, 5); + task.sendEntityData((ModelEngineEntityData) model, onlinePlayer, 5); } } @@ -122,13 +95,13 @@ public class EntityTaskManager { return true; } - public void sendHitBoxToAll(ModelEntityData model) { + public void sendHitBoxToAll(ModelEngineEntityData model) { for (Player viewer : model.getViewers()) { EntityUtils.sendCustomHitBox(viewer, model.getEntity().getEntityId(), 0.01f, 0.01f); } } - public void sendHitBox(ModelEntityData model, Player viewer) { + public void sendHitBox(ModelEngineEntityData model, Player viewer) { float w = 0; if (model.getActiveModel().isShadowVisible()) { @@ -140,13 +113,13 @@ public class EntityTaskManager { EntityUtils.sendCustomHitBox(viewer, model.getEntity().getEntityId(), 0.02f, w); } - public boolean hasAnimation(ModelEntityData model, String animation) { + public boolean hasAnimation(ModelEngineEntityData model, String animation) { ActiveModel activeModel = model.getActiveModel(); BlueprintAnimation animationProperty = activeModel.getBlueprint().getAnimations().get(animation); return !(animationProperty == null); } - public Method getScaleMethod() { - return scaleMethod; + public PropertyHandler getPropertyHandler() { + return propertyHandler; } } diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java b/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java index 37eaa14..5ff745f 100644 --- a/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java +++ b/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java @@ -1,13 +1,15 @@ package re.imc.geysermodelengine.managers.model; -import com.ticxo.modelengine.api.ModelEngineAPI; import com.ticxo.modelengine.api.model.ActiveModel; -import com.ticxo.modelengine.api.model.ModeledEntity; import com.ticxo.modelengine.api.model.bone.type.Mount; import org.apache.commons.lang3.tuple.Pair; -import org.bukkit.entity.Entity; +import org.bukkit.Bukkit; import re.imc.geysermodelengine.GeyserModelEngine; -import re.imc.geysermodelengine.managers.model.data.ModelEntityData; +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.model.Model; +import re.imc.geysermodelengine.managers.model.modelhandler.BetterModelHandler; +import re.imc.geysermodelengine.managers.model.modelhandler.ModelEngineHandler; +import re.imc.geysermodelengine.managers.model.modelhandler.ModelHandler; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -16,57 +18,47 @@ public class ModelManager { private final GeyserModelEngine plugin; + private ModelHandler modelHandler; + private final HashSet playerJoinedCache = new HashSet<>(); - private final ConcurrentHashMap> entitiesCache = new ConcurrentHashMap<>(); - private final ConcurrentHashMap modelEntitiesCache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap modelEntitiesCache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> entitiesCache = new ConcurrentHashMap<>(); + // MEG ONLY private final ConcurrentHashMap> driversCache = new ConcurrentHashMap<>(); public ModelManager(GeyserModelEngine plugin) { this.plugin = plugin; - } - public void create(ModeledEntity entity, ActiveModel model) { - ModelEntityData modelEntity = new ModelEntityData(plugin, entity, model); - int id = entity.getBase().getEntityId(); - - Map map = entitiesCache.computeIfAbsent(id, k -> new HashMap<>()); - - for (Map.Entry entry : map.entrySet()) { - if (entry.getKey() != model && entry.getKey().getBlueprint().getName().equals(model.getBlueprint().getName())) { - return; - } + if (Bukkit.getPluginManager().getPlugin("ModelEngine") != null) { + this.modelHandler = new ModelEngineHandler(); + plugin.getLogger().info("Using ModelEngine handler!"); + } else if (Bukkit.getPluginManager().getPlugin("BetterModel") != null) { + this.modelHandler = new BetterModelHandler(); + plugin.getLogger().info("Using BetterModel handler!"); + } else { + plugin.getLogger().severe("No supported model engine found!"); + plugin.getServer().getPluginManager().disablePlugin(plugin); + return; } - map.put(model, modelEntity); + modelHandler.loadListeners(plugin); } - public void processEntities(Entity entity) { - if (entitiesCache.containsKey(entity.getEntityId())) return; - - ModeledEntity modeledEntity = ModelEngineAPI.getModeledEntity(entity); - if (modeledEntity == null) return; - - Optional model = modeledEntity.getModels().values().stream().findFirst(); - model.ifPresent(m -> create(modeledEntity, m)); - } - - public void removeEntities() { - for (Map entities : entitiesCache.values()) { - entities.forEach((model, modelEntity) -> modelEntity.getEntity().remove()); - } + public ModelHandler getModelHandler() { + return modelHandler; } public HashSet getPlayerJoinedCache() { return playerJoinedCache; } - public ConcurrentHashMap> getEntitiesCache() { + public ConcurrentHashMap> getEntitiesCache() { return entitiesCache; } - public ConcurrentHashMap getModelEntitiesCache() { + public ConcurrentHashMap getModelEntitiesCache() { return modelEntitiesCache; } diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/entity/BetterModelEntityData.java b/src/main/java/re/imc/geysermodelengine/managers/model/entity/BetterModelEntityData.java new file mode 100644 index 0000000..192dd3d --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/entity/BetterModelEntityData.java @@ -0,0 +1,4 @@ +package re.imc.geysermodelengine.managers.model.entity; + +public class BetterModelEntityData { +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/entity/EntityData.java b/src/main/java/re/imc/geysermodelengine/managers/model/entity/EntityData.java new file mode 100644 index 0000000..22f70ef --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/entity/EntityData.java @@ -0,0 +1,20 @@ +package re.imc.geysermodelengine.managers.model.entity; + +import org.bukkit.entity.Player; +import re.imc.geysermodelengine.managers.model.model.Model; +import re.imc.geysermodelengine.packet.entity.PacketEntity; +import re.imc.geysermodelengine.runnables.EntityTaskRunnable; + +import java.util.Set; + +public interface EntityData { + + PacketEntity getEntity(); + Set getViewers(); + + void teleportToModel(); + + void remove(); + + EntityTaskRunnable getEntityTask(); +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/data/ModelEntityData.java b/src/main/java/re/imc/geysermodelengine/managers/model/entity/ModelEngineEntityData.java similarity index 72% rename from src/main/java/re/imc/geysermodelengine/managers/model/data/ModelEntityData.java rename to src/main/java/re/imc/geysermodelengine/managers/model/entity/ModelEngineEntityData.java index eadfd1b..5f2499d 100644 --- a/src/main/java/re/imc/geysermodelengine/managers/model/data/ModelEntityData.java +++ b/src/main/java/re/imc/geysermodelengine/managers/model/entity/ModelEngineEntityData.java @@ -1,4 +1,4 @@ -package re.imc.geysermodelengine.managers.model.data; +package re.imc.geysermodelengine.managers.model.entity; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import com.google.common.collect.Sets; @@ -7,16 +7,17 @@ import com.ticxo.modelengine.api.model.ModeledEntity; import org.bukkit.Location; import org.bukkit.entity.Player; import re.imc.geysermodelengine.GeyserModelEngine; +import re.imc.geysermodelengine.managers.model.model.Model; import re.imc.geysermodelengine.packet.entity.PacketEntity; import re.imc.geysermodelengine.runnables.EntityTaskRunnable; import java.util.Set; -public class ModelEntityData { +public class ModelEngineEntityData implements EntityData { private final GeyserModelEngine plugin; - private PacketEntity entity; + private final PacketEntity entity; private final Set viewers = Sets.newConcurrentHashSet(); @@ -26,38 +27,46 @@ public class ModelEntityData { private EntityTaskRunnable entityTask; - public ModelEntityData(GeyserModelEngine plugin, ModeledEntity modeledEntity, ActiveModel model) { + public ModelEngineEntityData(GeyserModelEngine plugin, ModeledEntity modeledEntity, ActiveModel activeModel) { this.plugin = plugin; this.modeledEntity = modeledEntity; - this.activeModel = model; - this.entity = spawnEntity(); + this.activeModel = activeModel; + this.entity = new PacketEntity(EntityTypes.PIG, viewers, modeledEntity.getBase().getLocation()); runEntityTask(); } + @Override public void teleportToModel() { Location location = modeledEntity.getBase().getLocation(); entity.teleport(location); } - public PacketEntity spawnEntity() { - entity = new PacketEntity(EntityTypes.PIG, viewers, modeledEntity.getBase().getLocation()); - return entity; - } - public void runEntityTask() { entityTask = new EntityTaskRunnable(plugin, this); } + @Override public PacketEntity getEntity() { return entity; } + @Override public Set getViewers() { return viewers; } + @Override + public void remove() { + + } + + @Override + public EntityTaskRunnable getEntityTask() { + return entityTask; + } + public ModeledEntity getModeledEntity() { return modeledEntity; } @@ -65,8 +74,4 @@ public class ModelEntityData { public ActiveModel getActiveModel() { return activeModel; } - - public EntityTaskRunnable getEntityTask() { - return entityTask; - } } diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/model/BetterModelModel.java b/src/main/java/re/imc/geysermodelengine/managers/model/model/BetterModelModel.java new file mode 100644 index 0000000..51bc102 --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/model/BetterModelModel.java @@ -0,0 +1,28 @@ +package re.imc.geysermodelengine.managers.model.model; + +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.modelhandler.ModelHandler; +import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; + +public class BetterModelModel implements Model { + + @Override + public String getName() { + return ""; + } + + @Override + public ModelHandler getModelHandler() { + return null; + } + + @Override + public EntityData getEntityData() { + return null; + } + + @Override + public PropertyHandler getPropertyHandler() { + return null; + } +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/model/Model.java b/src/main/java/re/imc/geysermodelengine/managers/model/model/Model.java new file mode 100644 index 0000000..6752878 --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/model/Model.java @@ -0,0 +1,14 @@ +package re.imc.geysermodelengine.managers.model.model; + +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.modelhandler.ModelHandler; +import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; + +public interface Model { + + String getName(); + + ModelHandler getModelHandler(); + EntityData getEntityData(); + PropertyHandler getPropertyHandler(); +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/model/ModelEngineModel.java b/src/main/java/re/imc/geysermodelengine/managers/model/model/ModelEngineModel.java new file mode 100644 index 0000000..edf32ee --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/model/ModelEngineModel.java @@ -0,0 +1,45 @@ +package re.imc.geysermodelengine.managers.model.model; + +import com.ticxo.modelengine.api.model.ActiveModel; +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.modelhandler.ModelHandler; +import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; + +public class ModelEngineModel implements Model { + + private final ActiveModel activeModel; + private final ModelHandler modelHandler; + private final EntityData entityData; + private final PropertyHandler propertyHandler; + + public ModelEngineModel(ActiveModel activeModel, ModelHandler modelHandler, EntityData entityData, PropertyHandler propertyHandler) { + this.activeModel = activeModel; + this.modelHandler = modelHandler; + this.entityData = entityData; + this.propertyHandler = propertyHandler; + } + + @Override + public String getName() { + return activeModel.getBlueprint().getName(); + } + + @Override + public ModelHandler getModelHandler() { + return modelHandler; + } + + @Override + public EntityData getEntityData() { + return entityData; + } + + @Override + public PropertyHandler getPropertyHandler() { + return propertyHandler; + } + + public ActiveModel getActiveModel() { + return activeModel; + } +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/BetterModelHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/BetterModelHandler.java new file mode 100644 index 0000000..d4b8f32 --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/BetterModelHandler.java @@ -0,0 +1,29 @@ +package re.imc.geysermodelengine.managers.model.modelhandler; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Entity; +import re.imc.geysermodelengine.GeyserModelEngine; +import re.imc.geysermodelengine.listener.BetterModelListener; + +public class BetterModelHandler implements ModelHandler { + + @Override + public void createModel(GeyserModelEngine plugin, Object modeledEntity, Object activeModel) { + + } + + @Override + public void processEntities(GeyserModelEngine plugin, Entity entity) { + + } + + @Override + public void removeEntities(GeyserModelEngine plugin) { + + } + + @Override + public void loadListeners(GeyserModelEngine plugin) { + Bukkit.getPluginManager().registerEvents(new BetterModelListener(plugin), plugin); + } +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelEngineHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelEngineHandler.java new file mode 100644 index 0000000..28e80a2 --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelEngineHandler.java @@ -0,0 +1,69 @@ +package re.imc.geysermodelengine.managers.model.modelhandler; + +import com.ticxo.modelengine.api.ModelEngineAPI; +import com.ticxo.modelengine.api.model.ActiveModel; +import com.ticxo.modelengine.api.model.ModeledEntity; +import kr.toxicity.model.api.data.raw.ModelData; +import org.bukkit.Bukkit; +import org.bukkit.entity.Entity; +import re.imc.geysermodelengine.GeyserModelEngine; +import re.imc.geysermodelengine.listener.ModelEngineListener; +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; +import re.imc.geysermodelengine.managers.model.model.Model; +import re.imc.geysermodelengine.managers.model.model.ModelEngineModel; +import re.imc.geysermodelengine.managers.model.propertyhandler.PropertyHandler; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class ModelEngineHandler implements ModelHandler { + + @Override + public void createModel(GeyserModelEngine plugin, Object modeledEntity, Object activeModel) { + ModeledEntity megEntity = (ModeledEntity) modeledEntity; + ActiveModel megActiveModel = (ActiveModel) activeModel; + + int entityID = megEntity.getBase().getEntityId(); + + PropertyHandler propertyHandler = plugin.getEntityTaskManager().getPropertyHandler(); + EntityData entityData = new ModelEngineEntityData(plugin, megEntity, megActiveModel); + + Model model = new ModelEngineModel(megActiveModel, this, entityData, propertyHandler); + + Map entityDataCache = plugin.getModelManager().getEntitiesCache().computeIfAbsent(entityID, k -> new HashMap<>()); + + for (Map.Entry entry : entityDataCache.entrySet()) { + if (entry.getKey() != model && entry.getKey().getName().equals(megActiveModel.getBlueprint().getName())) { + return; + } + } + + plugin.getModelManager().getModelEntitiesCache().put(entityID, model); + entityDataCache.put(model, entityData); + } + + @Override + public void processEntities(GeyserModelEngine plugin, Entity entity) { + if (plugin.getModelManager().getEntitiesCache().containsKey(entity.getEntityId())) return; + + ModeledEntity modeledEntity = ModelEngineAPI.getModeledEntity(entity); + if (modeledEntity == null) return; + + Optional model = modeledEntity.getModels().values().stream().findFirst(); + model.ifPresent(m -> createModel(plugin, modeledEntity, m)); + } + + @Override + public void removeEntities(GeyserModelEngine plugin) { + for (Map entities : plugin.getModelManager().getEntitiesCache().values()) { + entities.forEach((model, modelEntity) -> modelEntity.getEntity().remove()); + } + } + + @Override + public void loadListeners(GeyserModelEngine plugin) { + Bukkit.getPluginManager().registerEvents(new ModelEngineListener(plugin), plugin); + } +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelHandler.java new file mode 100644 index 0000000..0c4a2ae --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelHandler.java @@ -0,0 +1,16 @@ +package re.imc.geysermodelengine.managers.model.modelhandler; + +import org.bukkit.entity.Entity; +import re.imc.geysermodelengine.GeyserModelEngine; + +public interface ModelHandler { + + // Might do a hashmap way tbf + void createModel(GeyserModelEngine plugin, Object modeledEntity, Object activeModel); + + void processEntities(GeyserModelEngine plugin, Entity entity); + + void removeEntities(GeyserModelEngine plugin); + + void loadListeners(GeyserModelEngine plugin); +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/BetterModelPropertyHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/BetterModelPropertyHandler.java new file mode 100644 index 0000000..11389ef --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/BetterModelPropertyHandler.java @@ -0,0 +1,25 @@ +package re.imc.geysermodelengine.managers.model.propertyhandler; + +import org.bukkit.entity.Player; +import re.imc.geysermodelengine.managers.model.entity.EntityData; + +import java.awt.*; +import java.util.Collection; + +public class BetterModelPropertyHandler implements PropertyHandler { + + @Override + public void sendScale(EntityData modelData, Collection players, float lastScale, boolean firstSend) { + + } + + @Override + public void sendColor(EntityData modelData, Collection players, Color lastColor, boolean firstSend) { + + } + + @Override + public void sendHitBox(EntityData modelData, Player player) { + + } +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/ModelEnginePropertyHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/ModelEnginePropertyHandler.java new file mode 100644 index 0000000..c9dc034 --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/ModelEnginePropertyHandler.java @@ -0,0 +1,71 @@ +package re.imc.geysermodelengine.managers.model.propertyhandler; + +import com.ticxo.modelengine.api.model.ActiveModel; +import me.zimzaza4.geyserutils.spigot.api.EntityUtils; +import org.bukkit.entity.Player; +import org.joml.Vector3fc; +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; + +import java.awt.*; +import java.lang.reflect.Method; +import java.util.Collection; + +public class ModelEnginePropertyHandler implements PropertyHandler { + + private final Method scaleMethod; + + public ModelEnginePropertyHandler() { + try { + this.scaleMethod = ActiveModel.class.getMethod("getScale"); + } catch (NoSuchMethodException err) { + throw new RuntimeException(err); + } + } + + @Override + public void sendScale(EntityData modelData, Collection players, float lastScale, boolean firstSend) { + try { + if (players.isEmpty()) return; + + ModelEngineEntityData modelEngineEntityData = (ModelEngineEntityData) modelData; + + Vector3fc scale = (Vector3fc) scaleMethod.invoke(modelEngineEntityData.getActiveModel()); + + float average = (scale.x() + scale.y() + scale.z()) / 3; + + if (!firstSend) { + if (average == lastScale) return; + } + + for (Player player : players) { + EntityUtils.sendCustomScale(player, modelEngineEntityData.getEntity().getEntityId(), average); + } + } catch (Throwable ignored) {} + } + + @Override + public void sendColor(EntityData modelData, Collection players, Color lastColor, boolean firstSend) { + if (players.isEmpty()) return; + + ModelEngineEntityData modelEngineEntityData = (ModelEngineEntityData) modelData; + + Color color = new Color(modelEngineEntityData.getActiveModel().getDefaultTint().asARGB()); + if (modelEngineEntityData.getActiveModel().isMarkedHurt()) color = new Color(modelEngineEntityData.getActiveModel().getDamageTint().asARGB()); + + if (firstSend) { + if (color.equals(lastColor)) return; + } + + for (Player player : players) { + EntityUtils.sendCustomColor(player, modelEngineEntityData.getEntity().getEntityId(), color); + } + } + + @Override + public void sendHitBox(EntityData modelData, Player player) { + for (Player viewer : modelData.getViewers()) { + EntityUtils.sendCustomHitBox(viewer, modelData.getEntity().getEntityId(), 0.01f, 0.01f); + } + } +} diff --git a/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/PropertyHandler.java b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/PropertyHandler.java new file mode 100644 index 0000000..57248cc --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/PropertyHandler.java @@ -0,0 +1,16 @@ +package re.imc.geysermodelengine.managers.model.propertyhandler; + +import org.bukkit.entity.Player; +import re.imc.geysermodelengine.managers.model.entity.EntityData; + +import java.awt.*; +import java.util.Collection; + +public interface PropertyHandler { + + void sendScale(EntityData modelData, Collection players, float lastScale, boolean firstSend); + void sendColor(EntityData modelData, Collection players, Color lastColor, boolean firstSend); + void sendHitBox(EntityData modelData, Player player); + + +} diff --git a/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java b/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java index fd92295..3137622 100644 --- a/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java +++ b/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java @@ -11,7 +11,7 @@ import com.ticxo.modelengine.api.model.bone.ModelBone; import me.zimzaza4.geyserutils.spigot.api.EntityUtils; import org.bukkit.entity.Player; import re.imc.geysermodelengine.GeyserModelEngine; -import re.imc.geysermodelengine.managers.model.data.ModelEntityData; +import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; import re.imc.geysermodelengine.packet.entity.PacketEntity; import re.imc.geysermodelengine.util.BooleanPacker; @@ -26,7 +26,7 @@ public class EntityTaskRunnable { private final GeyserModelEngine plugin; - private final ModelEntityData model; + private final ModelEngineEntityData model; private int tick = 0; private int syncTick = 0; @@ -39,11 +39,9 @@ public class EntityTaskRunnable { private final ConcurrentHashMap lastIntSet = new ConcurrentHashMap<>(); private final Cache lastPlayedAnim = CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MILLISECONDS).build(); - private final BooleanPacker booleanPacker = new BooleanPacker(); - private final ScheduledFuture scheduledFuture; - public EntityTaskRunnable(GeyserModelEngine plugin, ModelEntityData model) { + public EntityTaskRunnable(GeyserModelEngine plugin, ModelEngineEntityData model) { this.plugin = plugin; this.model = model; @@ -70,7 +68,8 @@ public class EntityTaskRunnable { entity.remove(); plugin.getModelManager().getEntitiesCache().remove(modeledEntity.getBase().getEntityId()); - plugin.getModelManager().getModelEntitiesCache().remove(entity.getEntityId()); + plugin.getModelManager().getModelEntitiesCache().remove(modeledEntity.getBase().getEntityId()); + cancel(); return; } @@ -93,31 +92,32 @@ public class EntityTaskRunnable { if (viewers.isEmpty()) return; - plugin.getEntityTaskManager().sendScale(model, viewers, lastScale, false); - plugin.getEntityTaskManager().sendColor(model, viewers, lastColor, false); + plugin.getEntityTaskManager().getPropertyHandler().sendScale(model, viewers, lastScale, false); + plugin.getEntityTaskManager().getPropertyHandler().sendColor(model, viewers, lastColor, false); } public void cancel() { scheduledFuture.cancel(true); } - public void sendEntityData(ModelEntityData model, Player player, int delay) { + public void sendEntityData(ModelEngineEntityData model, Player player, int delay) { EntityUtils.setCustomEntity(player, model.getEntity().getEntityId(), plugin.getConfigManager().getConfig().getString("namespace") + ":" + model.getActiveModel().getBlueprint().getName().toLowerCase()); plugin.getSchedulerPool().schedule(() -> { model.getEntity().sendSpawnPacket(Collections.singletonList(player)); plugin.getSchedulerPool().schedule(() -> { - plugin.getEntityTaskManager().sendHitBox(model, player); - plugin.getEntityTaskManager().sendScale(model, Collections.singleton(player), lastScale, true); - plugin.getEntityTaskManager().sendColor(model, Collections.singleton(player), lastColor, true); + plugin.getEntityTaskManager().getPropertyHandler().sendHitBox(model, player); + + plugin.getEntityTaskManager().getPropertyHandler().sendScale(model, Collections.singleton(player), lastScale, true); + plugin.getEntityTaskManager().getPropertyHandler().sendColor(model, Collections.singleton(player), lastColor, true); updateEntityProperties(model, Collections.singleton(player), true); }, 500, TimeUnit.MILLISECONDS); }, delay * 50L, TimeUnit.MILLISECONDS); } - public void updateEntityProperties(ModelEntityData model, Collection players, boolean firstSend, String... forceAnims) { + public void updateEntityProperties(ModelEngineEntityData model, Collection players, boolean firstSend, String... forceAnims) { int entity = model.getEntity().getEntityId(); Set forceAnimSet = Set.of(forceAnims); @@ -163,13 +163,13 @@ public class EntityTaskRunnable { Map intUpdates = new HashMap<>(); int i = 0; - for (Integer integer : booleanPacker.mapBooleansToInts(boneUpdates)) { + for (Integer integer : BooleanPacker.mapBooleansToInts(boneUpdates)) { intUpdates.put(plugin.getConfigManager().getConfig().getString("namespace") + ":bone" + i, integer); i++; } i = 0; - for (Integer integer : booleanPacker.mapBooleansToInts(animUpdates)) { + for (Integer integer : BooleanPacker.mapBooleansToInts(animUpdates)) { intUpdates.put(plugin.getConfigManager().getConfig().getString("namespace") + ":anim" + i, integer); i++; } @@ -193,7 +193,7 @@ public class EntityTaskRunnable { } } - private void processBone(ModelEntityData model, BlueprintBone bone, Map map) { + private void processBone(ModelEngineEntityData model, BlueprintBone bone, Map map) { String name = plugin.getEntityTaskManager().unstripName(bone).toLowerCase(); if (name.equals("hitbox") || name.equals("shadow") || diff --git a/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java b/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java index 015682b..7d06be9 100644 --- a/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java +++ b/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java @@ -1,9 +1,10 @@ package re.imc.geysermodelengine.runnables; -import com.ticxo.modelengine.api.model.ActiveModel; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import re.imc.geysermodelengine.GeyserModelEngine; -import re.imc.geysermodelengine.managers.model.data.ModelEntityData; +import re.imc.geysermodelengine.managers.model.entity.EntityData; +import re.imc.geysermodelengine.managers.model.entity.ModelEngineEntityData; +import re.imc.geysermodelengine.managers.model.model.Model; import java.util.Map; import java.util.function.Consumer; @@ -19,8 +20,8 @@ public class UpdateTaskRunnable implements Consumer { @Override public void accept(ScheduledTask scheduledTask) { try { - for (Map models : plugin.getModelManager().getEntitiesCache().values()) { - models.values().forEach(model -> model.getEntityTask().updateEntityProperties(model, model.getViewers(), false)); + for (Map models : plugin.getModelManager().getEntitiesCache().values()) { + models.values().forEach(model -> model.getEntityTask().updateEntityProperties((ModelEngineEntityData) model, model.getViewers(), false)); } } catch (Throwable err) { throw new RuntimeException(err); diff --git a/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java b/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java index 5692a9d..ee2fe85 100644 --- a/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java +++ b/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java @@ -7,9 +7,9 @@ import java.util.Map; public class BooleanPacker { - private final int MAX_BOOLEANS = 24; + private static final int MAX_BOOLEANS = 24; - public int booleansToInt(List booleans) { + public static int booleansToInt(List booleans) { int result = 0; int i = 1; @@ -23,7 +23,7 @@ public class BooleanPacker { return result; } - public int mapBooleansToInt(Map booleanMap) { + public static int mapBooleansToInt(Map booleanMap) { int result = 0; int i = 1; @@ -39,7 +39,7 @@ public class BooleanPacker { return result; } - public List booleansToInts(List booleans) { + public static List booleansToInts(List booleans) { List results = new ArrayList<>(); int result = 0; int i = 1; @@ -62,7 +62,7 @@ public class BooleanPacker { return results; } - public List mapBooleansToInts(Map booleanMap) { + public static List mapBooleansToInts(Map booleanMap) { List keys = new ArrayList<>(booleanMap.keySet()); List booleans = new ArrayList<>(); diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml index 015a6c6..ac71c2f 100644 --- a/src/main/resources/paper-plugin.yml +++ b/src/main/resources/paper-plugin.yml @@ -15,7 +15,11 @@ dependencies: required: true packetevents: required: true - ModelEngine: - required: true floodgate: - required: true \ No newline at end of file + required: true + ModelEngine: + required: false + join-classpath: true + BetterModel: + required: false + join-classpath: true \ No newline at end of file