Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type ILibraryOptions } from "../library.type";

export const DEFAULT_LIBRARY_OPTIONS: ILibraryOptions = {
dependencies: [],
runBefore: [],
runAfter: [],
};
23 changes: 22 additions & 1 deletion packages/common/src/library/libraries/library.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
import { type ClearContext, type InitContext } from "../../context";
import { type ILibrary } from "./library.type";
import { RelationshipHandler } from "../relationship/relationship-handler";
import { DEFAULT_LIBRARY_OPTIONS } from "./consts/library-options-default.const";
import { type ILibrary, type ILibraryOptions } from "./library.type";

export abstract class Library implements ILibrary {
protected _relationship: RelationshipHandler;

constructor(rawOptions?: Partial<ILibraryOptions>) {
const options = {
...DEFAULT_LIBRARY_OPTIONS,
...rawOptions,
};

this._relationship = new RelationshipHandler(
options.dependencies,
options.runBefore,
options.runAfter,
);
}

get relationship(): RelationshipHandler {
return this._relationship;
}

abstract get name(): string;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
9 changes: 9 additions & 0 deletions packages/common/src/library/libraries/library.type.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { type ApplicationContext, type ClearContext } from "../../context";
import { type RelationshipHandler } from "../relationship/relationship-handler";

export interface ILibrary {
get name(): string;

get relationship(): RelationshipHandler;

init(context: ApplicationContext): Promise<void>;

clear(context: ClearContext): Promise<void>;
}

export interface ILibraryOptions {
dependencies: symbol[];
runBefore: symbol[];
runAfter: symbol[];
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type LibraryContext } from "../../../context";
import { type ILibrary } from "../../libraries/library.type";
import { type ILibrary } from "../../libraries";

export class LibraryHandle<T extends ILibrary = ILibrary> {
private readonly _symbol: symbol;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ import { BaseLibraryManager } from "./base-library.manager";

export enum DefaultLibrariesEnum {
ASSET_MANAGER,
INPUT,
COMPONENT_SYSTEM,
NETWORK,
GRAPHICS,
INPUT,
NETWORK,
}

const DEFAULT_LIBRARIES: { index: DefaultLibrariesEnum; sym: symbol }[] = [
{ index: DefaultLibrariesEnum.ASSET_MANAGER, sym: ASSET_MANAGER_LIBRARY },
{ index: DefaultLibrariesEnum.COMPONENT_SYSTEM, sym: COMPONENT_SYSTEM_LIBRARY },
{ index: DefaultLibrariesEnum.NETWORK, sym: NETWORK_LIBRARY },
{ index: DefaultLibrariesEnum.GRAPHICS, sym: GRAPHICS_LIBRARY },
{ index: DefaultLibrariesEnum.NETWORK, sym: NETWORK_LIBRARY },
];

export class LibraryManager extends BaseLibraryManager {
Expand Down
30 changes: 30 additions & 0 deletions packages/common/src/library/relationship/relationship-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export class RelationshipHandler {
private readonly _dependencies: symbol[];
private readonly _runBefore: symbol[];
private readonly _runAfter: symbol[];

/**
* Constructor for RelationshipHandler
*
* @param dependencies - Dependencies of the library
* @param runBefore - Libraries needed to run before this one
* @param runAfter - Libraries needed to run after this one
*/
constructor(dependencies: symbol[], runBefore: symbol[], runAfter: symbol[]) {
this._dependencies = dependencies;
this._runBefore = runBefore;
this._runAfter = runAfter;
}

get dependencies(): symbol[] {
return this._dependencies;
}

get runBefore(): symbol[] {
return this._runBefore;
}

get runAfter(): symbol[] {
return this._runAfter;
}
}
5 changes: 5 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
"taze": "taze major -w",
"lint-staged": "lint-staged"
},
"dependencies": {
"@nanoforge/asset-manager": "workspace:^",
"@nanoforge/common": "workspace:^",
"@nanoforge/input": "workspace:^"
},
"devDependencies": {
"@commitlint/cli": "^19.8.0",
"@commitlint/config-conventional": "^19.8.0",
Expand Down
4 changes: 1 addition & 3 deletions packages/core/src/application/nanoforge-application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ export abstract class NanoforgeApplication {
}

public run() {
this._core.run().then(() => {
console.info("Game ended successfully.");
});
this._core.run();
}
}
12 changes: 10 additions & 2 deletions packages/core/src/application/nanoforge-factory.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { AssetManagerLibrary } from "@nanoforge/asset-manager";
import { InputLibrary } from "@nanoforge/input";

import { type IApplicationOptions } from "./application-options.type";
import { NanoforgeClient } from "./nanoforge-client";
import { NanoforgeServer } from "./nanoforge-server";

class NanoforgeFactoryStatic {
createClient(options?: Partial<IApplicationOptions>): NanoforgeClient {
return new NanoforgeClient(options);
const app = new NanoforgeClient(options);
app.useAssetManager(new AssetManagerLibrary());
app.useInput(new InputLibrary());
return app;
}

createServer(options?: Partial<IApplicationOptions>): NanoforgeServer {
return new NanoforgeServer(options);
const app = new NanoforgeServer(options);
app.useAssetManager(new AssetManagerLibrary());
return app;
}
}

Expand Down
17 changes: 15 additions & 2 deletions packages/core/src/common/library/manager/library.manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from "@nanoforge/common";

import { EditableLibraryContext } from "../../context/contexts/library.editable-context";
import { Relationship } from "../relationship-functions";

export class EditableLibraryManager extends LibraryManager {
public set(sym: symbol, library: ILibrary) {
Expand Down Expand Up @@ -58,11 +59,23 @@ export class EditableLibraryManager extends LibraryManager {
this._set(DefaultLibrariesEnum.INPUT, INPUT_LIBRARY, library, new EditableLibraryContext());
}

public getLibraries(): LibraryHandle<ILibrary>[] {
public getLibraries(): LibraryHandle[] {
return this._libraries;
}

public getRunnerLibraries(): LibraryHandle<IRunnerLibrary>[] {
public getInitLibraries(): LibraryHandle[] {
return Relationship.getLibrariesByDependencies(this._libraries);
}

public getExecutionLibraries(): LibraryHandle<IRunnerLibrary>[] {
return Relationship.getLibrariesByRun(this._getRunnerLibraries());
}

public getClearLibraries(): LibraryHandle[] {
return Relationship.getLibrariesByDependencies(this._libraries, true);
}

private _getRunnerLibraries(): LibraryHandle<IRunnerLibrary>[] {
return this._libraries.filter(
(handle) => handle && typeof handle.library["run"] === "function",
) as LibraryHandle<IRunnerLibrary>[];
Expand Down
122 changes: 122 additions & 0 deletions packages/core/src/common/library/relationship-functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { type ILibrary, type LibraryHandle } from "@nanoforge/common";

class RelationshipStatic {
getLibrariesByDependencies(libraries: LibraryHandle[], reverse: boolean = false) {
let response: LibraryHandle[] = [];
for (const library of libraries) {
if (!library) continue;
response = this._pushLibraryWithDependencies(library, response, [], libraries);
}

if (reverse) return response.reverse();
return response;
}

getLibrariesByRun<T extends ILibrary = ILibrary>(libraries: LibraryHandle<T>[]) {
let response: LibraryHandle<T>[] = [];
const dependencies = new Map<symbol, Set<symbol>>(
libraries.map((library) => [library.symbol, new Set<symbol>()]),
);

for (const handle of libraries) {
const key = handle.symbol;

for (const before of handle.library.relationship.runBefore) {
this._pushToDependencies(key, before, dependencies);
}
for (const after of handle.library.relationship.runAfter) {
this._pushToDependencies(after, key, dependencies);
}
}

for (const library of libraries) {
response = this._pushLibraryWithDependenciesRun(
library,
dependencies,
response,
[],
libraries,
);
}
return response;
}

private _pushToDependencies(
key: symbol,
value: symbol,
dependencies: Map<symbol, Set<symbol>>,
): void {
let curr = dependencies.get(key);
if (!curr) curr = new Set();
curr.add(value);
dependencies.set(key, curr);
}

private _pushLibraryWithDependenciesRun<T extends ILibrary = ILibrary>(
handle: LibraryHandle<T>,
dependencies: Map<symbol, Set<symbol>>,
response: LibraryHandle<T>[],
cache: symbol[],
libraries: LibraryHandle<T>[],
): LibraryHandle<T>[] {
const key = handle.symbol;
if (this._symbolIsInList(key, response)) return response;

if (cache.includes(key)) throw new Error("Circular dependencies !");

cache.push(key);

const deps = dependencies.get(key);
if (!deps) throw new Error("Dependencies not found");

for (const dep of deps) {
if (this._symbolIsInList(dep, response)) continue;

const depHandle = libraries.find((lib) => lib?.symbol === dep) as LibraryHandle<T>;
if (!depHandle) throw new Error(`Cannot find library ${dep.toString()}`);

response = this._pushLibraryWithDependenciesRun<T>(
depHandle,
dependencies,
response,
cache,
libraries,
);
}
cache.pop();

response.push(handle);
return response;
}

private _pushLibraryWithDependencies(
handle: LibraryHandle,
response: LibraryHandle[],
cache: symbol[],
libraries: LibraryHandle[],
): LibraryHandle[] {
if (this._symbolIsInList(handle.symbol, response)) return response;

if (cache.includes(handle.symbol)) throw new Error("Circular dependencies !");

cache.push(handle.symbol);
for (const dep of handle.library.relationship.dependencies) {
if (this._symbolIsInList(dep, response)) continue;

const depHandle = libraries.find((lib) => lib?.symbol === dep) as LibraryHandle;
if (!depHandle) throw new Error(`Cannot find library ${dep.toString()}`);

response = this._pushLibraryWithDependencies(depHandle, response, cache, libraries);
}
cache.pop();

response.push(handle);
return response;
}

private _symbolIsInList(sym: symbol, libraries: LibraryHandle[]): boolean {
return libraries.some((lib) => lib.symbol === sym);
}
}

export const Relationship = new RelationshipStatic();
19 changes: 12 additions & 7 deletions packages/core/src/core/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import {
type IRunnerLibrary,
InitContext,
type LibraryHandle,
LibraryStatusEnum,
} from "@nanoforge/common";

import { type ApplicationConfig } from "../application/application-config";
import type { IApplicationOptions } from "../application/application-options.type";
import { type EditableLibraryContext } from "../common/context/contexts/library.editable-context";

export class Core {
private readonly config: ApplicationConfig;
Expand All @@ -28,7 +30,7 @@ export class Core {

public async run(): Promise<void> {
const context = this.getExecutionContext();
const libraries = this.config.libraryManager.getRunnerLibraries();
const libraries = this.config.libraryManager.getExecutionLibraries();
let requestAnimationFrameHandle: number;

const runner = async () => {
Expand All @@ -38,6 +40,7 @@ export class Core {
const render = () => {
if (!context.isRunning) {
clearInterval(intervalHandle);
this.runClear(this.getClearContext());
return;
}
cancelAnimationFrame(requestAnimationFrameHandle);
Expand All @@ -60,20 +63,22 @@ export class Core {
}

private async runInit(context: InitContext): Promise<void> {
for (const handle of this.config.libraryManager.getLibraries()) {
if (handle) await handle.library.init(context);
for (const handle of this.config.libraryManager.getInitLibraries()) {
await handle.library.init(context);
(handle.context as EditableLibraryContext).setStatus(LibraryStatusEnum.LOADED);
}
}

private async runExecute(context: ExecutionContext, libraries: LibraryHandle<IRunnerLibrary>[]) {
for (const handle of libraries) {
if (handle) await handle.library.run(context);
await handle.library.run(context);
}
}

private runClear(context: ClearContext) {
for (const handle of this.config.libraryManager.getLibraries()) {
if (handle) handle.library.clear(context);
private async runClear(context: ClearContext) {
for (const handle of this.config.libraryManager.getClearLibraries()) {
await handle.library.clear(context);
(handle.context as EditableLibraryContext).setStatus(LibraryStatusEnum.CLEAR);
}
}
}
6 changes: 6 additions & 0 deletions packages/core/tsconfig.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
"references": [
{
"path": "../common/tsconfig.build.json"
},
{
"path": "../asset-manager/tsconfig.build.json"
},
{
"path": "../input/tsconfig.build.json"
}
]
}
Loading
Loading