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 {