Skip to content

Commit 65037d3

Browse files
committed
change plugin session injection style
1 parent e99ff82 commit 65037d3

12 files changed

+94
-83
lines changed

esbuild.plugin-host.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ rmSync(OUTDIR, { recursive: true, force: true });
1616
minify: false,
1717
format: "esm",
1818
bundle: true,
19-
19+
packages: 'external',
2020
});
2121
})();

package.json

+16-3
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,28 @@
2020
"runtime": "yarn build:runtime && yarn serve:runtime",
2121
"build": "vite build -c vite.config.web.ts && yarn build:runtime"
2222
},
23+
"files": [
24+
"./types",
25+
"./host",
26+
"./ui",
27+
"./src",
28+
"package.json",
29+
"README.md"
30+
],
31+
"types": "./types/index.d.ts",
32+
"exports": {
33+
"./host/*": "./dist/host/*",
34+
"./ui/*": "./dist/ui/*"
35+
},
2336
"repository": {
2437
"type": "git",
25-
"url": "git+https://github.com/imbateam-gg/titan-reactor.git"
38+
"url": "git+https://github.com/alexpineda/titan-reactor.git"
2639
},
2740
"author": "Alex Pineda <[email protected]>",
2841
"bugs": {
29-
"url": "https://github.com/imbateam-gg/titan-reactor/issues"
42+
"url": "https://github.com/alexpineda/titan-reactor/issues"
3043
},
31-
"homepage": "https://github.com/imbateam-gg/titan-reactor#readme",
44+
"homepage": "https://www.blacksheepwall.tv",
3245
"debug": {
3346
"env": {
3447
"VITE_DEV_SERVER_HOSTNAME": "127.0.0.1",

src/common/types/plugin.ts

-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
import { SessionVariables } from "@core/world/settings-session-store";
2-
import { WorldEvents } from "@core/world/world-events";
3-
import { TypeEmitterProxy } from "@utils/type-emitter";
41
import { FieldDefinition } from "./fields";
52

63
export type PluginConfig = Record<string, FieldDefinition>;
@@ -45,21 +42,6 @@ export interface PluginMetaData extends PluginPackage {
4542
}
4643
}
4744

48-
/**
49-
* These are the injectable services that are available to plugins during a world session.
50-
*/
51-
export interface Injectables {
52-
/**
53-
* Reactive setting values that apply to the active session only.
54-
*/
55-
settings: SessionVariables;
56-
57-
/**
58-
* World events that can be listened to and emitted.
59-
*/
60-
events: TypeEmitterProxy<WorldEvents>;
61-
}
62-
6345
/**
6446
* A plugin that executes in the main process.
6547
*/

src/core/world/api-session.ts

+11-18
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,19 @@ export class ApiSession {
3030
this.#janitor = new Janitor();
3131

3232
this.#events = new WeakRef( events );
33-
this.#plugins = this.#janitor.mop( await createPluginSession( openBW, events ) );
34-
35-
this.#macros = this.#janitor.mop( createMacrosComposer( settings ) );
3633
const eventsProxy = this.#janitor.mop( new TypeEmitterProxy( events ) );
3734
const customEvents = this.#janitor.mop( new TypeEmitter() );
3835

36+
this.#plugins = this.#janitor.mop( await createPluginSession( openBW, events, {
37+
settings: settings.vars,
38+
events: eventsProxy,
39+
customEvents,
40+
game: gameTimeApi
41+
} ) );
42+
43+
this.#macros = this.#janitor.mop( createMacrosComposer( settings ) );
44+
45+
3946
this.#macros.macros.targets.setHandler( ":plugin", {
4047
action: ( action ) =>
4148
this.#plugins.store.operate( action, ( path ) => path.slice( 1 ) ),
@@ -58,28 +65,14 @@ export class ApiSession {
5865
// which is not allowed WITHIN plugins since they are 3rd party, but ok in user macros and sandbox
5966
this.#macros.setContainer(
6067
mix( {
61-
api: gameTimeApi,
68+
game: gameTimeApi,
6269
plugins: borrow( this.#plugins.store.vars ),
6370
settings: borrow( settings.vars ),
6471
events: eventsProxy,
6572
customEvents,
6673
} )
6774
);
6875

69-
this.#janitor.mop(
70-
this.native.injectApi(
71-
mix(
72-
{
73-
settings: settings.vars,
74-
events: eventsProxy,
75-
customEvents,
76-
},
77-
gameTimeApi
78-
)
79-
),
80-
"native.injectApi"
81-
);
82-
8376
this.native.useTryCatchOnHooks =
8477
useSettingsStore.getState().data.utilities.debugMode;
8578
this.#janitor.mop(

src/core/world/create-plugin-session.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ import { WorldEvents } from "./world-events";
1515
import { TypeEmitter, TypeEmitterProxy } from "@utils/type-emitter";
1616
import { normalizePluginConfiguration } from "@utils/function-utils";
1717
import { pluginsStore } from "@stores/plugins-store";
18+
import { PluginSessionContext } from "@plugins/plugin-base";
1819

1920
export type PluginSession = Awaited<ReturnType<typeof createPluginSession>>;
2021

2122
export const createPluginSession = async (
2223
openBW: OpenBW,
23-
_events: TypeEmitter<WorldEvents>
24+
_events: TypeEmitter<WorldEvents>,
25+
sessionContext: PluginSessionContext
2426
) => {
2527
const janitor = new Janitor( "PluginSession" );
2628

@@ -41,7 +43,7 @@ export const createPluginSession = async (
4143
} );
4244

4345
const nativePlugins = janitor.mop(
44-
new PluginSystemNative(),
46+
new PluginSystemNative(sessionContext),
4547
"nativePlugins"
4648
);
4749

src/core/world/plugin-session-store.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { log } from "@ipc/log";
66
import { PluginSystemNative } from "@plugins/plugin-system-native";
77
import { PluginMetaData } from "common/types";
88
import { PluginSystemUI } from "@plugins/plugin-system-ui";
9+
import { PluginSessionContext } from "@plugins/plugin-base";
910

1011
jest.mock( "@ipc/log" );
1112
jest.mock( "@core/global-events" );
@@ -44,6 +45,7 @@ const createBasePlugin = ( _package?: Partial<PluginMetaData> ) => {
4445
};
4546

4647
const plugins = new PluginSystemNative(
48+
{} as PluginSessionContext
4749
// [pluginPackage as unknown as PluginMetaData],
4850
// () => {},
4951
// () => {}

src/core/world/view-controller-composer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { DamageType, Explosion } from "common/enums";
55
import { PerspectiveCamera, Vector3 } from "three";
66
import { GameViewPort } from "../../camera/game-viewport";
77
import { World } from "./world";
8-
import { SceneController } from "@plugins/scene-controller";
8+
import type { SceneController } from "@plugins/scene-controller";
99
import { easeInCubic } from "@utils/function-utils";
1010
import range from "common/utils/range";
1111
import { mixer } from "@audio/main-mixer";

src/plugins/plugin-base.ts

+21-7
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,53 @@
11
import type { GameTimeApi } from "@core/world/game-time-api";
22
import type {
33
FieldDefinition,
4-
Injectables,
54
NativePlugin,
65
PluginConfig,
76
PluginPackage,
87
} from "common/types";
9-
10-
import { log } from "@ipc/log";
118
// import { savePluginsConfig } from "renderer/command-center/ipc/plugins";
129
import { normalizePluginConfiguration } from "@utils/function-utils";
10+
import type { SessionVariables } from "@core/world/settings-session-store";
11+
import type { TypeEmitter, TypeEmitterProxy } from "@utils/type-emitter";
12+
import type { WorldEvents } from "@core/world/world-events";
1313

1414
const structuredClone =
1515
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1616
globalThis.structuredClone ??
1717
( ( x: any ) => JSON.parse( JSON.stringify( x ) ) as unknown );
1818

19-
export interface PluginBase extends NativePlugin, GameTimeApi, Injectables {}
19+
export interface PluginBase extends NativePlugin, GameTimeApi {}
20+
21+
export type PluginSessionContext = {
22+
game: GameTimeApi;
23+
settings: SessionVariables;
24+
events: TypeEmitterProxy<WorldEvents>;
25+
customEvents: TypeEmitter<unknown>;
26+
}
2027

21-
export class PluginBase {
28+
export class PluginBase implements PluginBase {
2229
readonly id: string;
2330
readonly name: string;
2431
isSceneController = false;
2532
#config: PluginConfig = {};
2633

34+
game: GameTimeApi;
35+
settings: SessionVariables;
36+
events: TypeEmitterProxy<WorldEvents>;
37+
2738
/**
2839
* @internal
2940
* Same as config but simplified to [key] = value
3041
*/
3142
#normalizedConfig: Record<string, unknown> = {};
3243

33-
constructor( pluginPackage: PluginPackage ) {
44+
constructor( pluginPackage: PluginPackage, opts: PluginSessionContext ) {
3445
this.id = pluginPackage.id;
3546
this.name = pluginPackage.name;
3647
this.rawConfig = structuredClone( pluginPackage.config ?? {} );
48+
this.game = opts.game;
49+
this.settings = opts.settings;
50+
this.events = opts.events;
3751
}
3852

3953
sendUIMessage: ( message: any ) => void = () => {};
@@ -48,7 +62,7 @@ export class PluginBase {
4862
*/
4963
saveConfigProperty( key: string, value: unknown, persist = true ): void {
5064
if ( !( key in this.#config ) ) {
51-
log.warn(
65+
console.warn(
5266
`Plugin ${this.id} tried to set config key ${key} but it was not found`
5367
);
5468
return undefined;

src/plugins/plugin-system-native.ts

+27-19
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import { withErrorMessage } from "common/utils/with-error-message";
77
import { UI_SYSTEM_CUSTOM_MESSAGE } from "./events";
88
import throttle from "lodash.throttle";
99
import { Janitor } from "three-janitor";
10-
import { mix } from "@utils/object-utils";
1110
import { log } from "@ipc/log";
12-
import { PluginBase } from "./plugin-base";
11+
import { PluginBase, PluginSessionContext } from "./plugin-base";
1312
import { SceneController, VRSceneController } from "./scene-controller";
1413
import lSet from "lodash.set";
14+
import { mix } from "@utils/object-utils";
1515

1616
type PluginsConfigSnapshot = Record<
1717
string,
@@ -28,6 +28,7 @@ export class PluginSystemNative {
2828

2929
#sendCustomUIMessage!: (pluginId: string, message: any) => void;
3030
#compartments = new WeakMap<PluginBase, { globalThis: object }>();
31+
#sessionContext: PluginSessionContext;
3132

3233
/**
3334
* Error trapping is signficantly slower than not using it.
@@ -43,29 +44,36 @@ export class PluginSystemNative {
4344
return this.#plugins.reduce.bind(this.#plugins);
4445
}
4546

47+
constructor( sessionContext: PluginSessionContext ) {
48+
this.#sessionContext = sessionContext;
49+
}
50+
4651
async activatePlugin(
4752
pluginPackage: PluginMetaData,
4853
createCompartment: (env: unknown) => {
4954
globalThis: {
5055
Function: (...args: any[]) => () => object | PluginBase;
5156
};
52-
}
57+
},
58+
sessionContext: PluginSessionContext
5359
) {
5460

61+
//todo: remove this
5562
const compartment = createCompartment({
5663
PluginBase,
5764
SceneController,
5865
VRSceneController,
5966
});
6067

6168
try {
62-
const Plugin = await import(/* @vite-ignore */ pluginPackage.urls.host! );
69+
const Plugin = await import(/* @vite-ignore */pluginPackage.urls.host! );
6370

6471
if (!Plugin) {
6572
throw new Error("Plugin constructor must extend PluginBase");
6673
}
6774

68-
const plugin = new Plugin.default(pluginPackage);
75+
const plugin = new Plugin.default(pluginPackage, sessionContext);
76+
mix(plugin, sessionContext.game);
6977

7078
plugin.isSceneController = pluginPackage.isSceneController;
7179

@@ -95,12 +103,12 @@ export class PluginSystemNative {
95103
async init(
96104
pluginPackages: PluginMetaData[],
97105
msg: (id: string, message: any) => void,
98-
createCompartment: (env: any) => any
106+
createCompartment: (env: any) => any,
99107
) {
100108

101109
log.debug(`@plugin-system-native: init`);
102110
for (const pkg of pluginPackages) {
103-
const plugin = await this.activatePlugin(pkg, createCompartment);
111+
const plugin = await this.activatePlugin(pkg, createCompartment, this.#sessionContext);
104112
if (plugin) {
105113
this.#plugins.push(plugin);
106114
}
@@ -231,8 +239,9 @@ export class PluginSystemNative {
231239
pluginPackages: PluginMetaData[],
232240
createCompartment: (env: any) => any
233241
) {
242+
234243
const additionalPlugins = pluginPackages
235-
.map((p) => this.activatePlugin(p, createCompartment))
244+
.map((p) => this.activatePlugin(p, createCompartment, this.#sessionContext))
236245
.filter(Boolean);
237246

238247
this.#plugins = [...this.#plugins, ...additionalPlugins] as PluginBase[];
@@ -241,17 +250,16 @@ export class PluginSystemNative {
241250
/**
242251
* Temporarily inject an api into all active plugins.
243252
*/
244-
injectApi(object: object) {
245-
mix(PluginBase.prototype, object);
246-
const keys = Object.keys(object);
247-
248-
return () => {
249-
keys.forEach((key) => {
250-
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
251-
delete PluginBase.prototype[key as keyof typeof PluginBase.prototype];
252-
});
253-
};
254-
}
253+
// injectApi(object: object) {
254+
// const keys = Object.keys(object);
255+
256+
// return () => {
257+
// keys.forEach((key) => {
258+
// // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
259+
// delete PluginBase.prototype[key as keyof typeof PluginBase.prototype];
260+
// });
261+
// };
262+
// }
255263

256264
getConfigSnapshot() {
257265
return this.#plugins.reduce((acc, plugin) => {

0 commit comments

Comments
 (0)