Skip to content

Commit aa56c12

Browse files
committed
Update OfflineSkins patch to work with latest authlib
1 parent 48f5d8b commit aa56c12

1 file changed

Lines changed: 150 additions & 69 deletions

File tree

src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/OfflineSkins.java

Lines changed: 150 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
import java.util.HashMap;
77
import java.util.Map;
88

9+
import org.json.JSONObject;
910
import org.mcphackers.launchwrapper.LaunchConfig;
1011
import org.mcphackers.launchwrapper.protocol.skin.Skin;
1112
import org.mcphackers.launchwrapper.protocol.skin.SkinRequests;
1213
import org.mcphackers.launchwrapper.protocol.skin.SkinTexture;
1314
import org.mcphackers.launchwrapper.tweak.injection.InjectionWithContext;
1415
import org.mcphackers.launchwrapper.tweak.injection.MinecraftGetter;
16+
import org.mcphackers.launchwrapper.util.Base64;
1517
import org.mcphackers.launchwrapper.util.ClassNodeSource;
1618
import org.mcphackers.launchwrapper.util.asm.NodeHelper;
1719
import 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

Comments
 (0)