-1

This is from the Minecraft server source code, also called the Minecraft Bukkit API, now you know as much as I do.

There is an interface called Server:

public interface Server extends PluginMessegeRecipient {
    public String getVersion();
}

PluginMessageRecipient is an interface also.

There is a class called Bukkit that instantiates Server:

public final class Bukkit {
    private static Server server;

}

Inside methods in the Bucket class they invoke methods from the server object. For example:

server.getVersion();

The thing is, there is no code for getVersion in the Server interface, just a method signature. There is also no code in the PluginMessageRecipient interface nor does it extend anything.

I have read all the questions and answers on SO that say I need an anonymous class or an inner class and this does not seem to fit those solutions.

nicomp
  • 4,344
  • 4
  • 27
  • 60
  • 1
    I suspect that `server` is being instantiated to an implementing class of the `Server` interface at some point. Eg: `Bucket.server = new VersionFiveServer()` and `VersionFiveServer implements Server`. – CollinD Jun 17 '16 at 21:18
  • 1
    Server is an interface therefore it won't have code. It will only have the method signature. That's what an interface IS. Some other class will implement that interface and contain code. – ManoDestra Jun 17 '16 at 21:20
  • Related: http://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface – Alexis C. Jun 17 '16 at 21:20
  • @CollinD So you think there is a class called Server and an interface called Sever? – nicomp Jun 17 '16 at 21:20
  • Do you mean Bukkit?! Because thats what the code is from, and I don#t know any "Bucket API" for MC. – Polygnome Jun 17 '16 at 21:26

3 Answers3

1

There is a class called Bucket that instantiates Server:

Actually Bucket doesn't instantiate Server. The class Bucket contains a reference to a Server. You haven't shown how that got set so we don't know the actual class.

However, it is guaranteed that what is assigned to that reference (Bucket.server), assuming it's not null, is a an object of some concrete class that implements Server. That class will provide an implementation of getVersion() and that is what is being called.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • " The class Bucket contains a reference to a Server. You haven't shown how that got set so we don't know the actual class. " -- There isn't one. I can't show it. That's my question. – nicomp Jun 17 '16 at 21:40
  • It got set somewhere, so "There isn't one" is false on the face. You say it's an API, so undoubtedly there was a call somewhere, or a configuration file (XML, JSON, properties, ...) somewhere or a command-line option somewhere, combined with some kind of initialization code somewhere, that specified the implementing class. You simply haven't found it yet. Have you tried the documentation for the API? – Lew Bloch Jun 17 '16 at 21:52
0

Bukkit is just a Modding API. If you want to implement Bukkit, you need to create such an instance yourself and pass it there.

Take for example the unit tests that Bukkit includes: https://github.com/Bukkit/Bukkit/blob/f210234e59275330f83b994e199c76f6abd41ee7/src/test/java/org/bukkit/TestServer.java#L77

A real implementation that allows you to run a Bukkit server is Spigot.

Polygnome
  • 7,639
  • 2
  • 37
  • 57
0

If I recall correctly, the particular concrete class that's being selected is determined at runtime via reflection. Because Minecraft is not open source, all the developers have are the obfuscated compiled class files to work with.

The code searches through each class file within the minecraft jar, searching for a class that matches certain conditions, and then, using a bytecode library, force that class to implement that interface.

For example, let's say that the following (obfuscated) class was the real Server class within the Minecraft code

class a {

    String x_x317() {
        return q_q98;
    }

    static a a_a1;
    static String q_q98 = "1.9.4";
}

In this case, the method x_x317 returns the version string. The tool that allows them too hook into this class might do it based on the following conditions:

  1. The class has default access
  2. The class has only one default access static reference to itself
  3. The class has only one default access static String field.
  4. The class has a single method, that has default access, that returns String, and the returned value is the FieldRef found in 3.

This generally returns only one class. In the case that multiple are returned (usually in the dev phase of the new Bukkit version), they get more specific with their conditions to ensure that they only get the right class returned. They do this for every field, class, and method they need to identify.

Since they now know which exact class is the Server class, they can go ahead and make changes to it. First they would need to implement the interface

class a implements org.bukkit.Server

And then implement the method

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";
}

Now, we have a class that conforms to the Bukkit API.

When they need to instantiate that class, they just do something along the lines of

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();
}
Zymus
  • 1,673
  • 1
  • 18
  • 38
  • Actually, bukkit works off of an already-deobfuscated jar (and has a concrete implementation, `CraftServer`, which is custom though other parts of CraftBukkit reference the vanilla code) – Pokechu22 Jun 18 '16 at 05:16