diff --git a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java index fa259a8..30a02a8 100644 --- a/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java +++ b/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java @@ -41,18 +41,22 @@ public final class GeyserModelEngine extends JavaPlugin { @Getter private Cache joinedPlayer; + + @Getter + private int joinSendDelay; + @Override public void onEnable() { // Plugin startup logic saveDefaultConfig(); // alwaysSendSkin = getConfig().getBoolean("always-send-skin"); - skinSendDelay = getConfig().getInt("skin-send-delay"); - viewDistance = getConfig().getInt("skin-view-distance"); + skinSendDelay = getConfig().getInt("skin-send-delay", 0); + viewDistance = getConfig().getInt("skin-view-distance", 60); modelEntityType = EntityType.valueOf(getConfig().getString("model-entity-type", "BAT")); - int joinedDelay = getConfig().getInt("join-send-delay"); - if (joinedDelay > 0) { + joinSendDelay = getConfig().getInt("join-send-delay", 20); + if (joinSendDelay > 0) { joinedPlayer = CacheBuilder.newBuilder() - .expireAfterWrite(joinedDelay * 50L, TimeUnit.MILLISECONDS).build(); + .expireAfterWrite(joinSendDelay * 50L, TimeUnit.MILLISECONDS).build(); } instance = this; ProtocolLibrary.getProtocolManager().addPacketListener(new InteractPacketListener()); diff --git a/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java b/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java index 0e5cf15..2bb30ee 100644 --- a/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java +++ b/src/main/java/re/imc/geysermodelengine/listener/AddEntityPacketListener.java @@ -27,8 +27,16 @@ public class AddEntityPacketListener extends PacketAdapter { } ModelEntity model = ModelEntity.MODEL_ENTITIES.get(entity.getEntityId()); - if (model != null && FloodgateApi.getInstance().isFloodgatePlayer(event.getPlayer().getUniqueId())) { - model.getTask().sendEntityData(event.getPlayer(), GeyserModelEngine.getInstance().getSkinSendDelay()); + 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()); + } + } else { + event.setCancelled(true); + } } } } diff --git a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java index ad61df5..3b0c2a9 100644 --- a/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java +++ b/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java @@ -8,14 +8,11 @@ import com.ticxo.modelengine.api.events.RemoveModelEvent; import com.ticxo.modelengine.api.model.ActiveModel; import com.ticxo.modelengine.api.model.ModeledEntity; import org.bukkit.Bukkit; -import org.bukkit.entity.Damageable; import org.bukkit.entity.Entity; 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.EntityDeathEvent; -import org.bukkit.event.entity.EntityRemoveEvent; import org.bukkit.event.entity.ProjectileHitEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.world.EntitiesLoadEvent; @@ -34,6 +31,7 @@ public class ModelListener implements Listener { if (event.isCancelled()) { return; } + Bukkit.getScheduler().runTask(GeyserModelEngine.getInstance(), () -> { ModelEntity.create(event.getTarget(), event.getModel()); }); @@ -64,7 +62,11 @@ public class ModelListener implements Listener { @EventHandler public void onAnimationPlay(AnimationPlayEvent event) { - ModelEntity model = ModelEntity.ENTITIES.get(event.getModel().getModeledEntity().getBase().getEntityId()).get(event.getModel()); + Map map = ModelEntity.ENTITIES.get(event.getModel().getModeledEntity().getBase().getEntityId()); + if (map == null) { + return; + } + ModelEntity model = map.get(event.getModel()); if (model != null) { EntityTask task = model.getTask(); diff --git a/src/main/java/re/imc/geysermodelengine/model/EntityTask.java b/src/main/java/re/imc/geysermodelengine/model/EntityTask.java index 0b0cbe4..4c6c473 100644 --- a/src/main/java/re/imc/geysermodelengine/model/EntityTask.java +++ b/src/main/java/re/imc/geysermodelengine/model/EntityTask.java @@ -3,7 +3,6 @@ package re.imc.geysermodelengine.model; import com.ticxo.modelengine.api.animation.BlueprintAnimation; import com.ticxo.modelengine.api.entity.BaseEntity; import com.ticxo.modelengine.api.entity.BukkitEntity; -import com.ticxo.modelengine.api.entity.Hitbox; import com.ticxo.modelengine.api.model.ActiveModel; import com.ticxo.modelengine.api.model.ModeledEntity; import lombok.Getter; @@ -19,7 +18,6 @@ import org.geysermc.floodgate.api.FloodgateApi; import org.jetbrains.annotations.NotNull; import re.imc.geysermodelengine.GeyserModelEngine; -import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -33,6 +31,7 @@ public class EntityTask { ModelEntity model; int tick = 0; + int syncTick = 0; AtomicInteger animationCooldown = new AtomicInteger(0); AtomicInteger currentAnimationPriority = new AtomicInteger(0); @@ -53,9 +52,23 @@ public class EntityTask { } public void runSync() { + + syncTick ++; + if (syncTick > 400) { + syncTick = 0; + } + + 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(); } + model.getEntity().setVisualFire(false); model.teleportToModel(); } @@ -95,9 +108,8 @@ public class EntityTask { if (tick > 1 && tick % 5 == 0) { for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - if (!FloodgateApi.getInstance().isFloodgatePlayer(onlinePlayer.getUniqueId())) { - onlinePlayer.hideEntity(GeyserModelEngine.getInstance(), entity); - } else { + if (FloodgateApi.getInstance().isFloodgatePlayer(onlinePlayer.getUniqueId())) { + if (canSee(onlinePlayer, model.getEntity())) { if (!viewers.contains(onlinePlayer)) { diff --git a/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java b/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java index a0ca431..31b4b0b 100644 --- a/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java +++ b/src/main/java/re/imc/geysermodelengine/model/ModelEntity.java @@ -1,13 +1,17 @@ package re.imc.geysermodelengine.model; import com.google.common.collect.Sets; +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 re.imc.geysermodelengine.GeyserModelEngine; import java.util.HashMap; @@ -24,6 +28,7 @@ public class ModelEntity { public static Map MODEL_ENTITIES = new ConcurrentHashMap<>(); private LivingEntity entity; + private BukkitEntity controllerEntity; private final Set viewers = Sets.newConcurrentHashSet(); @@ -42,14 +47,28 @@ public class ModelEntity { } public void teleportToModel() { - entity.teleportAsync(modeledEntity.getBase().getLocation()); + Location location = modeledEntity.getBase().getLocation(); + /* + location.setPitch(modeledEntity.getXHeadRot()); + location.setYaw(modeledEntity.getYHeadRot()); + for (Player viewer : viewers) { + viewer.sendActionBar("X:" + modeledEntity.getXHeadRot() + ", Y:" + modeledEntity.getYHeadRot()); + } + */ + + entity.teleportAsync(location); + if (modeledEntity.getBase() instanceof BukkitEntity bukkitEntity && bukkitEntity.getOriginal() instanceof LivingEntity livingEntity) { + controllerEntity.getLookController().setHeadYaw(livingEntity.getEyeLocation().getYaw()); + controllerEntity.getLookController().setPitch(livingEntity.getEyeLocation().getPitch()); + controllerEntity.getLookController().setBodyYaw(livingEntity.getBodyYaw()); + } + } public static ModelEntity create(ModeledEntity entity, ActiveModel model) { ModelEntity modelEntity = new ModelEntity(entity, model); int id = entity.getBase().getEntityId(); Map map = ENTITIES.computeIfAbsent(id, k -> new HashMap<>()); map.put(model, modelEntity); - ENTITIES.put(id, map); return modelEntity; } @@ -60,6 +79,7 @@ public class ModelEntity { ModelEntity model = this; int id = entity.getEntityId(); MODEL_ENTITIES.put(id, model); + controllerEntity = new BukkitEntity(entity); return entity; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index d7d5e7a..a1a80e5 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,4 +1,4 @@ skin-send-delay: 0 skin-view-distance: 50 -join-send-delay: 10 +join-send-delay: 20 model-entity-type: BAT # must be a living entity \ No newline at end of file