Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Easy Performance Improvements (Reducing lodash filter and shallow clone in hot path) #134

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions src/game/rooms.js
Original file line number Diff line number Diff line change
@@ -364,11 +364,11 @@ function _findClosestByPath2(fromPos, objects, opts) {
lastPos = ret.path[ret.path.length-1];
}

objects.forEach(obj => {
for (const obj of objects) {
if(lastPos.isNearTo(obj)) {
result = obj;
}
});
}

return result;
}
@@ -649,7 +649,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) {
result = _.filter(result, opts.filter);
}
else {
result = _.clone(result);
result = [...result];
}

return result;
@@ -874,7 +874,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) {
path,
cacheKeySuffix = '';

opts = _.clone(opts || {});
opts = opts ? {...opts} : {};

if(opts.ignoreCreeps) {
cacheKeySuffix += '_ignoreCreeps'
@@ -1399,7 +1399,7 @@ exports.makePos = function(_register) {
room = register.rooms[this.roomName];

if(_.isObject(secondArg)) {
opts = _.clone(secondArg);
opts = {...secondArg};
}
opts = opts || {};

@@ -1428,7 +1428,7 @@ exports.makePos = function(_register) {

RoomPosition.prototype.findClosestByPath = register.wrapFn(function(type, opts) {

opts = _.clone(opts || {});
opts = opts ? {...opts} : {};

var room = register.rooms[this.roomName];

@@ -1522,7 +1522,7 @@ exports.makePos = function(_register) {
throw new Error(`Could not access room ${this.roomName}`);
}

opts = _.clone(opts || {});
opts = opts ? {...opts} : {};

var objects = [],
result = [];
@@ -1534,11 +1534,11 @@ exports.makePos = function(_register) {
objects = opts.filter ? _.filter(type, opts.filter) : type;
}

objects.forEach((i) => {
for (const i of objects) {
if(this.inRangeTo(i, range)) {
result.push(i);
}
});
}

return result;
});
@@ -1550,7 +1550,7 @@ exports.makePos = function(_register) {
throw new Error(`Could not access room ${this.roomName}`);
}

opts = _.clone(opts || {});
opts = opts ? {...opts} : {};

var objects = [],
result = [];
8 changes: 5 additions & 3 deletions src/processor/global-intents/market.js
Original file line number Diff line number Diff line change
@@ -68,9 +68,11 @@ module.exports = function({orders, userIntents, usersById, gameTime, roomObjects
return true;
}

_.filter(terminals, i => !!i.send).forEach(terminal => {

var intent = terminal.send;
terminals.forEach(terminal => {
const intent = terminal.send;
if (!intent) {
return;
}

bulkObjects.update(terminal, {send: null});

2 changes: 1 addition & 1 deletion src/processor/intents/creeps/attackController.js
Original file line number Diff line number Diff line change
@@ -50,4 +50,4 @@ module.exports = function(object, intent, {roomObjects, bulk, roomController, ga
object.actionLog.attack = {x: target.x, y: target.y};

eventLog.push({event: C.EVENT_ATTACK_CONTROLLER, objectId: object._id})
};
};
4 changes: 2 additions & 2 deletions src/processor/intents/creeps/claimController.js
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ module.exports = function(object, intent, {roomObjects, bulk, bulkUsers, users})
if(target.level > 0) {
return;
}
if ((_.filter(object.body, (i) => i.hits > 0 && i.type == C.CLAIM).length) === 0) {
if (!object.body.some((i) => i.hits > 0 && i.type == C.CLAIM)) {
return;
}
if(target.reservation && target.reservation.user != object.user) {
@@ -49,4 +49,4 @@ module.exports = function(object, intent, {roomObjects, bulk, bulkUsers, users})
});

driver.addRoomToUser(object.room, users[object.user], bulkUsers);
};
};
18 changes: 9 additions & 9 deletions src/processor/intents/creeps/invaders/findAttack.js
Original file line number Diff line number Diff line change
@@ -80,15 +80,15 @@ module.exports = function(creep, context) {
}

if(!target) {
const unreachableSpawns = _.filter(roomObjects, o =>
const unreachableSpawn = roomObjects ? roomObjects.find(o =>
o.type == 'spawn' && !checkPath(creep, new fakeRuntime.RoomPosition(o.x, o.y, o.room), scope)
);
if(!unreachableSpawns.length && roomController && roomController.user) {
) : null;
if(!unreachableSpawn && roomController && roomController.user) {
intents.set(creep._id, 'suicide', {});
return;
}

target = unreachableSpawns[0];
target = unreachableSpawn;
if(target) {
const direction = fakeRuntime.moveTo(creep, target, {ignoreDestructibleStructures: true, maxRooms: 1, ignoreRoads: true}, scope);
if(direction) {
@@ -105,15 +105,15 @@ module.exports = function(creep, context) {
}

const pos = fakeRuntime.RoomPosition.sUnpackLocal(creep['memory_move']['path'][0], creep.room);
const structures = _.filter(roomObjects, o => !!C.CONTROLLER_STRUCTURES[o.type] && o.type != 'spawn' && o.x == pos.x && o.y == pos.y);
if(structures.length > 0) {
const structure = roomObjects.find(o => !!C.CONTROLLER_STRUCTURES[o.type] && o.type != 'spawn' && o.x == pos.x && o.y == pos.y);
if(structure) {
if(fakeRuntime.hasActiveBodyparts(creep, C.RANGED_ATTACK)) {
intents.set(creep._id, 'rangedAttack', { id: structures[0]._id })
intents.set(creep._id, 'rangedAttack', { id: structure._id })
}
if(fakeRuntime.hasActiveBodyparts(creep, C.WORK)) {
intents.set(creep._id, 'dismantle', { id: structures[0]._id });
intents.set(creep._id, 'dismantle', { id: structure._id });
} else {
intents.set(creep._id, 'attack', { id: structures[0]._id, x: structures[0].x, y: structures[0].y });
intents.set(creep._id, 'attack', { id: structure._id, x: structure.x, y: structure.y });
}
}
}
4 changes: 2 additions & 2 deletions src/processor/intents/creeps/invaders/flee.js
Original file line number Diff line number Diff line change
@@ -7,8 +7,8 @@ const _ = require('lodash'),
module.exports = function(creep, range, context) {
const {scope, intents, hostiles} = context;

const nearCreeps = _.filter(hostiles, c => utils.dist(creep, c) < range);
if(_.some(nearCreeps)) {
const nearCreeps = hostiles.filter(c => utils.dist(creep, c) < range);
if(nearCreeps.length > 0) {
const direction = fakeRuntime.flee(creep, nearCreeps, range, {}, scope);
if(direction) {
intents.set(creep._id, 'move', { direction });
6 changes: 3 additions & 3 deletions src/processor/intents/creeps/invaders/healer.js
Original file line number Diff line number Diff line change
@@ -8,9 +8,9 @@ const _ = require('lodash'),
module.exports = function(creep, context) {
const {scope, intents, invaders} = context;

let healTargets = _.filter(invaders, c => utils.dist(c, creep) <= 3);
if(_.some(healTargets)) {
const healTarget = _.first(healTargets.sort((a, b) => (b.hitsMax - b.hits) - (a.hitsMax - a.hits)));
let healTargets = invaders.filter(c => utils.dist(c, creep) <= 3);
if(healTargets.length > 0) {
const healTarget = healTargets.sort((a, b) => (b.hitsMax - b.hits) - (a.hitsMax - a.hits))[0];
if(utils.dist(creep, healTarget) <= 1) {
intents.set(creep._id, 'heal', {id: healTarget._id, x: healTarget.x, y: healTarget.y});
} else {
2 changes: 1 addition & 1 deletion src/processor/intents/invader-core/stronghold/creeps.js
Original file line number Diff line number Diff line change
@@ -86,7 +86,7 @@ const behaviors = {
const safeMatrixCallback = defence.createSafeMatrixCallback(context);

fakeRuntime.walkTo(creep, target, { range: 3, costCallback: safeMatrixCallback }, context);
const targetInRange = _.first(_.filter(repairRamparts, r => utils.dist(creep, r) <= 3));
const targetInRange = repairRamparts.find(r => utils.dist(creep, r) <= 3);
if(targetInRange) {
intents.set(creep._id, 'repair', {id: targetInRange._id, x: targetInRange.x, y: targetInRange.y});
}
26 changes: 13 additions & 13 deletions src/processor/intents/invader-core/stronghold/stronghold.js
Original file line number Diff line number Diff line change
@@ -154,8 +154,8 @@ const refillTowers = function refillTowers(context) {
return false;
}

const underchargedTowers = _.filter(towers, t => (t.store.energy <= 2*C.TOWER_ENERGY_COST) && _.some(ramparts, {x: t.x, y: t.y}));
if(_.some(underchargedTowers)) {
const underchargedTowers = towers.filter(t => (t.store.energy <= 2*C.TOWER_ENERGY_COST) && _.some(ramparts, {x: t.x, y: t.y}));
if(underchargedTowers.length > 0) {
const towerToCharge = _.min(underchargedTowers, 'store.energy');
if(towerToCharge) {
intents.set(core._id, 'transfer', {id: towerToCharge._id, amount: towerToCharge.storeCapacityResource.energy - towerToCharge.store.energy, resourceType: C.RESOURCE_ENERGY});
@@ -169,8 +169,8 @@ const refillTowers = function refillTowers(context) {
const refillCreeps = function refillCreeps(context) {
const {core, intents, defenders} = context;

const underchargedCreeps = _.filter(defenders, c => (c.storeCapacity > 0) && (2*c.store.energy <= c.storeCapacity));
if(_.some(underchargedCreeps)) {
const underchargedCreeps = defenders.filter(c => (c.storeCapacity > 0) && (2*c.store.energy <= c.storeCapacity));
if(underchargedCreeps.length > 0) {
const creep = _.min(underchargedCreeps, 'store.energy');
if(creep) {
intents.set(core._id, 'transfer', {id: creep._id, amount: creep.storeCapacity - creep.store.energy, resourceType: C.RESOURCE_ENERGY});
@@ -187,17 +187,17 @@ const towersMaintenance = function towersMaintenance(context) {
return;
}

const protectedCreeps = _.filter(damagedDefenders, d => _.some(ramparts, {x: d.x, y: d.y}));
if(_.some(protectedCreeps)) {
const protectedCreeps = damagedDefenders.filter(d => _.some(ramparts, {x: d.x, y: d.y}));
if(protectedCreeps.length > 0) {
const creep = _.first(protectedCreeps);
const tower = _.first(towers);
intents.set(tower._id, 'heal', {id: creep._id});
_.pull(towers, tower);
return;
}

const protectedRoads = _.filter(damagedRoads, r => _.some(ramparts, {x: r.x, y: r.y}));
if(_.some(protectedRoads)) {
const protectedRoads = damagedRoads.filter(r => _.some(ramparts, {x: r.x, y: r.y}));
if(protectedRoads.length > 0) {
const road = _.first(damagedRoads);
const tower = _.first(towers);
intents.set(tower._id, 'repair', {id: road._id});
@@ -220,12 +220,12 @@ const focusClosest = function focusClosest(context) {
intents.set(t._id, 'attack', {id: target._id});
}

const meleesNear = _.filter(defenders, d => (range(d, target) == 1) && _.some(d.body, {type: C.ATTACK}));
const meleesNear = defenders.filter(d => (range(d, target) == 1) && _.some(d.body, {type: C.ATTACK}));
for(let melee of meleesNear) {
intents.set(melee._id, 'attack', {id: target._id, x: target.x, y: target.y});
}

const rangersInRange = _.filter(defenders, d => (range(d, target) <= 3) && _.some(d.body, {type: C.RANGED_ATTACK}));
const rangersInRange = defenders.filter(d => (range(d, target) <= 3) && _.some(d.body, {type: C.RANGED_ATTACK}));
for(let r of rangersInRange) {
if(range(r,target) == 1) {
intents.set(r._id, 'rangedMassAttack', {});
@@ -244,7 +244,7 @@ const focusMax = function focusMax(context) {
return false;
}

const activeTowers = _.filter(towers, t => t.store.energy >= C.TOWER_ENERGY_COST);
const activeTowers = towers.filter(t => t.store.energy >= C.TOWER_ENERGY_COST);
const target = _.max(hostiles, creep => {
let damage = _.sum(activeTowers, tower => {
let r = utils.dist(creep, tower);
@@ -277,12 +277,12 @@ const focusMax = function focusMax(context) {
return damage;
});

const meleesNear = _.filter(defenders, d => (range(d, target) == 1) && _.some(d.body, {type: C.ATTACK}));
const meleesNear = defenders.filter(d => (range(d, target) == 1) && _.some(d.body, {type: C.ATTACK}));
for(let melee of meleesNear) {
intents.set(melee._id, 'attack', {id: target._id, x: target.x, y: target.y});
}

const rangersInRange = _.filter(defenders, d => (range(d, target) <= 3) && _.some(d.body, {type: C.RANGED_ATTACK}));
const rangersInRange = defenders.filter(d => (range(d, target) <= 3) && _.some(d.body, {type: C.RANGED_ATTACK}));
for(let r of rangersInRange) {
if(range(r,target) == 1) {
intents.set(r._id, 'rangedMassAttack', {});
2 changes: 1 addition & 1 deletion src/processor/intents/spawns/renew-creep.js
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ module.exports = function(object, intent, scope) {
if(Math.abs(target.x - object.x) > 1 || Math.abs(target.y - object.y) > 1) {
return;
}
if(_.filter(target.body, (i) => i.type == C.CLAIM).length > 0) {
if(target.body.some((i) => i.type == C.CLAIM)) {
return;
}

26 changes: 26 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
var _ = require('lodash');

// shim lodash to use native array methods, built into the VM, when available.
// this only works if the module imports _ instead of the method directly.
const oldFilter = _.filter;
_.filter = (data, predicate) => {
if (data && typeof predicate === 'function') {
return data.filter(predicate);
}
return oldFilter(data, predicate);
}

const oldFind = _.find;
_.find = (data, predicate) => {
if (data && typeof predicate === 'function') {
return data.find(predicate);
}
return oldFind(data, predicate);
}

const oldMap = _.map;
_.map = (data, predicate) => {
if (data && typeof predicate === 'function') {
return data.map(predicate);
}
return oldMap(data, predicate);
}

var driver, C, offsetsByDirection = [, [0,-1], [1,-1], [1,0], [1,1], [0,1], [-1,1], [-1,0], [-1,-1]];

function loadDriver() {