This commit is contained in:
Kevin Alberts 2019-11-29 15:19:38 +01:00
commit 35bcd8d435
Signed by: Kurocon
GPG key ID: BCD496FEBA0C6BC1
17 changed files with 1784 additions and 0 deletions

76
creep.custom.js Normal file
View file

@ -0,0 +1,76 @@
var customCreep = function() {
StructureSpawn.prototype.spawnCustomCreep = function(role, name, energy, behaviourLevel) {
var body_parts = [];
var body_pre = [];
var body_component = [];
var body_post = []
var body_pre_cost = 0;
var body_component_cost = 0;
var body_post_cost = 0;
switch(role) {
case 'upgrader':
body_component = [WORK, CARRY, CARRY, MOVE];
body_component_cost = 250;
break;
case 'harvester':
body_pre = [CARRY, CARRY, MOVE];
body_pre_cost = 150;
body_component = [WORK];
body_component_cost = 100;
break;
case 'refiller':
body_pre = [WORK, MOVE];
body_pre_cost = 150;
body_component = [CARRY, CARRY, MOVE];
body_component_cost = 150;
break;
case 'wallRepairer':
body_component = [WORK, CARRY, CARRY, MOVE, MOVE, MOVE];
body_component_cost = 350;
break;
case 'pickup':
body_pre = [WORK, MOVE];
body_pre_cost = 150;
body_component = [CARRY, CARRY, MOVE];
body_component_cost = 150;
break;
case 'repairer':
body_component = [WORK, CARRY, CARRY, MOVE, MOVE];
body_component_cost = 300;
break;
case 'builder':
body_component = [WORK, CARRY, CARRY, MOVE];
body_component_cost = 250;
break;
default:
body_component = [WORK, CARRY, MOVE];
body_component_cost = 200;
break;
}
var num_body_part_patches = Math.floor((energy - (body_pre_cost + body_post_cost)) / body_component_cost);
// Make pre-body
for(var part of body_pre) {
body_parts.push(part);
}
// Make component body
for(var i = 0; i < num_body_part_patches; i++) {
for(var part of body_component) {
body_parts.push(part);
}
}
// Make post-body
for(var part of body_post) {
body_parts.push(part);
}
return this.spawnCreep(body_parts, name, {memory: {role: role}});
}
}
module.exports = customCreep;

26
energy.harvest.js Normal file
View file

@ -0,0 +1,26 @@
var harvester = require('energy.harvest.roundrobin');
var do_collect = function(creep, done_state, done_state_message) {
var source = null;
if(creep.memory.source_id) {
source = Game.getObjectById(creep.memory.source_id);
} else {
source = harvester.get_source(creep);
}
if(creep.store.getFreeCapacity() > 0) {
if(creep.harvest(source) == ERR_NOT_IN_RANGE) {
creep.moveTo(source, {visualizePathStyle: {stroke: '#ffaa00'}});
}
} else {
creep.memory.state = done_state;
harvester.release_source(creep);
creep.say(done_state_message);
}
}
var baseHarvester = {
do_collect: do_collect,
}
module.exports = baseHarvester;

View file

@ -0,0 +1,33 @@
var get_source = function(creep) {
var sources = creep.room.find(FIND_SOURCES);
var minSource = null;
var minSourceCount = null;
for(let source of sources) {
var amount_at_source = Memory.rooms[creep.room.name].sources[source.id] - Memory.rooms[creep.room.name].sources_spots[source.id];
if (minSourceCount == null || amount_at_source < minSourceCount) {
minSourceCount = amount_at_source;
minSource = source;
}
}
Memory.rooms[creep.room.name].sources[minSource.id] += 1;
creep.memory.source_id = minSource.id;
return minSource;
}
var release_source = function(creep) {
if(creep.memory.source_id) {
if(Memory.rooms[creep.room.name].sources[creep.memory.source_id] > 0){
Memory.rooms[creep.room.name].sources[creep.memory.source_id] -= 1;
}
delete creep.memory.source_id;
}
}
var roundRobinHarvester = {
get_source: get_source,
release_source: release_source
}
module.exports = roundRobinHarvester;

30
energy.storage.js Normal file
View file

@ -0,0 +1,30 @@
// Finds the closest container that has something in it
var find_container = function(creep) {
return creep.pos.findClosestByPath(FIND_STRUCTURES, {
filter: (s) => {
return (s.structureType == STRUCTURE_CONTAINER ||
s.structureType == STRUCTURE_STORAGE) &&
s.store.getUsedCapacity(RESOURCE_ENERGY) > 0;
}
});
}
var do_collect = function(creep, done_state, done_state_message) {
var container = find_container(creep);
if (container) {
if(creep.withdraw(container, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(container, {visualizePathStyle: {stroke: '#ffaa00'}});
}
}
if (creep.store.getFreeCapacity() == 0) {
// If we are full with energy, switch to the next state
creep.memory.state = done_state;
creep.say(done_state_message);
}
}
var baseCollector = {
do_collect: do_collect,
}
module.exports = baseCollector;

43
idle.base.js Normal file
View file

@ -0,0 +1,43 @@
var do_idle = function(creep) {
// No structure needs filling and my charge is full, move to an idle location
if (!creep.memory.idlePosition) {
var idlePosition;
switch (creep.room.name){
case "E16N2":
min_x = 36;
min_y = 7;
max_x = 40;
max_y = 8;
idlePosition = new RoomPosition(Math.floor(Math.random() * (max_x - min_x)) + min_x, Math.floor(Math.random() * (max_y - min_y)) + min_y, creep.room.name);
break;
default:
// Calculate a good idle position next to the closest spawn station
idlePosition = creep.pos.findClosestByRange(FIND_MY_SPAWNS).pos;
idlePosition.x = idlePosition.x - (Math.floor(Math.random() * 4) + 2); // Number between 2 and 4
idlePosition.y = idlePosition.y + (Math.floor(Math.random() * 5) - 2); // Number between -2 and 2
break;
}
creep.memory.idlePosition = {'x': idlePosition.x, 'y': idlePosition.y};
}
// If we are not at the idle position, move there.
if(!creep.pos.isEqualTo(creep.memory.idlePosition.x, creep.memory.idlePosition.y)) {
var result = creep.moveTo(new RoomPosition(creep.memory.idlePosition.x, creep.memory.idlePosition.y, creep.room.name), {visualizePathStyle: {stroke: '#aaaaaa'}});
if (result == ERR_NO_PATH) {
creep.say('No path');
delete creep.memory.idlePosition;
}
}
}
var clear_idle = function(creep) {
delete creep.memory.idlePosition;
}
var baseIdler = {
do_idle: do_idle,
clear_idle: clear_idle,
}
module.exports = baseIdler;

266
main.js Normal file
View file

@ -0,0 +1,266 @@
var _ = require('lodash');
var roleBase = require('role.base');
var roleIdle = require('role.idle');
var roleHarvester = require('role.harvester');
var roleHarvesterV2 = require('role.harvester.v2');
var roleRefiller = require('role.refiller');
var roleUpgrader = require('role.upgrader');
var roleBuilder = require('role.builder');
var roleRepairer = require('role.repairer');
var roleWallRepairer = require('role.wallrepairer');
var rolePickup = require('role.pickup');
/* About behaviour levels:
Level -1
Special level to make all creeps move to an idle location.
Level 1
The starting level, this can be run from the start of the map.
All bots will mine the resources they need, then do their task.
Level 2
This introduces refillers, overhauls harvesters and changes the behaviour of the rest.
Harvesters will deposit mined energy into a container or storage unit placed nearby.
Refillers will take energy to structures that need them.
Other creeps will take energy from the container/storage instead of mining them themselves.
Requirements: Containers placed next to all free spots of the sources in the room.
Harvesters will then place themselves between the container and the source.
For example: (S = source, H = harvester, C = container, X = wall, _ = empty)
__C__
_HHH_
CHSXX
_HXXX
__XXX
*/
var behaviourLevel = 2;
require('creep.custom')();
// Profiler - https://github.com/screepers/screeps-profiler
const profiler = require('screeps-profiler');
// Monkey-patch in the profiler
profiler.enable();
module.exports.loop = function () {
// Wrap my code in the profiler
profiler.wrap(function() {
// Setup variables with in-game objects for use in the script
var towers = _.filter(Game.structures, {structureType: STRUCTURE_TOWER});
var harvesters = _.filter(Game.creeps, (creep) => creep.memory.role == 'harvester');
var refillers = _.filter(Game.creeps, (creep) => creep.memory.role == 'refiller');
var builders = _.filter(Game.creeps, (creep) => creep.memory.role == 'builder');
var upgraders = _.filter(Game.creeps, (creep) => creep.memory.role == 'upgrader');
var repairers = _.filter(Game.creeps, (creep) => creep.memory.role == 'repairer');
var wallRepairers = _.filter(Game.creeps, (creep) => creep.memory.role == 'wallRepairer');
var pickups = _.filter(Game.creeps, (creep) => creep.memory.role == 'pickup');
// Cleanup memory
for(var name in Memory.creeps) {
if(!Game.creeps[name]) {
roleBase.clearMemory(name);
delete Memory.creeps[name];
console.log('Clearing non-existing creep memory:', name);
}
}
if(Memory.rooms == undefined) {Memory.rooms = {};}
for (var name in Game.rooms) {
if(Memory.rooms[name] == undefined) {
Memory.rooms[name] = {};
}
if(Memory.rooms[name].repairs == undefined) {
Memory.rooms[name].repairs = []
}
if(Memory.rooms[name].sources == undefined) {
Memory.rooms[name].sources = {};
for(let source of Game.rooms[name].find(FIND_SOURCES)) {
Memory.rooms[name].sources[source.id] = 0;
}
}
if(Memory.rooms[name].sources_spots == undefined) {
Memory.rooms[name].sources_spots = {};
for(let source of Game.rooms[name].find(FIND_SOURCES)) {
var num_spots = 0;
for (let x of [-1, 0, 1]) {
for (let y of [-1, 0, 1]) {
if(!(x == 0 && y == 0)){
var pos = new RoomPosition(source.pos.x + x, source.pos.y + y, source.pos.roomName);
if(pos.lookFor(LOOK_TERRAIN) == "plain"){
num_spots += 1;
}
}
}
}
Memory.rooms[name].sources_spots[source.id] = num_spots;
}
}
}
// Tower auto-repair structures nearby
for(var tower_id in towers) {
var tower = towers[tower_id];
// var closestDamagedStructure = tower.pos.findClosestByRange(FIND_STRUCTURES, {
// filter: (structure) => structure.hits < structure.hitsMax
// });
// if(closestDamagedStructure) {
// tower.repair(closestDamagedStructure);
// }
var closestHostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
if(closestHostile) {
tower.attack(closestHostile);
}
}
// Auto-spawn new creeps
var to_spawn = [];
var gameTime = Game.time.toString();
var name_index = gameTime.substring(gameTime.length-4, gameTime.length);
if(harvesters.length < 2) {
to_spawn.push(['harvester', 'Harvey' + name_index, [WORK, CARRY, MOVE]]);
}
// Refillers only necessary from behaviour level 2
if(behaviourLevel >= 2) {
if(refillers.length < 2) {
to_spawn.push(['refiller', 'Reffy' + name_index, [WORK, CARRY, MOVE]]);
}
}
if(builders.length < 1) {
to_spawn.push(['builder', 'Bob' + name_index, [WORK, CARRY, MOVE]]);
}
if(repairers.length < 2) {
to_spawn.push(['repairer', 'Reppy' + name_index, [WORK, CARRY, MOVE]]);
}
if(upgraders.length < 1) {
to_spawn.push(['upgrader', 'Uppy' + name_index, [WORK, CARRY, MOVE]]);
}
if(wallRepairers.length < 1) {
to_spawn.push(['wallRepairer', 'Wally' + name_index, [WORK, CARRY, MOVE]]);
}
if(pickups.length < 1) {
to_spawn.push(['pickup', 'Picky' + name_index, [WORK, CARRY, MOVE]]);
}
if(to_spawn.length > 0) {
for(var spawner_id in Game.spawns) {
var spawner = Game.spawns[spawner_id];
if(!spawner.spawning){
var entry = to_spawn.shift();
console.log("Spawning " + entry[0]);
var spawned = false;
var max_available_energy = spawner.store.getCapacity(RESOURCE_ENERGY);
for(let extension of _.filter(Game.structures, {structureType: STRUCTURE_EXTENSION, room: spawner.room})) {
max_available_energy += extension.store.getCapacity(RESOURCE_ENERGY);
}
//max_available_energy = 300;
var result = spawner.spawnCustomCreep(entry[0], entry[1], max_available_energy, behaviourLevel);
if (result == OK) {
spawner.room.visual.text('Spawning ' + entry[1] + ' /w ' + max_available_energy + " energy.", spawner.pos.x + 1, spawner.pos.y, {align: 'left', opacity: 0.8});
}
// If there are no harvesters any more, and there is not enough energy, spawn a basic harvester.
if(harvesters.length == 0 && result == ERR_NOT_ENOUGH_ENERGY) {
result = spawner.spawnCreep([WORK, CARRY, MOVE], "BasicHarvester", {memory: {role: 'harvester'}});
if (result == OK) {
spawner.room.visual.text('Spawning BasicHarvester.');
}
}
// If there are no refillers any more, and there is not enough energy, spawn a basic refiller.
if(refillers.length == 0 && result == ERR_NOT_ENOUGH_ENERGY) {
result = spawner.spawnCreep([WORK, CARRY, MOVE], "BasicRefiller", {memory: {role: 'refiller'}});
if (result == OK) {
spawner.room.visual.text('Spawning BasicRefiller.');
}
}
if (result != OK) {
switch (result) {
case ERR_BUSY:
console.log("Could not spawn " + entry[1] + ", spawner is busy.");
break;
case ERR_NOT_ENOUGH_ENERGY:
console.log("Could not spawn " + entry[1] + ", not enough energy.");
break;
case ERR_RCL_NOT_ENOUGH:
console.log("Could not spawn " + entry[1] + ", RCL not high enough.");
break;
default:
console.log("Could not spawn " + entry[1] + ", error code " + result);
break;
}
} else {
spawned = true;
}
}
}
if(!spawned){
console.log("Could not spawn, all spawners are busy or errored.");
}
}
// Execute creep ticks
for(var name in Game.creeps) {
var creep = Game.creeps[name];
var continue_with_role = roleBase.run(creep, behaviourLevel);
// If we are at behaviour level -1, move all bots to an idle position
if (behaviourLevel == -1) {
roleIdle.run(creep, behaviourLevel);
} else {
// Else, continue with the normal roles
if(continue_with_role) {
switch(creep.memory.role) {
case "harvester":
if (behaviourLevel >= 2) {
roleHarvesterV2.run(creep, behaviourLevel);
} else {
roleHarvester.run(creep, behaviourLevel);
}
break;
case "refiller":
if (behaviourLevel >= 2) {
roleRefiller.run(creep, behaviourLevel);
} else {
// No defined behaviour for refillers on level 1, just act as a Harvester.
roleHarvester.run(creep, behaviourLevel);
}
break;
case "upgrader":
roleUpgrader.run(creep, behaviourLevel);
break;
case "builder":
roleBuilder.run(creep, behaviourLevel);
break;
case "repairer":
roleRepairer.run(creep, behaviourLevel);
break;
case "wallRepairer":
roleWallRepairer.run(creep, behaviourLevel);
break;
case "pickup":
rolePickup.run(creep, behaviourLevel);
break;
default:
console.log("Creep with role " + creep.memory.role + " has no defined behaviour.");
}
}
}
}
// Print used CPU ticks every 10 game ticks
if(Game.time % 100 == 0) {
if(Game.cpu.limit){
console.log("Used " + Game.cpu.getUsed() + " / " + Game.cpu.limit + "(L) / " + Game.cpu.tickLimit + " (B) CPU this tick. Bucket level: " + Game.cpu.bucket);
}
}
});
}

40
role.base.js Normal file
View file

@ -0,0 +1,40 @@
var roleBase = {
clearMemory: function(creep_name) {
var memory = Memory.creeps[creep_name];
console.log("Cleaning up memory for (late) creep " + creep_name);
if(memory.source_id) {
for(var room in Game.rooms) {
if(Memory.rooms[room].sources[memory.source_id] != undefined){
if(Memory.rooms[room].sources[memory.source_id] > 0){
Memory.rooms[room].sources[memory.source_id] -= 1;
}
}
}
delete memory.source_id;
}
if(memory.repairId) {
for(var room in Game.rooms) {
_.remove(Memory.rooms[room].repairs, (n) => n == memory.repairId);
delete memory.repairId;
delete memory.repairTarget;
}
}
},
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
if(creep.ticksToLive <= 2) {
creep.say("Halp X.X!");
return false;
}
return true;
}
};
module.exports = roleBase;

69
role.builder.js Normal file
View file

@ -0,0 +1,69 @@
var idler = require('idle.base');
var harvester = require('energy.harvest');
var collector = require('energy.storage');
var get_targets = function(creep) {
return creep.room.find(FIND_CONSTRUCTION_SITES);
}
var roleBuilder = {
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
switch (creep.memory.state) {
case "idle":
idler.do_idle(creep);
if (get_targets(creep).length > 0){
// If there are any buildings to construct, switch back to the building state
idler.clear_idle(creep);
creep.memory.state = "build_structure";
creep.say("building");
}
if (creep.store.getFreeCapacity() > 0) {
// If we are not full with energy, switch to the get_energy state
idler.clear_idle(creep);
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "build_structure":
var targets = get_targets(creep);
if(targets.length > 0) {
if(creep.build(targets[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#ffffff'}});
}
} else {
// Else, go idle
creep.memory.state = "idle";
creep.say('idling');
}
if (creep.store.getUsedCapacity() == 0) {
// If we have no energy, switch to the get_energy state
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "get_energy":
var energy_source;
if(behaviourLevel >= 2) {
energy_source = collector;
} else {
energy_source = harvester;
}
energy_source.do_collect(creep, "build_structure", "building");
break;
default:
creep.memory.state = "get_energy";
creep.say("Reloading...");
}
}
};
module.exports = roleBuilder;

68
role.harvester.js Normal file
View file

@ -0,0 +1,68 @@
var idler = require('idle.base');
var harvester = require('energy.harvest');
var get_targets = function(creep) {
return creep.room.find(FIND_STRUCTURES, {
filter: (structure) => {
return (structure.structureType == STRUCTURE_EXTENSION ||
structure.structureType == STRUCTURE_SPAWN ||
structure.structureType == STRUCTURE_TOWER) &&
structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0;
}
});
}
var roleHarvester = {
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
switch (creep.memory.state) {
case "idle":
idler.do_idle(creep);
if (get_targets(creep).length > 0){
// If there are any buildings to charge, switch back to the charge state
idler.clear_idle(creep);
creep.memory.state = "charge_structure";
creep.say("Charging...");
}
if (creep.store.getFreeCapacity() > 0) {
// If we are not full with energy, switch to the get_energy state
idler.clear_idle(creep);
creep.memory.state = "get_energy";
creep.say('Harvesting...');
}
break;
case "charge_structure":
var targets = get_targets(creep);
if(targets.length > 0) {
if(creep.transfer(targets[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#449900'}});
}
} else {
// Else, go idle
creep.memory.state = "idle";
creep.say('Idling...');
}
if (creep.store.getUsedCapacity() == 0) {
// If we are not full with energy, switch to the get_energy state
creep.memory.state = "get_energy";
creep.say('Harvesting...');
}
break;
case "get_energy":
harvester.do_collect(creep, "charge_structure", "Charging...");
break;
default:
creep.memory.state = "get_energy";
creep.say('Harvesting...');
}
}
};
module.exports = roleHarvester;

204
role.harvester.v2.js Normal file
View file

@ -0,0 +1,204 @@
var idler = require('idle.base');
// Finds a new spot for the harvester to mine
var find_spot = function(creep) {
var sources = creep.room.find(FIND_SOURCES);
var possible_spots = {};
var num_spots = {};
var open_spots = {}
for(let source of sources) {
for (let x of [-1, 0, 1]) {
for (let y of [-1, 0, 1]) {
if(!(x == 0 && y == 0)){
var pos = new RoomPosition(source.pos.x + x, source.pos.y + y, source.pos.roomName);
if(pos.lookFor(LOOK_TERRAIN) == "plain"){
if(num_spots[source.id] == undefined) {
num_spots[source.id] = 0;
}
num_spots[source.id] += 1;
if(pos.lookFor(LOOK_CREEPS).length == 0) {
if(possible_spots[source.id] == undefined) {
possible_spots[source.id] = [];
}
possible_spots[source.id].push([pos.x, pos.y, pos.roomName, source.id]);
if(open_spots[source.id] == undefined) {
open_spots[source.id] = 0;
}
open_spots[source.id] += 1;
}
}
}
}
}
}
var best_source = null;
var best_occupied = null;
for (let source of sources) {
if (num_spots[source.id] != undefined && open_spots[source.id] != undefined){
var occupied = num_spots[source.id] - open_spots[source.id];
if ((best_occupied == null || occupied < best_occupied) && possible_spots[source.id] != undefined && possible_spots[source.id].length > 0) {
best_occupied = occupied;
best_source = source;
}
}
}
if (possible_spots[best_source.id].length > 0){
return possible_spots[best_source.id][0];
}
return null;
}
// Finds the container near the current spot of the creep
var find_container = function(creep) {
if (creep.memory.spot) {
for (let x of [-1, 0, 1]) {
for (let y of [-1, 0, 1]) {
if(!(x == 0 && y == 0)){
var pos = new RoomPosition(creep.memory.spot[0] + x, creep.memory.spot[1] + y, creep.memory.spot[2]);
var structs = pos.lookFor(LOOK_STRUCTURES);
for(let struct of structs) {
if (struct.structureType == STRUCTURE_CONTAINER || struct.structureType == STRUCTURE_STORAGE) {
return struct.id;
}
}
}
}
}
}
return null;
}
var roleHarvester = {
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
switch (creep.memory.state) {
case "idle":
idler.do_idle(creep);
if(creep.memory.idle_time == undefined){
creep.memory.idle_time = 0;
}
creep.memory.idle_time += 1;
// If we've been idling for a while, check if there is a spot available
if (creep.memory.idle_time > 10) {
idler.clear_idle(creep);
delete creep.memory.idle_time;
creep.memory.state = "find_spot";
creep.say("Looking...");
}
break;
case "find_spot":
// If we don't have a spot yet, find one
if (!creep.memory.spot) {
creep.memory.spot = find_spot(creep);
creep.memory.container = find_container(creep);
}
// If no spot was found, go back to idling
if (!creep.memory.spot) {
creep.memory.state = "idle";
creep.say("No spot!");
} else {
creep.memory.state = "walk_to_spot";
creep.say("Walking...");
}
break;
case "walk_to_spot":
if (creep.memory.spot) {
if (creep.pos.x != creep.memory.spot[0] || creep.pos.y != creep.memory.spot[1]) {
creep.moveTo(creep.memory.spot[0], creep.memory.spot[1], {visualizePathStyle: {stroke: '#0044aa'}})
// Check if our spot is still available
if ((new RoomPosition(creep.memory.spot[0], creep.memory.spot[1], creep.memory.spot[2])).lookFor(LOOK_CREEPS).length > 0){
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "idle";
creep.say("Occupied:(");
}
} else {
// We arrived! Start mining.
creep.memory.state = "mine_energy";
creep.say("Mining...");
}
} else {
// We don't have a spot
creep.memory.state = "find_spot";
creep.say("Looking...");
}
break;
case "mine_energy":
if (creep.memory.spot) {
var source = Game.getObjectById(creep.memory.spot[3]);
if (source) {
if(creep.store.getFreeCapacity() > 0) {
if(creep.harvest(source) == ERR_NOT_IN_RANGE) {
// Source is gone?
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say("Looking...");
}
} else {
// We are full, dump the energy into the container
creep.memory.state = "dump_energy";
creep.say("Dumping...");
}
} else {
// No source?
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say("Looking...");
}
} else {
// We don't have a spot
creep.memory.state = "find_spot";
creep.say("Looking...");
}
break;
case "dump_energy":
if (creep.memory.container) {
var container = Game.getObjectById(creep.memory.container);
if (container) {
if (container.store.getFreeCapacity(RESOURCE_ENERGY) > 0 && creep.store.getUsedCapacity() > 0) {
creep.transfer(container, RESOURCE_ENERGY);
}
} else {
// No container?
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say("Looking...");
}
if (creep.store.getUsedCapacity() == 0) {
// Everything dumped, go back to mining
creep.memory.state = "mine_energy";
creep.say("Mining...");
}
} else {
// No container?
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say("Looking...");
}
break;
default:
creep.memory.state = "find_spot";
creep.say('Looking...');
}
}
};
module.exports = roleHarvester;

14
role.idle.js Normal file
View file

@ -0,0 +1,14 @@
var idler = require('idle.base');
var roleIdle = {
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
idler.do_idle(creep);
}
};
module.exports = roleIdle;

227
role.pickup.js Normal file
View file

@ -0,0 +1,227 @@
var idler = require('idle.base');
// Finds energy laying around on the map
var find_energy = function(creep) {
if (!creep.memory.spot) {
max_energy = 0;
max_energy_obj = null;
for(let x of creep.room.find(FIND_DROPPED_RESOURCES, {filter: (s) => {return s.resourceType == RESOURCE_ENERGY}})){
if(x.amount > max_energy) {
if(x.pos.lookFor(LOOK_CREEPS).length == 0){
max_energy = x.amount;
max_energy_obj = x;
}
}
}
for (let x of creep.room.find(FIND_TOMBSTONES, {filter: (t) => {return t.store.getUsedCapacity(RESOURCE_ENERGY) > 0}})) {
if(x.store.getUsedCapacity(RESOURCE_ENERGY) > max_energy) {
if(x.pos.lookFor(LOOK_CREEPS).length == 0){
max_energy = x.store.getUsedCapacity(RESOURCE_ENERGY);
max_energy_obj = x;
}
}
}
if(max_energy_obj != null){
return [max_energy_obj.pos.x, max_energy_obj.pos.y, max_energy_obj.room.name, max_energy_obj.id];
}
}
}
// Finds the container near the current spot of the creep
var find_container = function(creep) {
var container = creep.pos.findClosestByRange(FIND_STRUCTURES, {
filter: (x) => {
return (x.structureType == STRUCTURE_CONTAINER || x.structureType == STRUCTURE_STORAGE) && x.store.getFreeCapacity(RESOURCE_ENERGY) > 0;
}
});
if (container) {
return container.id;
} else {
return null;
}
}
var rolePickup = {
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
switch (creep.memory.state) {
case "idle":
idler.do_idle(creep);
if(creep.memory.idle_time == undefined){
creep.memory.idle_time = 0;
}
creep.memory.idle_time += 1;
// If we've been idling for a while, check if there is a spot available
if (creep.memory.idle_time > 5) {
delete creep.memory.idle_time;
if(creep.store.getUsedCapacity() > 0){
creep.memory.state = "walk_to_container";
creep.say("Dropping...");
} else {
creep.memory.state = "find_spot";
creep.say("Looking...");
}
}
break;
case "find_spot":
// If we don't have a spot yet, find one
if (!creep.memory.spot) {
creep.memory.spot = find_energy(creep);
creep.memory.container = find_container(creep);
}
// If no spot was found, go back to idling
if (!creep.memory.spot) {
creep.memory.state = "idle";
creep.say("No drop!");
} else {
creep.memory.state = "walk_to_spot";
creep.say("Walking...");
}
break;
case "walk_to_spot":
if (creep.memory.spot) {
if(creep.memory.spot[0] == null || creep.memory.spot[1] == null || creep.memory.spot[2] == null){
// We don't have a spot
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say("Looking...");
} else {
if (creep.pos.x != creep.memory.spot[0] || creep.pos.y != creep.memory.spot[1]) {
creep.moveTo(creep.memory.spot[0], creep.memory.spot[1], {visualizePathStyle: {stroke: '#0044aa'}})
// Check if our spot is still available
if ((new RoomPosition(creep.memory.spot[0], creep.memory.spot[1], creep.memory.spot[2])).lookFor(LOOK_CREEPS).length > 0){
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "idle";
creep.say("Occupied:(");
}
} else {
// We arrived! Start grabbing.
creep.memory.state = "grab_energy";
creep.say("Grabbing...");
}
}
} else {
// We don't have a spot
creep.memory.state = "find_spot";
creep.say("Looking...");
}
break;
case "walk_to_container":
if (creep.memory.spot) {
delete creep.memory.spot;
}
if (creep.memory.container) {
var container = Game.getObjectById(creep.memory.container);
if (creep.pos.x != container.pos.x || creep.pos.y != container.pos.y) {
creep.moveTo(container, {visualizePathStyle: {stroke: '#0044aa'}});
} else {
// We arrived! Start dropping.
creep.memory.state = "drop_energy";
creep.say("Grabbing...");
}
} else {
// We don't have a container
creep.memory.container = find_container(creep);
if(!creep.memory.container){
creep.memory.state = "idle"
creep.say("No container:(");
}
}
break;
case "grab_energy":
if (creep.memory.spot) {
var target = Game.getObjectById(creep.memory.spot[3]);
if(target instanceof Tombstone) {
creep.withdraw(target, RESOURCE_ENERGY);
} else if (target instanceof Resource) {
creep.pickup(target);
} else {
creep.say("Unkn.Tgt.");
}
// If we have more space, look for a new spot
if(creep.store.getFreeCapacity > 0) {
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say("Looking...");
// Else, go to drop off
} else {
// We are full, dump the energy into the container
creep.memory.state = "drop_energy";
creep.say("Dumping...");
}
} else {
// We don't have a spot
creep.memory.state = "find_spot";
creep.say("Looking...");
}
break;
case "drop_energy":
if (creep.memory.container) {
var container = Game.getObjectById(creep.memory.container);
if (container) {
if (container.store.getFreeCapacity(RESOURCE_ENERGY) > 0 && creep.store.getUsedCapacity() > 0) {
if(creep.transfer(container, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(container);
}
} else if (container.store.getFreeCapacity(RESOURCE_ENERGY) == 0) {
// Find new container
creep.memory.container = find_container(creep);
if(!creep.memory.container){
creep.memory.state = "idle"
creep.say("No container:(");
}
}
} else {
// No container?
creep.memory.container = find_container(creep);
if(!creep.memory.container){
creep.memory.state = "idle"
creep.say("No container:(");
}
}
if (creep.store.getUsedCapacity() == 0) {
// Everything dumped, search for new energy
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say("Grabbing...");
}
} else {
// No container?
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say("Looking...");
}
break;
default:
creep.memory.spot = null;
creep.memory.container = null;
creep.memory.state = "find_spot";
creep.say('Looking...');
}
}
};
module.exports = rolePickup;

78
role.refiller.js Normal file
View file

@ -0,0 +1,78 @@
var idler = require('idle.base');
var collector = require('energy.storage');
// Finds the buildings that need energy
var find_targets = function(creep) {
var ref = creep.pos.findClosestByRange(FIND_STRUCTURES, {
filter: (structure) => {
return (structure.structureType == STRUCTURE_EXTENSION ||
structure.structureType == STRUCTURE_SPAWN ||
structure.structureType == STRUCTURE_TOWER) &&
structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0;
}
});
if (!ref) {
ref = creep.pos.findClosestByRange(FIND_STRUCTURES, {
filter: (s) => {
return (s.structureType == STRUCTURE_STORAGE && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0);
}
})
}
return ref;
}
var roleRefiller = {
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
switch (creep.memory.state) {
case "idle":
idler.do_idle(creep);
if (find_targets(creep)){
// If there are any buildings to charge, switch back to the charge state
idler.clear_idle(creep);
creep.memory.state = "charge_structure";
creep.say("Charging...");
}
if (creep.store.getFreeCapacity() > 0) {
// If we are not full with energy, switch to the get_energy state
idler.clear_idle(creep);
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "charge_structure":
var target = find_targets(creep);
if(target) {
if(creep.transfer(target, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(target, {visualizePathStyle: {stroke: '#449900'}});
}
} else {
// Else, go idle
creep.memory.state = "idle";
creep.say('Idling...');
}
if (creep.store.getUsedCapacity() == 0) {
// If we are not full with energy, switch to the get_energy state
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "get_energy":
collector.do_collect(creep, "charge_structure", "Charging...");
break;
default:
creep.memory.state = "idle";
creep.say('Idling...');
}
}
};
module.exports = roleRefiller;

143
role.repairer.js Normal file
View file

@ -0,0 +1,143 @@
var idler = require('idle.base');
var wallRepairer = require('role.wallrepairer');
var harvester = require('energy.harvest');
var collector = require('energy.storage');
var get_target = function(creep) {
var result;
var repairTarget;
result = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, {
filter: (structure) => structure.hits < structure.hitsMax && structure.hits < 10000 && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
});
if(result){
repairTarget = Math.min(11000, result.hitsMax);
}
if(!result) {
result = creep.pos.findClosestByRange(FIND_STRUCTURES, {
filter: (structure) => structure.hits < structure.hitsMax && (structure.structureType == STRUCTURE_CONTAINER || structure.structureType == STRUCTURE_STORAGE) && structure.hits < 10000 && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
});
if(result){
repairTarget = Math.min(11000, result.hitsMax);
}
}
if(!result) {
result = creep.pos.findClosestByRange(FIND_STRUCTURES, {
filter: (structure) => structure.hits < structure.hitsMax && structure.structureType != STRUCTURE_WALL && structure.hits < 10000 && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
});
if(result){
repairTarget = Math.min(11000, result.hitsMax);
}
}
if(!result) {
result = creep.pos.findClosestByRange(FIND_STRUCTURES, {
filter: (structure) => structure.hits < structure.hitsMax && (structure.structureType == STRUCTURE_CONTAINER || structure.structureType == STRUCTURE_STORAGE) && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
});
if(result){
repairTarget = result.hitsMax;
}
}
if(!result) {
result = creep.pos.findClosestByRange(FIND_STRUCTURES, {
filter: (structure) => structure.hits < structure.hitsMax && structure.structureType != STRUCTURE_WALL && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
});
if(result){
repairTarget = result.hitsMax;
}
}
// If no result can be found, go repair a wall or something
if(!result){
result = wallRepairer.get_target(creep);
repairTarget = -1;
}
if(result){
creep.memory.repairTarget = repairTarget;
creep.memory.repairId = result.id
Memory.rooms[creep.room.name].repairs.push(result.id);
}
return result
}
var roleRepairer = {
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
switch (creep.memory.state) {
case "idle":
idler.do_idle(creep);
if (get_target(creep)){
// If there are any buildings to repair, switch back to the repair state
idler.clear_idle(creep);
creep.memory.state = "repair_structure";
creep.say("repairing");
}
if (creep.store.getFreeCapacity() > 0) {
// If we are not full with energy, switch to the get_energy state
idler.clear_idle(creep);
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "repair_structure":
if(creep.memory.repairId){
var struct = Game.getObjectById(creep.memory.repairId);
if (struct.hits >= creep.memory.repairTarget) {
_.remove(Memory.rooms[creep.room.name].repairs, (n) => n == creep.memory.repairId);
delete creep.memory.repairId;
delete creep.memory.repairTarget;
}
}
if (!creep.memory.repairId) {
creep.memory.repairId = get_target(creep).id;
}
var closestDamagedStructure = Game.getObjectById(creep.memory.repairId);
if(closestDamagedStructure) {
if (creep.repair(closestDamagedStructure) == ERR_NOT_IN_RANGE) {
creep.moveTo(closestDamagedStructure, {visualizePathStyle: {stroke: '#FF9999'}});
}
} else {
// Else, go idle
creep.memory.state = "idle";
creep.say('idling');
}
if (creep.store.getUsedCapacity() == 0) {
// If we are out of energy, get more!
creep.memory.state = "get_energy";
creep.say('Reloading...');
// Forget what we were doing, so we can pick the best repair option when we are done recharging
_.remove(Memory.rooms[creep.room.name].repairs, (n) => n == creep.memory.repairId);
delete creep.memory.repairId;
delete creep.memory.repairTarget;
}
break;
case "get_energy":
var energy_source;
if(behaviourLevel >= 2) {
energy_source = collector;
} else {
energy_source = harvester;
}
energy_source.do_collect(creep, "repair_structure", "Repairing...");
break;
default:
creep.memory.state = "repair_structure";
creep.say('repairing');
}
}
};
module.exports = roleRepairer;

63
role.upgrader.js Normal file
View file

@ -0,0 +1,63 @@
var idler = require('idle.base');
var harvester = require('energy.harvest');
var collector = require('energy.storage');
var roleUpgrader = {
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
switch (creep.memory.state) {
case "idle":
idler.do_idle(creep);
if (creep.room.controller.progress < creep.room.controller.progressTotal){
// If there are any buildings to upgrade, switch back to the upgrading state
idler.clear_idle(creep);
creep.memory.state = "upgrade_structure";
creep.say("upgrading");
}
if (creep.store.getFreeCapacity() > 0) {
// If we are not full with energy, switch to the get_energy state
idler.clear_idle(creep);
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "upgrade_structure":
if (creep.room.controller.progress < creep.room.controller.progressTotal){
if(creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE) {
creep.moveTo(creep.room.controller, {visualizePathStyle: {stroke: '#ffffff'}});
}
} else {
// Else, go idle
creep.memory.state = "idle";
creep.say('idling');
}
if (creep.store.getUsedCapacity() == 0) {
// If we have no energy, switch to the get_energy state
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "get_energy":
var energy_source;
if(behaviourLevel >= 2) {
energy_source = collector;
} else {
energy_source = harvester;
}
energy_source.do_collect(creep, "upgrade_structure", "Upgrading...");
break;
default:
creep.memory.state = "get_energy";
creep.say("Reloading...");
}
}
};
module.exports = roleUpgrader;

80
role.wallrepairer.js Normal file
View file

@ -0,0 +1,80 @@
var idler = require('idle.base');
var harvester = require('energy.harvest');
var collector = require('energy.storage');
var get_target = function(creep) {
var walls = creep.room.find(FIND_STRUCTURES, {
filter: (s) => s.structureType == STRUCTURE_WALL && s.hits < s.hitsMax
});
for(var i = 0.0001; i < 1; i += 0.0001) {
for(var wall of walls) {
if ((wall.hits / wall.hitsMax) < i) {
return wall;
}
}
}
return null;
}
var roleRepairer = {
get_target: get_target,
/**
@param {Creep} creep
@param {int} behaviourLevel
**/
run: function(creep, behaviourLevel) {
switch (creep.memory.state) {
case "idle":
idler.do_idle(creep);
if (get_target(creep)){
// If there are any buildings to repair, switch back to the repair state
idler.clear_idle(creep);
creep.memory.state = "repair_structure";
creep.say("Repairing...");
}
if (creep.store.getFreeCapacity() > 0) {
// If we are not full with energy, switch to the get_energy state
idler.clear_idle(creep);
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "repair_structure":
var closestDamagedStructure = get_target(creep);
if(closestDamagedStructure) {
if (creep.repair(closestDamagedStructure) == ERR_NOT_IN_RANGE) {
creep.moveTo(closestDamagedStructure, {visualizePathStyle: {stroke: '#FF9999'}});
}
} else {
// Else, go idle
creep.memory.state = "idle";
creep.say('Idling...');
}
if (creep.store.getUsedCapacity() == 0) {
// If we are out of energy, get more!
creep.memory.state = "get_energy";
creep.say('Reloading...');
}
break;
case "get_energy":
var energy_source;
if(behaviourLevel >= 2) {
energy_source = collector;
} else {
energy_source = harvester;
}
energy_source.do_collect(creep, "repair_structure", "Repairing...");
break;
default:
creep.memory.state = "repair_structure";
creep.say('Repairing...');
}
}
};
module.exports = roleRepairer;

324
screeps-profiler.js Normal file
View file

@ -0,0 +1,324 @@
let usedOnStart = 0;
let enabled = false;
let depth = 0;
function setupProfiler() {
depth = 0; // reset depth, this needs to be done each tick.
Game.profiler = {
stream(duration, filter) {
setupMemory('stream', duration || 10, filter);
},
email(duration, filter) {
setupMemory('email', duration || 100, filter);
},
profile(duration, filter) {
setupMemory('profile', duration || 100, filter);
},
background(filter) {
setupMemory('background', false, filter);
},
restart() {
if (Profiler.isProfiling()) {
const filter = Memory.profiler.filter;
let duration = false;
if (!!Memory.profiler.disableTick) {
// Calculate the original duration, profile is enabled on the tick after the first call,
// so add 1.
duration = Memory.profiler.disableTick - Memory.profiler.enabledTick + 1;
}
const type = Memory.profiler.type;
setupMemory(type, duration, filter);
}
},
reset: resetMemory,
output: Profiler.output,
};
overloadCPUCalc();
}
function setupMemory(profileType, duration, filter) {
resetMemory();
const disableTick = Number.isInteger(duration) ? Game.time + duration : false;
if (!Memory.profiler) {
Memory.profiler = {
map: {},
totalTime: 0,
enabledTick: Game.time + 1,
disableTick,
type: profileType,
filter,
};
}
}
function resetMemory() {
Memory.profiler = null;
}
function overloadCPUCalc() {
if (Game.rooms.sim) {
usedOnStart = 0; // This needs to be reset, but only in the sim.
Game.cpu.getUsed = function getUsed() {
return performance.now() - usedOnStart;
};
}
}
function getFilter() {
return Memory.profiler.filter;
}
const functionBlackList = [
'getUsed', // Let's avoid wrapping this... may lead to recursion issues and should be inexpensive.
'constructor', // es6 class constructors need to be called with `new`
];
function wrapFunction(name, originalFunction) {
function wrappedFunction() {
if (Profiler.isProfiling()) {
const nameMatchesFilter = name === getFilter();
const start = Game.cpu.getUsed();
if (nameMatchesFilter) {
depth++;
}
const result = originalFunction.apply(this, arguments);
if (depth > 0 || !getFilter()) {
const end = Game.cpu.getUsed();
Profiler.record(name, end - start);
}
if (nameMatchesFilter) {
depth--;
}
return result;
}
return originalFunction.apply(this, arguments);
}
wrappedFunction.toString = () =>
`// screeps-profiler wrapped function:\n${originalFunction.toString()}`;
return wrappedFunction;
}
function hookUpPrototypes() {
Profiler.prototypes.forEach(proto => {
profileObjectFunctions(proto.val, proto.name);
});
}
function profileObjectFunctions(object, label) {
const objectToWrap = object.prototype ? object.prototype : object;
Object.getOwnPropertyNames(objectToWrap).forEach(functionName => {
const extendedLabel = `${label}.${functionName}`;
const isBlackListed = functionBlackList.indexOf(functionName) !== -1;
if (isBlackListed) {
return;
}
const descriptor = Object.getOwnPropertyDescriptor(objectToWrap, functionName);
if (!descriptor) {
return;
}
const hasAccessor = descriptor.get || descriptor.set;
if (hasAccessor) {
const configurable = descriptor.configurable;
if (!configurable) {
return;
}
const profileDescriptor = {};
if (descriptor.get) {
const extendedLabelGet = `${extendedLabel}:get`;
profileDescriptor.get = profileFunction(descriptor.get, extendedLabelGet);
}
if (descriptor.set) {
const extendedLabelSet = `${extendedLabel}:set`;
profileDescriptor.set = profileFunction(descriptor.set, extendedLabelSet);
}
Object.defineProperty(objectToWrap, functionName, profileDescriptor);
return;
}
const isFunction = typeof descriptor.value === 'function';
if (!isFunction) {
return;
}
const originalFunction = objectToWrap[functionName];
objectToWrap[functionName] = profileFunction(originalFunction, extendedLabel);
});
return objectToWrap;
}
function profileFunction(fn, functionName) {
const fnName = functionName || fn.name;
if (!fnName) {
console.log('Couldn\'t find a function name for - ', fn);
console.log('Will not profile this function.');
return fn;
}
return wrapFunction(fnName, fn);
}
const Profiler = {
printProfile() {
console.log(Profiler.output());
},
emailProfile() {
Game.notify(Profiler.output());
},
output(numresults) {
const displayresults = !!numresults ? numresults : 20;
if (!Memory.profiler || !Memory.profiler.enabledTick) {
return 'Profiler not active.';
}
const endTick = Math.min(Memory.profiler.disableTick || Game.time, Game.time);
const startTick = Memory.profiler.enabledTick + 1;
const elapsedTicks = endTick - startTick;
const header = 'calls\t\ttime\t\tavg\t\tfunction';
const footer = [
`Avg: ${(Memory.profiler.totalTime / elapsedTicks).toFixed(2)}`,
`Total: ${Memory.profiler.totalTime.toFixed(2)}`,
`Ticks: ${elapsedTicks}`,
].join('\t');
return [].concat(header, Profiler.lines().slice(0, displayresults), footer).join('\n');
},
lines() {
const stats = Object.keys(Memory.profiler.map).map(functionName => {
const functionCalls = Memory.profiler.map[functionName];
return {
name: functionName,
calls: functionCalls.calls,
totalTime: functionCalls.time,
averageTime: functionCalls.time / functionCalls.calls,
};
}).sort((val1, val2) => {
return val2.totalTime - val1.totalTime;
});
const lines = stats.map(data => {
return [
data.calls,
data.totalTime.toFixed(1),
data.averageTime.toFixed(3),
data.name,
].join('\t\t');
});
return lines;
},
prototypes: [
{ name: 'Game', val: Game },
{ name: 'Room', val: Room },
{ name: 'Structure', val: Structure },
{ name: 'Spawn', val: Spawn },
{ name: 'Creep', val: Creep },
{ name: 'RoomPosition', val: RoomPosition },
{ name: 'Source', val: Source },
{ name: 'Flag', val: Flag },
],
record(functionName, time) {
if (!Memory.profiler.map[functionName]) {
Memory.profiler.map[functionName] = {
time: 0,
calls: 0,
};
}
Memory.profiler.map[functionName].calls++;
Memory.profiler.map[functionName].time += time;
},
endTick() {
if (Game.time >= Memory.profiler.enabledTick) {
const cpuUsed = Game.cpu.getUsed();
Memory.profiler.totalTime += cpuUsed;
Profiler.report();
}
},
report() {
if (Profiler.shouldPrint()) {
Profiler.printProfile();
} else if (Profiler.shouldEmail()) {
Profiler.emailProfile();
}
},
isProfiling() {
if (!enabled || !Memory.profiler) {
return false;
}
return !Memory.profiler.disableTick || Game.time <= Memory.profiler.disableTick;
},
type() {
return Memory.profiler.type;
},
shouldPrint() {
const streaming = Profiler.type() === 'stream';
const profiling = Profiler.type() === 'profile';
const onEndingTick = Memory.profiler.disableTick === Game.time;
return streaming || (profiling && onEndingTick);
},
shouldEmail() {
return Profiler.type() === 'email' && Memory.profiler.disableTick === Game.time;
},
};
module.exports = {
wrap(callback) {
if (enabled) {
setupProfiler();
}
if (Profiler.isProfiling()) {
usedOnStart = Game.cpu.getUsed();
// Commented lines are part of an on going experiment to keep the profiler
// performant, and measure certain types of overhead.
// var callbackStart = Game.cpu.getUsed();
const returnVal = callback();
// var callbackEnd = Game.cpu.getUsed();
Profiler.endTick();
// var end = Game.cpu.getUsed();
// var profilerTime = (end - start) - (callbackEnd - callbackStart);
// var callbackTime = callbackEnd - callbackStart;
// var unaccounted = end - profilerTime - callbackTime;
// console.log('total-', end, 'profiler-', profilerTime, 'callbacktime-',
// callbackTime, 'start-', start, 'unaccounted', unaccounted);
return returnVal;
}
return callback();
},
enable() {
enabled = true;
hookUpPrototypes();
},
output: Profiler.output,
registerObject: profileObjectFunctions,
registerFN: profileFunction,
registerClass: profileObjectFunctions,
};