Skip to content

Commit

Permalink
Fix loading scenarios from local .sdd dir
Browse files Browse the repository at this point in the history
  • Loading branch information
bcdrme committed Nov 24, 2024
1 parent 9456b75 commit c866ca8
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 39 deletions.
79 changes: 48 additions & 31 deletions src/main/content/game/game-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,45 +137,62 @@ export class GameContentAPI extends PrDownloaderAPI<GameVersion> {
return this.parseAis(luaai);
}

public async getScenarios(): Promise<Scenario[]> {
const currentGameVersion = this.installedVersions.at(-1);
assert(currentGameVersion, "No current game version found");
const scenarioImages = await this.getGameFiles(currentGameVersion.packageMd5, "singleplayer/scenarios/**/*.{jpg,png}", false);
const scenarioDefinitions = await this.getGameFiles(currentGameVersion.packageMd5, "singleplayer/scenarios/**/*.lua", true);
const cacheDir = path.join(CONTENT_PATH, "scenario-images");
await fs.promises.mkdir(cacheDir, { recursive: true });
for (const scenarioImage of scenarioImages) {
const data = await fs.promises.readFile(scenarioImage.archivePath);
const buffer = await gunzip(data);
const fileName = path.parse(scenarioImage.fileName).base;
await fs.promises.writeFile(path.join(cacheDir, fileName), buffer);
}
const scenarios: Scenario[] = [];
for (const scenarioDefinition of scenarioDefinitions) {
try {
const scenario = parseLuaTable(scenarioDefinition.data) as Scenario;
if (scenario.imagepath) {
log.debug(`Imagepath: ${scenario.imagepath}`);
scenario.imagepath = path.join(cacheDir, scenario.imagepath).replaceAll("\\", "/");
public async getScenarios(gameVersion: string): Promise<Scenario[]> {
try {
const version = this.installedVersions.find((version) => version.gameVersion === gameVersion);
assert(version, `No installed version found for game version: ${gameVersion}`);
const scenarioImages = await this.getGameFiles(version.packageMd5, "singleplayer/scenarios/**/*.{jpg,png}", false);
const scenarioDefinitions = await this.getGameFiles(version.packageMd5, "singleplayer/scenarios/**/*.lua", true);
const cacheDir = path.join(CONTENT_PATH, "scenario-images");
await fs.promises.mkdir(cacheDir, { recursive: true });
for (const scenarioImage of scenarioImages) {
let buffer: Buffer;
if (scenarioImage.archivePath.endsWith(".gz")) {
const data = await fs.promises.readFile(scenarioImage.archivePath);
buffer = await gunzip(data);
} else {
log.warn(`No imagepath for scenario: ${scenario.title}`);
buffer = await fs.promises.readFile(scenarioImage.archivePath);
}
const fileName = path.parse(scenarioImage.fileName).base;
await fs.promises.writeFile(path.join(cacheDir, fileName), buffer);
}
const scenarios: Scenario[] = [];
for (const scenarioDefinition of scenarioDefinitions) {
try {
const scenario = parseLuaTable(scenarioDefinition.data) as Scenario;
if (scenario.imagepath) {
log.debug(`Imagepath: ${scenario.imagepath}`);
scenario.imagepath = path.join(cacheDir, scenario.imagepath).replaceAll("\\", "/");
} else {
log.warn(`No imagepath for scenario: ${scenario.title}`);
}
scenario.summary = scenario.summary.replace(/\[|\]/g, "");
scenario.briefing = scenario.briefing.replace(/\[|\]/g, "");
scenario.allowedsides = Array.isArray(scenario.allowedsides) && scenario.allowedsides[0] !== "" ? scenario.allowedsides : ["Armada", "Cortext", "Random"];
scenario.startscript = scenario.startscript.slice(1, -1);
scenarios.push(scenario);
} catch (err) {
console.error(`error parsing scenario lua file: ${scenarioDefinition.fileName}`, err);
}
scenario.summary = scenario.summary.replace(/\[|\]/g, "");
scenario.briefing = scenario.briefing.replace(/\[|\]/g, "");
scenario.allowedsides = Array.isArray(scenario.allowedsides) && scenario.allowedsides[0] !== "" ? scenario.allowedsides : ["Armada", "Cortext", "Random"];
scenario.startscript = scenario.startscript.slice(1, -1);
scenarios.push(scenario);
} catch (err) {
console.error(`error parsing scenario lua file: ${scenarioDefinition.fileName}`, err);
}
scenarios.sort((a, b) => a.index - b.index);
return scenarios;
} catch (err) {
log.error(`Error getting scenarios: ${err}`);
return [];
}
scenarios.sort((a, b) => a.index - b.index);
return scenarios;
}

public async uninstallVersionById(gameVersion: string) {
const version = this.installedVersions.find((version) => version.gameVersion === gameVersion);
await this.uninstallVersion(version);
}

public async uninstallVersion(version: GameVersion) {
// TODO: Uninstall game version through prd when prd supports it
removeFromArray(this.installedVersions, version);
assert(!version.packageMd5.endsWith(".sdd"), "Cannot uninstall local/custom game versions");
await fs.promises.rm(path.join(CONTENT_PATH, "packages", `${version.packageMd5}.sdp`));
this.installedVersions = this.installedVersions.filter((version) => version.packageMd5 !== version.packageMd5);
}

/**
Expand Down
5 changes: 2 additions & 3 deletions src/main/services/game.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { GameVersion } from "@main/content/game/game-version";
import { gameContentAPI } from "@main/content/game/game-content";
import { gameAPI } from "@main/game/game";
import { ipcMain } from "electron";
Expand All @@ -12,10 +11,10 @@ function init() {
function registerIpcHandlers(mainWindow: Electron.BrowserWindow) {
// Content
ipcMain.handle("game:downloadGame", (_, version: string) => gameContentAPI.downloadGame(version));
ipcMain.handle("game:getScenarios", () => gameContentAPI.getScenarios());
ipcMain.handle("game:getScenarios", (_, version: string) => gameContentAPI.getScenarios(version));
ipcMain.handle("game:getInstalledVersions", () => gameContentAPI.installedVersions);
ipcMain.handle("game:isVersionInstalled", (_, id: string) => gameContentAPI.isVersionInstalled(id));
ipcMain.handle("game:uninstallVersion", (_, version: GameVersion) => gameContentAPI.uninstallVersion(version));
ipcMain.handle("game:uninstallVersion", (_, version: string) => gameContentAPI.uninstallVersionById(version));

// Game
ipcMain.handle("game:launchScript", (_, script: string) => gameAPI.launchScript(script));
Expand Down
4 changes: 2 additions & 2 deletions src/preload/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ contextBridge.exposeInMainWorld("engine", engineApi);
const gameApi = {
// Content
downloadGame: (version: string): Promise<void> => ipcRenderer.invoke("game:downloadGame", version),
getScenarios: (): Promise<Scenario[]> => ipcRenderer.invoke("game:getScenarios"),
getScenarios: (version: string): Promise<Scenario[]> => ipcRenderer.invoke("game:getScenarios", version),
getInstalledVersions: (): Promise<GameVersion[]> => ipcRenderer.invoke("game:getInstalledVersions"),
isVersionInstalled: (version: string): Promise<boolean> => ipcRenderer.invoke("game:isVersionInstalled", version),
uninstallVersion: (version: GameVersion): Promise<void> => ipcRenderer.invoke("game:uninstallVersion", version),
uninstallVersion: (version: string): Promise<void> => ipcRenderer.invoke("game:uninstallVersion", version),

// Game
launchScript: (script: string): Promise<void> => ipcRenderer.invoke("game:launchScript", script),
Expand Down
36 changes: 36 additions & 0 deletions src/renderer/components/misc/DebugSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@
<Button @click="openStartScript"> Open Latest Start Script </Button>
<Button @click="openSyncLobbyContentTool"> Sync Lobby Content Tool </Button>

<Select
:modelValue="gameStore.selectedGameVersion"
:options="gameListOptions"
optionLabel="gameVersion"
label="Game"
:filter="true"
@update:model-value="onGameSelected"
/>

<Select
:modelValue="enginesStore.selectedEngineVersion"
:options="engineListOptions"
optionLabel="id"
label="Engine"
:filter="true"
class="fullwidth"
@update:model-value="onEngineSelected"
/>

<SyncDataDirsDialog v-model="syncLobbyContentToolOpen" />
</div>
</template>
Expand All @@ -36,6 +55,12 @@ import { useRouter } from "vue-router";
import Button from "@renderer/components/controls/Button.vue";
import Select from "@renderer/components/controls/Select.vue";
import SyncDataDirsDialog from "@renderer/components/misc/SyncDataDirsDialog.vue";
import { useDexieLiveQuery } from "@renderer/composables/useDexieLiveQuery";
import { db } from "@renderer/store/db";
import { gameStore } from "@renderer/store/game.store";
import { enginesStore } from "@renderer/store/engine.store";
import { EngineVersion } from "@main/content/engine/engine-version";
import { GameVersion } from "@main/content/game/game-version";
const active = ref(false);
const syncLobbyContentToolOpen = ref(false);
Expand All @@ -44,6 +69,17 @@ const router = useRouter();
const routes = router.getRoutes().sort((a, b) => a.path.localeCompare(b.path));
const currentRoute = router.currentRoute;
const gameListOptions = useDexieLiveQuery(() => db.gameVersions.toArray());
const engineListOptions = useDexieLiveQuery(() => db.engineVersions.toArray());
async function onEngineSelected(engineVersion: EngineVersion) {
enginesStore.selectedEngineVersion = engineVersion;
}
async function onGameSelected(gameVersion: GameVersion) {
gameStore.selectedGameVersion = gameVersion;
}
async function onRouteSelect(newRoute: string) {
console.log("Navigating to", newRoute);
await router.replace(newRoute);
Expand Down
16 changes: 13 additions & 3 deletions src/renderer/views/singleplayer/scenarios.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ import { gameStore } from "@renderer/store/game.store";
const router = useRouter();
const route = router.currentRoute.value;
//TODO move that to our db
const scenarios = await window.game.getScenarios();
const selectedScenario = ref<Scenario>(scenarios[0]);
const loadedScenarios = await window.game.getScenarios(gameStore.selectedGameVersion.gameVersion);
const scenarios = ref<Scenario[]>(loadedScenarios);
const selectedScenario = ref<Scenario>(scenarios.value[0]);
const map = useDexieLiveQueryWithDeps([selectedScenario], () => db.maps.get(selectedScenario.value?.mapfilename));
Expand All @@ -88,6 +89,15 @@ const selectedDifficulty = ref(difficulties.value.find((dif) => dif.name === sel
const factions = computed(() => selectedScenario.value.allowedsides);
const selectedFaction = ref(factions.value[0]);
watch(
() => gameStore.selectedGameVersion.gameVersion,
async (selectedVersion) => {
const loadedScenarios = await window.game.getScenarios(selectedVersion);
scenarios.value = loadedScenarios;
selectedScenario.value = scenarios.value[0];
}
);
watch(selectedScenario, (newScenario) => {
selectedDifficulty.value = difficulties.value.find((dif) => dif.name === newScenario.defaultdifficulty);
selectedFaction.value = factions.value[0] ?? "Armada";
Expand Down

0 comments on commit c866ca8

Please sign in to comment.