work in progress

This commit is contained in:
xSquishyLiam
2025-09-07 00:26:16 +01:00
parent 804d2aac04
commit 8e36bf2829
29 changed files with 574 additions and 2900 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="Uncommitted_changes_before_rebase_[Changes]" date="1757196821391" recycled="false" toDelete="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch" />
<option name="DESCRIPTION" value="Uncommitted changes before rebase [Changes]" />
</changelist>

View File

@@ -1,4 +0,0 @@
<changelist name="Uncommitted_changes_before_rebase_[Changes]1" date="1757196822407" recycled="false" toDelete="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]1/shelved.patch" />
<option name="DESCRIPTION" value="Uncommitted changes before rebase [Changes]" />
</changelist>

66
.idea/workspace.xml generated
View File

@@ -5,7 +5,35 @@
</component>
<component name="ChangeListManager">
<list default="true" id="ff2e9770-ec88-4715-adeb-b9dbda130e1a" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/Events/GeyserModelEngineModelSpawn.java" beforeDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/listener/BetterModelListener.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/listener/ModelEngineListener.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/entity/BetterModelEntityData.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/entity/EntityData.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/model/BetterModelModel.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/model/Model.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/model/ModelEngineModel.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/BetterModelHandler.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelEngineHandler.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/modelhandler/ModelHandler.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/BetterModelPropertyHandler.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/ModelEnginePropertyHandler.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/propertyhandler/PropertyHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]1/shelved.patch" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_rebase__Changes_.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_rebase__Changes_1.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle.kts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/GeyserModelEngine.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/listener/ModelListener.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/commands/CommandManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/EntityTaskManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/ModelManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/data/ModelEntityData.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/managers/model/entity/ModelEngineEntityData.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/runnables/EntityTaskRunnable.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/runnables/UpdateTaskRunnable.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/util/BooleanPacker.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/resources/paper-plugin.yml" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/paper-plugin.yml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -77,25 +105,25 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;Gradle.Download Sources.executor&quot;: &quot;Run&quot;,
&quot;Gradle.GeyserModelEngine [build].executor&quot;: &quot;Run&quot;,
&quot;Gradle.GeyserModelEngine [jar].executor&quot;: &quot;Run&quot;,
&quot;Maven.GeyserModelEngine [install...].executor&quot;: &quot;Run&quot;,
&quot;Maven.GeyserModelEngine [install].executor&quot;: &quot;Run&quot;,
&quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;bettermodel-support-dev&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/Coding/Forks/Minecraft/GeyserModelEngine&quot;,
&quot;project.structure.last.edited&quot;: &quot;Project&quot;,
&quot;project.structure.proportion&quot;: &quot;0.0&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;reference.settings.project.maven.runner&quot;
<component name="PropertiesComponent"><![CDATA[{
"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"
}
}</component>
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\Coding\Forks\Minecraft\GeyserModelEngine" />

View File

@@ -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")

View File

@@ -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();
}

View File

@@ -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());
}
}

View File

@@ -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<Model, EntityData> 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());
}
}
}

View File

@@ -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<ActiveModel, ModelEntityData> 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) {

View File

@@ -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());

View File

@@ -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<Player> 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<Player> 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<Player> viewers) {
public void checkViewers(EntityData model, Set<Player> 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;
}
}

View File

@@ -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<UUID> playerJoinedCache = new HashSet<>();
private final ConcurrentHashMap<Integer, Map<ActiveModel, ModelEntityData>> entitiesCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Integer, ModelEntityData> modelEntitiesCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Integer, Model> modelEntitiesCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Integer, Map<Model, EntityData>> entitiesCache = new ConcurrentHashMap<>();
// MEG ONLY
private final ConcurrentHashMap<UUID, Pair<ActiveModel, Mount>> 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<ActiveModel, ModelEntityData> map = entitiesCache.computeIfAbsent(id, k -> new HashMap<>());
for (Map.Entry<ActiveModel, ModelEntityData> entry : map.entrySet()) {
if (entry.getKey() != model && entry.getKey().getBlueprint().getName().equals(model.getBlueprint().getName())) {
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;
}
modelHandler.loadListeners(plugin);
}
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<ActiveModel> model = modeledEntity.getModels().values().stream().findFirst();
model.ifPresent(m -> create(modeledEntity, m));
}
public void removeEntities() {
for (Map<ActiveModel, ModelEntityData> entities : entitiesCache.values()) {
entities.forEach((model, modelEntity) -> modelEntity.getEntity().remove());
}
public ModelHandler getModelHandler() {
return modelHandler;
}
public HashSet<UUID> getPlayerJoinedCache() {
return playerJoinedCache;
}
public ConcurrentHashMap<Integer, Map<ActiveModel, ModelEntityData>> getEntitiesCache() {
public ConcurrentHashMap<Integer, Map<Model, EntityData>> getEntitiesCache() {
return entitiesCache;
}
public ConcurrentHashMap<Integer, ModelEntityData> getModelEntitiesCache() {
public ConcurrentHashMap<Integer, Model> getModelEntitiesCache() {
return modelEntitiesCache;
}

View File

@@ -0,0 +1,4 @@
package re.imc.geysermodelengine.managers.model.entity;
public class BetterModelEntityData {
}

View File

@@ -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<Player> getViewers();
void teleportToModel();
void remove();
EntityTaskRunnable getEntityTask();
}

View File

@@ -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<Player> 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<Player> 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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<Model, EntityData> entityDataCache = plugin.getModelManager().getEntitiesCache().computeIfAbsent(entityID, k -> new HashMap<>());
for (Map.Entry<Model, EntityData> 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<ActiveModel> model = modeledEntity.getModels().values().stream().findFirst();
model.ifPresent(m -> createModel(plugin, modeledEntity, m));
}
@Override
public void removeEntities(GeyserModelEngine plugin) {
for (Map<Model, EntityData> 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);
}
}

View File

@@ -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);
}

View File

@@ -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<Player> players, float lastScale, boolean firstSend) {
}
@Override
public void sendColor(EntityData modelData, Collection<Player> players, Color lastColor, boolean firstSend) {
}
@Override
public void sendHitBox(EntityData modelData, Player player) {
}
}

View File

@@ -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<Player> 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<Player> 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);
}
}
}

View File

@@ -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<Player> players, float lastScale, boolean firstSend);
void sendColor(EntityData modelData, Collection<Player> players, Color lastColor, boolean firstSend);
void sendHitBox(EntityData modelData, Player player);
}

View File

@@ -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<String, Integer> lastIntSet = new ConcurrentHashMap<>();
private final Cache<String, Boolean> 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<Player> players, boolean firstSend, String... forceAnims) {
public void updateEntityProperties(ModelEngineEntityData model, Collection<Player> players, boolean firstSend, String... forceAnims) {
int entity = model.getEntity().getEntityId();
Set<String> forceAnimSet = Set.of(forceAnims);
@@ -163,13 +163,13 @@ public class EntityTaskRunnable {
Map<String, Integer> 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<String, Boolean> map) {
private void processBone(ModelEngineEntityData model, BlueprintBone bone, Map<String, Boolean> map) {
String name = plugin.getEntityTaskManager().unstripName(bone).toLowerCase();
if (name.equals("hitbox") ||
name.equals("shadow") ||

View File

@@ -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<ScheduledTask> {
@Override
public void accept(ScheduledTask scheduledTask) {
try {
for (Map<ActiveModel, ModelEntityData> models : plugin.getModelManager().getEntitiesCache().values()) {
models.values().forEach(model -> model.getEntityTask().updateEntityProperties(model, model.getViewers(), false));
for (Map<Model, EntityData> models : plugin.getModelManager().getEntitiesCache().values()) {
models.values().forEach(model -> model.getEntityTask().updateEntityProperties((ModelEngineEntityData) model, model.getViewers(), false));
}
} catch (Throwable err) {
throw new RuntimeException(err);

View File

@@ -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<Boolean> booleans) {
public static int booleansToInt(List<Boolean> booleans) {
int result = 0;
int i = 1;
@@ -23,7 +23,7 @@ public class BooleanPacker {
return result;
}
public int mapBooleansToInt(Map<String, Boolean> booleanMap) {
public static int mapBooleansToInt(Map<String, Boolean> booleanMap) {
int result = 0;
int i = 1;
@@ -39,7 +39,7 @@ public class BooleanPacker {
return result;
}
public List<Integer> booleansToInts(List<Boolean> booleans) {
public static List<Integer> booleansToInts(List<Boolean> booleans) {
List<Integer> results = new ArrayList<>();
int result = 0;
int i = 1;
@@ -62,7 +62,7 @@ public class BooleanPacker {
return results;
}
public List<Integer> mapBooleansToInts(Map<String, Boolean> booleanMap) {
public static List<Integer> mapBooleansToInts(Map<String, Boolean> booleanMap) {
List<String> keys = new ArrayList<>(booleanMap.keySet());
List<Boolean> booleans = new ArrayList<>();

View File

@@ -15,7 +15,11 @@ dependencies:
required: true
packetevents:
required: true
ModelEngine:
required: true
floodgate:
required: true
ModelEngine:
required: false
join-classpath: true
BetterModel:
required: false
join-classpath: true