miijs 1.8.1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,10 +1,18 @@
1
1
  const fs = require('fs');
2
- const { createCanvas, loadImage } = require('canvas');
2
+ const nodeCanvas = require('canvas');
3
+ const { createCanvas, loadImage, ImageData } = nodeCanvas;
3
4
  const jsQR = require('jsqr');
4
- var Jimp = require('jimp');
5
- const QRCode = require('qrcode');
5
+ const Jimp = require('jimp');
6
+ const THREE = require('three');
7
+ const QRCodeStyling = require("qr-code-styling");
8
+ const { JSDOM } = require("jsdom");
6
9
  const httpsLib = require('https');
7
10
  const asmCrypto=require("./asmCrypto.js");
11
+ const path=require("path");
12
+ const createGL = require('gl');
13
+ const {FFLCharModelDescDefault,createCharModel,initCharModelTextures,initializeFFL,parseHexOrB64ToUint8Array}=require("./ffl.js");
14
+ const ModuleFFL=require("./ffl-emscripten-single-file.js");
15
+ const FFLShaderMaterial=require("./FFLShaderMaterial.js");
8
16
  function getKeyByValue(object, value) {
9
17
  for (var key in object) {
10
18
  if (object[key] === value) {
@@ -13,9 +21,14 @@ function getKeyByValue(object, value) {
13
21
  }
14
22
  }
15
23
 
16
- var binary;
17
- function getBinaryFromAddress(addr){//EG: 0x20
18
- let byte = binary.readUInt8(addr);
24
+ //If FFLResHigh.dat is in the same directory as Node.js is calling the library from, use it by default
25
+ var _fflRes=null;
26
+ if(fs.existsSync("./FFLResHigh.dat")){
27
+ _fflRes=new Uint8Array(fs.readFileSync("./FFLResHigh.dat",""));
28
+ }
29
+
30
+ function getBinaryFromAddress(addr, bin){
31
+ let byte = bin.readUInt8(addr);
19
32
  let binaryString = '';
20
33
  for (let i = 7; i >= 0; i--) {
21
34
  binaryString += ((byte >> i) & 1) ? '1' : '0';
@@ -66,18 +79,17 @@ function encodeAesCcm(data){
66
79
  var ciphertext = asmCrypto.AES_CCM.encrypt(plaintext,aes_key,nonce,undefined,TAG_LENGTH);
67
80
  return Uint8Cat(cfsd.subarray(NONCE_OFFSET,NONCE_OFFSET + NONCE_LENGTH),ciphertext.subarray(0,ciphertext.length - 24),ciphertext.subarray(ciphertext.length - TAG_LENGTH,ciphertext.length))
68
81
  }
69
- function downloadImage(url, filepath) {
82
+ async function downloadImage(url) {
70
83
  return new Promise((resolve, reject) => {
71
84
  httpsLib.get(url, (res) => {
72
85
  if (res.statusCode === 200) {
73
- res.pipe(fs.createWriteStream(filepath))
74
- .on('error', reject)
75
- .once('close', () => resolve(filepath));
86
+ const data = [];
87
+ res.on('data', chunk => data.push(chunk));
88
+ res.on('end', () => resolve(Buffer.concat(data)));
89
+ res.on('error', reject);
76
90
  } else {
77
- // Consume response data to free up memory
78
91
  res.resume();
79
92
  reject(new Error(`Request Failed With a Status Code: ${res.statusCode}`));
80
-
81
93
  }
82
94
  });
83
95
  });
@@ -1060,7 +1072,99 @@ var defaultInstrs={
1060
1072
  }
1061
1073
  }
1062
1074
  };
1063
- module.exports={
1075
+
1076
+ async function renderMii(studioMii,fflRes=_fflRes) {
1077
+ var width=600,height=600;
1078
+ /* ---------- WebGL 1 context ---------- */
1079
+ const gl = createGL(width, height, { preserveDrawingBuffer: true });
1080
+
1081
+ /* ---------- dummy canvas to keep Three.js happy ---------- */
1082
+ const dummyCanvas = {
1083
+ width,
1084
+ height,
1085
+ getContext: () => gl,
1086
+ addEventListener () {},
1087
+ removeEventListener () {},
1088
+ style: {},
1089
+ };
1090
+
1091
+ /* ---------- Three.js renderer ---------- */
1092
+
1093
+
1094
+ const renderer = new THREE.WebGLRenderer({
1095
+ canvas: dummyCanvas,
1096
+ context: gl,
1097
+ });
1098
+ renderer.setSize(width, height);
1099
+ renderer.setClearColor(0xffffff);
1100
+
1101
+ let moduleFFL, currentCharModel;
1102
+ /* ---------- simple scene ---------- */
1103
+ const scene = new THREE.Scene();
1104
+ scene.background = new THREE.Color().setHex(0xffffff, THREE.ColorManagement ? THREE.ColorManagement.workingColorSpace : '');
1105
+ let camera = new THREE.PerspectiveCamera(15, width / height, 1, 5000);
1106
+ camera.position.set(0, 30, 500);
1107
+ function updateCharModelInScene(data, modelDesc) {
1108
+ // Decode data.
1109
+ if (typeof data === 'string') {
1110
+ data = parseHexOrB64ToUint8Array(data);
1111
+ }
1112
+ // Continue assuming it is Uint8Array.
1113
+ // If an existing CharModel exists, update it.
1114
+ if (currentCharModel) {
1115
+ // Remove current CharModel from the scene, then dispose it.
1116
+ currentCharModel.meshes && scene.remove(currentCharModel.meshes);
1117
+ currentCharModel.dispose();
1118
+ }
1119
+
1120
+ // Create a new CharModel.
1121
+ currentCharModel = createCharModel(data, modelDesc, FFLShaderMaterial, moduleFFL);
1122
+ // Initialize textures for the new CharModel.
1123
+ initCharModelTextures(currentCharModel, renderer);
1124
+
1125
+ // Add CharModel meshes to scene.
1126
+ scene.add(currentCharModel.meshes);
1127
+ }
1128
+
1129
+ const box = new THREE.Mesh(
1130
+ new THREE.BoxGeometry(),
1131
+ new THREE.MeshBasicMaterial({ color: 0x00ffff })
1132
+ );
1133
+ scene.add(box);
1134
+ const initResult = await initializeFFL(fflRes, ModuleFFL);
1135
+ moduleFFL = initResult.module;
1136
+
1137
+ updateCharModelInScene(studioMii, FFLCharModelDescDefault); // Use default expression.
1138
+
1139
+ renderer.render(scene, camera);
1140
+
1141
+
1142
+
1143
+ /* ---------- read pixels ---------- */
1144
+ const pixels = new Uint8Array(width * height * 4);
1145
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
1146
+
1147
+ /* ---------- flip rows (Uint8Array → Buffer) ---------- */
1148
+ const src = Buffer.from(pixels); // <-- Convert here
1149
+ const flipped = Buffer.alloc(src.length);
1150
+
1151
+ const rowBytes = width * 4;
1152
+ for (let y = 0; y < height; y++) {
1153
+ const srcStart = y * rowBytes;
1154
+ const dstStart = (height - y - 1) * rowBytes;
1155
+ src.copy(flipped, dstStart, srcStart, srcStart + rowBytes);
1156
+ }
1157
+
1158
+ /* ---------- draw into Node-canvas ---------- */
1159
+ const canvas = createCanvas(width, height);
1160
+ const ctx = canvas.getContext('2d');
1161
+ const img = new ImageData(new Uint8ClampedArray(flipped.buffer), width, height);
1162
+ ctx.putImageData(img, 0, 0);
1163
+
1164
+ return canvas.toBuffer('image/png');
1165
+ }
1166
+
1167
+ var exports={
1064
1168
  readWiiBin:function(binOrPath){
1065
1169
  var thisMii={
1066
1170
  info:{},
@@ -1074,103 +1178,109 @@ module.exports={
1074
1178
  glasses:{},
1075
1179
  facialHair:{}
1076
1180
  };
1181
+
1182
+ let data;
1077
1183
  if(/[^01]/ig.test(binOrPath)){
1078
- binary = fs.readFileSync(binOrPath);
1184
+ data = fs.readFileSync(binOrPath);
1079
1185
  }
1080
1186
  else{
1081
- binary=Buffer.from(binOrPath);
1187
+ data=Buffer.from(binOrPath);
1082
1188
  }
1189
+
1190
+ const get = address => getBinaryFromAddress(address, data);
1191
+
1083
1192
  var name="";
1084
1193
  for(var i=0;i<10;i++){
1085
- name+=binary.slice(3+i*2, 4+i*2)+"";
1194
+ name+=data.slice(3+i*2, 4+i*2)+"";
1086
1195
  }
1087
1196
  thisMii.name=name.replaceAll("\x00","");
1088
1197
  var cname="";
1089
1198
  for(var i=0;i<10;i++){
1090
- cname+=binary.slice(55+i*2, 56+i*2)+"";
1199
+ cname+=data.slice(55+i*2, 56+i*2)+"";
1091
1200
  }
1092
1201
  thisMii.creatorName=cname.replaceAll("\x00","");
1093
1202
  thisMii.info.creatorName=thisMii.creatorName;
1094
1203
  thisMii.info.name=thisMii.name;//Up to ten characters
1095
- thisMii.info.gender=getBinaryFromAddress(0x00)[1]==="1"?"Female":"Male";//0 for Male, 1 for Female
1096
- thisMii.info.miiId=parseInt(getBinaryFromAddress(0x18),2).toString(16)+parseInt(getBinaryFromAddress(0x19),2).toString(16)+parseInt(getBinaryFromAddress(0x1A),2).toString(16)+parseInt(getBinaryFromAddress(0x1B),2).toString(16);
1097
- thisMii.info.systemId=parseInt(getBinaryFromAddress(0x1C),2).toString(16)+parseInt(getBinaryFromAddress(0x1D),2).toString(16)+parseInt(getBinaryFromAddress(0x1E),2).toString(16)+parseInt(getBinaryFromAddress(0x1F),2).toString(16);
1098
- var temp=getBinaryFromAddress(0x20);
1204
+ thisMii.info.gender=get(0x00)[1]==="1"?"Female":"Male";//0 for Male, 1 for Female
1205
+ thisMii.info.miiId=parseInt(get(0x18),2).toString(16)+parseInt(get(0x19),2).toString(16)+parseInt(get(0x1A),2).toString(16)+parseInt(get(0x1B),2).toString(16);
1206
+ thisMii.info.systemId=parseInt(get(0x1C),2).toString(16)+parseInt(get(0x1D),2).toString(16)+parseInt(get(0x1E),2).toString(16)+parseInt(get(0x1F),2).toString(16);
1207
+ var temp=get(0x20);
1099
1208
  thisMii.face.shape=parseInt(temp.slice(0,3),2);//0-7
1100
1209
  thisMii.face.col=skinCols[parseInt(temp.slice(3,6),2)];//0-5
1101
- temp=getBinaryFromAddress(0x21);
1102
- thisMii.face.feature=wiiFaceFeatures[parseInt(getBinaryFromAddress(0x20).slice(6,8)+temp.slice(0,2),2)];//0-11
1210
+ temp=get(0x21);
1211
+ thisMii.face.feature=wiiFaceFeatures[parseInt(get(0x20).slice(6,8)+temp.slice(0,2),2)];//0-11
1103
1212
  thisMii.info.mingle=temp[5]==="0";//0 for Mingle, 1 for Don't Mingle
1104
- temp=getBinaryFromAddress(0x2C);
1213
+ temp=get(0x2C);
1105
1214
  for(var i=0;i<12;i++){
1106
1215
  if(wiiNoses[i]===parseInt(temp.slice(0,4),2)){
1107
1216
  thisMii.nose.type=i;
1108
1217
  }
1109
1218
  }
1110
1219
  thisMii.nose.size=parseInt(temp.slice(4,8),2);
1111
- thisMii.nose.yPos=parseInt(getBinaryFromAddress(0x2D).slice(0,5),2);//From top to bottom, 0-18, default 9
1112
- temp=getBinaryFromAddress(0x2E);
1220
+ thisMii.nose.yPos=parseInt(get(0x2D).slice(0,5),2);//From top to bottom, 0-18, default 9
1221
+ temp=get(0x2E);
1113
1222
  thisMii.mouth.type=mouthTable[""+parseInt(temp.slice(0,5),2)];//0-23, Needs lookup table
1114
1223
  thisMii.mouth.col=wiiMouthColors[parseInt(temp.slice(5,7),2)];//0-2, refer to mouthColors array
1115
- temp2=getBinaryFromAddress(0x2F);
1224
+ temp2=get(0x2F);
1116
1225
  thisMii.mouth.size=parseInt(temp[7]+temp2.slice(0,3),2);//0-8, default 4
1117
1226
  thisMii.mouth.yPos=parseInt(temp2.slice(3,8),2);//0-18, default 9, from top to bottom
1118
- temp=getBinaryFromAddress(0x00);
1119
- var temp2=getBinaryFromAddress(0x01);
1227
+ temp=get(0x00);
1228
+ var temp2=get(0x01);
1120
1229
  thisMii.info.birthMonth=parseInt(temp.slice(2,6),2);
1121
1230
  thisMii.info.birthday=parseInt(temp.slice(6,8)+temp2.slice(0,3),2);
1122
1231
  thisMii.info.favColor=favCols[parseInt(temp2.slice(3,7),2)];//0-11, refer to cols array
1123
1232
  thisMii.info.favorited=temp2[7]==="0"?false:true;
1124
- thisMii.info.height=parseInt(getBinaryFromAddress(0x16),2);//0-127
1125
- thisMii.info.weight=parseInt(getBinaryFromAddress(0x17),2);//0-127
1126
- thisMii.info.downloadedFromCheckMiiOut=getBinaryFromAddress(0x21)[7]==="0"?false:true;
1127
- temp=getBinaryFromAddress(0x34);
1128
- temp2=getBinaryFromAddress(0x35);
1233
+ thisMii.info.height=parseInt(get(0x16),2);//0-127
1234
+ thisMii.info.weight=parseInt(get(0x17),2);//0-127
1235
+ thisMii.info.downloadedFromCheckMiiOut=get(0x21)[7]==="0"?false:true;
1236
+ temp=get(0x34);
1237
+ temp2=get(0x35);
1129
1238
  thisMii.mole.on=temp[0]==="0"?false:true;//0 for Off, 1 for On
1130
1239
  thisMii.mole.size=parseInt(temp.slice(1,5),2);//0-8, default 4
1131
1240
  thisMii.mole.xPos=parseInt(temp2.slice(2,7),2);//0-16, Default 2
1132
1241
  thisMii.mole.yPos=parseInt(temp.slice(5,8)+temp2.slice(0,2),2);//Top to bottom
1133
- temp=getBinaryFromAddress(0x22);
1134
- temp2=getBinaryFromAddress(0x23);
1242
+ temp=get(0x22);
1243
+ temp2=get(0x23);
1135
1244
  thisMii.hair.type=hairTable[""+parseInt(temp.slice(0,7),2)];//0-71, Needs lookup table
1136
1245
  thisMii.hair.col=hairCols[parseInt(temp[7]+temp2.slice(0,2),2)];//0-7, refer to hairCols array
1137
1246
  thisMii.hair.flipped=temp2[2]==="0"?false:true;
1138
- temp=getBinaryFromAddress(0x24);
1139
- temp2=getBinaryFromAddress(0x25);
1247
+ temp=get(0x24);
1248
+ temp2=get(0x25);
1140
1249
  thisMii.eyebrows.type=eyebrowTable[""+parseInt(temp.slice(0,5),2)];//0-23, Needs lookup table
1141
1250
  thisMii.eyebrows.rotation=parseInt(temp.slice(6,8)+temp2.slice(0,2),2);//0-11, default varies based on eyebrow type
1142
- temp=getBinaryFromAddress(0x26);
1143
- temp2=getBinaryFromAddress(0x27);
1251
+ temp=get(0x26);
1252
+ temp2=get(0x27);
1144
1253
  thisMii.eyebrows.col=hairCols[parseInt(temp.slice(0,3),2)];
1145
1254
  thisMii.eyebrows.size=parseInt(temp.slice(3,7),2);//0-8, default 4
1146
1255
  thisMii.eyebrows.yPos=(parseInt(temp[7]+temp2.slice(0,4),2))-3;//0-15, default 10
1147
1256
  thisMii.eyebrows.distApart=parseInt(temp2.slice(4,8),2);//0-12, default 2
1148
- thisMii.eyes.type=eyeTable[parseInt(getBinaryFromAddress(0x28).slice(0,6),2)];//0-47, needs lookup table
1149
- temp=getBinaryFromAddress(0x29);
1257
+ thisMii.eyes.type=eyeTable[parseInt(get(0x28).slice(0,6),2)];//0-47, needs lookup table
1258
+ temp=get(0x29);
1150
1259
  thisMii.eyes.rotation=parseInt(temp.slice(0,3),2);//0-7, default varies based on eye type
1151
1260
  thisMii.eyes.yPos=parseInt(temp.slice(3,8),2);//0-18, default 12, top to bottom
1152
- temp=getBinaryFromAddress(0x2A);
1261
+ temp=get(0x2A);
1153
1262
  thisMii.eyes.col=eyeCols[parseInt(temp.slice(0,3),2)];//0-5
1154
1263
  thisMii.eyes.size=parseInt(temp.slice(4,7),2);//0-7, default 4
1155
- temp2=getBinaryFromAddress(0x2B);
1264
+ temp2=get(0x2B);
1156
1265
  thisMii.eyes.distApart=parseInt(temp[7]+temp2.slice(0,3),2);//0-12, default 2
1157
- temp=getBinaryFromAddress(0x30);
1266
+ temp=get(0x30);
1158
1267
  thisMii.glasses.type=parseInt(temp.slice(0,4),2);//0-8
1159
1268
  thisMii.glasses.col=wiiGlassesCols[parseInt(temp.slice(4,7),2)];//0-5
1160
- temp=getBinaryFromAddress(0x31);
1269
+ temp=get(0x31);
1161
1270
  thisMii.glasses.size=parseInt(temp.slice(0,3),2);//0-7, default 4
1162
1271
  thisMii.glasses.yPos=parseInt(temp.slice(3,8),2);//0-20, default 10
1163
- temp=getBinaryFromAddress(0x32);
1164
- temp2=getBinaryFromAddress(0x33);
1272
+ temp=get(0x32);
1273
+ temp2=get(0x33);
1165
1274
  thisMii.facialHair.mustacheType=parseInt(temp.slice(0,2),2);//0-3
1166
1275
  thisMii.facialHair.beardType=parseInt(temp.slice(2,4),2);//0-3
1167
1276
  thisMii.facialHair.col=hairCols[parseInt(temp.slice(4,7),2)];//0-7
1168
1277
  thisMii.facialHair.mustacheSize=parseInt(temp[7]+temp2.slice(0,3),2);//0-30, default 20
1169
1278
  thisMii.facialHair.mustacheYPos=parseInt(temp2.slice(3,8),2);//0-16, default 2
1279
+ thisMii.console="wii";
1170
1280
  return thisMii;
1171
1281
  },
1172
1282
  read3DSQR:async function(binOrPath){
1173
- function readMii(){
1283
+ function readMii(data){
1174
1284
  var miiJson={
1175
1285
  info:{},
1176
1286
  perms:{},
@@ -1184,100 +1294,100 @@ module.exports={
1184
1294
  glasses:{},
1185
1295
  mole:{}
1186
1296
  };
1187
- binary=fs.readFileSync("./decryptedTemp.3dMii");
1188
- var temp=getBinaryFromAddress(0x18);
1189
- var temp2=getBinaryFromAddress(0x19);
1297
+ const get = address => getBinaryFromAddress(address, data);
1298
+ var temp=get(0x18);
1299
+ var temp2=get(0x19);
1190
1300
  miiJson.info.birthday=parseInt(temp2.slice(6,8)+temp.slice(0,3),2);
1191
1301
  miiJson.info.birthMonth=parseInt(temp.slice(3,7),2);
1192
1302
  var name="";
1193
1303
  for(var i=0x1A;i<0x2E;i+=2){
1194
- if(getBinaryFromAddress(i)==="00000000"){
1304
+ if(get(i)==="00000000"){
1195
1305
  break;
1196
1306
  }
1197
- name+=binary.slice(i,i+1);
1307
+ name+=data.slice(i,i+1);
1198
1308
  }
1199
1309
  miiJson.name=name.replaceAll("\x00","");
1200
1310
  var cname="";
1201
1311
  for(var i=0x48;i<0x5C;i+=2){
1202
- if(getBinaryFromAddress(i)==="00000000"){
1312
+ if(get(i)==="00000000"){
1203
1313
  break;
1204
1314
  }
1205
- cname+=binary.slice(i,i+1);
1315
+ cname+=data.slice(i,i+1);
1206
1316
  }
1207
1317
  miiJson.creatorName=cname.replaceAll("\x00","");
1208
1318
  miiJson.info.name=miiJson.name;
1209
1319
  miiJson.info.creatorName=miiJson.creatorName;
1210
- miiJson.info.height=parseInt(getBinaryFromAddress(0x2E),2);
1211
- miiJson.info.weight=parseInt(getBinaryFromAddress(0x2F),2);
1320
+ miiJson.info.height=parseInt(get(0x2E),2);
1321
+ miiJson.info.weight=parseInt(get(0x2F),2);
1212
1322
  miiJson.info.gender=temp[7]==="1"?"Female":"Male";
1213
- temp=getBinaryFromAddress(0x30);
1323
+ temp=get(0x30);
1214
1324
  miiJson.perms.sharing=temp[7]==="1"?false:true;
1215
1325
  miiJson.info.favColor=favCols[parseInt(temp2.slice(2,6),2)];
1216
- miiJson.perms.copying=getBinaryFromAddress(0x01)[7]==="1"?true:false;
1217
- miiJson.hair.style=lookupTable("hairs",parseInt(getBinaryFromAddress(0x32),2),true);
1326
+ miiJson.perms.copying=get(0x01)[7]==="1"?true:false;
1327
+ miiJson.hair.style=lookupTable("hairs",parseInt(get(0x32),2),true);
1218
1328
  miiJson.face.shape=lookupTable("faces",parseInt(temp.slice(3,7),2),false);
1219
1329
  miiJson.face.col=skinCols[parseInt(temp.slice(0,3),2)];
1220
- temp=getBinaryFromAddress(0x31);
1330
+ temp=get(0x31);
1221
1331
  miiJson.face.feature=faceFeatures3DS[parseInt(temp.slice(4,8),2)];
1222
1332
  miiJson.face.makeup=makeups3DS[parseInt(temp.slice(0,4),2)];
1223
- temp=getBinaryFromAddress(0x34);
1333
+ temp=get(0x34);
1224
1334
  miiJson.eyes.type=lookupTable("eyes",parseInt(temp.slice(2,8),2),true);
1225
- temp2=getBinaryFromAddress(0x33);
1335
+ temp2=get(0x33);
1226
1336
  miiJson.hair.col=hairCols[parseInt(temp2.slice(5,8),2)];
1227
1337
  miiJson.hair.flipped=temp2[4]==="0"?false:true;
1228
- miiJson.eyes.col=eyeCols[parseInt(getBinaryFromAddress(0x35)[7]+temp.slice(0,2),2)];
1229
- temp=getBinaryFromAddress(0x35);
1338
+ miiJson.eyes.col=eyeCols[parseInt(get(0x35)[7]+temp.slice(0,2),2)];
1339
+ temp=get(0x35);
1230
1340
  miiJson.eyes.size=parseInt(temp.slice(3,7),2);
1231
1341
  miiJson.eyes.squash=parseInt(temp.slice(0,3),2);
1232
- temp=getBinaryFromAddress(0x36);
1233
- temp2=getBinaryFromAddress(0x37);
1342
+ temp=get(0x36);
1343
+ temp2=get(0x37);
1234
1344
  miiJson.eyes.rot=parseInt(temp.slice(3,8),2);
1235
1345
  miiJson.eyes.distApart=parseInt(temp2[7]+temp.slice(0,3),2);
1236
1346
  miiJson.eyes.yPos=parseInt(temp2.slice(2,7),2);
1237
- temp=getBinaryFromAddress(0x38);
1347
+ temp=get(0x38);
1238
1348
  miiJson.eyebrows.style=lookupTable("eyebrows",parseInt(temp.slice(3,8),2),true);
1239
1349
  miiJson.eyebrows.col=hairCols[parseInt(temp.slice(0,3),2)];
1240
- temp=getBinaryFromAddress(0x39);
1350
+ temp=get(0x39);
1241
1351
  miiJson.eyebrows.size=parseInt(temp.slice(4,8),2);
1242
1352
  miiJson.eyebrows.squash=parseInt(temp.slice(1,4),2);
1243
- temp=getBinaryFromAddress(0x3A);
1353
+ temp=get(0x3A);
1244
1354
  miiJson.eyebrows.rot=parseInt(temp.slice(4,8),2);
1245
- temp2=getBinaryFromAddress(0x3B);
1355
+ temp2=get(0x3B);
1246
1356
  miiJson.eyebrows.distApart=parseInt(temp2[7]+temp.slice(0,3),2);
1247
1357
  miiJson.eyebrows.yPos=parseInt(temp2.slice(2,7),2)-3;
1248
- temp=getBinaryFromAddress(0x3C);
1358
+ temp=get(0x3C);
1249
1359
  miiJson.nose.type=lookupTable("noses",parseInt(temp.slice(3,8),2),true);
1250
- temp2=getBinaryFromAddress(0x3D);
1360
+ temp2=get(0x3D);
1251
1361
  miiJson.nose.size=parseInt(temp2[7]+temp.slice(0,3),2);
1252
1362
  miiJson.nose.yPos=parseInt(temp2.slice(2,7),2);
1253
- temp=getBinaryFromAddress(0x3E);
1363
+ temp=get(0x3E);
1254
1364
  miiJson.mouth.type=lookupTable("mouths",parseInt(temp.slice(2,8),2),true);
1255
- temp2=getBinaryFromAddress(0x3F);
1365
+ temp2=get(0x3F);
1256
1366
  miiJson.mouth.col=mouthCols3DS[parseInt(temp2[7]+temp.slice(0,2),2)];
1257
1367
  miiJson.mouth.size=parseInt(temp2.slice(3,7),2);
1258
1368
  miiJson.mouth.squash=parseInt(temp2.slice(0,3),2);
1259
- temp=getBinaryFromAddress(0x40);
1369
+ temp=get(0x40);
1260
1370
  miiJson.mouth.yPos=parseInt(temp.slice(3,8),2);
1261
1371
  miiJson.facialHair.mustacheType=parseInt(temp.slice(0,3),2);
1262
- temp=getBinaryFromAddress(0x42);
1372
+ temp=get(0x42);
1263
1373
  miiJson.facialHair.beardType=parseInt(temp.slice(5,8),2);
1264
1374
  miiJson.facialHair.col=hairCols[parseInt(temp.slice(2,5),2)];
1265
- temp2=getBinaryFromAddress(0x43);
1375
+ temp2=get(0x43);
1266
1376
  miiJson.facialHair.mustacheSize=parseInt(temp2.slice(6,8)+temp.slice(0,2),2);
1267
1377
  miiJson.facialHair.mustacheYPos=parseInt(temp2.slice(1,6),2);
1268
- temp=getBinaryFromAddress(0x44);
1378
+ temp=get(0x44);
1269
1379
  miiJson.glasses.type=parseInt(temp.slice(4,8),2);
1270
1380
  miiJson.glasses.col=glassesCols3DS[parseInt(temp.slice(1,4),2)];
1271
- temp2=getBinaryFromAddress(0x45);
1381
+ temp2=get(0x45);
1272
1382
  miiJson.glasses.size=parseInt(temp2.slice(5,8)+temp[0],2);
1273
1383
  miiJson.glasses.yPos=parseInt(temp2.slice(0,5),2);
1274
- temp=getBinaryFromAddress(0x46);
1384
+ temp=get(0x46);
1275
1385
  miiJson.mole.on=temp[7]==="0"?false:true;
1276
1386
  miiJson.mole.size=parseInt(temp.slice(3,7),2);
1277
- temp2=getBinaryFromAddress(0x47);
1387
+ temp2=get(0x47);
1278
1388
  miiJson.mole.xPos=parseInt(temp2.slice(6,8)+temp.slice(0,3),2);
1279
1389
  miiJson.mole.yPos=parseInt(temp2.slice(1,6),2);
1280
- fs.unlinkSync("./decryptedTemp.3dMii");
1390
+ miiJson.console="3ds";
1281
1391
  return miiJson;
1282
1392
  }
1283
1393
  let qrCode;
@@ -1299,13 +1409,15 @@ module.exports={
1299
1409
  }
1300
1410
  if (qrCode) {
1301
1411
  var data = decodeAesCcm(new Uint8Array(qrCode));
1302
- fs.writeFileSync("./decryptedTemp.3dMii",Buffer.from(data));
1303
- return Promise.resolve(readMii());
1412
+ return Promise.resolve(readMii(Buffer.from(data)));
1304
1413
  } else {
1305
1414
  console.error('Failed to decode QR code');
1306
1415
  }
1307
1416
  },
1308
- writeWiiBin:function(jsonIn,outPath){
1417
+ writeWiiBin:function(jsonIn, outPath){
1418
+ if(jsonIn.console?.toLowerCase() !== "wii"){
1419
+ this.convertMii(jsonIn);
1420
+ }
1309
1421
  var mii=jsonIn;
1310
1422
  var miiBin="0";
1311
1423
  miiBin+=mii.info.gender==="Male"?"0":"1";
@@ -1414,328 +1526,282 @@ module.exports={
1414
1526
  }
1415
1527
  fs.writeFileSync(outPath, Buffer.from(buffers));
1416
1528
  },
1417
- write3DSQR:function(jsonIn,outPath){
1418
- var mii=jsonIn;
1419
- function makeMiiBinary(mii){
1420
- if(mii.perms.sharing&&mii.info.type==="Special"){
1421
- mii.perms.sharing=false;
1422
- console.log("Cannot have Sharing enabled for Special Miis. Disabled Sharing.");
1423
- }
1424
- var miiBin="00000011";
1425
- miiBin+="0000000";
1426
- miiBin+=mii.perms.copying?"1":"0";
1427
- miiBin+="00000000";
1428
- miiBin+="00110000";
1429
- miiBin+="1000101011010010000001101000011100011000110001100100011001100110010101100111111110111100000001110101110001000101011101100000001110100100010000000000000000000000".slice(0,8*8);
1430
- miiBin+=mii.info.type==="Special"?"0":"1";
1431
- miiBin+="0000000";
1432
- for(var i=0;i<3;i++){
1433
- miiBin+=Math.floor(Math.random()*255).toString(2).padStart(8,"0");
1434
- }
1435
- miiBin+="0000000001000101011101100000001110100100010000000000000000000000";
1436
- miiBin+=mii.info.birthday.toString(2).padStart(5,"0").slice(2,5);
1437
- miiBin+=mii.info.birthMonth.toString(2).padStart(4,"0");
1438
- miiBin+=mii.info.gender==="Male"?"0":"1";
1439
- miiBin+="00";
1440
- miiBin+=favCols.indexOf(mii.info.favColor).toString(2).padStart(4,"0");
1441
- miiBin+=mii.info.birthday.toString(2).padStart(5,"0").slice(0,2);
1442
- for(var i=0;i<10;i++){
1443
- if(i<mii.name.length){
1444
- miiBin+=mii.name.charCodeAt(i).toString(2).padStart(8,"0");
1445
- }
1446
- else{
1447
- miiBin+="00000000";
1529
+ write3DSQR:async function(jsonIn,outPath,fflRes=_fflRes){
1530
+ if(!["3ds","wii u"].includes(jsonIn.console?.toLowerCase())){
1531
+ jsonIn=this.convertMii(jsonIn);
1532
+ }
1533
+ return new Promise(async (resolve, reject) => {
1534
+ var mii=jsonIn;
1535
+ function makeMiiBinary(mii){
1536
+ if(mii.perms.sharing&&mii.info.type==="Special"){
1537
+ mii.perms.sharing=false;
1538
+ console.log("Cannot have Sharing enabled for Special Miis. Disabled Sharing.");
1448
1539
  }
1540
+ var miiBin="00000011";
1541
+ miiBin+="0000000";
1542
+ miiBin+=mii.perms.copying?"1":"0";
1449
1543
  miiBin+="00000000";
1450
- }
1451
- miiBin+=mii.info.height.toString(2).padStart(8,"0");
1452
- miiBin+=mii.info.weight.toString(2).padStart(8,"0");
1453
- miiBin+=skinCols.indexOf(mii.face.col).toString(2).padStart(3,"0");
1454
- miiBin+=tables.faces[mii.face.shape].toString(2).padStart(4,"0");
1455
- miiBin+=mii.perms.sharing?"0":"1";
1456
- miiBin+=makeups3DS.indexOf(mii.face.makeup).toString(2).padStart(4,"0");
1457
- miiBin+=faceFeatures3DS.indexOf(mii.face.feature).toString(2).padStart(4,"0");
1458
- miiBin+=tables.hairs[mii.hair.style[0]][mii.hair.style[1]].toString(2).padStart(8,"0");
1459
- miiBin+="0000";
1460
- miiBin+=mii.hair.flipped?"1":"0";
1461
- miiBin+=hairCols.indexOf(mii.hair.col).toString(2).padStart(3,"0");
1462
- miiBin+=eyeCols.indexOf(mii.eyes.col).toString(2).padStart(3,"0").slice(1,3);
1463
- miiBin+=tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]].toString(2).padStart(6,"0");
1464
- miiBin+=mii.eyes.squash.toString(2).padStart(3,"0");
1465
- miiBin+=mii.eyes.size.toString(2).padStart(4,"0");
1466
- miiBin+=eyeCols.indexOf(mii.eyes.col).toString(2).padStart(3,"0")[0];
1467
- miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0").slice(1,4);
1468
- miiBin+=mii.eyes.rot.toString(2).padStart(5,"0");
1469
- miiBin+="00";
1470
- miiBin+=mii.eyes.yPos.toString(2).padStart(5,"0");
1471
- miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0")[0];
1472
- miiBin+=hairCols.indexOf(mii.eyebrows.col).toString(2).padStart(3,"0");
1473
- miiBin+=tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]].toString(2).padStart(5,"0");
1474
- miiBin+="0";
1475
- miiBin+=mii.eyebrows.squash.toString(2).padStart(3,"0");
1476
- miiBin+=mii.eyebrows.size.toString(2).padStart(4,"0");
1477
- miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0").slice(1,4);
1478
- miiBin+="0";
1479
- miiBin+=mii.eyebrows.rot.toString(2).padStart(4,"0");
1480
- miiBin+="00";
1481
- miiBin+=(mii.eyebrows.yPos+3).toString(2).padStart(5,"0");
1482
- miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0")[0];
1483
- miiBin+=mii.nose.size.toString(2).padStart(4,"0").slice(1,4);
1484
- miiBin+=tables.noses[mii.nose.type[0]][mii.nose.type[1]].toString(2).padStart(5,"0");
1485
- miiBin+="00";
1486
- miiBin+=mii.nose.yPos.toString(2).padStart(5,"0");
1487
- miiBin+=mii.nose.size.toString(2).padStart(4,"0")[0];
1488
- miiBin+=mouthCols3DS.indexOf(mii.mouth.col).toString(2).padStart(3,"0").slice(1,3);
1489
- miiBin+=tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]].toString(2).padStart(6,"0");
1490
- miiBin+=mii.mouth.squash.toString(2).padStart(3,"0");
1491
- miiBin+=mii.mouth.size.toString(2).padStart(4,"0");
1492
- miiBin+=mouthCols3DS.indexOf(mii.mouth.col).toString(2).padStart(3,"0")[0];
1493
- miiBin+=mii.facialHair.mustacheType.toString(2).padStart(3,"0");
1494
- miiBin+=mii.mouth.yPos.toString(2).padStart(5,"0");
1495
- miiBin+="00000000";
1496
- miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0").slice(2,4);
1497
- miiBin+=hairCols.indexOf(mii.facialHair.col).toString(2).padStart(3,"0");
1498
- miiBin+=mii.facialHair.beardType.toString(2).padStart(3,"0");
1499
- miiBin+="0";
1500
- miiBin+=mii.facialHair.mustacheYPos.toString(2).padStart(5,"0");
1501
- miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0").slice(0,2);
1502
- miiBin+=mii.glasses.size.toString(2).padStart(4,"0")[3];
1503
- miiBin+=glassesCols3DS.indexOf(mii.glasses.col).toString(2).padStart(3,"0");
1504
- miiBin+=mii.glasses.type.toString(2).padStart(4,"0");
1505
- miiBin+="0";
1506
- miiBin+=mii.glasses.yPos.toString(2).padStart(4,"0");
1507
- miiBin+=mii.glasses.size.toString(2).padStart(4,"0").slice(0,3);
1508
- miiBin+=mii.mole.xPos.toString(2).padStart(5,"0").slice(2,5);
1509
- miiBin+=mii.mole.size.toString(2).padStart(4,"0");
1510
- miiBin+=mii.mole.on?"1":"0";
1511
- miiBin+="0";
1512
- miiBin+=mii.mole.yPos.toString(2).padStart(5,"0");
1513
- miiBin+=mii.mole.xPos.toString(2).padStart(5,"0").slice(0,2);
1514
- for(var i=0;i<10;i++){
1515
- if(i<mii.creatorName.length){
1516
- miiBin+=mii.creatorName.charCodeAt(i).toString(2).padStart(8,"0");
1544
+ miiBin+="00110000";
1545
+ miiBin+="1000101011010010000001101000011100011000110001100100011001100110010101100111111110111100000001110101110001000101011101100000001110100100010000000000000000000000".slice(0,8*8);
1546
+ miiBin+=mii.info.type==="Special"?"0":"1";
1547
+ miiBin+="0000000";
1548
+ for(var i=0;i<3;i++){
1549
+ miiBin+=Math.floor(Math.random()*255).toString(2).padStart(8,"0");
1517
1550
  }
1518
- else{
1551
+ miiBin+="0000000001000101011101100000001110100100010000000000000000000000";
1552
+ miiBin+=mii.info.birthday.toString(2).padStart(5,"0").slice(2,5);
1553
+ miiBin+=mii.info.birthMonth.toString(2).padStart(4,"0");
1554
+ miiBin+=mii.info.gender==="Male"?"0":"1";
1555
+ miiBin+="00";
1556
+ miiBin+=favCols.indexOf(mii.info.favColor).toString(2).padStart(4,"0");
1557
+ miiBin+=mii.info.birthday.toString(2).padStart(5,"0").slice(0,2);
1558
+ for(var i=0;i<10;i++){
1559
+ if(i<mii.name.length){
1560
+ miiBin+=mii.name.charCodeAt(i).toString(2).padStart(8,"0");
1561
+ }
1562
+ else{
1563
+ miiBin+="00000000";
1564
+ }
1519
1565
  miiBin+="00000000";
1520
1566
  }
1567
+ miiBin+=mii.info.height.toString(2).padStart(8,"0");
1568
+ miiBin+=mii.info.weight.toString(2).padStart(8,"0");
1569
+ miiBin+=skinCols.indexOf(mii.face.col).toString(2).padStart(3,"0");
1570
+ miiBin+=tables.faces[mii.face.shape].toString(2).padStart(4,"0");
1571
+ miiBin+=mii.perms.sharing?"0":"1";
1572
+ miiBin+=makeups3DS.indexOf(mii.face.makeup).toString(2).padStart(4,"0");
1573
+ miiBin+=faceFeatures3DS.indexOf(mii.face.feature).toString(2).padStart(4,"0");
1574
+ miiBin+=tables.hairs[mii.hair.style[0]][mii.hair.style[1]].toString(2).padStart(8,"0");
1575
+ miiBin+="0000";
1576
+ miiBin+=mii.hair.flipped?"1":"0";
1577
+ miiBin+=hairCols.indexOf(mii.hair.col).toString(2).padStart(3,"0");
1578
+ miiBin+=eyeCols.indexOf(mii.eyes.col).toString(2).padStart(3,"0").slice(1,3);
1579
+ miiBin+=tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]].toString(2).padStart(6,"0");
1580
+ miiBin+=mii.eyes.squash.toString(2).padStart(3,"0");
1581
+ miiBin+=mii.eyes.size.toString(2).padStart(4,"0");
1582
+ miiBin+=eyeCols.indexOf(mii.eyes.col).toString(2).padStart(3,"0")[0];
1583
+ miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0").slice(1,4);
1584
+ miiBin+=mii.eyes.rot.toString(2).padStart(5,"0");
1585
+ miiBin+="00";
1586
+ miiBin+=mii.eyes.yPos.toString(2).padStart(5,"0");
1587
+ miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0")[0];
1588
+ miiBin+=hairCols.indexOf(mii.eyebrows.col).toString(2).padStart(3,"0");
1589
+ miiBin+=tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]].toString(2).padStart(5,"0");
1590
+ miiBin+="0";
1591
+ miiBin+=mii.eyebrows.squash.toString(2).padStart(3,"0");
1592
+ miiBin+=mii.eyebrows.size.toString(2).padStart(4,"0");
1593
+ miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0").slice(1,4);
1594
+ miiBin+="0";
1595
+ miiBin+=mii.eyebrows.rot.toString(2).padStart(4,"0");
1596
+ miiBin+="00";
1597
+ miiBin+=(mii.eyebrows.yPos+3).toString(2).padStart(5,"0");
1598
+ miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0")[0];
1599
+ miiBin+=mii.nose.size.toString(2).padStart(4,"0").slice(1,4);
1600
+ miiBin+=tables.noses[mii.nose.type[0]][mii.nose.type[1]].toString(2).padStart(5,"0");
1601
+ miiBin+="00";
1602
+ miiBin+=mii.nose.yPos.toString(2).padStart(5,"0");
1603
+ miiBin+=mii.nose.size.toString(2).padStart(4,"0")[0];
1604
+ miiBin+=mouthCols3DS.indexOf(mii.mouth.col).toString(2).padStart(3,"0").slice(1,3);
1605
+ miiBin+=tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]].toString(2).padStart(6,"0");
1606
+ miiBin+=mii.mouth.squash.toString(2).padStart(3,"0");
1607
+ miiBin+=mii.mouth.size.toString(2).padStart(4,"0");
1608
+ miiBin+=mouthCols3DS.indexOf(mii.mouth.col).toString(2).padStart(3,"0")[0];
1609
+ miiBin+=mii.facialHair.mustacheType.toString(2).padStart(3,"0");
1610
+ miiBin+=mii.mouth.yPos.toString(2).padStart(5,"0");
1521
1611
  miiBin+="00000000";
1612
+ miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0").slice(2,4);
1613
+ miiBin+=hairCols.indexOf(mii.facialHair.col).toString(2).padStart(3,"0");
1614
+ miiBin+=mii.facialHair.beardType.toString(2).padStart(3,"0");
1615
+ miiBin+="0";
1616
+ miiBin+=mii.facialHair.mustacheYPos.toString(2).padStart(5,"0");
1617
+ miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0").slice(0,2);
1618
+ miiBin+=mii.glasses.size.toString(2).padStart(4,"0")[3];
1619
+ miiBin+=glassesCols3DS.indexOf(mii.glasses.col).toString(2).padStart(3,"0");
1620
+ miiBin+=mii.glasses.type.toString(2).padStart(4,"0");
1621
+ miiBin+="0";
1622
+ miiBin+=mii.glasses.yPos.toString(2).padStart(4,"0");
1623
+ miiBin+=mii.glasses.size.toString(2).padStart(4,"0").slice(0,3);
1624
+ miiBin+=mii.mole.xPos.toString(2).padStart(5,"0").slice(2,5);
1625
+ miiBin+=mii.mole.size.toString(2).padStart(4,"0");
1626
+ miiBin+=mii.mole.on?"1":"0";
1627
+ miiBin+="0";
1628
+ miiBin+=mii.mole.yPos.toString(2).padStart(5,"0");
1629
+ miiBin+=mii.mole.xPos.toString(2).padStart(5,"0").slice(0,2);
1630
+ for(var i=0;i<10;i++){
1631
+ if(i<mii.creatorName.length){
1632
+ miiBin+=mii.creatorName.charCodeAt(i).toString(2).padStart(8,"0");
1633
+ }
1634
+ else{
1635
+ miiBin+="00000000";
1636
+ }
1637
+ miiBin+="00000000";
1638
+ }
1639
+ //Writing based on miiBin
1640
+ var toWrite=miiBin.match(/.{1,8}/g);
1641
+ var buffers=[];
1642
+ for(var i=0;i<toWrite.length;i++){
1643
+ buffers.push(parseInt(toWrite[i],2));
1644
+ }
1645
+ const buffer = Buffer.from(buffers);
1646
+ return buffer;
1522
1647
  }
1523
- //Writing based on miiBin
1524
- var toWrite=miiBin.match(/.{1,8}/g);
1525
- var buffers=[];
1526
- for(var i=0;i<toWrite.length;i++){
1527
- buffers.push(parseInt(toWrite[i],2));
1648
+ const miiBinary = makeMiiBinary(mii);
1649
+ var encryptedData = Buffer.from(encodeAesCcm(new Uint8Array(miiBinary)));
1650
+
1651
+ const options = {
1652
+ width: 300,
1653
+ height: 300,
1654
+ data: encryptedData.toString("latin1"),
1655
+ image: "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", // 1x1 gif
1656
+ dotsOptions: {
1657
+ color: "#000000",
1658
+ type: "square"
1659
+ },
1660
+ backgroundOptions: {
1661
+ color: "#ffffff",
1662
+ },
1663
+ imageOptions: {
1664
+ crossOrigin: "anonymous",
1665
+ imageSize: 0.4 // Changes how large center area is
1666
+ }
1528
1667
  }
1529
- const buffer = Buffer.from(buffers);
1530
- fs.writeFileSync(outPath, buffer);
1531
- }
1532
- makeMiiBinary(mii);
1533
- var encryptedData = Buffer.from(encodeAesCcm(new Uint8Array(fs.readFileSync(outPath))));
1534
- fs.writeFileSync(outPath,encryptedData);
1535
- QRCode.toFile('./'+mii.name+'Output.png', [{ data: fs.readFileSync(outPath), mode: 'byte' }], {type: 'png'}, function (err) {
1536
- if (err) throw err;
1537
- });
1538
- var studioMii=new Uint8Array([0x08, 0x00, 0x40, 0x03, 0x08, 0x04, 0x04, 0x02, 0x02, 0x0c, 0x03, 0x01, 0x06, 0x04, 0x06, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x21, 0x40, 0x04, 0x00, 0x02, 0x14, 0x03, 0x13, 0x04, 0x17, 0x0d, 0x04, 0x00, 0x0a, 0x04, 0x01, 0x09]);
1539
- //miiPreview.src = 'https://studio.mii.nintendo.com/miis/image.png?data=' + mii.previewData + "&width=270&type=face";
1540
- function encodeStudio(studio) {
1541
- function byteToString(int){
1542
- var str = int.toString(16);
1543
- if(str.length < 2)str = '0' + str;
1544
- return str;
1668
+ const qrCodeImage = new QRCodeStyling({
1669
+ jsdom: JSDOM,
1670
+ nodeCanvas,
1671
+ ...options
1672
+ });
1673
+ const qrBuffer = Buffer.from( await qrCodeImage.getRawData("png") )
1674
+
1675
+ var studioMii=new Uint8Array([0x08, 0x00, 0x40, 0x03, 0x08, 0x04, 0x04, 0x02, 0x02, 0x0c, 0x03, 0x01, 0x06, 0x04, 0x06, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x21, 0x40, 0x04, 0x00, 0x02, 0x14, 0x03, 0x13, 0x04, 0x17, 0x0d, 0x04, 0x00, 0x0a, 0x04, 0x01, 0x09]);
1676
+ studioMii[0x16] = mii.info.gender==="Male"?0:1;
1677
+ studioMii[0x15] = favCols.indexOf(mii.info.favColor);
1678
+ studioMii[0x1E] = mii.info.height;
1679
+ studioMii[2] = mii.info.weight;
1680
+ studioMii[0x13] = tables.faces[mii.face.shape];
1681
+ studioMii[0x11] = skinCols.indexOf(mii.face.col);
1682
+ studioMii[0x14] = faceFeatures3DS.indexOf(mii.face.feature);
1683
+ studioMii[0x12] = makeups3DS.indexOf(mii.face.makeup);
1684
+ studioMii[0x1D] = tables.hairs[mii.hair.style[0]][mii.hair.style[1]];
1685
+ studioMii[0x1B] = hairCols.indexOf(mii.hair.col);
1686
+ if (!studioMii[0x1B]) studioMii[0x1B] = 8;
1687
+ studioMii[0x1C] = mii.hair.flipped?1:0;
1688
+ studioMii[7] = tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]];
1689
+ studioMii[4] = eyeCols.indexOf(mii.eyes.col) + 8;
1690
+ studioMii[6] = mii.eyes.size;
1691
+ studioMii[3] = mii.eyes.squash;
1692
+ studioMii[5] = mii.eyes.rot;
1693
+ studioMii[8] = mii.eyes.distApart;
1694
+ studioMii[9] = mii.eyes.yPos;
1695
+ studioMii[0xE] = tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]];
1696
+ studioMii[0xB] = hairCols.indexOf(mii.eyebrows.col);
1697
+ if (!studioMii[0xB]) studioMii[0xB] = 8;
1698
+ studioMii[0xD] = mii.eyebrows.size;
1699
+ studioMii[0xA] = mii.eyebrows.squash;
1700
+ studioMii[0xC] = mii.eyebrows.rot;
1701
+ studioMii[0xF] = mii.eyebrows.distApart;
1702
+ studioMii[0x10] = mii.eyebrows.yPos+3;
1703
+ studioMii[0x2C] = tables.noses[mii.nose.type[0]][mii.nose.type[1]];
1704
+ studioMii[0x2B] = mii.nose.size;
1705
+ studioMii[0x2D] = mii.nose.yPos;
1706
+ studioMii[0x26] = tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]];
1707
+ studioMii[0x24] = mouthCols3DS.indexOf(mii.mouth.col);
1708
+ if (studioMii[0x24] < 4) {
1709
+ studioMii[0x24] += 19;
1710
+ } else {
1711
+ studioMii[0x24] = 0;
1545
1712
  }
1546
- var n = 0;
1547
- var eo;
1548
- var dest = byteToString(n);
1549
- for (var i = 0; i < studio.length; i++) {
1550
- eo = (7 + (studio[i] ^ n)) & 0xFF;
1551
- n = eo;
1552
- dest += byteToString(eo);
1713
+ studioMii[0x25] = mii.mouth.size;
1714
+ studioMii[0x23] = mii.mouth.squash;
1715
+ studioMii[0x27] = mii.mouth.yPos;
1716
+ studioMii[0x29] = mii.facialHair.mustacheType;
1717
+ studioMii[1] = mii.facialHair.beardType;
1718
+ studioMii[0] = hairCols.indexOf(mii.facialHair.col);
1719
+ if (!studioMii[0]) studioMii[0] = 8;
1720
+ studioMii[0x28] = mii.facialHair.mustacheSize;
1721
+ studioMii[0x2A] = mii.facialHair.mustacheYPos;
1722
+ studioMii[0x19] = mii.glasses.type;
1723
+ studioMii[0x17] = mii.glasses.col;
1724
+ if (!studioMii[0x17]) {
1725
+ studioMii[0x17] = 8;
1726
+ } else if (studioMii[0x17] < 6) {
1727
+ studioMii[0x17] += 13;
1728
+ } else {
1729
+ studioMii[0x17] = 0;
1553
1730
  }
1554
- return dest;
1555
- }
1556
- studioMii[0x16] = mii.info.gender==="Male"?0:1;
1557
- studioMii[0x15] = favCols.indexOf(mii.info.favColor);
1558
- studioMii[0x1E] = mii.info.height;
1559
- studioMii[2] = mii.info.weight;
1560
- studioMii[0x13] = tables.faces[mii.face.shape];
1561
- studioMii[0x11] = skinCols.indexOf(mii.face.col);
1562
- studioMii[0x14] = faceFeatures3DS.indexOf(mii.face.feature);
1563
- studioMii[0x12] = makeups3DS.indexOf(mii.face.makeup);
1564
- studioMii[0x1D] = tables.hairs[mii.hair.style[0]][mii.hair.style[1]];
1565
- studioMii[0x1B] = hairCols.indexOf(mii.hair.col);
1566
- if (!studioMii[0x1B]) studioMii[0x1B] = 8;
1567
- studioMii[0x1C] = mii.hair.flipped?1:0;
1568
- studioMii[7] = tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]];
1569
- studioMii[4] = eyeCols.indexOf(mii.eyes.col) + 8;
1570
- studioMii[6] = mii.eyes.size;
1571
- studioMii[3] = mii.eyes.squash;
1572
- studioMii[5] = mii.eyes.rot;
1573
- studioMii[8] = mii.eyes.distApart;
1574
- studioMii[9] = mii.eyes.yPos;
1575
- studioMii[0xE] = tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]];
1576
- studioMii[0xB] = hairCols.indexOf(mii.eyebrows.col);
1577
- if (!studioMii[0xB]) studioMii[0xB] = 8;
1578
- studioMii[0xD] = mii.eyebrows.size;
1579
- studioMii[0xA] = mii.eyebrows.squash;
1580
- studioMii[0xC] = mii.eyebrows.rot;
1581
- studioMii[0xF] = mii.eyebrows.distApart;
1582
- studioMii[0x10] = mii.eyebrows.yPos+3;
1583
- studioMii[0x2C] = tables.noses[mii.nose.type[0]][mii.nose.type[1]];
1584
- studioMii[0x2B] = mii.nose.size;
1585
- studioMii[0x2D] = mii.nose.yPos;
1586
- studioMii[0x26] = tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]];
1587
- studioMii[0x24] = mouthCols3DS.indexOf(mii.mouth.col);
1588
- if (studioMii[0x24] < 4) {
1589
- studioMii[0x24] += 19;
1590
- } else {
1591
- studioMii[0x24] = 0;
1592
- }
1593
- studioMii[0x25] = mii.mouth.size;
1594
- studioMii[0x23] = mii.mouth.squash;
1595
- studioMii[0x27] = mii.mouth.yPos;
1596
- studioMii[0x29] = mii.facialHair.mustacheType;
1597
- studioMii[1] = mii.facialHair.beardType;
1598
- studioMii[0] = hairCols.indexOf(mii.facialHair.col);
1599
- if (!studioMii[0]) studioMii[0] = 8;
1600
- studioMii[0x28] = mii.facialHair.mustacheSize;
1601
- studioMii[0x2A] = mii.facialHair.mustacheYPos;
1602
- studioMii[0x19] = mii.glasses.type;
1603
- studioMii[0x17] = mii.glasses.col;
1604
- if (!studioMii[0x17]) {
1605
- studioMii[0x17] = 8;
1606
- } else if (studioMii[0x17] < 6) {
1607
- studioMii[0x17] += 13;
1608
- } else {
1609
- studioMii[0x17] = 0;
1610
- }
1611
- studioMii[0x18] = mii.glasses.size;
1612
- studioMii[0x1A] = mii.glasses.yPos;
1613
- studioMii[0x20] = mii.mole.on?1:0;
1614
- studioMii[0x1F] = mii.mole.size;
1615
- studioMii[0x21] = mii.mole.xPos;
1616
- studioMii[0x22] = mii.mole.yPos;
1617
- downloadImage('https://studio.mii.nintendo.com/miis/image.png?data=' + encodeStudio(studioMii) + "&width=270&type=face","./temp.png").then(d=>{
1618
- Jimp.read(mii.name+'Output.png', (err, fir_img) => {
1619
- if(err) {
1620
- console.log(err);
1621
- } else {
1622
- Jimp.read('temp.png', (err, sec_img) => {
1623
- if(err) {
1624
- console.log(err);
1625
- } else {
1626
- fir_img.resize(424, 424);
1627
- sec_img.resize(130,130);
1628
- const canvas = new Jimp(sec_img.bitmap.width, sec_img.bitmap.height, 0xFFFFFFFF);
1629
- canvas.composite(sec_img, 0, 0);
1630
- fir_img.blit(canvas, 212-130/2,212-130/2);
1631
- Jimp.loadFont(Jimp.FONT_SANS_16_BLACK).then(font => {
1632
- fir_img.print(font, 0, 50, {
1633
- text: mii.name,
1634
- alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
1635
- alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
1636
- }, 424, 424);
1637
- Jimp.read('./node_modules/miijs/crown.jpg',(err,thi_img)=>{
1638
- thi_img.resize(40,20);
1639
- if(mii.info.type==="Special") fir_img.blit(thi_img,232,150);
1640
- fir_img.write(outPath);
1641
- fs.unlinkSync("./temp.png");
1642
- });
1643
- });
1644
- }
1645
- })
1646
- }
1647
- fs.unlinkSync(mii.name+"Output.png");
1648
- });
1649
- });
1650
- },
1651
- render3DSMiiFromJSON:function(jsonIn,outPath){
1652
- var mii=jsonIn;
1653
- var studioMii=new Uint8Array([0x08, 0x00, 0x40, 0x03, 0x08, 0x04, 0x04, 0x02, 0x02, 0x0c, 0x03, 0x01, 0x06, 0x04, 0x06, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x21, 0x40, 0x04, 0x00, 0x02, 0x14, 0x03, 0x13, 0x04, 0x17, 0x0d, 0x04, 0x00, 0x0a, 0x04, 0x01, 0x09]);
1654
- //miiPreview.src = 'https://studio.mii.nintendo.com/miis/image.png?data=' + mii.previewData + "&width=270&type=face";
1655
- function encodeStudio(studio) {
1656
- function byteToString(int){
1657
- var str = int.toString(16);
1658
- if(str.length < 2)str = '0' + str;
1659
- return str;
1731
+ studioMii[0x18] = mii.glasses.size;
1732
+ studioMii[0x1A] = mii.glasses.yPos;
1733
+ studioMii[0x20] = mii.mole.on?1:0;
1734
+ studioMii[0x1F] = mii.mole.size;
1735
+ studioMii[0x21] = mii.mole.xPos;
1736
+ studioMii[0x22] = mii.mole.yPos;
1737
+ let miiPNGBuf = null;
1738
+ let renderedWithStudio = fflRes===null || fflRes===undefined;
1739
+ if(renderedWithStudio){
1740
+ miiPNGBuf = await this.render3DSMiiWithStudio(jsonIn);
1660
1741
  }
1661
- var n = 0;
1662
- var eo;
1663
- var dest = byteToString(n);
1664
- for (var i = 0; i < studio.length; i++) {
1665
- eo = (7 + (studio[i] ^ n)) & 0xFF;
1666
- n = eo;
1667
- dest += byteToString(eo);
1742
+ else{
1743
+ miiPNGBuf = await this.render3DSMii(jsonIn,fflRes);
1668
1744
  }
1669
- return dest;
1670
- }
1671
- studioMii[0x16] = mii.info.gender==="Male"?0:1;
1672
- studioMii[0x15] = favCols.indexOf(mii.info.favColor);
1673
- studioMii[0x1E] = mii.info.height;
1674
- studioMii[2] = mii.info.weight;
1675
- studioMii[0x13] = tables.faces[mii.face.shape];
1676
- studioMii[0x11] = skinCols.indexOf(mii.face.col);
1677
- studioMii[0x14] = faceFeatures3DS.indexOf(mii.face.feature);
1678
- studioMii[0x12] = makeups3DS.indexOf(mii.face.makeup);
1679
- studioMii[0x1D] = tables.hairs[mii.hair.style[0]][mii.hair.style[1]];
1680
- studioMii[0x1B] = hairCols.indexOf(mii.hair.col);
1681
- if (!studioMii[0x1B]) studioMii[0x1B] = 8;
1682
- studioMii[0x1C] = mii.hair.flipped?1:0;
1683
- studioMii[7] = tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]];
1684
- studioMii[4] = eyeCols.indexOf(mii.eyes.col) + 8;
1685
- studioMii[6] = mii.eyes.size;
1686
- studioMii[3] = mii.eyes.squash;
1687
- studioMii[5] = mii.eyes.rot;
1688
- studioMii[8] = mii.eyes.distApart;
1689
- studioMii[9] = mii.eyes.yPos;
1690
- studioMii[0xE] = tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]];
1691
- studioMii[0xB] = hairCols.indexOf(mii.eyebrows.col);
1692
- if (!studioMii[0xB]) studioMii[0xB] = 8;
1693
- studioMii[0xD] = mii.eyebrows.size;
1694
- studioMii[0xA] = mii.eyebrows.squash;
1695
- studioMii[0xC] = mii.eyebrows.rot;
1696
- studioMii[0xF] = mii.eyebrows.distApart;
1697
- studioMii[0x10] = mii.eyebrows.yPos+3;
1698
- studioMii[0x2C] = tables.noses[mii.nose.type[0]][mii.nose.type[1]];
1699
- studioMii[0x2B] = mii.nose.size;
1700
- studioMii[0x2D] = mii.nose.yPos;
1701
- studioMii[0x26] = tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]];
1702
- studioMii[0x24] = mouthCols3DS.indexOf(mii.mouth.col);
1703
- if (studioMii[0x24] < 4) {
1704
- studioMii[0x24] += 19;
1705
- } else {
1706
- studioMii[0x24] = 0;
1707
- }
1708
- studioMii[0x25] = mii.mouth.size;
1709
- studioMii[0x23] = mii.mouth.squash;
1710
- studioMii[0x27] = mii.mouth.yPos;
1711
- studioMii[0x29] = mii.facialHair.mustacheType;
1712
- studioMii[1] = mii.facialHair.beardType;
1713
- studioMii[0] = hairCols.indexOf(mii.facialHair.col);
1714
- if (!studioMii[0]) studioMii[0] = 8;
1715
- studioMii[0x28] = mii.facialHair.mustacheSize;
1716
- studioMii[0x2A] = mii.facialHair.mustacheYPos;
1717
- studioMii[0x19] = mii.glasses.type;
1718
- studioMii[0x17] = glassesCols3DS.indexOf(mii.glasses.col);
1719
- if (!studioMii[0x17]) {
1720
- studioMii[0x17] = 8;
1721
- } else if (studioMii[0x17] < 6) {
1722
- studioMii[0x17] += 13;
1723
- } else {
1724
- studioMii[0x17] = 0;
1745
+ const main_img = await Jimp.read(qrBuffer);
1746
+ main_img.resize(424, 424, Jimp.RESIZE_NEAREST_NEIGHBOR); // Don't anti-alias the QR code
1747
+
1748
+ let miiSize, miiZoomFactor, miiYOffset;
1749
+ if (renderedWithStudio) {
1750
+ miiSize = 100;
1751
+ miiZoomFactor = 1;
1752
+ miiYOffset = -15;
1753
+
1754
+ } else {
1755
+ miiSize = 100;
1756
+ miiZoomFactor = 1.25;
1757
+ miiYOffset = -5;
1758
+ }
1759
+ const mii_img = await Jimp.read(miiPNGBuf);
1760
+ mii_img.resize(miiSize*miiZoomFactor, miiSize*miiZoomFactor, Jimp.RESIZE_BICUBIC);
1761
+ mii_img.crop(
1762
+ (miiSize*miiZoomFactor - 100) / 2,
1763
+ (miiSize*miiZoomFactor - 100) / 2,
1764
+ miiSize,
1765
+ miiSize
1766
+ );
1767
+
1768
+ const canvas = new Jimp(mii_img.bitmap.width, mii_img.bitmap.height, 0xFFFFFFFF);
1769
+ canvas.composite(mii_img, 0, miiYOffset);
1770
+ main_img.blit(canvas, 212-100/2, 212-100/2);
1771
+ const font = await Jimp.loadFont(Jimp.FONT_SANS_16_BLACK)
1772
+
1773
+ main_img.print(font, 0, 55, {
1774
+ text: mii.name,
1775
+ alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
1776
+ alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
1777
+ }, 424, 395);
1778
+
1779
+ if(mii.info.type==="Special"){
1780
+ const crown_img = await Jimp.read(path.join(__dirname, 'crown.jpg'));
1781
+ crown_img.resize(40,20);
1782
+ main_img.blit(crown_img,225,160);
1783
+ }
1784
+
1785
+ main_img.write(outPath, (err, img) =>
1786
+ resolve(img)
1787
+ );
1788
+ })
1789
+ },
1790
+ render3DSMiiWithStudio:async function(jsonIn){
1791
+ if(!["3ds","wii u"].includes(jsonIn.console?.toLowerCase())){
1792
+ jsonIn=this.convertMii(jsonIn);
1725
1793
  }
1726
- studioMii[0x18] = mii.glasses.size;
1727
- studioMii[0x1A] = mii.glasses.yPos;
1728
- studioMii[0x20] = mii.mole.on?1:0;
1729
- studioMii[0x1F] = mii.mole.size;
1730
- studioMii[0x21] = mii.mole.xPos;
1731
- studioMii[0x22] = mii.mole.yPos;
1732
- downloadImage('https://studio.mii.nintendo.com/miis/image.png?data=' + encodeStudio(studioMii) + "&width=270&type=face",outPath);
1794
+ var studioMii=this.convert3DSMiiToStudio(jsonIn);
1795
+ return await downloadImage('https://studio.mii.nintendo.com/miis/image.png?data=' + studioMii + "&width=270&type=face");
1733
1796
  },
1734
- convertMii:function (jsonIn,typeFrom){
1735
- typeFrom=typeFrom.toLowerCase();
1797
+ convertMii:function(jsonIn){
1798
+ typeFrom=jsonIn.console?.toLowerCase();
1799
+ if(typeFrom===null||typeFrom===undefined){
1800
+ return jsonIn;
1801
+ }
1736
1802
  let mii=jsonIn;
1737
1803
  var miiTo={};
1738
- if(typeFrom==="3ds"){
1804
+ if(["wii u","3ds"].includes(typeFrom)){
1739
1805
  miiTo={
1740
1806
  info:{},
1741
1807
  face:{},
@@ -1823,6 +1889,7 @@ module.exports={
1823
1889
  if(mii.facialHair.beardType>3){
1824
1890
  mii.facialHair.beardType=3;
1825
1891
  }
1892
+ miiTo.console="wii";
1826
1893
  }
1827
1894
  else if(typeFrom==="wii"){
1828
1895
  miiTo={
@@ -1898,10 +1965,17 @@ module.exports={
1898
1965
  miiTo.mole.size=mii.mole.size;
1899
1966
  miiTo.mole.xPos=mii.mole.xPos;
1900
1967
  miiTo.mole.yPos=mii.mole.yPos;
1968
+ miiTo.console="3ds";
1901
1969
  }
1902
1970
  return miiTo;
1903
1971
  },
1904
1972
  make3DSChild:function(dad,mom,options={}){
1973
+ if(!["3ds","wii u"].includes(dad.console?.toLowerCase())){
1974
+ dad=this.convertMii(dad,"wii");
1975
+ }
1976
+ if(!["3ds","wii u"].includes(mom.console?.toLowerCase())){
1977
+ mom=this.convertMii(dad,"wii");
1978
+ }
1905
1979
  var g=options.gender||Math.floor(Math.random()*2)===1?"Male":"Female";
1906
1980
  var child={
1907
1981
  "info":{
@@ -1951,9 +2025,11 @@ module.exports={
1951
2025
  }
1952
2026
  child.face.col=skinCols[c[0]+Math.round((c[1]-c[0])/2)];
1953
2027
  child.name=child.info.name;
2028
+ child.type="3DS";
1954
2029
  return child;
1955
2030
  },
1956
- generateInstructions:function(mii,type,full){
2031
+ generateInstructions:function(mii,full){
2032
+ let type=mii.console?.toLowerCase();
1957
2033
  if(type.toLowerCase()==="wii"){
1958
2034
  var instrs={
1959
2035
  "base":`Select "${mii.info.gender}", and then "Start from Scratch".`,
@@ -2068,5 +2144,97 @@ module.exports={
2068
2144
  }
2069
2145
  return instrs;
2070
2146
  }
2147
+ },
2148
+ convert3DSMiiToStudio:function(jsonIn){
2149
+ if(!["3ds","wii u"].includes(jsonIn.console?.toLowerCase())){
2150
+ jsonIn=this.convertMii(jsonIn);
2151
+ }
2152
+ var mii=jsonIn;
2153
+ var studioMii=new Uint8Array([0x08, 0x00, 0x40, 0x03, 0x08, 0x04, 0x04, 0x02, 0x02, 0x0c, 0x03, 0x01, 0x06, 0x04, 0x06, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x21, 0x40, 0x04, 0x00, 0x02, 0x14, 0x03, 0x13, 0x04, 0x17, 0x0d, 0x04, 0x00, 0x0a, 0x04, 0x01, 0x09]);
2154
+ function encodeStudio(studio) {
2155
+ function byteToString(int){
2156
+ var str = int.toString(16);
2157
+ if(str.length < 2)str = '0' + str;
2158
+ return str;
2159
+ }
2160
+ var n = 0;
2161
+ var eo;
2162
+ var dest = byteToString(n);
2163
+ for (var i = 0; i < studio.length; i++) {
2164
+ eo = (7 + (studio[i] ^ n)) & 0xFF;
2165
+ n = eo;
2166
+ dest += byteToString(eo);
2167
+ }
2168
+ return dest;
2169
+ }
2170
+ studioMii[0x16] = mii.info.gender==="Male"?0:1;
2171
+ studioMii[0x15] = favCols.indexOf(mii.info.favColor);
2172
+ studioMii[0x1E] = mii.info.height;
2173
+ studioMii[2] = mii.info.weight;
2174
+ studioMii[0x13] = tables.faces[mii.face.shape];
2175
+ studioMii[0x11] = skinCols.indexOf(mii.face.col);
2176
+ studioMii[0x14] = faceFeatures3DS.indexOf(mii.face.feature);
2177
+ studioMii[0x12] = makeups3DS.indexOf(mii.face.makeup);
2178
+ studioMii[0x1D] = tables.hairs[mii.hair.style[0]][mii.hair.style[1]];
2179
+ studioMii[0x1B] = hairCols.indexOf(mii.hair.col);
2180
+ if (!studioMii[0x1B]) studioMii[0x1B] = 8;
2181
+ studioMii[0x1C] = mii.hair.flipped?1:0;
2182
+ studioMii[7] = tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]];
2183
+ studioMii[4] = eyeCols.indexOf(mii.eyes.col) + 8;
2184
+ studioMii[6] = mii.eyes.size;
2185
+ studioMii[3] = mii.eyes.squash;
2186
+ studioMii[5] = mii.eyes.rot;
2187
+ studioMii[8] = mii.eyes.distApart;
2188
+ studioMii[9] = mii.eyes.yPos;
2189
+ studioMii[0xE] = tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]];
2190
+ studioMii[0xB] = hairCols.indexOf(mii.eyebrows.col);
2191
+ if (!studioMii[0xB]) studioMii[0xB] = 8;
2192
+ studioMii[0xD] = mii.eyebrows.size;
2193
+ studioMii[0xA] = mii.eyebrows.squash;
2194
+ studioMii[0xC] = mii.eyebrows.rot;
2195
+ studioMii[0xF] = mii.eyebrows.distApart;
2196
+ studioMii[0x10] = mii.eyebrows.yPos+3;
2197
+ studioMii[0x2C] = tables.noses[mii.nose.type[0]][mii.nose.type[1]];
2198
+ studioMii[0x2B] = mii.nose.size;
2199
+ studioMii[0x2D] = mii.nose.yPos;
2200
+ studioMii[0x26] = tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]];
2201
+ studioMii[0x24] = mouthCols3DS.indexOf(mii.mouth.col);
2202
+ if (studioMii[0x24] < 4) {
2203
+ studioMii[0x24] += 19;
2204
+ } else {
2205
+ studioMii[0x24] = 0;
2206
+ }
2207
+ studioMii[0x25] = mii.mouth.size;
2208
+ studioMii[0x23] = mii.mouth.squash;
2209
+ studioMii[0x27] = mii.mouth.yPos;
2210
+ studioMii[0x29] = mii.facialHair.mustacheType;
2211
+ studioMii[1] = mii.facialHair.beardType;
2212
+ studioMii[0] = hairCols.indexOf(mii.facialHair.col);
2213
+ if (!studioMii[0]) studioMii[0] = 8;
2214
+ studioMii[0x28] = mii.facialHair.mustacheSize;
2215
+ studioMii[0x2A] = mii.facialHair.mustacheYPos;
2216
+ studioMii[0x19] = mii.glasses.type;
2217
+ studioMii[0x17] = glassesCols3DS.indexOf(mii.glasses.col);
2218
+ if (!studioMii[0x17]) {
2219
+ studioMii[0x17] = 8;
2220
+ } else if (studioMii[0x17] < 6) {
2221
+ studioMii[0x17] += 13;
2222
+ } else {
2223
+ studioMii[0x17] = 0;
2224
+ }
2225
+ studioMii[0x18] = mii.glasses.size;
2226
+ studioMii[0x1A] = mii.glasses.yPos;
2227
+ studioMii[0x20] = mii.mole.on?1:0;
2228
+ studioMii[0x1F] = mii.mole.size;
2229
+ studioMii[0x21] = mii.mole.xPos;
2230
+ studioMii[0x22] = mii.mole.yPos;
2231
+ return encodeStudio(studioMii);
2232
+ },
2233
+ render3DSMii:async function(jsonIn,fflRes=_fflRes){
2234
+ if(!["3ds","wii u"].includes(jsonIn.console?.toLowerCase())){
2235
+ jsonIn=this.convertMii(jsonIn);
2236
+ }
2237
+ return await renderMii(this.convert3DSMiiToStudio(jsonIn),fflRes);
2071
2238
  }
2072
2239
  }
2240
+ module.exports=exports;