GC-Resources/Tool/book.js
2024-08-31 16:04:29 +08:00

1047 lines
33 KiB
JavaScript

const path = require("path");
const fs = require("fs");
const https = require("https");
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
async function runAvatar(lang, getHashLANG, dlicon = false) {
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`;
// hoyoshit https://upload-os-bbs.mihoyo.com/game_record/genshin/character_icon/ not found Momoka,Linette,Liney,Freminet
var urlIcon = "";
if (dlicon) {
// https://enka.network/ui/${iconName}.png
// https://api.ambr.top/assets/UI/
try {
urlIcon = await downloadIcon(
`../Tool/dump/${iconName}.png`,
`../Tool/icon/avatar/${iconName}.png`,
`/image/game/genshin/avatar/${iconName}.png`,
`https://api.ambr.top/assets/UI/${iconName}.png`
);
} catch (error) {
console.log(error);
}
}
var objAvatar = new Object();
objAvatar["id"] = id;
objAvatar["name"] = name;
objAvatar["rank"] = data.qualityType;
objAvatar["img"] = urlIcon;
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
*/
}
async function runMonster(lang, getHashLANG, dlicon = false) {
const saveMonster = lang + "monster.json";
const getMonster = readJsonFile(
"../Resources/ExcelBinOutput/MonsterExcelConfigData.json"
);
const getMonsterInfo = readJsonFile(
"../Resources/ExcelBinOutput/MonsterDescribeExcelConfigData.json"
);
var dataMonster = [];
var countNoFound = 0;
for (const data of Object.values(getMonster)) {
if (data && data.nameTextMapHash) {
const hash = data.nameTextMapHash;
const id = data.id;
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`;
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 {
//var testus = mName.split(`_`)
infoMonster = getMonsterInfo.find((item) => item.icon.includes(mName));
if (infoMonster) {
iconPath = infoMonster.icon;
//name = getHashLANG[infoMonster.nameTextMapHash] || getHashCN[infoMonster.nameTextMapHash] || mName || `N/A`;
} else {
if (varTus && 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
try {
urlIcon = await downloadIcon(
`../Tool/dump/${iconPath}.png`,
`../Tool/icon/monster/${iconPath}.png`,
`/image/game/genshin/monster/${iconPath}.png`,
`https://api.ambr.top/assets/UI/monster/${iconPath}.png`
);
} catch (error) {
console.log(error);
}
} else {
//console.log(`not found icon, id ${id} with name ${name}`)
countNoFound++;
}
}
var objMonster = new Object();
objMonster["id"] = id;
objMonster["type"] = mType;
objMonster["name"] = name;
objMonster["img"] = urlIcon;
dataMonster.push(objMonster);
} else {
console.log("skip", data);
}
}
fs.writeFileSync(saveMonster, JSON.stringify(dataMonster, null, 2));
dataMonster = []; // cleanup
console.log(`done monster: ${saveMonster} - no found icon ${countNoFound}`);
}
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);
}
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) {
const saveItem = lang + "item.json";
var dataItem = [];
const filePaths = [
"../Resources/ExcelBinOutput/MaterialExcelConfigData.json",
"../Resources/ExcelBinOutput/HomeWorldFurnitureExcelConfigData.json",
];
for (const filePath of filePaths) {
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}
var urlIcon = "";
if (dlicon) {
if (iconPath != "") {
// https://enka.network/ui/
// https://api.ambr.top/assets/UI/furniture
try {
urlIcon = await downloadIcon(
`../Tool/dump/${iconPath}.png`,
`../Tool/icon/item/${iconPath}.png`,
`/image/game/genshin/item/${iconPath}.png`,
`https://api.ambr.top/assets/UI/${iconPath}.png`
);
} catch (error) {
console.log(error);
}
} else {
console.log(`not found iocn ${id} with name ${name}`);
}
}
var objItem = new Object();
objItem["id"] = id;
objItem["name"] = `${name}`;
objItem["type"] = data.itemType;
objItem["rank"] = data.rankLevel;
objItem["img"] = urlIcon;
dataItem.push(objItem);
} else {
console.log("skip", data);
}
}
}
fs.writeFileSync(saveItem, JSON.stringify(dataItem, null, 2));
dataItem = []; // cleanup
console.log(`done item: ` + saveItem);
}
async function runWeapon(lang, getHashLANG, dlicon = false) {
const saveItem = lang + "weapon.json";
var dataItem = [];
const filePaths = ["../Resources/ExcelBinOutput/WeaponExcelConfigData.json"];
for (const filePath of filePaths) {
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`;
if (name.includes(`test`)) {
continue;
}
var subType = data.weaponType;
var iconPath = data.icon;
var urlIcon = "";
if (dlicon) {
if (iconPath != "") {
// https://upload-os-bbs.mihoyo.com/game_record/genshin/equip/
try {
urlIcon = await downloadIcon(
`../Tool/dump/${iconPath}.png`,
`../Tool/icon/weapon/${iconPath}.png`,
`/image/game/genshin/weapon/${iconPath}.png`,
`https://feixiaoqiu.com/static/images/weapon/${iconPath}.png`
);
} catch (error) {
console.log(error);
}
} else {
console.log(`not found iocn ${id} with name ${name}`);
}
}
var objItem = {
id: id,
name: `${name}`,
type_main: data.itemType,
type_sub: subType,
rank: data.rankLevel,
img: urlIcon,
};
dataItem.push(objItem);
} else {
console.log("skip", data);
}
}
}
fs.writeFileSync(saveItem, JSON.stringify(dataItem, null, 2));
dataItem = []; // cleanup
console.log(`done wp: ` + saveItem);
}
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)}`;
}
}
async function runRelic(lang, getHashLANG, dlicon = false) {
// 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`;
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);
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(
`../Tool/dump/${iconPath}.png`,
`../Tool/icon/artifact/${iconPath}.png`,
`/image/game/genshin/artifact/${iconPath}.png`,
`https://upload-os-bbs.mihoyo.com/game_record/genshin/equip/${iconPath}.png`
);
} catch (error) {
console.log(error);
}
} else {
console.log(`not found iocn ${id} with name ${name}`);
}
}
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;
objItem["img"] = urlIcon;
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
if (!dataMappings[mapLanguageCode(lang, true)]) {
dataMappings[mapLanguageCode(lang, true)] = {};
}
const filePaths = [
"../Resources/ExcelBinOutput/AvatarExcelConfigData.json",
"../Resources/ExcelBinOutput/WeaponExcelConfigData.json",
];
for (const filePath of filePaths) {
try {
const getAvatar = await readJsonFileAsync(filePath);
for (const data of Object.values(getAvatar)) {
if (data && data.nameTextMapHash) {
const hash = data.nameTextMapHash;
var id = data.id;
const rank = getColorByRankLevel(
data.qualityType || data.rankLevel.toString()
);
const name = textMapData[hash] || `N/A`;
var nameType = "idk";
if (filePath.includes(`AvatarExcelConfigData`)) {
id = (id % 1000) + 1000;
nameType = textMapData[`4233146695`] || `N/A`;
} else if (filePath.includes(`WeaponExcelConfigData`)) {
nameType = textMapData[`4231343903`] || `N/A`;
}
dataMappings[mapLanguageCode(lang, true)][id] = [
`${name} (${nameType})`,
rank,
];
} else {
console.log("skip", data);
}
}
} catch (error) {
console.error("Error processing file:", error);
}
}
// Type Banner
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
} else {
const langDirectory = `../Tool/resources/${mapLanguageCode(
lang,
false
)}/`;
if (!fs.existsSync(langDirectory)) {
fs.mkdirSync(langDirectory, { recursive: true });
}
const getHashLANG = readJsonFile(
`../Resources/TextMap/TextMap${lang}.json`
);
//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)
//runProp(langDirectory, getHashLANG)
runQuest(langDirectory, getHashLANG)
}
}
if (version == 1) {
await writeFileAsync(
saveMappings,
JSON.stringify(dataMappings, null, 2),
"utf-8"
);
}
}
//runAvatar();
//runScene();
//runMonster();
//runItem();
//runRelic();
//runWeapon();
//runProp();
//runMappings(2);
runMappings(2);
//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();
});
});
}
function mapLanguageCode(languageCode, useLowerCase = false) {
// http://www.lingoes.net/en/translator/langcode.htm
const languageMap = {
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
};
// Check if the language code has a mapping, otherwise use the original code
var tus = languageMap[languageCode] || languageCode;
if (useLowerCase) {
tus = tus.toLowerCase();
}
return tus;
}
function getColorByRankLevel(rankLevel) {
switch (rankLevel) {
case ("3", "QUALITY_BLUE"):
return "blue";
case ("4", "QUALITY_PURPLE"):
return "purple";
case ("5", "QUALITY_ORANGE"):
return "yellow";
default:
return "";
}
}
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\Genshin Impact game\GenshinImpact_Data\StreamingAssets\AssetBundles\blocks" "C:\Users\siakb\Desktop\Project\ASS\MELON\gi\50" --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;
}
var isvaild = isValidUrl(url);
console.log(
`File not found ${destination}, downloading from ${url}, vaild ${isvaild}`
);
if (!isvaild) {
try {
if (await fileExists(url)) {
// Correcting the fs.copyFile call with callback function
fs.copyFile(url, destination, (err) => {
if (err) {
console.log(`switch2 ${url}`);
return "";
}
});
return localpb;
} else {
console.log(`switch1 ${urlif404}`);
//return "";
console.log(`Failed to download icon from ${url} (not found file local). Trying alternative URL: ${urlif404}`);
return await downloadIcon(urlif404, destination, localpb);
}
} catch (error) {
console.error(
`Failed to copy local file ${url} to ${destination}: ${error.message}`,
error
);
return "";
}
} else {
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`));
});
});
}
}
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
}
});
});
}
// Function to check if a string is a valid URL
function isValidUrl(string) {
try {
new URL(string);
return true;
} catch (error) {
return false;
}
}