modmapper-web/slices/plugins.ts

229 lines
6.5 KiB
TypeScript
Raw Normal View History

2022-02-27 06:17:52 +00:00
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
import type { AppState, AppThunk } from "../lib/store"
2022-03-15 05:03:51 +00:00
import { excludedPlugins } from "../lib/plugins";
import { Mod } from "../components/ModData";
2022-02-27 06:17:52 +00:00
export interface Header {
author?: string;
description?: string;
masters: string[];
next_object_id: number;
num_records_and_groups: number;
version: number;
}
export interface Cell {
editor_id?: string;
form_id: number;
is_persistent: boolean;
world_form_id?: number;
x?: 0;
y?: 0;
}
export interface World {
editor_id: string;
form_id: number;
}
export interface ParsedPlugin {
2022-02-27 06:17:52 +00:00
header: Header;
cells: Cell[];
worlds: World[];
}
export interface PluginFile {
parsed?: ParsedPlugin;
2022-02-27 06:17:52 +00:00
filename: string;
lastModified: number;
hash: string;
parseError?: string;
enabled: boolean;
2022-03-12 19:00:40 +00:00
size: number;
2022-02-27 06:17:52 +00:00
}
export interface File {
id: number;
name: string;
file_name: string;
nexus_file_id: number;
mod_id: number;
category?: string;
version?: string;
mod_version?: string;
size: number;
uploaded_at?: number;
has_download_link: boolean;
updated_at: Date;
created_at: Date;
downloaded_at?: Date;
has_plugin: boolean;
unable_to_extract_plugins: boolean;
}
export interface FetchedPlugin {
id: number;
name: string;
hash: string;
file_id: number;
mod_id: number;
version: number;
size: number;
author?: string;
description?: string;
masters: string[];
file_name: string;
file_path: string;
updated_at: Date;
created_at: Date;
}
export interface FetchedCell {
x: 0;
y: 0;
}
export interface PluginsByHashWithMods {
hash: string;
plugins: FetchedPlugin[];
files: File[];
mods: Mod[];
cells: FetchedCell[];
enabled?: boolean;
}
2022-02-27 06:17:52 +00:00
export type PluginsState = {
parsedPlugins: PluginFile[];
fetchedPlugins: PluginsByHashWithMods[];
selectedFetchedPlugin?: PluginsByHashWithMods;
2022-02-27 06:17:52 +00:00
pending: number;
}
const initialState: PluginsState = { parsedPlugins: [], fetchedPlugins: [], pending: 0 };
2022-02-27 06:17:52 +00:00
export const pluginsSlice = createSlice({
name: "plugins",
initialState,
reducers: {
addParsedPlugin: (state: PluginsState, action: PayloadAction<PluginFile>) => ({
...state,
parsedPlugins: [...state.parsedPlugins, action.payload],
}),
addFetchedPlugin: (state: PluginsState, action: PayloadAction<PluginsByHashWithMods>) => ({
...state,
fetchedPlugins: [...state.fetchedPlugins, action.payload],
}),
updateParsedPlugin: (state: PluginsState, action: PayloadAction<PluginFile>) => ({
...state,
parsedPlugins: [...state.parsedPlugins.filter(plugin => plugin.hash !== action.payload.hash), action.payload],
}),
updateFetchedPlugin: (state: PluginsState, action: PayloadAction<PluginsByHashWithMods>) => ({
...state,
fetchedPlugins: [...state.fetchedPlugins.filter(plugin => plugin.hash !== action.payload.hash), action.payload],
}),
setParsedPlugins: (state: PluginsState, action: PayloadAction<PluginFile[]>) => ({
...state,
parsedPlugins: action.payload,
}),
setFetchedPlugins: (state: PluginsState, action: PayloadAction<PluginsByHashWithMods[]>) => ({
...state,
fetchedPlugins: action.payload,
}),
setPending: (state: PluginsState, action: PayloadAction<number>) => ({
...state,
pending: action.payload,
}),
decrementPending: (state: PluginsState, action: PayloadAction<number>) => ({
...state,
pending: state.pending - action.payload,
}),
toggleParsedPlugin: (state: PluginsState, action: PayloadAction<string>) => ({
...state,
parsedPlugins: state.parsedPlugins.map((plugin) => (plugin.filename === action.payload ? { ...plugin, enabled: !plugin.enabled } : plugin)),
}),
toggleFetchedPlugin: (state: PluginsState, action: PayloadAction<string>) => ({
...state,
fetchedPlugins: state.fetchedPlugins.map((plugin) => (plugin.hash === action.payload ? { ...plugin, enabled: !plugin.enabled } : plugin)),
}),
enableAllParsedPlugins: (state: PluginsState) => ({
...state,
parsedPlugins: state.parsedPlugins.map((plugin) => ({ ...plugin, enabled: !plugin.parseError && !excludedPlugins.includes(plugin.filename) && true })),
}),
enableAllFetchedPlugins: (state: PluginsState) => ({
...state,
fetchedPlugins: state.fetchedPlugins.map((plugin) => ({ ...plugin, enabled: true })),
}),
disableAllParsedPlugins: (state: PluginsState) => ({
...state,
parsedPlugins: state.parsedPlugins.map((plugin) => ({ ...plugin, enabled: false })),
}),
disableAllFetchedPlugins: (state: PluginsState) => ({
...state,
fetchedPlugins: state.fetchedPlugins.map((plugin) => ({ ...plugin, enabled: false })),
}),
setSelectedFetchedPlugin: (state: PluginsState, action: PayloadAction<PluginsByHashWithMods | undefined>) => ({
...state,
selectedFetchedPlugin: action.payload,
}),
clearParsedPlugins: (state: PluginsState) => ({
...state,
parsedPlugins: [],
pending: 0,
}),
2022-02-27 06:17:52 +00:00
},
})
export const {
addParsedPlugin,
addFetchedPlugin,
updateParsedPlugin,
updateFetchedPlugin,
setParsedPlugins,
setFetchedPlugins,
setPending,
decrementPending,
toggleParsedPlugin,
toggleFetchedPlugin,
enableAllParsedPlugins,
enableAllFetchedPlugins,
disableAllParsedPlugins,
disableAllFetchedPlugins,
setSelectedFetchedPlugin,
clearParsedPlugins,
} = pluginsSlice.actions;
2022-02-27 06:17:52 +00:00
export const selectPlugins = (state: AppState) => state.plugins
export const applyLoadOrder = (): AppThunk => (dispatch, getState) => {
const { plugins, pluginsTxt } = getState();
const originalPlugins = [...plugins.parsedPlugins];
2022-02-27 06:17:52 +00:00
let newPlugins = [];
for (let line of pluginsTxt.split("\n")) {
let enabled = false;
line = line.trim(); // remove carriage return at end of line
if (line.startsWith("#")) {
continue;
}
if (line.startsWith("*")) {
enabled = true;
line = line.slice(1);
}
const originalIndex = originalPlugins.findIndex((p) => p.filename === line);
if (originalIndex >= 0) {
const original = originalPlugins.splice(originalIndex, 1)[0];
if (original) {
newPlugins.push({ ...original, enabled });
}
}
}
dispatch(setParsedPlugins([...originalPlugins.sort((a, b) => b.lastModified - a.lastModified), ...newPlugins]));
2022-02-27 06:17:52 +00:00
}
export const addParsedPluginInOrder = (plugin: PluginFile): AppThunk => (dispatch) => {
dispatch(updateParsedPlugin(plugin));
2022-02-27 06:17:52 +00:00
dispatch(applyLoadOrder());
}
export default pluginsSlice.reducer