From 737d7cb363bfda7f150579fd08a23065eb9bf530 Mon Sep 17 00:00:00 2001 From: Reider745 <70357814+Reider745@users.noreply.github.com> Date: Tue, 18 Jun 2024 20:27:02 +0300 Subject: [PATCH] =?UTF-8?q?Feat:=20=D0=9E=D1=81=D0=BD=D0=BE=D0=B2=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=B0=D0=B1=D0=BE=D1=80=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/reider745/InnerCoreServer.java | 3 + .../java/com/reider745/api/ReflectHelper.java | 4 + .../reider745/behavior/BehaviorContent.java | 9 +++ .../com/reider745/behavior/BehaviorPack.java | 73 +++++++++++++++++++ .../behavior/entities/ComponentsTag.java | 9 +++ .../behavior/entities/CustomEntity.java | 63 ++++++++++++++++ .../behavior/entities/EntitiesContent.java | 35 +++++++++ .../behavior/entities/EntitiesVersion.java | 7 ++ .../entities/EntityContentFactory.java | 38 ++++++++++ .../behavior/entities/TagContentEntities.java | 4 + .../behavior/entities/TagContentFactory.java | 9 +++ .../entities/formats/EntitiesVersion113.java | 32 ++++++++ .../formats/tags/ComponentsFactory.java | 33 +++++++++ .../formats/tags/DescriptionsFactory.java | 32 ++++++++ .../tags/components/CollisionComponent.java | 26 +++++++ .../tags/components/FireImmuneComponent.java | 21 ++++++ .../com/reider745/hooks/EntityOverrides.java | 50 ++++++++++++- .../java/com/reider745/hooks/ServerHooks.java | 9 ++- 18 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/reider745/behavior/BehaviorContent.java create mode 100644 src/main/java/com/reider745/behavior/BehaviorPack.java create mode 100644 src/main/java/com/reider745/behavior/entities/ComponentsTag.java create mode 100644 src/main/java/com/reider745/behavior/entities/CustomEntity.java create mode 100644 src/main/java/com/reider745/behavior/entities/EntitiesContent.java create mode 100644 src/main/java/com/reider745/behavior/entities/EntitiesVersion.java create mode 100644 src/main/java/com/reider745/behavior/entities/EntityContentFactory.java create mode 100644 src/main/java/com/reider745/behavior/entities/TagContentEntities.java create mode 100644 src/main/java/com/reider745/behavior/entities/TagContentFactory.java create mode 100644 src/main/java/com/reider745/behavior/entities/formats/EntitiesVersion113.java create mode 100644 src/main/java/com/reider745/behavior/entities/formats/tags/ComponentsFactory.java create mode 100644 src/main/java/com/reider745/behavior/entities/formats/tags/DescriptionsFactory.java create mode 100644 src/main/java/com/reider745/behavior/entities/formats/tags/components/CollisionComponent.java create mode 100644 src/main/java/com/reider745/behavior/entities/formats/tags/components/FireImmuneComponent.java diff --git a/src/main/java/com/reider745/InnerCoreServer.java b/src/main/java/com/reider745/InnerCoreServer.java index 861cf1f73..63f309939 100644 --- a/src/main/java/com/reider745/InnerCoreServer.java +++ b/src/main/java/com/reider745/InnerCoreServer.java @@ -6,6 +6,7 @@ import com.google.common.base.Preconditions; import com.reider745.api.CallbackHelper; +import com.reider745.behavior.BehaviorPack; import com.reider745.block.CustomBlock; import com.reider745.commands.CommandsHelper; import com.reider745.event.EventListener; @@ -342,6 +343,8 @@ public void reload() { } public void start() { + /*BehaviorPack pack = new BehaviorPack(new File(InnerCoreServer.dataPath, "pack").getAbsolutePath()); + pack.load();*/ } public static Object getProperty(String variable) { diff --git a/src/main/java/com/reider745/api/ReflectHelper.java b/src/main/java/com/reider745/api/ReflectHelper.java index c8921cf13..90857dfba 100644 --- a/src/main/java/com/reider745/api/ReflectHelper.java +++ b/src/main/java/com/reider745/api/ReflectHelper.java @@ -1,5 +1,9 @@ package com.reider745.api; +import cn.nukkit.entity.Entity; +import cn.nukkit.level.format.FullChunk; +import cn.nukkit.nbt.tag.CompoundTag; + import java.lang.reflect.Field; import java.lang.reflect.Method; diff --git a/src/main/java/com/reider745/behavior/BehaviorContent.java b/src/main/java/com/reider745/behavior/BehaviorContent.java new file mode 100644 index 000000000..4353ee3d4 --- /dev/null +++ b/src/main/java/com/reider745/behavior/BehaviorContent.java @@ -0,0 +1,9 @@ +package com.reider745.behavior; + +import org.json.JSONObject; + +public abstract class BehaviorContent { + public abstract String getTagName(); + public abstract String getDefaultDirectory(); + public abstract void load(JSONObject json); +} diff --git a/src/main/java/com/reider745/behavior/BehaviorPack.java b/src/main/java/com/reider745/behavior/BehaviorPack.java new file mode 100644 index 000000000..e1c85176b --- /dev/null +++ b/src/main/java/com/reider745/behavior/BehaviorPack.java @@ -0,0 +1,73 @@ +package com.reider745.behavior; + +import com.reider745.behavior.entities.EntitiesContent; +import com.zhekasmirnov.horizon.runtime.logger.Logger; +import com.zhekasmirnov.horizon.util.FileUtils; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +public class BehaviorPack { + private static final ArrayList contents_api = new ArrayList<>(); + + static { + contents_api.add(new EntitiesContent()); + + } + + private final String path; + + public BehaviorPack(String path){ + this.path = path + "/"; + } + + public void load(){ + Logger.info("Loaded behavior-pack"); + + final File contentsFile = new File(path + "contents.json"); + if(contentsFile.exists()) { + try { + final JSONObject contents = FileUtils.readJSON(contentsFile); + if (contents.has("content")) { + JSONArray content = contents.getJSONArray("content"); + + for (int i = 0; i < content.length(); i++) { + JSONObject json = content.getJSONObject(i); + + loadFileContext(this.path + json.getString("path")); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + for(BehaviorContent content : contents_api){ + final String pathFolder = this.path + content.getDefaultDirectory(); + final String[] files = new File(pathFolder).list(); + for(String file : files) + loadFileContext(pathFolder+"/"+file); + } + } + + + public void loadFileContext(String path){ + try{ + final JSONObject contents = FileUtils.readJSON(new File(path)); + + for(BehaviorContent content : contents_api){ + if(contents.has(content.getTagName())){ + content.load(contents); + return; + } + } + + throw new RuntimeException("Not support "+path); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/reider745/behavior/entities/ComponentsTag.java b/src/main/java/com/reider745/behavior/entities/ComponentsTag.java new file mode 100644 index 000000000..e1e9671e4 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/ComponentsTag.java @@ -0,0 +1,9 @@ +package com.reider745.behavior.entities; + +public abstract class ComponentsTag { + public abstract String getNameTag(); + + public void load(EntityContentFactory factory, Object json){ + + } +} diff --git a/src/main/java/com/reider745/behavior/entities/CustomEntity.java b/src/main/java/com/reider745/behavior/entities/CustomEntity.java new file mode 100644 index 000000000..c0d776396 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/CustomEntity.java @@ -0,0 +1,63 @@ +package com.reider745.behavior.entities; + +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.custom.EntityDefinition; +import cn.nukkit.level.format.FullChunk; +import cn.nukkit.nbt.tag.CompoundTag; +import cn.nukkit.network.protocol.AddEntityPacket; +import cn.nukkit.network.protocol.DataPacket; + + +public class CustomEntity extends Entity implements cn.nukkit.entity.custom.CustomEntity { + public CustomEntity(FullChunk chunk, CompoundTag nbt) { + super(chunk, nbt); + } + + protected EntityContentFactory factory; + public EntityContentFactory getFactory(){ + if(factory != null) + return factory; + + factory = EntityContentFactory.factoryMap.get(this.namedTag.getString("___id___")); + return factory; + } + + + @Override + public float getWidth() { + return getFactory().collision.width; + } + + @Override + public float getLength() { + return this.getWidth(); + } + + @Override + public float getHeight() { + return getFactory().collision.height; + } + + @Override + public EntityDefinition getEntityDefinition() { + return getFactory().getEntityDefinition(); + } + + @Override + protected DataPacket createAddEntityPacket() { + AddEntityPacket packet = (AddEntityPacket) super.createAddEntityPacket(); + packet.id = getFactory().description.identifier; + return packet; + } + + @Override + public int getNetworkId() { + return -1; + } + + @Override + public void setOnFire(int seconds) { + if(!factory.isFireImmune) + super.setOnFire(seconds); + } +} diff --git a/src/main/java/com/reider745/behavior/entities/EntitiesContent.java b/src/main/java/com/reider745/behavior/entities/EntitiesContent.java new file mode 100644 index 000000000..4237daa2e --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/EntitiesContent.java @@ -0,0 +1,35 @@ +package com.reider745.behavior.entities; + +import com.reider745.behavior.BehaviorContent; +import com.reider745.behavior.entities.formats.EntitiesVersion113; +import org.json.JSONObject; + +import java.util.HashMap; + +public class EntitiesContent extends BehaviorContent { + private static final HashMap versions = new HashMap<>(); + + static { + versions.put("1.13.0", new EntitiesVersion113()); + } + + @Override + public String getTagName() { + return "minecraft:entity"; + } + + @Override + public String getDefaultDirectory() { + return "entities"; + } + + @Override + public void load(JSONObject json) { + final String version_name = json.getString("format_version"); + final EntitiesVersion version = versions.get(version_name); + if(version == null) + throw new RuntimeException("not support version "+version_name); + + version.load(json.getJSONObject(getTagName())).build(); + } +} diff --git a/src/main/java/com/reider745/behavior/entities/EntitiesVersion.java b/src/main/java/com/reider745/behavior/entities/EntitiesVersion.java new file mode 100644 index 000000000..7e23578ae --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/EntitiesVersion.java @@ -0,0 +1,7 @@ +package com.reider745.behavior.entities; + +import org.json.JSONObject; + +public abstract class EntitiesVersion { + public abstract EntityContentFactory load(JSONObject json); +} diff --git a/src/main/java/com/reider745/behavior/entities/EntityContentFactory.java b/src/main/java/com/reider745/behavior/entities/EntityContentFactory.java new file mode 100644 index 000000000..17a38c259 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/EntityContentFactory.java @@ -0,0 +1,38 @@ +package com.reider745.behavior.entities; + +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.custom.EntityDefinition; +import cn.nukkit.entity.custom.EntityManager; +import cn.nukkit.level.Position; +import com.reider745.behavior.entities.formats.tags.DescriptionsFactory; +import com.reider745.behavior.entities.formats.tags.components.CollisionComponent; + +import java.util.ArrayList; +import java.util.HashMap; + +public class EntityContentFactory { + public DescriptionsFactory.DescriptionTag description; + public CollisionComponent collision; + private ArrayList components = new ArrayList<>(); + + public boolean isFireImmune = false; + + public static final HashMap factoryMap = new HashMap<>(); + + public EntityDefinition getEntityDefinition() { + return new EntityDefinition( + description.identifier, + null, + false, + description.identifier, + CustomEntity.class + ); + } + + public void build(){ + factoryMap.put(description.identifier, this); + Entity.registerEntity(description.identifier, CustomEntity.class); + EntityManager.get() + .registerDefinition(this.getEntityDefinition()); + } +} diff --git a/src/main/java/com/reider745/behavior/entities/TagContentEntities.java b/src/main/java/com/reider745/behavior/entities/TagContentEntities.java new file mode 100644 index 000000000..b42570e02 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/TagContentEntities.java @@ -0,0 +1,4 @@ +package com.reider745.behavior.entities; + +public abstract class TagContentEntities { +} diff --git a/src/main/java/com/reider745/behavior/entities/TagContentFactory.java b/src/main/java/com/reider745/behavior/entities/TagContentFactory.java new file mode 100644 index 000000000..ec2e83395 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/TagContentFactory.java @@ -0,0 +1,9 @@ +package com.reider745.behavior.entities; + +import com.reider745.behavior.entities.EntityContentFactory; +import org.json.JSONObject; + +public abstract class TagContentFactory { + public abstract String getNameTag(); + public abstract void loadJSON(EntityContentFactory factory, JSONObject json); +} diff --git a/src/main/java/com/reider745/behavior/entities/formats/EntitiesVersion113.java b/src/main/java/com/reider745/behavior/entities/formats/EntitiesVersion113.java new file mode 100644 index 000000000..3f3c74904 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/formats/EntitiesVersion113.java @@ -0,0 +1,32 @@ +package com.reider745.behavior.entities.formats; + +import com.reider745.behavior.entities.EntitiesVersion; +import com.reider745.behavior.entities.EntityContentFactory; +import com.reider745.behavior.entities.TagContentFactory; +import com.reider745.behavior.entities.formats.tags.ComponentsFactory; +import com.reider745.behavior.entities.formats.tags.DescriptionsFactory; +import org.json.JSONObject; + +import java.util.ArrayList; + +public class EntitiesVersion113 extends EntitiesVersion { + private static final ArrayList tags = new ArrayList<>(); + + static { + tags.add(new DescriptionsFactory()); + tags.add(new ComponentsFactory()); + } + + @Override + public EntityContentFactory load(JSONObject json) { + final EntityContentFactory entityFactory = new EntityContentFactory(); + + for(TagContentFactory factory : tags){ + if(json.has(factory.getNameTag())){ + factory.loadJSON(entityFactory, json.getJSONObject(factory.getNameTag())); + } + } + + return entityFactory; + } +} diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/ComponentsFactory.java b/src/main/java/com/reider745/behavior/entities/formats/tags/ComponentsFactory.java new file mode 100644 index 000000000..85d8c1742 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/ComponentsFactory.java @@ -0,0 +1,33 @@ +package com.reider745.behavior.entities.formats.tags; + +import com.reider745.behavior.entities.ComponentsTag; +import com.reider745.behavior.entities.EntityContentFactory; +import com.reider745.behavior.entities.TagContentFactory; +import com.reider745.behavior.entities.formats.tags.components.CollisionComponent; +import com.reider745.behavior.entities.formats.tags.components.FireImmuneComponent; +import org.json.JSONObject; + +import java.util.ArrayList; + +public class ComponentsFactory extends TagContentFactory { + public static ArrayList tags = new ArrayList<>(); + + static { + tags.add(new FireImmuneComponent()); + tags.add(new CollisionComponent()); + } + + @Override + public String getNameTag() { + return "components"; + } + + @Override + public void loadJSON(EntityContentFactory entityFactory, JSONObject json) { + for(ComponentsTag tag : tags){ + if(json.has(tag.getNameTag())){ + tag.load(entityFactory, json.get(tag.getNameTag())); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/DescriptionsFactory.java b/src/main/java/com/reider745/behavior/entities/formats/tags/DescriptionsFactory.java new file mode 100644 index 000000000..bc2969e4d --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/DescriptionsFactory.java @@ -0,0 +1,32 @@ +package com.reider745.behavior.entities.formats.tags; + +import com.reider745.behavior.entities.EntityContentFactory; +import com.reider745.behavior.entities.TagContentEntities; +import com.reider745.behavior.entities.TagContentFactory; +import org.json.JSONObject; + +public class DescriptionsFactory extends TagContentFactory { + public static class DescriptionTag extends TagContentEntities{ + public String identifier; + public boolean isSpawnable, isSummonable, isExperimental; + + private DescriptionTag(JSONObject json){ + identifier = json.getString("identifier"); + isSpawnable = json.getBoolean("is_spawnable"); + isSummonable = json.getBoolean("is_summonable"); + isExperimental = json.getBoolean("is_experimental"); + + identifier = Character.toUpperCase(identifier.charAt(0)) + identifier.substring(1); + } + } + + @Override + public String getNameTag() { + return "description"; + } + + @Override + public void loadJSON(EntityContentFactory entityFactory, JSONObject json) { + entityFactory.description = new DescriptionTag(json); + } +} diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/components/CollisionComponent.java b/src/main/java/com/reider745/behavior/entities/formats/tags/components/CollisionComponent.java new file mode 100644 index 000000000..162d7ca09 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/components/CollisionComponent.java @@ -0,0 +1,26 @@ +package com.reider745.behavior.entities.formats.tags.components; + +import com.reider745.behavior.entities.ComponentsTag; +import com.reider745.behavior.entities.EntityContentFactory; +import com.zhekasmirnov.horizon.runtime.logger.Logger; +import org.json.JSONObject; + +public class CollisionComponent extends ComponentsTag { + public int width, height; + + @Override + public String getNameTag() { + return "minecraft:collision_box"; + } + + @Override + public void load(EntityContentFactory factory, Object json) { + if(json instanceof JSONObject object){ + width = object.getInt("width"); + height = object.getInt("height"); + + factory.collision = this; + }else + Logger.warning("Not support CollisionComponent "+json.getClass()); + } +} diff --git a/src/main/java/com/reider745/behavior/entities/formats/tags/components/FireImmuneComponent.java b/src/main/java/com/reider745/behavior/entities/formats/tags/components/FireImmuneComponent.java new file mode 100644 index 000000000..7deb03f09 --- /dev/null +++ b/src/main/java/com/reider745/behavior/entities/formats/tags/components/FireImmuneComponent.java @@ -0,0 +1,21 @@ +package com.reider745.behavior.entities.formats.tags.components; + + +import com.reider745.behavior.entities.ComponentsTag; +import com.reider745.behavior.entities.EntityContentFactory; +import com.zhekasmirnov.horizon.runtime.logger.Logger; + +public class FireImmuneComponent extends ComponentsTag { + @Override + public String getNameTag() { + return "minecraft:fire_immune"; + } + + @Override + public void load(EntityContentFactory factory, Object json) { + if(json instanceof Boolean value) + factory.isFireImmune = value; + else + Logger.warning("Not support FireImmuneComponent "+json.getClass()); + } +} diff --git a/src/main/java/com/reider745/hooks/EntityOverrides.java b/src/main/java/com/reider745/hooks/EntityOverrides.java index a937be7d4..86733edb5 100644 --- a/src/main/java/com/reider745/hooks/EntityOverrides.java +++ b/src/main/java/com/reider745/hooks/EntityOverrides.java @@ -1,19 +1,26 @@ package com.reider745.hooks; import cn.nukkit.entity.Entity; +import cn.nukkit.entity.custom.EntityDefinition; +import cn.nukkit.entity.custom.EntityManager; +import cn.nukkit.level.format.FullChunk; +import cn.nukkit.nbt.tag.CompoundTag; +import com.reider745.api.ReflectHelper; import com.reider745.api.hooks.HookClass; import com.reider745.api.hooks.annotation.Hooks; import com.reider745.api.hooks.annotation.Inject; +import com.reider745.behavior.entities.CustomEntity; +import com.reider745.behavior.entities.EntityContentFactory; import javassist.CannotCompileException; import javassist.CtClass; import javassist.CtMethod; import javassist.NotFoundException; import java.lang.reflect.Field; +import java.util.Map; @Hooks(className = "cn.nukkit.entity.item.EntityArmorStand") public class EntityOverrides implements HookClass { - @Override public void init(CtClass ctClass) { try { @@ -47,6 +54,47 @@ public static void scheduleUpdate(Entity self){ } catch (IllegalAccessException ignore) {} } + + // Патч для кастумных мобов в наборах параметров + @Inject( + className = "cn.nukkit.entity.Entity", + signature = "(Ljava/lang/String;Lcn/nukkit/level/format/FullChunk;Lcn/nukkit/nbt/tag/CompoundTag;[Ljava/lang/Object;)Lcn/nukkit/entity/Entity;" + ) + public static Entity createEntity(String name, FullChunk chunk, CompoundTag nbt, Object... args) { + final Map> knownEntities = ReflectHelper.getField(Entity.class, "knownEntities"); + + final EntityContentFactory factory = EntityContentFactory.factoryMap.get(name); + if(factory != null) { + nbt.putString("___id___", name); + return new CustomEntity(chunk, nbt); + } + + if (knownEntities.containsKey(name)) { + return ReflectHelper.invoke( + Entity.class, + "createEntity", + new Object[]{knownEntities.get(name), chunk, nbt, args}, + Class.class, + FullChunk.class, + CompoundTag.class, + Object[].class + ); + } + EntityDefinition entityDefinition = EntityManager.get().getDefinition(name); + if (entityDefinition != null) { + return ReflectHelper.invoke( + Entity.class, + "createEntity", + new Object[]{entityDefinition.getImplementation(), chunk, nbt, args}, + Class.class, + FullChunk.class, + CompoundTag.class, + Object[].class + ); + } + return null; + } + // @Inject(className = "cn.nukkit.entity.EntityHumanType", type = TypeHook.BEFORE, signature = "(Lcn/nukkit/item/Item;Lcn/nukkit/entity/Entity;FZLcn/nukkit/event/entity/EntityDamageEvent$DamageCause;)Lcn/nukkit/item/Item;") // public static void damageArmor(HookController controller, EntityHumanType human, Item armor, Entity damager, // float damage, boolean shield, DamageCause cause) { diff --git a/src/main/java/com/reider745/hooks/ServerHooks.java b/src/main/java/com/reider745/hooks/ServerHooks.java index ea5e547eb..deafd29bf 100644 --- a/src/main/java/com/reider745/hooks/ServerHooks.java +++ b/src/main/java/com/reider745/hooks/ServerHooks.java @@ -49,8 +49,13 @@ public static int getPropertyInt(Server server, String variable, Integer default @Inject public static boolean getPropertyBoolean(Server server, String variable, Object defaultValue) { - if (!InnerCoreServer.isUnsupportedOptionsAllowed() - && (variable.equals("xbox-auth") || variable.equals("enable-raw-ores"))) + if (!InnerCoreServer.isUnsupportedOptionsAllowed() && (variable.equals("xbox-auth"))) + return false; + + if(variable.equals("load-all-worlds"))// Увы это может сломать сохраенения TileEntity, поэтому настройка заблокировна + return true; + + if(variable.equals("enable-raw-ores"))// Исключительно для новых версий, поэтому без права на включение return false; Config properties = server.getProperties();