Skip to content

Commit

Permalink
Optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
Aragas committed Apr 20, 2024
1 parent e67d0d4 commit c4ae7f1
Show file tree
Hide file tree
Showing 14 changed files with 150 additions and 247 deletions.
5 changes: 3 additions & 2 deletions src/utils/blse/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ export const installBLSE = async (api: types.IExtensionApi, files: string[]): Pr

const isXbox = isStoreXbox(discovery.store);
const instructions = files
.filter((file: string) => !file.endsWith(path.sep))
.filter((file) => file.includes(isXbox ? BINARY_FOLDER_XBOX : BINARY_FOLDER_STANDARD))
.filter(
(file: string) => !file.endsWith(path.sep) && file.includes(isXbox ? BINARY_FOLDER_XBOX : BINARY_FOLDER_STANDARD)
)
.map<types.IInstruction>((file) => ({
type: 'copy',
source: file,
Expand Down
5 changes: 1 addition & 4 deletions src/utils/blse/modType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,5 @@ export const getInstallPathBLSE = (api: types.IExtensionApi, game: types.IGame):
};

export const isModTypeBLSE = (instructions: types.IInstruction[]): boolean => {
const blseInstruction = instructions.find(
(inst) => inst.type === 'copy' && inst.source && inst.source.endsWith(BLSE_CLI_EXE)
);
return !!blseInstruction;
return instructions.some((inst) => inst.type === 'copy' && inst.source && inst.source.endsWith(BLSE_CLI_EXE));
};
4 changes: 1 addition & 3 deletions src/utils/blse/vortex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ const sendNotification = (
actions: [
{
title: actionTitle,
action: (dismiss: types.NotificationDismiss) => {
action(dismiss);
},
action: action,
},
],
});
Expand Down
128 changes: 36 additions & 92 deletions src/utils/loadOrder/manager.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
/* eslint-disable prettier/prettier */
import React from "react";
import { actions, types, selectors } from "vortex-api";
import { IInvalidResult } from "vortex-api/lib/extensions/file_based_loadorder/types/types";
import {
BannerlordModuleManager,
Utils,
types as vetypes,
} from "@butr/vortexextensionnative";
import {
vortexToLibrary,
libraryToVortex,
libraryVMToVortex,
libraryVMToLibrary,
} from ".";
import { VortexLauncherManager } from "../";
import { GAME_ID } from "../../common";
import { LoadOrderInfoPanel, BannerlordItemRenderer } from "../../views";
import { RequiredProperties, VortexLoadOrderStorage } from "../../types";
import React from 'react';
import { types, selectors } from 'vortex-api';
import { IInvalidResult } from 'vortex-api/lib/extensions/file_based_loadorder/types/types';
import { BannerlordModuleManager, Utils, types as vetypes } from '@butr/vortexextensionnative';
import { vortexToLibrary, libraryToVortex, libraryVMToVortex, libraryVMToLibrary } from '.';
import { VortexLauncherManager } from '../';
import { GAME_ID } from '../../common';
import { LoadOrderInfoPanel, BannerlordItemRenderer } from '../../views';
import { RequiredProperties, VortexLoadOrderStorage } from '../../types';

export class LoadOrderManager implements types.IFBLOGameInfo {
private _api: types.IExtensionApi;
Expand All @@ -37,12 +27,7 @@ export class LoadOrderManager implements types.IFBLOGameInfo {
this._api = api;
this._manager = manager;
this.customItemRenderer = ({ className = '', item }) => (
<BannerlordItemRenderer
api={api}
item={item}
className={className}
key={item.loEntry.id}
/>
<BannerlordItemRenderer api={api} item={item} className={className} key={item.loEntry.id} />
);
const refresh = () => this.forceRefresh();
this.usageInstructions = () => <LoadOrderInfoPanel refresh={refresh} />;
Expand All @@ -51,17 +36,15 @@ export class LoadOrderManager implements types.IFBLOGameInfo {
private forceRefresh = (): void => {
const profileId = selectors.activeProfile(this._api.getState()).id;
const action = {
type: "SET_FB_FORCE_UPDATE",
type: 'SET_FB_FORCE_UPDATE',
payload: {
profileId,
},
};
this._api.store?.dispatch(action);
};

public serializeLoadOrder = (
loadOrder: VortexLoadOrderStorage,
): Promise<void> => {
public serializeLoadOrder = (loadOrder: VortexLoadOrderStorage): Promise<void> => {
const loadOrderConverted = vortexToLibrary(loadOrder);
this._manager.saveLoadOrderVortex(loadOrderConverted);
return Promise.resolve();
Expand All @@ -74,50 +57,39 @@ export class LoadOrderManager implements types.IFBLOGameInfo {
this._manager.setModulesToLaunch(loadOrder);
}
};
private checkSavedLoadOrder = (
autoSort: boolean,
loadOrder: VortexLoadOrderStorage,
): void => {
private checkSavedLoadOrder = (autoSort: boolean, loadOrder: VortexLoadOrderStorage): void => {
const savedLoadOrderIssues = Utils.isLoadOrderCorrect(
loadOrder.map<vetypes.ModuleInfoExtendedWithMetadata>(
(x) => x.data!.moduleInfoExtended,
),
loadOrder.map<vetypes.ModuleInfoExtendedWithMetadata>((x) => x.data!.moduleInfoExtended)
);
if (autoSort && savedLoadOrderIssues.length > 0) {
// If there were any issues with the saved LO, the orderer will sort the LO to the nearest working state
this._api.sendNotification?.({
type: "warning",
type: 'warning',
message: `The Saved Load Order was re-sorted with the default algorithm!\nReasons:\n${savedLoadOrderIssues.join(
`\n *`,
`\n *`
)}`,
});
}
};
private checkOrderByLoadOrderResult = (
autoSort: boolean,
result: vetypes.OrderByLoadOrderResult,
): void => {
private checkOrderByLoadOrderResult = (autoSort: boolean, result: vetypes.OrderByLoadOrderResult): void => {
if (autoSort && result.issues) {
this._api.sendNotification?.({
type: "warning",
type: 'warning',
message: `The Saved Load Order was re-sorted with the default algorithm!\nReasons:\n${result.issues.join(
`\n`,
`\n`
)}`,
});
}
};
private checkResult = (
autoSort: boolean,
result: vetypes.OrderByLoadOrderResult,
): result is RequiredProperties<
vetypes.OrderByLoadOrderResult,
"orderedModuleViewModels"
> => {
result: vetypes.OrderByLoadOrderResult
): result is RequiredProperties<vetypes.OrderByLoadOrderResult, 'orderedModuleViewModels'> => {
if (!result || !result.orderedModuleViewModels || !result.result) {
if (autoSort) {
// The user is not expecting a sort operation, so don't give the notification
this._api.sendNotification?.({
type: "error",
type: 'error',
message: `Failed to correct the Load Order! Keeping the original list as-is.`,
});
}
Expand All @@ -127,17 +99,11 @@ export class LoadOrderManager implements types.IFBLOGameInfo {
};
private getExcludedLoadOrder = (
loadOrder: vetypes.LoadOrder,
result: vetypes.OrderByLoadOrderResult,
result: vetypes.OrderByLoadOrderResult
): vetypes.LoadOrder => {
const excludedLoadOrder = Object.entries(
loadOrder,
).reduce<vetypes.LoadOrder>((arr, curr) => {
const excludedLoadOrder = Object.entries(loadOrder).reduce<vetypes.LoadOrder>((arr, curr) => {
const [id, entry] = curr;
if (
result.orderedModuleViewModels?.find(
(x) => x.moduleInfoExtended.id === entry.id,
)
) {
if (result.orderedModuleViewModels?.find((x) => x.moduleInfoExtended.id === entry.id)) {
arr[id] = entry;
}
return arr;
Expand All @@ -152,12 +118,9 @@ export class LoadOrderManager implements types.IFBLOGameInfo {
this._manager.refreshModules();

// Get the saved Load Order
const allModules = this._manager.getAllModules();
const savedLoadOrder = this._manager.loadLoadOrderVortex();
const savedLoadOrderVortex = libraryToVortex(
this._api,
this._manager.getAllModules(),
savedLoadOrder,
);
const savedLoadOrderVortex = libraryToVortex(this._api, allModules, savedLoadOrder);

this.checkSavedLoadOrder(autoSort, savedLoadOrderVortex);

Expand All @@ -175,45 +138,26 @@ export class LoadOrderManager implements types.IFBLOGameInfo {

// Use the sorted to closest valid state Load Order
if (autoSort) {
const loadOrderVortex = libraryVMToVortex(
this._api,
result.orderedModuleViewModels,
);
const loadOrderVortex = libraryVMToVortex(this._api, result.orderedModuleViewModels);
this.setParameters(libraryVMToLibrary(result.orderedModuleViewModels));
return Promise.resolve(loadOrderVortex);
}

// Do not use the sorted LO, but take the list of modules. It excludes modules that are not usable
const excludedSavedLoadOrder = this.getExcludedLoadOrder(
savedLoadOrder,
result,
);
const excludedSavedLoadOrder = this.getExcludedLoadOrder(savedLoadOrder, result);
this.setParameters(excludedSavedLoadOrder);
return Promise.resolve(
libraryToVortex(
this._api,
this._manager.getAllModules(),
excludedSavedLoadOrder,
),
);
return Promise.resolve(libraryToVortex(this._api, allModules, excludedSavedLoadOrder));
};

public validate = (
_prev: VortexLoadOrderStorage,
curr: VortexLoadOrderStorage,
): Promise<types.IValidationResult> => {
const modules = (curr || []).flatMap<vetypes.ModuleInfoExtendedWithMetadata>(
(entry) =>
entry.data && entry.enabled ? entry.data.moduleInfoExtended : [],
public validate = (_prev: VortexLoadOrderStorage, curr: VortexLoadOrderStorage): Promise<types.IValidationResult> => {
const modules = (curr || []).flatMap<vetypes.ModuleInfoExtendedWithMetadata>((entry) =>
entry.data && entry.enabled ? entry.data.moduleInfoExtended : []
);
//const validationManager = ValidationManager.fromVortex(curr);

const invalidResults = Array<IInvalidResult>();
for (const enabledModule of modules) {
const loadOrderIssues = BannerlordModuleManager.validateLoadOrder(
modules,
enabledModule,
);
const loadOrderIssues = BannerlordModuleManager.validateLoadOrder(modules, enabledModule);
for (const issue of loadOrderIssues) {
invalidResults.push({
id: issue.target.id,
Expand All @@ -228,8 +172,8 @@ export class LoadOrderManager implements types.IFBLOGameInfo {
invalidResults.length === 0
? undefined!
: {
invalid: invalidResults,
},
invalid: invalidResults,
}
);
};
}
14 changes: 8 additions & 6 deletions src/utils/loadOrder/persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import { fs, selectors, types } from 'vortex-api';
import { GAME_ID, LOAD_ORDER_SUFFIX } from '../../common';
import { PersistenceLoadOrderStorage } from '../../types';

const getLoadOrderFileName = (api: types.IExtensionApi): string => {
const profileId = selectors.activeProfile(api.getState()).id;
const getLoadOrderFileName = (profileId: string): string => {
return `${profileId}${LOAD_ORDER_SUFFIX}`;
};

const getLoadOrderFilePath = (api: types.IExtensionApi): string => {
const loadOrderFileName = getLoadOrderFileName(api);
const getLoadOrderFilePath = (api: types.IExtensionApi, loadOrderFileName: string): string => {
return path.join(selectors.installPathForGame(api.getState(), GAME_ID), loadOrderFileName);
};

Expand All @@ -20,7 +18,9 @@ const getLoadOrderFilePath = (api: types.IExtensionApi): string => {
*/
export const readLoadOrder = (api: types.IExtensionApi): PersistenceLoadOrderStorage => {
try {
const loFilePath = getLoadOrderFilePath(api);
const profileId = selectors.activeProfile(api.getState()).id;
const loFileName = getLoadOrderFileName(profileId);
const loFilePath = getLoadOrderFilePath(api, loFileName);
const fileContents = fs.readFileSync(loFilePath, 'utf8');
return JSON.parse(fileContents);
} catch {
Expand All @@ -35,7 +35,9 @@ export const readLoadOrder = (api: types.IExtensionApi): PersistenceLoadOrderSto
*/
export const writeLoadOrder = (api: types.IExtensionApi, loadOrder: PersistenceLoadOrderStorage): void => {
try {
const loFilePath = getLoadOrderFilePath(api);
const profileId = selectors.activeProfile(api.getState()).id;
const loFileName = getLoadOrderFileName(profileId);
const loFilePath = getLoadOrderFilePath(api, loFileName);
//await fs.ensureDirWritableS(path.dirname(loFilePath));
fs.writeFileSync(loFilePath, JSON.stringify(Object.values(loadOrder), null, 2), { encoding: 'utf8' });
} catch {
Expand Down
3 changes: 1 addition & 2 deletions src/utils/module/modType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ export const getInstallPathModule = (api: types.IExtensionApi, game: types.IGame
};

export const isModTypeModule = (instructions: types.IInstruction[]): boolean => {
const copyInstructions = instructions.filter((instr) => instr.type === 'copy');
return !!copyInstructions.find((instr) => instr.destination?.endsWith(SUBMODULE_FILE));
return instructions.some((instr) => instr.type === 'copy' && instr.destination?.endsWith(SUBMODULE_FILE));
};
4 changes: 2 additions & 2 deletions src/utils/moduleUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export const getModIds = (api: types.IExtensionApi, moduleId: string): getModIds
if (!mod.attributes || !mod.attributes['subModsIds']) {
return arr;
}
const subModsIds: string[] = mod.attributes['subModsIds'];
if (subModsIds.includes(moduleId)) {
const subModsIds: Set<string> = new Set(mod.attributes['subModsIds']);
if (subModsIds.has(moduleId)) {
arr.push({
id: mod.attributes['modId'],
source: mod.attributes['source'],
Expand Down
2 changes: 2 additions & 0 deletions src/utils/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
BANNERLORD_EXE_LAUNCHER,
} from '../common';

// TODO: Reuse tool creation code

const addDiscoveredTool = (api: types.IExtensionApi, tool: types.IDiscoveredTool) => {
return api.store?.dispatch(actions.addDiscoveredTool(GAME_ID, tool.id, tool, false));
};
Expand Down
4 changes: 2 additions & 2 deletions src/utils/util.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { fs, types, util } from 'vortex-api';
import { EPICAPP_ID, GOG_IDS, STEAMAPP_ID, XBOX_ID } from '../common';

export const getPathExistsAsync = (path: string): Promise<boolean> => {
export const getPathExistsAsync = async (path: string): Promise<boolean> => {
return fs
.statAsync(path)
.then(() => true)
.catch(() => false);
};

export const findGame = (): Promise<types.IGameStoreEntry> => {
export const findGame = async (): Promise<types.IGameStoreEntry> => {
return util.GameStoreHelper.findByAppId([EPICAPP_ID, STEAMAPP_ID.toString(), ...GOG_IDS, XBOX_ID]);
};
16 changes: 4 additions & 12 deletions src/utils/validationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,14 @@ import { VortexLoadOrderStorage } from '../types';
export class ValidationManager implements vetypes.IValidationManager {
static fromVortex = (loadOrder: VortexLoadOrderStorage): ValidationManager => {
return new ValidationManager((moduleId: string): boolean => {
try {
const module = loadOrder.find((x) => x.id === moduleId);
return !!module && module.enabled;
} catch {
return false;
}
const module = loadOrder.find((x) => x.id === moduleId);
return !!module && module.enabled;
});
};
static fromLibrary = (loadOrder: vetypes.LoadOrder): ValidationManager => {
return new ValidationManager((moduleId: string): boolean => {
try {
const module = loadOrder[moduleId];
return !!module && module.isSelected;
} catch {
return false;
}
const module = loadOrder[moduleId];
return !!module && module.isSelected;
});
};

Expand Down
Loading

0 comments on commit c4ae7f1

Please sign in to comment.