diff --git a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java index 9d76dcf..49b3fed 100644 --- a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java +++ b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java @@ -1,11 +1,14 @@ 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.google.common.collect.Sets; 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; @@ -16,10 +19,14 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import re.imc.geysermodelengine.listener.AddEntityPacketListener; import re.imc.geysermodelengine.listener.ModelListener; +import re.imc.geysermodelengine.listener.MountPacketListener; import re.imc.geysermodelengine.model.ModelEntity; +import java.util.HashSet; import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; public final class GeyserModelEngine extends JavaPlugin { @@ -55,6 +62,12 @@ public final class GeyserModelEngine extends JavaPlugin { @Getter private int joinSendDelay; + @Getter + private boolean debug; + + @Getter + private Map> drivers = new ConcurrentHashMap<>(); + @Override public void onEnable() { // Plugin startup logic @@ -62,6 +75,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) { @@ -70,6 +84,7 @@ public final class GeyserModelEngine extends JavaPlugin { } instance = this; ProtocolLibrary.getProtocolManager().addPacketListener(new AddEntityPacketListener()); + ProtocolLibrary.getProtocolManager().addPacketListener(new MountPacketListener()); Bukkit.getPluginManager().registerEvents(new ModelListener(), this); Bukkit.getScheduler() diff --git a/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java b/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java index 8e13905..fb22064 100644 --- a/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java +++ b/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java @@ -46,6 +46,11 @@ public class AddEntityPacketListener extends PacketAdapter { if (model != null) { 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; } @@ -58,7 +63,7 @@ public class AddEntityPacketListener extends PacketAdapter { if (task == null || firstJoined) { Bukkit.getScheduler().runTaskLater(GeyserModelEngine.getInstance(), () -> { model.getTask().sendEntityData(event.getPlayer(), GeyserModelEngine.getInstance().getSkinSendDelay()); - }, delay); + }, delay); } else { task.sendEntityData(event.getPlayer(), GeyserModelEngine.getInstance().getSkinSendDelay()); } diff --git a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java index 937b88a..0806edc 100644 --- a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java +++ b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java @@ -1,10 +1,9 @@ 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; @@ -17,11 +16,9 @@ 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.EntityChangeBlockEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.EntitySpawnEvent; -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; @@ -42,10 +39,6 @@ public class ModelListener implements Listener { return; } - - UUID entityId = event.getTarget().getBase().getUUID(); - ModelBlueprint blueprint = event.getModel().getBlueprint(); - Bukkit.getScheduler().runTask(GeyserModelEngine.getInstance(), () -> { ModelEntity.create(event.getTarget(), event.getModel()); }); @@ -57,6 +50,29 @@ public class ModelListener implements Listener { public void onRemoveModel(RemoveModelEvent event) { } + @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()); + + 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 onEntityLoad(EntitiesLoadEvent event) { Bukkit.getScheduler() @@ -108,6 +124,7 @@ public class ModelListener implements Listener { } } + @EventHandler(priority = EventPriority.HIGHEST) public void onModelEntitySpawn(EntitySpawnEvent event) { if (GeyserModelEngine.getInstance().isSpawningModelEntity() && event.getEntity() instanceof LivingEntity entity) { @@ -182,4 +199,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..02c2158 --- /dev/null +++ b/src/main/java/re/imc/geysermodelengine/listener/MountPacketListener.java @@ -0,0 +1,65 @@ +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.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"); + seat.getSecond().clearPassengers(); + } + } + } + } +} diff --git a/src/main/java/re/imc/geysermodelengine/model/EntityTask.java b/src/main/java/re/imc/geysermodelengine/model/EntityTask.java index 4fff2ea..15c729f 100644 --- a/src/main/java/re/imc/geysermodelengine/model/EntityTask.java +++ b/src/main/java/re/imc/geysermodelengine/model/EntityTask.java @@ -39,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; @@ -68,54 +69,64 @@ public class EntityTask { } } - if (model.getEntity().isDead() && model.getModeledEntity().getBase().isAlive() && !model.getActiveModel().isRemoved()) { + if (!removed && model.getEntity().isDead() && model.getModeledEntity().getBase().isAlive() && !model.getActiveModel().isRemoved()) { model.spawnEntity(); } - model.getEntity().setVisualFire(false); model.teleportToModel(); } public void runAsync() { Entity entity = model.getEntity(); + if (entity.isDead()) { + return; + } Set viewers = model.getViewers(); ActiveModel activeModel = model.getActiveModel(); ModeledEntity modeledEntity = model.getModeledEntity(); if (activeModel.isRemoved() || !modeledEntity.getBase().isAlive()) { - if (!modeledEntity.getBase().isAlive()) { - - if (!activeModel.isRemoved() && hasAnimation("death")) { - new BukkitRunnable() { - @Override - public void run() { - entity.remove(); - } - }.runTaskLater(GeyserModelEngine.getInstance(), Math.min(Math.max(playAnimation("death", 999, 5f, true) - 3, 0), 200)); - } else { - new BukkitRunnable() { - @Override - public void run() { - entity.remove(); - } - }.runTask(GeyserModelEngine.getInstance()); - } + 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()) { @@ -144,17 +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)) { @@ -204,10 +204,11 @@ 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()); if (looping) { - playBedrockAnimation("animation." + model.getActiveModel().getBlueprint().getName() + "." + lastAnimation, looping, 0f); + playBedrockAnimation(lastAnimation, Set.of(player), looping, 0f); } sendHitBox(player); sendScale(player); @@ -286,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, blendTime), 0); + Bukkit.getScheduler().runTaskLaterAsynchronously(GeyserModelEngine.getInstance(), () -> playBedrockAnimation(id, model.getViewers(), looping, blendTime), 0); } else { - playBedrockAnimation(id, looping, blendTime); + playBedrockAnimation(id, model.getViewers(), looping, blendTime); } } return animationCooldown.get(); @@ -328,12 +329,11 @@ public class EntityTask { */ - private void playBedrockAnimation(String animationId, boolean loop, float blendTime) { + public void playBedrockAnimation(String animationId, Set viewers, boolean loop, float blendTime) { - model.getViewers().forEach(viewer -> viewer.sendActionBar("CURRENT AN:" + animationId)); + // model.getViewers().forEach(viewer -> viewer.sendActionBar("CURRENT AN:" + animationId)); Entity entity = model.getEntity(); - Set viewers = model.getViewers(); Animation.AnimationBuilder animation = Animation.builder() .animation(animationId) @@ -383,6 +383,15 @@ 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 diff --git a/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java b/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java index 723ab17..861e5b9 100644 --- a/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java +++ b/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java @@ -1,13 +1,16 @@ 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 org.bukkit.Location; +import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; import re.imc.geysermodelengine.GeyserModelEngine; import java.util.HashMap; @@ -49,9 +52,9 @@ public class ModelEntity { for (Player viewer : viewers) { viewer.sendActionBar("X:" + modeledEntity.getXHeadRot() + ", Y:" + modeledEntity.getYHeadRot()); } - */ - entity.teleportAsync(location); + */ + ModelEngineAPI.getEntityHandler().setPosition(entity, location.getX(), location.getY(), location.getZ()); if (modeledEntity.getBase() instanceof BukkitEntity bukkitEntity && bukkitEntity.getOriginal() instanceof LivingEntity livingEntity) { controllerEntity.getLookController().setHeadYaw(livingEntity.getEyeLocation().getYaw()); controllerEntity.getLookController().setPitch(livingEntity.getEyeLocation().getPitch()); @@ -89,7 +92,7 @@ public class ModelEntity { display.setGravity(false); display.setMaxHealth(2048); display.setHealth(2048); - + display.setMetadata("model_entity", new FixedMetadataValue(GeyserModelEngine.getInstance(), true)); //display.setInvulnerable(true);