diff --git a/.husky/pre-commit b/.husky/pre-commit index 545eff9..1b621c0 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,2 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - npm test -npm run lint \ No newline at end of file +npx lint-staged diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..e80e8be --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,3 @@ +{ + "*.{js,jsx,ts,tsx}": "eslint --fix" +} diff --git a/eslint.config.mts b/eslint.config.mts index f0a8240..32d443b 100644 --- a/eslint.config.mts +++ b/eslint.config.mts @@ -11,14 +11,33 @@ export default defineConfig([ "@stylistic": stylistic }, extends: ["js/recommended"], - languageOptions: { globals: globals.browser }, + languageOptions: { + globals: globals.browser, + parserOptions: { + projectService: true, + }, + }, rules: { "@stylistic/max-len": ["error", { code: 80, tabWidth: 2 }], - } + }, }, tseslint.configs.recommended, + tseslint.configs.stylisticTypeChecked, stylistic.configs.customize({ quotes: "double", semi: true, - }) + }), + { + rules: { + "@typescript-eslint/no-unused-vars": ["error", { + "args": "all", + "argsIgnorePattern": "^_", + "caughtErrors": "all", + "caughtErrorsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "ignoreRestSiblings": true + }], + } + } ]); diff --git a/package.json b/package.json index 254637d..88f7cb4 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,12 @@ "scripts": { "build": "npx spack", "lint": "npx eslint src/", - "prepare": "husky install", - "test": "jest", + "test": "jest --passWithNoTests", "push": "yarn build && node ./upload.js" }, "dependencies": { - "@types/screeps": "^3.3.8" + "@types/screeps": "^3.3.8", + "screeps-profiler": "^3.0.0" }, "devDependencies": { "@eslint/js": "^9.39.2", @@ -22,6 +22,7 @@ "@swc/jest": "^0.2.39", "@types/jest": "^30.0.0", "@types/node": "^25.0.3", + "@types/screeps-profiler": "^1.2.6", "@typescript-eslint/eslint-plugin": "^8.50.0", "@typescript-eslint/parser": "^8.50.0", "dotenv": "^17.2.3", @@ -30,6 +31,7 @@ "husky": "^9.1.7", "jest": "^30.2.0", "jiti": "^2.6.1", + "lint-staged": "^16.2.7", "screeps-jest": "^2.0.3", "ts-node": "^10.9.2", "typescript": "^5.9.3", diff --git a/src/Proto/index.ts b/src/Proto/index.ts index 6ce56d7..fc49a2f 100644 --- a/src/Proto/index.ts +++ b/src/Proto/index.ts @@ -1,9 +1,8 @@ declare global { interface RoomMemory { - sources: { - [id: Id]: SourceMemory; - }; + sources: Record, SourceMemory>; spawn: Id | null; + mineral: Id | null; _spawnCacheTimeout?: number; } @@ -19,6 +18,7 @@ declare global { interface Room { get sources(): Source[]; get spawn(): StructureSpawn | null; + get mineral(): Mineral | null; } } @@ -63,6 +63,23 @@ Object.defineProperty(Room.prototype, "spawn", { configurable: true, }); +Object.defineProperty(Room.prototype, "mineral", { + get: function (this: Room) { + if (this == Room.prototype || this == undefined) return undefined; + if (!this.memory.mineral) { + const minerals = this.find(FIND_MINERALS); + if (minerals.length > 0) { + this.memory.mineral = minerals[0].id; + } + } + return this.memory.mineral == null + ? null + : Game.getObjectById(this.memory.mineral); + }, + enumerable: false, + configurable: true, +}); + Object.defineProperty(Source.prototype, "memory", { get: function (this: Source) { return this.room.memory.sources[this.id]; @@ -80,7 +97,7 @@ Object.defineProperty(Source.prototype, "container", { || Game.getObjectById(this.memory.container) == null) { const containers = this.pos.findInRange(FIND_STRUCTURES, 1, { filter: (s: Structure) => s.structureType === STRUCTURE_CONTAINER, - }) as StructureContainer[]; + }); if (containers.length > 0) { this.memory.container = containers[0].id; } diff --git a/src/RoomPlanner/index.ts b/src/RoomPlanner/index.ts index 2fdea09..479a33f 100644 --- a/src/RoomPlanner/index.ts +++ b/src/RoomPlanner/index.ts @@ -6,29 +6,30 @@ const UNSET = 999; declare global { interface RoomMemory { - _planner: string + _planner: string; } } - const structureCoding: (BuildableStructureConstant | null)[] = - [null, STRUCTURE_ROAD, STRUCTURE_CONTAINER, STRUCTURE_EXTENSION, STRUCTURE_FACTORY, - STRUCTURE_EXTRACTOR, STRUCTURE_WALL, STRUCTURE_SPAWN, STRUCTURE_POWER_SPAWN, - STRUCTURE_STORAGE, STRUCTURE_NUKER, STRUCTURE_TERMINAL, STRUCTURE_LAB, - STRUCTURE_LINK, STRUCTURE_TOWER, STRUCTURE_RAMPART]; +const structureCoding: (BuildableStructureConstant | null)[] + = [null, STRUCTURE_ROAD, STRUCTURE_CONTAINER, STRUCTURE_EXTENSION, + STRUCTURE_FACTORY, STRUCTURE_EXTRACTOR, STRUCTURE_WALL, STRUCTURE_SPAWN, + STRUCTURE_POWER_SPAWN, STRUCTURE_STORAGE, STRUCTURE_NUKER, + STRUCTURE_TERMINAL, STRUCTURE_LAB, STRUCTURE_LINK, + STRUCTURE_TOWER, STRUCTURE_RAMPART]; const getCoord = (x: number, y: number): number => { return x + y * roomSize; -} +}; const distanceTransform = (mask: (0 | 999 | 1000)[]): number[] => { - let arr: number[] = new Array(...mask); - for (let i = 0; arr.find((x) => x === UNSET) != null; i++) { + const arr: number[] = new Array(...mask); + for (let i = 0; arr.find(x => x === UNSET) != null; i++) { for (let x = 0; x < roomSize; x++) { for (let y = 0; y < roomSize; y++) { if (arr[getCoord(x, y)] === i) { for (let dx = -1; dx < 2; dx++) { for (let dy = -1; dy < 2; dy++) { if (x + dx < 0 || y + dy < 0 || x + dx >= 50 || y + dy >= 50 - || arr[getCoord(x, y)] === OBSTACLE) { + || arr[getCoord(x, y)] === OBSTACLE) { continue; } if (arr[getCoord(x + dx, y + dy)] === UNSET) { @@ -60,13 +61,13 @@ const distanceTransform = (mask: (0 | 999 | 1000)[]): number[] => { } */ const createBuildSites = (room: Room) => { - let structures = new Array(); + const structures = []; for (let i = 0; i < room.memory._planner.length; i++) { structures.push( - structureCoding[(room.memory._planner.charCodeAt(i) - 32) & 0b11111] + structureCoding[(room.memory._planner.charCodeAt(i) - 32) & 0b11111], ); structures.push( - structureCoding[(room.memory._planner.charCodeAt(i) - 32) >> 5] + structureCoding[(room.memory._planner.charCodeAt(i) - 32) >> 5], ); } for (let x = 0; x < roomSize; x++) { @@ -127,10 +128,10 @@ const createBuildSites = (room: Room) => { } } } -} +}; export default profiler.registerFN(function RoomPlanner(room: Room) { - if (room.controller == null || !room.controller.my) { + if (!room.controller?.my) { return; } if (Game.cpu.bucket < 100 && room.name != "sim") { @@ -144,21 +145,23 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { return; } const terrain = room.getTerrain(); - let mask: number[] = new Array(roomSize * roomSize).fill(0); + const mask: number[] = new Array(roomSize * roomSize).fill(0); for (let x = 0; x < roomSize; x++) { for (let y = 0; y < roomSize; y++) { mask[getCoord(x, y)] = terrain.get(x, y); } } const wallDistance = distanceTransform( - mask.map((t) => t === TERRAIN_MASK_WALL ? 0 : UNSET)); - const controllerCoord = - (room.controller?.pos.x ?? 0) + (room.controller?.pos.y ?? -1) * roomSize; + mask.map(t => t === TERRAIN_MASK_WALL ? 0 : UNSET)); + const controllerCoord + = (room.controller?.pos.x ?? 0) + (room.controller?.pos.y ?? -1) * roomSize; const controllerDistance = distanceTransform( mask.map((t, i) => - i === controllerCoord ? 0 : ( - t === TERRAIN_MASK_WALL ? OBSTACLE : UNSET - )) + i === controllerCoord + ? 0 + : ( + t === TERRAIN_MASK_WALL ? OBSTACLE : UNSET + )), ); const buildCenter = wallDistance.map( (x, i) => [x * 2.5 - controllerDistance[i], i]).sort( @@ -174,7 +177,7 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { // Build structures // - let structures: (BuildableStructureConstant | null)[] + const structures: (BuildableStructureConstant | null)[] = new Array(roomSize * roomSize); // Build Roads + Containers @@ -184,34 +187,37 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { room.find(FIND_EXIT_LEFT)?.[0], room.find(FIND_EXIT_RIGHT)?.[0], room.find(FIND_EXIT_BOTTOM)?.[0]] - .map((pos) => pos == null ? null : ({ pos, highRange: true }))); - for (let target of roadTargets) { - if (target == null) { continue; } + .map(pos => pos == null ? null : ({ pos, highRange: true }))); + for (const target of roadTargets) { + if (target == null) { + continue; + } const { path } = PathFinder.search(buildCenterPos, { pos: target.pos, range: "highRange" in target ? 3 : 1 }, { - swampCost: 10, - plainCost: 2, - roomCallback: function(roomName) { - if (roomName != room.name) { - return false; - } + swampCost: 10, + plainCost: 2, + roomCallback: function (roomName) { + if (roomName != room.name) { + return false; + } - let costs = new PathFinder.CostMatrix; - for (let x = 0; x < roomSize; x++) { - for (let y = 0; y < roomSize; y++) { - if (structures[getCoord(x, y)] === STRUCTURE_ROAD) { - costs.set(x, y, 1); + const costs = new PathFinder.CostMatrix(); + for (let x = 0; x < roomSize; x++) { + for (let y = 0; y < roomSize; y++) { + if (structures[getCoord(x, y)] === STRUCTURE_ROAD) { + costs.set(x, y, 1); + } } } - } - return costs; - } - }); + return costs; + }, + }); for (let i = 0; i < path.length; i++) { const pos = path[i]; structures[getCoord(pos.x, pos.y)] = (i === path.length - 1 && "energy" in target) - ? STRUCTURE_CONTAINER : STRUCTURE_ROAD; + ? STRUCTURE_CONTAINER + : STRUCTURE_ROAD; } } @@ -238,18 +244,18 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { [buildCenterX - 2, buildCenterY + 2], [buildCenterX + 2, buildCenterY - 2], [buildCenterX + 2, buildCenterY + 2], - ].map(([x, y]) => [x, y, controllerDistance[x + y * roomSize]] + ].map(([x, y]) => [x, y, controllerDistance[x + y * roomSize]], ).sort(([_x, _y, i], [_x2, _y2, j]) => i - j); - for (let [x, y, i] of coreCorners) { + for (const [x, y, _i] of coreCorners) { const directionX = (x - buildCenterX) / Math.abs(x - buildCenterX); const directionY = (y - buildCenterY) / Math.abs(y - buildCenterY); let ok = true; s: for (let dx = 0; Math.abs(dx) < 4; dx += directionX) { for (let dy = 0; Math.abs(dy) < 4; dy += directionY) { if ((structures[getCoord(x + dx, y + dy)] == null - || structures[getCoord(x + dx, y + dy)] === STRUCTURE_ROAD) - && mask[getCoord(x + dx, y + dy)] === 0) { + || structures[getCoord(x + dx, y + dy)] === STRUCTURE_ROAD) + && mask[getCoord(x + dx, y + dy)] === 0) { continue; } ok = false; @@ -269,7 +275,7 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { } } if (!(dx === 0 && Math.abs(dy) === 3) - && !(dy === 0 && Math.abs(dx) === 3)) { + && !(dy === 0 && Math.abs(dx) === 3)) { structures[getCoord(x + dx, y + dy)] = STRUCTURE_LAB; } } @@ -281,7 +287,8 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { // Extensions let extensions = 0; a: for (let dx = 0; dx < roomSize / 2; dx++) { - for (let dy = 0; dy < wallDistance[getCoord(buildCenterX, buildCenterY)]; dy++) { + const dylimit = wallDistance[getCoord(buildCenterX, buildCenterY)]; + for (let dy = 0; dy < dylimit; dy++) { for (let cardinal = 0; cardinal < 4; cardinal++) { const x = cardinal < 2 ? buildCenterX + dx : buildCenterX - dx; const y = cardinal % 2 == 0 ? buildCenterY + dy : buildCenterY - dy; @@ -289,8 +296,8 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { break a; } if (structures[getCoord(x, y)] == null - && (mask[getCoord(x, y)] === 0 - || mask[getCoord(x, y)] === TERRAIN_MASK_SWAMP)) { + && (mask[getCoord(x, y)] === 0 + || mask[getCoord(x, y)] === TERRAIN_MASK_SWAMP)) { let ok = false; s: for (let ddx = -1; ddx < 2; ddx++) { for (let ddy = -1; ddy < 2; ddy++) { @@ -303,7 +310,8 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { if (ok) { if (x % 2 == y % 3 || x % 3 == y % 2) { structures[getCoord(x, y)] = STRUCTURE_ROAD; - } else { + } + else { structures[getCoord(x, y)] = STRUCTURE_EXTENSION; extensions++; } @@ -326,8 +334,8 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { for (let x = 0; x < roomSize; x++) { for (let y = 0; y < roomSize; y++) { if (structures[getCoord(x, y)] != null - && structures[getCoord(x, y)] != STRUCTURE_ROAD - && structures[getCoord(x, y)] != STRUCTURE_CONTAINER) { + && structures[getCoord(x, y)] != STRUCTURE_ROAD + && structures[getCoord(x, y)] != STRUCTURE_CONTAINER) { if (x < smallestX) { smallestX = x; } @@ -358,12 +366,12 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { plainCost: 100, swampCost: 100, - roomCallback: function(roomName) { + roomCallback: function (roomName) { if (roomName != room.name) { return false; } - let costs = new PathFinder.CostMatrix; + const costs = new PathFinder.CostMatrix(); for (let x = 0; x < roomSize; x++) { for (let y = 0; y < roomSize; y++) { if (mask[getCoord(x, y)] === TERRAIN_MASK_WALL) { @@ -372,7 +380,8 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { if (structures[getCoord(x, y)] != null) { if (structures[getCoord(x, y)] == STRUCTURE_ROAD) { costs.set(x, y, 254); - } else { + } + else { costs.set(x, y, 255); } } @@ -392,39 +401,42 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { }); path.push(room.getPositionAt(smallestX - 1, centerLine)!); - for (let i = 0; i < path.length; i++) { - let s = structures[getCoord(path[i].x, path[i].y)] === STRUCTURE_ROAD - || structures[getCoord(path[i].x + 1, path[i].y)] === STRUCTURE_ROAD - || structures[getCoord(path[i].x - 1, path[i].y)] === STRUCTURE_ROAD - || structures[getCoord(path[i].x + 1, path[i].y + 1)] === STRUCTURE_ROAD - || structures[getCoord(path[i].x + 1, path[i].y - 1)] === STRUCTURE_ROAD - || structures[getCoord(path[i].x - 1, path[i].y + 1)] === STRUCTURE_ROAD - || structures[getCoord(path[i].x - 1, path[i].y - 1)] === STRUCTURE_ROAD - || structures[getCoord(path[i].x, path[i].y + 1)] === STRUCTURE_ROAD - || structures[getCoord(path[i].x, path[i].y - 1)] === STRUCTURE_ROAD + for (const pos of path) { + const s = structures[getCoord(pos.x, pos.y)] === STRUCTURE_ROAD + || structures[getCoord(pos.x + 1, pos.y)] === STRUCTURE_ROAD + || structures[getCoord(pos.x - 1, pos.y)] === STRUCTURE_ROAD + || structures[getCoord(pos.x + 1, pos.y + 1)] === STRUCTURE_ROAD + || structures[getCoord(pos.x + 1, pos.y - 1)] === STRUCTURE_ROAD + || structures[getCoord(pos.x - 1, pos.y + 1)] === STRUCTURE_ROAD + || structures[getCoord(pos.x - 1, pos.y - 1)] === STRUCTURE_ROAD + || structures[getCoord(pos.x, pos.y + 1)] === STRUCTURE_ROAD + || structures[getCoord(pos.x, pos.y - 1)] === STRUCTURE_ROAD ? STRUCTURE_RAMPART : STRUCTURE_WALL; - if (mask[getCoord(path[i].x, path[i].y)] != TERRAIN_MASK_WALL) { - structures[getCoord(path[i].x, path[i].y)] = s; - } else { + if (mask[getCoord(pos.x, pos.y)] != TERRAIN_MASK_WALL) { + structures[getCoord(pos.x, pos.y)] = s; + } + else { continue; } - if (mask[getCoord(path[i].x+1, path[i].y)] != TERRAIN_MASK_WALL - && structures[getCoord(path[i].x+1, path[i].y)] != STRUCTURE_RAMPART) { - structures[getCoord(path[i].x+1, path[i].y)] = s; - }if (mask[getCoord(path[i].x-1, path[i].y)] != TERRAIN_MASK_WALL - && structures[getCoord(path[i].x-1, path[i].y)] != STRUCTURE_RAMPART) { - structures[getCoord(path[i].x-1, path[i].y)] = s; - }if (mask[getCoord(path[i].x, path[i].y+1)] != TERRAIN_MASK_WALL - && structures[getCoord(path[i].x, path[i].y+1)] != STRUCTURE_RAMPART) { - structures[getCoord(path[i].x, path[i].y+1)] = s; - }if (mask[getCoord(path[i].x, path[i].y-1)] != TERRAIN_MASK_WALL - && structures[getCoord(path[i].x, path[i].y-1)] != STRUCTURE_RAMPART) { - structures[getCoord(path[i].x, path[i].y-1)] = s; + if (mask[getCoord(pos.x + 1, pos.y)] != TERRAIN_MASK_WALL + && structures[getCoord(pos.x + 1, pos.y)] != STRUCTURE_RAMPART) { + structures[getCoord(pos.x + 1, pos.y)] = s; + } + if (mask[getCoord(pos.x - 1, pos.y)] != TERRAIN_MASK_WALL + && structures[getCoord(pos.x - 1, pos.y)] != STRUCTURE_RAMPART) { + structures[getCoord(pos.x - 1, pos.y)] = s; + } + if (mask[getCoord(pos.x, pos.y + 1)] != TERRAIN_MASK_WALL + && structures[getCoord(pos.x, pos.y + 1)] != STRUCTURE_RAMPART) { + structures[getCoord(pos.x, pos.y + 1)] = s; + } + if (mask[getCoord(pos.x, pos.y - 1)] != TERRAIN_MASK_WALL + && structures[getCoord(pos.x, pos.y - 1)] != STRUCTURE_RAMPART) { + structures[getCoord(pos.x, pos.y - 1)] = s; } } - // Render // renderHeatmap(controllerDistance, room.visual); /* for (let x = 0; x < roomSize; x++) { @@ -438,10 +450,10 @@ export default profiler.registerFN(function RoomPlanner(room: Room) { let str = ""; for (let i = 0; i < structures.length; i += 2) { - str += String.fromCharCode(32 + - (structureCoding.findIndex((s) => s == structures[i])) - + (structureCoding.findIndex((s) => s == structures[i + 1]) << 5) - ); + str += String.fromCharCode(32 + + (structureCoding.findIndex(s => s == structures[i])) + + (structureCoding.findIndex(s => s == structures[i + 1]) << 5), + ); } room.memory._planner = str; diff --git a/src/Tasks/Harvest.ts b/src/Tasks/Harvest.ts index 0498854..ff8ef63 100644 --- a/src/Tasks/Harvest.ts +++ b/src/Tasks/Harvest.ts @@ -14,7 +14,7 @@ const defaultOptions: HarvestOptions = { }; export const Harvest - = (target: Source | Mineral, + = (target: Source | Mineral, opts: Partial = {}): TaskData => ({ target, targetPos: target.pos, @@ -33,7 +33,7 @@ export const runHarvest = profiler.registerFN((creep: Creep): TaskStatus => { return TaskStatus.DONE; } - const target = task.target as Source | Mineral | null; + const target = task.target as Source | Mineral | null; const opts = task.options as HarvestOptions; const data = task.data as HarvestData; diff --git a/src/Tasks/Task.ts b/src/Tasks/Task.ts index 9043477..938aa6b 100644 --- a/src/Tasks/Task.ts +++ b/src/Tasks/Task.ts @@ -9,7 +9,7 @@ export enum TaskType { Transfer, Build, Repair, - Pickup + Pickup, } export enum TaskStatus { diff --git a/src/Workers/Clerk.ts b/src/Workers/Clerk.ts index d2afdf8..3321887 100644 --- a/src/Workers/Clerk.ts +++ b/src/Workers/Clerk.ts @@ -1,26 +1,53 @@ -import { runAction } from "../Actions/Action"; -import { harvestFromClosestActiveSource } from "../Actions/harvest"; -import { transferEnergy } from "../Actions/transferEnergy"; -import { upgradeController } from "../Actions/upgradeController"; import { closestContainerWithEnergy, closestExtensionToFill, - closestStorageToFill, closestTowerToFill, - notNull, -} from "../Actions/Util"; -import { withdrawEnergy } from "../Actions/withdrawEnergy"; +} from "./Util"; +import Tasks from "../Tasks"; import { WorkerDefinition } from "./worker"; -const action = (creep: Creep, spawn: StructureSpawn) => runAction(creep, - withdrawEnergy(closestContainerWithEnergy(creep.pos))) - .or(harvestFromClosestActiveSource()) - .andThen(transferEnergy(closestExtensionToFill(creep.pos))) - .or(transferEnergy(spawn)) - .or(transferEnergy(closestTowerToFill(creep.pos))) - .or(transferEnergy(closestStorageToFill(creep.pos, RESOURCE_ENERGY))) - .or(notNull(creep.room.controller, upgradeController)) - .repeat(); +const assignTask = (creep: Creep) => { + if (creep.store.energy > 0) { + const ext = closestExtensionToFill(creep.pos); + if (ext != null) { + return Tasks.Transfer(ext); + } + if (creep.room.spawn?.store.getFreeCapacity(RESOURCE_ENERGY) ?? 0 > 0) { + return Tasks.Transfer(creep.room.spawn!); + } + const tower = closestTowerToFill(creep.pos); + if (tower != null) { + return Tasks.Transfer(tower); + } + if (creep.room.controller != null) { + if (creep.room.controller.ticksToDowngrade > 1000) { + const urgentRepair = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, { + filter: s => s.hits < s.hitsMax * 0.3, + }); + if (urgentRepair != null) { + return Tasks.Repair(urgentRepair); + } + } + return Tasks.Upgrade(creep.room.controller); + } + } + else { + const resource = creep.pos.findClosestByRange(FIND_DROPPED_RESOURCES, + { filter: r => r.resourceType === RESOURCE_ENERGY }); + if (resource != null) { + return Tasks.Pickup(resource); + } + const container = closestContainerWithEnergy(creep.pos); + if (container != null) { + return Tasks.Withdraw(container); + } + const source = creep.pos.findClosestByPath(FIND_SOURCES_ACTIVE); + if (source != null) { + return Tasks.Harvest(source); + } + } + return null; +}; const body = (energy: number) => ( energy < 100 @@ -30,7 +57,7 @@ const body = (energy: number) => ( ); export const Clerk: WorkerDefinition = { - runAction: action, + assignTask, name: "clerk", requiredCreeps: () => 3, bodyDefinition: body, diff --git a/src/Workers/Constructor.ts b/src/Workers/Constructor.ts index 230ffea..72d893d 100644 --- a/src/Workers/Constructor.ts +++ b/src/Workers/Constructor.ts @@ -1,34 +1,61 @@ -import { runAction } from "../Actions/Action"; -import { buildConstructionSite } from "../Actions/buildConstructionSite"; -import { harvestFromClosestActiveSource } from "../Actions/harvest"; -import { repairStructure } from "../Actions/repairStructure"; -import { upgradeController } from "../Actions/upgradeController"; import { closestContainerWithEnergy, - closestStorageWithResource, - notNull, -} from "../Actions/Util"; -import { withdrawEnergy } from "../Actions/withdrawEnergy"; +} from "./Util"; +import Tasks from "../Tasks"; import { WorkerDefinition } from "./worker"; -const action = (creep: Creep) => runAction(creep, - withdrawEnergy(closestStorageWithResource(creep.pos, RESOURCE_ENERGY))) - .or(withdrawEnergy(closestContainerWithEnergy(creep.pos))) - .or(harvestFromClosestActiveSource()) - .andThen(buildConstructionSite()) - .or(repairStructure()) - .or(notNull(creep.room.controller, upgradeController)) - .repeat(); +const assignTask = (creep: Creep) => { + if (creep.store.energy === 0) { + const storage = creep.room.storage; + if (storage != null && storage.store.energy > 0) { + return Tasks.Withdraw(storage); + } + const container = closestContainerWithEnergy(creep.pos); + if (container != null) { + return Tasks.Withdraw(container); + } + const source = creep.room.sources.find(s => s.energy > 0); + if (source != null) { + return Tasks.Harvest(source); + } + } + else { + const urgentRepair = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, { + filter: s => s.hits < s.hitsMax * 0.3, + }); + if (urgentRepair != null) { + return Tasks.Repair(urgentRepair); + } + const constructionSite + = creep.pos.findClosestByRange(FIND_MY_CONSTRUCTION_SITES); + if (constructionSite != null) { + return Tasks.Build(constructionSite); + } + const structure = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, { + filter: s => s.hits < s.hitsMax * 0.8, + }) ?? creep.pos.findClosestByRange(FIND_STRUCTURES, { + filter: s => s.hits < s.hitsMax * 0.8 + && (s.structureType === STRUCTURE_WALL + || s.structureType === STRUCTURE_ROAD), + }); + if (structure != null) { + return Tasks.Repair(structure); + } + else if (creep.room.controller != null) { + return Tasks.Upgrade(creep.room.controller); + } + } + return null; +}; const body = (energy: number) => new Array(Math.floor(energy / 250)) .fill([WORK, MOVE, CARRY, CARRY]).reduce((x, y) => x.concat(y), []); export const Constructor: WorkerDefinition = { - runAction: action, + assignTask, name: "constructor", - requiredCreeps: (room: Room) => - room.find(FIND_CONSTRUCTION_SITES).length > 10 ? 2 : 1, + requiredCreeps: () => 1, bodyDefinition: body, motivationalThougts: [ "I 💗 making", diff --git a/src/Workers/Miner.ts b/src/Workers/Miner.ts index 5d0ee5d..4ce15fc 100644 --- a/src/Workers/Miner.ts +++ b/src/Workers/Miner.ts @@ -1,29 +1,32 @@ -import { runAction } from "../Actions/Action"; -import { harvestFromClosestActiveSource } from "../Actions/harvest"; -import { transferEnergy } from "../Actions/transferEnergy"; -import { closestContainerToFill } from "../Actions/Util"; +import Tasks from "../Tasks"; import { WorkerDefinition } from "./worker"; -const action = (creep: Creep) => runAction(creep, - harvestFromClosestActiveSource()) - .andThen(transferEnergy(closestContainerToFill(creep.pos))) - .repeat(); +const assignTask = (creep: Creep) => { + const source = creep.room.sources.find( + s => s.container != null + && s.assignedCreeps.find(c => c.name.startsWith("miner")) == null); + if (source != null) { + return Tasks.Harvest(source, { stopWhenFull: false }); + } + return null; +}; -const body = (energy: number) => ( - energy < 300 - ? [] - : ([WORK, WORK, MOVE, CARRY] - .concat(new Array(Math.floor((energy - 300) / 100)).fill(WORK))) -); +const body = (energy: number) => { + const maximumWorkParts + = SOURCE_ENERGY_CAPACITY / ENERGY_REGEN_TIME / HARVEST_POWER; + if (energy < BODYPART_COST.move + BODYPART_COST.work) { + return []; + } + return [MOVE].concat(new Array(Math.min(maximumWorkParts, + Math.floor((energy - BODYPART_COST.move) / BODYPART_COST.work))) + .fill(WORK)); +}; export const Miner: WorkerDefinition = { - runAction: action, + assignTask, name: "miner", requiredCreeps: (room: Room) => - room.find(FIND_STRUCTURES, - { filter: { structureType: STRUCTURE_CONTAINER } }).length > 0 - ? 4 - : 0, + room.sources.filter(s => s.container != null).length, bodyDefinition: body, motivationalThougts: [ "RocknStone", diff --git a/src/Workers/Upgrader.ts b/src/Workers/Upgrader.ts index 7f42a69..fa6d274 100644 --- a/src/Workers/Upgrader.ts +++ b/src/Workers/Upgrader.ts @@ -1,27 +1,33 @@ -import { runAction } from "../Actions/Action"; -import { harvestFromClosestActiveSource } from "../Actions/harvest"; -import { upgradeController } from "../Actions/upgradeController"; -import { - closestContainerWithEnergy, - closestStorageWithResource, - notNull, -} from "../Actions/Util"; -import { withdrawEnergy } from "../Actions/withdrawEnergy"; +import Tasks from "../Tasks"; +import { closestContainerWithEnergy, closestStorageWithResource } from "./Util"; import { WorkerDefinition } from "./worker"; -const action = (creep: Creep) => runAction(creep, - withdrawEnergy(closestStorageWithResource(creep.pos, RESOURCE_ENERGY))) - .or(withdrawEnergy(closestContainerWithEnergy(creep.pos))) - .or(harvestFromClosestActiveSource()) - .andThen(notNull(creep.room.controller, upgradeController)) - .repeat(); +const assignTask = (creep: Creep) => { + if (creep.store.energy > 0 + && creep.room.controller != null) { + return Tasks.Upgrade(creep.room.controller); + } + const storage = closestStorageWithResource(creep.pos, RESOURCE_ENERGY); + if (storage != null) { + return Tasks.Withdraw(storage); + } + const container = closestContainerWithEnergy(creep.pos); + if (container != null) { + return Tasks.Withdraw(container); + } + const source = creep.pos.findClosestByPath(FIND_SOURCES_ACTIVE); + if (source != null) { + return Tasks.Harvest(source); + } + return null; +}; const body = (energy: number) => new Array(Math.floor(energy / 300)) .fill([WORK, WORK, MOVE, CARRY]).reduce((x, y) => x.concat(y), []); export const Upgrader: WorkerDefinition = { - runAction: action, + assignTask, name: "upgrader", requiredCreeps: () => 1, bodyDefinition: body, diff --git a/src/Workers/worker.ts b/src/Workers/worker.ts index 5c5ae93..d8b3c19 100644 --- a/src/Workers/worker.ts +++ b/src/Workers/worker.ts @@ -1,38 +1,37 @@ +import profiler from "screeps-profiler"; +import { TaskData } from "../Tasks/Task"; + export interface WorkerDefinition { - runAction: (creep: Creep, spawn: StructureSpawn) => void; + assignTask: (creep: Creep) => TaskData | null; name: string; requiredCreeps: (room: Room) => number; bodyDefinition: (energy: number) => BodyPartConstant[]; motivationalThougts?: string[]; } -export const spawnWorkers - = (spawn: StructureSpawn, workers: WorkerDefinition[]): void => { +export const spawnWorkers = profiler.registerFN( + (spawn: StructureSpawn, workers: WorkerDefinition[]): void => { for (const worker of workers) { for (let i = 0; i < worker.requiredCreeps(spawn.room); i++) { - const ret = spawn.spawnCreep(worker.bodyDefinition( - spawn.store.getCapacity(RESOURCE_ENERGY) - + (spawn.room.find(FIND_MY_STRUCTURES, - { filter: { structureType: STRUCTURE_EXTENSION } }).length - * (Object.keys(Game.creeps).length < 2 - ? (25 * Object.keys(Game.creeps).length) - : 50))), worker.name + i.toString()); + const ret = spawn.spawnCreep( + worker.bodyDefinition(spawn.room.energyCapacityAvailable), + worker.name + i.toString()); if (ret === OK || ret === ERR_NOT_ENOUGH_ENERGY) { return; } } } - }; + }, "spawnWorkers"); -export const runWorkers - = (spawn: StructureSpawn, workers: WorkerDefinition[]): void => { +export const runWorkers = profiler.registerFN( + function runWorkers(workers: WorkerDefinition[]) { for (const worker of workers) { for (const creep of Object.values(Game.creeps)) { if (creep.spawning) { continue; } if (creep.name.startsWith(worker.name)) { - worker.runAction(creep, spawn); + creep.run(worker.assignTask); if (worker.motivationalThougts != null && Math.random() < 0.1) { creep.say( worker.motivationalThougts[ @@ -42,4 +41,4 @@ export const runWorkers } } } - }; + }); diff --git a/src/index.ts b/src/index.ts index 4c8c5a8..7d565ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,14 @@ -import { buildContainers } from "./RoomPlanner/Blueprints/Containers"; -import { buildExtentions } from "./RoomPlanner/Blueprints/Extensions"; -import { buildRoads } from "./RoomPlanner/Blueprints/Roads"; import { Clerk } from "./Workers/Clerk"; import { Constructor } from "./Workers/Constructor"; import { Miner } from "./Workers/Miner"; import { Upgrader } from "./Workers/Upgrader"; import { runWorkers, spawnWorkers } from "./Workers/worker"; import "../deps/Traveler/Traveler"; +import profiler from "screeps-profiler"; +import "./Proto"; +import RoomPlanner from "./RoomPlanner"; -const runTowers = (spawn: StructureSpawn) => { +const runTowers = profiler.registerFN((spawn: StructureSpawn) => { const towers: StructureTower[] = spawn.room.find(FIND_MY_STRUCTURES, { filter: s => s.structureType === STRUCTURE_TOWER }); for (const tower of towers) { @@ -34,28 +34,32 @@ const runTowers = (spawn: StructureSpawn) => { console.log(tower.repair(str)); } }; -}; +}, "runTowers"); -export function loop() { +profiler.enable(); +export const loop = profiler.wrap(() => { const spawn = Game.spawns.Spawn1; const controller = spawn.room.controller; if (!controller) { return; } - const workerTypes = [Clerk, Upgrader, Miner, Constructor]; - spawnWorkers(spawn, workerTypes); - runWorkers(spawn, workerTypes); - runTowers(spawn); - if (Game.time % 100 === 0) { - buildRoads(spawn.room); + if (spawn.room.name != "sim") { + const workerTypes = [Clerk, Upgrader, Miner, Constructor]; + spawnWorkers(spawn, workerTypes); + runWorkers(workerTypes); + runTowers(spawn); } - if (Game.time % 100 === 50) { - buildExtentions(spawn.room); + + for (const creep in Memory.creeps) { + if (!(creep in Game.creeps)) { + delete Memory.creeps[creep]; + } } - if (Game.time % 100 === 25) { - buildContainers(spawn.room); + if (Game.time % 101 === 0) { + Game.profiler.email(100); } if (Game.cpu.bucket === 10000) { Game.cpu.generatePixel(); } -} + RoomPlanner(spawn.room); +}); diff --git a/yarn.lock b/yarn.lock index 0b56460..9743355 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,6 +1163,11 @@ dependencies: undici-types "~7.16.0" +"@types/screeps-profiler@^1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@types/screeps-profiler/-/screeps-profiler-1.2.6.tgz#dae10bda7a5321fb54de4ef7452687d187ae4a8b" + integrity sha512-eKGrjB28yknFsoEeXfGny0yz3MNN0QEYKcOb7jSPgm3KLfZUBL2FqNEiCj4kF7E1v4HG9F2/J5rXFDoyNy4u+A== + "@types/screeps@^3.3.8": version "3.3.8" resolved "https://registry.yarnpkg.com/@types/screeps/-/screeps-3.3.8.tgz#64ca98d10e250ef454508db17919b1927c744cb6" @@ -1517,6 +1522,13 @@ ansi-escapes@^4.3.2: dependencies: type-fest "^0.21.3" +ansi-escapes@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.2.0.tgz#31b25afa3edd3efc09d98c2fee831d460ff06b49" + integrity sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw== + dependencies: + environment "^1.0.0" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -1546,7 +1558,7 @@ ansi-styles@^5.2.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -ansi-styles@^6.1.0: +ansi-styles@^6.1.0, ansi-styles@^6.2.1: version "6.2.3" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== @@ -1811,6 +1823,21 @@ cjs-module-lexer@^2.1.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz#bff23b0609cc9afa428bd35f1918f7d03b448562" integrity sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ== +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== + dependencies: + restore-cursor "^5.0.0" + +cli-truncate@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-5.1.1.tgz#455476face9904d94b7d11e98d9adbca15292ea5" + integrity sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A== + dependencies: + slice-ansi "^7.1.0" + string-width "^8.0.0" + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -1854,6 +1881,16 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.2.tgz#b71fd37fe4069e4c3c7c13925252ada4eba14e8e" + integrity sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ== + commander@^6.0.0: version "6.2.1" resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" @@ -1985,6 +2022,11 @@ emittery@^0.13.1: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== +emoji-regex@^10.3.0: + version "10.6.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d" + integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -1995,6 +2037,11 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -2123,6 +2170,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + events-universal@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/events-universal/-/events-universal-1.0.1.tgz#b56a84fd611b6610e0a2d0f09f80fdf931e2dfe6" @@ -2319,6 +2371,11 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.0, get-east-asian-width@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz#9bc4caa131702b4b61729cb7e42735bc550c9ee6" + integrity sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q== + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -2501,6 +2558,13 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-fullwidth-code-point@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz#046b2a6d4f6b156b2233d3207d4b5a9783999b98" + integrity sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ== + dependencies: + get-east-asian-width "^1.3.1" + is-generator-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" @@ -3030,6 +3094,31 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +lint-staged@^16.2.7: + version "16.2.7" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.7.tgz#c4a635960c17b52fe774f1f40aee8ce1bd86531f" + integrity sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow== + dependencies: + commander "^14.0.2" + listr2 "^9.0.5" + micromatch "^4.0.8" + nano-spawn "^2.0.0" + pidtree "^0.6.0" + string-argv "^0.3.2" + yaml "^2.8.1" + +listr2@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-9.0.5.tgz#92df7c4416a6da630eb9ef46da469b70de97b316" + integrity sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g== + dependencies: + cli-truncate "^5.0.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^6.1.0" + rfdc "^1.4.1" + wrap-ansi "^9.0.0" + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -3054,6 +3143,17 @@ lodash@^3: resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" integrity sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ== +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== + dependencies: + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" + lowercase-keys@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" @@ -3120,6 +3220,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== + mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" @@ -3159,6 +3264,11 @@ ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +nano-spawn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-2.0.0.tgz#f1250434c09ae18870d4f729fc54b406cf85a3e1" + integrity sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw== + napi-postinstall@^0.3.0: version "0.3.4" resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.4.tgz#7af256d6588b5f8e952b9190965d6b019653bbb9" @@ -3210,6 +3320,13 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== + dependencies: + mimic-function "^5.0.0" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -3325,6 +3442,11 @@ picomatch@^4.0.2, picomatch@^4.0.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== +pidtree@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + pirates@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" @@ -3412,6 +3534,19 @@ responselike@^3.0.0: dependencies: lowercase-keys "^3.0.0" +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== + dependencies: + onetime "^7.0.0" + signal-exit "^4.1.0" + +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== + safe-buffer@5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -3424,6 +3559,11 @@ screeps-jest@^2.0.3: dependencies: lodash "^3" +screeps-profiler@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/screeps-profiler/-/screeps-profiler-3.0.0.tgz#4d76c6e7465f50d6bf7d0dab667001cfc03e8d49" + integrity sha512-wIXkRvRbz+1utWY/RysmvpOT7kvV5CpMwknpGDx2UKiL8G5SIp7K2LsOtNb+EeIxPrrvNfpHN6BAkcgJKZT1qQ== + seek-bzip@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-2.0.0.tgz#f0478ab6acd0ac72345d18dc7525dd84d3c706a2" @@ -3482,7 +3622,7 @@ signal-exit@^3.0.3: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.0.1: +signal-exit@^4.0.1, signal-exit@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== @@ -3492,6 +3632,14 @@ slash@3.0.0, slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slice-ansi@^7.1.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.2.tgz#adf7be70aa6d72162d907cd0e6d5c11f507b5403" + integrity sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w== + dependencies: + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" + sort-keys-length@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" @@ -3545,6 +3693,11 @@ streamx@^2.15.0: fast-fifo "^1.3.2" text-decoder "^1.1.0" +string-argv@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + string-length@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -3580,6 +3733,23 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" +string-width@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== + dependencies: + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" + +string-width@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-8.1.0.tgz#9e9fb305174947cf45c30529414b5da916e9e8d1" + integrity sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg== + dependencies: + get-east-asian-width "^1.3.0" + strip-ansi "^7.1.0" + "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -3594,7 +3764,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: +strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.2" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba" integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA== @@ -3904,6 +4074,15 @@ wrap-ansi@^8.1.0: string-width "^5.0.1" strip-ansi "^7.0.1" +wrap-ansi@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz#956832dea9494306e6d209eb871643bb873d7c98" + integrity sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -3932,6 +4111,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^2.8.1: + version "2.8.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.2.tgz#5694f25eca0ce9c3e7a9d9e00ce0ddabbd9e35c5" + integrity sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A== + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"