push some codegen boilerplate

This commit is contained in:
Tofaa 2024-01-31 17:46:25 +04:00
parent 3183a3140d
commit e22a057bff
20 changed files with 724 additions and 41 deletions

View file

@ -9,6 +9,7 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/api" />
<option value="$PROJECT_DIR$/code-gen" />
<option value="$PROJECT_DIR$/common" />
<option value="$PROJECT_DIR$/platforms" />
<option value="$PROJECT_DIR$/platforms/spigot" />

View file

@ -5,15 +5,25 @@
</component>
<component name="ChangeListManager">
<list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/Hologram.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/Main.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaClass.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/code-gen/src/main/java/me/tofaa/entitylib/codegen/MetaMethod.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/code-gen/src/main/resources/EntityMeta.json" 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$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/Metadata.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/ai/goals/RandomHeadMovementGoal.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" 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$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLib.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" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -76,42 +86,56 @@
<option name="showExcludedFiles" value="false" />
<option name="showLibraryContents" value="true" />
</component>
<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 [dependencies].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/api/src/main/java/me/tofaa/entitylib/meta&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.15&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"Downloaded.Files.Path.Enabled": "false",
"Gradle.Build EntityLib.executor": "Run",
"Gradle.EntityLib [dependencies].executor": "Run",
"Gradle.EntityLib:code-gen [:code-gen:Main.main()].executor": "Run",
"Gradle.EntityLib:test-plugin [runServer].executor": "Run",
"Repository.Attach.Annotations": "false",
"Repository.Attach.JavaDocs": "false",
"Repository.Attach.Sources": "false",
"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/api/src/main/java/me/tofaa/entitylib/meta",
"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": "Project",
"project.structure.proportion": "0.15",
"project.structure.side.proportion": "0.2",
"settings.editor.selected.configurable": "preferences.pluginManager",
"vue.rearranger.settings.migration": "true"
}
}</component>
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\Github\EntityLib\api\src\main\java\me\tofaa\entitylib\meta" />
<recent name="D:\Github\EntityLib\test-plugin" />
</key>
</component>
<component name="RunManager" selected="Gradle.EntityLib [dependencies]">
<component name="RunManager" selected="Application.Main">
<configuration name="Main" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="me.tofaa.entitylib.codegen.Main" />
<module name="EntityLib.code-gen.main" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="me.tofaa.entitylib.codegen.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="EntityLib [dependencies]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
<ExternalSystemSettings>
<option name="executionName" />
@ -202,6 +226,7 @@
</configuration>
<recent_temporary>
<list>
<item itemvalue="Application.Main" />
<item itemvalue="Gradle.EntityLib [dependencies]" />
<item itemvalue="Gradle.EntityLib:test-plugin [runServer]" />
<item itemvalue="Gradle.PE-EntityMeta [compileTestJava]" />
@ -256,7 +281,11 @@
<workItem from="1706284605696" duration="11691000" />
<workItem from="1706371324325" duration="1187000" />
<workItem from="1706443875388" duration="4827000" />
<workItem from="1706513591682" duration="2661000" />
<workItem from="1706513591682" duration="8659000" />
<workItem from="1706592660140" duration="89000" />
<workItem from="1706601592145" duration="1670000" />
<workItem from="1706614921404" duration="10508000" />
<workItem from="1706696719616" duration="4783000" />
</task>
<servers />
</component>
@ -271,6 +300,11 @@
<line>6787</line>
<option name="timeStamp" value="1" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java</url>
<line>37</line>
<option name="timeStamp" value="3" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-method">
<url>file://$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/meta/types/DisplayMeta.java</url>
<line>153</line>

View file

@ -30,7 +30,7 @@ public final class EntityLib {
}
}
public static EntityLibAPI<?, ?> getApi() {
public static <W, T> EntityLibAPI<W, T> getApi() {
return api;
}

View file

@ -35,6 +35,8 @@ public interface WorldWrapper<W> {
@Nullable WrapperEntity getEntity(@NotNull UUID uuid);
void removeEntity(WrapperEntity entity);
/**
* Gets the block at the specified coordinates. Depending on the platforms implementation, this method may be slow.
* @param x The x coordinate.

View file

@ -3,7 +3,6 @@ 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;

View file

@ -42,6 +42,7 @@ public class WrapperEntity implements Tickable {
this.entityType = entityType;
this.entityMeta = entityMeta;
this.ticking = true;
this.viewers = new HashSet<>();
}
public boolean spawn(WorldWrapper<?> world, Location location) {
@ -84,15 +85,23 @@ public class WrapperEntity implements Tickable {
return true;
}
public void remove() {
world.removeEntity(this);
}
public void despawn() {
if (!spawned) return;
spawned = false;
sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId));
}
public void teleport(WorldWrapper<?> world, @NotNull Location location) {
public void teleport(WorldWrapper<?> world, @NotNull Location location, boolean onGround) {
if (!spawned) {
return;
}
this.location = location;
this.world = world;
this.onGround = onGround;
sendPacketToViewers(
new WrapperPlayServerEntityTeleport(
entityId,
@ -104,6 +113,10 @@ public class WrapperEntity implements Tickable {
);
}
public void teleport(WorldWrapper<?> world, @NotNull Location location) {
teleport(world, location, onGround);
}
public boolean addViewer(UUID uuid) {
if (!viewers.add(uuid)) {
return false;
@ -129,6 +142,22 @@ public class WrapperEntity implements Tickable {
addViewer(user.getUUID());
}
/**
* Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition
* @param uuid the uuid of the user to add
*/
public void addViewerSilently(UUID uuid) {
viewers.add(uuid);
}
/**
* Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition
* @param user the user to add
*/
public void addViewerSilently(User user) {
addViewerSilently(user.getUUID());
}
public void removeViewer(UUID uuid) {
if (!viewers.remove(uuid)) {
return;
@ -136,6 +165,26 @@ public class WrapperEntity implements Tickable {
sendPacket(uuid, new WrapperPlayServerDestroyEntities(entityId));
}
public void removeViewer(User user) {
removeViewer(user.getUUID());
}
/**
* removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal
* @param uuid of the user to remove
*/
public void removeViewerSilently(UUID uuid) {
viewers.remove(uuid);
}
/**
* removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal
* @param user the user to remove
*/
public void removeViewerSilently(User user) {
removeViewerSilently(user.getUUID());
}
public boolean isOnGround() {
return onGround;
}
@ -345,7 +394,7 @@ public class WrapperEntity implements Tickable {
WrapperEntity e = world.getEntity(passenger);
if (e != null) {
e.riding = -1;
e.teleport(world, e.preRidingLocation);
e.teleport(world, e.preRidingLocation, e.onGround);
}
}

View file

@ -66,7 +66,7 @@ public class RandomHeadMovementGoal extends GoalSelector {
@Override
public void tick(long time) {
--lookTime;
entity.teleport(entity.getWorld(), CoordinateUtil.withDirection(entity.getLocation(), lookDirection));
entity.teleport(entity.getWorld(), CoordinateUtil.withDirection(entity.getLocation(), lookDirection), entity.isOnGround());
}
@Override

View file

@ -0,0 +1,70 @@
package me.tofaa.entitylib.wrapper.hologram;
import com.github.retrooper.packetevents.protocol.world.Location;
import com.github.retrooper.packetevents.util.Vector3f;
import me.tofaa.entitylib.WorldWrapper;
import me.tofaa.entitylib.meta.display.TextDisplayMeta;
import me.tofaa.entitylib.meta.types.DisplayMeta;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.Consumer;
public interface Hologram<W> {
static <C> Hologram.@NotNull Legacy<C> legacy(@NotNull WorldWrapper<C> world, @NotNull Location location) {
return new LegacyHologram<>(world, location);
}
static <C> Hologram.@NotNull Legacy<C> legacy(@NotNull WorldWrapper<C> world, @NotNull Location location, List<Component> lines) {
return new LegacyHologram<>(world, location, lines);
}
@NotNull Location getLocation();
@NotNull WorldWrapper<W> getWorld();
void show();
void hide();
void teleport(Location location);
@Nullable Component getLine(int index);
int length();
void setLine(int index, @Nullable Component line);
void addLine(@Nullable Component line);
interface Modern<W> extends Hologram<W> {
// I got too lazy
void setModifier(@NotNull Consumer<TextDisplayMeta> consumer);
}
interface Legacy<W> extends Hologram<W> {
float getLineOffset(boolean marker);
void setLineOffset(boolean marker, float value);
default float getLineOffset() {
return getLineOffset(false);
}
default void setLineOffset(float value) {
setLineOffset(false, value);
}
boolean isMarker();
void setMarker(boolean marker);
}
}

View file

@ -0,0 +1,140 @@
package me.tofaa.entitylib.wrapper.hologram;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.world.Location;
import com.github.retrooper.packetevents.util.Vector3d;
import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.WorldWrapper;
import me.tofaa.entitylib.meta.other.ArmorStandMeta;
import me.tofaa.entitylib.wrapper.WrapperEntity;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
final class LegacyHologram<W> implements Hologram.Legacy<W> {
private Location location;
private WorldWrapper<W> world;
private List<WrapperEntity> lines = new ArrayList<>(3);
private float lineOffset = -0.9875f;
private float markerOffset = -0.40625f;
private boolean marker;
LegacyHologram(@NotNull WorldWrapper<W> world, @NotNull Location location) {
this.world = world;
this.location = location;
}
LegacyHologram(@NotNull WorldWrapper<W> world, @NotNull Location location, List<Component> lines) {
this(world, location);
for (Component line : lines) {
addLine(line);
}
}
@Override
public boolean isMarker() {
return marker;
}
@Override
public void setMarker(boolean marker) {
this.marker = true;
if (lines.isEmpty()) return;
teleport(location); // refresh
}
@Override
public void show() {
for (WrapperEntity line : lines) {
line.spawn(world, location);
}
teleport(location);
}
@Override
public void hide() {
for (WrapperEntity line : lines) {
line.despawn();
}
}
@Override
public void teleport(Location location) {
this.location = location;
// reversed order
for (int i = lines.size() -1; i >= 0; i--) {
WrapperEntity line = lines.get(i);
double y;
if (marker) {
y = location.getY() + markerOffset;
} else {
y = location.getY() + (i * lineOffset);
}
ArmorStandMeta meta = (ArmorStandMeta) line.getEntityMeta();
meta.setMarker(marker);
Location l = new Location(location.getX(), y, location.getZ(), location.getYaw(), location.getPitch());
line.teleport(world, l, false);
}
}
@Override
public @Nullable Component getLine(int index) {
if (index < 0 || index >= lines.size()) {
return null;
}
return lines.get(index).getEntityMeta().getCustomName();
}
@Override
public void setLine(int index, @Nullable Component line) {
WrapperEntity e = world.spawnEntity(EntityTypes.ARMOR_STAND, location);
ArmorStandMeta meta = (ArmorStandMeta) e.getEntityMeta();
meta.setCustomName(line);
meta.setCustomNameVisible(true);
meta.setInvisible(true);
meta.setHasNoGravity(true);
meta.setSmall(true);
meta.setMarker(marker);
this.lines.set(index, e);
e.spawn(world, location);
teleport(location);
}
@Override
public void addLine(@Nullable Component line) {
setLine(lines.size(), line);
}
@Override
public float getLineOffset(boolean marker) {
return marker ? markerOffset : lineOffset;
}
@Override
public int length() {
return lines.size();
}
@Override
public void setLineOffset(boolean marker, float value) {
if (marker) {
markerOffset = value;
} else {
lineOffset = value;
}
}
@Override
public @NotNull Location getLocation() {
return location;
}
@Override
public @NotNull WorldWrapper<W> getWorld() {
return world;
}
}

View file

@ -0,0 +1,98 @@
package me.tofaa.entitylib.wrapper.hologram;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.world.Location;
import me.tofaa.entitylib.WorldWrapper;
import me.tofaa.entitylib.meta.display.TextDisplayMeta;
import me.tofaa.entitylib.meta.other.ArmorStandMeta;
import me.tofaa.entitylib.wrapper.WrapperEntity;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
final class ModernHologram<W> implements Hologram.Modern<W> {
private Location location;
private WorldWrapper<W> world;
private List<WrapperEntity> lines = new ArrayList<>(3);
private Consumer<TextDisplayMeta> modifier;
@Override
public void show() {
for (WrapperEntity line : lines) {
line.spawn(world, location);
}
teleport(location);
}
@Override
public void hide() {
for (WrapperEntity line : lines) {
line.despawn();
}
}
@Override
public void teleport(Location location) {
this.location = location;
if (lines.isEmpty()) return;
WrapperEntity first = lines.get(0);
first.teleport(world, location);
for (WrapperEntity e : lines) {
if (e.getUuid().equals(first.getUuid())) continue;
first.addPassenger(e);
}
}
@Override
public @Nullable Component getLine(int index) {
if (index < 0 || index >= lines.size()) {
return null;
}
return lines.get(index).getEntityMeta().getCustomName();
}
@Override
public void setLine(int index, @Nullable Component line) {
WrapperEntity e = world.spawnEntity(EntityTypes.TEXT_DISPLAY, location);
TextDisplayMeta meta = (TextDisplayMeta) e.getEntityMeta();
meta.setInvisible(true);
meta.setHasNoGravity(true);
meta.setText(line);
this.modifier.accept(meta);
this.lines.set(index, e);
e.spawn(world, location);
teleport(location);
}
@Override
public void addLine(@Nullable Component line) {
setLine(lines.size(), line);
}
@Override
public int length() {
return lines.size();
}
@Override
public @NotNull Location getLocation() {
return location;
}
@Override
public @NotNull WorldWrapper<W> getWorld() {
return world;
}
@Override
public void setModifier(@NotNull Consumer<TextDisplayMeta> consumer) {
this.modifier = consumer;
}
}

20
code-gen/build.gradle Normal file
View file

@ -0,0 +1,20 @@
plugins {
id 'java'
}
// jdk 17
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.squareup:javapoet:1.13.0'
implementation 'com.github.retrooper.packetevents:api:2.2.0'
implementation 'org.jetbrains:annotations:24.0.0'
}

View file

@ -0,0 +1,114 @@
package me.tofaa.entitylib.codegen;
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 com.google.gson.reflect.TypeToken;
import com.squareup.javapoet.*;
import org.jetbrains.annotations.NotNull;
import javax.lang.model.element.Modifier;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public final class Main {
private Main() {}
public static void main(String[] args) throws IOException {
createMetadataClass();
List<MetaClass> metaClasses = new ArrayList<>();
// test
}
private static void writeClass(MetaClass metaClass) {
File file = new File("src/main/java");
TypeSpec typeSpec = metaClass.create();
JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", typeSpec).build();
try {
FileWriter fileWriter = new FileWriter(file);
javaFile.writeTo(fileWriter);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void createMetadataClass() {
TypeSpec.Builder builder = builder("me.tofaa.entitylib.meta", "Metadata");
builder.addField(int.class, "entityId", Modifier.PRIVATE, Modifier.FINAL);
builder.addField(TypeToken.getParameterized(Map.class, Byte.class, EntityDataType.class).getType(), "metadataMap", Modifier.PRIVATE, Modifier.FINAL);
MethodSpec.Builder constructor = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addCode("this.entityId = entityId;\n")
.addCode("this.metadataMap = new ConcurrentHashMap<>();\n")
.addParameter(int.class, "entityId");
MethodSpec.Builder getIndex = MethodSpec.methodBuilder("getIndex")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(TypeVariableName.get("T"))
.addParameter(byte.class, "index")
.addParameter(TypeVariableName.get("T"), "defaultValue")
.returns(TypeVariableName.get("T"))
.addCode("EntityData entityData = metadataMap.get(index);\n")
.addCode("if (entityData == null) return defaultValue;\n")
.addCode("if (entityData.getValue() == null) return defaultValue;\n")
.addCode("return (T) entityData.getValue();\n");
MethodSpec.Builder setIndex = MethodSpec.methodBuilder("setIndex")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(TypeVariableName.get("T"))
.addParameter(byte.class, "index")
.addParameter(EntityDataType.class, "dataType")
.addParameter(TypeVariableName.get("T"), "value")
.addCode("EntityData data = new EntityData(index, dataType, value);\n")
.addCode("this.metadataMap.put(index, data);\n");
MethodSpec.Builder getEntries = MethodSpec.methodBuilder("getEntries")
.addModifiers(Modifier.PUBLIC)
.returns(TypeToken.getParameterized(List.class, EntityData.class).getType())
.addCode("return new ArrayList<>(metadataMap.values());\n")
.addAnnotation(NotNull.class);
MethodSpec.Builder createPacket = MethodSpec.methodBuilder("createPacket")
.addModifiers(Modifier.PUBLIC)
.returns(WrapperPlayServerEntityMetadata.class)
.addCode("return new WrapperPlayServerEntityMetadata(entityId, getEntries());\n")
.addAnnotation(NotNull.class);
builder.addMethod(constructor.build());
builder.addMethod(getIndex.build());
builder.addMethod(setIndex.build());
builder.addMethod(getEntries.build());
builder.addMethod(createPacket.build());
File file = new File("src/main/java");
JavaFile javaFile = JavaFile.builder("me.tofaa.entitylib.meta", builder.build()).build();
try {
FileWriter fileWriter = new FileWriter(file);
javaFile.writeTo(fileWriter);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
// Include comment in generated code
public static TypeSpec.Builder builder(String packageName, String className) {
return TypeSpec.classBuilder(ClassName.get(packageName, className))
.addModifiers(Modifier.PUBLIC)
.addJavadoc("AUTOGENERATED CODE BY ENTITYLIB CODEGEN\n")
.addJavadoc("DO NOT EDIT\n");
}
}

View file

@ -0,0 +1,34 @@
package me.tofaa.entitylib.codegen;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
import java.util.List;
import static me.tofaa.entitylib.codegen.Main.builder;
public record MetaClass(
String name,
String extendsClass,
List<MetaMethod> methods
) {
public TypeSpec create() {
String split[] = name.split(":");
String packageName = split[0];
String className = split[1];
TypeSpec.Builder builder = builder(packageName, className);
if (extendsClass != null) {
String[] extendsSplit = extendsClass.split(":");
builder.superclass(ClassName.get(extendsSplit[0], extendsSplit[1]));
}
for (MetaMethod method : methods) {
builder.addMethods(method.create());
}
return builder.build();
}
}

View file

@ -0,0 +1,65 @@
package me.tofaa.entitylib.codegen;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import javax.lang.model.element.Modifier;
import java.util.List;
public record MetaMethod(
String name,
String returnType,
String defaultReturn,
String dataType,
List<VersionCheck> versionChecks
) {
public List<MethodSpec> create() {
String[] nameSplit = name.split(":");
String[] returnSplit = returnType.split(":");
String namePackage = nameSplit[0];
String nameClass = nameSplit[1];
String returnPackage = returnSplit[0];
String returnClass = returnSplit[1];
String methodBasedName = nameClass.substring(0, 1).toUpperCase() + nameClass.substring(1);
/* offset calculator first */
MethodSpec.Builder calculator = MethodSpec.methodBuilder(
"calculate" + methodBasedName + "Offset")
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
.addParameter(int.class, "version");
for (VersionCheck check : versionChecks) {
calculator.beginControlFlow("if (version >= $L && version <= $L)", check.from(), check.to());
calculator.addStatement("return $L", check.offset());
calculator.endControlFlow();
}
// throw exception if version is not in range
calculator.addStatement("throw new IllegalArgumentException(\"Version \" + version + \" is not in range\")");
String versionVariable = "byte offset = calculate" + methodBasedName + "Offset(EntityLib.getApi().getPacketEvents().getServerManager().getVersion().getProtocolVersion())";
/* getter method spec. No params */
MethodSpec.Builder getter = MethodSpec.methodBuilder("get" + methodBasedName)
.addModifiers(Modifier.PUBLIC)
.returns(ClassName.get(returnPackage, returnClass))
.addStatement(versionVariable)
.addStatement("return metadata.getIndex(" + "offset," + defaultReturn);
MethodSpec.Builder setter = MethodSpec.methodBuilder("set" + methodBasedName)
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(ClassName.get(returnPackage, returnClass), "value")
.addStatement(versionVariable)
.addStatement("metadata.setIndex(" + "offset, " + dataType + ", " + "value");
return List.of(
calculator.build(),
getter.build(),
setter.build()
);
}
public record VersionCheck(int from, int to, byte offset) {}
}

View file

@ -0,0 +1,15 @@
{
"class-id": "me.tofaa.entitylib.codegen:User",
"methods": [
{
"name": "getUsername",
"return-type": "java.lang.String",
"parameters": [
]
}
]
}

View file

@ -1,7 +1,9 @@
package me.tofaa.entitylib.common;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.PacketEventsAPI;
import me.tofaa.entitylib.APIConfig;
import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.EntityLibAPI;
import me.tofaa.entitylib.Platform;
import me.tofaa.entitylib.tick.TickContainer;

View file

@ -43,6 +43,13 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
return entity;
}
@Override
public void removeEntity(WrapperEntity entity) {
entity.despawn();
this.entities.remove(entity.getUuid());
this.entitiesById.remove(entity.getEntityId());
}
@Override
public <T extends WrapperEntity> @NotNull T spawnEntity(Class<T> wrapperClass, @NotNull EntityType entityType, @NotNull Location location) {
UUID uuid = EntityLib.getPlatform().getEntityUuidProvider().provide(entityType);

View file

@ -4,4 +4,5 @@ include 'api'
include 'platforms:spigot'
findProject(':platforms:spigot')?.name = 'spigot'
include 'common'
include 'code-gen'

View file

@ -281,7 +281,7 @@ public final class EntityLib {
/**
* Sets the entity id provider to the given one.
* @param entityIdProvider the entity id provider. The default implementation can be found at {@link EntityIdProvider#simple()}
* @param entityIdProvider the entity id provider. The default implementation can be found at {@link me.tofaa.entitylib.entity.EntityIdProvider#simple()}
*/
public static void setEntityIdProvider(EntityIdProvider entityIdProvider) {
EntityLib.entityIdProvider = entityIdProvider;

View file

@ -1,12 +1,29 @@
package me.tofaa.testentitylib;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import me.tofaa.entitylib.APIConfig;
import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.EntityLibAPI;
import me.tofaa.entitylib.WorldWrapper;
import me.tofaa.entitylib.spigot.SpigotEntityLibPlatform;
import me.tofaa.entitylib.wrapper.WrapperEntity;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
public class TestEntityLibPlugin extends JavaPlugin {
public class TestEntityLibPlugin extends JavaPlugin implements Listener {
private EntityLibAPI<World, BukkitTask> api;
private WrapperEntity e;
private WorldWrapper<World> world;
@Override
@ -19,5 +36,20 @@ public class TestEntityLibPlugin extends JavaPlugin {
.usePlatformLogger();
EntityLib.init(platform, settings);
api = EntityLib.getApi();
getServer().getPluginManager().registerEvents(this, this);
}
@EventHandler
public void onCrouch(PlayerToggleSneakEvent event) {
Player player = event.getPlayer();
if (e != null) {
e.remove();
e = null;
}
world = api.wrapWorld(player.getWorld());
e = world.spawnEntity(EntityTypes.CHICKEN, SpigotConversionUtil.fromBukkitLocation(player.getLocation()));
}
}