66import java .util .HashMap ;
77import java .util .Map ;
88
9+ import org .json .JSONObject ;
910import org .mcphackers .launchwrapper .LaunchConfig ;
1011import org .mcphackers .launchwrapper .protocol .skin .Skin ;
1112import org .mcphackers .launchwrapper .protocol .skin .SkinRequests ;
1213import org .mcphackers .launchwrapper .protocol .skin .SkinTexture ;
1314import org .mcphackers .launchwrapper .tweak .injection .InjectionWithContext ;
1415import org .mcphackers .launchwrapper .tweak .injection .MinecraftGetter ;
16+ import org .mcphackers .launchwrapper .util .Base64 ;
1517import org .mcphackers .launchwrapper .util .ClassNodeSource ;
1618import org .mcphackers .launchwrapper .util .asm .NodeHelper ;
1719import org .objectweb .asm .Type ;
@@ -85,76 +87,102 @@ public boolean apply(ClassNodeSource source, LaunchConfig config) {
8587 insns .add (new InsnNode (ARETURN ));
8688
8789 for (MethodNode impl : mcSessionService .methods ) {
88- if (( impl . access & ACC_ABSTRACT ) != 0 ) {
89- MethodNode implMethod = NodeHelper . newMethod ( sessionService , ACC_PUBLIC ,
90- impl . name , impl . desc , impl . signature , impl . exceptions . toArray ( new String [ 0 ]), false ) ;
91- insns = implMethod . instructions ;
92- if ( impl . name . equals ( "getTextures" ) && impl . desc . equals ( "(Lcom/mojang/authlib/GameProfile;Z)Ljava/util/Map;" )) {
93- insns .add (getTextures ( source ));
94- continue ;
95- }
96- if ( impl . name . equals ( "getPackedTextures" ) && impl . desc . equals ( "(Lcom/mojang/authlib/GameProfile;)Lcom/mojang/authlib/properties/Property;" )) {
97- // TODO
98- return false ;
99- }
100- int i = 1 ;
101- insns . add ( new VarInsnNode ( ALOAD , 0 )) ;
102- insns . add ( new FieldInsnNode ( GETFIELD , sessionService . name , dispatcher . name , dispatcher . desc ));
103- for ( Type type : Type . getArgumentTypes ( impl .desc )) {
104- switch ( type . getSort ()) {
105- case Type . BOOLEAN :
106- case Type . BYTE :
107- case Type . CHAR :
108- case Type . SHORT :
109- case Type . INT :
110- insns .add (new VarInsnNode ( ILOAD , i ));
111- break ;
112- case Type . LONG :
113- insns . add ( new VarInsnNode ( LLOAD , i ));
114- break ;
115- case Type . FLOAT :
116- insns .add (new VarInsnNode ( FLOAD , i ));
117- break ;
118- case Type . DOUBLE :
119- insns .add (new VarInsnNode ( DLOAD , i ));
120- break ;
121- case Type . ARRAY :
122- case Type . OBJECT :
123- insns .add (new VarInsnNode ( ALOAD , i ));
124- break ;
125- default :
126- return false ;
127- }
128- i += type . getSize ( );
129- }
130- insns . add ( new MethodInsnNode ( INVOKEINTERFACE , "com/mojang/authlib/minecraft/MinecraftSessionService" , impl . name , impl .desc ));
131- switch (Type . getReturnType ( impl . desc ) .getSort ()) {
90+ MethodNode implMethod = NodeHelper . newMethod ( sessionService , ACC_PUBLIC ,
91+ impl . name , impl . desc , impl . signature , impl . exceptions . toArray ( new String [ 0 ]), false );
92+ insns = implMethod . instructions ;
93+ if ( impl . name . equals ( "getTextures" ) && impl . desc . equals ( "(Lcom/mojang/authlib/GameProfile;Z)Ljava/util/Map;" )) {
94+ insns . add ( new VarInsnNode ( ALOAD , 1 ));
95+ insns .add (pushIdAndName ( ));
96+ insns . add ( getTextures ( source , false )) ;
97+ continue ;
98+ }
99+ if ( impl . name . equals ( "getTextures" ) && impl . desc . equals ( "(Lcom/mojang/authlib/GameProfile;)Lcom/mojang/authlib/minecraft/MinecraftProfileTextures;" )) {
100+ insns . add ( new VarInsnNode ( ALOAD , 1 )) ;
101+ insns . add ( pushIdAndName ());
102+ insns . add ( getTextures ( source , true )) ;
103+ continue ;
104+ }
105+ if ( impl . name . equals ( "getPackedTextures" ) && impl .desc . equals ( "(Lcom/mojang/authlib/GameProfile;)Lcom/mojang/authlib/properties/Property;" )) {
106+ insns . add ( new TypeInsnNode ( NEW , "com/mojang/authlib/properties/Property" ));
107+ insns . add ( new InsnNode ( DUP ));
108+ insns . add ( new LdcInsnNode ( "textures" ));
109+ insns . add ( new VarInsnNode ( ALOAD , 1 ));
110+ insns . add ( pushIdAndName ());
111+ insns . add ( new MethodInsnNode ( INVOKESTATIC , "org/mcphackers/launchwrapper/tweak/injection/vanilla/OfflineSkins" , "getTexturesBase64" , "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" ));
112+ insns .add (new MethodInsnNode ( INVOKESPECIAL , "com/mojang/authlib/properties/Property" , "<init>" , "(Ljava/lang/String;Ljava/lang/String;)V" ));
113+ insns . add ( new InsnNode ( ARETURN )) ;
114+ continue ;
115+ }
116+ if ( impl . name . equals ( "unpackTextures" ) && impl . desc . equals ( "(Lcom/mojang/authlib/properties/Property;)Lcom/mojang/authlib/minecraft/MinecraftProfileTextures;" )) {
117+ insns . add ( new VarInsnNode ( ALOAD , 1 ));
118+ insns .add (new MethodInsnNode ( INVOKEVIRTUAL , "com/mojang/authlib/properties/Property" , "value" , "()Ljava/lang/String;" ));
119+ insns . add ( new MethodInsnNode ( INVOKESTATIC , "org/mcphackers/launchwrapper/tweak/injection/vanilla/OfflineSkins" , "unpackProfileBase64" , "(Ljava/lang/String;)[Ljava/lang/String;" )) ;
120+ insns . add ( new InsnNode ( DUP ));
121+ insns .add (new InsnNode ( ICONST_0 ));
122+ insns . add ( new InsnNode ( AALOAD )) ;
123+ insns . add ( new InsnNode ( SWAP ));
124+ insns . add ( new InsnNode ( ICONST_1 ));
125+ insns .add (new InsnNode ( AALOAD ));
126+ insns . add ( getTextures ( source , true )) ;
127+ continue ;
128+ }
129+ int i = 1 ;
130+ insns . add ( new VarInsnNode ( ALOAD , 0 ) );
131+ insns . add ( new FieldInsnNode ( GETFIELD , sessionService . name , dispatcher . name , dispatcher . desc ));
132+ for ( Type type : Type . getArgumentTypes ( impl .desc )) {
133+ switch (type .getSort ()) {
132134 case Type .BOOLEAN :
133135 case Type .BYTE :
134136 case Type .CHAR :
135137 case Type .SHORT :
136138 case Type .INT :
137- insns .add (new InsnNode ( IRETURN ));
139+ insns .add (new VarInsnNode ( ILOAD , i ));
138140 break ;
139141 case Type .LONG :
140- insns .add (new InsnNode ( LRETURN ));
142+ insns .add (new VarInsnNode ( LLOAD , i ));
141143 break ;
142144 case Type .FLOAT :
143- insns .add (new InsnNode ( FRETURN ));
145+ insns .add (new VarInsnNode ( FLOAD , i ));
144146 break ;
145147 case Type .DOUBLE :
146- insns .add (new InsnNode ( DRETURN ));
148+ insns .add (new VarInsnNode ( DLOAD , i ));
147149 break ;
148150 case Type .ARRAY :
149151 case Type .OBJECT :
150- insns .add (new InsnNode (ARETURN ));
151- break ;
152- case Type .VOID :
153- insns .add (new InsnNode (RETURN ));
152+ insns .add (new VarInsnNode (ALOAD , i ));
154153 break ;
155154 default :
156155 return false ;
157156 }
157+ i += type .getSize ();
158+ }
159+ insns .add (new MethodInsnNode (INVOKEINTERFACE , "com/mojang/authlib/minecraft/MinecraftSessionService" , impl .name , impl .desc ));
160+ switch (Type .getReturnType (impl .desc ).getSort ()) {
161+ case Type .BOOLEAN :
162+ case Type .BYTE :
163+ case Type .CHAR :
164+ case Type .SHORT :
165+ case Type .INT :
166+ insns .add (new InsnNode (IRETURN ));
167+ break ;
168+ case Type .LONG :
169+ insns .add (new InsnNode (LRETURN ));
170+ break ;
171+ case Type .FLOAT :
172+ insns .add (new InsnNode (FRETURN ));
173+ break ;
174+ case Type .DOUBLE :
175+ insns .add (new InsnNode (DRETURN ));
176+ break ;
177+ case Type .ARRAY :
178+ case Type .OBJECT :
179+ insns .add (new InsnNode (ARETURN ));
180+ break ;
181+ case Type .VOID :
182+ insns .add (new InsnNode (RETURN ));
183+ break ;
184+ default :
185+ return false ;
158186 }
159187 }
160188
@@ -168,21 +196,9 @@ public boolean apply(ClassNodeSource source, LaunchConfig config) {
168196 }
169197 return false ;
170198 }
171- private static InsnList pushIdAndName () {
172- InsnList insns = new InsnList ();
173- insns .add (new InsnNode (DUP ));
174- insns .add (new MethodInsnNode (INVOKEVIRTUAL , "com/mojang/authlib/GameProfile" , "getId" , "()Ljava/util/UUID;" ));
175- insns .add (new MethodInsnNode (INVOKEVIRTUAL , "java/util/UUID" , "toString" , "()Ljava/lang/String;" ));
176- insns .add (new LdcInsnNode ("-" ));
177- insns .add (new LdcInsnNode ("" ));
178- insns .add (new MethodInsnNode (INVOKEVIRTUAL , "java/lang/String" , "replace" , "(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;" ));
179- insns .add (new InsnNode (SWAP ));
180- insns .add (new MethodInsnNode (INVOKEVIRTUAL , "com/mojang/authlib/GameProfile" , "getName" , "()Ljava/lang/String;" ));
181- return insns ;
182- }
183199
184200 /**
185- * Helper method called from ASM
201+ * Helper methods
186202 */
187203 public static Map <SkinTexture , Skin > getTexturesMap (String id , String username ) {
188204 SkinRequests skins = SkinRequests .getInstance ();
@@ -196,15 +212,61 @@ public static Map<SkinTexture, Skin> getTexturesMap(String id, String username)
196212 return map ;
197213 }
198214
199- private static InsnList getTextures (ClassNodeSource source ) {
215+ public static String [] unpackProfileBase64 (String base64 ) {
216+ String [] uuidAndName = new String [2 ];
217+ try {
218+ JSONObject jsonObject = new JSONObject (new String (Base64 .decode (base64 ), "UTF-8" ));
219+ uuidAndName [0 ] = jsonObject .getString ("profileId" );
220+ uuidAndName [1 ] = jsonObject .getString ("profileName" );
221+ } catch (Exception e ) {
222+ e .printStackTrace ();
223+ }
224+ return uuidAndName ;
225+ }
226+
227+ public static String getTexturesBase64 (String id , String username ) {
228+ SkinRequests skins = SkinRequests .getInstance ();
229+ JSONObject json = new JSONObject ();
230+ json .put ("profileId" , id );
231+ json .put ("profileName" , username );
232+ JSONObject textures = new JSONObject ();
233+ json .put ("textures" , textures );
234+ for (SkinTexture skinTex : SkinTexture .values ()) {
235+ Skin skin = skins .downloadSkin (id , username , skinTex );
236+ if (skin == null ) {
237+ continue ;
238+ }
239+ JSONObject texture = new JSONObject ();
240+ texture .put ("url" , skin .getURL ());
241+ textures .put (skinTex .name (), texture );
242+ }
243+ return Base64 .encodeBytes (json .toString ().getBytes ());
244+ }
245+ /*
246+ * Helper methods end
247+ */
248+
249+ private static InsnList pushIdAndName () {
250+ InsnList insns = new InsnList ();
251+ insns .add (new InsnNode (DUP ));
252+ insns .add (new MethodInsnNode (INVOKEVIRTUAL , "com/mojang/authlib/GameProfile" , "getId" , "()Ljava/util/UUID;" ));
253+ insns .add (new MethodInsnNode (INVOKEVIRTUAL , "java/util/UUID" , "toString" , "()Ljava/lang/String;" ));
254+ insns .add (new LdcInsnNode ("-" ));
255+ insns .add (new LdcInsnNode ("" ));
256+ insns .add (new MethodInsnNode (INVOKEVIRTUAL , "java/lang/String" , "replace" , "(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;" ));
257+ insns .add (new InsnNode (SWAP ));
258+ insns .add (new MethodInsnNode (INVOKEVIRTUAL , "com/mojang/authlib/GameProfile" , "getName" , "()Ljava/lang/String;" ));
259+ return insns ;
260+ }
261+
262+ private static InsnList getTextures (ClassNodeSource source , boolean retRecordClass ) {
200263 int mapIndex = 2 ;
201264 int mapIndex2 = 3 ;
202265 int valuesIndex = 4 ;
203266 int valuesIndex2 = 5 ;
204267 int iIndex = 6 ;
205268 InsnList insns = new InsnList ();
206- insns .add (new VarInsnNode (ALOAD , 1 ));
207- insns .add (pushIdAndName ());
269+ // stack: String id, String username
208270 insns .add (new MethodInsnNode (INVOKESTATIC , "org/mcphackers/launchwrapper/tweak/injection/vanilla/OfflineSkins" , "getTexturesMap" , "(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Map;" ));
209271 insns .add (new VarInsnNode (ASTORE , mapIndex2 ));
210272
@@ -288,7 +350,26 @@ private static InsnList getTextures(ClassNodeSource source) {
288350 insns .add (new JumpInsnNode (GOTO , startLoop ));
289351 insns .add (endLoop );
290352
291- insns .add (new VarInsnNode (ALOAD , mapIndex ));
353+ if (retRecordClass ) {
354+ insns .add (new TypeInsnNode (NEW , "com/mojang/authlib/minecraft/MinecraftProfileTextures" ));
355+ insns .add (new InsnNode (DUP ));
356+ insns .add (new VarInsnNode (ALOAD , mapIndex ));
357+ insns .add (new FieldInsnNode (GETSTATIC , "com/mojang/authlib/minecraft/MinecraftProfileTexture$Type" , "SKIN" , "Lcom/mojang/authlib/minecraft/MinecraftProfileTexture$Type;" ));
358+ insns .add (new MethodInsnNode (INVOKEINTERFACE , "java/util/Map" , "get" , "(Ljava/lang/Object;)Ljava/lang/Object;" ));
359+ insns .add (new TypeInsnNode (CHECKCAST , "com/mojang/authlib/minecraft/MinecraftProfileTexture" ));
360+ insns .add (new VarInsnNode (ALOAD , mapIndex ));
361+ insns .add (new FieldInsnNode (GETSTATIC , "com/mojang/authlib/minecraft/MinecraftProfileTexture$Type" , "CAPE" , "Lcom/mojang/authlib/minecraft/MinecraftProfileTexture$Type;" ));
362+ insns .add (new MethodInsnNode (INVOKEINTERFACE , "java/util/Map" , "get" , "(Ljava/lang/Object;)Ljava/lang/Object;" ));
363+ insns .add (new TypeInsnNode (CHECKCAST , "com/mojang/authlib/minecraft/MinecraftProfileTexture" ));
364+ insns .add (new VarInsnNode (ALOAD , mapIndex ));
365+ insns .add (new FieldInsnNode (GETSTATIC , "com/mojang/authlib/minecraft/MinecraftProfileTexture$Type" , "ELYTRA" , "Lcom/mojang/authlib/minecraft/MinecraftProfileTexture$Type;" ));
366+ insns .add (new MethodInsnNode (INVOKEINTERFACE , "java/util/Map" , "get" , "(Ljava/lang/Object;)Ljava/lang/Object;" ));
367+ insns .add (new TypeInsnNode (CHECKCAST , "com/mojang/authlib/minecraft/MinecraftProfileTexture" ));
368+ insns .add (new FieldInsnNode (GETSTATIC , "com/mojang/authlib/SignatureState" , "SIGNED" , "Lcom/mojang/authlib/SignatureState;" ));
369+ insns .add (new MethodInsnNode (INVOKESPECIAL , "com/mojang/authlib/minecraft/MinecraftProfileTextures" , "<init>" , "(Lcom/mojang/authlib/minecraft/MinecraftProfileTexture;Lcom/mojang/authlib/minecraft/MinecraftProfileTexture;Lcom/mojang/authlib/minecraft/MinecraftProfileTexture;Lcom/mojang/authlib/SignatureState;)V" ));
370+ } else {
371+ insns .add (new VarInsnNode (ALOAD , mapIndex ));
372+ }
292373 insns .add (new InsnNode (ARETURN ));
293374 return insns ;
294375 }
0 commit comments