这是来自Minecraft服务器源代码,也称为Minecraft Bukkit API,现在你和我一样了解。
有一个名为Server的接口:
public interface Server extends PluginMessegeRecipient {
public String getVersion();
}
PluginMessageRecipient也是一个接口。
有一个名为Bukkit的类实例化Server:
public final class Bukkit {
private static Server server;
}
Bucket类中的内部方法,它们从服务器对象调用方法。例如:
server.getVersion();
问题是,Server接口中没有getVersion的代码,只是方法签名。 PluginMessageRecipient接口中也没有代码,也没有扩展任何代码。
我已经阅读了所有问题和答案,说我需要一个匿名类或内部类,这似乎不适合那些解决方案。
答案 0 :(得分:1)
有一个名为
Bucket
的类可以实例化Server:
实际上Bucket
并未实例化Server
。课程Bucket
包含对Server
的引用。你还没有表明它是如何设置的,所以我们不知道实际的课程。
但是,保证 分配给该引用(Bucket.server
),假设它不是null
,是一个具体的对象实现 Server
的类。该类将提供getVersion()
的实现,这就是所谓的。
答案 1 :(得分:0)
Bukkit只是一个Modding API。如果你想实现Bukkit,你需要自己创建这样一个实例并将其传递给那里。
以Bukkit包含的单元测试为例: https://github.com/Bukkit/Bukkit/blob/f210234e59275330f83b994e199c76f6abd41ee7/src/test/java/org/bukkit/TestServer.java#L77
允许您运行Bukkit服务器的真正实现是Spigot。
答案 2 :(得分:0)
如果我没记错的话,选择的特定具体类是在运行时通过反射确定的。因为Minecraft不是开源的,所以所有的开发人员都使用了混淆的编译类文件。
代码搜索minecraft jar中的每个类文件,搜索匹配特定条件的类,然后使用字节码库强制该类实现该接口。
例如,假设以下(混淆)类是Minecraft代码中的真实 Server
类
class a {
String x_x317() {
return q_q98;
}
static a a_a1;
static String q_q98 = "1.9.4";
}
在这种情况下,方法x_x317
返回版本字符串。允许它们进入此类的工具可能会根据以下条件执行此操作:
String
,返回值为3中的FieldRef
。这通常只返回一个类。如果返回多个(通常在新的Bukkit版本的开发阶段),他们会更加具体地了解他们的条件,以确保他们只返回正确的类。他们为他们需要识别的每个领域,类和方法执行此操作。
由于他们现在知道哪个类是Server
类,所以他们可以继续进行更改。首先,他们需要实现界面
class a implements org.bukkit.Server
然后实现方法
class a implements org.bukkit.Server {
String x_x317() {
return q_q98;
}
public String getVersionNumber() {
return x_x317();
}
static a a_a1;
static String q_q98 = "1.9.4";
}
现在,我们有一个符合Bukkit API的类。
当他们需要实例化该类时,他们只是按照
的方式做一些事情Server server = findAndTransformServerClassFromMinecraftJar();
// ...
Server findAndTransformServerClassFromMinecraftJar() {
// load classes from jar
// map them to the appropriate interfaces
// transform and hook the required classes and methods
Class<?> serverClass = doTheFirstThreeSteps();
return (Server) serverClass.newInstance();
}