major refactor

This commit is contained in:
Tofaa2 2024-06-23 22:56:13 +04:00
parent 2a3732fa83
commit 718940178f
33 changed files with 840 additions and 226 deletions

View file

@ -14,6 +14,7 @@
<option value="$PROJECT_DIR$/model-engine-addon" /> <option value="$PROJECT_DIR$/model-engine-addon" />
<option value="$PROJECT_DIR$/platforms" /> <option value="$PROJECT_DIR$/platforms" />
<option value="$PROJECT_DIR$/platforms/spigot" /> <option value="$PROJECT_DIR$/platforms/spigot" />
<option value="$PROJECT_DIR$/platforms/standalone" />
<option value="$PROJECT_DIR$/platforms/velocity" /> <option value="$PROJECT_DIR$/platforms/velocity" />
<option value="$PROJECT_DIR$/test-plugin" /> <option value="$PROJECT_DIR$/test-plugin" />
</set> </set>

View file

@ -5,14 +5,39 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment=""> <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestHologramsCommand.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/container/AbstractEntityContainer.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/container/ContainerImpl.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/container/EntityContainer.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/build.gradle" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibApi.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/task/ExecutionType.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/task/Scheduler.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/task/SchedulerImpl.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/task/Task.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/task/TaskImpl.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/task/TaskSchedule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/utils/Check.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/utils/Check.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityAttributes.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityAttributes.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntityCreature.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperExperienceOrbEntity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperLivingEntity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperPlayer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test-plugin/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/build.gradle" afterDir="false" /> <change beforePath="$PROJECT_DIR$/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/platforms/spigot/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/platforms/velocity/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/velocity/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityEntityLibAPI.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestMassivePigCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestMassivePigCommand.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestTextDisplayCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestTextDisplayCommand.java" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -83,51 +108,51 @@
<option name="showExcludedFiles" value="false" /> <option name="showExcludedFiles" value="false" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent"><![CDATA[{ <component name="PropertiesComponent">{
"keyToString": { &quot;keyToString&quot;: {
"Downloaded.Files.Path.Enabled": "false", &quot;Downloaded.Files.Path.Enabled&quot;: &quot;false&quot;,
"Gradle.Build EntityLib.executor": "Run", &quot;Gradle.Build EntityLib.executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib [dependencies].executor": "Run", &quot;Gradle.EntityLib [dependencies].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib [publish].executor": "Run", &quot;Gradle.EntityLib [publish].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib [runServer] (1).executor": "Run", &quot;Gradle.EntityLib [runServer] (1).executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib [runServer].executor": "Run", &quot;Gradle.EntityLib [runServer].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib:code-gen [:code-gen:Main.main()].executor": "Run", &quot;Gradle.EntityLib:code-gen [:code-gen:Main.main()].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib:test-plugin [cleanAllRunTaskCaches].executor": "Run", &quot;Gradle.EntityLib:test-plugin [cleanAllRunTaskCaches].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib:test-plugin [cleanCustomServiceCaches].executor": "Run", &quot;Gradle.EntityLib:test-plugin [cleanCustomServiceCaches].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib:test-plugin [cleanPaperCache].executor": "Run", &quot;Gradle.EntityLib:test-plugin [cleanPaperCache].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib:test-plugin [cleanPaperPluginsCache].executor": "Run", &quot;Gradle.EntityLib:test-plugin [cleanPaperPluginsCache].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib:test-plugin [publish].executor": "Run", &quot;Gradle.EntityLib:test-plugin [publish].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib:test-plugin [runServer].executor": "Run", &quot;Gradle.EntityLib:test-plugin [runServer].executor&quot;: &quot;Run&quot;,
"Gradle.EntityLib:test-plugin [shadowJar].executor": "Run", &quot;Gradle.EntityLib:test-plugin [shadowJar].executor&quot;: &quot;Run&quot;,
"JAR Application.Unnamed.executor": "Run", &quot;JAR Application.Unnamed.executor&quot;: &quot;Run&quot;,
"Repository.Attach.Annotations": "false", &quot;Repository.Attach.Annotations&quot;: &quot;false&quot;,
"Repository.Attach.JavaDocs": "false", &quot;Repository.Attach.JavaDocs&quot;: &quot;false&quot;,
"Repository.Attach.Sources": "false", &quot;Repository.Attach.Sources&quot;: &quot;false&quot;,
"RunOnceActivity.OpenProjectViewOnStart": "true", &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
"RunOnceActivity.ShowReadmeOnStart": "true", &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
"WebServerToolWindowFactoryState": "false", &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
"git-widget-placeholder": "master", &quot;git-widget-placeholder&quot;: &quot;master&quot;,
"ignore.virus.scanning.warn.message": "true", &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
"jdk.selected.JAVA_MODULE": "corretto-17", &quot;jdk.selected.JAVA_MODULE&quot;: &quot;corretto-17&quot;,
"kotlin-language-version-configured": "true", &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
"last_opened_file_path": "D:/Github/EntityLib", &quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib&quot;,
"node.js.detected.package.eslint": "true", &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
"node.js.detected.package.tslint": "true", &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
"node.js.selected.package.eslint": "(autodetect)", &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
"node.js.selected.package.tslint": "(autodetect)", &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
"nodejs_package_manager_path": "npm", &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
"project.structure.last.edited": "Modules", &quot;project.structure.last.edited&quot;: &quot;Modules&quot;,
"project.structure.proportion": "0.15", &quot;project.structure.proportion&quot;: &quot;0.15&quot;,
"project.structure.side.proportion": "0.2", &quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
"settings.editor.selected.configurable": "preferences.editor", &quot;settings.editor.selected.configurable&quot;: &quot;preferences.editor&quot;,
"vue.rearranger.settings.migration": "true" &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}, },
"keyToStringList": { &quot;keyToStringList&quot;: {
"kotlin-gradle-user-dirs": [ &quot;kotlin-gradle-user-dirs&quot;: [
"/home/tofaa/.gradle" &quot;/home/tofaa/.gradle&quot;
] ]
} }
}]]></component> }</component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS"> <key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/model-engine-addon" /> <recent name="$PROJECT_DIR$/model-engine-addon" />
@ -385,7 +410,8 @@
<workItem from="1716488324710" duration="3710000" /> <workItem from="1716488324710" duration="3710000" />
<workItem from="1716722129881" duration="965000" /> <workItem from="1716722129881" duration="965000" />
<workItem from="1716926795264" duration="1000" /> <workItem from="1716926795264" duration="1000" />
<workItem from="1718023888535" duration="1738000" /> <workItem from="1718023888535" duration="2457000" />
<workItem from="1719160307151" duration="6107000" />
</task> </task>
<servers /> <servers />
</component> </component>

View file

@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.PacketEventsAPI;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.protocol.world.Location; import com.github.retrooper.packetevents.protocol.world.Location;
import me.tofaa.entitylib.container.EntityContainer;
import me.tofaa.entitylib.tick.TickContainer; import me.tofaa.entitylib.tick.TickContainer;
import me.tofaa.entitylib.wrapper.WrapperEntity; import me.tofaa.entitylib.wrapper.WrapperEntity;
import me.tofaa.entitylib.wrapper.WrapperPlayer; import me.tofaa.entitylib.wrapper.WrapperPlayer;
@ -30,30 +31,12 @@ public interface EntityLibAPI<T> {
void onEnable(); void onEnable();
@NotNull <T extends WrapperEntity> T createEntity(UUID uuid, int entityId, EntityType type); @NotNull <P extends WrapperEntity> P cloneEntity(@NotNull Object platformEntity);
@NotNull <T extends WrapperEntity> T createEntity(EntityType type);
@NotNull WrapperPlayer spawnPlayer(UserProfile profile, Location location);
@NotNull WrapperPlayer createPlayer(UserProfile profile);
@NotNull WrapperPlayer createPlayer(UserProfile profile, int entityId);
@NotNull <T extends WrapperEntity> T spawnEntity(@NotNull Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location);
@NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location);
@NotNull <T extends WrapperEntity> T spawnEntity(@NotNull T entity, @NotNull Location location);
@NotNull <T extends WrapperEntity> T cloneEntity(@NotNull Object platformEntity, @NotNull Location location);
@Nullable WrapperEntity getEntity(int id); @Nullable WrapperEntity getEntity(int id);
@Nullable WrapperEntity getEntity(@NotNull UUID uuid); @Nullable WrapperEntity getEntity(@NotNull UUID uuid);
void removeEntity(WrapperEntity entity);
@NotNull Collection<WrapperEntity> getAllEntities(); @NotNull Collection<WrapperEntity> getAllEntities();
/** /**
@ -71,4 +54,13 @@ public interface EntityLibAPI<T> {
* @param tickContainer the TickContainer to add. * @param tickContainer the TickContainer to add.
*/ */
void addTickContainer(@NotNull TickContainer<?, T> tickContainer); void addTickContainer(@NotNull TickContainer<?, T> tickContainer);
@NotNull
EntityContainer getDefaultContainer();
void addContainer(EntityContainer container);
void removeContainer(EntityContainer container);
@NotNull Collection<EntityContainer> getEntityContainers();
} }

View file

@ -0,0 +1,90 @@
package me.tofaa.entitylib.container;
import me.tofaa.entitylib.wrapper.WrapperEntity;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractEntityContainer implements EntityContainer {
private final Map<UUID, WrapperEntity> entities = new ConcurrentHashMap<>();
private final Map<Integer, WrapperEntity> entitiesById = new ConcurrentHashMap<>();
@Override
public void addEntity(WrapperEntity entity) {
entities.put(entity.getUuid(), entity);
entitiesById.put(entity.getEntityId(), entity);
}
@Override
public void removeEntity(WrapperEntity entity, boolean despawn) {
entities.remove(entity.getUuid());
entitiesById.remove(entity.getEntityId());
if (despawn) {
entity.despawn();
}
}
@Override
public void removeEntity(int entityId, boolean despawn) {
WrapperEntity entity = entitiesById.get(entityId);
if (entity != null) {
removeEntity(entity, despawn);
}
}
@Override
public void removeEntity(UUID uuid, boolean despawn) {
WrapperEntity entity = entities.get(uuid);
if (entity != null) {
removeEntity(entity, despawn);
}
}
@Override
public void clearEntities(boolean despawn) {
entities.values().forEach(entity -> removeEntity(entity, despawn));
}
@Override
public void tick() {
}
public @NotNull Iterator<WrapperEntity> iterator() {
return entities.values().iterator();
}
@Override
public Collection<WrapperEntity> getEntities() {
return Collections.unmodifiableCollection(entities.values());
}
@Override
public WrapperEntity getEntity(UUID uuid) {
return entities.get(uuid);
}
@Override
public WrapperEntity getEntity(int entityId) {
return entitiesById.get(entityId);
}
@Override
public boolean containsEntity(UUID uuid) {
return entities.containsKey(uuid);
}
@Override
public boolean containsEntity(int entityId) {
return entitiesById.containsKey(entityId);
}
@Override
public boolean containsEntity(WrapperEntity entity) {
return entities.containsValue(entity);
}
}

View file

@ -0,0 +1,4 @@
package me.tofaa.entitylib.container;
class ContainerImpl extends AbstractEntityContainer {
}

View file

@ -0,0 +1,63 @@
package me.tofaa.entitylib.container;
import me.tofaa.entitylib.wrapper.WrapperEntity;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.UUID;
/**
* Containers are basic iterable classes that hold entities. These containers can be extended to provide more functionality, and this allows for seperation of logic between certain entities.
* <p>
* To access a specific {@link WrapperEntity}'s container you can use {@link WrapperEntity#getParentContainer()}.
* </p>
*/
public interface EntityContainer extends Iterable<WrapperEntity> {
static EntityContainer basic() {
return new ContainerImpl();
}
void addEntity(WrapperEntity entity);
void removeEntity(WrapperEntity entity, boolean despawn);
default void removeEntity(WrapperEntity entity) {
removeEntity(entity, false);
}
void removeEntity(int entityId, boolean despawn);
default void removeEntity(int entityId) {
removeEntity(entityId, false);
}
void removeEntity(UUID uuid, boolean despawn);
default void removeEntity(UUID entity) {
removeEntity(entity, false);
}
void clearEntities(boolean despawn);
default void clearEntities() {
clearEntities(false);
}
void tick();
Collection<WrapperEntity> getEntities();
@Nullable WrapperEntity getEntity(UUID uuid);
@Nullable WrapperEntity getEntity(int entityId);
boolean containsEntity(UUID uuid);
boolean containsEntity(int entityId);
/** Value based contains, not reference based */
boolean containsEntity(WrapperEntity entity);
}

View file

@ -8,6 +8,7 @@ import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.*; import com.github.retrooper.packetevents.wrapper.play.server.*;
import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.TrackedEntity; import me.tofaa.entitylib.TrackedEntity;
import me.tofaa.entitylib.container.EntityContainer;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import me.tofaa.entitylib.meta.types.ObjectData; import me.tofaa.entitylib.meta.types.ObjectData;
import me.tofaa.entitylib.tick.Tickable; import me.tofaa.entitylib.tick.Tickable;
@ -34,6 +35,7 @@ public class WrapperEntity implements Tickable, TrackedEntity {
private Vector3d velocity; private Vector3d velocity;
private int riding = -1; private int riding = -1;
private final Set<Integer> passengers; private final Set<Integer> passengers;
private EntityContainer parent;
public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) { public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
this.entityId = entityId; this.entityId = entityId;
@ -45,7 +47,22 @@ public class WrapperEntity implements Tickable, TrackedEntity {
this.passengers = ConcurrentHashMap.newKeySet(); this.passengers = ConcurrentHashMap.newKeySet();
} }
public boolean spawn(Location location) { public WrapperEntity(int entityId, EntityType entityType) {
this(entityId, EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
}
public WrapperEntity(UUID uuid, EntityType entityType) {
this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType);
}
public WrapperEntity(EntityType entityType) {
this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
}
public WrapperEntity(int entityId, UUID uuid, EntityType entityType) {
this(entityId, uuid, entityType, EntityMeta.createMeta(entityId, entityType));
}
public boolean spawn(Location location, EntityContainer parent) {
if (spawned) return false; if (spawned) return false;
this.location = location; this.location = location;
this.spawned = true; this.spawned = true;
@ -63,9 +80,15 @@ public class WrapperEntity implements Tickable, TrackedEntity {
) )
); );
sendPacketToViewers(entityMeta.createPacket()); sendPacketToViewers(entityMeta.createPacket());
this.parent = parent;
parent.addEntity(this);
return true; return true;
} }
public boolean spawn(Location location) {
return spawn(location, EntityLib.getApi().getDefaultContainer());
}
protected int getObjectData() { protected int getObjectData() {
if (entityMeta instanceof ObjectData) { if (entityMeta instanceof ObjectData) {
return ((ObjectData) entityMeta).getObjectData(); return ((ObjectData) entityMeta).getObjectData();
@ -98,7 +121,7 @@ public class WrapperEntity implements Tickable, TrackedEntity {
} }
public void remove() { public void remove() {
EntityLib.getApi().removeEntity(this); parent.removeEntity(this, true);
} }
public void despawn() { public void despawn() {
@ -159,6 +182,10 @@ public class WrapperEntity implements Tickable, TrackedEntity {
} }
} }
public EntityContainer getParentContainer() {
return parent;
}
public void sendMessageToViewers(Component message) { public void sendMessageToViewers(Component message) {
sendPacketToViewers(new WrapperPlayServerSystemChatMessage(false, message)); sendPacketToViewers(new WrapperPlayServerSystemChatMessage(false, message));
} }
@ -381,6 +408,18 @@ public class WrapperEntity implements Tickable, TrackedEntity {
} }
} }
public void sendPacketToViewersIfSpawned(PacketWrapper<?> packet) {
if (spawned) {
sendPacketToViewers(packet);
}
}
public void sendPacketsToViewersIfSpawned(PacketWrapper<?>... wrappers) {
if (spawned) {
sendPacketsToViewers(wrappers);
}
}
private static void sendPacket(UUID user, PacketWrapper<?> wrapper) { private static void sendPacket(UUID user, PacketWrapper<?> wrapper) {
if (wrapper == null) return; if (wrapper == null) return;
Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user); Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user);

View file

@ -75,7 +75,7 @@ public final class WrapperEntityAttributes {
public void refresh() { public void refresh() {
entity.sendPacketToViewers(createPacket()); if (entity.isSpawned()) entity.sendPacketToViewers(createPacket());
} }
public WrapperPlayServerUpdateAttributes createPacket() { public WrapperPlayServerUpdateAttributes createPacket() {

View file

@ -1,6 +1,7 @@
package me.tofaa.entitylib.wrapper; package me.tofaa.entitylib.wrapper;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import me.tofaa.entitylib.wrapper.ai.AIGroup; import me.tofaa.entitylib.wrapper.ai.AIGroup;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -29,6 +30,21 @@ public class WrapperEntityCreature extends WrapperLivingEntity {
this.aiGroups = new HashSet<>(); this.aiGroups = new HashSet<>();
} }
public WrapperEntityCreature(int entityId, @NotNull UUID uuid, EntityType entityType) {
this(entityId, uuid, entityType, EntityMeta.createMeta(entityId, entityType));
}
public WrapperEntityCreature(int entityId, EntityType entityType) {
this(entityId, EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
}
public WrapperEntityCreature(UUID uuid, EntityType entityType) {
this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType);
}
public WrapperEntityCreature(EntityType entityType) {
this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
}
@Override @Override
public void tick(long time) { public void tick(long time) {
super.tick(time); super.tick(time);

View file

@ -3,6 +3,7 @@ package me.tofaa.entitylib.wrapper;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.world.Location; import com.github.retrooper.packetevents.protocol.world.Location;
import com.github.retrooper.packetevents.util.Vector3d; import com.github.retrooper.packetevents.util.Vector3d;
import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -17,6 +18,21 @@ public class WrapperExperienceOrbEntity extends WrapperEntity {
super(entityId, uuid, entityType, meta); super(entityId, uuid, entityType, meta);
} }
public WrapperExperienceOrbEntity(int entityId, @NotNull UUID uuid, EntityType entityType) {
this(entityId, uuid, entityType, EntityMeta.createMeta(entityId, entityType));
}
public WrapperExperienceOrbEntity(int entityId, EntityType entityType) {
this(entityId, EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
}
public WrapperExperienceOrbEntity(UUID uuid, EntityType entityType) {
this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType);
}
public WrapperExperienceOrbEntity(EntityType entityType) {
this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
}
/** /**
* Applies a slight slide motion towards the given location. * Applies a slight slide motion towards the given location.
* <p> * <p>

View file

@ -1,19 +1,14 @@
package me.tofaa.entitylib.wrapper; package me.tofaa.entitylib.wrapper;
import com.github.retrooper.packetevents.protocol.attribute.Attribute;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.player.HumanoidArm;
import com.github.retrooper.packetevents.protocol.potion.PotionType; import com.github.retrooper.packetevents.protocol.potion.PotionType;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTeams; import me.tofaa.entitylib.EntityLib;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import me.tofaa.entitylib.meta.types.LivingEntityMeta;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public class WrapperLivingEntity extends WrapperEntity{ public class WrapperLivingEntity extends WrapperEntity{
@ -27,6 +22,21 @@ public class WrapperLivingEntity extends WrapperEntity{
this.attributes = new WrapperEntityAttributes(this); this.attributes = new WrapperEntityAttributes(this);
} }
public WrapperLivingEntity(int entityId, UUID uuid, EntityType entityType) {
this(entityId, uuid, entityType, EntityMeta.createMeta(entityId, entityType));
}
public WrapperLivingEntity(int entityId, EntityType entityType) {
this(entityId, EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
}
public WrapperLivingEntity(UUID uuid, EntityType entityType) {
this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType);
}
public WrapperLivingEntity(EntityType entityType) {
this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
}
@Override @Override
public void refresh() { public void refresh() {
super.refresh(); super.refresh();

View file

@ -46,12 +46,12 @@ public class WrapperPlayer extends WrapperLivingEntity {
public void setGameMode(GameMode gameMode) { public void setGameMode(GameMode gameMode) {
this.gameMode = gameMode; this.gameMode = gameMode;
sendPacketsToViewers(new WrapperPlayServerPlayerInfoUpdate(WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_GAME_MODE, createInfo())); sendPacketsToViewersIfSpawned(new WrapperPlayServerPlayerInfoUpdate(WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_GAME_MODE, createInfo()));
} }
public void setDisplayName(Component displayName) { public void setDisplayName(Component displayName) {
this.displayName = displayName; this.displayName = displayName;
sendPacketsToViewers(new WrapperPlayServerPlayerInfoUpdate(WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_DISPLAY_NAME, createInfo())); sendPacketsToViewersIfSpawned(new WrapperPlayServerPlayerInfoUpdate(WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_DISPLAY_NAME, createInfo()));
} }
public Component getDisplayName() { public Component getDisplayName() {
@ -94,9 +94,9 @@ public class WrapperPlayer extends WrapperLivingEntity {
public void setInTablist(boolean tablist) { public void setInTablist(boolean tablist) {
this.tablist = tablist; this.tablist = tablist;
sendPacketToViewers(tabListPacket()); sendPacketsToViewersIfSpawned(tabListPacket());
if (!tablist) { if (!tablist) {
sendPacketToViewers(tabListRemovePacket()); sendPacketsToViewersIfSpawned(tabListRemovePacket());
} }
} }
@ -106,7 +106,7 @@ public class WrapperPlayer extends WrapperLivingEntity {
public void setLatency(int latency) { public void setLatency(int latency) {
this.latency = latency; this.latency = latency;
sendPacketsToViewers( sendPacketsToViewersIfSpawned(
new WrapperPlayServerPlayerInfoUpdate( new WrapperPlayServerPlayerInfoUpdate(
WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_LATENCY, WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_LATENCY,
createInfo() createInfo()

View file

@ -96,7 +96,8 @@ final class LegacyHologram implements Hologram.Legacy {
@Override @Override
public void setLine(int index, @Nullable Component line) { public void setLine(int index, @Nullable Component line) {
WrapperEntity e = EntityLib.getApi().spawnEntity(EntityTypes.ARMOR_STAND, location); WrapperEntity e = new WrapperEntity(EntityTypes.ARMOR_STAND);
e.spawn(location);
ArmorStandMeta meta = (ArmorStandMeta) e.getEntityMeta(); ArmorStandMeta meta = (ArmorStandMeta) e.getEntityMeta();
meta.setCustomName(line); meta.setCustomName(line);
meta.setCustomNameVisible(true); meta.setCustomNameVisible(true);

View file

@ -10,6 +10,7 @@ import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.sql.Wrapper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -72,7 +73,8 @@ final class ModernHologram implements Hologram.Modern {
@Override @Override
public void setLine(int index, @Nullable Component line) { public void setLine(int index, @Nullable Component line) {
WrapperEntity e = EntityLib.getApi().spawnEntity(EntityTypes.TEXT_DISPLAY, location); WrapperEntity e = new WrapperEntity(EntityTypes.TEXT_DISPLAY);
e.spawn(location);
TextDisplayMeta meta = (TextDisplayMeta) e.getEntityMeta(); TextDisplayMeta meta = (TextDisplayMeta) e.getEntityMeta();
meta.setInvisible(true); meta.setInvisible(true);
meta.setHasNoGravity(true); meta.setHasNoGravity(true);

View file

@ -11,6 +11,8 @@ allprojects {
"net.kyori:adventure-text-serializer-legacy:${adventureVersion}", "net.kyori:adventure-text-serializer-legacy:${adventureVersion}",
"net.kyori:adventure-nbt:${adventureVersion}"] "net.kyori:adventure-nbt:${adventureVersion}"]
project.ext.peVersion = '2.3.0'
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'java-library' apply plugin: 'java-library'
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
@ -59,6 +61,6 @@ allprojects {
dependencies { dependencies {
compileOnlyApi 'com.github.retrooper.packetevents:spigot:2.3.0' compileOnlyApi 'com.github.retrooper.packetevents:spigot:${project.ext.peVersion}'
} }

View file

@ -9,6 +9,7 @@ import me.tofaa.entitylib.APIConfig;
import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.EntityLibAPI; import me.tofaa.entitylib.EntityLibAPI;
import me.tofaa.entitylib.Platform; import me.tofaa.entitylib.Platform;
import me.tofaa.entitylib.container.EntityContainer;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import me.tofaa.entitylib.meta.projectile.ThrownExpBottleMeta; import me.tofaa.entitylib.meta.projectile.ThrownExpBottleMeta;
import me.tofaa.entitylib.meta.types.LivingEntityMeta; import me.tofaa.entitylib.meta.types.LivingEntityMeta;
@ -33,6 +34,9 @@ public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
protected final Map<Integer, WrapperEntity> entitiesById = new ConcurrentHashMap<>(); protected final Map<Integer, WrapperEntity> entitiesById = new ConcurrentHashMap<>();
protected final Map<UUID, WrapperEntity> entities = new ConcurrentHashMap<>(); protected final Map<UUID, WrapperEntity> entities = new ConcurrentHashMap<>();
protected final Set<EntityContainer> entityContainers = ConcurrentHashMap.newKeySet();
protected final EntityContainer defaultEntityContainer = EntityContainer.basic();
protected AbstractEntityLibAPI(Platform<P> platform, APIConfig settings) { protected AbstractEntityLibAPI(Platform<P> platform, APIConfig settings) {
this.platform = platform; this.platform = platform;
this.packetEvents = settings.getPacketEvents(); this.packetEvents = settings.getPacketEvents();
@ -40,125 +44,6 @@ public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.emptyList(); this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.emptyList();
} }
@Override
public <T1 extends WrapperEntity> @NotNull T1 createEntity(UUID uuid, int entityId, EntityType type) {
if (entities.containsKey(uuid)) {
throw new IllegalArgumentException("Entity with UUID " + uuid + " already exists in this world.");
}
if (entitiesById.containsKey(entityId)) {
throw new IllegalArgumentException("Entity with ID " + entityId + " already exists in this world.");
}
EntityMeta meta = EntityMeta.createMeta(entityId, type);
WrapperEntity e;
if (meta instanceof LivingEntityMeta) {
e = new WrapperLivingEntity(entityId, uuid, type, meta);
}
else if (meta instanceof ThrownExpBottleMeta) {
e = new WrapperExperienceOrbEntity(entityId, uuid, type, meta);
}
else {
e = new WrapperEntity(entityId, uuid, type, meta);
}
entities.put(uuid, e);
entitiesById.put(entityId, e);
return (T1) e;
}
@Override
public <T1 extends WrapperEntity> @NotNull T1 createEntity(EntityType type) {
UUID uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(type);
while (entities.containsKey(uuid)) {
uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(type);
}
int entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, type);
while (entitiesById.containsKey(entityId)) {
entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, type);
}
return createEntity(uuid, entityId, type);
}
@Override
public @NotNull WrapperPlayer spawnPlayer(UserProfile profile, Location location) {
if (getEntity(profile.getUUID()) != null) {
throw new IllegalArgumentException("Entity with UUID " + profile.getUUID() + " already exists in this world.");
}
int id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
while (entitiesById.containsKey(id)) {
id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
}
WrapperPlayer player = new WrapperPlayer(profile, id);
player.spawn(location);
entities.put(player.getUuid(), player);
entitiesById.put(player.getEntityId(), player);
return player;
}
@Override
public @NotNull WrapperPlayer createPlayer(UserProfile profile) {
int id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
while (entitiesById.containsKey
(id)) {
id = EntityLib.getPlatform().getEntityIdProvider().provide(profile.getUUID(), EntityTypes.PLAYER);
}
return createPlayer(profile, id);
}
@Override
public @NotNull WrapperPlayer createPlayer(UserProfile profile, int entityId) {
if (getEntity(profile.getUUID()) != null) {
throw new IllegalArgumentException("Entity with UUID " + profile.getUUID() + " already exists in this world.");
}
WrapperPlayer player = new WrapperPlayer(profile, entityId);
entities.put(player.getUuid(), player);
entitiesById.put(player.getEntityId(), player);
return player;
}
@Override
public <T1 extends WrapperEntity> @NotNull T1 spawnEntity(@NotNull T1 entity, @NotNull Location location) {
entity.spawn(location);
entities.put(entity.getUuid(), entity);
entitiesById.put(entity.getEntityId(), entity);
return entity;
}
@Override
public void removeEntity(WrapperEntity entity) {
entity.despawn();
this.entities.remove(entity.getUuid());
this.entitiesById.remove(entity.getEntityId());
}
@Override
public <T1 extends WrapperEntity> @NotNull T1 spawnEntity(@NotNull Class<T1> wrapperClass, @NotNull EntityType entityType, @NotNull Location location) {
UUID uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
while (entities.containsKey(uuid)) {
uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);
}
int entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType);
while (entitiesById.containsKey(entityId)) {
entityId = EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType);
}
EntityMeta meta = EntityMeta.createMeta(entityId, entityType);
WrapperEntity e;
if (meta instanceof LivingEntityMeta) {
e = new WrapperLivingEntity(entityId, uuid, entityType, meta);
}
else if (meta instanceof ThrownExpBottleMeta) {
e = new WrapperExperienceOrbEntity(entityId, uuid, entityType, meta);
}
else {
e = new WrapperEntity(entityId, uuid, entityType, meta);
}
return spawnEntity(wrapperClass.cast(e), location);
}
@Override
public @NotNull WrapperEntity spawnEntity(@NotNull EntityType entityType, @NotNull Location location) {
return spawnEntity(WrapperEntity.class, entityType, location);
}
@Override @Override
public @Nullable WrapperEntity getEntity(int id) { public @Nullable WrapperEntity getEntity(int id) {
return entitiesById.get(id); return entitiesById.get(id);
@ -174,6 +59,27 @@ public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
return Collections.unmodifiableCollection(entities.values()); return Collections.unmodifiableCollection(entities.values());
} }
@Override
public void addContainer(EntityContainer container) {
entityContainers.add(container);
}
@Override
public void removeContainer(EntityContainer container) {
entityContainers.remove(container);
}
@Override
public @NotNull EntityContainer getDefaultContainer() {
return defaultEntityContainer;
}
@NotNull
@Override
public Set<EntityContainer> getEntityContainers() {
return entityContainers;
}
@NotNull @NotNull
@Override @Override
public APIConfig getSettings() { public APIConfig getSettings() {

View file

@ -1,6 +1,6 @@
dependencies { dependencies {
api(project(":common")) api(project(":common"))
compileOnly('com.github.retrooper.packetevents:spigot:2.3.0') compileOnly('com.github.retrooper.packetevents:spigot:' + peVersion)
compileOnly('org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT') compileOnly('org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT')
} }

View file

@ -44,7 +44,7 @@ public class SpigotEntityLibAPI extends AbstractEntityLibAPI<JavaPlugin, BukkitT
} }
@Override @Override
public <T extends WrapperEntity> @NotNull T cloneEntity(@NotNull Object platformEntity, @NotNull Location location) { public <T extends WrapperEntity> @NotNull T cloneEntity(@NotNull Object platformEntity) {
Check.stateCondition(!(platformEntity instanceof Entity), "Entity must be a Bukkit entity"); Check.stateCondition(!(platformEntity instanceof Entity), "Entity must be a Bukkit entity");
Entity e = (Entity) platformEntity; Entity e = (Entity) platformEntity;
EntityType type = SpigotConversionUtil.fromBukkitEntityType(e.getType()); EntityType type = SpigotConversionUtil.fromBukkitEntityType(e.getType());
@ -84,10 +84,7 @@ public class SpigotEntityLibAPI extends AbstractEntityLibAPI<JavaPlugin, BukkitT
else { else {
entity = new WrapperEntity(id, uuid, type, meta); entity = new WrapperEntity(id, uuid, type, meta);
} }
if (entity == null) { return (T) entity;
throw new IllegalArgumentException("Could not clone entity");
}
return (T) this.spawnEntity(entity, location);
} }
@Override @Override

View file

@ -0,0 +1,6 @@
dependencies {
api(project(":common"))
compileOnly('com.github.retrooper.packetevents:api:2.3.0')
}

View file

@ -0,0 +1,57 @@
package me.tofaa.entitylib.standalone;
import com.github.retrooper.packetevents.protocol.world.Location;
import me.tofaa.entitylib.APIConfig;
import me.tofaa.entitylib.Platform;
import me.tofaa.entitylib.common.AbstractEntityLibAPI;
import me.tofaa.entitylib.standalone.task.ExecutionType;
import me.tofaa.entitylib.standalone.task.Scheduler;
import me.tofaa.entitylib.standalone.task.Task;
import me.tofaa.entitylib.standalone.task.TaskSchedule;
import me.tofaa.entitylib.tick.TickContainer;
import me.tofaa.entitylib.wrapper.WrapperEntity;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Level;
public class StandaloneEntityLibApi extends AbstractEntityLibAPI<Object, Task> {
private final Scheduler scheduler = Scheduler.newScheduler();
protected StandaloneEntityLibApi(Platform<Object> platform, APIConfig settings) {
super(platform, settings);
}
@Override
public void onLoad() {
}
@Override
public void onEnable() {
}
@Override
public <P extends WrapperEntity> @NotNull P cloneEntity(@NotNull Object platformEntity) {
throw new UnsupportedOperationException("Not supported in standalone mode");
}
@Override
public void addTickContainer(@NotNull TickContainer<?, Task> tickContainer) {
if (!settings.shouldTickTickables()) {
if (settings.isDebugMode()) {
platform.getLogger().log(Level.WARNING, "Tried to add a TickContainer when ticking tickables is disabled!");
}
return;
}
tickContainers.add(tickContainer);
if (settings.isDebugMode()) {
platform.getLogger().log(Level.CONFIG, "Registering new tick container...");
}
getTickContainers().add(tickContainer);
Task task = scheduler.scheduleTask(() -> tickContainer.tick(System.currentTimeMillis()), TaskSchedule.duration(50L), TaskSchedule.duration(50L), ExecutionType.ASYNC);
tickContainer.setHandle(task);
}
}

View file

@ -0,0 +1,37 @@
package me.tofaa.entitylib.standalone;
import me.tofaa.entitylib.APIConfig;
import me.tofaa.entitylib.EntityLibAPI;
import me.tofaa.entitylib.common.AbstractPlatform;
import org.jetbrains.annotations.NotNull;
public class StandaloneEntityLibPlatform extends AbstractPlatform<Object> {
private StandaloneEntityLibApi api;
private StandaloneEntityLibPlatform() {
super(null);
}
@Override
public void setupApi(@NotNull APIConfig settings) {
super.setupApi(settings);
api = new StandaloneEntityLibApi(this, settings);
}
@Override
public @NotNull Object getHandle() {
throw new UnsupportedOperationException("Standalone platform does not have a handle.");
}
@Override
public EntityLibAPI<?> getAPI() {
return api;
}
@Override
public String getName() {
return "Standalone";
}
}

View file

@ -0,0 +1,8 @@
package me.tofaa.entitylib.standalone.task;
public enum ExecutionType {
BLOCKING,
ASYNC,
}

View file

@ -0,0 +1,29 @@
package me.tofaa.entitylib.standalone.task;
import java.util.function.Supplier;
public interface Scheduler {
static Scheduler newScheduler() {
return new SchedulerImpl();
}
void process();
void shutdown();
Task submitTask(Supplier<TaskSchedule> supplier, ExecutionType type);
default Task scheduleTask(Runnable task, TaskSchedule delay, TaskSchedule repeat, ExecutionType type) {
return buildTask(task)
.delay(delay)
.repeat(repeat)
.executionType(type)
.schedule();
}
default Task.Builder buildTask(Runnable task) {
return new Task.Builder(task, this);
}
}

View file

@ -0,0 +1,87 @@
package me.tofaa.entitylib.standalone.task;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
class SchedulerImpl implements Scheduler {
private static final AtomicInteger TASK_COUNTER = new AtomicInteger(0);
private static final ScheduledExecutorService SCHEDULED_EXECUTOR = Executors.newSingleThreadScheduledExecutor((e) -> {
Thread thread = new Thread(e);
thread.setDaemon(true);
return thread;
});
private static final ForkJoinPool FORK_JOIN_POOL = new ForkJoinPool();
private static final Queue<TaskImpl> TASKS = new ConcurrentLinkedDeque<>();
private Thread thread;
@Override
public void process() {
thread = new Thread(() -> {
while (true) {
process();
}
});
thread.start();
}
@Override
public void shutdown() {
thread.interrupt();
thread = null;
}
@Override
public Task submitTask(Supplier<TaskSchedule> supplier, ExecutionType type) {
TaskImpl task = new TaskImpl(TASK_COUNTER.getAndIncrement(), supplier, type, this);
handleTask(task);
return task;
}
private void handleTask(TaskImpl task) {
TaskSchedule schedule = task.task.get();
if (schedule instanceof TaskSchedule.DurationSchedule) {
TaskSchedule.DurationSchedule d = (TaskSchedule.DurationSchedule) schedule;
SCHEDULED_EXECUTOR.schedule(() -> {
safeExecute(task);
}, d.duration.toMillis(), TimeUnit.MILLISECONDS);
}
else if (schedule instanceof TaskSchedule.FutureSchedule) {
TaskSchedule.FutureSchedule f = (TaskSchedule.FutureSchedule) schedule;
f.future.thenRun(() -> {
safeExecute(task);
});
}
else if (schedule instanceof TaskSchedule.ParkSchedule) {
task.parked = 1;
}
else if (schedule instanceof TaskSchedule.StopSchedule) {
task.cancel();
}
else if (schedule instanceof TaskSchedule.ImmediateSchedule) {
TASKS.offer(task);
}
}
void unparkTask(TaskImpl task) {
task.tryUnpark();
TASKS.offer(task);
}
private void safeExecute(TaskImpl task) {
if (task.executionType() == ExecutionType.BLOCKING) {
TASKS.offer(task);
}
else {
FORK_JOIN_POOL.submit(() -> {
if (task.alive) {
handleTask(task);
}
});
}
}
}

View file

@ -0,0 +1,62 @@
package me.tofaa.entitylib.standalone.task;
import java.util.concurrent.atomic.AtomicBoolean;
public interface Task {
int id();
ExecutionType executionType();
void unpark();
boolean isParked();
void cancel();
class Builder {
private final Runnable runnable;
private final Scheduler scheduler;
private ExecutionType executionType = ExecutionType.SYNC;//default
private TaskSchedule delay = TaskSchedule.immediate();
private TaskSchedule repeat = TaskSchedule.stop();
Builder(Runnable runnable, Scheduler scheduler) {
this.runnable = runnable;
this.scheduler = scheduler;
}
public Builder executionType(ExecutionType executionType) {
this.executionType = executionType;
return this;
}
public Builder delay(TaskSchedule delay) {
this.delay = delay;
return this;
}
public Builder repeat(TaskSchedule repeat) {
this.repeat = repeat;
return this;
}
public Task schedule() {
AtomicBoolean first = new AtomicBoolean();
return scheduler.submitTask(() -> {
if (first.get()) {
first.set(false);
return delay;
}
runnable.run();
return repeat;
}, executionType);
}
}
}

View file

@ -0,0 +1,79 @@
package me.tofaa.entitylib.standalone.task;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.function.Supplier;
class TaskImpl implements Task {
// thread safe way to set the parked value of any task, Like VarHandle but for older java versions
private static final AtomicIntegerFieldUpdater<TaskImpl> PARKED_UPDATER = AtomicIntegerFieldUpdater.newUpdater(TaskImpl.class, "parked");
volatile boolean alive = true;
volatile int parked = 1; // 1 is true, 0 is false
final int id;
final Supplier<TaskSchedule> task;
final ExecutionType type;
final Scheduler owner;
TaskImpl(int id, Supplier<TaskSchedule> task, ExecutionType type, Scheduler owner) {
this.id = id;
this.task = task;
this.type = type;
this.owner = owner;
}
@Override
public int id() {
return id;
}
@Override
public ExecutionType executionType() {
return type;
}
@Override
public void unpark() {
this.owner.unparkTask(this);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
return this.id == ((TaskImpl) obj).id;
}
@Override
public int hashCode() {
// murmur hash 3
int h = id;
h ^= h >>> 16;
h *= 0x85ebca6b;
h ^= h >>> 13;
h *= 0xc2b2ae35;
h ^= h >>> 16;
return h;
}
@Override
public String toString() {
return "SimpleTask(id=" + id + ", task=" + task + ", executionType=" + type + ", owner=" + owner + ", alive=" + alive + ", parked=" + parked + ")";
}
void tryUnpark() {
PARKED_UPDATER.compareAndSet(this, 1, 0);
}
@Override
public boolean isParked() {
return parked == 1;
}
@Override
public void cancel() {
alive = false;
}
}

View file

@ -0,0 +1,79 @@
package me.tofaa.entitylib.standalone.task;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public interface TaskSchedule {
static TaskSchedule duration(Duration duration) {
return new DurationSchedule(duration);
}
static TaskSchedule duration(long duration) {
return new DurationSchedule(Duration.ofMillis(duration));
}
static TaskSchedule duration(long duration, TimeUnit unit) {
return new DurationSchedule(Duration.ofMillis(unit.toMillis(duration)));
}
static TaskSchedule seconds(long seconds) {
return new DurationSchedule(Duration.ofSeconds(seconds));
}
static TaskSchedule minutes(long minutes) {
return new DurationSchedule(Duration.ofMinutes(minutes));
}
static TaskSchedule hours(long hours) {
return new DurationSchedule(Duration.ofHours(hours));
}
static TaskSchedule milliseconds(long milliseconds) {
return new DurationSchedule(Duration.ofMillis(milliseconds));
}
static TaskSchedule future(CompletableFuture<?> future) {
return new FutureSchedule(future);
}
static TaskSchedule park() {
return ParkSchedule.INSTANCE;
}
static TaskSchedule stop() {
return StopSchedule.INSTANCE;
}
static TaskSchedule immediate() {
return ImmediateSchedule.INSTANCE;
}
class DurationSchedule implements TaskSchedule {
Duration duration;
DurationSchedule(Duration duration) {
this.duration = duration;
}
}
class FutureSchedule implements TaskSchedule {
CompletableFuture<?> future;
FutureSchedule(CompletableFuture<?> future) {
this.future = future;
}
}
class ParkSchedule implements TaskSchedule {
private static final ParkSchedule INSTANCE = new ParkSchedule();
ParkSchedule() {}
}
class StopSchedule implements TaskSchedule {
private static final StopSchedule INSTANCE = new StopSchedule();
StopSchedule() {}
}
class ImmediateSchedule implements TaskSchedule {
private static final ImmediateSchedule INSTANCE = new ImmediateSchedule();
ImmediateSchedule() {}
}
}

View file

@ -15,6 +15,6 @@ java.toolchain.languageVersion.set(JavaLanguageVersion.of(17))
dependencies { dependencies {
api(project(":common")) api(project(":common"))
compileOnly('com.github.retrooper.packetevents:velocity:2.3.0') compileOnly('com.github.retrooper.packetevents:velocity:' + peVersion)
compileOnly 'com.velocitypowered:velocity-api:3.3.0-SNAPSHOT' compileOnly 'com.velocitypowered:velocity-api:3.3.0-SNAPSHOT'
} }

View file

@ -1,10 +1,8 @@
package me.tofaa.entitylib.velocity; package me.tofaa.entitylib.velocity;
import com.github.retrooper.packetevents.protocol.world.Location;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.scheduler.ScheduledTask; import com.velocitypowered.api.scheduler.ScheduledTask;
import me.tofaa.entitylib.APIConfig; import me.tofaa.entitylib.APIConfig;
import me.tofaa.entitylib.Platform;
import me.tofaa.entitylib.common.AbstractEntityLibAPI; import me.tofaa.entitylib.common.AbstractEntityLibAPI;
import me.tofaa.entitylib.tick.TickContainer; import me.tofaa.entitylib.tick.TickContainer;
import me.tofaa.entitylib.wrapper.WrapperEntity; import me.tofaa.entitylib.wrapper.WrapperEntity;
@ -50,7 +48,7 @@ public class VelocityEntityLibAPI extends AbstractEntityLibAPI<ProxyServer, Sche
@NotNull @NotNull
@Override @Override
public WrapperEntity cloneEntity(@NotNull Object platformEntity, @NotNull Location location) { public <P extends WrapperEntity> P cloneEntity(@NotNull Object platformEntity) {
throw new UnsupportedOperationException("No support for cloning entities on Velocity"); throw new UnsupportedOperationException("No support for cloning entities on Velocity");
} }
} }

View file

@ -16,3 +16,6 @@ if (!Boolean.parseBoolean(System.getenv("JITPACK"))) {
include 'platforms:velocity' include 'platforms:velocity'
findProject(':platforms:velocity')?.name = 'velocity' findProject(':platforms:velocity')?.name = 'velocity'
include 'platforms:standalone'
findProject(':platforms:standalone')?.name = 'standalone'

View file

@ -43,6 +43,7 @@ public class TestEntityLibPlugin extends JavaPlugin {
commandMap.register("testapi", new TestTextDisplayCommand()); commandMap.register("testapi", new TestTextDisplayCommand());
commandMap.register("testplayer", new TestPlayerCommand()); commandMap.register("testplayer", new TestPlayerCommand());
commandMap.register("testholo", new TestHologramsCommand()); commandMap.register("testholo", new TestHologramsCommand());
commandMap.register("testmassivepig", new TestMassivePigCommand());
} }
catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();

View file

@ -3,6 +3,7 @@ package me.tofaa.testentitylib;
import com.github.retrooper.packetevents.protocol.attribute.Attributes; import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.wrapper.WrapperLivingEntity; import me.tofaa.entitylib.wrapper.WrapperLivingEntity;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -30,7 +31,7 @@ public class TestMassivePigCommand extends BukkitCommand {
player.sendMessage("Large pig removed"); player.sendMessage("Large pig removed");
return true; return true;
} }
pig = EntityLib.getApi().createEntity(EntityTypes.PIG); pig = new WrapperLivingEntity(EntityTypes.PIG);
pig.getAttributes().setAttribute( pig.getAttributes().setAttribute(
Attributes.GENERIC_SCALE, Attributes.GENERIC_SCALE,
10, 10,
@ -40,6 +41,8 @@ public class TestMassivePigCommand extends BukkitCommand {
WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.MULTIPLY_BASE WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.MULTIPLY_BASE
) )
); );
pig.addViewer(player.getUniqueId());
pig.spawn(SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
player.sendMessage("Large pig spawned"); player.sendMessage("Large pig spawned");
return true; return true;
} }

View file

@ -22,19 +22,19 @@ public class TestTextDisplayCommand extends BukkitCommand {
@Override @Override
public boolean execute(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) { public boolean execute(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) {
if (!(commandSender instanceof Player)) return true; // if (!(commandSender instanceof Player)) return true;
Player player = (Player) commandSender; // Player player = (Player) commandSender;
if (e == null) { // if (e == null) {
e = EntityLib.getApi().createEntity(EntityTypes.PIG); // e = EntityLib.getApi().createEntity(EntityTypes.PIG);
e.spawn(SpigotConversionUtil.fromBukkitLocation(player.getLocation())); // e.spawn(SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
e.addViewer(player.getUniqueId()); // e.addViewer(player.getUniqueId());
player.sendMessage("Spawned"); // player.sendMessage("Spawned");
} // }
String msg = String.join(" ", strings); // String msg = String.join(" ", strings);
PigMeta meta = (PigMeta) e.getEntityMeta(); // PigMeta meta = (PigMeta) e.getEntityMeta();
meta.setCustomNameVisible(true); // meta.setCustomNameVisible(true);
meta.setCustomName(Component.text(msg)); // meta.setCustomName(Component.text(msg));
player.sendMessage("Set text to: " + msg); // player.sendMessage("Set text to: " + msg);
return true; return true;
} }
} }