Remove need for program arguments. Add notice of bStats in readme.

This commit is contained in:
SeanOMik 2021-07-18 23:12:38 -04:00
parent 9619fea1cc
commit 89200ae301
No known key found for this signature in database
GPG Key ID: CA09E5BE1F32728A
20 changed files with 405 additions and 107 deletions

View File

@ -7,7 +7,7 @@
<parent> <parent>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<artifactId>tamablefoxes_v1_14_R1</artifactId> <artifactId>tamablefoxes_v1_14_R1</artifactId>
@ -41,5 +41,15 @@
<artifactId>anvilgui</artifactId> <artifactId>anvilgui</artifactId>
<version>1.5.1-SNAPSHOT</version> <version>1.5.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -5,32 +5,63 @@ import net.minecraft.server.v1_14_R1.EntityTypes;
import net.seanomik.tamablefoxes.util.FieldHelper; import net.seanomik.tamablefoxes.util.FieldHelper;
import net.seanomik.tamablefoxes.util.NMSInterface; import net.seanomik.tamablefoxes.util.NMSInterface;
import net.seanomik.tamablefoxes.util.Utils; import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.util.io.Config;
import net.seanomik.tamablefoxes.util.io.LanguageConfig; import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
import org.bukkit.entity.EntityType;
// In IntelliJ, these show up as an error, but it compiles fine.
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class NMSInterface_1_14_R1 implements NMSInterface { public class NMSInterface_1_14_R1 implements NMSInterface {
@Override @Override
public void registerCustomFoxEntity() { public void registerCustomFoxEntity() {
Class<?> clazz = null;
try {
// This must be `EntityFox` since after being compiled, the class goes back to `EntityFox` instead of `Fox`
ClassReader cr = new ClassReader(EntityFox.class.getResourceAsStream("EntityFox.class"));
ClassNode node = new ClassNode();
cr.accept(node, 0);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
node.accept(cw);
clazz = new ClassDefiner(ClassLoader.getSystemClassLoader()).get(node.name.replace("/", "."), cw.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
try { // Replace the fox entity try { // Replace the fox entity
Field field = EntityTypes.FOX.getClass().getDeclaredField("aZ"); Field field = EntityTypes.FOX.getClass().getDeclaredField("aZ"); // aZ = factory
FieldHelper.setField(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new); Class<?> finalClazz = clazz;
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced()); FieldHelper.setFieldUsingUnsafe(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new);
Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
} catch (Exception e) { } catch (Exception e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace()); Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override @Override
public void spawnTamableFox(Location loc, FoxType type) { public void spawnTamableFox(Location loc, FoxType type) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, EntityType.FOX)).getHandle(); EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle();
tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW); tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW);
} }
static class ClassDefiner extends ClassLoader {
public ClassDefiner(ClassLoader parent) {
super(parent);
}
public Class<?> get(String name, byte[] bytes) {
Class<?> c = defineClass(name, bytes, 0, bytes.length);
resolveClass(c);
return c;
}
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<artifactId>tamablefoxes_v1_15_R1</artifactId> <artifactId>tamablefoxes_v1_15_R1</artifactId>
@ -41,5 +41,15 @@
<artifactId>anvilgui</artifactId> <artifactId>anvilgui</artifactId>
<version>1.5.1-SNAPSHOT</version> <version>1.5.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -5,32 +5,63 @@ import net.minecraft.server.v1_15_R1.EntityTypes;
import net.seanomik.tamablefoxes.util.FieldHelper; import net.seanomik.tamablefoxes.util.FieldHelper;
import net.seanomik.tamablefoxes.util.NMSInterface; import net.seanomik.tamablefoxes.util.NMSInterface;
import net.seanomik.tamablefoxes.util.Utils; import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.util.io.Config;
import net.seanomik.tamablefoxes.util.io.LanguageConfig; import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
import org.bukkit.entity.EntityType;
// In IntelliJ, these show up as an error, but it compiles fine.
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class NMSInterface_1_15_R1 implements NMSInterface { public class NMSInterface_1_15_R1 implements NMSInterface {
@Override @Override
public void registerCustomFoxEntity() { public void registerCustomFoxEntity() {
Class<?> clazz = null;
try {
// This must be `EntityFox` since after being compiled, the class goes back to `EntityFox` instead of `Fox`
ClassReader cr = new ClassReader(EntityFox.class.getResourceAsStream("EntityFox.class"));
ClassNode node = new ClassNode();
cr.accept(node, 0);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
node.accept(cw);
clazz = new ClassDefiner(ClassLoader.getSystemClassLoader()).get(node.name.replace("/", "."), cw.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
try { // Replace the fox entity try { // Replace the fox entity
Field field = EntityTypes.FOX.getClass().getDeclaredField("ba"); Field field = EntityTypes.FOX.getClass().getDeclaredField("ba"); // ba = factory
FieldHelper.setField(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new); Class<?> finalClazz = clazz;
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced()); FieldHelper.setFieldUsingUnsafe(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new);
Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
} catch (Exception e) { } catch (Exception e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace()); Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override @Override
public void spawnTamableFox(Location loc, FoxType type) { public void spawnTamableFox(Location loc, FoxType type) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, EntityType.FOX)).getHandle(); EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle();
tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW); tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW);
} }
static class ClassDefiner extends ClassLoader {
public ClassDefiner(ClassLoader parent) {
super(parent);
}
public Class<?> get(String name, byte[] bytes) {
Class<?> c = defineClass(name, bytes, 0, bytes.length);
resolveClass(c);
return c;
}
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<artifactId>tamablefoxes_v1_16_R1</artifactId> <artifactId>tamablefoxes_v1_16_R1</artifactId>
@ -41,5 +41,15 @@
<artifactId>anvilgui</artifactId> <artifactId>anvilgui</artifactId>
<version>1.5.1-SNAPSHOT</version> <version>1.5.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,37 +1,67 @@
package net.seanomik.tamablefoxes.versions.version_1_16_R1; package net.seanomik.tamablefoxes.versions.version_1_16_R1;
import net.minecraft.server.v1_16_R1.EntityTypes;
import net.minecraft.server.v1_16_R1.EntityFox; import net.minecraft.server.v1_16_R1.EntityFox;
import net.minecraft.server.v1_16_R1.EntityTypes;
import net.seanomik.tamablefoxes.util.FieldHelper; import net.seanomik.tamablefoxes.util.FieldHelper;
import net.seanomik.tamablefoxes.util.NMSInterface; import net.seanomik.tamablefoxes.util.NMSInterface;
import net.seanomik.tamablefoxes.util.Utils; import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.util.io.Config;
import net.seanomik.tamablefoxes.util.io.LanguageConfig; import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R1.entity.CraftEntity;
import org.bukkit.entity.EntityType;
// In IntelliJ, these show up as an error, but it compiles fine.
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class NMSInterface_1_16_R1 implements NMSInterface { public class NMSInterface_1_16_R1 implements NMSInterface {
@Override @Override
public void registerCustomFoxEntity() { public void registerCustomFoxEntity() {
Class<?> clazz = null;
try {
// This must be `EntityFox` since after being compiled, the class goes back to `EntityFox` instead of `Fox`
ClassReader cr = new ClassReader(EntityFox.class.getResourceAsStream("EntityFox.class"));
ClassNode node = new ClassNode();
cr.accept(node, 0);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
node.accept(cw);
clazz = new ClassDefiner(ClassLoader.getSystemClassLoader()).get(node.name.replace("/", "."), cw.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
try { // Replace the fox entity try { // Replace the fox entity
Field field = EntityTypes.FOX.getClass().getDeclaredField("be"); Field field = EntityTypes.FOX.getClass().getDeclaredField("be"); // be = factory
FieldHelper.setField(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new); Class<?> finalClazz = clazz;
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced()); FieldHelper.setFieldUsingUnsafe(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new);
Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
} catch (Exception e) { } catch (Exception e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace()); Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override @Override
public void spawnTamableFox(Location loc, FoxType type) { public void spawnTamableFox(Location loc, FoxType type) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, EntityType.FOX)).getHandle(); EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle();
tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW); tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW);
} }
static class ClassDefiner extends ClassLoader {
public ClassDefiner(ClassLoader parent) {
super(parent);
}
public Class<?> get(String name, byte[] bytes) {
Class<?> c = defineClass(name, bytes, 0, bytes.length);
resolveClass(c);
return c;
}
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<artifactId>tamablefoxes_v1_16_R2</artifactId> <artifactId>tamablefoxes_v1_16_R2</artifactId>
@ -41,5 +41,15 @@
<artifactId>anvilgui</artifactId> <artifactId>anvilgui</artifactId>
<version>1.5.1-SNAPSHOT</version> <version>1.5.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -5,33 +5,63 @@ import net.minecraft.server.v1_16_R2.EntityTypes;
import net.seanomik.tamablefoxes.util.FieldHelper; import net.seanomik.tamablefoxes.util.FieldHelper;
import net.seanomik.tamablefoxes.util.NMSInterface; import net.seanomik.tamablefoxes.util.NMSInterface;
import net.seanomik.tamablefoxes.util.Utils; import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.util.io.Config;
import net.seanomik.tamablefoxes.util.io.LanguageConfig; import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R2.entity.CraftEntity;
import org.bukkit.entity.EntityType;
// In IntelliJ, these show up as an error, but it compiles fine.
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class NMSInterface_1_16_R2 implements NMSInterface { public class NMSInterface_1_16_R2 implements NMSInterface {
@Override @Override
public void registerCustomFoxEntity() { public void registerCustomFoxEntity() {
Class<?> clazz = null;
try {
// This must be `EntityFox` since after being compiled, the class goes back to `EntityFox` instead of `Fox`
ClassReader cr = new ClassReader(EntityFox.class.getResourceAsStream("EntityFox.class"));
ClassNode node = new ClassNode();
cr.accept(node, 0);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
node.accept(cw);
clazz = new ClassDefiner(ClassLoader.getSystemClassLoader()).get(node.name.replace("/", "."), cw.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
try { // Replace the fox entity try { // Replace the fox entity
Field field = EntityTypes.FOX.getClass().getDeclaredField("bf"); Field field = EntityTypes.FOX.getClass().getDeclaredField("bf"); // bm = factory
FieldHelper.setField(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new); Class<?> finalClazz = clazz;
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced()); FieldHelper.setFieldUsingUnsafe(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new);
Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
} catch (Exception e) { } catch (Exception e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace()); Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override @Override
public void spawnTamableFox(Location loc, FoxType type) { public void spawnTamableFox(Location loc, FoxType type) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, EntityType.FOX)).getHandle(); EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle();
tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW); tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW);
} }
static class ClassDefiner extends ClassLoader {
public ClassDefiner(ClassLoader parent) {
super(parent);
}
public Class<?> get(String name, byte[] bytes) {
Class<?> c = defineClass(name, bytes, 0, bytes.length);
resolveClass(c);
return c;
}
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<artifactId>tamablefoxes_v1_16_R3</artifactId> <artifactId>tamablefoxes_v1_16_R3</artifactId>
@ -41,5 +41,15 @@
<artifactId>anvilgui</artifactId> <artifactId>anvilgui</artifactId>
<version>1.5.1-SNAPSHOT</version> <version>1.5.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -5,33 +5,63 @@ import net.minecraft.server.v1_16_R3.EntityTypes;
import net.seanomik.tamablefoxes.util.FieldHelper; import net.seanomik.tamablefoxes.util.FieldHelper;
import net.seanomik.tamablefoxes.util.NMSInterface; import net.seanomik.tamablefoxes.util.NMSInterface;
import net.seanomik.tamablefoxes.util.Utils; import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.util.io.Config;
import net.seanomik.tamablefoxes.util.io.LanguageConfig; import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;
import org.bukkit.entity.EntityType;
// In IntelliJ, these show up as an error, but it compiles fine.
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class NMSInterface_1_16_R3 implements NMSInterface { public class NMSInterface_1_16_R3 implements NMSInterface {
@Override @Override
public void registerCustomFoxEntity() { public void registerCustomFoxEntity() {
Class<?> clazz = null;
try {
// This must be `EntityFox` since after being compiled, the class goes back to `EntityFox` instead of `Fox`
ClassReader cr = new ClassReader(EntityFox.class.getResourceAsStream("EntityFox.class"));
ClassNode node = new ClassNode();
cr.accept(node, 0);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
node.accept(cw);
clazz = new ClassDefiner(ClassLoader.getSystemClassLoader()).get(node.name.replace("/", "."), cw.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
try { // Replace the fox entity try { // Replace the fox entity
Field field = EntityTypes.FOX.getClass().getDeclaredField("bf"); Field field = EntityTypes.FOX.getClass().getDeclaredField("bf"); // bm = factory
FieldHelper.setField(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new); Class<?> finalClazz = clazz;
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced()); FieldHelper.setFieldUsingUnsafe(field, EntityTypes.FOX, (EntityTypes.b<EntityFox>) EntityTamableFox::new);
Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
} catch (Exception e) { } catch (Exception e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace()); Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override @Override
public void spawnTamableFox(Location loc, FoxType type) { public void spawnTamableFox(Location loc, FoxType type) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, EntityType.FOX)).getHandle(); EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle();
tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW); tamableFox.setFoxType((type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW);
} }
static class ClassDefiner extends ClassLoader {
public ClassDefiner(ClassLoader parent) {
super(parent);
}
public Class<?> get(String name, byte[] bytes) {
Class<?> c = defineClass(name, bytes, 0, bytes.length);
resolveClass(c);
return c;
}
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<build> <build>
@ -80,5 +80,15 @@
<artifactId>anvilgui</artifactId> <artifactId>anvilgui</artifactId>
<version>1.5.1-SNAPSHOT</version> <version>1.5.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -4,24 +4,45 @@ import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.animal.Fox; import net.minecraft.world.entity.animal.Fox;
import net.seanomik.tamablefoxes.util.FieldHelper; import net.seanomik.tamablefoxes.util.FieldHelper;
import net.seanomik.tamablefoxes.util.NMSInterface; import net.seanomik.tamablefoxes.util.NMSInterface;
import net.seanomik.tamablefoxes.util.io.Config; import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.util.io.LanguageConfig; import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity;
// In IntelliJ, these show up as an error, but it compiles fine.
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class NMSInterface_1_17_1_R1 implements NMSInterface { public class NMSInterface_1_17_1_R1 implements NMSInterface {
@Override @Override
public void registerCustomFoxEntity() { public void registerCustomFoxEntity() {
Class<?> clazz = null;
try {
// This must be `EntityFox` since after being compiled, the class goes back to `EntityFox` instead of `Fox`
ClassReader cr = new ClassReader(Fox.class.getResourceAsStream("EntityFox.class"));
ClassNode node = new ClassNode();
cr.accept(node, 0);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
node.accept(cw);
clazz = new ClassDefiner(ClassLoader.getSystemClassLoader()).get(node.name.replace("/", "."), cw.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
try { // Replace the fox entity try { // Replace the fox entity
Field field = EntityType.FOX.getClass().getDeclaredField("bm"); // bm = factory Field field = EntityType.FOX.getClass().getDeclaredField("bm"); // bm = factory
FieldHelper.setField(field, EntityType.FOX, (EntityType.EntityFactory<Fox>) EntityTamableFox::new); Class<?> finalClazz = clazz;
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced()); FieldHelper.setFieldUsingUnsafe(field, EntityType.FOX, (EntityType.EntityFactory<Fox>) EntityTamableFox::new);
Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
} catch (Exception e) { } catch (Exception e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace()); Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -31,4 +52,16 @@ public class NMSInterface_1_17_1_R1 implements NMSInterface {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle(); EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle();
tamableFox.setFoxType((type == FoxType.RED) ? Fox.Type.RED : Fox.Type.SNOW); tamableFox.setFoxType((type == FoxType.RED) ? Fox.Type.RED : Fox.Type.SNOW);
} }
static class ClassDefiner extends ClassLoader {
public ClassDefiner(ClassLoader parent) {
super(parent);
}
public Class<?> get(String name, byte[] bytes) {
Class<?> c = defineClass(name, bytes, 0, bytes.length);
resolveClass(c);
return c;
}
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<build> <build>
@ -80,5 +80,15 @@
<artifactId>anvilgui</artifactId> <artifactId>anvilgui</artifactId>
<version>1.5.1-SNAPSHOT</version> <version>1.5.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -4,24 +4,45 @@ import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.animal.Fox; import net.minecraft.world.entity.animal.Fox;
import net.seanomik.tamablefoxes.util.FieldHelper; import net.seanomik.tamablefoxes.util.FieldHelper;
import net.seanomik.tamablefoxes.util.NMSInterface; import net.seanomik.tamablefoxes.util.NMSInterface;
import net.seanomik.tamablefoxes.util.io.Config; import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.util.io.LanguageConfig; import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity;
// In IntelliJ, these show up as an error, but it compiles fine.
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class NMSInterface_1_17_R1 implements NMSInterface { public class NMSInterface_1_17_R1 implements NMSInterface {
@Override @Override
public void registerCustomFoxEntity() { public void registerCustomFoxEntity() {
Class<?> clazz = null;
try {
// This must be `EntityFox` since after being compiled, the class goes back to `EntityFox` instead of `Fox`
ClassReader cr = new ClassReader(Fox.class.getResourceAsStream("EntityFox.class"));
ClassNode node = new ClassNode();
cr.accept(node, 0);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
node.accept(cw);
clazz = new ClassDefiner(ClassLoader.getSystemClassLoader()).get(node.name.replace("/", "."), cw.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
try { // Replace the fox entity try { // Replace the fox entity
Field field = EntityType.FOX.getClass().getDeclaredField("bm"); // bm = factory Field field = EntityType.FOX.getClass().getDeclaredField("bm"); // bm = factory
FieldHelper.setField(field, EntityType.FOX, (EntityType.EntityFactory<Fox>) EntityTamableFox::new); Class<?> finalClazz = clazz;
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced()); FieldHelper.setFieldUsingUnsafe(field, EntityType.FOX, (EntityType.EntityFactory<Fox>) EntityTamableFox::new);
Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
} catch (Exception e) { } catch (Exception e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace()); Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -31,4 +52,16 @@ public class NMSInterface_1_17_R1 implements NMSInterface {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle(); EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle();
tamableFox.setFoxType((type == FoxType.RED) ? Fox.Type.RED : Fox.Type.SNOW); tamableFox.setFoxType((type == FoxType.RED) ? Fox.Type.RED : Fox.Type.SNOW);
} }
static class ClassDefiner extends ClassLoader {
public ClassDefiner(ClassLoader parent) {
super(parent);
}
public Class<?> get(String name, byte[] bytes) {
Class<?> c = defineClass(name, bytes, 0, bytes.length);
resolveClass(c);
return c;
}
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<artifactId>tamablefoxes</artifactId> <artifactId>tamablefoxes</artifactId>

View File

@ -26,7 +26,7 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
public NMSInterface nmsInterface; public NMSInterface nmsInterface;
public boolean equalOrBetween(double num, double min, double max) { private boolean equalOrBetween(double num, double min, double max) {
return num >= min && num <= max; return num >= min && num <= max;
} }
@ -45,7 +45,6 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
double versionDouble = Double.parseDouble(specificVersion.substring(2)); double versionDouble = Double.parseDouble(specificVersion.substring(2));
System.out.println("MC Version: " + versionDouble);
if (equalOrBetween(versionDouble, 14D, 14.4D)) { if (equalOrBetween(versionDouble, 14D, 14.4D)) {
nmsInterface = new NMSInterface_1_14_R1(); nmsInterface = new NMSInterface_1_14_R1();
} else if (equalOrBetween(versionDouble, 15D, 15.2D)) { } else if (equalOrBetween(versionDouble, 15D, 15.2D)) {
@ -75,7 +74,6 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
} }
Metrics metrics = new Metrics(this, BSTATS_PLUGIN_ID); Metrics metrics = new Metrics(this, BSTATS_PLUGIN_ID);
//metrics.addCustomChart(new SingleLineChart("servers", () -> 1));
} }
@Override @Override

View File

@ -4,10 +4,7 @@ SpigotMC Plugin that gives you the ability to tame foxes!
</p> </p>
### WARNING: Do not reload the plugin, you may loose foxes!! ### WARNING: Do not reload the plugin, you may loose foxes!!
#### NOTE: IF YOU ARE RUNNING JAVA 16, YOU NEED TO ADD SOME STUFF TO YOUR JVM ARGUMENTS (make sure it's before the -jar argument) IN YOUR SERVER START SCRIPT: #### NOTE: You no longer need to add the program arguments to your start file. If you previously had them, you can delete them, but I don't think it would harm if you leave them in.
```bash
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED
```
### Default configuration files: ### Default configuration files:
* <a href="https://github.com/SeanOMik/TamableFoxes/blob/master/Plugin/src/main/resources/config.yml">config.yml</a> * <a href="https://github.com/SeanOMik/TamableFoxes/blob/master/Plugin/src/main/resources/config.yml">config.yml</a>
@ -51,3 +48,6 @@ Have you ever wanted to tame foxes? Well, now you can! <b>Use chicken to tame</b
![foxes with baby looking at player](https://www.spigotmc.org/attachments/2019-07-18_23-24-24-png.441399/) ![foxes with baby looking at player](https://www.spigotmc.org/attachments/2019-07-18_23-24-24-png.441399/)
![giving fox totem](https://proxy.spigotmc.org/3c5f51d25b3fbb2e6bdacaa995c4e87538c13c62?url=https%3A%2F%2Fi.gyazo.com%2F34f94804beb17ffa68b73874c8c8d1d5.gif) ![giving fox totem](https://proxy.spigotmc.org/3c5f51d25b3fbb2e6bdacaa995c4e87538c13c62?url=https%3A%2F%2Fi.gyazo.com%2F34f94804beb17ffa68b73874c8c8d1d5.gif)
![fox leaping towards chicken](https://proxy.spigotmc.org/4527d9b156ae8ad83f4b67a1407c67376eabcc52?url=https%3A%2F%2Fi.gyazo.com%2F367b397a86f31b0ba27fba228c295347.gif) ![fox leaping towards chicken](https://proxy.spigotmc.org/4527d9b156ae8ad83f4b67a1407c67376eabcc52?url=https%3A%2F%2Fi.gyazo.com%2F367b397a86f31b0ba27fba228c295347.gif)
<small>The plugin by default submits anonymous stats about your server (player count, plugin/server version and type) to a public statistics websites (bstats.org) in order to provide the developers with usage information. If you wish to opt out, you can do so in the `bstats/config.yml` file.

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
</parent> </parent>
<artifactId>tamablefoxes-util</artifactId> <artifactId>tamablefoxes-util</artifactId>

View File

@ -4,57 +4,69 @@ import net.seanomik.tamablefoxes.util.io.Config;
import net.seanomik.tamablefoxes.util.io.LanguageConfig; import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import sun.misc.Unsafe;
import sun.misc.Unsafe;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
public final class FieldHelper { public final class FieldHelper {
public static void setFieldUsingUnsafe(final Field field, final Object object, final Object newValue) {
private static final VarHandle MODIFIERS;
static {
String version = System.getProperty("java.version");
if (!version.startsWith("1.8")) {
try { try {
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup()); field.setAccessible(true);
MODIFIERS = lookup.findVarHandle(Field.class, "modifiers", int.class); int fieldModifiersMask = field.getModifiers();
} catch (IllegalAccessException | NoSuchFieldException ex) { boolean isFinalModifierPresent = (fieldModifiersMask & Modifier.FINAL) == Modifier.FINAL;
if (isFinalModifierPresent) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
try {
sun.misc.Unsafe unsafe = getUnsafe();
long offset = unsafe.objectFieldOffset(field);
setFieldUsingUnsafe(object, field.getType(), offset, newValue, unsafe);
return null;
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
} else {
try {
field.set(object, newValue);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
} else { }
MODIFIERS = null; } catch (SecurityException ex) {
throw new RuntimeException(ex);
} }
} }
private static sun.misc.Unsafe getUnsafe() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
public static void makeNonFinal(Field field) { Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
// Check if we're running a supported java version for this new method.
if (MODIFIERS == null) {
try {
if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
Field fieldMutable = field.getClass().getDeclaredField("modifiers");
fieldMutable.setAccessible(true);
fieldMutable.set(field, fieldMutable.getInt(field) & ~Modifier.FINAL);
fieldMutable.setAccessible(false);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace();
}
} else {
int mods = field.getModifiers();
if (Modifier.isFinal(mods)) {
MODIFIERS.set(field, mods & ~Modifier.FINAL);
}
}
}
public static void setField(Field field, Object obj, Object value) throws IllegalAccessException {
makeNonFinal(field);
field.setAccessible(true); field.setAccessible(true);
field.set(obj, value); return (sun.misc.Unsafe) field.get(null);
field.setAccessible(false); }
private static void setFieldUsingUnsafe(Object base, Class type, long offset, Object newValue, Unsafe unsafe) {
if (type == Integer.TYPE) {
unsafe.putInt(base, offset, ((Integer) newValue));
} else if (type == Short.TYPE) {
unsafe.putShort(base, offset, ((Short) newValue));
} else if (type == Long.TYPE) {
unsafe.putLong(base, offset, ((Long) newValue));
} else if (type == Byte.TYPE) {
unsafe.putByte(base, offset, ((Byte) newValue));
} else if (type == Boolean.TYPE) {
unsafe.putBoolean(base, offset, ((Boolean) newValue));
} else if (type == Float.TYPE) {
unsafe.putFloat(base, offset, ((Float) newValue));
} else if (type == Double.TYPE) {
unsafe.putDouble(base, offset, ((Double) newValue));
} else if (type == Character.TYPE) {
unsafe.putChar(base, offset, ((Character) newValue));
} else {
unsafe.putObject(base, offset, newValue);
}
} }
} }

View File

@ -6,7 +6,7 @@
<groupId>net.seanomik</groupId> <groupId>net.seanomik</groupId>
<artifactId>tamablefoxes-parent</artifactId> <artifactId>tamablefoxes-parent</artifactId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>