ZCraftbukkitAPI [>Massive< update!]
ZCraftbukkitApi 1.1.2
For some tasks, there is just no other option than using some classes in the craftbukkit package.
This does, however, come with the huge disadvantage that the plugin has to be manually updated every time!
Using java reflection, this plugin allows for version-independent execution of methods such as
net.minecraft.server.[insert version here].IChatBaseComponent.ChatSerializer.a("some string")
etc. using a method:
the netCraftMulticall!
Say You have a string called jsonMessage, and You want it to be sent to a Player p.
Until now, You had to do
((CraftPlayer)p).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(IChatBaseComponent.ChatSerializer.a(jsonMessage)));
(or write it out across several lines of course)
and do version dependent imports. Either that, or use a giant, fragile hulk of java reflection and neither of those options are feasible.
This line, however, can be almost directly copied into the ZCraftbukkitAPI - multicall - function, which does not need to be updated from version to version:
first, You can create the multithread-safe ZApi - object using
ZApi yourZApiObj = new ZApi();
(keep them in your classes as static or have only one in your main class, as there is a lot of caching involved and needed as it increases performance by a LOT.)
yourZApiObj.netCraftMulticall("entity.CraftPlayer{0}.getHandle().playerConnection.sendPacket(new PacketPlayOutChat(IChatBaseComponent.ChatSerializer.a(String{1})))",p,jsonMessage);
This then gets "compiled" and cached in your object. You now have, with almost no effort, made this line version independent!
You can also use all org.bukkit and java methods, for example You could technically do
yourZApiObj.netCraftMulticall("System.out.println(String{0})","hi");
and it would print hi into the server console.
Do keep in mind that the plugin has no way of telling which classes You imported, so for using a Snowball (which is in the org.bukkit.entity package) You would have to do eg.
Object shooter = youZApiObj.netCraftMulticall("org.bukkit.entity.SnowBall{0}.getShooter()",yourSnowB);
Obviously You wouldn't need the API for this purely Bukkit related operation, but it's just an example ;)
if You wanted to do that call a few times over, You'd have to type or paste a lot... unless You use the alias-function!
if You do
yourZApiObj.alias("SnowBall",SnowBall.class)
your api-object will remember what a SnowBall is, and You can leave away the org.bukkit.entity.
This is also useful if You want to use a method defined in your own plugin!
You can simply register your plugins class, lets call it ACoolPlugin:
yourZApiObj.alias("ACoolPlugin",ACoolPlugin.class);
and from now on until You decide to manually clear the cache, your ZApi-object will remember what an ACoolPlugin is and will be able to use all of its methods and fields.
Some classes like System, List, String, the primitives and their wrapping classes are already known to every ZApi instance. See which ones on the documentation included in the jar
How to use the netCraftMulticall exactly:
Any netCraftMulticall has to be called on a ZApi-instance. It takes an arbitrary amount of arguments, the first one of which has to be a string containing the instructions.
Since the object cannot see your local variables, You'll need to hand over your arguments yourself.
But fist, let us start out with the basic class naming: while java and bukkit classes can be addressed using their normal package names like java.util.Scanner etc., that obviously can't work for net.minecraft.server and org.bukkit.craftbukkit classes. These will be addressed by what follows the version identifier, for example v1_11_R1. For net.minecraft methods, that's usually the class name itself (IChatBaseComp), for bukkit there is oftentimes a prefix. For example a CraftPlayer would be called entity.CraftPlayer etc., You get the idea.
As You have seen above, where You would normally put the Object itself, You put the class name followed by a curly bracket opening, a number and a curly bracket closing.
This number is the index in the list of arguments you passed, starting with zero. If You hand over the instruction "System.out.println(String{0}.concat(String{1}))", it will assume you hand over two Strings. If those two are "a" and "b", ab will be printed to the console. The indexes do not have to be in order nor is there a limitation on how often you can use them, you only need to pass enough arguments (int this case two)
You can nest methods, fields, values and even constructors in the instruction as deeply as You want. It handles static fields and methods just fine, returning whatever it would have returned as normal java code. If You simply use a constructor, say "new String()", it will return the constructed object. Only typing a class name like "String" will return the Class - object.
Note that structuring braces are not allowed (and not needed, as You won't cast). Also, if a method takes a byte and You hand over a float, an exception will be thrown, so cast before handing over. (Objects do not have to be cast, ever)
Important: pay attention to exact method signatures. If You wanted to send a packet suing sendPacket() on a playerconnection, You'd have to write sendPacket(Packet{1}) (number arbitrarily chosen) and not sendPacket(PacketPlayOutChat{1}), as a method that only takes PacketPlayOut - packets will not be found.
Development strategy when using this plugin
Long story short, write and test your code using the version dependent methods and classes and convert afterwards so that the IDE can suggest methods etc. Then test everything again to make sure everything was copied over correctly.
This way, your plugin does not have to be updated anymore, leaving more time for working on the plugin itself. It also opens up a whole new world of possibilities for smaller plugins, that can't expect to be updated for every new version.
Simply download the jar and link it in your IDE. You can now use the ZApi-class found in the me.zainlessbrombie.zcraftbukkitapi - package, that simple!
(Obviously, the plugin has to be running on the server. Also don't forget to add the depend in your yml ;) )
Everything this plugin does is cached in the respective objects, so the performance is actually not that different from using the version dependent methods themselves! (Off by a few percent in my tests)
Found a bug or an issue You couldn't resolve? Just leave a comment here! :)
Todo: Add compatibility for Enums. Totally forgot those, never heard of a net.server Enum being used but why not add it anyways ^^ (also add an option to not cache)
Maven:
to add to local repo (there is no online repo):
mvn install:install-file Dfile=<howYouNamedTheApiJar>
add to pom:
<dependency>
<groupId>me.zainlessbrombie</groupId>
<artifactId>ZCraftApi</artifactId>
<version>1.0</version>
</dependency>
-
View User Profile
-
Send Message
Posted Jan 6, 201730 minutes ago an plugin project has been made, what maybe it become?
-
View User Profile
-
Send Message
Posted Jan 6, 2017Marketed and improved correctly, who knows? Time will tell :))