rewrite to a more platformized structure.

This commit is contained in:
Tofaa 2024-01-26 13:17:38 +04:00
parent 54a730754f
commit 3091083821
20 changed files with 888 additions and 34 deletions

View file

@ -5,11 +5,20 @@
</component>
<component name="ChangeListManager">
<list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLibPlatform.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/WrapperWorld.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/EntityLibEvent.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/event/UserReceiveMetaUpdateEvent.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/extras/InvalidVersionException.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/EntityMeta.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/TickContainer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/api/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/Metadata.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/Metadata.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -72,30 +81,34 @@
<option name="showExcludedFiles" value="false" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"Gradle.Build EntityLib.executor": "Run",
"Gradle.EntityLib:test-plugin [runServer].executor": "Run",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"WebServerToolWindowFactoryState": "false",
"git-widget-placeholder": "feat/platform-api",
"ignore.virus.scanning.warn.message": "true",
"jdk.selected.JAVA_MODULE": "corretto-17",
"kotlin-language-version-configured": "true",
"last_opened_file_path": "D:/Github/EntityLib",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"project.structure.last.edited": "Modules",
"project.structure.proportion": "0.0",
"project.structure.side.proportion": "0.0",
"settings.editor.selected.configurable": "preferences.pluginManager",
"vue.rearranger.settings.migration": "true"
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;Downloaded.Files.Path.Enabled&quot;: &quot;false&quot;,
&quot;Gradle.Build EntityLib.executor&quot;: &quot;Run&quot;,
&quot;Gradle.EntityLib:test-plugin [runServer].executor&quot;: &quot;Run&quot;,
&quot;Repository.Attach.Annotations&quot;: &quot;false&quot;,
&quot;Repository.Attach.JavaDocs&quot;: &quot;false&quot;,
&quot;Repository.Attach.Sources&quot;: &quot;false&quot;,
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;feat/platform-api&quot;,
&quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
&quot;jdk.selected.JAVA_MODULE&quot;: &quot;corretto-17&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/Github/EntityLib&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;project.structure.last.edited&quot;: &quot;Modules&quot;,
&quot;project.structure.proportion&quot;: &quot;0.0&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.0&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}]]></component>
}</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\Github\EntityLib\test-plugin" />
@ -216,6 +229,10 @@
<workItem from="1705578156456" duration="78000" />
<workItem from="1705636302508" duration="7111000" />
<workItem from="1705951390204" duration="3936000" />
<workItem from="1705984769972" duration="76000" />
<workItem from="1706183895216" duration="664000" />
<workItem from="1706187926445" duration="4339000" />
<workItem from="1706248178234" duration="1973000" />
</task>
<servers />
</component>

View file

@ -1,5 +1,6 @@
plugins {
id 'java'
id 'java-library'
}
group = 'me.tofaa.entitylib'
@ -10,10 +11,8 @@ repositories {
}
dependencies {
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
api 'org.jetbrains:annotations:24.0.0'
test {
useJUnitPlatform()
compileOnlyApi(adventureDependencies)
compileOnlyApi 'com.github.retrooper.packetevents:api:2.2.0'
}

View file

@ -0,0 +1,100 @@
package me.tofaa.entitylib;
import com.github.retrooper.packetevents.PacketEventsAPI;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
public final class APISettings {
private boolean debugMode = false;
private boolean checkForUpdates = false;
private boolean tickTickables = false;
private PacketEventsAPI<?> packetEvents;
private boolean platformLogger = false;
public APISettings(PacketEventsAPI<?> packetEvents) {
this.packetEvents = packetEvents;
}
public boolean requiresUpdate() throws IOException {
if (!checkForUpdates) return false;
String urlString = "https://api.github.com/repos/Tofaa2/EntityLib/releases/latest";
String version = EntityLib.getVersion();
URL url = new URL(urlString);
JsonParser json = new JsonParser();
InputStream stream = url.openStream();
JsonArray array = json.parse(new InputStreamReader(stream)).getAsJsonArray();
String latest = array.get(0).getAsJsonObject().get("tag_name").getAsString();
stream.close();
return !version.equalsIgnoreCase(latest);
}
public @NotNull APISettings usePlatformLogger() {
this.platformLogger = true;
return this;
}
public @NotNull APISettings usePlatformLogger(boolean platformLogger) {
this.platformLogger = platformLogger;
return this;
}
public @NotNull APISettings debugMode(boolean debugMode) {
this.debugMode = debugMode;
return this;
}
public @NotNull APISettings checkForUpdates() {
this.checkForUpdates = true;
return this;
}
public @NotNull APISettings tickTickables() {
this.tickTickables = true;
return this;
}
public @NotNull APISettings debugMode() {
this.debugMode = true;
return this;
}
public @NotNull APISettings checkForUpdates(boolean checkForUpdates) {
this.checkForUpdates = checkForUpdates;
return this;
}
public @NotNull APISettings tickTickables(boolean tickTickables) {
this.tickTickables = tickTickables;
return this;
}
public boolean isDebugMode() {
return debugMode;
}
public boolean shouldCheckForUpdate() {
return checkForUpdates;
}
public boolean shouldTickTickables() {
return tickTickables;
}
public PacketEventsAPI<?> getPacketEvents() {
return packetEvents;
}
public boolean shouldUsePlatformLogger() {
return platformLogger;
}
}

View file

@ -0,0 +1,28 @@
package me.tofaa.entitylib;
public final class EntityLib {
private EntityLib() {}
private static String version = "1.2.0-SNAPSHOT";
private static Platform platform;
private static EntityLibAPI api;
public static void init(Platform<?> platform, APISettings settings) {
EntityLib.platform = platform;
platform.setupApi(settings);
api = platform.getAPI();
}
public static EntityLibAPI<?, ?> getApi() {
return api;
}
public static Platform<?> getPlatform() {
return platform;
}
public static String getVersion() {
return version;
}
}

View file

@ -0,0 +1,43 @@
package me.tofaa.entitylib;
import com.github.retrooper.packetevents.PacketEventsAPI;
import me.tofaa.entitylib.tick.TickContainer;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Represents the API for EntityLib.
* Handles the loading, enabling, and disabling of the API. And handles platform specific creation of EntityLib content.
* @param <W> The {@link WorldWrapper}'s param type for the platform specific World.
* @param <T> The {@link TickContainer}'s param type for the platform specific TickContainer.
*/
public interface EntityLibAPI<W, T> {
PacketEventsAPI<?> getPacketEvents();
void onLoad();
void onEnable();
@NotNull APISettings getSettings();
/**
* If a platform supports ticking
* this method should be responsible for setting up the {@link me.tofaa.entitylib.tick.TickContainer}'s.
*/
void setupTickingContainers();
/**
* @return An unmodifiable collection of TickContainers.
*/
@NotNull Collection<TickContainer<?, T>> getTickContainers();
/**
* Adds a TickContainer to the API. Automatically starts ticking it.
* @param tickContainer the TickContainer to add.
*/
void addTickContainer(@NotNull TickContainer<?, T> tickContainer);
}

View file

@ -0,0 +1,53 @@
package me.tofaa.entitylib;
import me.tofaa.entitylib.event.EntityLibEvent;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
import java.util.logging.Logger;
/**
* A generic representation of a platform that EntityLib is running on.
* @param <P> The platform handle, for Spigot this would be a JavaPlugin. etc etc.
*/
public interface Platform<P> {
/**
* @return the logger EntityLib uses internally.
*/
@NotNull Logger getLogger();
/**
* Sends an event to the platform. Platform implementations should handle the event accordingly.
* @param event the event to send.
*/
void sendEvent(EntityLibEvent event);
/**
* Registers a listener for the given event class, the handle will be called when the event is sent.
* @param eventClass the event class to listen for.
* @param handle the handle to call when the event is sent.
* @param <T> the event type.
*/
<T extends EntityLibEvent> void registerListener(Class<T> eventClass, Consumer<T> handle);
/**
* Sets up the API for the platform. This method should be called automatically by the platform. Don't call it yourself.
* @param settings
*/
void setupApi(@NotNull APISettings settings);
/**
* @return The API instance.
*/
EntityLibAPI<?, ?> getAPI();
/**
* @return the platforms name.
*/
String getName();
@NotNull P getHandle();
}

View file

@ -0,0 +1,19 @@
package me.tofaa.entitylib;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.resources.ResourceLocation;
/**
* Represents a platform specific world.
* These are not needed at all times, and should exclusively be used when an Entity needs to be
* aware of its surroundings.
* @param <W> The platform specific World type.
*/
public interface WorldWrapper<W> {
ResourceLocation getPacketEventsWorld();
WrappedBlockState getBlock(int x, int y, int z);
W getHandle();
}

View file

@ -0,0 +1,13 @@
package me.tofaa.entitylib.event;
public interface EntityLibEvent {
boolean isCancelled();
void setCancelled(boolean cancelled);
default boolean isAsync() {
return false;
}
}

View file

@ -0,0 +1,29 @@
package me.tofaa.entitylib.event;
import com.github.retrooper.packetevents.protocol.player.User;
import me.tofaa.entitylib.meta.EntityMeta;
public final class UserReceiveMetaUpdateEvent implements EntityLibEvent {
private final User user;
private boolean cancelled;
private EntityMeta meta;
public UserReceiveMetaUpdateEvent(User user) {
this.user = user;
}
public User getUser() {
return user;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public void setCancelled(boolean cancelled) {
}
}

View file

@ -0,0 +1,23 @@
package me.tofaa.entitylib.extras;
public class InvalidVersionException extends RuntimeException {
public InvalidVersionException() {
}
public InvalidVersionException(String message) {
super(message);
}
public InvalidVersionException(String message, Throwable cause) {
super(message, cause);
}
public InvalidVersionException(Throwable cause) {
super(cause);
}
public InvalidVersionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View file

@ -0,0 +1,221 @@
package me.tofaa.entitylib.meta;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.manager.server.VersionComparison;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import com.github.retrooper.packetevents.protocol.entity.data.EntityMetadataProvider;
import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.extras.InvalidVersionException;
import net.kyori.adventure.text.Component;
import java.util.List;
public class EntityMeta implements EntityMetadataProvider {
public static final byte OFFSET = 0;
public static final byte MAX_OFFSET = OFFSET + 8;
private final static byte ON_FIRE_BIT = 0x01;
private final static byte CROUCHING_BIT = 0x02;
private final static byte SPRINTING_BIT = 0x08;
private final static byte SWIMMING_BIT = 0x10;
private final static byte INVISIBLE_BIT = 0x20;
private final static byte HAS_GLOWING_EFFECT_BIT = 0x40;
private final static byte FLYING_WITH_ELYTRA_BIT = (byte) 0x80;
protected final int entityId;
protected final Metadata metadata;
public EntityMeta(int entityId, Metadata metadata) {
this.entityId = entityId;
this.metadata = metadata;
}
public boolean isOnFire() {
return getMaskBit(OFFSET, ON_FIRE_BIT);
}
public void setOnFire(boolean value) {
setMaskBit(OFFSET, ON_FIRE_BIT, value);
}
public boolean isSneaking() {
return getMaskBit(OFFSET, CROUCHING_BIT);
}
public void setSneaking(boolean value) {
setMaskBit(OFFSET, CROUCHING_BIT, value);
}
public boolean isSprinting() {
return getMaskBit(OFFSET, SPRINTING_BIT);
}
public void setSprinting(boolean value) {
setMaskBit(OFFSET, SPRINTING_BIT, value);
}
public boolean isInvisible() {
return getMaskBit(OFFSET, INVISIBLE_BIT);
}
public void setInvisible(boolean value) {
setMaskBit(OFFSET, INVISIBLE_BIT, value);
}
public short getAirTicks() {
return this.metadata.getIndex((byte) 1, (short) 300);
}
public void setAirTicks(short value) {
this.metadata.setIndex((byte) 1, EntityDataTypes.SHORT, value);
}
public Component getCustomName() {
return this.metadata.getIndex(offset(OFFSET, 2), null);
}
public void setCustomName(Component value) {
this.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.ADV_COMPONENT, value);
}
public boolean isCustomNameVisible() {
return this.metadata.getIndex(offset(OFFSET, 3), false);
}
public void setCustomNameVisible(boolean value) {
this.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BOOLEAN, value);
}
public boolean hasGlowingEffect() {
return getMaskBit(OFFSET, HAS_GLOWING_EFFECT_BIT);
}
public boolean isSwimming() {
return getMaskBit(OFFSET, SWIMMING_BIT);
}
public void setSwimming(boolean value) {
setMaskBit(OFFSET, SWIMMING_BIT, value);
}
public void setHasGlowingEffect(boolean value) {
setMaskBit(OFFSET, HAS_GLOWING_EFFECT_BIT, value);
}
public boolean isFlyingWithElytra() {
return getMaskBit(OFFSET, FLYING_WITH_ELYTRA_BIT);
}
public void setFlyingWithElytra(boolean value) {
setMaskBit(OFFSET, FLYING_WITH_ELYTRA_BIT, value);
}
public boolean isSilent() {
return this.metadata.getIndex((byte) 4, false);
}
public void setSilent(boolean value) {
this.metadata.setIndex((byte) 4, EntityDataTypes.BOOLEAN, value);
}
public boolean isHasNoGravity() {
return this.metadata.getIndex(offset(OFFSET, 5), true);
}
public void setHasNoGravity(boolean value) {
this.metadata.setIndex(offset(OFFSET, 5), EntityDataTypes.BOOLEAN, value);
}
public EntityPose getPose() {
return this.metadata.getIndex(offset(OFFSET, 6), EntityPose.STANDING);
}
public void setPose(EntityPose value) {
this.metadata.setIndex(offset(OFFSET, 6), EntityDataTypes.ENTITY_POSE, value);
}
public int getTicksFrozenInPowderedSnow() {
return this.metadata.getIndex(offset(OFFSET, 7), 0);
}
public void setTicksFrozenInPowderedSnow(int value) {
this.metadata.setIndex(offset(OFFSET, 7), EntityDataTypes.INT, value);
}
public WrapperPlayServerEntityMetadata createPacket() {
return metadata.createPacket();
}
protected static void isVersionOlder(ServerVersion version) {
if (!EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.OLDER_THAN, version)) {
throw new InvalidVersionException("This method is only available for versions older than " + version.name() + ".");
}
}
protected static void isVersionNewer(ServerVersion version) {
if (!EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.NEWER_THAN, version)) {
throw new InvalidVersionException("This method is only available for versions newer than " + version.name() + ".");
}
}
protected static boolean isVersion(ServerVersion version, VersionComparison comparison) {
return EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(comparison, version);
}
protected static boolean isVersion(ServerVersion version) {
return EntityLib.getApi().getPacketEvents().getServerManager().getVersion().is(VersionComparison.EQUALS, version);
}
/**
* Annoying java 8 not letting me do OFFSET + amount in the method call so this is a workaround
* @param value the value to offset
* @param amount the amount to offset by
* @return the offset value
*/
protected static byte offset(byte value, int amount) {
return (byte) (value + amount);
}
protected byte getMask(byte index) {
return this.metadata.getIndex(index, (byte) 0);
}
protected void setMask(byte index, byte mask) {
this.metadata.setIndex(index, EntityDataTypes.BYTE, mask);
}
protected boolean getMaskBit(byte index, byte bit) {
return (getMask(index) & bit) == bit;
}
protected void setMaskBit(int index, byte bit, boolean value) {
byte mask = getMask((byte)index);
boolean currentValue = (mask & bit) == bit;
if (currentValue == value) {
return;
}
if (value) {
mask |= bit;
} else {
mask &= (byte) ~bit;
}
setMask((byte)index, mask);
}
@Override
public List<EntityData> entityData(ClientVersion clientVersion) {
return metadata.getEntries(); // TODO: Atm this is useless cause of the way the api works. Might change in the future
}
@Override
public List<EntityData> entityData() {
return metadata.getEntries();
}
}

View file

@ -0,0 +1,45 @@
package me.tofaa.entitylib.meta;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
import me.tofaa.entitylib.EntityLib;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@SuppressWarnings("unchecked")
public class Metadata {
private final Map<Byte, EntityData> metadataMap = new ConcurrentHashMap<>();
private final int entityId;
public Metadata(int entityId) {
this.entityId = entityId;
}
public <T> T getIndex(byte index, @Nullable T defaultValue) {
EntityData entityData = metadataMap.get(index);
if (entityData == null) return defaultValue;
if (entityData.getValue() == null) return defaultValue;
return (T) entityData.getValue();
}
public <T> void setIndex(byte index, @NotNull EntityDataType<T> dataType, T value) {
EntityData data = new EntityData(index, dataType, value);
this.metadataMap.put(index, data);
}
@NotNull List<EntityData> getEntries() {
return new ArrayList<>(metadataMap.values());
}
public WrapperPlayServerEntityMetadata createPacket() {
return new WrapperPlayServerEntityMetadata(entityId, getEntries());
}
}

View file

@ -0,0 +1,72 @@
package me.tofaa.entitylib.tick;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Represents a storage/container for {@link Tickable}s.
* @param <T> The type of {@link Tickable} to store.
* @param <H> If a platform enforces a specific method of ticking, this type represents the handler for that method.
*/
public abstract class TickContainer<T extends Tickable, H> {
private final Set<T> tickables = new HashSet<>();
private H handle;
/**
* @return The {@link Tickable}s stored in this container. This collection is immutable
*/
public @NotNull Collection<T> getTickables() {
return Collections.unmodifiableCollection(tickables);
}
/**
* Adds a {@link Tickable} to this container.
* @param tickable The {@link Tickable} to add.
* @return {@code true} if the {@link Tickable} was added, {@code false} otherwise.
*/
public boolean addTickable(@NotNull T tickable) {
return tickables.add(tickable);
}
/**
* Removes a {@link Tickable} from this container.
* @param tickable The {@link Tickable} to remove.
* @return {@code true} if the {@link Tickable} was removed, {@code false} otherwise.
*/
public boolean removeTickable(T tickable) {
return tickables.remove(tickable);
}
/**
* Ticks all {@link Tickable}s in this container, this method can be overriden to provide a custom implementation.
* @param time The current time in milliseconds, incase the {@link Tickable} needs to know the current time.
*/
public void tick(long time) {
for (T tickable : tickables) {
tickable.tick(time);
}
}
/**
* @return The handler for this container.
*/
public @NotNull H getHandle() {
return handle;
}
/**
* Sets the handler for this container. This method is only used internally.
* @param handle The handler to set.
*/
@ApiStatus.Internal
public void setHandle(@NotNull H handle) {
this.handle = handle;
}
}

View file

@ -0,0 +1,7 @@
package me.tofaa.entitylib.tick;
public interface Tickable {
void tick(long time);
}

View file

@ -5,6 +5,12 @@ plugins {
allprojects {
project.ext.adventureVersion = '4.15.0'
project.ext.adventureDependencies=["net.kyori:adventure-api:${adventureVersion}",
"net.kyori:adventure-text-serializer-gson:${adventureVersion}",
"net.kyori:adventure-text-serializer-legacy:${adventureVersion}",
"net.kyori:adventure-nbt:${adventureVersion}"]
apply plugin: 'java'
group = 'me.tofaa.entitylib'

View file

@ -0,0 +1,15 @@
plugins {
id 'java'
}
group = 'me.tofaa.entitylib'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation(project(":api"))
implementation('org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT')
}

View file

@ -0,0 +1,98 @@
package me.tofaa.entitylib.spigot;
import com.github.retrooper.packetevents.PacketEventsAPI;
import me.tofaa.entitylib.APISettings;
import me.tofaa.entitylib.EntityLibAPI;
import me.tofaa.entitylib.tick.TickContainer;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.logging.Level;
public class SpigotEntityLibAPI implements EntityLibAPI<World, BukkitTask> {
private final SpigotEntityLibPlatform platform;
private final PacketEventsAPI<?> packetEvents;
private final APISettings settings;
private Collection<TickContainer<?, BukkitTask>> tickContainers;
SpigotEntityLibAPI(SpigotEntityLibPlatform platform, APISettings settings) {
this.platform = platform;
this.packetEvents = settings.getPacketEvents();
this.settings = settings;
}
@Override
public void onLoad() {
this.tickContainers = settings.shouldTickTickables() ? new HashSet<>() : Collections.EMPTY_SET;
}
@Override
public void onEnable() {
}
@NotNull @Override
public APISettings getSettings() {
return settings;
}
@Override
public void setupTickingContainers() {
if (!getSettings().shouldTickTickables()) {
if (getSettings().isDebugMode()) {
platform.getLogger().log(Level.CONFIG, "Skipping ticking containers as it is disabled in the settings.");
}
return;
}
if (getSettings().isDebugMode()) {
platform.getLogger().log(Level.CONFIG, "Setting up ticking containers...");
}
if (tickContainers.isEmpty()) {
if (getSettings().isDebugMode()) {
platform.getLogger().log(Level.CONFIG, "No tick containers found.");
}
return;
}
if (getSettings().isDebugMode()) {
platform.getLogger().log(Level.CONFIG, "Found " + tickContainers.size() + " tick containers.");
}
tickContainers.forEach(this::registerNewTickContainer);
}
@Override
public PacketEventsAPI<?> getPacketEvents() {
return packetEvents;
}
@Override
public Collection<TickContainer<?, BukkitTask>> getTickContainers() {
return tickContainers;
}
@Override
public void addTickContainer(@NotNull TickContainer<?, BukkitTask> tickContainer) {
tickContainers.add(tickContainer);
registerNewTickContainer(tickContainer);
}
public void registerNewTickContainer(TickContainer<?, BukkitTask> tickContainer) {
if (getSettings().isDebugMode()) {
platform.getLogger().log(Level.CONFIG, "Registering new tick container...");
}
getTickContainers().add(tickContainer);
BukkitTask task = Bukkit.getScheduler().runTaskTimerAsynchronously(platform.getHandle(), () -> tickContainer.tick(System.currentTimeMillis()), 1L, 1L);
tickContainer.setHandle(task);
}
}

View file

@ -0,0 +1,65 @@
package me.tofaa.entitylib.spigot;
import me.tofaa.entitylib.APISettings;
import me.tofaa.entitylib.EntityLibAPI;
import me.tofaa.entitylib.Platform;
import me.tofaa.entitylib.event.EntityLibEvent;
import me.tofaa.entitylib.tick.TickContainer;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SpigotEntityLibPlatform implements Platform<JavaPlugin> {
private final JavaPlugin plugin;
private SpigotEntityLibAPI api;
private Logger logger;
public SpigotEntityLibPlatform(@NotNull JavaPlugin plugin) {
this.plugin = plugin;
}
@Override
public void setupApi(@NotNull APISettings settings) {
this.logger = settings.shouldUsePlatformLogger() ? plugin.getLogger() : Logger.getLogger("EntityLib");
this.api = new SpigotEntityLibAPI(this, settings);
this.api.onLoad();
this.api.onEnable();
}
@Override
public @NotNull Logger getLogger() {
return logger;
}
@Override
public void sendEvent(EntityLibEvent event) {
}
@Override
public <T extends EntityLibEvent> void registerListener(Class<T> eventClass, Consumer<T> handle) {
}
@Override
public EntityLibAPI getAPI() {
return api;
}
@Override
public @NotNull JavaPlugin getHandle() {
return plugin;
}
@Override
public String getName() {
return "Spigot";
}
}

View file

@ -1,4 +1,6 @@
rootProject.name = 'EntityLib'
include 'test-plugin'
include 'api'
include 'platforms:spigot'
findProject(':platforms:spigot')?.name = 'spigot'

View file

@ -9,7 +9,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;