mirror of
https://hub.spigotmc.org/stash/scm/spigot/craftbukkit.git
synced 2025-04-22 11:05:48 +00:00
Finish Commodore action for Material split
Needs full testing
This commit is contained in:
src/main/java/org/bukkit/craftbukkit
@ -32,7 +32,6 @@ import org.bukkit.block.BlockType;
|
||||
import org.bukkit.block.DecoratedPot;
|
||||
import org.bukkit.block.Jukebox;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.block.CraftBlockType;
|
||||
import org.bukkit.craftbukkit.tag.CraftTag;
|
||||
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
@ -370,7 +369,7 @@ public class EnumEvil {
|
||||
return blockDataMeta.getBlockData(material.asBlockType());
|
||||
}
|
||||
|
||||
public static Criteria statistic(Statistic statistic, Material material) { // TODO: 5/18/23 Static method
|
||||
public static Criteria statistic(Statistic statistic, Material material) {
|
||||
if (statistic.getType() == Statistic.Type.ITEM) {
|
||||
return Criteria.statistic(statistic, material.asItemType());
|
||||
} else if (statistic.getType() == Statistic.Type.BLOCK) {
|
||||
@ -379,15 +378,15 @@ public class EnumEvil {
|
||||
return Criteria.statistic(statistic);
|
||||
}
|
||||
|
||||
public static BlockData createBlockData(Material material) { // TODO: 5/18/23 Static method
|
||||
public static BlockData createBlockData(Material material) {
|
||||
return Bukkit.createBlockData(material.asBlockType());
|
||||
}
|
||||
|
||||
public static BlockData createBlockData(Material material, Consumer<BlockData> consumer) { // TODO: 5/18/23 Static method
|
||||
public static BlockData createBlockData(Material material, Consumer<BlockData> consumer) {
|
||||
return Bukkit.createBlockData(material.asBlockType(), consumer::accept);
|
||||
}
|
||||
|
||||
public static BlockData createBlockData(Material material, String data) { // TODO: 5/18/23 Static method
|
||||
public static BlockData createBlockData(Material material, String data) {
|
||||
return Bukkit.createBlockData(material.asBlockType(), data);
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,8 @@ public class Commodore
|
||||
"org/bukkit/block/Block (B)V setData",
|
||||
"org/bukkit/block/Block (BZ)V setData",
|
||||
"org/bukkit/inventory/ItemStack ()I getTypeId",
|
||||
"org/bukkit/inventory/ItemStack (I)V setTypeId"
|
||||
"org/bukkit/inventory/ItemStack (I)V setTypeId",
|
||||
"org/bukkit/inventory/ItemStack ()Lorg/bukkit/Material; getType"
|
||||
) );
|
||||
|
||||
public static void main(String[] args)
|
||||
@ -111,7 +112,7 @@ public class Commodore
|
||||
|
||||
if ( entry.getName().endsWith( ".class" ) )
|
||||
{
|
||||
b = convert( b, false , true );
|
||||
b = convert( b, false, false, true );
|
||||
entry = new JarEntry( entry.getName() );
|
||||
}
|
||||
|
||||
@ -130,7 +131,7 @@ public class Commodore
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] convert(byte[] b, final boolean modern, final boolean enumCompatibility )
|
||||
public static byte[] convert(byte[] b, final boolean modern, final boolean preEnumKilling, final boolean enumCompatibility )
|
||||
{
|
||||
ClassReader cr = new ClassReader( b );
|
||||
ClassWriter cw = new ClassWriter( cr, 0 );
|
||||
@ -507,7 +508,7 @@ public class Commodore
|
||||
return;
|
||||
}
|
||||
|
||||
if ( enumCompatibility ) {
|
||||
if ( enumCompatibility && preEnumKilling ) {
|
||||
if ( owner.equals( "java/lang/Class" ) && name.equals( "getEnumConstants" ) )
|
||||
{
|
||||
super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", "getEnumConstants", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
|
||||
@ -595,16 +596,33 @@ public class Commodore
|
||||
}
|
||||
}
|
||||
|
||||
if ( owner.startsWith( "org/bukkit" ) && desc.contains( "org/bukkit/Material" ) )
|
||||
if ( !preEnumKilling )
|
||||
{
|
||||
if ( replaceMaterialMethod( owner, name, desc, ( newName, newDesc ) -> {
|
||||
super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", newName, newDesc, false );
|
||||
} ) )
|
||||
super.visitMethodInsn( opcode, owner, name, desc, itf );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( owner.startsWith( "org/bukkit" ) && desc.contains( "org/bukkit/Material" ) ) || owner.equals( "org/bukkit/Tag" ) || owner.equals( "org/bukkit/entity/Piglin" ) )
|
||||
{
|
||||
if ( replaceMaterialMethod( owner, name, desc, ( newName, newDesc ) ->
|
||||
super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", newName, newDesc, false ) ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: 5/18/23 Change Tags, static methods and piglin methods
|
||||
|
||||
if ( owner.equals( "org/bukkit/Bukkit" ) && name.equals( "createBlockData" ) )
|
||||
{
|
||||
super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", name, desc, false );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( owner.equals( "org/bukkit/scoreboard/Criteria" ) && name.equals( "statistic" ) && desc.contains( "Material" ) )
|
||||
{
|
||||
super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", name, desc, false );
|
||||
return;
|
||||
}
|
||||
|
||||
super.visitMethodInsn( opcode, owner, name, desc, itf );
|
||||
return;
|
||||
}
|
||||
@ -673,6 +691,27 @@ public class Commodore
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( owner.startsWith( "org/bukkit" ) && desc.contains( "org/bukkit/Material" ) ) || owner.equals( "org/bukkit/Tag" ) || owner.equals( "org/bukkit/entity/Piglin" ) )
|
||||
{
|
||||
if ( replaceMaterialMethod( owner, name, desc, ( newName, newDesc ) ->
|
||||
super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", newName, newDesc, false ) ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( owner.equals( "org/bukkit/Bukkit" ) && name.equals( "createBlockData" ) )
|
||||
{
|
||||
super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", name, desc, false );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( owner.equals( "org/bukkit/scoreboard/Criteria" ) && name.equals( "statistic" ) && desc.contains( "Material" ) )
|
||||
{
|
||||
super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", name, desc, false );
|
||||
return;
|
||||
}
|
||||
|
||||
super.visitMethodInsn( opcode, owner, name, desc, itf );
|
||||
}
|
||||
|
||||
@ -693,7 +732,7 @@ public class Commodore
|
||||
{
|
||||
// Need to also change class type when changing the creation of a new Object
|
||||
// Fore more info see org.bukkit.craftbukkit.legacy.ImposterEnumMap
|
||||
if ( enumCompatibility && Opcodes.NEW == opcode && type.equals( "java/util/EnumMap" ) )
|
||||
if ( enumCompatibility && preEnumKilling && Opcodes.NEW == opcode && type.equals( "java/util/EnumMap" ) )
|
||||
{
|
||||
super.visitTypeInsn( opcode, "org/bukkit/craftbukkit/legacy/ImposterEnumMap" );
|
||||
return;
|
||||
@ -708,13 +747,35 @@ public class Commodore
|
||||
List<Object> methodArgs = new ArrayList<>();
|
||||
for ( Object object : bootstrapMethodArguments )
|
||||
{
|
||||
if ( enumCompatibility && object instanceof Handle handle && handle.getOwner().equals( "java/util/EnumMap" ) )
|
||||
if ( enumCompatibility && preEnumKilling && object instanceof Handle handle && handle.getOwner().equals( "java/util/EnumMap" ) )
|
||||
{
|
||||
Handle newHandle = new Handle( handle.getTag(), "org/bukkit/craftbukkit/legacy/ImposterEnumMap", handle.getName(), handle.getDesc(), handle.isInterface() );
|
||||
methodArgs.add( newHandle );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( preEnumKilling && object instanceof Handle handle ) {
|
||||
if ( ( handle.getOwner().startsWith( "org/bukkit" ) && handle.getDesc().contains( "org/bukkit/Material" ) ) || handle.getOwner().equals( "org/bukkit/Tag" ) || handle.getOwner().equals( "org/bukkit/entity/Piglin" ) )
|
||||
{
|
||||
if ( replaceMaterialMethod( handle.getOwner(), handle.getName(), handle.getDesc(), ( newName, newDesc ) ->
|
||||
methodArgs.add( new Handle( Opcodes.H_INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", newName, newDesc, false ) ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
} else if ( handle.getOwner().equals( "org/bukkit/Bukkit" ) && handle.getName().equals( "createBlockData" ) )
|
||||
{
|
||||
methodArgs.add( new Handle( Opcodes.H_INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", handle.getName(), handle.getDesc(), false ) );
|
||||
continue;
|
||||
|
||||
} else if ( handle.getOwner().equals( "org/bukkit/scoreboard/Criteria" ) && handle.getName().equals( "statistic" ) && handle.getDesc().contains( "Material" ) )
|
||||
{
|
||||
methodArgs.add( new Handle( Opcodes.H_INVOKESTATIC, "org/bukkit/craftbukkit/legacy/EnumEvil", handle.getName(), handle.getDesc(), false ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
methodArgs.add( object );
|
||||
}
|
||||
|
||||
methodArgs.add( object );
|
||||
}
|
||||
|
||||
@ -727,6 +788,33 @@ public class Commodore
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
/*
|
||||
This method looks (and probably is) overengineered, but it gives the most flexible when it comes to remapping normal methods to static one.
|
||||
The problem with normal owner and desc replacement is that child classes have them as an owner, instead there parents for there parents methods
|
||||
|
||||
For example, if we have following two interfaces org.bukkit.BlockData and org.bukkit.Orientable extents BlockData
|
||||
and BlockData has the method org.bukkit.Material getType which we want to reroute to the static method
|
||||
org.bukkit.Material org.bukkit.craftbukkit.legacy.EnumEvil#getType(org.bukkit.BlockData)
|
||||
|
||||
If we now call BlockData#getType we get as the owner org/bukkit/BlockData and as desc ()Lorg/bukkit/Material;
|
||||
Which we can nicely reroute by checking if the owner is BlockData and the name getType
|
||||
The problem, starts if we use Orientable#getType no we get as owner org/bukkit/Orientable and as desc ()Lorg/bukkit/Material;
|
||||
Now we can now longer safely say to which getType method we need to reroute (assume there are multiple getType methods from different classes,
|
||||
which are not related to BlockData), simple using the owner class will not work, since would reroute to
|
||||
EnumEvil#getType(org.bukkit.Orientable) which is not EnumEvil#getType(org.bukkit.BlockData) and will throw a method not found error
|
||||
at runtime.
|
||||
|
||||
Meaning we would need to add checks for each subclass, which would be pur insanity.
|
||||
|
||||
To solve this, we go through each super class and interfaces (and their super class and interfaces etc.) and try to get an owner
|
||||
which matches with one of our replacement methods. Based on how inheritance works in java, this method should be safe to use.
|
||||
|
||||
As a site note: This method could also be used for the other method reroute, e.g. legacy method rerouting, where only the replacement
|
||||
method needs to be written, and this method figures out the rest, which could reduce the size and complexity of the Commodore class.
|
||||
The question then becomes one about performance (since this is not the most performance way) and convenience.
|
||||
But since it is only applied for each class and method call once when they get first loaded, it should not be that bad.
|
||||
(Although some load time testing could be done)
|
||||
*/
|
||||
public static boolean replaceMaterialMethod( String owner, String name, String desc, BiConsumer<String, String> consumer )
|
||||
{
|
||||
Type[] args = Type.getArgumentTypes( desc );
|
||||
@ -807,7 +895,7 @@ public class Commodore
|
||||
|
||||
Set<Class<?>> classes = Sets.newHashSet( clazz.getInterfaces() );
|
||||
classes.add( clazz.getSuperclass() );
|
||||
classes.remove( null );
|
||||
classes.remove( null ); // Super class can be null, remove it if this is the case
|
||||
classes.removeAll( visit );
|
||||
toVisit.addAll( classes );
|
||||
|
||||
|
@ -378,11 +378,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
return pdf.getAPIVersion() == null;
|
||||
}
|
||||
|
||||
public static boolean enumCompatibilityMode(PluginDescriptionFile pdf) {
|
||||
if (!((CraftServer) Bukkit.getServer()).enumCompatibilityMode) {
|
||||
return false;
|
||||
}
|
||||
public static boolean enumCompatibilityMode() {
|
||||
return ((CraftServer) Bukkit.getServer()).enumCompatibilityMode;
|
||||
}
|
||||
|
||||
public static boolean preEnumKilling(PluginDescriptionFile pdf) {
|
||||
if (pdf.getAPIVersion() == null) {
|
||||
return true;
|
||||
}
|
||||
@ -396,7 +396,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
@Override
|
||||
public byte[] processClass(PluginDescriptionFile pdf, String path, byte[] clazz) {
|
||||
try {
|
||||
clazz = Commodore.convert(clazz, !isLegacy(pdf), enumCompatibilityMode(pdf));
|
||||
clazz = Commodore.convert(clazz, !isLegacy(pdf), preEnumKilling(pdf), enumCompatibilityMode());
|
||||
} catch (Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Fatal error trying to convert " + pdf.getFullName() + ":" + path, ex);
|
||||
}
|
||||
|
Reference in New Issue
Block a user