Skip to content

Commit

Permalink
dynasties support, fix for mod updating ignoring tags
Browse files Browse the repository at this point in the history
  • Loading branch information
Shazbot committed Aug 7, 2024
1 parent 2d21662 commit 0f6cdde
Show file tree
Hide file tree
Showing 21 changed files with 525 additions and 21 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,5 @@ temp/
.yarn/cache/

dumps

sublog.txt
11 changes: 10 additions & 1 deletion locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -381,5 +381,14 @@
"setFolderPathsManuallyPharaoh": "The mod manager tried to get Pharaoh folder locations from Windows Registry, but it couldn't find them! You'll have to set them manually!",
"setFolderPathsManuallyOptionallyPharaoh": "The mod manager automatically found Pharaoh folder paths from the Windows Registry, but you can set them manually here.",
"noMissingFilesFound": "No missing files found!",
"missingFiles": "Missing Files"
"missingFiles": "Missing Files",
"dynasties": "Pharaoh Dynasties",
"mainDynastiesFolder": "The main Dynasties folder that contains Pharaoh.exe, for example C:\\Program Files (x86)\\Steam\\steamapps\\common\\Total War PHARAOH DYNASTIES",
"dynastiesFolder": "Dynasties folder:",
"dynastiesContentFolder": "The Dynasties Steam Workshop content folder named 2951630 (which is the steam ID for Pharaoh Dynasties) that contains mods, for example C:\\Program Files (x86)\\Steam\\steamapps\\workshop\\content\\2951630",
"selectDynastiesFolder": "Select Dynasties Folder",
"setFolderPathsManuallyDynasties": "The mod manager tried to get Pharaoh Dynasties folder locations from Windows Registry, but it couldn't find them! You'll have to set them manually!",
"setFolderPathsManuallyOptionallyDynasties": "The mod manager automatically found Pharaoh Dynasties folder paths from the Windows Registry, but you can set them manually here.",
"chooseNewModTag": "Choose tag for the new mod:",
"upload": "Upload"
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "wh3mm",
"productName": "wh3mm",
"version": "2.7.0",
"version": "2.8.0",
"description": "WH3 Mod Manager",
"main": ".webpack/main",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions src/appConfigFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const removeModDataWeDontSave = (mods: Mod[] | undefined) => {
mod.isDeleted = false;
mod.isMovie = false;
mod.dependencyPacks = [];
mod.tags = [];
}
};

Expand Down
2 changes: 2 additions & 0 deletions src/appData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ for (const supportedGame of supportedGames) {
attila: undefined,
troy: undefined,
pharaoh: undefined,
dynasties: undefined,
};
(appData as AppData).gameToPresets = {
wh2: [],
Expand All @@ -106,6 +107,7 @@ for (const supportedGame of supportedGames) {
attila: [],
troy: [],
pharaoh: [],
dynasties: [],
};

export default appData as AppData;
39 changes: 39 additions & 0 deletions src/appSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ const appSlice = createSlice({
if (removedModData) {
mod.isEnabled = removedModData.isEnabled;
mod.loadOrder = removedModData.loadOrder;
mod.tags = removedModData.tags;
// state.currentPreset.mods.splice(state.currentPreset.mods.indexOf(mod), 1);
// state.currentPreset.mods.splice(removedModData.indexInMods, 0, mod);
state.removedModsData = state.removedModsData.filter(({ modPath }) => modPath != mod.path);
Expand Down Expand Up @@ -560,6 +561,7 @@ const appSlice = createSlice({
indexInMods: state.currentPreset.mods.indexOf(removedMod),
loadOrder: removedMod.loadOrder,
time: Date.now(),
tags: removedMod.tags,
});
state.removedModsCategories[removedMod.path] = removedMod.categories ?? [];

Expand Down Expand Up @@ -587,6 +589,16 @@ const appSlice = createSlice({
!equal(dataMod.reqModIdToName, data.reqModIdToName)
)
dataMod.reqModIdToName = data.reqModIdToName;
if (data.tags) {
if (dataMod.tags.length != data.tags.length) {
// console.log("tags changed:", dataMod.name, dataMod.tags, "->", data.tags);
dataMod.tags = data.tags;
}
if (contentMod.tags.length != data.tags.length) {
// console.log("tags changed:", contentMod.name, contentMod.tags, "->", data.tags);
contentMod.tags = data.tags;
}
}
}
}

Expand All @@ -607,6 +619,16 @@ const appSlice = createSlice({
}

if (data.lastChanged && mod.lastChanged != data.lastChanged) mod.lastChanged = data.lastChanged;
if (data.tags && mod.tags.length != data.tags.length) {
// console.log("tags changed:", mod.name, mod.tags, "->", data.tags);
mod.tags = data.tags;
}

// timeAddedToUserList we get from Steam is always 0, not sure what it's for but it's not actually time of subbing
// if (data.subscriptionTime && mod.subbedTime != data.subscriptionTime) {
// console.log("subbedTime:", mod.subbedTime, "->", data.subscriptionTime);
// mod.subbedTime = data.subscriptionTime;
// }
}
},
setPackHeaderData: (state: AppState, action: PayloadAction<PackHeaderData | PackHeaderData[]>) => {
Expand Down Expand Up @@ -1138,6 +1160,20 @@ const appSlice = createSlice({
createBisectedModListPresets: (state: AppState, action: PayloadAction<boolean>) => {
createBisectedModListPresetsInternal(state, action.payload);
},
setIsModTagPickerOpen: (state: AppState, action: PayloadAction<boolean>) => {
state.isModTagPickerOpen = action.payload;
},
setCurrentModToUpload: (state: AppState, action: PayloadAction<Mod | undefined>) => {
state.currentModToUpload = action.payload;
},
setTagForMod: (state: AppState, action: PayloadAction<{ mod: Mod; tag: string }>) => {
const payloadMod = action.payload.mod;
const payloadTag = action.payload.tag;
const mod = state.currentPreset.mods.find((mod) => mod.path == payloadMod.path);
if (!mod) return;

mod.tags = ["mod", payloadTag];
},
selectCategory: (state: AppState, action: PayloadAction<CategorySelectionPayload>) => {
const { mods, category, selectOperation } = action.payload;

Expand Down Expand Up @@ -1243,6 +1279,9 @@ export const {
setCustomizableMods,
createBisectedModListPresets,
requestGameFolderPaths,
setCurrentModToUpload,
setIsModTagPickerOpen,
setTagForMod,
} = appSlice.actions;

export default appSlice.reducer;
Binary file added src/assets/game_icons/dynasties.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion src/components/GamePathsSetup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const supportedGameToMainGameFolderLocalization: Record<SupportedGames, string>
attila: "mainAttilaFolder",
troy: "mainTroyFolder",
pharaoh: "mainPharaohFolder",
dynasties: "mainDynastiesFolder",
};
const supportedGameToGameFolderLocalization: Record<SupportedGames, string> = {
wh2: "wh2Folder",
Expand All @@ -32,6 +33,7 @@ const supportedGameToGameFolderLocalization: Record<SupportedGames, string> = {
attila: "attilaFolder",
troy: "troyFolder",
pharaoh: "pharaohFolder",
dynasties: "dynastiesFolder",
};
const supportedGameToContentFolderLocalization: Record<SupportedGames, string> = {
wh2: "wh2ContentFolder",
Expand All @@ -40,6 +42,7 @@ const supportedGameToContentFolderLocalization: Record<SupportedGames, string> =
attila: "attilaContentFolder",
troy: "troyContentFolder",
pharaoh: "pharaohContentFolder",
dynasties: "dynastiesContentFolder",
};
const supportedGameToSelectFolderLocalization: Record<SupportedGames, string> = {
wh2: "selectWH2Folder",
Expand All @@ -48,6 +51,7 @@ const supportedGameToSelectFolderLocalization: Record<SupportedGames, string> =
attila: "selectAttilaFolder",
troy: "selectTroyFolder",
pharaoh: "selectPharaohFolder",
dynasties: "selectDynastiesFolder",
};
const supportedGameToSetFolderPathsManuallyLocalization: Record<SupportedGames, string> = {
wh2: "setFolderPathsManuallyWH2",
Expand All @@ -56,6 +60,7 @@ const supportedGameToSetFolderPathsManuallyLocalization: Record<SupportedGames,
attila: "setFolderPathsManuallyAttila",
troy: "setFolderPathsManuallyTroy",
pharaoh: "setFolderPathsManuallyPharaoh",
dynasties: "setFolderPathsManuallyDynasties",
};
const supportedGameToSetFolderPathsManuallyOptionallyLocalization: Record<SupportedGames, string> = {
wh2: "setFolderPathsManuallyOptionallyWH2",
Expand All @@ -64,6 +69,7 @@ const supportedGameToSetFolderPathsManuallyOptionallyLocalization: Record<Suppor
attila: "setFolderPathsManuallyOptionallyAttila",
troy: "setFolderPathsManuallyOptionallyTroy",
pharaoh: "setFolderPathsManuallyOptionallyPharaoh",
dynasties: "setFolderPathsManuallyOptionallyDynasties",
};

const GamePathsSetup = memo(({ isOpen, setIsOpen }: GamePathsSetupProps) => {
Expand All @@ -78,6 +84,8 @@ const GamePathsSetup = memo(({ isOpen, setIsOpen }: GamePathsSetupProps) => {

const localized: Record<string, string> = useContext(localizationContext);

console.log("requestFolderPathsForGame:", requestFolderPathsForGame);

return (
<>
{(isOpen || (isSetAppFolderPathsDone && isAnyPathEmpty) || requestFolderPathsForGame) && (
Expand All @@ -95,7 +103,7 @@ const GamePathsSetup = memo(({ isOpen, setIsOpen }: GamePathsSetupProps) => {
<Modal.Body>
<div className="flex flex-col gap-y-8 gap-x-4 z-10 leading-relaxed dark:text-gray-300 relative font-normal items-center">
<div>
{(isAnyPathEmpty && (
{((isAnyPathEmpty || requestFolderPathsForGame) && (
<p className="m-auto text-center">
{localized[supportedGameToSetFolderPathsManuallyLocalization[currentGame]]}
</p>
Expand Down
2 changes: 2 additions & 0 deletions src/components/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useAppSelector } from "../hooks";
import Sidebar from "./Sidebar";
import ModRows from "./ModRows";
import Categories from "./Categories";
import ModTagPicker from "./ModTagPicker";

const Main = () => {
const currentTab = useAppSelector((state) => state.app.currentTab);
Expand All @@ -16,6 +17,7 @@ const Main = () => {
<div className="ml-3 col-span-2 relative">
<Sidebar />
</div>
<ModTagPicker></ModTagPicker>
</div>
)}
</>
Expand Down
11 changes: 9 additions & 2 deletions src/components/ModDropdownOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Tooltip } from "flowbite-react";
import React, { memo, useCallback, useContext, useState } from "react";
import { setModLoadOrderRelativeTo, toggleAlwaysEnabledMods, toggleAlwaysHiddenMods } from "../appSlice";
import {
setCurrentModToUpload,
setIsModTagPickerOpen,
setModLoadOrderRelativeTo,
toggleAlwaysEnabledMods,
toggleAlwaysHiddenMods,
} from "../appSlice";
import {
FaFolderOpen,
FaExternalLinkAlt,
Expand Down Expand Up @@ -100,7 +106,8 @@ const ModDropdownOptions = memo((props: ModDropdownOptionsProps) => {
);
const uploadMod = useCallback(
(mod: Mod) => {
window.api?.uploadMod(mod);
dispatch(setCurrentModToUpload(mod));
dispatch(setIsModTagPickerOpen(true));
},
[allMods]
);
Expand Down
94 changes: 94 additions & 0 deletions src/components/ModTagPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Modal } from "../flowbite/components/Modal/index";
import React, { memo, useCallback, useContext, useState } from "react";
import { useAppDispatch, useAppSelector } from "../hooks";
import localizationContext from "../localizationContext";
import selectStyle from "../styles/selectStyle";
import Select, { ActionMeta, SingleValue } from "react-select";
import { setIsModTagPickerOpen, setTagForMod } from "../appSlice";

type OptionType = {
value: string;
label: string;
};

const options: OptionType[] = [
"graphical",
"campaign",
"units",
"battle",
"ui",
"maps",
"overhaul",
"compilation",
"cheat",
].map((tag) => ({ value: tag, label: tag }));

const ModTagPicker = memo(() => {
const dispatch = useAppDispatch();

const isModTagPickerOpen = useAppSelector((state) => state.app.isModTagPickerOpen);
const currentModToUpload = useAppSelector((state) => state.app.currentModToUpload);

const [currentTag, setCurrentTag] = useState<string>("graphical");

const onUploadMod = () => {
if (currentModToUpload) {
window.api?.uploadMod({ ...currentModToUpload, tags: ["mod", currentTag] });
dispatch(setIsModTagPickerOpen(false));
}
};

const onClose = useCallback(() => {
dispatch(setIsModTagPickerOpen(false));
}, []);

const onTagChange = (newValue: SingleValue<OptionType>, actionMeta: ActionMeta<OptionType>) => {
if (!newValue) return;
if (!currentModToUpload) return;

console.log(`label: ${newValue.label}, value: ${newValue.value}, action: ${actionMeta.action}`);
if (actionMeta.action === "select-option") {
setCurrentTag(newValue.value);
dispatch(setTagForMod({ mod: currentModToUpload, tag: newValue.value }));
}
};

const localized: Record<string, string> = useContext(localizationContext);

return (
<>
{currentModToUpload && isModTagPickerOpen && (
<Modal
show={isModTagPickerOpen}
onClose={onClose}
size="lg"
position="top-center"
explicitClasses={["mt-8", "modalDontOverflowWindowHeight", "modalGiveChildVisibleOverflow"]}
>
<Modal.Header>{localized.uploadMod}</Modal.Header>
<Modal.Body>
<div className="flex flex-col gap-4">
<span className="text-slate-100 select-none text-center w-full">
{localized.chooseNewModTag}
</span>
<Select
options={options}
styles={selectStyle}
onChange={onTagChange}
defaultValue={options[0]}
></Select>
<button
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded text-sm m-auto "
type="button"
onClick={() => onUploadMod()}
>
{localized.upload}
</button>
</div>
</Modal.Body>
</Modal>
)}
</>
);
});
export default ModTagPicker;
4 changes: 2 additions & 2 deletions src/components/OptionsDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,14 @@ const OptionsDrawer = memo(() => {
<div className="rounded border border-slate-400 h-32 w-32 flex justify-center items-center">
<Select
className="aspect-square m-2 mt-5"
id="languageSelect"
id="gameSelect"
options={availableGames}
styles={selectStyle}
onChange={onGameChange}
isClearable={false}
isSearchable={false}
components={{ SingleValue, DropdownIndicator: null }}
defaultValue={{ value: currentGame, label: currentGame } as OptionType}
value={{ value: currentGame, label: currentGame } as OptionType}
></Select>
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,7 @@ body:not(.disable-row-hover) .row:hover > div:not(.drop-ghost) {
.modalDontOverflowWindowHeight {
max-height: calc(100% - 2rem);
}

.modalGiveChildVisibleOverflow > :first-child {
overflow: visible;
}
Loading

0 comments on commit 0f6cdde

Please sign in to comment.