Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions Electron/AMAI-release/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ const path = require("path");
const { takeHeapSnapshot } = require("process");
const spawnSync = require("child_process").spawnSync;
const arrayOfFiles = [];

let totalFiles = 0;
let currentFileIndex = 0;

/** uncomment to debbug */
// const ls = spawnSync(
Expand Down Expand Up @@ -33,16 +34,14 @@ const installOnDirectory = async () => {
const args = process.argv.slice(2);
const response = args[0];
const commander = args[1];
const ver = args[2]
const language = args[3]
const installCommander = commander == 1
const vsAICommander = commander == 2
let bj = 'Blizzard.j'
if (vsAICommander) { bj = 'vsai\\Blizzard.j'}

const ver = args[2];
const language = args[3];
const installCommander = commander == 1;
const vsAICommander = commander == 2;
let bj = 'Blizzard.j';
if (vsAICommander) {bj = 'vsai\\Blizzard.j'}
const commonAIPath = `Scripts\\${ver}\\common.ai`
const blizzardPath =`Scripts\\${ver}\\Blizzard.j`

process.send(`#### Installing AMAI for ${ver} Commander ${commander > 0 ? bj : 'None'} forcing ai language to ${language || 'default'} ####`);

// TODO: change to receive array of maps
Expand Down Expand Up @@ -71,8 +70,6 @@ const installOnDirectory = async () => {
return
}



if (language !== '-') {
setLanguage(commonAIPath, language);
if (installCommander) {
Expand All @@ -85,15 +82,25 @@ const installOnDirectory = async () => {
}
}


if(arrayOfFiles) {
totalFiles = arrayOfFiles.length;
//process.send({ type: 'progress', current: currentFileIndex, total: totalFiles });
for (const file of arrayOfFiles) {
/** uncomment to debbug */
// process.send(`path.extname(file): ${path.extname(file)}`);

const ext = path.extname(file).toLowerCase();

if(ext.indexOf(`w3m`) >= 0 || ext.indexOf(`w3x`) >= 0) {
currentFileIndex++;
// Send complete progress data including both current and total
if (process.send) {
process.send({
type: 'progress',
current: currentFileIndex,
total: totalFiles,
});
}
process.send(`#### Installing ${ver} into file: ${file} ####`);
} else {
process.send(`skip file: ${file}`);
Expand Down Expand Up @@ -128,7 +135,7 @@ const installOnDirectory = async () => {
process.send(mpqEditor.error.message)
: process.send(`Resize map hashtable size ${file}`);

const f1AddToMPQ = spawnSync(
const f1AddToMPQ = spawnSync(
`MPQEditor.exe`,
[
'a',
Expand Down Expand Up @@ -178,16 +185,15 @@ const installOnDirectory = async () => {
f1AddVSAIToMPQ.error ?
process.send(f1AddVSAIToMPQ.error.message)
: process.send(`Installing VS Vanilla AI Scripts ${file}`);

}

const f2AddToMPQ = spawnSync(
const f2AddToMPQ = spawnSync(
`MPQEditor.exe`,
[
'a',
file,
`Scripts\\${ver}\\${bj}`,
`Scripts\\Blizzard.j`,
`Scripts\\Blizzard.j`
],
{ encoding : `utf8` }
);
Expand All @@ -206,7 +212,6 @@ const installOnDirectory = async () => {
f2AddToMPQ.error ?
process.send(f2AddToMPQ.error.message)
: process.send(installCommander ? `Installing commander ${file}` : `Installing VS Vanilla AI commander ${file}`);

}

const f3AddToMPQ = spawnSync(
Expand Down Expand Up @@ -239,7 +244,6 @@ const installOnDirectory = async () => {
}
}


function setLanguage(file, language) {
let data = fs.readFileSync(file, 'utf8');
const searchFor = /string language = "([^"]*)"/;
Expand Down
113 changes: 101 additions & 12 deletions Electron/app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const cp = require('child_process');
let win: BrowserWindow = null;
let translations : { [key: string]: string } = {};
let currentLanguage: string = "English";
let defaultPath: string | null = null;
const args = process.argv.slice(1),
serve = args.some(val => val === '--serve');

Expand All @@ -25,13 +26,14 @@ const isDev = () => {
const createWindow = (): BrowserWindow => {

const size = screen.getPrimaryDisplay().workAreaSize;

// Create the browser window.
win = new BrowserWindow({
x: 0,
y: 0,
width: size.width,
height: size.height,
minWidth: 1280,
minHeight: 940,
webPreferences: {
devTools: true,
nodeIntegration: true,
Expand Down Expand Up @@ -76,16 +78,65 @@ const createWindow = (): BrowserWindow => {

const execInstall = async (signal, commander: number = 1, isMap: boolean = false, ver: string = "REFORGED", forceLang: boolean) => {
const controller = new AbortController();
const response = dialog.showOpenDialogSync(win, {
// TODO: add i18n here
title : isMap ? translations["PAGES.ELECTRON.OPEN_MAP"] || '': translations["PAGES.ELECTRON.OPEN_DIR"] || '',
// TODO: Change to let multiples selections when is map
properties: isMap ? ['openFile'] : ['openDirectory'],
// TODO: add i18n here
filters: isMap ? [
let response;
try {
const settingsPath = path.join(app.getPath('userData'), 'settings.json');
if (fs.existsSync(settingsPath)) {
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
defaultPath = settings.defaultPath || null;
console.log('get default Path :',defaultPath);
}
} catch (err) {
console.error('Failed to load default path:', err);
}
// Handle folder mode (isMap = false)
if (!isMap) {
// If default path exists, use it directly
if (defaultPath) {
response = [defaultPath];
} else {
// Show dialog and save selected path as default
response = dialog.showOpenDialogSync(win, {
title: translations["PAGES.ELECTRON.OPEN_DIR"] || '',
properties: ['openDirectory'],
});

// Save the selected path as default if not canceled
if (response && response.length > 0) {
defaultPath = response[0];
console.log('set default Path :',defaultPath);
// Save to settings.json directly in main process
const settingsPath = path.join(app.getPath('userData'), 'settings.json');
const settings = {
defaultPath: defaultPath
};
fs.writeFileSync(settingsPath, JSON.stringify(settings));
}
}
} else {
// Handle map mode (isMap = true)
const documentsPath = app.getPath('documents');
response = dialog.showOpenDialogSync(win, {
title: translations["PAGES.ELECTRON.OPEN_MAP"] || '',
properties: ['openFile'],
filters: [
{ name: translations["PAGES.ELECTRON.MAPFILE"] || '', extensions: ['w3x', 'w3m'] },
] : null,
});
],
// Use default path if available, otherwise open "documents"
defaultPath: defaultPath || documentsPath,
});
// 选择文件后自动将文件所在目录设为默认路径
if (response && response.length > 0) {
const filePath = response[0];
const folderPath = path.dirname(filePath);
defaultPath = folderPath;
const settingsPath = path.join(app.getPath('userData'), 'settings.json');
const settings = { defaultPath: folderPath };
fs.writeFileSync(settingsPath, JSON.stringify(settings));
console.log('Default path updated to:', folderPath);
}
console.log('default Path :',defaultPath);
}

let child;

Expand Down Expand Up @@ -156,10 +207,16 @@ const execInstall = async (signal, commander: number = 1, isMap: boolean = false
}
);


// send messages to modal on front
child.on('message', (message) => {
win.webContents.send('on-install-message', message);
if (typeof message === 'object' && message.type === 'progress') {
// Send progress updates via dedicated channel
console.log('progress:', message);
win.webContents.send('on-install-progress', message);
} else {
// Send regular messages via standard channel
win.webContents.send('on-install-message', message);
}
});

// close modal on process finishes
Expand All @@ -171,6 +228,37 @@ const execInstall = async (signal, commander: number = 1, isMap: boolean = false
}
}


const setupFileOperations = () => {
ipcMain?.handle('file-operations', async (_, { operation, payload }) => {
switch(operation) {
case 'load-default-path':
const settingsPath = path.join(app.getPath('userData'), 'settings.json');
if (fs.existsSync(settingsPath)) {
return JSON.parse(fs.readFileSync(settingsPath, 'utf8')).defaultPath;
}
return null;

case 'select-folder':
const result = dialog.showOpenDialogSync(win, {
title: translations["PAGES.ELECTRON.OPEN_DIR"] || '',
defaultPath: payload?.defaultPath,
properties: ['openDirectory'],
});
return result && result.length > 0 ? result[0] : null;

case 'save-default-path': {
const settingsPath = path.join(app.getPath('userData'), 'settings.json');
fs.writeFileSync(settingsPath, JSON.stringify({ defaultPath: payload }));
return true;
}

default:
throw new Error(`unknow: ${operation}`);
}
});
}

const installProcess = () => {
let signal = {};

Expand Down Expand Up @@ -267,4 +355,5 @@ const installTrans = () => {

init();
installTrans();
setupFileOperations();
installProcess();
30 changes: 25 additions & 5 deletions Electron/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export class AppComponent implements AfterViewChecked {
public active = false;
public couldClose = false;
public messages = [];
public currentFile = 0;
public totalFiles = 0;
public installingText = '';

@ViewChild('logareawrapper') private readonly logContainer: ElementRef;

Expand Down Expand Up @@ -44,16 +47,29 @@ export class AppComponent implements AfterViewChecked {
})
this.cdr.detectChanges();
});


if (electronService.isElectron) {
this.menuService.createMenu();

this.electronService.ipcRenderer.on('on-install-progress', (_, args: { current: number, total: number }) => {
// console.log('totalFiles-in:', args.total, 'currentFile-in:', args.current);
if ( args.total > 0 && this.totalFiles < args.total) {
this.totalFiles = args.total;
}
if (this.currentFile < this.totalFiles) {
this.currentFile++;
this.title = '(' + this.currentFile + '/' + this.totalFiles + ') ' + this.installingText;
}
// console.log('totalFiles-out:', this.totalFiles, 'currentFile-out:', this.currentFile);
this.cdr.detectChanges();
});

// TODO: add 'push notification'/'notification'
this.electronService.ipcRenderer.on('on-install-init', (_, args: InstallModel) => {
console.log('args-install-init', args)
this.translate.get(t_('PAGES.APP.INSTALLING'), {path: args.response}).subscribe((res: string) => {
this.title = res
this.title = '(0/X) ' + res;
this.installingText = res;
});
this.active = true;
this.couldClose = false;
Expand All @@ -77,16 +93,19 @@ export class AppComponent implements AfterViewChecked {
console.log('args-install-empty', args);
this.active = false;
this.couldClose = true;
this.totalFiles = 0;
this.currentFile = 0;
this.cdr.detectChanges();
});

// TODO: add 'push notification'/'notification'
this.electronService.ipcRenderer.on('on-install-exit', (_, args) => {
this.translate.get(t_('PAGES.APP.INSTALL_DONE')).subscribe((res: string) => {
this.title = res;
this.title = '(' + this.currentFile + '/' + this.totalFiles + ')' + ' ' + res;
});
this.couldClose = true;

this.totalFiles = 0;
this.currentFile = 0;
this
.menuService
.changeEnabledMenuState(true);
Expand All @@ -104,7 +123,8 @@ export class AppComponent implements AfterViewChecked {
this.electronService.ipcRenderer.on('on-install-error', (_, args) => {
console.log('args-install-error', args);
this.couldClose = true;

this.totalFiles = 0;
this.currentFile = 0;
this
.menuService
.changeEnabledMenuState(true);
Expand Down
24 changes: 17 additions & 7 deletions Electron/src/app/home/home.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ <h1 class="title">
<div id="imageREF" class="imageContainerREF" #imageREF data-action="Ref" (mouseover)="onMouseEnter($event, 'Ref')" (mouseout)="onMouseLeave($event, 'Ref')" (click)="onClick($event, 'Ref')">
<img id="ImagesREFEnable" src="assets/REF.Enable.png" alt="REFSelected" [ngStyle]="{'display': Images_REF_Shown ? 'block' : 'none'}"/>
<img id="ImagesREFDisable" src="assets/REF.Disable.png" alt="REF" [ngStyle]="{'display': !Images_REF_Shown ? 'block' : 'none'}"/>
<span>1.33+</span>
<span class="reccomendations">Optimal:2.0.4</span>
<span>2.0.3+</span>
<span class="reccomendations">{{ 'PAGES.HOME.REF_BEST_GAME_VERSION' | translate }}</span>
</div>
<div id="imageTFT" class="imageContainerTFT" #imageTFT data-action="Tft" (mouseover)="onMouseEnter($event, 'Tft')" (mouseout)="onMouseLeave($event, 'Tft')" (click)="onClick($event, 'Tft')">
<img id="ImagesTFTEnable" src="assets/TFT.Enable.png" alt="TFTSelected" [ngStyle]="{'display': Images_TFT_Shown ? 'block' : 'none'}"/>
<img id="ImagesTFTDisable" src="assets/TFT.Disable.png" alt="TFT" [ngStyle]="{'display': !Images_TFT_Shown ? 'block' : 'none'}"/>
<span>1.24+</span>
<span class="reccomendations">Optimal:1.24-1.28</span>
<span>1.24e+</span>
<span class="reccomendations">{{ 'PAGES.HOME.TFT_BEST_GAME_VERSION' | translate }}</span>
</div>
<div id="imageROC" class="imageContainerROC" #imageROC data-action="Roc" (mouseover)="onMouseEnter($event, 'Roc')" (mouseout)="onMouseLeave($event, 'Roc')" (click)="onClick($event, 'Roc')">
<img id="ImagesROCEnable" src="assets/ROC.Enable.png" alt="ROCSelected" [ngStyle]="{'display': Images_ROC_Shown ? 'block' : 'none'}"/>
<img id="ImagesROCDisable" src="assets/ROC.Disable.png" alt="ROC" [ngStyle]="{'display': !Images_ROC_Shown ? 'block' : 'none'}"/>
<span>1.24 - 1.31</span>
<span class="reccomendations">Optimal:1.24-1.28</span>
<span>1.24e+ ~ 1.31</span>
<span class="reccomendations">{{ 'PAGES.HOME.ROC_BEST_GAME_VERSION' | translate }}</span>
</div>
</div>

Expand Down Expand Up @@ -50,4 +50,14 @@ <h1 class="title">
<input type="checkbox" class="switch-text" id="ForceLang" [checked]="forcelang" #ForceLang (input)="onInputChange(ForceLang.id)">{{ 'PAGES.HOME.FORCELANG' | translate }}
</label>
</div>
</div>
<div class="default-folder-container" (click)="selectDefaultFolder($event)" *ngIf="defaultPath">
<span class="default-folder-text">
{{ 'PAGES.HOME.DEFAULT_PATH' | translate }}
<button
class="underlined-path"
[title]="defaultPathText"
style="cursor: pointer; display: inline-block; position: relative; z-index: 1; user-select: none; text-decoration: underline;"
>{{defaultPathText}}</button>
</span>
</div>
</div>
Loading