Add automatic localizer function matching - Fix for v1.99.6.4

main
peshomir 2024-08-26 14:31:24 +03:00
parent fafefddfb2
commit 388dfb7f0f
3 changed files with 29 additions and 16 deletions

View File

@ -58,7 +58,11 @@ const matchDictionaryExpression = expression => {
// and this matches "a=b+1;", the returned value will be the object: { var1: "a", var2: "b" } // and this matches "a=b+1;", the returned value will be the object: { var1: "a", var2: "b" }
const replaceRawCode = (/** @type {string} */ raw, /** @type {string} */ result, nameMappings) => { const replaceRawCode = (/** @type {string} */ raw, /** @type {string} */ result, nameMappings) => {
const { expression, groups } = generateRegularExpression(raw, false, nameMappings); const { expression, groups } = generateRegularExpression(raw, false, nameMappings);
let replacementString = result.replaceAll("$", "$$").replace(/\w+/g, match => { let localizerCount = 0;
let replacementString = result.replaceAll("$", "$$").replaceAll("__L()", "__L)").replaceAll("__L(", "__L,")
.replace(/\w+/g, match => {
// these would get stored as "___localizer1", "___localizer2", ...
if (match === "__L") match = "___localizer" + (++localizerCount);
return groups.hasOwnProperty(match) ? "$" + groups[match] : match; return groups.hasOwnProperty(match) ? "$" + groups[match] : match;
}); });
//console.log(replacementString); //console.log(replacementString);
@ -77,11 +81,20 @@ const matchRawCode = (/** @type {string} */ raw, nameMappings) => {
const generateRegularExpression = (/** @type {string} */ code, /** @type {boolean} */ isForDictionary, nameMappings) => { const generateRegularExpression = (/** @type {string} */ code, /** @type {boolean} */ isForDictionary, nameMappings) => {
const groups = {}; const groups = {};
let groupNumberCounter = 1; let groupNumberCounter = 1;
let raw = escapeRegExp(code).replace(isForDictionary ? /(?:@@)*(@?)(\w+)/g : /()(\w+)/g, (_match, modifier, word) => { let localizerCount = 0;
let raw = escapeRegExp(code).replaceAll("__L\\(\\)", "___localizer\\)")
// when there is a parameter, add a comma to separate it from the added number
.replaceAll("__L\\(", "___localizer,");
raw = raw.replace(isForDictionary ? /(?:@@)*(@?)(\w+)/g : /()(\w+)/g, (_match, modifier, word) => {
// if a substitution string for the "word" is specified in the nameMappings, use it // if a substitution string for the "word" is specified in the nameMappings, use it
if (nameMappings && nameMappings.hasOwnProperty(word)) return nameMappings[word]; if (nameMappings && nameMappings.hasOwnProperty(word)) return nameMappings[word];
// if the "word" is a number or is one of these specific words, ingore it // if the "word" is a number or is one of these specific words, ingore it
if (/^\d/.test(word) || ["return", "this", "var", "function", "Math"].includes(word)) return word; if (/^\d/.test(word) || ["return", "this", "var", "function", "Math"].includes(word)) return word;
// for easy localizer function matching
else if (word === "___localizer") {
groups[word + (++localizerCount)] = groupNumberCounter++;
return "\\b(L\\(\\d+)"; // would match "L(123", "L(50" and etc. when using "__L("
}
else if (groups.hasOwnProperty(word)) return "\\" + groups[word]; // regex numeric reference to the group else if (groups.hasOwnProperty(word)) return "\\" + groups[word]; // regex numeric reference to the group
else { else {
groups[word] = groupNumberCounter++; groups[word] = groupNumberCounter++;
@ -94,8 +107,8 @@ const generateRegularExpression = (/** @type {string} */ code, /** @type {boolea
[ [
/,this\.(?<gIsTeamGame>\w+)=this\.\w+<7\|\|9===this\.\w+,/g, /,this\.(?<gIsTeamGame>\w+)=this\.\w+<7\|\|9===this\.\w+,/g,
/=function\((\w+),(\w+),\w+\){\1===(?<game>\w+)\.(?<playerId>\w+)\?\w+\(175," "\+\w+\(34,\[(?<playerData>\w+)\.(?<playerNames>\w+)\[\2\]\]\),1001,\2,\w+\(/g, /=function\((\w+),(\w+),\w+\){\1===(?<game>\w+)\.(?<playerId>\w+)\?\w+\(175," "\+\w+\(\d+,\[(?<playerData>\w+)\.(?<playerNames>\w+)\[\2\]\]\),1001,\2,\w+\(/g,
/\w+\.\w+\((\w+)\)\?\w+\.\w+\(\1\)\?(\w+)=(\w+)\(29,\[\2\]\):\(\w+=\w+\.\w+\(\1\),\2=\3\(30,\[\w+\.\w+\.\w+\((?<playerData>\w+)\.(?<rawPlayerNames>\w+)\[(\w+)\],\w+\.\w+\.\w+\(0,10\),150\),(\w+\.\w+\.\w+\()\4\.(?<playerBalances>\w+)\[\6\]\),\7\4\.(?<playerTerritories>\w+)\[\6\]\),\2\]\),\w+=!0\):\2=/g, /\w+\.\w+\((\w+)\)\?\w+\.\w+\(\1\)\?(\w+)=(\w+)\(\d+,\[\2\]\):\(\w+=\w+\.\w+\(\1\),\2=\3\(\d+,\[\w+\.\w+\.\w+\((?<playerData>\w+)\.(?<rawPlayerNames>\w+)\[(\w+)\],\w+\.\w+\.\w+\(0,10\),150\),(\w+\.\w+\.\w+\()\4\.(?<playerBalances>\w+)\[\6\]\),\7\4\.(?<playerTerritories>\w+)\[\6\]\),\2\]\),\w+=!0\):\2=/g,
/function \w+\(\)\{if\(2===(?<game>\w+)\.(?<gameState>\w+)\)return 1;\w+\.\w+\(\),\1\.\2=2,\1\.\w+=\1.\w+\}/g, /function \w+\(\)\{if\(2===(?<game>\w+)\.(?<gameState>\w+)\)return 1;\w+\.\w+\(\),\1\.\2=2,\1\.\w+=\1.\w+\}/g,
/(function \w+\((\w+),(?<fontSize>\w+),(?<x>\w+),(?<y>\w+),(?<canvas>\w+)\){)(\6\.fillText\((?<playerData>\w+)\.(?<playerNames>\w+)\[\2\],\4,\5\)),(\2<(?<game>\w+)\.(?<gHumans>\w+)&&2!==\8\.(?<playerStates>\w+)\[[^}]+)}/g, /(function \w+\((\w+),(?<fontSize>\w+),(?<x>\w+),(?<y>\w+),(?<canvas>\w+)\){)(\6\.fillText\((?<playerData>\w+)\.(?<playerNames>\w+)\[\2\],\4,\5\)),(\2<(?<game>\w+)\.(?<gHumans>\w+)&&2!==\8\.(?<playerStates>\w+)\[[^}]+)}/g,
/\w+\.font=(?<fontGeneratorFunction>\w+\.\w+\.\w+)\(1,\.39\*this\.\w+\),/g /\w+\.font=(?<fontGeneratorFunction>\w+\.\w+\.\w+)\(1,\.39\*this\.\w+\),/g
@ -103,7 +116,7 @@ const generateRegularExpression = (/** @type {string} */ code, /** @type {boolea
const rawCodeSegments = [ const rawCodeSegments = [
"this.@gIsSingleplayer?this.@gLobbyMaxJoin=@SingleplayerMenu.@getSingleplayerPlayerCount():this.gLobbyMaxJoin=this.@gMaxPlayers,this.@gBots=this.gLobbyMaxJoin-this.@gHumans,this.sg=0,", "this.@gIsSingleplayer?this.@gLobbyMaxJoin=@SingleplayerMenu.@getSingleplayerPlayerCount():this.gLobbyMaxJoin=this.@gMaxPlayers,this.@gBots=this.gLobbyMaxJoin-this.@gHumans,this.sg=0,",
"[0]=@L(80),@strs[1]=@game.@gIsSingleplayer?@L(81):@L(82),", "[0]=__L(),@strs[1]=@game.@gIsSingleplayer?__L():__L(),",
"?(this.gB=Math.floor(.0536*aK.fw),g5=aK.g5-4*@uiSizes.@gap-this.gB):", "?(this.gB=Math.floor(.0536*aK.fw),g5=aK.g5-4*@uiSizes.@gap-this.gB):",
`for(a0L=new Array(@game.@gMaxPlayers),a0A.font=a07,@i=game.gMaxPlayers-1;0<=i;i--)a0L[i]=i+1+".",@playerData.@playerNames[i]=aY.qW.tm(playerData.@rawPlayerNames[i],a07,a0W),a0K[i]=Math.floor(a0A.measureText(playerData.playerNames[i]).width);`, `for(a0L=new Array(@game.@gMaxPlayers),a0A.font=a07,@i=game.gMaxPlayers-1;0<=i;i--)a0L[i]=i+1+".",@playerData.@playerNames[i]=aY.qW.tm(playerData.@rawPlayerNames[i],a07,a0W),a0K[i]=Math.floor(a0A.measureText(playerData.playerNames[i]).width);`,
] ]

View File

@ -13,8 +13,8 @@ export default ({ replace, replaceOne, replaceRawCode, dictionary, matchOne, mat
replaceOne(/(\(22,"logo",8,")[^"]+"\)/g, "$1" + assets.smallLogo + "\")"); replaceOne(/(\(22,"logo",8,")[^"]+"\)/g, "$1" + assets.smallLogo + "\")");
// Add FX Client version info to the game version window // Add FX Client version info to the game version window
replaceRawCode(`ar.oa(4,1,new s8(L(254),gameVersion+"<br><a href='"+ah.aC5+"' target='_blank'>"+ah.aC5+"</a>",`, replaceRawCode(`ar.oa(4,1,new s8(__L(),gameVersion+"<br><a href='"+ah.aC5+"' target='_blank'>"+ah.aC5+"</a>",`,
`ar.oa(4,1,new s8(L(254),gameVersion+"<br><a href='"+ah.aC5+"' target='_blank'>"+ah.aC5+"</a>" `ar.oa(4,1,new s8(__L(),gameVersion+"<br><a href='"+ah.aC5+"' target='_blank'>"+ah.aC5+"</a>"
+ "<br><br><b>" + "FX Client v" + fx_version + " " + fx_update + "<br><a href='https://discord.gg/dyxcwdNKwK' target='_blank'>FX Client Discord server</a>" + "<br><br><b>" + "FX Client v" + fx_version + " " + fx_update + "<br><a href='https://discord.gg/dyxcwdNKwK' target='_blank'>FX Client Discord server</a>"
+ "<br><a href='https://github.com/fxclient/FXclient' target='_blank'>Github repository</a></b>",`); + "<br><a href='https://github.com/fxclient/FXclient' target='_blank'>Github repository</a></b>",`);
@ -28,8 +28,8 @@ export default ({ replace, replaceOne, replaceRawCode, dictionary, matchOne, mat
// TODO: test this; it might cause issues with new boat mechanics? // TODO: test this; it might cause issues with new boat mechanics?
{ // Add Troop Density and Maximum Troops in side panel { // Add Troop Density and Maximum Troops in side panel
const { valuesArray } = replaceRawCode(`,labels[5]=L(86),labels[6]=L(87),labels[7]=L(88),(valuesArray=new Array(labels.length))[0]=game.io?`, const { valuesArray } = replaceRawCode(`,labels[5]=__L(),labels[6]=__L(),labels[7]=__L(),(valuesArray=new Array(labels.length))[0]=game.io?`,
`,labels[5]=L(86),labels[6]=L(87),labels[7]=L(88), `,labels[5]=__L(),labels[6]=__L(),labels[7]=__L(),
labels.push("Max Troops", "Density"), // add labels labels.push("Max Troops", "Density"), // add labels
(valuesArray=new Array(labels.length))[0]=game.io?`); (valuesArray=new Array(labels.length))[0]=game.io?`);
replaceOne(new RegExp(/(:(?<valueIndex>\w+)<7\?\w+\.\w+\.\w+\(valuesArray\[\2\]\)):(\w+\.\w+\(valuesArray\[7\]\))}/ replaceOne(new RegExp(/(:(?<valueIndex>\w+)<7\?\w+\.\w+\.\w+\(valuesArray\[\2\]\)):(\w+\.\w+\(valuesArray\[7\]\))}/
@ -42,18 +42,18 @@ export default ({ replace, replaceOne, replaceRawCode, dictionary, matchOne, mat
} }
// Increment win counter on wins // Increment win counter on wins
replaceRawCode(`=function(sE){o.ha(sE,2),b.h9<100?xD(0,L(21,[a8.jx[sE]]),3,sE,ad.gN,ad.kl,-1,!0):xD(0,L(28,[a8.jx[sE]]),3,sE,ad.gN,ad.kl,-1,!0)`, replaceRawCode(`=function(sE){o.ha(sE,2),b.h9<100?xD(0,__L([a8.jx[sE]]),3,sE,ad.gN,ad.kl,-1,!0):xD(0,__L([a8.jx[sE]]),3,sE,ad.gN,ad.kl,-1,!0)`,
`=function(sE){ `=function(sE){
if (${playerId} === sE && !${gIsSingleplayer}) if (${playerId} === sE && !${gIsSingleplayer})
wins_counter++, window.localStorage.setItem("fx_winCount", wins_counter), wins_counter++, window.localStorage.setItem("fx_winCount", wins_counter),
xD(0,"Your Win Count is now " + wins_counter,3,sE,ad.gN,ad.kl,-1,!0); xD(0,"Your Win Count is now " + wins_counter,3,sE,ad.gN,ad.kl,-1,!0);
o.ha(sE,2),b.h9<100?xD(0,L(21,[a8.jx[sE]]),3,sE,ad.gN,ad.kl,-1,!0):xD(0,L(28,[a8.jx[sE]]),3,sE,ad.gN,ad.kl,-1,!0)`); o.ha(sE,2),b.h9<100?xD(0,__L([a8.jx[sE]]),3,sE,ad.gN,ad.kl,-1,!0):xD(0,__L([a8.jx[sE]]),3,sE,ad.gN,ad.kl,-1,!0)`);
{ // Add settings button and win count { // Add settings button and win count
// add settings button // add settings button
replaceRawCode(`,new nQ("☰<br>"+L(193),function(){aD6(3)},aa.ks),new nQ("",function(){at.d5(12)},aa.kg,!1)]`, replaceRawCode(`,new nQ("☰<br>"+__L(),function(){aD6(3)},aa.ks),new nQ("",function(){at.d5(12)},aa.kg,!1)]`,
`,new nQ("☰<br>"+L(193),function(){aD6(3)},aa.ks),new nQ("",function(){at.d5(12)},aa.kg,!1), `,new nQ("☰<br>"+__L(),function(){aD6(3)},aa.ks),new nQ("",function(){at.d5(12)},aa.kg,!1),
new nQ("FX Client settings", function() { WindowManager.openWindow("settings"); }, "rgba(0, 0, 20, 0.5")]`) new nQ("FX Client settings", function() { WindowManager.openWindow("settings"); }, "rgba(0, 0, 20, 0.5")]`)
// set settings button position // set settings button position
replaceRawCode(`aZ.g5.vO(aD3[3].button,x+a0S+gap,a3X+h+gap,a0S,h);`, replaceRawCode(`aZ.g5.vO(aD3[3].button,x+a0S+gap,a3X+h+gap,a0S,h);`,
@ -142,7 +142,7 @@ canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6
{ // Player list and leaderboard filter tabs { // Player list and leaderboard filter tabs
// Draw player list button // Draw player list button
const uiOffset = dictionary.uiSizes + "." + dictionary.gap; const uiOffset = dictionary.uiSizes + "." + dictionary.gap;
const { groups: { drawFunction, topBarHeight } } = replaceOne(/(=1;function (?<drawFunction>\w+)\(\){[^}]+?(?<canvas>\w+)\.fillRect\(0,(?<topBarHeight>\w+),\w+,1\),(?:\3\.fillRect\([^()]+\),)+\3\.font=\w+,(\w+\.\w+)\.textBaseline\(\3,1\),\5\.textAlign\(\3,1\),\3\.fillText\(\w+\(79\),Math\.floor\()(\w+)\/2\),(Math\.floor\(\w+\+\w+\/2\)\));/g, const { groups: { drawFunction, topBarHeight } } = replaceOne(/(=1;function (?<drawFunction>\w+)\(\){[^}]+?(?<canvas>\w+)\.fillRect\(0,(?<topBarHeight>\w+),\w+,1\),(?:\3\.fillRect\([^()]+\),)+\3\.font=\w+,(\w+\.\w+)\.textBaseline\(\3,1\),\5\.textAlign\(\3,1\),\3\.fillText\(\w+\(\d+\),Math\.floor\()(\w+)\/2\),(Math\.floor\(\w+\+\w+\/2\)\));/g,
"$1($6 + $<topBarHeight> - 22) / 2), $7; playerList.drawButton($<canvas>, 12, 12, $<topBarHeight> - 22);"); "$1($6 + $<topBarHeight> - 22) / 2), $7; playerList.drawButton($<canvas>, 12, 12, $<topBarHeight> - 22);");
const buttonBoundsCheck = `utils.isPointInRectangle($<x>, $<y>, ${uiOffset} + 12, ${uiOffset} + 12, ${topBarHeight} - 22, ${topBarHeight} - 22)` const buttonBoundsCheck = `utils.isPointInRectangle($<x>, $<y>, ${uiOffset} + 12, ${uiOffset} + 12, ${topBarHeight} - 22, ${topBarHeight} - 22)`
// Handle player list button and leaderboard tabs mouseDown // Handle player list button and leaderboard tabs mouseDown

View File

@ -1,5 +1,5 @@
const fx_version = '0.6.5.4'; // FX Client Version const fx_version = '0.6.5.5'; // FX Client Version
const fx_update = 'Aug 24'; // FX Client Last Updated const fx_update = 'Aug 26'; // FX Client Last Updated
if (localStorage.getItem("fx_winCount") == undefined || localStorage.getItem("fx_winCount") == null) { if (localStorage.getItem("fx_winCount") == undefined || localStorage.getItem("fx_winCount") == null) {
var wins_counter = 0; var wins_counter = 0;