Skip to content

Commit

Permalink
🚧 wip start building up the runtimefeature initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
effs committed Dec 9, 2022
1 parent 9b7c5db commit dde38ff
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 24 deletions.
67 changes: 52 additions & 15 deletions src/features.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import {
pipe,
} from "fp-ts/lib/function";
import {
fromNullable,
getOrElse,
Option,
} from "fp-ts/lib/Option";
import {
FeatureSet,
FeatureState,
VersionedStaticFeatureSet,
UserControlledFeatureDefaults,
UserControlledFeature,
boolAsFeature,
RuntimeFeatureDefaults,
RuntimeFeatureInitializers,
UserControlledFeatureSet,
RuntimeFeatureSet,
featureAsBool,
RuntimeFeature,
} from "./features.types";
import {
VORTEX_STORE_PATHS,
Expand All @@ -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),
Expand All @@ -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),
};


Expand All @@ -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<boolean> =>
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(
Expand All @@ -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(
Expand All @@ -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),
});

16 changes: 10 additions & 6 deletions src/features.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<FeatureState>): boolean =>
featureState() === FeatureState.Enabled;


//
// Some features are build-time static,
// Others are either lazy or dynamic and only known at runtime,
Expand All @@ -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...
Expand All @@ -51,13 +53,15 @@ export type Feature =
// FeatureSets are what user code uses...

export type StaticFeatureSet = Record<keyof typeof StaticFeature, Lazy<FeatureState>>;
export type VersionedStaticFeatureSet = StaticFeatureSet & Versioned;
// StaticFeatures are constant, no need for defaults

export type RuntimeFeatureSet = Record<keyof typeof RuntimeFeature, Lazy<FeatureState>>;
export type UserControlledFeatureSet = Record<keyof typeof UserControlledFeature, Lazy<FeatureState>>;
export type RuntimeFeatureAvailableFunc = Lazy<boolean>;
export type RuntimeFeatureInitializers = Record<keyof typeof RuntimeFeature, RuntimeFeatureAvailableFunc>;

// StaticFeatures are constant, no need for defaults
export type RuntimeFeatureDefaults = Record<RuntimeFeature, boolean>;
export type UserControlledFeatureSet = Record<keyof typeof UserControlledFeature, Lazy<FeatureState>>;
export type UserControlledFeatureDefaults = Record<UserControlledFeature, boolean>;

export type VersionedStaticFeatureSet = StaticFeatureSet & Versioned;

export type FeatureSet = VersionedStaticFeatureSet & RuntimeFeatureSet & UserControlledFeatureSet;
14 changes: 11 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ import {
storeGetUserControlledFeature,
UserControlledFeature,
FeatureSet,
RuntimeFeatureSet,
RuntimeFeature,
RuntimeFeatureInitializers,
} from "./features";
import {
wrapTestSupported,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 = {
Expand Down

0 comments on commit dde38ff

Please sign in to comment.