1
1
package io .izzel .arclight .common .mod .util .remapper .patcher .integrated ;
2
2
3
3
import io .izzel .arclight .api .PluginPatcher ;
4
+ import io .izzel .arclight .common .mod .server .ArclightServer ;
5
+ import io .izzel .arclight .common .mod .util .remapper .ArclightRemapper ;
6
+ import org .apache .logging .log4j .Logger ;
4
7
import org .objectweb .asm .Opcodes ;
5
8
import org .objectweb .asm .Type ;
6
- import org .objectweb .asm .commons .GeneratorAdapter ;
7
- import org .objectweb .asm .commons .Method ;
8
- import org .objectweb .asm .tree .AbstractInsnNode ;
9
- import org .objectweb .asm .tree .ClassNode ;
10
- import org .objectweb .asm .tree .InsnList ;
11
- import org .objectweb .asm .tree .InsnNode ;
12
- import org .objectweb .asm .tree .MethodInsnNode ;
13
- import org .objectweb .asm .tree .MethodNode ;
14
- import org .objectweb .asm .tree .TypeInsnNode ;
15
- import org .objectweb .asm .tree .VarInsnNode ;
9
+ import org .objectweb .asm .tree .*;
16
10
17
- import java .util .Locale ;
11
+ import java .util .HashMap ;
12
+ import java .util .Map ;
18
13
19
14
public class WorldEdit {
20
-
21
- public static void handleBukkitAdapter (ClassNode node , PluginPatcher .ClassRepo repo ) {
22
- MethodNode standardize = new MethodNode (Opcodes .ACC_PRIVATE | Opcodes .ACC_STATIC | Opcodes .ACC_SYNTHETIC , "patcher$standardize" ,
23
- Type .getMethodDescriptor (Type .getType (String .class ), Type .getType (String .class )), null , null );
24
- try {
25
- GeneratorAdapter adapter = new GeneratorAdapter (standardize , standardize .access , standardize .name , standardize .desc );
26
- adapter .loadArg (0 );
27
- adapter .push (':' );
28
- adapter .push ('_' );
29
- adapter .invokeVirtual (Type .getType (String .class ), Method .getMethod (String .class .getMethod ("replace" , char .class , char .class )));
30
- adapter .push ("\\ s+" );
31
- adapter .push ("_" );
32
- adapter .invokeVirtual (Type .getType (String .class ), Method .getMethod (String .class .getMethod ("replaceAll" , String .class , String .class )));
33
- adapter .push ("\\ W" );
34
- adapter .push ("" );
35
- adapter .invokeVirtual (Type .getType (String .class ), Method .getMethod (String .class .getMethod ("replaceAll" , String .class , String .class )));
36
- adapter .getStatic (Type .getType (Locale .class ), "ENGLISH" , Type .getType (Locale .class ));
37
- adapter .invokeVirtual (Type .getType (String .class ), Method .getMethod (String .class .getMethod ("toUpperCase" , Locale .class )));
38
- adapter .returnValue ();
39
- adapter .endMethod ();
40
- } catch (Throwable t ) {
41
- t .printStackTrace ();
42
- }
43
- node .methods .add (standardize );
44
- for (MethodNode method : node .methods ) {
45
- if (method .name .equals ("adapt" )) {
46
- handleAdapt (node , standardize , method );
47
- }
48
- }
49
- }
50
-
51
- public static void handlePickName (ClassNode node , PluginPatcher .ClassRepo repo ) {
52
- for (MethodNode method : node .methods ) {
53
- if (method .name .equals ("pickName" )) {
54
- method .instructions .clear ();
55
- method .instructions .add (new VarInsnNode (Opcodes .ALOAD , 1 ));
56
- method .instructions .add (new InsnNode (Opcodes .ARETURN ));
57
- return ;
58
- }
59
- }
60
- }
61
-
62
- private static void handleAdapt (ClassNode node , MethodNode standardize , MethodNode method ) {
63
- switch (method .desc ) {
64
- case "(Lcom/sk89q/worldedit/world/item/ItemType;)Lorg/bukkit/Material;" :
65
- case "(Lcom/sk89q/worldedit/world/block/BlockType;)Lorg/bukkit/Material;" :
66
- case "(Lcom/sk89q/worldedit/world/biome/BiomeType;)Lorg/bukkit/block/Biome;" :
67
- case "(Lcom/sk89q/worldedit/world/entity/EntityType;)Lorg/bukkit/entity/EntityType;" : {
68
- for (AbstractInsnNode instruction : method .instructions ) {
69
- if (instruction .getOpcode () == Opcodes .ATHROW ) {
70
- InsnList list = new InsnList ();
71
- list .add (new VarInsnNode (Opcodes .ALOAD , 0 ));
72
- list .add (new MethodInsnNode (Opcodes .INVOKEVIRTUAL , Type .getMethodType (method .desc ).getArgumentTypes ()[0 ].getInternalName (), "getId" , "()Ljava/lang/String;" , false ));
73
- list .add (new MethodInsnNode (Opcodes .INVOKESTATIC , node .name , standardize .name , standardize .desc , false ));
74
- switch (Type .getMethodType (method .desc ).getReturnType ().getInternalName ()) {
75
- case "org/bukkit/Material" :
76
- list .add (new MethodInsnNode (Opcodes .INVOKESTATIC , "org/bukkit/Material" , "getMaterial" , "(Ljava/lang/String;)Lorg/bukkit/Material;" , false ));
77
- break ;
78
- case "org/bukkit/block/Biome" :
79
- list .add (new MethodInsnNode (Opcodes .INVOKESTATIC , "org/bukkit/block/Biome" , "valueOf" , "(Ljava/lang/String;)Lorg/bukkit/block/Biome;" , false ));
80
- break ;
81
- case "org/bukkit/entity/EntityType" :
82
- list .add (new MethodInsnNode (Opcodes .INVOKESTATIC , "org/bukkit/entity/EntityType" , "fromName" , "(Ljava/lang/String;)Lorg/bukkit/entity/EntityType;" , false ));
83
- break ;
84
- }
85
- list .add (new InsnNode (Opcodes .ARETURN ));
86
- method .instructions .insert (instruction , list );
87
- method .instructions .set (instruction , new InsnNode (Opcodes .POP ));
88
- return ;
89
- }
90
- }
91
- break ;
92
- }
93
- }
94
- }
95
-
15
+ // Don't use SpigotWatchdog since we're not using it
96
16
public static void handleWatchdog (ClassNode node , PluginPatcher .ClassRepo repo ) {
97
17
if (node .interfaces .size () == 1 && node .interfaces .get (0 ).equals ("com/sk89q/worldedit/extension/platform/Watchdog" )
98
18
&& node .name .contains ("SpigotWatchdog" )) {
@@ -110,4 +30,117 @@ public static void handleWatchdog(ClassNode node, PluginPatcher.ClassRepo repo)
110
30
}
111
31
}
112
32
}
33
+
34
+ // Correctly handle reflection name picking
35
+ // Their naming mapping for NMS is somehow behind the version
36
+ public static void handleStaticRefraction (ClassNode node , PluginPatcher .ClassRepo repo ) {
37
+ ArclightServer .LOGGER .warn ("Loading WorldEdit Bukkit support for 1.21.1 ..." );
38
+ ArclightServer .LOGGER .warn ("For WorldEdit (on bukkit) compatibility issues, please report to us in advance!" );
39
+ var remapper = ArclightRemapper .getMojRemapper ();
40
+ var addEntity = remapper .mapMethodName (
41
+ "net/minecraft/server/level/ServerLevel" ,
42
+ "addFreshEntity" ,
43
+ "(Lnet/minecraft/world/entity/Entity;)Z" ,
44
+ Opcodes .ACC_PUBLIC
45
+ );
46
+
47
+ var mapped = Map .of (
48
+ "getChunkFutureMainThread" , remapper .mapMethodName (
49
+ "net/minecraft/server/level/ServerChunkCache" ,
50
+ "getChunkFutureMainThread" ,
51
+ "(IILnet/minecraft/world/level/chunk/status/ChunkStatus;Z)Ljava/util/concurrent/CompletableFuture;" ,
52
+ Opcodes .ACC_PRIVATE
53
+ ),
54
+ "mainThreadProcessor" , remapper .mapFieldName (
55
+ "net/minecraft/server/level/ServerChunkCache" ,
56
+ "mainThreadProcessor" ,
57
+ "Lnet/minecraft/server/level/ServerChunkCache$MainThreadExecutor;" ,
58
+ Opcodes .ACC_PRIVATE | Opcodes .ACC_FINAL
59
+ ),
60
+ "nextTickTime" , remapper .mapFieldName (
61
+ "net/minecraft/server/MinecraftServer" ,
62
+ "nextTickTimeNanos" ,
63
+ "J" ,
64
+ Opcodes .ACC_PRIVATE
65
+ ),
66
+ "getBlockEntity" , remapper .mapMethodName (
67
+ "net/minecraft/world/level/BlockGetter" ,
68
+ "getBlockEntity" ,
69
+ "(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/entity/BlockEntity;" ,
70
+ Opcodes .ACC_PUBLIC
71
+ ),
72
+ "addFreshEntity" , addEntity ,
73
+ "addFreshEntityWithPassengers" , addEntity ,
74
+ "getBlockState" , remapper .mapMethodName (
75
+ "net/minecraft/world/level/Level" ,
76
+ "getBlockState" ,
77
+ "(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;" ,
78
+ Opcodes .ACC_PUBLIC
79
+ ),
80
+ "setBlock" , remapper .mapMethodName (
81
+ "net/minecraft/world/level/LevelWriter" ,
82
+ "setBlock" ,
83
+ "(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z" ,
84
+ Opcodes .ACC_PUBLIC
85
+ ),
86
+ "removeBlock" , remapper .mapMethodName (
87
+ "net/minecraft/world/level/Level" ,
88
+ "removeBlock" ,
89
+ "(Lnet/minecraft/core/BlockPos;Z)Z" ,
90
+ Opcodes .ACC_PUBLIC
91
+ ),
92
+ "destroyBlock" , remapper .mapMethodName (
93
+ "net/minecraft/world/level/Level" ,
94
+ "destroyBlock" ,
95
+ "(Lnet/minecraft/core/BlockPos;ZLnet/minecraft/world/entity/Entity;I)Z" ,
96
+ Opcodes .ACC_PUBLIC
97
+ )
98
+ );
99
+ for (MethodNode method : node .methods ) {
100
+ if ("<clinit>" .equals (method .name )) {
101
+ boolean isLastPut = true ;
102
+ LdcInsnNode lastLdc = null ;
103
+ Map <String , String > fieldToProvided = new HashMap <>();
104
+ for (var insn : method .instructions ) {
105
+ if (isLastPut && insn instanceof LdcInsnNode ldc && ldc .cst instanceof String ) {
106
+ lastLdc = ldc ;
107
+ isLastPut = false ;
108
+ }
109
+ if (insn instanceof FieldInsnNode field ) {
110
+ fieldToProvided .put (field .name , (String ) lastLdc .cst );
111
+ isLastPut = true ;
112
+ }
113
+ }
114
+ method .instructions .clear ();
115
+
116
+ int line = 0 ;
117
+ for (var entry : fieldToProvided .entrySet ()) {
118
+ var label = new LabelNode ();
119
+ method .instructions .add (label );
120
+ method .instructions .add (new LineNumberNode (--line , label ));
121
+ method .instructions .add (new LdcInsnNode (mapped .get (entry .getValue ())));
122
+ method .instructions .add (new FieldInsnNode (
123
+ Opcodes .PUTSTATIC ,
124
+ node .name ,
125
+ entry .getKey (),
126
+ "Ljava/lang/String;"
127
+ ));
128
+ }
129
+
130
+ var label = new LabelNode ();
131
+ method .instructions .add (label );
132
+ method .instructions .add (new LineNumberNode (--line , label ));
133
+ method .instructions .add (new FieldInsnNode (Opcodes .GETSTATIC , Type .getInternalName (ArclightServer .class ), "LOGGER" , Type .getDescriptor (Logger .class )));
134
+ method .instructions .add (new InsnNode (Opcodes .DUP ));
135
+ method .instructions .add (new LdcInsnNode ("Arclight is enabling support for WorldEdit!" ));
136
+ method .instructions .add (new MethodInsnNode (Opcodes .INVOKEINTERFACE , Type .getInternalName (Logger .class ), "warn" , "(Ljava/lang/String;)V" , true ));
137
+ method .instructions .add (new LdcInsnNode ("For issues with WorldEdit please report to Arclight." ));
138
+ method .instructions .add (new MethodInsnNode (Opcodes .INVOKEINTERFACE , Type .getInternalName (Logger .class ), "warn" , "(Ljava/lang/String;)V" , true ));
139
+
140
+ method .instructions .add (new InsnNode (Opcodes .RETURN ));
141
+
142
+ method .visitMaxs (2 , 0 );
143
+ }
144
+ }
145
+ }
113
146
}
0 commit comments