2024-03-21 02:10:38 +08:00
|
|
|
const path = require('path');
|
|
|
|
const fs = require('fs');
|
2024-03-25 01:39:06 +08:00
|
|
|
const https = require('https');
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
const textMapFolderPath = path.resolve('../Resources/TextMap');
|
|
|
|
const textMapFiles = fs.readdirSync(textMapFolderPath);
|
|
|
|
|
|
|
|
const getHashEN = readJsonFile('../Resources/TextMap/TextMapEN.json');
|
|
|
|
const getHashCN = readJsonFile('../Resources/TextMap/TextMapCHS.json'); // beta stuff
|
|
|
|
|
|
|
|
// TODO: API IMAGE
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
async function runAvatar(lang, getHashLANG, dlicon = false) {
|
2024-03-21 02:10:38 +08:00
|
|
|
const saveAvatar = lang + `avatar.json`;
|
|
|
|
const getAvatar = readJsonFile('../Resources/ExcelBinOutput/AvatarExcelConfigData.json');
|
|
|
|
var dataAvatar = [];
|
|
|
|
for (const data of Object.values(getAvatar)) {
|
|
|
|
|
|
|
|
if (data && data.nameTextMapHash && data.nameTextMapHash) {
|
|
|
|
const hash = data.nameTextMapHash;
|
|
|
|
const id = data.id;
|
|
|
|
|
|
|
|
if (id < 10000002 || id >= 11000000) continue;
|
|
|
|
|
|
|
|
const iconName = data.iconName;
|
|
|
|
|
|
|
|
const name = getHashLANG[hash] || getHashCN[hash] || `N/A`;
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
// hoyoshit https://upload-os-bbs.mihoyo.com/game_record/genshin/character_icon/ not found Momoka,Linette,Liney,Freminet
|
|
|
|
var urlIcon = ""
|
|
|
|
if (dlicon) {
|
|
|
|
var iconUrl = `https://enka.network/ui/${iconName}.png`;
|
|
|
|
try {
|
|
|
|
urlIcon = await downloadIcon(iconUrl, `../Tool/icon/avatar/${iconName}.png`, `/image/game/genshin/avatar/${iconName}.png`)
|
|
|
|
} catch (error) {
|
|
|
|
console.log(error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-21 02:10:38 +08:00
|
|
|
var objAvatar = new Object();
|
|
|
|
objAvatar["id"] = id;
|
|
|
|
objAvatar["name"] = name;
|
2024-03-25 01:39:06 +08:00
|
|
|
objAvatar["rank"] = data.qualityType
|
|
|
|
objAvatar['img'] = urlIcon
|
2024-03-21 02:10:38 +08:00
|
|
|
dataAvatar.push(objAvatar)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
fs.writeFileSync(saveAvatar, JSON.stringify(dataAvatar, null, 2));
|
|
|
|
dataAvatar = []; // cleanup
|
|
|
|
console.log(`done avatar: ` + saveAvatar)
|
|
|
|
}
|
|
|
|
function runScene(lang, getHashLANG) {
|
|
|
|
const saveScene = lang + `scene.json`;
|
|
|
|
const getScene = readJsonFile('../Resources/ExcelBinOutput/SceneExcelConfigData.json');
|
|
|
|
var dataScene = [];
|
|
|
|
for (const data of Object.values(getScene)) {
|
|
|
|
|
|
|
|
if (data && data.id) {
|
|
|
|
|
|
|
|
const id = data.id;
|
|
|
|
const name = `${data.scriptData}` + (data.levelEntityConfig == "" ? "" : " (" + data.levelEntityConfig + ")")
|
|
|
|
|
|
|
|
var objScene = new Object();
|
|
|
|
objScene["id"] = id;
|
|
|
|
objScene["name"] = `${name}`;
|
|
|
|
|
|
|
|
dataScene.push(objScene)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
console.log(`Done scene: ` + saveScene)
|
|
|
|
fs.writeFileSync(saveScene, JSON.stringify(dataScene, null, 2));
|
|
|
|
dataScene = []; // cleanup
|
|
|
|
|
|
|
|
/*
|
|
|
|
const saveStage = lang + `stage.json`;
|
|
|
|
const getStage = readJsonFile('../Resources/ExcelOutput/StageConfig.json');
|
|
|
|
for (const data of Object.values(getStage)) {
|
|
|
|
|
|
|
|
if (data && data.StageName && data.StageName.Hash) {
|
|
|
|
const hash = data.StageName.Hash;
|
|
|
|
const id = data.StageID;
|
|
|
|
|
|
|
|
const name = getHashLANG[hash] || getHashCN[hash] || `N/A`;
|
|
|
|
|
|
|
|
var objScene = new Object();
|
|
|
|
objScene["id"] = id;
|
|
|
|
objScene["name"] = `${name} (${data.StageType} #${data.Level})`;
|
|
|
|
dataScene.push(objScene)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
console.log(`Done stage: ` + saveStage)
|
|
|
|
fs.writeFileSync(saveStage, JSON.stringify(dataScene, null, 2));
|
|
|
|
dataScene = []; // cleanup
|
|
|
|
*/
|
|
|
|
}
|
2024-03-25 01:39:06 +08:00
|
|
|
async function runMonster(lang, getHashLANG, dlicon = false) {
|
2024-03-21 02:10:38 +08:00
|
|
|
const saveMonster = lang + 'monster.json';
|
|
|
|
const getMonster = readJsonFile('../Resources/ExcelBinOutput/MonsterExcelConfigData.json');
|
2024-03-25 01:39:06 +08:00
|
|
|
const getMonsterInfo = readJsonFile('../Resources/ExcelBinOutput/MonsterDescribeExcelConfigData.json');
|
2024-03-21 02:10:38 +08:00
|
|
|
var dataMonster = [];
|
|
|
|
for (const data of Object.values(getMonster)) {
|
|
|
|
|
|
|
|
if (data && data.nameTextMapHash) {
|
|
|
|
const hash = data.nameTextMapHash;
|
|
|
|
const id = data.id;
|
2024-03-25 01:39:06 +08:00
|
|
|
const mName = data.monsterName;
|
|
|
|
const mType = data.type;
|
|
|
|
const varDP = data.describeId
|
|
|
|
const varTus = data.LODPatternName
|
|
|
|
|
|
|
|
var name = getHashLANG[hash] || getHashCN[hash] || mName || `N/A`;
|
2024-03-21 02:10:38 +08:00
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
var urlIcon = ""
|
|
|
|
var iconPath = ""
|
|
|
|
|
|
|
|
// some monster no have describe id (so skip download image)
|
|
|
|
var infoMonster = getMonsterInfo.find(item => item.id === varDP)
|
|
|
|
if (infoMonster) {
|
|
|
|
name = getHashLANG[infoMonster.nameTextMapHash] || getHashCN[infoMonster.nameTextMapHash] || mName || `N/A`;
|
|
|
|
iconPath = infoMonster.icon;
|
|
|
|
} else {
|
|
|
|
infoMonster = getMonsterInfo.find(item => item.icon.includes(mName))
|
|
|
|
if (infoMonster) {
|
|
|
|
iconPath = infoMonster.icon;
|
|
|
|
} else {
|
|
|
|
if (varTus.includes(`Animal`)) {
|
|
|
|
iconPath = `UI_AnimalIcon_${mName}`
|
|
|
|
}
|
|
|
|
//console.log(`not found info monster: ${name} > ${id} (${varDP})`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dlicon) {
|
|
|
|
if (iconPath != "") {
|
|
|
|
// https://enka.network/ui/
|
|
|
|
// https://api.ambr.top/assets/UI/furniture
|
|
|
|
var iconUrl = `https://api.ambr.top/assets/UI/monster/${iconPath}.png`;
|
|
|
|
var iconUrlv2 = `https://enka.network/ui/${iconPath}.png`;
|
|
|
|
try {
|
|
|
|
urlIcon = await downloadIcon(iconUrl, `../Tool/icon/monster/${iconPath}.png`, `/image/game/genshin/monster/${iconPath}.png`, iconUrlv2);
|
|
|
|
} catch (error) {
|
|
|
|
console.log(error);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// console.log(`not found iocn ${id} with name ${name}`)
|
|
|
|
}
|
|
|
|
}
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
var objMonster = new Object();
|
|
|
|
objMonster["id"] = id;
|
2024-03-25 01:39:06 +08:00
|
|
|
objMonster["type"] = mType;
|
2024-03-21 02:10:38 +08:00
|
|
|
objMonster["name"] = name;
|
2024-03-25 01:39:06 +08:00
|
|
|
objMonster["img"] = urlIcon;
|
2024-03-21 02:10:38 +08:00
|
|
|
dataMonster.push(objMonster)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
fs.writeFileSync(saveMonster, JSON.stringify(dataMonster, null, 2));
|
|
|
|
dataMonster = []; // cleanup
|
|
|
|
console.log(`done monster: ` + saveMonster)
|
|
|
|
}
|
|
|
|
function runProp(lang, getHashLANG) {
|
|
|
|
const saveProp = lang + 'prop.json';
|
|
|
|
const getProp = readJsonFile('../Resources/ExcelBinOutput/GadgetExcelConfigData.json');
|
|
|
|
var dataProp = [];
|
|
|
|
for (const data of Object.values(getProp)) {
|
|
|
|
|
|
|
|
if (data && data.nameTextMapHash) {
|
|
|
|
const hash = data.nameTextMapHash;
|
|
|
|
const hash2 = data.interactNameTextMapHash;
|
|
|
|
const id = data.id;
|
|
|
|
const NamePath = data.jsonName;
|
|
|
|
|
|
|
|
const name = (getHashLANG[hash] || getHashCN[hash] || getHashLANG[hash2] || getHashCN[hash2] || `N/A`) + (NamePath == "" ? "" : " (" + NamePath + ")")
|
|
|
|
|
|
|
|
var objProp = new Object();
|
|
|
|
objProp["id"] = id;
|
|
|
|
objProp["name"] = name;
|
|
|
|
dataProp.push(objProp)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
fs.writeFileSync(saveProp, JSON.stringify(dataProp, null, 2));
|
|
|
|
dataProp = []; // cleanup
|
|
|
|
console.log(`done Prop: ` + saveProp)
|
|
|
|
}
|
2024-03-25 01:39:06 +08:00
|
|
|
|
|
|
|
function runQuest(lang, getHashLANG) {
|
|
|
|
const saveQuest = lang + 'quest.json';
|
|
|
|
const getQuest = readJsonFile('../Resources/ExcelBinOutput/QuestExcelConfigData.json');
|
|
|
|
var dataQuest = [];
|
|
|
|
for (const data of Object.values(getQuest)) {
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
|
|
|
|
const hash = data.descTextMapHash;
|
|
|
|
const hash2 = data.stepDescTextMapHash;
|
|
|
|
const hash3 = data.guideTipsTextMapHash;
|
|
|
|
|
|
|
|
const id_main = data.mainId;
|
|
|
|
const id_sub = data.subId;
|
|
|
|
const type = data.showType || "None"
|
|
|
|
const order = data.order;
|
|
|
|
|
|
|
|
/*
|
|
|
|
if(type == "QUEST_HIDDEN"){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
const name = getHashLANG[hash] || getHashCN[hash] || `N/A`
|
|
|
|
const info = getHashLANG[hash2] || getHashCN[hash3] || ``
|
|
|
|
const guide = getHashLANG[hash3] || getHashCN[hash3] || ``
|
|
|
|
|
|
|
|
var objQuest = new Object();
|
|
|
|
objQuest["id"] = id_sub;
|
|
|
|
objQuest["id_main"] = id_main;
|
|
|
|
objQuest["name"] = name + ` (${id_main}\/${id_sub} #${order})`;
|
|
|
|
objQuest["info"] = info;
|
|
|
|
objQuest["guide"] = guide;
|
|
|
|
objQuest["type"] = type;
|
|
|
|
|
|
|
|
dataQuest.push(objQuest)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
fs.writeFileSync(saveQuest, JSON.stringify(dataQuest, null, 2));
|
|
|
|
dataQuest = []; // cleanup
|
|
|
|
console.log(`done Quest: ` + saveQuest)
|
|
|
|
}
|
|
|
|
|
|
|
|
async function runItem(lang, getHashLANG, dlicon = false) {
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
const saveItem = lang + 'item.json';
|
|
|
|
var dataItem = [];
|
|
|
|
|
|
|
|
const filePaths = [
|
|
|
|
'../Resources/ExcelBinOutput/MaterialExcelConfigData.json',
|
|
|
|
'../Resources/ExcelBinOutput/HomeWorldFurnitureExcelConfigData.json'
|
|
|
|
];
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
for (const filePath of filePaths) {
|
2024-03-21 02:10:38 +08:00
|
|
|
const getItem = readJsonFile(filePath);
|
|
|
|
for (const data of Object.values(getItem)) {
|
|
|
|
if (data && data.nameTextMapHash) {
|
|
|
|
const hash = data.nameTextMapHash;
|
|
|
|
const id = data.id;
|
|
|
|
|
|
|
|
const name = getHashLANG[hash] || getHashCN[hash] || `N/A`;
|
|
|
|
|
|
|
|
var iconPath = data.icon; // UI_EquipIcon_${item.type}_${item.id}
|
2024-03-25 01:39:06 +08:00
|
|
|
var urlIcon = ""
|
|
|
|
if (dlicon) {
|
|
|
|
if (iconPath != "") {
|
|
|
|
// https://enka.network/ui/
|
|
|
|
// https://api.ambr.top/assets/UI/furniture
|
|
|
|
var iconUrl = `https://enka.network/ui/${iconPath}.png`;
|
|
|
|
var iconUrlv2 = `https://api.ambr.top/assets/UI/${iconPath}.png`;
|
|
|
|
try {
|
|
|
|
urlIcon = await downloadIcon(iconUrl, `../Tool/icon/item/${iconPath}.png`, `/image/game/genshin/item/${iconPath}.png`, iconUrlv2);
|
|
|
|
} catch (error) {
|
|
|
|
console.log(error);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log(`not found iocn ${id} with name ${name}`)
|
|
|
|
}
|
|
|
|
}
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
var objItem = new Object();
|
|
|
|
objItem["id"] = id;
|
|
|
|
objItem["name"] = `${name}`;
|
|
|
|
objItem["type"] = data.itemType;
|
2024-03-25 01:39:06 +08:00
|
|
|
objItem["rank"] = data.rankLevel;
|
|
|
|
objItem["img"] = urlIcon;
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
dataItem.push(objItem);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
}
|
2024-03-25 01:39:06 +08:00
|
|
|
}
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
fs.writeFileSync(saveItem, JSON.stringify(dataItem, null, 2));
|
|
|
|
dataItem = []; // cleanup
|
2024-03-25 01:39:06 +08:00
|
|
|
console.log(`done item: ` + saveItem);
|
2024-03-21 02:10:38 +08:00
|
|
|
}
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
async function runWeapon(lang, getHashLANG, dlicon = false) {
|
2024-03-21 02:10:38 +08:00
|
|
|
const saveItem = lang + 'weapon.json';
|
|
|
|
var dataItem = [];
|
|
|
|
|
|
|
|
const filePaths = [
|
2024-03-25 01:39:06 +08:00
|
|
|
'../Resources/ExcelBinOutput/WeaponExcelConfigData.json'
|
2024-03-21 02:10:38 +08:00
|
|
|
];
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
for (const filePath of filePaths) {
|
2024-03-21 02:10:38 +08:00
|
|
|
const getItem = readJsonFile(filePath);
|
|
|
|
for (const data of Object.values(getItem)) {
|
|
|
|
if (data && data.nameTextMapHash) {
|
|
|
|
const hash = data.nameTextMapHash;
|
|
|
|
const id = data.id;
|
|
|
|
|
|
|
|
const name = getHashLANG[hash] || getHashCN[hash] || `N/A`;
|
2024-03-25 01:39:06 +08:00
|
|
|
if (name.includes(`test`)) {
|
|
|
|
continue;
|
|
|
|
}
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
var subType = data.weaponType;
|
|
|
|
var iconPath = data.icon;
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
var urlIcon = ""
|
|
|
|
if (dlicon) {
|
|
|
|
if (iconPath != "") {
|
|
|
|
var iconUrl = `https://enka.network/ui/${iconPath}.png`;
|
|
|
|
var iconUrlv2 = `https://upload-os-bbs.mihoyo.com/game_record/genshin/equip/${iconPath}.png`;
|
|
|
|
try {
|
|
|
|
urlIcon = await downloadIcon(iconUrl, `../Tool/icon/weapon/${iconPath}.png`, `/image/game/genshin/weapon/${iconPath}.png`, iconUrlv2);
|
|
|
|
} catch (error) {
|
|
|
|
console.log(error);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log(`not found iocn ${id} with name ${name}`);
|
|
|
|
}
|
|
|
|
}
|
2024-03-21 02:10:38 +08:00
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
var objItem = {
|
|
|
|
"id": id,
|
|
|
|
"name": `${name}`,
|
|
|
|
"type_main": data.itemType,
|
|
|
|
"type_sub": subType,
|
|
|
|
"rank": data.rankLevel,
|
|
|
|
"img": urlIcon
|
|
|
|
};
|
2024-03-21 02:10:38 +08:00
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
dataItem.push(objItem);
|
2024-03-21 02:10:38 +08:00
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
}
|
2024-03-25 01:39:06 +08:00
|
|
|
}
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
fs.writeFileSync(saveItem, JSON.stringify(dataItem, null, 2));
|
|
|
|
dataItem = []; // cleanup
|
2024-03-25 01:39:06 +08:00
|
|
|
console.log(`done wp: ` + saveItem);
|
2024-03-21 02:10:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const getRelicConfig = readJsonFile('../Resources/ExcelBinOutput/ReliquaryExcelConfigData.json');
|
|
|
|
|
|
|
|
|
|
|
|
const getRelicSub = readJsonFile('../Resources/ExcelBinOutput/ReliquaryAffixExcelConfigData.json'); // sub
|
|
|
|
|
|
|
|
const getAvatarProp = readJsonFile('../Resources/ExcelBinOutput/AvatarCurveExcelConfigData.json');
|
|
|
|
const getHasIndex1 = readJsonFile(`../Resources/ExcelBinOutput/ManualTextMapConfigData.json`)
|
|
|
|
|
|
|
|
// Main
|
|
|
|
const getRelicMain = readJsonFile('../Resources/ExcelBinOutput/ReliquaryMainPropExcelConfigData.json');
|
|
|
|
const levelConfig = readJsonFile(`../Resources/ExcelBinOutput/ReliquaryLevelExcelConfigData.json`)
|
|
|
|
|
|
|
|
// Simulator
|
|
|
|
// /give 76544 lv1 x1 15001 501064,1 501204,1 501224,1 501234,1
|
|
|
|
function runGiveEmu(cmd) {
|
|
|
|
|
|
|
|
const parts = cmd.split(" ");
|
|
|
|
const action = parts[1];
|
|
|
|
|
|
|
|
const item_id = parseInt(action);
|
|
|
|
|
|
|
|
let level = 1;
|
|
|
|
let item_count = 1;
|
|
|
|
let refined_count = 0;
|
|
|
|
let main_prop_id = 0;
|
|
|
|
let propDataCount = 0;
|
|
|
|
var maxStep = false;
|
|
|
|
var maxLevel = 999;
|
|
|
|
|
|
|
|
if (parts.length > 2) {
|
|
|
|
let currentParamIndex = 2;
|
|
|
|
while (currentParamIndex < parts.length) {
|
|
|
|
|
|
|
|
const param = parts[currentParamIndex];
|
|
|
|
//console.log(param)
|
|
|
|
|
|
|
|
if (param.startsWith("x")) {
|
|
|
|
item_count = parseInt(param.replace("x", ""));
|
|
|
|
} else if (param.startsWith("s")) {
|
|
|
|
//main_prop_id = parseInt(param.replace("s", ""));
|
|
|
|
} else if (param.startsWith("lv")) {
|
|
|
|
level = parseInt(param.replace("lv", "")) + 1;
|
|
|
|
console.log(`found level: ` + level)
|
|
|
|
} else if (param.startsWith("r")) {
|
|
|
|
refined_count = parseInt(param.replace("r", "")) + 1;
|
|
|
|
} else if (param.startsWith("sorted")) {
|
|
|
|
//continue
|
|
|
|
} else if (param.startsWith("-maxsteps")) {
|
|
|
|
maxStep = true;
|
|
|
|
//console.log(`found max`)
|
|
|
|
} else {
|
|
|
|
|
|
|
|
main_prop_id = parseInt(param)
|
|
|
|
|
|
|
|
var dataRelic = getRelicConfig.find(entry => entry.id == item_id);
|
|
|
|
console.log(dataRelic)
|
|
|
|
|
|
|
|
var dataRelicMain = getRelicMain.find(entry => entry.id == main_prop_id);
|
|
|
|
if (dataRelicMain) {
|
|
|
|
|
|
|
|
//console.log(dataRelicMain)
|
|
|
|
//console.log(`RelicMainAffixConfig ${dataRelic.MainAffixGroup} > ${main_prop_id}`)
|
|
|
|
|
|
|
|
// Get Name
|
|
|
|
var mainPropHash = getHasIndex1.find(item =>
|
|
|
|
item.textMapId === dataRelicMain.propType
|
|
|
|
).textMapContentTextMapHash;
|
|
|
|
|
|
|
|
const nameMain = getHashEN[mainPropHash] || getHashCN[mainPropHash] || `N/A`;
|
|
|
|
|
|
|
|
//console.log(dataRelic.rankLevel)
|
|
|
|
|
|
|
|
var valueMain = 0;
|
|
|
|
var TesLevel = levelConfig.find(entry =>
|
|
|
|
entry.level === level &&
|
|
|
|
entry.rank === dataRelic.rankLevel &&
|
|
|
|
entry.addProps.some(prop => prop.propType === dataRelicMain.propType)
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!TesLevel) {
|
|
|
|
//var tus1 = getRelicSub.find(entry => entry.propType == dataRelicMain.propType);
|
|
|
|
//valueMain = tus1.propValue
|
|
|
|
//console.log(`${dataRelicMain.propType} > ${main_prop_id} > ${valueMain}`, tus1)
|
|
|
|
//continue;
|
|
|
|
console.log('not found data...')
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
var tus2 = TesLevel.addProps.find(prop => prop.propType === dataRelicMain.propType);
|
|
|
|
//console.log(tus2)
|
|
|
|
valueMain = tus2.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
var lo = CaC(dataRelicMain.propType, valueMain);
|
|
|
|
console.log(`Main ${nameMain}: ${lo}`)
|
|
|
|
|
|
|
|
// Add sub prop
|
|
|
|
for (let i = currentParamIndex; i < parts.length; i++) {
|
|
|
|
|
|
|
|
const propData = parts[i].split(/[,:;.]/);
|
|
|
|
const prop_id = parseInt(propData[0]);
|
|
|
|
let prop_count = parseInt(propData[1]);
|
|
|
|
if (isNaN(prop_count)) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
//console.log(`${prop_id} > ${prop_count}`)
|
|
|
|
|
|
|
|
var SubData = getRelicSub.find(prop => prop.id === prop_id);
|
|
|
|
if (!SubData) continue
|
|
|
|
//console.log(SubData)
|
|
|
|
|
|
|
|
// limit count base level max art
|
|
|
|
const maxCount = Math.floor(maxLevel / 3) + 1; // or just use 15 ?
|
|
|
|
const count = Math.min(prop_count, maxCount);
|
|
|
|
|
|
|
|
// fix step count
|
|
|
|
var finalValue = SubData.propValue;
|
|
|
|
if (count >= 2) {
|
|
|
|
finalValue = finalValue * count
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get Name
|
|
|
|
var subPropHash = getHasIndex1.find(item =>
|
|
|
|
item.textMapId === SubData.propType
|
|
|
|
).textMapContentTextMapHash;
|
|
|
|
const nameSub = getHashEN[subPropHash] || getHashCN[subPropHash] || `N/A`;
|
|
|
|
|
|
|
|
var lo = CaC(SubData.propType, finalValue);
|
|
|
|
console.log(`Sub ${nameSub}: ${lo}`)
|
|
|
|
|
|
|
|
propDataCount++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log(`not found`)
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
currentParamIndex++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return console.log(`bad cmd`)
|
|
|
|
}
|
|
|
|
|
|
|
|
//console.log(extra_params)
|
|
|
|
|
|
|
|
console.log(`${cmd}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
function CaC(name, finalValue) {
|
|
|
|
if (name.includes('PERCENT') || name.includes('CRITICAL') || name.includes('CHARGE') || name.includes('HURT') || name.includes('HEAL')) {
|
|
|
|
return `${(finalValue * 100).toFixed(2)}%`
|
|
|
|
} else {
|
|
|
|
return `+${Math.floor(finalValue)}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
async function runRelic(lang, getHashLANG, dlicon = false) {
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
// lock basic stats
|
|
|
|
var maxLevel = 21;
|
|
|
|
var maxRank = 5;
|
|
|
|
|
|
|
|
const saveMainRelic = lang + 'relic_main.json';
|
|
|
|
var dataMainRelic = [];
|
|
|
|
for (const data of Object.values(getRelicMain)) {
|
|
|
|
|
|
|
|
var id = data.id;
|
|
|
|
var name = data.propType;
|
|
|
|
|
|
|
|
// Get Name
|
|
|
|
var mainPropHash = getHasIndex1.find(item => item.textMapId === name).textMapContentTextMapHash;
|
|
|
|
const nameMain = getHashLANG[mainPropHash] || getHashCN[mainPropHash] || `N/A`;
|
|
|
|
|
|
|
|
var valueMain = 0;
|
|
|
|
var TesLevel = levelConfig.find(entry =>
|
|
|
|
entry.level === maxLevel &&
|
|
|
|
entry.rank === maxRank &&
|
|
|
|
entry.addProps.some(prop => prop.propType === name)
|
|
|
|
);
|
|
|
|
if (!TesLevel) {
|
|
|
|
//valueMain = getRelicSub.find(entry => entry.propType == name).propValue
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
valueMain = TesLevel.addProps.find(prop => prop.propType === name).value;
|
|
|
|
}
|
|
|
|
|
|
|
|
var bonus = CaC(name, valueMain)
|
|
|
|
|
|
|
|
var objMainRelic = new Object();
|
|
|
|
objMainRelic["id"] = id;
|
|
|
|
objMainRelic["grup"] = data.propDepotId
|
|
|
|
objMainRelic["name"] = `${nameMain} (${bonus} > R${maxRank}LV${maxLevel})`;
|
|
|
|
dataMainRelic.push(objMainRelic)
|
|
|
|
|
|
|
|
}
|
|
|
|
fs.writeFileSync(saveMainRelic, JSON.stringify(dataMainRelic, null, 2));
|
|
|
|
dataMainRelic = []; // cleanup
|
|
|
|
console.log(`done MainRelic: ` + saveMainRelic)
|
|
|
|
|
|
|
|
const saveSubRelic = lang + 'relic_sub.json';
|
|
|
|
var dataSubRelic = [];
|
|
|
|
|
|
|
|
for (const sub of Object.values(getRelicSub)) {
|
|
|
|
|
|
|
|
var id = sub.id;
|
|
|
|
var name = sub.propType;
|
|
|
|
|
|
|
|
var mainPropHash = getHasIndex1.find(item => item.textMapId === name).textMapContentTextMapHash;
|
|
|
|
const nameMain = getHashLANG[mainPropHash] || getHashCN[mainPropHash] || `N/A`;
|
|
|
|
|
|
|
|
var bonus = CaC(name, sub.propValue)
|
|
|
|
|
|
|
|
var objSubRelic = new Object();
|
|
|
|
objSubRelic["id"] = id;
|
|
|
|
objSubRelic["grup"] = sub.depotId
|
|
|
|
objSubRelic["name"] = `${nameMain} (${bonus})`;
|
|
|
|
dataSubRelic.push(objSubRelic)
|
|
|
|
}
|
|
|
|
|
|
|
|
fs.writeFileSync(saveSubRelic, JSON.stringify(dataSubRelic, null, 2));
|
|
|
|
dataSubRelic = []; // cleanup
|
|
|
|
console.log(`done SubRelic: ` + saveSubRelic)
|
|
|
|
|
|
|
|
const saveItemRelic = lang + 'relic_item.json';
|
|
|
|
const getItemRelic = readJsonFile('../Resources/ExcelBinOutput/ReliquaryExcelConfigData.json');
|
|
|
|
var dataItemRelic = [];
|
|
|
|
const uniqueMainSub = new Set();
|
|
|
|
for (const data of Object.values(getItemRelic)) {
|
|
|
|
|
|
|
|
const hash = data.nameTextMapHash;
|
|
|
|
const id = data.id;
|
|
|
|
|
|
|
|
const name = getHashLANG[hash] || getHashCN[hash] || `N/A`;
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
var IndexCheck = getHasIndex1.find(item => item.textMapId === data.equipType);
|
|
|
|
if (!IndexCheck) {
|
|
|
|
console.log(data.equipType)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
var indexType = IndexCheck.textMapContentTextMapHash
|
|
|
|
const IndexName = getHashLANG[indexType] || getHashCN[indexType] || `N/A`;
|
|
|
|
|
|
|
|
//var idgu = data.appendPropNum ?? 0;
|
|
|
|
|
|
|
|
var main = data.mainPropDepotId;
|
|
|
|
var sub = data.appendPropDepotId;
|
|
|
|
var rank = data.rankLevel;
|
|
|
|
|
|
|
|
var subp = `${name} (${IndexName}) (R${rank})`;
|
|
|
|
|
|
|
|
if (!uniqueMainSub.has(subp)) {
|
|
|
|
uniqueMainSub.add(subp);
|
2024-03-25 01:39:06 +08:00
|
|
|
|
|
|
|
var iconPath = data.icon;
|
|
|
|
var urlIcon = ""
|
|
|
|
if (dlicon) {
|
|
|
|
if (iconPath != "") {
|
|
|
|
var iconUrl = `https://enka.network/ui/${iconPath}.png`;
|
|
|
|
var iconUrlv2 = `https://upload-os-bbs.mihoyo.com/game_record/genshin/equip/${iconPath}.png`;
|
|
|
|
try {
|
|
|
|
urlIcon = await downloadIcon(iconUrl, `../Tool/icon/artifact/${iconPath}.png`, `/image/game/genshin/artifact/${iconPath}.png`, iconUrlv2);
|
|
|
|
} catch (error) {
|
|
|
|
console.log(error);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log(`not found iocn ${id} with name ${name}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-21 02:10:38 +08:00
|
|
|
var objItem = new Object();
|
|
|
|
objItem["id"] = id;
|
|
|
|
//objItem["num"] = idgu;
|
|
|
|
objItem["name"] = subp;
|
|
|
|
objItem["rarity"] = data.Rarity;
|
|
|
|
objItem["rank"] = rank;
|
|
|
|
objItem["main"] = main;
|
|
|
|
objItem["sub"] = sub;
|
|
|
|
objItem["type"] = data.equipType;
|
2024-03-25 01:39:06 +08:00
|
|
|
objItem["img"] = urlIcon
|
2024-03-21 02:10:38 +08:00
|
|
|
dataItemRelic.push(objItem)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fs.writeFileSync(saveItemRelic, JSON.stringify(dataItemRelic, null, 2));
|
|
|
|
dataItemRelic = []; // cleanup
|
|
|
|
console.log(`done Item Relic: ` + saveItemRelic)
|
|
|
|
}
|
|
|
|
|
|
|
|
async function runMappings(version = 1) {
|
|
|
|
var dataMappings = {};
|
|
|
|
const saveMappings = '../Tool/data/mappings.json';
|
|
|
|
|
|
|
|
for (const textMapFile of textMapFiles) {
|
|
|
|
|
|
|
|
var lang = textMapFile.replace("TextMap", "").replace(".json", "");
|
|
|
|
|
|
|
|
if (version == 1) {
|
|
|
|
const textMapFilePath = path.resolve(textMapFolderPath, textMapFile);
|
|
|
|
const textMapData = await readJsonFileAsync(textMapFilePath);
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize the object if it's undefined
|
2024-03-21 11:36:11 +08:00
|
|
|
if (!dataMappings[mapLanguageCode(lang, true)]) {
|
|
|
|
dataMappings[mapLanguageCode(lang, true)] = {};
|
2024-03-21 02:10:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const filePaths = [
|
2024-03-21 11:36:11 +08:00
|
|
|
'../Resources/ExcelBinOutput/AvatarExcelConfigData.json',
|
|
|
|
'../Resources/ExcelBinOutput/WeaponExcelConfigData.json'
|
2024-03-21 02:10:38 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
for (const filePath of filePaths) {
|
|
|
|
try {
|
|
|
|
const getAvatar = await readJsonFileAsync(filePath);
|
|
|
|
for (const data of Object.values(getAvatar)) {
|
2024-03-21 11:36:11 +08:00
|
|
|
if (data && data.nameTextMapHash) {
|
|
|
|
const hash = data.nameTextMapHash;
|
|
|
|
var id = data.id;
|
|
|
|
const rank = getColorByRankLevel(data.qualityType || data.rankLevel.toString());
|
2024-03-21 02:10:38 +08:00
|
|
|
const name = textMapData[hash] || `N/A`;
|
|
|
|
|
|
|
|
var nameType = "idk";
|
2024-03-21 11:36:11 +08:00
|
|
|
if (filePath.includes(`AvatarExcelConfigData`)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (id >= 11000000) {
|
|
|
|
continue // skip test avatar
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
id = id % 1000 + 1000;
|
|
|
|
|
|
|
|
nameType = textMapData[`4233146695`] || `N/A`;
|
|
|
|
} else if (filePath.includes(`WeaponExcelConfigData`)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (id <= 11101 || id >= 20000) {
|
|
|
|
continue // skip non weapon items
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
nameType = textMapData[`4231343903`] || `N/A`;
|
2024-03-21 02:10:38 +08:00
|
|
|
}
|
|
|
|
|
2024-03-21 11:36:11 +08:00
|
|
|
dataMappings[mapLanguageCode(lang, true)][id] = [`${name} (${nameType})`, rank];
|
2024-03-21 02:10:38 +08:00
|
|
|
} else {
|
|
|
|
console.log("skip", data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error("Error processing file:", error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Type Banner
|
2024-03-21 11:36:11 +08:00
|
|
|
dataMappings[mapLanguageCode(lang, true)][200] = textMapData[`332935371`] || `N/A`; // Standard Wish
|
|
|
|
dataMappings[mapLanguageCode(lang, true)][301] = textMapData[`2272170627`] || `N/A`; // Character Event Wish
|
|
|
|
dataMappings[mapLanguageCode(lang, true)][400] = textMapData[`3352513147`] || `N/A`; // Character Event Wish-2
|
|
|
|
dataMappings[mapLanguageCode(lang, true)][302] = textMapData[`2864268523`] || `N/A`; // Weapon Event Wish
|
2024-03-21 02:10:38 +08:00
|
|
|
} else {
|
|
|
|
|
2024-03-21 11:36:11 +08:00
|
|
|
const langDirectory = `../Tool/resources/${mapLanguageCode(lang, false)}/`;
|
2024-03-21 02:10:38 +08:00
|
|
|
|
|
|
|
if (!fs.existsSync(langDirectory)) {
|
|
|
|
fs.mkdirSync(langDirectory, { recursive: true });
|
|
|
|
}
|
|
|
|
|
|
|
|
const getHashLANG = readJsonFile(`../Resources/TextMap/TextMap${lang}.json`);
|
|
|
|
|
2024-03-25 01:39:06 +08:00
|
|
|
await runAvatar(langDirectory, getHashLANG, true)
|
|
|
|
runScene(langDirectory, getHashLANG) // TODO: add dungeon image
|
|
|
|
await runMonster(langDirectory, getHashLANG, true)
|
|
|
|
await runItem(langDirectory, getHashLANG, true)
|
|
|
|
await runRelic(langDirectory, getHashLANG, true)
|
|
|
|
await runWeapon(langDirectory, getHashLANG, true)
|
2024-03-21 02:10:38 +08:00
|
|
|
runProp(langDirectory, getHashLANG)
|
2024-03-25 01:39:06 +08:00
|
|
|
runQuest(langDirectory, getHashLANG)
|
2024-03-21 02:10:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version == 1) {
|
|
|
|
await writeFileAsync(saveMappings, JSON.stringify(dataMappings, null, 2), 'utf-8');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//runAvatar();
|
|
|
|
//runScene();
|
|
|
|
//runMonster();
|
|
|
|
//runItem();
|
|
|
|
//runRelic();
|
|
|
|
//runWeapon();
|
|
|
|
//runProp();
|
2024-03-25 01:39:06 +08:00
|
|
|
runMappings(2);
|
|
|
|
//runMappings(1);
|
2024-03-21 02:10:38 +08:00
|
|
|
//runGiveEmu(`/give 76544 lv19 x1 15001 501064,10 501204,10 501224,10 501234,10`);
|
|
|
|
//runGiveEmu(`/give 63036 lv15 s1 1:99 2:1 3:1 4:1`);
|
|
|
|
//runGiveEmu(`/give 63116 lv15 s4 4:1 7:2 8:1 9:5`);
|
|
|
|
//runGiveEmu(`/give 63115 lv15 s10 5:1 7:1 8:1 9:6`);
|
|
|
|
//runGiveEmu(`/give 61013 lv20 s1 1:10000000 5:100000000 7:100000 10:100000`)
|
|
|
|
|
|
|
|
// Function to read and parse JSON file
|
|
|
|
function readJsonFile(filePath) {
|
|
|
|
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
|
|
return JSON.parse(fileContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function readJsonFileAsync(filePath) {
|
|
|
|
try {
|
|
|
|
const fileContent = await new Promise((resolve, reject) => {
|
|
|
|
fs.readFile(filePath, 'utf-8', (err, data) => {
|
|
|
|
if (err) reject(err);
|
|
|
|
else resolve(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return JSON.parse(fileContent);
|
|
|
|
} catch (error) {
|
|
|
|
console.error(`Error reading JSON file at ${filePath}:`, error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function writeFileAsync(filePath, content, encoding = 'utf-8') {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
fs.writeFile(filePath, content, encoding, (err) => {
|
|
|
|
if (err) reject(err);
|
|
|
|
else resolve();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-03-21 11:36:11 +08:00
|
|
|
function mapLanguageCode(languageCode, useLowerCase = false) {
|
|
|
|
// http://www.lingoes.net/en/translator/langcode.htm
|
2024-03-21 02:10:38 +08:00
|
|
|
const languageMap = {
|
2024-03-21 11:36:11 +08:00
|
|
|
CHS: 'zh_CN',
|
|
|
|
CHT: 'zh_TW',
|
|
|
|
DE: 'de_DE', // TODO
|
|
|
|
EN: 'en_US',
|
|
|
|
ES: 'es_ES',
|
|
|
|
FR: 'fr_FR',
|
|
|
|
ID: 'id_ID',
|
|
|
|
JP: 'ja_JP',
|
|
|
|
KR: 'ko_KR',
|
|
|
|
PT: 'pt_PT', // TODO
|
|
|
|
RU: 'ru_RU',
|
|
|
|
TH: 'th_TH',
|
|
|
|
VI: 'vi_VN',
|
|
|
|
IT: 'it_IT', // TODO
|
|
|
|
TR: `tr_TR` // TODO
|
2024-03-21 02:10:38 +08:00
|
|
|
};
|
|
|
|
// Check if the language code has a mapping, otherwise use the original code
|
2024-03-21 11:36:11 +08:00
|
|
|
var tus = languageMap[languageCode] || languageCode;
|
|
|
|
if (useLowerCase) {
|
|
|
|
tus = tus.toLowerCase();
|
|
|
|
}
|
|
|
|
return tus;
|
2024-03-21 02:10:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
function getColorByRankLevel(rankLevel) {
|
|
|
|
switch (rankLevel) {
|
2024-03-21 11:36:11 +08:00
|
|
|
case "3", "QUALITY_BLUE":
|
2024-03-21 02:10:38 +08:00
|
|
|
return "blue";
|
2024-03-21 11:36:11 +08:00
|
|
|
case "4", "QUALITY_PURPLE":
|
2024-03-21 02:10:38 +08:00
|
|
|
return "purple";
|
2024-03-21 11:36:11 +08:00
|
|
|
case "5", "QUALITY_ORANGE":
|
2024-03-21 02:10:38 +08:00
|
|
|
return "yellow";
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
2024-03-25 01:39:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
async function fileExists(filePath) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
fs.access(filePath, fs.constants.F_OK, (err) => {
|
|
|
|
if (err) {
|
|
|
|
if (err.code === 'ENOENT') {
|
|
|
|
resolve(false); // File does not exist
|
|
|
|
} else {
|
|
|
|
reject(err); // Other errors
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
resolve(true); // File exists
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// or AssetStudio.CLI.exe "F:\Game\GI\4.0.1_OS\GenshinImpact_Data\StreamingAssets\AssetBundles\blocks" "C:\Users\siakb\Desktop\ASS\MELON" --silent --types "Texture2D" --types "Sprite" --game GI --names "(^Eff_UI_Talent.*)|(^Skill_A_.*)|(^Skill_E_.*)|(^Skill_S_.*)|(^MonsterSkill.*)|(^UI_AchievementIcon_.*)|(^UI_AnimalIcon_.*)|(^UI_AvatarIcon_.*)|(^UI_Buff_Item_.*)|(^UI_Codex_Scenery_.*)|(^UI_Costume_.*)|(^UI_DungeonPic_.*)|(^UI_Emotion.*)|(^UI_EquipIcon_.*)|(^UI_FlycloakIcon_.*)|(^UI_Gacha_AvatarIcon_.*)|(^UI_Gacha_AvatarImg_.*)|(^UI_Gacha_EquipIcon_.*)|(^UI_Gacha_FlycloakIcon_.*)|(^UI_GcgIcon_.*)|(^UI_Gcg_Bg_.*)|(^UI_Gcg_Buff_Common_Element_.*)|(^UI_Gcg_CardBack_.*)|(^UI_Gcg_CardFace_.*)|(^UI_Gcg_Cardtable_.*)|(^UI_Gcg_Char_.*)|(^UI_Gcg_Tag_.*)|(^UI_ItemIcon_.*)|(^UI_MonsterIcon_.*)|(^UI_NameCardIcon_.*)|(^UI_NameCardPic_.*)|(^UI_RelicIcon_.*)|(^UI_Talent_.*)"
|
|
|
|
async function downloadIcon(url, destination, localpb, urlif404 = "", timeout = 7000) {
|
|
|
|
if (await fileExists(destination)) {
|
|
|
|
// Check file size
|
|
|
|
const stats = await fs.promises.stat(destination);
|
|
|
|
if (stats.size === 0) {
|
|
|
|
localpb = ""; // Set localpb to empty if file size is 0KB
|
|
|
|
//console.log(`File exists but has size 0KB: ${destination}`);
|
|
|
|
} else {
|
|
|
|
//console.log(`File already exists at ${destination}. Skipping download.`);
|
|
|
|
}
|
|
|
|
return localpb;
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`File not found ${destination}, downloading from ${url}`);
|
|
|
|
|
|
|
|
const fileStream = fs.createWriteStream(destination);
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const request = https.get(url, response => {
|
|
|
|
if (response.statusCode === 200) {
|
|
|
|
response.pipe(fileStream);
|
|
|
|
fileStream.on('finish', () => {
|
|
|
|
fileStream.close();
|
|
|
|
resolve(localpb);
|
|
|
|
});
|
|
|
|
} else if (urlif404 && urlif404 !== "") {
|
|
|
|
console.log(`Failed to download icon from ${url} (${response.statusCode}). Trying alternative URL: ${urlif404}`);
|
|
|
|
fileStream.close();
|
|
|
|
fs.unlink(destination, async () => {
|
|
|
|
try {
|
|
|
|
await downloadIcon(urlif404, destination, localpb);
|
|
|
|
resolve(localpb);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
fileStream.close();
|
|
|
|
//fs.unlink(destination, () => {}); // Remove partially downloaded file
|
|
|
|
reject(`Failed to download icon ${url} (${response.statusCode})`);
|
|
|
|
}
|
|
|
|
}).on('error', async err => {
|
|
|
|
fileStream.close();
|
|
|
|
fs.unlink(destination, async () => {
|
|
|
|
try {
|
|
|
|
await downloadIcon(urlif404, destination, localpb);
|
|
|
|
resolve(localpb);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Set a timeout for the request
|
|
|
|
request.setTimeout(timeout, () => {
|
|
|
|
request.destroy(); // Abort the request if it exceeds the timeout
|
|
|
|
fileStream.close();
|
|
|
|
fs.unlink(destination, () => { }); // Remove partially downloaded file
|
|
|
|
reject(new Error(`Request timed out after ${timeout} milliseconds`));
|
|
|
|
});
|
|
|
|
});
|
2024-03-21 02:10:38 +08:00
|
|
|
}
|