diff --git a/README_EN.md b/README_EN.md index 8af8718..7d5d976 100644 --- a/README_EN.md +++ b/README_EN.md @@ -21,7 +21,9 @@ Download the following plugins according to the server core | GeyserCustomEntity Fork | [Github](https://github.com/zimzaza4/Geyser) | Make Geyser support custom entities | | GeyserModelEnginePackGenerator | [Github](https://github.com/zimzaza4/GeyserModelEnginePackGenerator) | Help you automatically transform the model to generate resource packs | -place `GeyserModelEngine` `GeyserCustomEntityFork` in the plugins folder +replace your Geyser with that Geyser fork + +put `GeyserModelEngine` in the plugins folder (only spigot) and `geyserutils-spigot`/`velocity`/`bungeecord` diff --git a/libs/geyserutils-spigot-1.0-SNAPSHOT.jar b/libs/geyserutils-spigot-1.0-SNAPSHOT.jar index d5781c3..ec7de3a 100644 Binary files a/libs/geyserutils-spigot-1.0-SNAPSHOT.jar and b/libs/geyserutils-spigot-1.0-SNAPSHOT.jar differ diff --git a/pom.xml b/pom.xml index 4210fee..dc30351 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,7 @@ me.zimzaza4 geyserutils-spigot - 1.0.1 + 1.0.0 system ${project.basedir}/libs/geyserutils-spigot-1.0-SNAPSHOT.jar @@ -122,12 +122,6 @@ 2.2.2-SNAPSHOT provided - - LibsDisguises - LibsDisguises - 10.0.35 - provided - com.comphenix.protocol ProtocolLib diff --git a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java index 30a02a8..ef7814c 100644 --- a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java +++ b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java @@ -1,12 +1,15 @@ package re.imc.geysermodelengine; import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.wrappers.Pair; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; 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 lombok.Getter; +import lombok.Setter; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Entity; @@ -14,12 +17,13 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import re.imc.geysermodelengine.listener.AddEntityPacketListener; -import re.imc.geysermodelengine.listener.InteractPacketListener; import re.imc.geysermodelengine.listener.ModelListener; +import re.imc.geysermodelengine.listener.MountPacketListener; import re.imc.geysermodelengine.model.ModelEntity; import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; public final class GeyserModelEngine extends JavaPlugin { @@ -42,9 +46,27 @@ public final class GeyserModelEngine extends JavaPlugin { @Getter private Cache joinedPlayer; + @Getter + @Setter + private boolean spawningModelEntity = false; + + + @Getter + @Setter + private ModelEntity currentModel = null; + + @Getter private int joinSendDelay; + @Getter + private boolean debug; + + @Getter + private Map> drivers = new ConcurrentHashMap<>(); + + @Getter + private boolean initialized = false; @Override public void onEnable() { // Plugin startup logic @@ -52,6 +74,7 @@ public final class GeyserModelEngine extends JavaPlugin { // alwaysSendSkin = getConfig().getBoolean("always-send-skin"); skinSendDelay = getConfig().getInt("skin-send-delay", 0); viewDistance = getConfig().getInt("skin-view-distance", 60); + debug = getConfig().getBoolean("debug", false); modelEntityType = EntityType.valueOf(getConfig().getString("model-entity-type", "BAT")); joinSendDelay = getConfig().getInt("join-send-delay", 20); if (joinSendDelay > 0) { @@ -59,8 +82,8 @@ public final class GeyserModelEngine extends JavaPlugin { .expireAfterWrite(joinSendDelay * 50L, TimeUnit.MILLISECONDS).build(); } instance = this; - ProtocolLibrary.getProtocolManager().addPacketListener(new InteractPacketListener()); ProtocolLibrary.getProtocolManager().addPacketListener(new AddEntityPacketListener()); + ProtocolLibrary.getProtocolManager().addPacketListener(new MountPacketListener()); Bukkit.getPluginManager().registerEvents(new ModelListener(), this); Bukkit.getScheduler() @@ -76,6 +99,7 @@ public final class GeyserModelEngine extends JavaPlugin { } } } + initialized = true; }, 100); } diff --git a/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java b/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java index 2bb30ee..fb22064 100644 --- a/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java +++ b/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java @@ -1,16 +1,28 @@ package re.imc.geysermodelengine.listener; import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.events.*; import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.wrappers.WrappedWatchableObject; +import com.ticxo.modelengine.api.ModelEngineAPI; import com.ticxo.modelengine.api.entity.BukkitEntity; +import com.ticxo.modelengine.api.entity.Hitbox; +import com.ticxo.modelengine.api.interaction.DynamicHitbox; +import com.ticxo.modelengine.api.interaction.InteractionTracker; +import com.ticxo.modelengine.api.model.bone.type.SubHitbox; +import com.ticxo.modelengine.api.nms.entity.HitboxEntity; +import org.bukkit.Bukkit; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.geysermc.floodgate.api.FloodgateApi; import org.jetbrains.annotations.NotNull; import re.imc.geysermodelengine.GeyserModelEngine; +import re.imc.geysermodelengine.model.EntityTask; import re.imc.geysermodelengine.model.ModelEntity; import java.util.Set; +import java.util.UUID; public class AddEntityPacketListener extends PacketAdapter { public AddEntityPacketListener() { @@ -19,21 +31,49 @@ public class AddEntityPacketListener extends PacketAdapter { @Override public void onPacketSending(PacketEvent event) { + PacketContainer packet = event.getPacket(); StructureModifier modifier = packet.getEntityModifier(event); Entity entity = modifier.readSafely(0); + if (entity == null) { return; } + boolean isBedrock = FloodgateApi.getInstance().isFloodgatePlayer(event.getPlayer().getUniqueId()); ModelEntity model = ModelEntity.MODEL_ENTITIES.get(entity.getEntityId()); + if (model != null) { - if (FloodgateApi.getInstance().isFloodgatePlayer(event.getPlayer().getUniqueId())) { - if (GeyserModelEngine.getInstance().getJoinedPlayer() != null && GeyserModelEngine.getInstance().getJoinedPlayer().getIfPresent(event.getPlayer()) != null) { - model.getTask().sendEntityData(event.getPlayer(), GeyserModelEngine.getInstance().getJoinSendDelay()); - } else { - model.getTask().sendEntityData(event.getPlayer(), GeyserModelEngine.getInstance().getSkinSendDelay()); + if (isBedrock) { + if (packet.getMeta("delayed").isPresent()) { + if (model.getTask().isLooping()) { + + String lastAnimation = model.getTask().getLastAnimation(); + model.getTask().playBedrockAnimation(lastAnimation, Set.of(event.getPlayer()), true, 0f); + } + return; } + + EntityTask task = model.getTask(); + int delay = 1; + boolean firstJoined = GeyserModelEngine.getInstance().getJoinedPlayer().getIfPresent(event.getPlayer()) != null; + if (firstJoined) { + delay = GeyserModelEngine.getInstance().getJoinSendDelay(); + } + if (task == null || firstJoined) { + Bukkit.getScheduler().runTaskLater(GeyserModelEngine.getInstance(), () -> { + model.getTask().sendEntityData(event.getPlayer(), GeyserModelEngine.getInstance().getSkinSendDelay()); + }, delay); + } else { + task.sendEntityData(event.getPlayer(), GeyserModelEngine.getInstance().getSkinSendDelay()); + } + + event.setCancelled(true); + + Bukkit.getScheduler().runTaskLater(GeyserModelEngine.getInstance(), () -> { + packet.setMeta("delayed", 1); + ProtocolLibrary.getProtocolManager().sendServerPacket(event.getPlayer(), packet); + }, delay + 2); } else { event.setCancelled(true); } diff --git a/src/main/java/re/imc/geysermodelengine/listener/InteractPacketListener.java b/src/main/java/re/imc/geysermodelengine/listener/InteractPacketListener.java deleted file mode 100644 index 596286f..0000000 --- a/src/main/java/re/imc/geysermodelengine/listener/InteractPacketListener.java +++ /dev/null @@ -1,39 +0,0 @@ -package re.imc.geysermodelengine.listener; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.events.*; -import com.comphenix.protocol.reflect.StructureModifier; -import com.ticxo.modelengine.api.entity.BukkitEntity; -import com.ticxo.modelengine.api.entity.BukkitPlayer; -import org.bukkit.entity.Entity; -import re.imc.geysermodelengine.GeyserModelEngine; -import re.imc.geysermodelengine.model.ModelEntity; - -import java.util.Set; - -public class InteractPacketListener extends PacketAdapter { - public InteractPacketListener() { - super(GeyserModelEngine.getInstance(), ListenerPriority.HIGHEST, Set.of(PacketType.Play.Client.USE_ENTITY), ListenerOptions.SYNC); - } - - - @Override - public void onPacketReceiving(PacketEvent event) { - PacketContainer packet = event.getPacket(); - StructureModifier modifier = packet.getEntityModifier(event); - Entity entity = modifier.readSafely(0); - if (entity == null) { - return; - } - ModelEntity model = ModelEntity.MODEL_ENTITIES.get(entity.getEntityId()); - - if (model != null && model.getModeledEntity().getBase() instanceof BukkitEntity bukkitEntity) { - modifier.writeSafely(0, bukkitEntity.getOriginal()); - - event.setPacket(packet); - } - - } - - -} diff --git a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java index 3b0c2a9..0706c72 100644 --- a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java +++ b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java @@ -1,28 +1,36 @@ package re.imc.geysermodelengine.listener; +import com.comphenix.protocol.wrappers.Pair; +import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; import com.ticxo.modelengine.api.ModelEngineAPI; -import com.ticxo.modelengine.api.events.AddModelEvent; -import com.ticxo.modelengine.api.events.AnimationEndEvent; -import com.ticxo.modelengine.api.events.AnimationPlayEvent; -import com.ticxo.modelengine.api.events.RemoveModelEvent; +import com.ticxo.modelengine.api.events.*; +import com.ticxo.modelengine.api.generator.blueprint.ModelBlueprint; import com.ticxo.modelengine.api.model.ActiveModel; import com.ticxo.modelengine.api.model.ModeledEntity; +import com.ticxo.modelengine.api.model.render.ModelRenderer; +import me.zimzaza4.geyserutils.spigot.api.PlayerUtils; import org.bukkit.Bukkit; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.entity.*; import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.world.EntitiesLoadEvent; import org.bukkit.metadata.FixedMetadataValue; +import org.geysermc.floodgate.api.FloodgateApi; import re.imc.geysermodelengine.GeyserModelEngine; import re.imc.geysermodelengine.model.EntityTask; import re.imc.geysermodelengine.model.ModelEntity; import java.util.Map; import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; public class ModelListener implements Listener { @@ -32,36 +40,50 @@ public class ModelListener implements Listener { return; } + if (!GeyserModelEngine.getInstance().isInitialized()) { + return; + } + Bukkit.getScheduler().runTask(GeyserModelEngine.getInstance(), () -> { ModelEntity.create(event.getTarget(), event.getModel()); }); } + + @EventHandler public void onRemoveModel(RemoveModelEvent event) { - event.getTarget().getBase(); - } - @EventHandler - public void onEntityLoad(EntitiesLoadEvent event) { - Bukkit.getScheduler() - .runTaskLater(GeyserModelEngine.getInstance(), () -> { - for (Entity entity : event.getEntities()) { - if (!ModelEntity.ENTITIES.containsKey(entity.getEntityId())) { - ModeledEntity modeledEntity = ModelEngineAPI.getModeledEntity(entity); - if (modeledEntity != null) { - Optional model = modeledEntity.getModels().values().stream().findFirst(); - model.ifPresent(m -> ModelEntity.create(modeledEntity, m)); - } - } - } + @EventHandler(priority = EventPriority.MONITOR) + public void onModelMount(ModelMountEvent event) { + Map map = ModelEntity.ENTITIES.get(event.getVehicle().getModeledEntity().getBase().getEntityId()); + if (map == null) { + return; + } + if (!event.isDriver()) { + return; + } + ModelEntity model = map.get(event.getVehicle()); - }, 20); + if (model != null && event.getPassenger() instanceof Player player) { + GeyserModelEngine.getInstance().getDrivers().put(player, new Pair<>(event.getVehicle(), event.getSeat())); + } } + @EventHandler(priority = EventPriority.MONITOR) + public void onModelDismount(ModelDismountEvent event) { + if (event.getPassenger() instanceof Player player) { + GeyserModelEngine.getInstance().getDrivers().remove(player); + } + } + + @EventHandler public void onAnimationPlay(AnimationPlayEvent event) { + if (event.getModel().getModeledEntity() == null) { + return; + } Map map = ModelEntity.ENTITIES.get(event.getModel().getModeledEntity().getBase().getEntityId()); if (map == null) { return; @@ -91,6 +113,29 @@ public class ModelListener implements Listener { } } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onModelEntitySpawn(EntitySpawnEvent event) { + if (GeyserModelEngine.getInstance().isSpawningModelEntity() && event.getEntity() instanceof LivingEntity entity) { + if (event.isCancelled()) { + event.setCancelled(false); + } + ModelEntity model = GeyserModelEngine.getInstance().getCurrentModel(); + int id = entity.getEntityId(); + ActiveModel activeModel = model.getActiveModel(); + ModelEntity.MODEL_ENTITIES.put(id, model); + model.applyFeatures(entity, "model." + activeModel.getBlueprint().getName()); + GeyserModelEngine.getInstance().setCurrentModel(null); + GeyserModelEngine.getInstance().setSpawningModelEntity(false); + + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + if (FloodgateApi.getInstance().isFloodgatePlayer(onlinePlayer.getUniqueId())) { + PlayerUtils.setCustomEntity(onlinePlayer, entity.getEntityId(), "modelengine:" + model.getActiveModel().getBlueprint().getName().toLowerCase()); + } + } + } + } + @EventHandler public void onModelEntityHurt(EntityDamageEvent event) { Map model = ModelEntity.ENTITIES.get(event.getEntity().getEntityId()); @@ -143,4 +188,9 @@ public class ModelListener implements Listener { public void onPlayerJoin(PlayerJoinEvent event) { GeyserModelEngine.getInstance().getJoinedPlayer().put(event.getPlayer(), true); } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + GeyserModelEngine.getInstance().getDrivers().remove(event.getPlayer()); + } } diff --git a/src/main/java/re/imc/geysermodelengine/listener/MountPacketListener.java b/src/main/java/re/imc/geysermodelengine/listener/MountPacketListener.java new file mode 100644 index 0000000..7d1dbb7 --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/listener/MountPacketListener.java @@ -0,0 +1,66 @@ +package re.imc.geysermodelengine.listener; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.ListenerOptions; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.wrappers.EnumWrappers; +import com.comphenix.protocol.wrappers.Pair; +import com.ticxo.modelengine.api.ModelEngineAPI; +import com.ticxo.modelengine.api.model.ActiveModel; +import com.ticxo.modelengine.api.model.bone.type.Mount; +import org.geysermc.floodgate.api.FloodgateApi; +import re.imc.geysermodelengine.GeyserModelEngine; + +import java.util.Set; + +public class MountPacketListener extends PacketAdapter { + public MountPacketListener() { + super(GeyserModelEngine.getInstance(), ListenerPriority.HIGHEST, Set.of(PacketType.Play.Client.STEER_VEHICLE, PacketType.Play.Client.ENTITY_ACTION), ListenerOptions.SYNC); + } + + @Override + public void onPacketReceiving(PacketEvent event) { + if (!FloodgateApi.getInstance().isFloodgatePlayer(event.getPlayer().getUniqueId())) { + return; + } + + if (event.getPacket().getType() == PacketType.Play.Client.STEER_VEHICLE) { + Pair seat = GeyserModelEngine.getInstance().getDrivers().get(event.getPlayer()); + if (seat != null) { + float pitch = event.getPlayer().getPitch(); + if (seat.getFirst().getModeledEntity().getBase().isFlying()) { + if (pitch < -30) { + event.getPacket().getBooleans().writeSafely(0, true); + } + if (pitch > 45) { + event.getPacket().getBooleans().writeSafely(1, true); + } + } else { + if (event.getPlayer().getInventory().getHeldItemSlot() == 0) { + event.getPacket().getBooleans().writeSafely(0, true); + event.getPlayer().getInventory().setHeldItemSlot(3); + event.getPlayer().sendActionBar("jump"); + } + if (pitch > 89 || event.getPlayer().getInventory().getHeldItemSlot() == 1) { + event.getPacket().getBooleans().writeSafely(1, true); + event.getPlayer().sendActionBar("shift"); + } + if (event.getPlayer().getInventory().getHeldItemSlot() == 8) { + event.getPacket().getBooleans().writeSafely(0, true); + event.getPlayer().sendActionBar("hold jump"); + } + } + } + } else { + Pair seat = GeyserModelEngine.getInstance().getDrivers().get(event.getPlayer()); + if (seat != null) { + if (event.getPacket().getPlayerActions().read(0) == EnumWrappers.PlayerAction.START_SNEAKING) { + event.getPlayer().sendActionBar("leave"); + ModelEngineAPI.getMountPairManager().tryDismount(event.getPlayer()); + } + } + } + } +} diff --git a/src/main/java/re/imc/geysermodelengine/model/EntityTask.java b/src/main/java/re/imc/geysermodelengine/model/EntityTask.java index 4c6c473..452d54c 100644 --- a/src/main/java/re/imc/geysermodelengine/model/EntityTask.java +++ b/src/main/java/re/imc/geysermodelengine/model/EntityTask.java @@ -17,6 +17,7 @@ import org.bukkit.util.BoundingBox; import org.geysermc.floodgate.api.FloodgateApi; import org.jetbrains.annotations.NotNull; import re.imc.geysermodelengine.GeyserModelEngine; +import re.imc.geysermodelengine.listener.ModelListener; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -38,9 +39,10 @@ public class EntityTask { boolean firstAnimation = true; boolean spawnAnimationPlayed = false; + boolean removed = false; String lastAnimation = ""; - boolean looping = false; + boolean looping = true; private BukkitRunnable syncTask; @@ -59,14 +61,16 @@ public class EntityTask { } if (syncTick % 5 == 0) { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { if (!FloodgateApi.getInstance().isFloodgatePlayer(onlinePlayer.getUniqueId())) { onlinePlayer.hideEntity(GeyserModelEngine.getInstance(), model.getEntity()); } } } - if (model.getEntity().isDead()) { - model.spawnEntity(); + + if (!removed && model.getEntity().isDead() && model.getModeledEntity().getBase().isAlive() && !model.getActiveModel().isRemoved()) { + // model.spawnEntity(); } model.getEntity().setVisualFire(false); @@ -74,37 +78,55 @@ public class EntityTask { } public void runAsync() { Entity entity = model.getEntity(); + if (entity.isDead()) { + return; + } Set viewers = model.getViewers(); ActiveModel activeModel = model.getActiveModel(); ModeledEntity modeledEntity = model.getModeledEntity(); - if (modeledEntity.isDestroyed() || !modeledEntity.getBase().isAlive()) { - if (!modeledEntity.isDestroyed() && !modeledEntity.getBase().isAlive()) { - - String animation = hasAnimation("death") ? "death" : "idle"; - new BukkitRunnable() { - @Override - public void run() { - entity.remove(); - } - }.runTaskLater(GeyserModelEngine.getInstance(), Math.max(playAnimation(animation, 99) - 1, 0)); - + if (activeModel.isRemoved() || !modeledEntity.getBase().isAlive()) { + if (!activeModel.isRemoved() && hasAnimation("death")) { + new BukkitRunnable() { + @Override + public void run() { + removed = true; + entity.remove(); + } + }.runTaskLater(GeyserModelEngine.getInstance(), Math.min(Math.max(playAnimation("death", 999, 5f, true) - 3, 0), 200)); + } else { + new BukkitRunnable() { + @Override + public void run() { + removed = true; + entity.remove(); + } + }.runTask(GeyserModelEngine.getInstance()); } - ENTITIES.remove(modeledEntity.getBase().getEntityId()); - MODEL_ENTITIES.remove(entity.getEntityId()); - cancel(); - return; - } - if (model.getEntity().isDead()) { + ENTITIES.remove(modeledEntity.getBase().getEntityId()); MODEL_ENTITIES.remove(entity.getEntityId()); cancel(); return; } /* + if (model.getEntity().isDead()) { + ENTITIES.remove(modeledEntity.getBase().getEntityId()); + MODEL_ENTITIES.remove(entity.getEntityId()); + cancel(); + return; + } + + */ + /* if (waitingTick > 0) { waitingTick--; } */ + + if (!spawnAnimationPlayed) { + spawnAnimationPlayed = true; + } + if (tick > 1 && tick % 5 == 0) { for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { @@ -133,16 +155,6 @@ public class EntityTask { } } - - - if (!spawnAnimationPlayed) { - spawnAnimationPlayed = true; - if (hasAnimation("spawn")) { - playAnimation("spawn", 99); - } else { - playAnimation("idle", 0); - } - } if (tick % 40 == 0) { for (Player viewer : Set.copyOf(viewers)) { @@ -190,32 +202,36 @@ public class EntityTask { } public void sendEntityData(Player player, int delay) { + // System.out.println("TYPE: " + "modelengine:" + model.getActiveModel().getBlueprint().getName().toLowerCase()); + PlayerUtils.setCustomEntity(player, model.getEntity().getEntityId(), "modelengine:" + model.getActiveModel().getBlueprint().getName().toLowerCase()); + Bukkit.getScheduler().runTaskLaterAsynchronously(GeyserModelEngine.getInstance(), () -> { - PlayerUtils.sendCustomSkin(player, model.getEntity(), model.getActiveModel().getBlueprint().getName()); - playBedrockAnimation("animation." + model.getActiveModel().getBlueprint().getName() + "." + lastAnimation, looping); + // PlayerUtils.sendCustomSkin(player, model.getEntity(), model.getActiveModel().getBlueprint().getName()); + if (looping) { + playBedrockAnimation(lastAnimation, Set.of(player), looping, 0f); + } sendHitBox(player); + sendScale(player); Bukkit.getScheduler().runTaskLaterAsynchronously(GeyserModelEngine.getInstance(), () -> { sendHitBox(player); }, 8); }, delay); } + + public void sendScale(Player player) { + // todo? + } + public void sendHitBoxToAll() { for (Player viewer : model.getViewers()) { - if (model.getModeledEntity().getBase() instanceof BukkitEntity bukkitEntity) { - @NotNull BoundingBox box = bukkitEntity.getOriginal().getBoundingBox(); - PlayerUtils.sendCustomHitBox(viewer, model.getEntity(), (float) box.getHeight(), (float) ((box.getWidthX() + box.getWidthZ()) / 2f)); - // huh i dont know how to deal with width - } + PlayerUtils.sendCustomHitBox(viewer, model.getEntity(), 0.01f, 0.01f); } } public void sendHitBox(Player viewer) { - if (model.getModeledEntity().getBase() instanceof BukkitEntity bukkitEntity) { - @NotNull BoundingBox box = bukkitEntity.getOriginal().getBoundingBox(); - PlayerUtils.sendCustomHitBox(viewer, model.getEntity(), (float) box.getHeight(), (float) ((box.getWidthX() + box.getWidthZ()) / 2f)); - // huh i dont know how to deal with width - } + PlayerUtils.sendCustomHitBox(viewer, model.getEntity(), 0.01f, 0.01f); + } public boolean hasAnimation(String animation) { @@ -223,7 +239,11 @@ public class EntityTask { BlueprintAnimation animationProperty = activeModel.getBlueprint().getAnimations().get(animation); return !(animationProperty == null); } + public int playAnimation(String animation, int p) { + return playAnimation(animation, p, 0, false); + } + public int playAnimation(String animation, int p, float blendTime, boolean forceLoop) { ActiveModel activeModel = model.getActiveModel(); @@ -248,7 +268,7 @@ public class EntityTask { firstAnimation = false; } boolean lastLoopState = looping; - looping = animationProperty.getLoopMode() == BlueprintAnimation.LoopMode.LOOP;; + looping = forceLoop || animationProperty.getLoopMode() == BlueprintAnimation.LoopMode.LOOP;; if (lastAnimation.equals(animation)) { if (looping) { @@ -258,6 +278,7 @@ public class EntityTask { } + if (play) { currentAnimationPriority.set(p); @@ -266,14 +287,14 @@ public class EntityTask { // delaySend = true; } - String id = "animation." + activeModel.getBlueprint().getName() + "." + animationProperty.getName(); + String id = "animation." + activeModel.getBlueprint().getName().toLowerCase() + "." + animationProperty.getName().toLowerCase(); lastAnimation = id; animationCooldown.set((int) (animationProperty.getLength() * 20)); if (delaySend) { - Bukkit.getScheduler().runTaskLaterAsynchronously(GeyserModelEngine.getInstance(), () -> playBedrockAnimation("animation." + activeModel.getBlueprint().getName() + "." + animationProperty.getName(), looping), 2); + Bukkit.getScheduler().runTaskLaterAsynchronously(GeyserModelEngine.getInstance(), () -> playBedrockAnimation(id, model.getViewers(), looping, blendTime), 0); } else { - playBedrockAnimation(id, looping); + playBedrockAnimation(id, model.getViewers(), looping, blendTime); } } return animationCooldown.get(); @@ -308,17 +329,15 @@ public class EntityTask { */ - private void playBedrockAnimation(String animationId, boolean loop) { + public void playBedrockAnimation(String animationId, Set viewers, boolean loop, float blendTime) { // model.getViewers().forEach(viewer -> viewer.sendActionBar("CURRENT AN:" + animationId)); Entity entity = model.getEntity(); - Set viewers = model.getViewers(); Animation.AnimationBuilder animation = Animation.builder() .animation(animationId) - .blendOutTime(0f) - .controller("controller.animation.armor_stand.wiggle"); + .blendOutTime(blendTime); if (loop) { animation.nextState(animationId); @@ -363,6 +382,17 @@ public class EntityTask { } public void run(GeyserModelEngine instance, int i) { + + String id = ""; + ActiveModel activeModel = model.getActiveModel(); + if (hasAnimation("spawn")) { + id = "animation." + activeModel.getBlueprint().getName().toLowerCase() + ".spawn"; + } else { + id = "animation." + activeModel.getBlueprint().getName().toLowerCase() + ".idle"; + } + + lastAnimation = id; + sendHitBoxToAll(); syncTask = new BukkitRunnable() { @Override public void run() { diff --git a/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java b/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java index 31b4b0b..1025ddb 100644 --- a/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java +++ b/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java @@ -1,23 +1,21 @@ package re.imc.geysermodelengine.model; import com.google.common.collect.Sets; +import com.ticxo.modelengine.api.ModelEngineAPI; import com.ticxo.modelengine.api.entity.BukkitEntity; import com.ticxo.modelengine.api.model.ActiveModel; import com.ticxo.modelengine.api.model.ModeledEntity; import lombok.Getter; -import me.libraryaddict.disguise.DisguiseAPI; -import me.libraryaddict.disguise.disguisetypes.PlayerDisguise; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.geysermc.floodgate.api.FloodgateApi; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.util.Vector; import re.imc.geysermodelengine.GeyserModelEngine; import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @Getter @@ -54,9 +52,12 @@ public class ModelEntity { for (Player viewer : viewers) { viewer.sendActionBar("X:" + modeledEntity.getXHeadRot() + ", Y:" + modeledEntity.getYHeadRot()); } - */ - entity.teleportAsync(location); + */ + Vector vector = modeledEntity.getBase().getMoveController().getVelocity(); + ModelEngineAPI.getEntityHandler().setPosition(entity, location.getX(), location.getY(), location.getZ()); + // ModelEngineAPI.getEntityHandler().movePassenger(entity, location.getX(), location.getY(), location.getZ()); + controllerEntity.getMoveController().setVelocity(vector.getX(), vector.getY(), vector.getZ()); if (modeledEntity.getBase() instanceof BukkitEntity bukkitEntity && bukkitEntity.getOriginal() instanceof LivingEntity livingEntity) { controllerEntity.getLookController().setHeadYaw(livingEntity.getEyeLocation().getYaw()); controllerEntity.getLookController().setPitch(livingEntity.getEyeLocation().getPitch()); @@ -68,17 +69,23 @@ public class ModelEntity { ModelEntity modelEntity = new ModelEntity(entity, model); int id = entity.getBase().getEntityId(); Map map = ENTITIES.computeIfAbsent(id, k -> new HashMap<>()); + for (Map.Entry entry : map.entrySet()) { + if (entry.getKey() != model && entry.getKey().getBlueprint().getName().equals(model.getBlueprint().getName())) { + return null; + } + } map.put(model, modelEntity); return modelEntity; } public LivingEntity spawnEntity() { - entity = (LivingEntity) modeledEntity.getBase().getLocation().getWorld().spawnEntity(modeledEntity.getBase().getLocation(), GeyserModelEngine.getInstance().getModelEntityType()); - applyFeatures(entity, "model." + activeModel.getBlueprint().getName()); ModelEntity model = this; - int id = entity.getEntityId(); - MODEL_ENTITIES.put(id, model); + // int lastEntityId = ReflectionManager.getNewEntityId(); + // System.out.println("RID:" + entityId); + GeyserModelEngine.getInstance().setSpawningModelEntity(true); + GeyserModelEngine.getInstance().setCurrentModel(model); + entity = (LivingEntity) modeledEntity.getBase().getLocation().getWorld().spawnEntity(modeledEntity.getBase().getLocation(), GeyserModelEngine.getInstance().getModelEntityType()); controllerEntity = new BukkitEntity(entity); return entity; } @@ -89,11 +96,11 @@ public class ModelEntity { } - private void applyFeatures(LivingEntity display, String name) { + public void applyFeatures(LivingEntity display, String name) { display.setGravity(false); display.setMaxHealth(2048); display.setHealth(2048); - + display.setMetadata("model_entity", new FixedMetadataValue(GeyserModelEngine.getInstance(), true)); //display.setInvulnerable(true); @@ -102,15 +109,17 @@ public class ModelEntity { display.setPersistent(false); // armorStand.setVisible(false); + + /* String uuid = UUID.randomUUID().toString(); - PlayerDisguise disguise = new PlayerDisguise(name + "_" + uuid); + MobDisguise disguise = new MobDisguise(DisguiseType.getType(entity.getType())); + disguise.setDisguiseName(uuid); - DisguiseAPI.disguiseEntity(display, disguise.setNameVisible(false)); + DisguiseAPI.disguiseEntity(display, disguise); + */ } - - } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a1a80e5..eee40f1 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,4 +1,5 @@ skin-send-delay: 0 skin-view-distance: 50 join-send-delay: 20 -model-entity-type: BAT # must be a living entity \ No newline at end of file +model-entity-type: BAT # must be a living entity +debug: false \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 2cbdd53..c7c9df6 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,5 +4,4 @@ main: re.imc.geysermodelengine.GeyserModelEngine api-version: '1.19' depend: - ModelEngine - - LibsDisguises - floodgate \ No newline at end of file