From dde38ffe020030438358fd3ae261d2a363b85f50 Mon Sep 17 00:00:00 2001 From: Auska <13802421+effs@users.noreply.github.com> Date: Fri, 9 Dec 2022 04:03:52 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20wip=20start=20building=20up=20th?= =?UTF-8?q?e=20runtimefeature=20initialization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features.ts | 67 +++++++++++++++++++++++++++++++++---------- src/features.types.ts | 16 +++++++---- src/index.ts | 14 +++++++-- 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/src/features.ts b/src/features.ts index 82ca88f..0355e50 100644 --- a/src/features.ts +++ b/src/features.ts @@ -1,6 +1,11 @@ import { pipe, } from "fp-ts/lib/function"; +import { + fromNullable, + getOrElse, + Option, +} from "fp-ts/lib/Option"; import { FeatureSet, FeatureState, @@ -8,9 +13,11 @@ import { UserControlledFeatureDefaults, UserControlledFeature, boolAsFeature, - RuntimeFeatureDefaults, + RuntimeFeatureInitializers, UserControlledFeatureSet, RuntimeFeatureSet, + featureAsBool, + RuntimeFeature, } from "./features.types"; import { VORTEX_STORE_PATHS, @@ -29,15 +36,16 @@ export * from "./features.types"; // Default setup export const BaselineFeatureSetForTests: FeatureSet = { - fromVersion: `0.9.5`, + fromVersion: `0.9.6`, REDmodding: constant(FeatureState.Disabled), REDmodLoadOrder: constant(FeatureState.Disabled), REDmodAutoconversionTag: constant(FeatureState.Enabled), + REDmoddingDLC: constant(FeatureState.Enabled), REDmodAutoconvertArchives: constant(FeatureState.Disabled), }; export const StaticFeaturesForStartup: VersionedStaticFeatureSet = { - fromVersion: `0.9.5`, + fromVersion: `0.9.6`, REDmodding: constant(FeatureState.Enabled), REDmodLoadOrder: constant(FeatureState.Enabled), REDmodAutoconversionTag: constant(FeatureState.Disabled), @@ -48,11 +56,8 @@ export const StaticFeaturesForStartup: VersionedStaticFeatureSet = { // Helpers for the store so we don't repeat this everywhere // -export const DefaultEnabledStateForRuntimeFeatures: RuntimeFeatureDefaults = { -}; - export const DefaultEnabledStateForUserControlledFeatures: UserControlledFeatureDefaults = { - [UserControlledFeature.REDmodAutoconvertArchives]: false, + [UserControlledFeature.REDmodAutoconvertArchives]: featureAsBool(FeatureState.Disabled), }; @@ -67,6 +72,24 @@ interface StoreUtil { // Subtlety here: get will get the full state, but set only gets the slice. Should reconsider. +These actually shouldn't be stored in persistent store, only session. that way +we can safely poll once at startup +export const storeGetRuntimeFeature = + (storeUtil: StoreUtil, feature: RuntimeFeature, vortexState: unknown): Option => + pipe( + storeUtil.getSafe( + vortexState, + [...VORTEX_STORE_PATHS.settings, feature], + undefined, + ), + fromNullable, + ); + +const storeSetRuntimeFeature = + (storeUtil: StoreUtil, feature: RuntimeFeature, v2077SubtreeOfVortexState: object, value: boolean): object => + storeUtil.setSafe(v2077SubtreeOfVortexState, [feature], value); + + export const storeGetUserControlledFeature = (storeUtil: StoreUtil, feature: UserControlledFeature, vortexState: unknown): boolean => storeUtil.getSafe( @@ -90,11 +113,24 @@ export const storeSetUserControlledFeature = // just a bit more explicit. // -const runtimeFeatureGetters = - (vortexExtApi: VortexExtensionApi, storeUtil: StoreUtil): RuntimeFeatureSet => ({ - }); +const makeRuntimeFeatureGetters = ( + vortexExtApi: VortexExtensionApi, + storeUtil: StoreUtil, + runtimeFeatureInitializers: RuntimeFeatureInitializers, +): RuntimeFeatureSet => ({ + REDmoddingDLC: () => + pipe( + storeGetRuntimeFeature( + storeUtil, + RuntimeFeature.REDmoddingDlc, + vortexExtApi.store.getState(), + ), + getOrElse( + boolAsFeature, + ), +}); -const userControlledFeatureGetters = +const makeUserControlledFeatureGetters = (vortexExtApi: VortexExtensionApi, storeUtil: StoreUtil): UserControlledFeatureSet => ({ REDmodAutoconvertArchives: () => pipe( @@ -108,12 +144,13 @@ const userControlledFeatureGetters = }); export const MakeCompleteRuntimeFeatureSet = ( - staticFeatures: VersionedStaticFeatureSet, vortexExtApi: VortexExtensionApi, - storeUtil: StoreUtil, // JFC peer dependencies + storeUtil: StoreUtil, + staticFeatures: VersionedStaticFeatureSet, + runtimeFeatureInitializers: RuntimeFeatureInitializers, ): FeatureSet => ({ ...staticFeatures, - ...runtimeFeatureGetters(vortexExtApi, storeUtil), - ...userControlledFeatureGetters(vortexExtApi, storeUtil), + ...makeRuntimeFeatureGetters(vortexExtApi, storeUtil, runtimeFeatureInitializers), + ...makeUserControlledFeatureGetters(vortexExtApi, storeUtil), }); diff --git a/src/features.types.ts b/src/features.types.ts index e307277..2f03e46 100644 --- a/src/features.types.ts +++ b/src/features.types.ts @@ -17,10 +17,12 @@ export const enum FeatureState { export const boolAsFeature = (currentState: boolean): FeatureState => (currentState ? FeatureState.Enabled : FeatureState.Disabled); +export const featureAsBool = (featureState: FeatureState): boolean => + featureState === FeatureState.Enabled; + export const IsFeatureEnabled = (featureState: Lazy): boolean => featureState() === FeatureState.Enabled; - // // Some features are build-time static, // Others are either lazy or dynamic and only known at runtime, @@ -34,7 +36,7 @@ export const enum StaticFeature { } export const enum RuntimeFeature { - REDmoddingDLC = `v2077_feature_redmodding_dlc_available`, + REDmoddingDlc = `v2077_feature_redmodding_dlc_available`, } // Need to be underscored since it isn't always just a string... thanks react... @@ -51,13 +53,15 @@ export type Feature = // FeatureSets are what user code uses... export type StaticFeatureSet = Record>; +export type VersionedStaticFeatureSet = StaticFeatureSet & Versioned; +// StaticFeatures are constant, no need for defaults + export type RuntimeFeatureSet = Record>; -export type UserControlledFeatureSet = Record>; +export type RuntimeFeatureAvailableFunc = Lazy; +export type RuntimeFeatureInitializers = Record; -// StaticFeatures are constant, no need for defaults -export type RuntimeFeatureDefaults = Record; +export type UserControlledFeatureSet = Record>; export type UserControlledFeatureDefaults = Record; -export type VersionedStaticFeatureSet = StaticFeatureSet & Versioned; export type FeatureSet = VersionedStaticFeatureSet & RuntimeFeatureSet & UserControlledFeatureSet; diff --git a/src/index.ts b/src/index.ts index f91ca02..8e7d668 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,6 +39,9 @@ import { storeGetUserControlledFeature, UserControlledFeature, FeatureSet, + RuntimeFeatureSet, + RuntimeFeature, + RuntimeFeatureInitializers, } from "./features"; import { wrapTestSupported, @@ -174,6 +177,14 @@ const prepStartHooks = // This is the main function Vortex will run when detecting the game extension. const main = (vortexExt: VortexExtensionContext): boolean => { + const runtimeFeatureSet: RuntimeFeatureInitializers = { + [RuntimeFeature.REDmoddingDlc]: () => + isREDmoddingDlcAvailable, + }; + + const fullFeatureSetAvailablePostStartup = + MakeCompleteRuntimeFeatureSet(StaticFeaturesForStartup, vortexExt.api, vortexApiLib.util); + const MaybeREDmodTools = IsFeatureEnabled(StaticFeaturesForStartup.REDmodding) ? REDmoddingTools.available.tools @@ -206,9 +217,6 @@ const main = (vortexExt: VortexExtensionContext): boolean => { ? REDmoddingTools.GameExeModded.parameters : []; - const fullFeatureSetAvailablePostStartup = - MakeCompleteRuntimeFeatureSet(StaticFeaturesForStartup, vortexExt.api, vortexApiLib.util); - // Ok, now we have everything in hand to register our stuff with Vortex const vortexGameParams = {