Skip to content

Commit efc1f45

Browse files
committed
grub skin
1 parent b978897 commit efc1f45

File tree

1 file changed

+40
-29
lines changed

1 file changed

+40
-29
lines changed

utils.js

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,6 @@ export default class Utils {
198198
}
199199
this.apiLimited = true;
200200
console.log('[INFO] API REQUEST:', apiPath);
201-
setTimeout(() => {
202-
this.apiLimited = false;
203-
}, this.config.api.ratelimit * 1000);
204201

205202
let body;
206203
try {
@@ -216,46 +213,60 @@ export default class Utils {
216213
throw new Error(err);
217214
}
218215

216+
setTimeout(() => {
217+
this.apiLimited = false;
218+
}, this.config.api.ratelimit * 1000);
219+
220+
219221
return JSON.parse(body);
220222
}
221223

222-
async getPlayerAssets(uuid, playerpath) {
224+
static defaultSkin(uuid) {
225+
// great thanks to Minecrell for research into Minecraft and Java's UUID hashing!
226+
// https://git.io/xJpV
227+
// MC uses `uuid.hashCode() & 1` for alex
228+
// that can be compacted to counting the LSBs of every 4th byte in the UUID
229+
// an odd sum means alex, an even sum means steve
230+
// XOR-ing all the LSBs gives us 1 for alex and 0 for steve
231+
const isEven = (c) => {
232+
if (c >= '0' && c <= '9') {
233+
return (c & 1) === 0; // eslint-disable-line
234+
} else if (c >= 'a' && c <= 'f') {
235+
return (c & 1) === 1; // eslint-disable-line
236+
}
237+
console.log('Invalid digit', c);
238+
return null;
239+
};
240+
const lsbsEven =
241+
(isEven(uuid[7]) !== isEven(uuid[23])) !== (isEven(uuid[15]) !== isEven(uuid[31]));
242+
return lsbsEven ? 'Alex' : 'Steve';
243+
}
244+
245+
static async getPlayerAssets(uuid, playerpath) {
223246
try {
224247
fs.ensureDirSync(playerpath);
225248
} catch (error) {
226249
throw new Error(error);
227250
}
228-
const skinapipath = `https://sessionserver.mojang.com/session/minecraft/profile/${uuid}`;
229251

230-
let res;
231-
try {
232-
res = await this.getMojangAPI(skinapipath);
233-
} catch (err) {
234-
console.error('[ERROR] SKIN API', skinapipath, err);
235-
throw new Error(err);
236-
}
237-
const apiprefixAvatar = 'https://crafatar.com/avatars/';
238-
const apiprefixBody = 'https://crafatar.com/renders/body/';
239-
let slim = '';
240-
res.properties.forEach((t) => {
241-
if (t.name === 'textures') {
242-
const texture = JSON.parse(Buffer.from(t.value, 'base64').toString('ascii'));
243-
if (texture.textures.SKIN) {
244-
if (texture.textures.SKIN.metadata && texture.textures.SKIN.metadata.model === 'slim') {
245-
// Alex model
246-
slim = '&default=MHF_Alex';
247-
}
248-
}
249-
}
250-
});
252+
const apiPrefixAvatar = 'https://crafatar.com/avatars/';
253+
const apiPrefixBody = 'https://crafatar.com/renders/body/';
254+
const apiPrefixSkin = 'https://crafatar.com/skins/';
255+
256+
const slim = `&default=MHF_${Utils.defaultSkin(uuid)}`;
257+
251258
Utils.download(
252-
`${apiprefixAvatar}${uuid}?size=64&overlay${slim}`,
259+
`${apiPrefixAvatar}${uuid}?size=64&overlay${slim}`,
253260
path.join(playerpath, 'avatar.png'),
254261
);
255262
Utils.download(
256-
`${apiprefixBody}${uuid}?size=128&overlay${slim}`,
263+
`${apiPrefixBody}${uuid}?size=128&overlay${slim}`,
257264
path.join(playerpath, 'body.png'),
258265
);
266+
Utils.download(
267+
`${apiPrefixSkin}${uuid}?${slim}`,
268+
path.join(playerpath, 'skin.png'),
269+
);
259270
}
260271

261272
static download(apiPath, dest) {
@@ -295,7 +306,7 @@ export default class Utils {
295306
return resolve(data);
296307
} else if (data && data.stats && data.data) {
297308
try {
298-
await this.getPlayerAssets(uuid.replace(/-/g, ''), playerpath);
309+
await Utils.getPlayerAssets(uuid.replace(/-/g, ''), playerpath);
299310
} catch (error) {
300311
console.log(error);
301312
}

0 commit comments

Comments
 (0)