diff --git a/assets/localization/FR/strings.xml b/assets/localization/FR/strings.xml
new file mode 100644
index 0000000..2632eb4
--- /dev/null
+++ b/assets/localization/FR/strings.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/changelog.txt b/changelog.txt
index 3dedf9a..f6bb0fa 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,4 +1,8 @@
---------------------------------------------------------------------------------------------------
+Version: 1.1.2
+* Collection Load Order Tab was not updated correctly on Load Order Page changes
+* Added French localization
+---------------------------------------------------------------------------------------------------
Version: 1.1.1
* Fixed collection creation
---------------------------------------------------------------------------------------------------
diff --git a/package.json b/package.json
index 94e2b6b..4e82c4d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "game-mount-and-blade-ii-bannerlord-butr",
- "version": "1.1.1",
+ "version": "1.1.2",
"description": "A Vortex extension for Mount and Blade II: Bannerlord mod management.",
"author": "BUTR Team & Nexus Mods",
"license": "GPL-3.0+",
diff --git a/src/blse/events.ts b/src/blse/events.ts
index 9d28ab9..a2c763f 100644
--- a/src/blse/events.ts
+++ b/src/blse/events.ts
@@ -1,6 +1,6 @@
import { actions, types } from 'vortex-api';
import { findBLSEMod } from './utils';
-import { hasSettingsInterfacePrimaryTool } from '../vortex';
+import { hasPersistentBannerlordMods, hasSettingsInterfacePrimaryTool } from '../vortex';
import { GAME_ID } from '../common';
export const didDeployBLSE = (api: types.IExtensionApi): Promise => {
@@ -12,7 +12,8 @@ export const didDeployBLSE = (api: types.IExtensionApi): Promise => {
const primaryTool = state.settings.interface.primaryTool.mountandblade2bannerlord;
- const blseMod = findBLSEMod(state);
+ const mods = hasPersistentBannerlordMods(state.persistent) ? state.persistent.mods.mountandblade2bannerlord : {};
+ const blseMod = findBLSEMod(mods);
if (blseMod && primaryTool === undefined) {
api.store?.dispatch(actions.setPrimaryTool(GAME_ID, 'blse-cli'));
}
@@ -38,7 +39,8 @@ export const didPurgeBLSE = (api: types.IExtensionApi): Promise => {
return Promise.resolve();
}
- const blseMod = findBLSEMod(state);
+ const mods = hasPersistentBannerlordMods(state.persistent) ? state.persistent.mods.mountandblade2bannerlord : {};
+ const blseMod = findBLSEMod(mods);
if (blseMod) {
api.store?.dispatch(actions.setPrimaryTool(GAME_ID, undefined!));
}
diff --git a/src/blse/utils.ts b/src/blse/utils.ts
index 48e0365..7c9a1cf 100644
--- a/src/blse/utils.ts
+++ b/src/blse/utils.ts
@@ -4,7 +4,7 @@ import { IFileInfo } from '@nexusmods/nexus-api/lib';
import { BLSE_MOD_ID, BLSE_URL, GAME_ID } from '../common';
import { hasPersistentBannerlordMods } from '../vortex';
import { LocalizationManager } from '../localization';
-import { IBannerlordMod } from '../types';
+import { IBannerlordMod, IBannerlordModStorage } from '../types';
export const isModActive = (profile: types.IProfile, mod: IBannerlordMod): boolean => {
return profile.modState[mod.id]?.enabled ?? false;
@@ -13,10 +13,7 @@ const isModBLSE = (mod: IBannerlordMod): boolean => {
return mod.type === `bannerlord-blse` || (mod.attributes?.modId === 1 && mod.attributes?.source === `nexus`);
};
-export const findBLSEMod = (state: types.IState): IBannerlordMod | undefined => {
- if (!hasPersistentBannerlordMods(state.persistent)) return undefined;
-
- const mods = state.persistent.mods.mountandblade2bannerlord ?? {};
+export const findBLSEMod = (mods: IBannerlordModStorage): IBannerlordMod | undefined => {
const blseMods: IBannerlordMod[] = Object.values(mods).filter((mod: IBannerlordMod) => isModBLSE(mod));
if (blseMods.length === 0) return undefined;
diff --git a/src/blse/vortex.ts b/src/blse/vortex.ts
index 2bef9fd..74f9154 100644
--- a/src/blse/vortex.ts
+++ b/src/blse/vortex.ts
@@ -1,6 +1,7 @@
import { actions, selectors, types } from 'vortex-api';
import { deployBLSE, downloadBLSE, findBLSEDownload, findBLSEMod, isModActive } from './utils';
import { LocalizationManager } from '../localization';
+import { hasPersistentBannerlordMods } from '../vortex';
const sendNotification = (
api: types.IExtensionApi,
@@ -31,7 +32,8 @@ export const recommendBLSE = (api: types.IExtensionApi): void => {
const profile: types.IProfile | undefined = selectors.activeProfile(state);
- const blseMod = findBLSEMod(state);
+ const mods = hasPersistentBannerlordMods(state.persistent) ? state.persistent.mods.mountandblade2bannerlord : {};
+ const blseMod = findBLSEMod(mods);
if (blseMod) {
// Found but not enabled
const blseIsActive = isModActive(profile, blseMod);
@@ -84,7 +86,8 @@ export const forceInstallBLSE = async (api: types.IExtensionApi): Promise
const profile: types.IProfile | undefined = selectors.activeProfile(state);
- const blseMod = findBLSEMod(state);
+ const mods = hasPersistentBannerlordMods(state.persistent) ? state.persistent.mods.mountandblade2bannerlord : {};
+ const blseMod = findBLSEMod(mods);
if (blseMod) {
// Found but not enabled
const blseIsActive = isModActive(profile, blseMod);
diff --git a/src/butr/utils.ts b/src/butr/utils.ts
index f5be00d..8d0bc0f 100644
--- a/src/butr/utils.ts
+++ b/src/butr/utils.ts
@@ -1,11 +1,10 @@
-import { types } from 'vortex-api';
import { IModAnalyzerRequestModule, IModAnalyzerRequestQuery, IModuleCompatibilityInfoCache } from './types';
import { ModAnalyzerProxy } from './modAnalyzerProxy';
import { versionToString, VortexLauncherManager } from '../launcher';
-export const getCompatibilityScores = async (api: types.IExtensionApi): Promise => {
- const launcherManager = VortexLauncherManager.getInstance(api);
-
+export const getCompatibilityScores = async (
+ launcherManager: VortexLauncherManager
+): Promise => {
const allModules = launcherManager.getAllModules();
const gameVersion = launcherManager.getGameVersionVortex();
diff --git a/src/collections/generalData.ts b/src/collections/generalData.ts
index 07cbf2b..e80c369 100644
--- a/src/collections/generalData.ts
+++ b/src/collections/generalData.ts
@@ -1,4 +1,5 @@
import { selectors, types } from 'vortex-api';
+import { profile } from 'node:console';
import { ICollectionData, ICollectionDataWithGeneralData, ICollectionGeneralData } from './types';
import { genCollectionGeneralLoadOrder, parseCollectionGeneralLoadOrder } from './loadOrder';
import { CollectionParseError } from './errors';
@@ -7,25 +8,19 @@ import { hasPersistentBannerlordMods, hasPersistentLoadOrder } from '../vortex';
import { findBLSEMod, forceInstallBLSE, isModActive } from '../blse';
import { vortexToPersistence } from '../loadOrder';
import { VortexLauncherManager } from '../launcher';
+import { IBannerlordMod, IBannerlordModStorage, VortexLoadOrderStorage } from '../types';
/**
* Assumes that the correct Game ID is active and that the profile is set up correctly.
*/
export const genCollectionGeneralData = (
- api: types.IExtensionApi,
- includedModIds: string[]
+ profile: types.IProfile,
+ loadOrder: VortexLoadOrderStorage,
+ includedMods: IBannerlordModStorage
): Promise => {
- const state = api.getState();
-
- const profile: types.IProfile | undefined = selectors.activeProfile(state);
-
- const loadOrder = hasPersistentLoadOrder(state.persistent) ? state.persistent.loadOrder[profile.id] ?? [] : [];
- const mods = hasPersistentBannerlordMods(state.persistent) ? state.persistent.mods.mountandblade2bannerlord : {};
-
- const includedMods = Object.values(mods).filter((mod) => includedModIds.includes(mod.id));
- const collectionLoadOrder = genCollectionGeneralLoadOrder(loadOrder, includedMods);
+ const collectionLoadOrder = genCollectionGeneralLoadOrder(loadOrder, Object.values(includedMods));
- const blseMod = findBLSEMod(state);
+ const blseMod = findBLSEMod(includedMods);
const hasBLSE = blseMod !== undefined && isModActive(profile, blseMod);
return Promise.resolve({
diff --git a/src/index.ts b/src/index.ts
index ca65d4f..cd145e9 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -13,7 +13,7 @@ import {
SettingsProps,
} from './views';
import { BannerlordGame } from './game';
-import { IAddedFiles } from './types';
+import { IAddedFiles, IBannerlordModStorage } from './types';
import { reducer } from './react';
import { actionsSettings } from './settings';
import {
@@ -32,7 +32,13 @@ import { didDeployLoadOrder, gamemodeActivatedLoadOrder, LoadOrderManager } from
import { didDeployBLSE, didPurgeBLSE, getInstallPathBLSE, installBLSE, isModTypeBLSE, testBLSE } from './blse';
import { VortexLauncherManager } from './launcher';
import { gamemodeActivatedSave } from './save';
-import { addedFilesEvent, getInstallPathModule, isModTypeModule } from './vortex';
+import {
+ addedFilesEvent,
+ getInstallPathModule,
+ hasPersistentBannerlordMods,
+ hasPersistentLoadOrder,
+ isModTypeModule,
+} from './vortex';
import { version } from '../package.json';
// TODO: Better dialogs with settings
@@ -64,11 +70,26 @@ const main = (context: types.IExtensionContext): boolean => {
if (hasContextWithCollectionFeature(context)) {
context.optional.registerCollectionFeature(
/*id:*/ `${GAME_ID}_load_order`,
- /*generate:*/ async (gameId: string, includedMods: string[], _mod: types.IMod) => {
+ /*generate:*/ async (gameId: string, includedModIds: string[], _mod: types.IMod) => {
if (GAME_ID !== gameId) {
return {};
}
- return await genCollectionGeneralData(context.api, includedMods);
+
+ const state = context.api.getState();
+ const profile: types.IProfile | undefined = selectors.activeProfile(state);
+ const loadOrder = hasPersistentLoadOrder(state.persistent) ? state.persistent.loadOrder[profile?.id] ?? [] : [];
+ const mods = hasPersistentBannerlordMods(state.persistent)
+ ? state.persistent.mods.mountandblade2bannerlord
+ : {};
+
+ const includedMods = Object.values(mods)
+ .filter((mod) => includedModIds.includes(mod.id))
+ .reduce((map, obj) => {
+ map[obj.id] = obj;
+ return map;
+ }, {});
+
+ return await genCollectionGeneralData(profile, loadOrder, includedMods);
},
/*parse:*/ async (gameId: string, collection: ICollectionData, _mod: types.IMod) => {
if (GAME_ID !== gameId) {
diff --git a/src/views/CollectionGeneralData/pages/GeneralDataPage.tsx b/src/views/CollectionGeneralData/pages/GeneralDataPage.tsx
index 7efbe6c..ea67fd1 100644
--- a/src/views/CollectionGeneralData/pages/GeneralDataPage.tsx
+++ b/src/views/CollectionGeneralData/pages/GeneralDataPage.tsx
@@ -9,8 +9,10 @@ import { getCompatibilityScores, IModuleCompatibilityInfoCache } from '../../../
import { genCollectionGeneralData } from '../../../collections';
import { useLocalization } from '../../../localization';
import { hasPersistentBannerlordMods, hasPersistentLoadOrder } from '../../../vortex';
+import { useLauncher } from '../../../launcher';
interface IFromState {
+ profile: types.IProfile | undefined;
loadOrder: VortexLoadOrderStorage;
mods: IBannerlordModStorage;
}
@@ -22,23 +24,24 @@ export const BannerlordGeneralDataPage = (props: BannerlordGeneralDataPageProps)
const [hasBLSE, setHasBLSE] = useState(false);
const [persistentLoadOrder, setPersistentLoadOrder] = useState([]);
- const { loadOrder, mods } = useSelector(mapState);
+ const { profile, loadOrder, mods } = useSelector(mapState);
- const context = useContext(MainContext);
+ const launcherManager = useLauncher();
useEffect(() => {
async function setData(): Promise {
- const data = await genCollectionGeneralData(context.api, Object.keys(mods));
+ if (!profile) return;
+ const data = await genCollectionGeneralData(profile, loadOrder, mods);
setHasBLSE(data.hasBLSE);
setPersistentLoadOrder(data.suggestedLoadOrder);
}
setData().catch(() => {});
- }, [context.api, mods]);
+ }, [profile, loadOrder, mods]);
const { localize: t } = useLocalization();
const refreshCompatibilityScores = (): void => {
- getCompatibilityScores(context.api)
+ getCompatibilityScores(launcherManager)
.then((cache) => {
setCompatibilityInfoCache(cache);
})
@@ -90,6 +93,7 @@ const mapState = (state: types.IState): IFromState => {
const loadOrder = hasPersistentLoadOrder(state.persistent) ? state.persistent.loadOrder[profile?.id] ?? [] : [];
const mods = hasPersistentBannerlordMods(state.persistent) ? state.persistent.mods.mountandblade2bannerlord : {};
return {
+ profile,
loadOrder,
mods,
};
diff --git a/src/views/Saves/components/RadioView.tsx b/src/views/Saves/components/RadioView.tsx
index e641949..8b05182 100644
--- a/src/views/Saves/components/RadioView.tsx
+++ b/src/views/Saves/components/RadioView.tsx
@@ -23,6 +23,6 @@ export const RadioView = (props: RadioViewProps): JSX.Element => {
onChange={() => onChange(save)}
/>
) : (
-
+ <>>
);
};
diff --git a/src/views/Saves/pages/SavePage.tsx b/src/views/Saves/pages/SavePage.tsx
index 5c64e4c..fda8721 100644
--- a/src/views/Saves/pages/SavePage.tsx
+++ b/src/views/Saves/pages/SavePage.tsx
@@ -10,6 +10,7 @@ import { actionsSave } from '../../../save';
import { versionToString, VortexLauncherManager } from '../../../launcher';
import { getSaveFromSettings } from '../../../settings';
import { findBLSEMod, isModActive } from '../../../blse';
+import { hasPersistentBannerlordMods } from '../../../vortex';
interface IFromState {
profile: types.IProfile | undefined;
@@ -213,7 +214,8 @@ const mapState = (state: types.IState): IFromState => {
const saveName = profile !== undefined ? getSaveFromSettings(state, profile.id) ?? 'No Save' : 'No Save';
- const blseMod = findBLSEMod(state);
+ const mods = hasPersistentBannerlordMods(state.persistent) ? state.persistent.mods.mountandblade2bannerlord : {};
+ const blseMod = findBLSEMod(mods);
const hasBLSE = blseMod !== undefined && profile !== undefined && isModActive(profile, blseMod);
return {