Skip to content

Commit

Permalink
Merge pull request #29 from NarraLeaf/dev_nomen
Browse files Browse the repository at this point in the history
narraleaf-react-0.0.4
  • Loading branch information
helloyork authored Oct 4, 2024
2 parents fc7642c + 47829e3 commit a449111
Show file tree
Hide file tree
Showing 28 changed files with 659 additions and 449 deletions.
18 changes: 18 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## [0.0.4] - 2024/10/01

### Fixed

- `liveGame.newGame` does not reset the game state
- deserializing does not trigger repainting
- Some methods in `Control` are working incorrectly
- Some image components cannot update correctly

### Changed

- `scene.backgroundImageState` is deprecated, use `scene.backgroundImage` instead
- Now applying of transformations and transitions are separated, you can now apply both at the same time
- Deprecated `contentNode.initChild`
- `liveGame.newGame`, `liveGame.deserialize` and `liveGame.serialize` now does not require a gameState instance

## [0.0.3] - 2024/10/01

### Added
Expand All @@ -16,6 +32,8 @@
### Fixed

- New game does not reset the game state
- Positions cannot handle number 0
- Components does not flush after applying transformations

## [0.0.3-beta.1] - 2024-09-30

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "narraleaf-react",
"version": "0.0.3",
"version": "0.0.4",
"description": "A React visual novel player framework",
"main": "./dist/main.js",
"types": "./dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/game/nlcore/action/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class Action<ContentNodeType = any, Callee = LogicAction.GameElement> {
public executeAction(_state: GameState): CalledActionResult | Awaitable<CalledActionResult, any> {
return {
type: this.type as any,
node: this.contentNode,
node: this.contentNode.getChild(),
};
}

Expand Down
7 changes: 6 additions & 1 deletion src/game/nlcore/action/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,12 @@ export const ImageActionTypes = {
applyTransform: "image:applyTransform",
init: "image:init",
dispose: "image:dispose",
/**
* @deprecated
*/
setTransition: "image:setTransition",
applyTransition: "image:applyTransition",
flush: "image:flush",
} as const;
export type ImageActionContentType = {
[K in typeof ImageActionTypes[keyof typeof ImageActionTypes]]:
Expand All @@ -84,7 +88,8 @@ export type ImageActionContentType = {
K extends "image:dispose" ? [] :
K extends "image:setTransition" ? [ITransition | null] :
K extends "image:applyTransition" ? [ITransition] :
any;
K extends "image:flush" ? [] :
any;
}
/* Condition */
export const ConditionActionTypes = {
Expand Down
5 changes: 0 additions & 5 deletions src/game/nlcore/action/actionable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ export class Actionable<
return null;
}

/**@internal */
public fromData(_: StateData): this {
return this;
}

/**@internal */
public fromChained(chained: Proxied<GameElement, Chained<LogicAction.Actions>>): LogicAction.Actions[] {
return chained.getActions();
Expand Down
160 changes: 95 additions & 65 deletions src/game/nlcore/action/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,64 @@ export class CharacterAction<T extends typeof CharacterActionTypes[keyof typeof
});
return awaitable;
}
return super.executeAction(state);

throw super.unknownType();
}
}

export class SceneAction<T extends typeof SceneActionTypes[keyof typeof SceneActionTypes] = typeof SceneActionTypes[keyof typeof SceneActionTypes]>
extends TypedAction<SceneActionContentType, T, Scene> {
static ActionTypes = SceneActionTypes;

static handleSceneInit(sceneAction: SceneAction, state: GameState, awaitable: Awaitable<CalledActionResult, any>) {
if (sceneAction.callee._liveState.active) {
return {
type: sceneAction.type,
node: sceneAction.contentNode.getChild()
};
}
sceneAction.callee._liveState.active = true;

state
.registerSrcManager(sceneAction.callee.srcManager)
.addScene(sceneAction.callee);

SceneAction.registerEventListeners(sceneAction.callee, state, () => {
awaitable.resolve({
type: sceneAction.type,
node: sceneAction.contentNode.getChild()
});
state.stage.next();
});

return awaitable;
}

static registerEventListeners(scene: Scene, state: GameState, onInit?: () => void) {
scene.events.once("event:scene.unmount", () => {
state.offSrcManager(scene.srcManager);
});

scene.events.once("event:scene.mount", () => {
if (scene.state.backgroundMusic) {
SoundAction.initSound(state, scene.state.backgroundMusic);
scene.events.emit("event:scene.setBackgroundMusic",
scene.state.backgroundMusic,
scene.config.backgroundMusicFade
);
}
});

scene.events.once("event:scene.imageLoaded", () => {
const initTransform = scene.getInitTransform();
scene.events.any("event:scene.initTransform", initTransform).then(() => {
if (onInit) {
onInit();
}
});
});
}

public executeAction(state: GameState): CalledActionResult | Awaitable<CalledActionResult, any> {
if (this.type === SceneActionTypes.action) {
return super.executeAction(state);
Expand Down Expand Up @@ -129,41 +179,8 @@ export class SceneAction<T extends typeof SceneActionTypes[keyof typeof SceneAct
});
return awaitable;
} else if (this.type === SceneActionTypes.init) {
if (this.callee._liveState.active) {
return super.executeAction(state);
}
this.callee._liveState.active = true;

const awaitable = new Awaitable<CalledActionResult, any>(v => v);
state
.registerSrcManager(this.callee.srcManager)
.addScene(this.callee);

this.callee.events.once("event:scene.unmount", () => {
state.offSrcManager(this.callee.srcManager);
});

this.callee.events.once("event:scene.mount", () => {
if (this.callee.state.backgroundMusic) {
SoundAction.initSound(state, this.callee.state.backgroundMusic);
this.callee.events.emit("event:scene.setBackgroundMusic",
this.callee.state.backgroundMusic,
this.callee.config.backgroundMusicFade
);
}
});

this.callee.events.once("event:scene.imageLoaded", () => {
const initTransform = this.callee.getInitTransform();
this.callee.events.any("event:scene.initTransform", initTransform).then(() => {
awaitable.resolve({
type: this.type,
node: this.contentNode.getChild()
});
state.stage.next();
});
});
return awaitable;
return SceneAction.handleSceneInit(this, state, awaitable);
} else if (this.type === SceneActionTypes.exit) {
this.callee._liveState.active = false;

Expand Down Expand Up @@ -266,10 +283,10 @@ export class ImageAction<T extends typeof ImageActionTypes[keyof typeof ImageAct
state.stage.next();
});
return awaitable;
}

if (this.type === ImageActionTypes.setSrc) {
} else if (this.type === ImageActionTypes.setSrc) {
this.callee.state.src = (this.contentNode as ContentNode<ImageActionContentType["image:setSrc"]>).getContent()[0];
state.logger.debug("Image - Set Src", this.callee.state.src);

state.stage.update();
return super.executeAction(state);
} else if ([
Expand All @@ -283,10 +300,7 @@ export class ImageAction<T extends typeof ImageActionTypes[keyof typeof ImageAct
if (this.type === ImageActionTypes.hide) {
this.callee.state.display = false;
}
return {
type: this.type,
node: this.contentNode.getChild()
};
return super.executeAction(state) as CalledActionResult;
}));
const transform = (this.contentNode as ContentNode<ImageActionContentType["image:show"]>).getContent()[1];

Expand All @@ -311,12 +325,6 @@ export class ImageAction<T extends typeof ImageActionTypes[keyof typeof ImageAct
state.disposeImage(this.callee);
this.callee._$setDispose();
return super.executeAction(state);
} else if (this.type === ImageActionTypes.setTransition) {
this.callee.events.emit(
"event:image.setTransition",
(this.contentNode as ContentNode<ImageActionContentType["image:setTransition"]>).getContent()[0]
);
return super.executeAction(state);
} else if (this.type === ImageActionTypes.applyTransition) {
const awaitable = new Awaitable<CalledActionResult, CalledActionResult>(v => v)
.registerSkipController(new SkipController(() => {
Expand All @@ -329,14 +337,25 @@ export class ImageAction<T extends typeof ImageActionTypes[keyof typeof ImageAct
};
}));
const transition = (this.contentNode as ContentNode<ImageActionContentType["image:applyTransition"]>).getContent()[0];
transition.start(() => {
this.callee.events.any("event:image.applyTransition", transition).then(() => {
awaitable.resolve({
type: this.type,
node: this.contentNode.getChild()
});
state.stage.next();
});
return awaitable;
} else if (this.type === ImageActionTypes.flush) {
const awaitable = new Awaitable<CalledActionResult, CalledActionResult>(v => v);
this.callee.events.any("event:image.flushComponent")
.then(() => {
awaitable.resolve({
type: this.type,
node: this.contentNode.getChild()
});
state.stage.next();
});
return awaitable;
}

throw super.unknownType();
Expand All @@ -355,7 +374,7 @@ export class ConditionAction<T extends typeof ConditionActionTypes[keyof typeof
this.contentNode.addChild(nodes?.[0]?.contentNode || null);
return {
type: this.type as any,
node: this.contentNode,
node: this.contentNode.getChild(),
};
}

Expand All @@ -372,10 +391,7 @@ export class ScriptAction<T extends typeof ScriptActionTypes[keyof typeof Script
this.contentNode.getContent().execute({
gameState,
});
return {
type: this.type as any,
node: this.contentNode,
};
return super.executeAction(gameState);
}
}

Expand Down Expand Up @@ -500,6 +516,9 @@ export class ControlAction<T extends typeof ControlActionTypes[keyof typeof Cont
let current: LogicAction.Actions | null = action;
while (!exited && current) {
const next = state.game.getLiveGame().executeAction(state, current);

state.logger.debug("Control - Next Action", next);

if (!next) {
break;
}
Expand Down Expand Up @@ -538,6 +557,7 @@ export class ControlAction<T extends typeof ControlActionTypes[keyof typeof Cont
type: this.type,
node: this.contentNode.getChild()
});
state.stage.next();
});
return awaitable;
} else {
Expand All @@ -549,13 +569,8 @@ export class ControlAction<T extends typeof ControlActionTypes[keyof typeof Cont
const contentNode = this.contentNode as ContentNode<ControlActionContentType[T]>;
const [content] = contentNode.getContent() as [LogicAction.Actions[]];
if (this.type === ControlActionTypes.do) {
const firstNode = content[0]?.contentNode;
const lastNode = content[content.length - 1]?.contentNode;
const thisChild = this.contentNode.getChild();

lastNode?.addChild(thisChild);
this.contentNode.addChild(firstNode || null);
return super.executeAction(state);
const awaitable = new Awaitable<CalledActionResult, CalledActionResult>(v => v);
return this.execute(state, awaitable, content);
} else if (this.type === ControlActionTypes.doAsync) {
(async () => {
if (content.length > 0) {
Expand All @@ -571,29 +586,44 @@ export class ControlAction<T extends typeof ControlActionTypes[keyof typeof Cont
type: this.type,
node: this.contentNode.getChild()
});
state.stage.next();
});
return awaitable;
} else if (this.type === ControlActionTypes.all) {
const awaitable = new Awaitable<CalledActionResult, CalledActionResult>(v => v);
return this.execute(state, awaitable, content);
(async () => {
await Promise.all(content.map(action => this.executeSingleAction(state, action)));
awaitable.resolve({
type: this.type,
node: this.contentNode.getChild()
});
state.stage.next();
})();
return awaitable;
} else if (this.type === ControlActionTypes.allAsync) {
(async () => {
if (content.length > 0) {
await this.executeAllActions(state, content[0]);
for (const action of content) {
this.executeSingleAction(state, action).then(_ => (void 0));
}
})();
return super.executeAction(state);
} else if (this.type === ControlActionTypes.repeat) {
const [actions, times] =
(this.contentNode as ContentNode<ControlActionContentType["control:repeat"]>).getContent();
const awaitable = new Awaitable<CalledActionResult, CalledActionResult>(v => v);
(async () => {
for (let i = 0; i < times; i++) {
if (actions.length > 0) {
await this.executeAllActions(state, actions[0]);
}
}
awaitable.resolve({
type: this.type,
node: this.contentNode.getChild()
});
state.stage.next();
})();
return super.executeAction(state);
return awaitable;
}

throw new Error("Unknown control action type: " + this.type);
Expand Down
19 changes: 19 additions & 0 deletions src/game/nlcore/action/baseElement.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import {ElementStateRaw} from "@core/elements/story";
import {LogicAction} from "@core/action/logicAction";

export class BaseElement {
/**@internal */
protected id: string = "";
Expand All @@ -15,5 +18,21 @@ export class BaseElement {
/**@internal */
reset() {
}

/**@internal */
fromData(_: ElementStateRaw) {
return this;
}

/**@internal */
protected construct(actions: LogicAction.Actions[]): LogicAction.Actions[] {
for (let i = 0; i < actions.length; i++) {
const action = actions[i];
if (i !== 0) {
actions[i - 1]?.contentNode.setChild(action.contentNode);
}
}
return actions;
}
}

Loading

0 comments on commit a449111

Please sign in to comment.