Skip to content

Commit

Permalink
Add exclusive jobs tests. Splitting jobs utils.
Browse files Browse the repository at this point in the history
  • Loading branch information
Neloreck committed Aug 15, 2023
1 parent b40f983 commit 3a872f0
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 130 deletions.
159 changes: 159 additions & 0 deletions src/engine/core/utils/job/job_exclusive.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { describe, expect, it, jest } from "@jest/globals";
import { getFS } from "xray16";

import { loadExclusiveJob } from "@/engine/core/utils/job/job_exclusive";
import { TJobDescriptor } from "@/engine/core/utils/job/types";
import { IniFile, LuaArray } from "@/engine/lib/types";
import { mockIniFile, registerIniFileMock } from "@/fixtures/xray";

describe("'job_exclusive' utils", () => {
it("'loadExclusiveJob' should correctly handle empty ini", () => {
const list: LuaArray<TJobDescriptor> = new LuaTable();

loadExclusiveJob(mockIniFile("text.ltx", {}), "a", "b", list);
expect(list).toEqualLuaArrays([]);
});

it("'loadExclusiveJob' should correctly throw if script does not exist", () => {
const list: LuaArray<TJobDescriptor> = new LuaTable();
const ini: IniFile = mockIniFile("text.ltx", {
smart_terrain: {
work1: "some_file.ltx",
},
});

jest.spyOn(getFS(), "exist").mockImplementation(() => 0);
expect(() => loadExclusiveJob(ini, "smart_terrain", "work1", list)).toThrow();
});

it("'loadExclusiveJob' should correctly read if script does exist", () => {
const list: LuaArray<TJobDescriptor> = new LuaTable();
const ini: IniFile = mockIniFile("text.ltx", {
smart_terrain: {
work1: "some_file2.ltx",
},
});
const jobIni: IniFile = mockIniFile("scripts\\some_file2.ltx", {});

registerIniFileMock(jobIni);

jest.spyOn(getFS(), "exist").mockImplementation(() => 1);

expect(() => loadExclusiveJob(ini, "smart_terrain", "work1", list)).not.toThrow();
expect(list).toEqualLuaArrays([
{
_precondition_is_monster: false,
job_id: {
ini_file: expect.any(Object),
ini_path: "scripts\\some_file2.ltx",
job_type: null,
online: null,
section: "logic@work1",
},
priority: 45,
},
]);
});

it("'loadExclusiveJob' should correctly read configured jobs without condlist", () => {
const list: LuaArray<TJobDescriptor> = new LuaTable();
const ini: IniFile = mockIniFile("text.ltx", {
smart_terrain: {
work2: "some_file3.ltx",
},
});
const jobIni: IniFile = mockIniFile("scripts\\some_file3.ltx", {
"logic@work2": {
prior: 101,
monster_job: true,
job_online: true,
active: "animpoint@test1",
},
});

registerIniFileMock(jobIni);

jest.spyOn(getFS(), "exist").mockImplementation(() => 1);
loadExclusiveJob(ini, "smart_terrain", "work2", list);

expect(list).toEqualLuaArrays([
{
_precondition_is_monster: true,
job_id: {
ini_file: expect.any(Object),
ini_path: "scripts\\some_file3.ltx",
job_type: "smartcover_job",
online: true,
section: "logic@work2",
},
priority: 101,
},
]);
});

it("'loadExclusiveJob' should correctly read configured jobs with condlist", () => {
const list: LuaArray<TJobDescriptor> = new LuaTable();
const ini: IniFile = mockIniFile("text.ltx", {
smart_terrain: {
work2: "some_file3.ltx",
},
});
const jobIni: IniFile = mockIniFile("scripts\\some_file3.ltx", {
"logic@work2": {
prior: 105,
monster_job: false,
suitable: "{+test_info} true, false",
job_online: false,
active: "patrol@test1",
},
});

registerIniFileMock(jobIni);

jest.spyOn(getFS(), "exist").mockImplementation(() => 1);
loadExclusiveJob(ini, "smart_terrain", "work2", list);

expect(list).toEqualLuaArrays([
{
_precondition_function: expect.any(Function),
_precondition_is_monster: false,
_precondition_params: {
condlist: {
"1": {
infop_check: {
"1": {
name: "test_info",
required: true,
},
},
infop_set: {},
section: "true",
},
"2": {
infop_check: {},
infop_set: {},
section: "false",
},
},
},
job_id: {
ini_file: expect.any(Object),
ini_path: "scripts\\some_file3.ltx",
job_type: "path_job",
online: false,
section: "logic@work2",
},
priority: 105,
},
{
_precondition_is_monster: false,
job_id: {
ini_file: expect.any(Object),
job_type: "path_job",
section: "logic@work2",
},
priority: -1,
},
]);
});
});
118 changes: 118 additions & 0 deletions src/engine/core/utils/job/job_exclusive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { getFS, ini_file } from "xray16";

import { registry } from "@/engine/core/database";
import { SmartTerrain } from "@/engine/core/objects";
import { assert } from "@/engine/core/utils/assertion";
import {
getSchemeFromSection,
parseConditionsList,
pickSectionFromCondList,
readIniBoolean,
readIniNumber,
readIniString,
TConditionList,
} from "@/engine/core/utils/ini";
import { IJobDescriptor, TJobDescriptor } from "@/engine/core/utils/job/types";
import { roots } from "@/engine/lib/constants/roots";
import { FALSE } from "@/engine/lib/constants/words";
import {
AnyObject,
EJobType,
EScheme,
IniFile,
JobTypeByScheme,
LuaArray,
Optional,
ServerHumanObject,
TName,
TPath,
TRate,
TSection,
} from "@/engine/lib/types";

/**
* Add jobs unique to terrain instance.
*/
export function loadExclusiveJob(
ini: IniFile,
section: TSection,
field: TSection,
jobsList: LuaArray<TJobDescriptor>
): void {
const workScriptPath: Optional<TPath> = readIniString(ini, section, field, false, "", null);

// Field with work path does not exist, nothing to load.
if (workScriptPath === null) {
return;
}

const iniPath: TPath = "scripts\\" + workScriptPath;

assert(getFS().exist(roots.gameConfig, iniPath), "There is no job configuration file '%s'.", iniPath);

const jobIniFile: Optional<IniFile> = new ini_file(iniPath);
const jobOnline: Optional<string> = readIniString(jobIniFile, "logic@" + field, "job_online", false, "", null);
const newPrior: TRate = readIniNumber(jobIniFile, "logic@" + field, "prior", false, 45);
const jobSuitableCondlist: Optional<string> = readIniString(jobIniFile, "logic@" + field, "suitable", false, "");
const isMonster: boolean = readIniBoolean(jobIniFile, "logic@" + field, "monster_job", false, false);
const activeSection: TSection = readIniString(jobIniFile, "logic@" + field, "active", false, "");
const scheme: Optional<EScheme> = getSchemeFromSection(activeSection) as EScheme;

let jobType: Optional<EJobType> = (JobTypeByScheme[scheme] as EJobType) || null;

if (scheme === EScheme.MOB_HOME && readIniBoolean(jobIniFile, activeSection, "gulag_point", false, false)) {
jobType = EJobType.POINT_JOB;
}

// Add generic job placeholder if condlist is not defined, just combine ini parameters.
if (jobSuitableCondlist === null) {
const jobDescriptor: IJobDescriptor = {
priority: newPrior,
_precondition_is_monster: isMonster,
job_id: {
section: "logic@" + field,
ini_path: iniPath,
online: jobOnline,
ini_file: jobIniFile,
job_type: jobType as TName,
},
};

table.insert(jobsList, jobDescriptor);
} else {
const conditionsList: TConditionList = parseConditionsList(jobSuitableCondlist);

table.insert(jobsList, {
priority: newPrior,
_precondition_is_monster: isMonster,
job_id: {
section: "logic@" + field,
ini_path: iniPath,
ini_file: jobIniFile,
online: jobOnline,
job_type: jobType,
},
_precondition_params: { condlist: conditionsList },
_precondition_function: (
serverObject: ServerHumanObject,
smartTerrain: SmartTerrain,
precondParams: AnyObject
): boolean => {
const result: Optional<string> = pickSectionFromCondList(registry.actor, serverObject, precondParams.condlist);

return result !== FALSE && result !== null;
},
});

// todo: Why is it needed with -1?
table.insert(jobsList, {
priority: -1,
_precondition_is_monster: isMonster,
job_id: {
section: "logic@" + field,
ini_file: jobIniFile,
job_type: jobType,
},
});
}
}
Loading

0 comments on commit 3a872f0

Please sign in to comment.