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
Show file tree
Hide file tree
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
Expand Up @@ -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;
}
Expand Down Expand Up @@ -649,7 +649,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) {
result = _.filter(result, opts.filter);
}
else {
result = _.clone(result);
result = [...result];
}

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

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

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

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

Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -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 = [];
Expand All @@ -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;
});
Expand All @@ -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 = [];
Expand Down
8 changes: 5 additions & 3 deletions src/processor/global-intents/market.js
Original file line number Diff line number Diff line change
Expand Up @@ -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});

Expand Down
2 changes: 1 addition & 1 deletion src/processor/intents/creeps/attackController.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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) {
Expand All @@ -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
Expand Up @@ -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) {
Expand All @@ -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 });
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/processor/intents/creeps/invaders/flee.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down
6 changes: 3 additions & 3 deletions src/processor/intents/creeps/invaders/healer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/processor/intents/invader-core/stronghold/creeps.js
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}
Expand Down
26 changes: 13 additions & 13 deletions src/processor/intents/invader-core/stronghold/stronghold.js
Original file line number Diff line number Diff line change
Expand Up @@ -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});
Expand All @@ -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});
Expand All @@ -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});
Expand All @@ -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', {});
Expand All @@ -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);
Expand Down Expand Up @@ -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', {});
Expand Down
2 changes: 1 addition & 1 deletion src/processor/intents/spawns/renew-creep.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
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() {
Expand Down