Skip to content

Commit

Permalink
[FIXES] Generic meet scheme fixes, decoupling of binders logics (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
Neloreck authored Sep 19, 2023
1 parent 2776e54 commit e020937
Show file tree
Hide file tree
Showing 47 changed files with 517 additions and 285 deletions.
1 change: 0 additions & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ jobs:

- name: Update nightly tag
uses: EndBug/latest-tag@latest
if: github.ref_name == 'dev'
id: update-nightly-tag
with:
ref: nightly
Expand Down
9 changes: 4 additions & 5 deletions src/engine/core/database/logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
export function saveObjectLogic(object: ClientObject, packet: NetPacket): void {
const state: IRegistryObjectState = registry.objects.get(object.id());

openSaveMarker(packet, "object" + object.name());
openSaveMarker(packet, object.name());

packet.w_stringZ(state.jobIni ? state.jobIni : "");
packet.w_stringZ(state.iniFilename ? state.iniFilename : "");
Expand All @@ -40,13 +40,12 @@ export function saveObjectLogic(object: ClientObject, packet: NetPacket): void {
packet.w_s32((state.activationTime || 0) - time_global());
writeTimeToPacket(packet, state.activationGameTime);

// todo: Active section or active scheme?
if (state.activeScheme) {
emitSchemeEvent(object, state[state.activeScheme] as IBaseSchemeState, ESchemeEvent.SAVE);
}

savePortableStore(object, packet);
closeSaveMarker(packet, "object" + object.name());
closeSaveMarker(packet, object.name());
}

/**
Expand All @@ -58,7 +57,7 @@ export function saveObjectLogic(object: ClientObject, packet: NetPacket): void {
export function loadObjectLogic(object: ClientObject, reader: NetProcessor): void {
const state: IRegistryObjectState = registry.objects.get(object.id());

openLoadMarker(reader, "object" + object.name());
openLoadMarker(reader, object.name());

const jobIni: Optional<TPath> = reader.r_stringZ();
const iniFilename: Optional<TName> = reader.r_stringZ();
Expand All @@ -77,5 +76,5 @@ export function loadObjectLogic(object: ClientObject, reader: NetProcessor): voi

loadPortableStore(object.id(), reader);

closeLoadMarker(reader, "object" + object.name());
closeLoadMarker(reader, object.name());
}
3 changes: 2 additions & 1 deletion src/engine/core/database/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { registry } from "@/engine/core/database/registry";

describe("registry storage", () => {
it("storage to contain all fields", () => {
expect(Object.keys(registry)).toHaveLength(41);
expect(Object.keys(registry)).toHaveLength(42);
});

it("storage to initialize with correct data", () => {
expect(registry.simulator).toBeNull();
expect(registry.actor).toBeNull();
expect(registry.activeSpeaker).toBeNull();
expect(registry.activeSmartTerrainId).toBeNull();
Expand Down
5 changes: 5 additions & 0 deletions src/engine/core/database/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { TConditionList } from "@/engine/core/utils/ini/ini_types";
import type { ERelation } from "@/engine/core/utils/relation";
import { storyNames, TStoryName } from "@/engine/lib/constants/story_names";
import type {
AlifeSimulator,
ClientObject,
EScheme,
IniFile,
Expand All @@ -36,6 +37,10 @@ import type {
* Stores up-to-date game state.
*/
export const registry = {
/**
* Current simulator, injected on game start.
*/
simulator: null as unknown as AlifeSimulator,
/**
* Current actor, injected on game start.
*/
Expand Down
14 changes: 13 additions & 1 deletion src/engine/core/database/simulation.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { beforeEach, describe, it } from "@jest/globals";
import { beforeEach, describe, expect, it } from "@jest/globals";
import { alife } from "xray16";

import { registry } from "@/engine/core/database/registry";
import { registerSimulator } from "@/engine/core/database/simulation";
import { AlifeSimulator } from "@/engine/lib/types";

describe("'simulation' module of the database", () => {
beforeEach(() => {
registry.simulator = null as unknown as AlifeSimulator;
registry.objects = new LuaTable();
});

it("registerSimulator should correctly register simulator", () => {
expect(registry.simulator).toBeNull();

registerSimulator();

expect(registry.simulator).toBe(alife());
});

it.todo("should correctly register simulation objects");

it.todo("should correctly unregister simulation objects");
Expand Down
9 changes: 8 additions & 1 deletion src/engine/core/database/simulation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { clsid } from "xray16";
import { alife, clsid } from "xray16";

import { SIMULATION_OBJECTS_PROPS_LTX } from "@/engine/core/database/ini_registry";
import { registry } from "@/engine/core/database/registry";
Expand All @@ -8,6 +8,13 @@ import { isSquad } from "@/engine/core/utils/object/object_class";
import { ACTOR, DEFAULT } from "@/engine/lib/constants/words";
import { TCount, TSection } from "@/engine/lib/types";

/**
* Register simulator instance in the registry.
*/
export function registerSimulator(): void {
registry.simulator = alife();
}

/**
* Register simulation object in registries for participation in game events.
*
Expand Down
2 changes: 1 addition & 1 deletion src/engine/core/database/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export interface IRegistryObjectState extends Record<EScheme, Optional<IBaseSche
/**
* todo;
*/
enemy_id: Optional<TNumberId>;
enemyId: Optional<TNumberId>;
/**
* todo;
*/
Expand Down
4 changes: 2 additions & 2 deletions src/engine/core/managers/debug/DebugManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ export class DebugManager extends AbstractManager {
logger.info("Activation game time:", gameTimeToString(state.activationGameTime));
logger.info("Portable store:", toJSON(state.portableStore));
logger.info("State overrides:", toJSON(state.overrides));
logger.info("Enemy id:", state.enemy_id);
logger.info("Enemy name:", state.enemy_id ? alife().object(state.enemy_id)?.name() : NIL);
logger.info("Enemy id:", state.enemyId);
logger.info("Enemy name:", state.enemyId ? alife().object(state.enemyId)?.name() : NIL);
logger.info("Script combat type:", state.script_combat_type);
logger.info("Registered camp:", state.camp || "none");

Expand Down
5 changes: 5 additions & 0 deletions src/engine/core/objects/ai/scheme/AbstractScheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ export abstract class AbstractScheme {

/**
* Assign some scheme state to an object and prepare shared constants in it in a correct way.
* Initializes base state in object registry.
*
* todo;
*
* @returns base scheme state for provided `scheme`
*/
protected static assign<T extends IBaseSchemeState>(
object: ClientObject,
Expand Down
109 changes: 107 additions & 2 deletions src/engine/core/objects/binders/creature/StalkerBinder.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
import { describe, it } from "@jest/globals";
import { beforeEach, describe, expect, it, jest } from "@jest/globals";

import { IRegistryObjectState, registerObject, registry } from "@/engine/core/database";
import { DialogManager } from "@/engine/core/managers/dialogs";
import { GlobalSoundManager } from "@/engine/core/managers/sounds";
import { TradeManager } from "@/engine/core/managers/trade";
import { StalkerBinder } from "@/engine/core/objects/binders";
import { ClientObject } from "@/engine/lib/types";
import {
EPacketDataType,
mockClientGameObject,
MockCTime,
mockNetPacket,
MockNetProcessor,
mockNetReader,
} from "@/fixtures/xray";

describe("StalkerBinder class", () => {
beforeEach(() => {
registry.managers = new LuaTable();
registry.objects = new LuaTable();
});

it.todo("should correctly initialize");

it.todo("should correctly initialize info portions");
Expand All @@ -11,7 +31,92 @@ describe("StalkerBinder class", () => {

it.todo("should correctly handle update event");

it.todo("should correctly handle save/load");
it("should correctly handle save/load", () => {
const tradeManager: TradeManager = TradeManager.getInstance();
const globalSoundManager: GlobalSoundManager = GlobalSoundManager.getInstance();
const dialogManager: DialogManager = DialogManager.getInstance();

jest.spyOn(tradeManager, "saveObjectState").mockImplementation(jest.fn());
jest.spyOn(tradeManager, "loadObjectState").mockImplementation(jest.fn());
jest.spyOn(globalSoundManager, "saveObject").mockImplementation(jest.fn());
jest.spyOn(globalSoundManager, "loadObject").mockImplementation(jest.fn());
jest.spyOn(dialogManager, "saveObjectDialogs").mockImplementation(jest.fn());
jest.spyOn(dialogManager, "loadObjectDialogs").mockImplementation(jest.fn());

jest.spyOn(Date, "now").mockImplementationOnce(() => 7000);

const object: ClientObject = mockClientGameObject();
const binder: StalkerBinder = new StalkerBinder(object);
const netProcessor: MockNetProcessor = new MockNetProcessor();

registerObject(object);

binder.reinit();

const state: IRegistryObjectState = registry.objects.get(object.id());

state.activationTime = 5000;
state.activationGameTime = MockCTime.mock(2012, 6, 12, 20, 15, 30, 500);
state.jobIni = "job_ini.ltx";
state.iniFilename = "ini.ltx";
state.sectionLogic = "logic";
state.activeSection = "scheme@section";
state.smartTerrainName = "some_smart";

binder.save(mockNetPacket(netProcessor));

expect(tradeManager.saveObjectState).toHaveBeenCalledWith(netProcessor, object);
expect(globalSoundManager.saveObject).toHaveBeenCalledWith(netProcessor, object);
expect(dialogManager.saveObjectDialogs).toHaveBeenCalledWith(netProcessor, object);

expect(netProcessor.writeDataOrder).toEqual([
EPacketDataType.STRING,
EPacketDataType.STRING,
EPacketDataType.STRING,
EPacketDataType.STRING,
EPacketDataType.STRING,
EPacketDataType.STRING,
EPacketDataType.I32,
EPacketDataType.U8,
EPacketDataType.U8,
EPacketDataType.U8,
EPacketDataType.U8,
EPacketDataType.U8,
EPacketDataType.U8,
EPacketDataType.U16,
EPacketDataType.U32,
EPacketDataType.U16,
EPacketDataType.U16,
]);
expect(netProcessor.dataList).toEqual([
"save_from_StalkerBinder",
"job_ini.ltx",
"ini.ltx",
"logic",
"scheme@section",
"some_smart",
-2000,
12,
6,
12,
20,
15,
30,
500,
0,
14,
16,
]);

binder.load(mockNetReader(netProcessor));

expect(tradeManager.loadObjectState).toHaveBeenCalledWith(netProcessor, object);
expect(globalSoundManager.loadObject).toHaveBeenCalledWith(netProcessor, object);
expect(dialogManager.loadObjectDialogs).toHaveBeenCalledWith(netProcessor, object);

expect(netProcessor.readDataOrder).toEqual(netProcessor.writeDataOrder);
expect(netProcessor.dataList).toHaveLength(0);
});

it.todo("should correctly handle death event");

Expand Down
Loading

0 comments on commit e020937

Please sign in to comment.