Skip to content

Commit

Permalink
Extended mocks. Continue testing/moving object related utils by categ…
Browse files Browse the repository at this point in the history
…ories.
  • Loading branch information
Neloreck committed Jun 25, 2023
1 parent 58acb0d commit bdad4ce
Show file tree
Hide file tree
Showing 16 changed files with 182 additions and 83 deletions.
2 changes: 1 addition & 1 deletion src/engine/core/managers/interaction/TravelManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
getObjectSmartTerrain,
getObjectSquad,
getServerDistanceBetween,
} from "@/engine/core/utils/object/object_general";
} from "@/engine/core/utils/object";
import { isAnySquadMemberEnemyToActor } from "@/engine/core/utils/relation";
import { postProcessors } from "@/engine/lib/constants/animation/post_processors";
import { captions } from "@/engine/lib/constants/captions/captions";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ import {
TConditionList,
} from "@/engine/core/utils/ini";
import { LuaLogger } from "@/engine/core/utils/logging";
import { areObjectsOnSameLevel } from "@/engine/core/utils/object/object_general";
import { areObjectsOnSameLevel } from "@/engine/core/utils/object";
import { ERelation } from "@/engine/core/utils/relation";
import {
activateSchemeBySection,
Expand Down
6 changes: 2 additions & 4 deletions src/engine/core/objects/server/squad/Squad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,13 @@ import {
TConditionList,
} from "@/engine/core/utils/ini";
import { LuaLogger } from "@/engine/core/utils/logging";
import { areObjectsOnSameLevel } from "@/engine/core/utils/object/object_general";
import { areObjectsOnSameLevel } from "@/engine/core/utils/object";
import {
areCommunitiesEnemies,
ERelation,
getSquadMembersRelationToActor,
getSquadMembersRelationToActorSafe,
setClientObjectRelation,
setObjectSympathy,
setServerObjectRelation,
} from "@/engine/core/utils/relation";
import { isEmpty } from "@/engine/core/utils/table";
import { gameConfig } from "@/engine/lib/configs/GameConfig";
Expand Down Expand Up @@ -730,7 +728,7 @@ export class Squad extends cse_alife_online_offline_group implements ISimulation
areObjectsOnSameLevel(serverObject, alife().actor()) &&
spawnPosition.distance_to_sqr(alife().actor().position) <= alife().switch_distance() * alife().switch_distance()
) {
// todo: Delete also, same as with stalkers and monsters??? Memory leak probable
// todo: Delete also, same as with stalkers and monsters?
registry.spawnedVertexes.set(serverObject.id, lvi);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ISimulationActivityDescriptor, SmartTerrain } from "@/engine/core/objec
import { Squad } from "@/engine/core/objects/server/squad/Squad";
import { hasAlifeInfo } from "@/engine/core/utils/info_portion";
import { LuaLogger } from "@/engine/core/utils/logging";
import { getServerDistanceBetween } from "@/engine/core/utils/object/object_general";
import { getServerDistanceBetween } from "@/engine/core/utils/object";
import { isAnySquadMemberEnemyToActor } from "@/engine/core/utils/relation";
import { isInTimeInterval } from "@/engine/core/utils/time";
import { communities, TCommunity } from "@/engine/lib/constants/communities";
Expand Down
2 changes: 1 addition & 1 deletion src/engine/core/utils/alife.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { alife } from "xray16";
import { Squad } from "@/engine/core/objects";
import { TSimulationObject } from "@/engine/core/objects/server/types";
import { LuaLogger } from "@/engine/core/utils/logging";
import { areObjectsOnSameLevel, getServerDistanceBetween } from "@/engine/core/utils/object/object_general";
import { areObjectsOnSameLevel, getServerDistanceBetween } from "@/engine/core/utils/object/object_location";
import { logicsConfig } from "@/engine/lib/configs/LogicsConfig";
import { MAX_I32 } from "@/engine/lib/constants/memory";
import { ServerObject, TDistance, TRate } from "@/engine/lib/types";
Expand Down
1 change: 1 addition & 0 deletions src/engine/core/utils/object/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "@/engine/core/utils/object/object_general";
export * from "@/engine/core/utils/object/object_location";
export * from "@/engine/core/utils/object/object_state";
export * from "@/engine/core/utils/object/object_find";
2 changes: 1 addition & 1 deletion src/engine/core/utils/object/object_find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { alife, level } from "xray16";

import { registry } from "@/engine/core/database";
import { LuaLogger } from "@/engine/core/utils/logging";
import { areObjectsOnSameLevel } from "@/engine/core/utils/object/object_general";
import { areObjectsOnSameLevel } from "@/engine/core/utils/object/object_location";
import {
AlifeSimulator,
AnyCallable,
Expand Down
46 changes: 0 additions & 46 deletions src/engine/core/utils/object/object_general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,32 +251,6 @@ export function getAlifeCharacterCommunity(object: ServerHumanObject | ServerGro
return communities.monster;
}

/**
* todo;
*/
export function getServerDistanceBetween(first: ServerObject, second: ServerObject): TDistance {
return graphDistance(first.m_game_vertex_id, second.m_game_vertex_id);
}

/**
* todo;
*/
export function getServerDistanceBetweenSafe(
first: Optional<ServerObject>,
second: Optional<ServerObject>
): Optional<TDistance> {
return first && second && graphDistance(first.m_game_vertex_id, second.m_game_vertex_id);
}

/**
* todo;
*/
export function areObjectsOnSameLevel(first: ServerObject, second: ServerObject): boolean {
return (
game_graph().vertex(first.m_game_vertex_id).level_id() === game_graph().vertex(second.m_game_vertex_id).level_id()
);
}

/**
* todo;
*/
Expand Down Expand Up @@ -517,23 +491,3 @@ export function anomalyHasArtefact(

return $multi(false, null);
}

/**
* todo;
*/
export function isObjectAsleep(object: ClientObject): boolean {
return registry.objects.get(object.id()).stateManager!.animstate.states.currentState === EStalkerState.SLEEP;
}

/**
* Check whether object is in provided smart terrain (name).
*
* @param object - client object to check
* @param smartTerrainName - desired smart terrain to check
* @returns whether object is assigned to smart terrain with desired name
*/
export function isObjectInSmartTerrain(object: ClientObject, smartTerrainName: TName): boolean {
const smartTerrain: Optional<SmartTerrain> = getObjectSmartTerrain(object);

return smartTerrain ? smartTerrain.name() === smartTerrainName : false;
}
83 changes: 77 additions & 6 deletions src/engine/core/utils/object/object_location.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import { describe, expect, it } from "@jest/globals";
import { describe, expect, it, jest } from "@jest/globals";
import { alife, game_graph } from "xray16";

import { isObjectInZone, isObjectOnLevel } from "@/engine/core/utils/object/object_location";
import {
areObjectsOnSameLevel,
getServerDistanceBetween,
isDistanceBetweenObjectsGreaterOrEqual,
isDistanceBetweenObjectsLessOrEqual,
isObjectInSmartTerrain,
isObjectInZone,
isObjectOnLevel,
} from "@/engine/core/utils/object/object_location";
import { ClientObject, ServerObject } from "@/engine/lib/types";
import { mockClientGameObject, mockServerAlifeObject } from "@/fixtures/xray";
import { mockRegisteredActor } from "@/fixtures/engine";
import { mockClientGameObject, mockServerAlifeObject, mockServerAlifeSmartZone } from "@/fixtures/xray";

describe("object location utils", () => {
it("'isObjectInSmartTerrain' check object inside smart terrain", () => {
const smartTerrain = mockServerAlifeSmartZone({ name: <T extends string>() => "test-smart" as T });
const { actorClientObject } = mockRegisteredActor({}, { m_smart_terrain_id: smartTerrain.id });

expect(isObjectInSmartTerrain(actorClientObject, "test-smart")).toBe(true);
expect(isObjectInSmartTerrain(actorClientObject, "test-smart-another")).toBe(false);
expect(isObjectInSmartTerrain(actorClientObject, "another")).toBe(false);
});

it("'isObjectInZone' check object inside", () => {
const object: ClientObject = mockClientGameObject();
const zone: ClientObject = mockClientGameObject();
Expand All @@ -17,13 +35,66 @@ describe("object location utils", () => {
expect(isObjectInZone(null, zone)).toBe(false);
});

it("'isObjectOnLevel' check object inside", () => {
it("'isObjectOnLevel' check object on level", () => {
const object: ServerObject = mockServerAlifeObject();

expect(isObjectOnLevel(null, "zaton")).toBe(false);
expect(isObjectOnLevel(object, "pripyat")).toBe(true);

expect(game_graph().vertex(object.m_game_vertex_id).level_id()).toBe(1);
expect(alife().level_name).toHaveBeenCalledWith(1);
expect(game_graph().vertex(object.m_game_vertex_id).level_id()).toBe(10);
expect(alife().level_name).toHaveBeenCalledWith(10);
});

it("'areObjectsOnSameLevel' check objects on level", () => {
expect(areObjectsOnSameLevel(mockServerAlifeObject(), mockServerAlifeObject())).toBe(true);
expect(areObjectsOnSameLevel(mockServerAlifeObject(), mockServerAlifeObject({ m_game_vertex_id: 990 }))).toBe(
false
);
expect(
areObjectsOnSameLevel(
mockServerAlifeObject({ m_game_vertex_id: 990 }),
mockServerAlifeObject({ m_game_vertex_id: 990 })
)
).toBe(true);
});

it("'isDistanceBetweenObjectsGreaterOrEqual' should correctly check", () => {
const first: ClientObject = mockClientGameObject();
const second: ClientObject = mockClientGameObject();

jest.spyOn(first.position(), "distance_to").mockImplementation(() => 150);
expect(isDistanceBetweenObjectsGreaterOrEqual(first, second, 100)).toBe(true);

jest.spyOn(first.position(), "distance_to").mockImplementation(() => 25);
expect(isDistanceBetweenObjectsGreaterOrEqual(first, second, 55)).toBe(false);

jest.spyOn(first.position(), "distance_to").mockImplementation(() => 1000);
expect(isDistanceBetweenObjectsGreaterOrEqual(first, second, 1000)).toBe(true);
});

it("'isDistanceBetweenObjectsLessOrEqual' should correctly check", () => {
const first: ClientObject = mockClientGameObject();
const second: ClientObject = mockClientGameObject();

jest.spyOn(first.position(), "distance_to").mockImplementation(() => 150);
expect(isDistanceBetweenObjectsLessOrEqual(first, second, 100)).toBe(false);

jest.spyOn(first.position(), "distance_to").mockImplementation(() => 25);
expect(isDistanceBetweenObjectsLessOrEqual(first, second, 55)).toBe(true);

jest.spyOn(first.position(), "distance_to").mockImplementation(() => 1000);
expect(isDistanceBetweenObjectsLessOrEqual(first, second, 1000)).toBe(true);
});

it("'getServerDistanceBetween' should correctly get distance for offline objects", () => {
const first: ServerObject = mockServerAlifeObject({ m_game_vertex_id: 500 });

jest.spyOn(game_graph().vertex(500).game_point(), "distance_to").mockImplementation(() => 600);
expect(getServerDistanceBetween(first, mockServerAlifeObject())).toBe(600);

const second: ServerObject = mockServerAlifeObject({ m_game_vertex_id: 501 });

jest.spyOn(game_graph().vertex(501).game_point(), "distance_to").mockImplementation(() => 255);
expect(getServerDistanceBetween(second, mockServerAlifeObject())).toBe(255);
});
});
56 changes: 47 additions & 9 deletions src/engine/core/utils/object/object_location.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import { alife, game_graph } from "xray16";

import { registry } from "@/engine/core/database";
import { SmartTerrain } from "@/engine/core/objects";
import { getObjectSmartTerrain } from "@/engine/core/utils/object/object_general";
import { graphDistance } from "@/engine/core/utils/vector";
import { ClientObject, Optional, ServerObject, TDistance, TName } from "@/engine/lib/types";

/**
* Check whether object is in provided smart terrain (name).
*
* @param object - client object to check
* @param smartTerrainName - desired smart terrain to check
* @returns whether object is assigned to smart terrain with desired name
*/
export function isObjectInSmartTerrain(object: ClientObject, smartTerrainName: TName): boolean {
const smartTerrain: Optional<SmartTerrain> = getObjectSmartTerrain(object);

return smartTerrain ? smartTerrain.name() === smartTerrainName : false;
}

/**
* Check whether object is inside another zone object.
*
Expand All @@ -26,7 +41,12 @@ export function isObjectOnLevel(object: Optional<ServerObject>, levelName: TName
}

/**
* @returns whether distance between objects greater or equal.
* Check distance between objects.
*
* @param first - object distance from
* @param second - object distance to
* @param distance - distance in meters
* @returns whether distance between objects greater or equal
*/
export function isDistanceBetweenObjectsGreaterOrEqual(
first: ClientObject,
Expand All @@ -37,7 +57,12 @@ export function isDistanceBetweenObjectsGreaterOrEqual(
}

/**
* @returns whether distance between objects less or equal.
* Check distance between objects.
*
* @param first - object distance from
* @param second - object distance to
* @param distance - distance in meters
* @returns whether distance between objects less or equal
*/
export function isDistanceBetweenObjectsLessOrEqual(
first: ClientObject,
Expand All @@ -48,15 +73,28 @@ export function isDistanceBetweenObjectsLessOrEqual(
}

/**
* @returns whether distance to actor greater or equal.
* Check whether objects are on same level.
*
* @param first - object to compare
* @param second - object to compare
* @returns whether objects are on same level
*/
export function isDistanceToActorGreaterOrEqual(object: ClientObject, distance: TDistance): boolean {
return object.position().distance_to_sqr(registry.actor.position()) >= distance * distance;
export function areObjectsOnSameLevel(first: ServerObject, second: ServerObject): boolean {
return (
game_graph().vertex(first.m_game_vertex_id).level_id() === game_graph().vertex(second.m_game_vertex_id).level_id()
);
}

/**
* @returns whether distance to actor less or equal.
* Get absolute distance for objects based on game graphs.
* Approximately calculates distance for servers that are offline and may be on different levels.
*
* todo: Use table memo for storing distance between different static vertexes.
*
* @param first - object to check
* @param second - object to check
* @returns game distance between two objects
*/
export function isDistanceToActorLessOrEqual(object: ClientObject, distance: TDistance): boolean {
return object.position().distance_to_sqr(registry.actor.position()) <= distance * distance;
export function getServerDistanceBetween(first: ServerObject, second: ServerObject): TDistance {
return graphDistance(first.m_game_vertex_id, second.m_game_vertex_id);
}
10 changes: 10 additions & 0 deletions src/engine/core/utils/object/object_state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { registry } from "@/engine/core/database";
import { EStalkerState } from "@/engine/core/objects/state";
import { ClientObject } from "@/engine/lib/types";

/**
* todo;
*/
export function isObjectAsleep(object: ClientObject): boolean {
return registry.objects.get(object.id()).stateManager!.animstate.states.currentState === EStalkerState.SLEEP;
}
16 changes: 13 additions & 3 deletions src/engine/core/utils/vector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,20 @@ export function distanceBetween(first: ClientObject, second: ClientObject): numb
}

/**
*
* Get graph distance between two vertexes.
*/
export function graphDistance(firstVertexId: TNumberId, secondVertexId: TNumberId): TDistance {
return game_graph().vertex(firstVertexId).game_point().distance_to(game_graph().vertex(secondVertexId).game_point());
}

/**
* Get graph distance between two vertexes in sqr.
*/
export function graphDistance(vertexId1: TNumberId, vertexId2: TNumberId): TDistance {
return game_graph().vertex(vertexId1).game_point().distance_to(game_graph().vertex(vertexId2).game_point());
export function graphDistanceSqr(firstVertexId: TNumberId, secondVertexId: TNumberId): TDistance {
return game_graph()
.vertex(firstVertexId)
.game_point()
.distance_to_sqr(game_graph().vertex(secondVertexId).game_point());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/engine/scripts/declarations/dialogs/dialogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { isObjectWounded, isStalkerAlive } from "@/engine/core/utils/check/check
import { createAutoSave } from "@/engine/core/utils/game_save";
import { giveInfo, hasAlifeInfo } from "@/engine/core/utils/info_portion";
import { LuaLogger } from "@/engine/core/utils/logging";
import { getCharacterCommunity, isObjectInSmartTerrain } from "@/engine/core/utils/object/object_general";
import { getCharacterCommunity, isObjectInSmartTerrain } from "@/engine/core/utils/object";
import {
actorHasMedKit,
getActorAvailableMedKit,
Expand Down
11 changes: 10 additions & 1 deletion src/fixtures/xray/mocks/CGameGraph.mock.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { jest } from "@jest/globals";

import { TNumberId } from "@/engine/lib/types";
import { MockCVertex } from "@/fixtures/xray/mocks/CVertex.mock";

/**
* todo;
*/
export class MockCGameGraph {
public vertex = jest.fn(() => new MockCVertex());
public static registry: Record<TNumberId, MockCVertex> = {};

public vertex = jest.fn((vertexId: TNumberId = 1) => {
if (!MockCGameGraph.registry[vertexId]) {
MockCGameGraph.registry[vertexId] = new MockCVertex(vertexId);
}

return MockCGameGraph.registry[vertexId];
});
}
Loading

0 comments on commit bdad4ce

Please sign in to comment.