Skip to content
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
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[*.js]
indent_size = 2
indent_style = space
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
shard*.json
node_modules
yarn-error.log
data/
12 changes: 12 additions & 0 deletions .screeps.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
servers:
loan:
host: screeps.com
secure: true
token: # Your token here
portalSegment: 97
noviceSegment: 96
areaSegment: 95
configs:
sector-scanner:
server: loan
output-dir: data
8 changes: 7 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
FROM node:10
FROM node:18-slim

LABEL maintainer="Screeps Sector Scanner"
LABEL version="1.0"
LABEL description="Screeps Sector Scanner"

WORKDIR /app
COPY package.json .
COPY yarn.lock .
RUN yarn install
COPY . .
CMD ["yarn","start"]
116 changes: 6 additions & 110 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,111 +1,7 @@
const axios = require('axios')
const { ScreepsAPI } = require('screeps-api')
const fs = require('fs').promises
const debug = false
const spawn = require('child_process').spawn

let api

async function run () {
api = await ScreepsAPI.fromConfig('main', 'main')
const log = (...a) => debug ? console.log(...a) : ''
await api.me()
await api.socket.connect()
const shardNames = (await api.raw.game.shards.info()).shards.map(s => s.name)
/** /
const shards = JSON.parse(await fs.readFile('output.json'))
/**/
console.log('scanning sectors')
const shards = {}
for(const shard of shardNames) {
const data = await getSectors(shard)
shards[shard] = data
}
/**/
console.log('scanning portal rooms')
const portalRooms = []
for (const [shard, { roomMaps }] of Object.entries(shards)) {
const time = Math.floor((await api.raw.game.time(shard)).time / 100) * 100 - 200
shards[shard].portals = []
let count = 0
for(const room in roomMaps) {
if(roomMaps[room].p && roomMaps[room].p.length) {
portalRooms.push([shard, room])
}
}
}

const BATCH_SIZE=500
const batches = []
while(portalRooms.length) {
batches.push(portalRooms.splice(0, BATCH_SIZE))
}
for(const batch of batches) {
await Promise.all(batch.map(async ([shard, room]) => {
const { objects } = await getRoomObjects(shard, room)
shards[shard].portals.push(...Object.values(objects).filter(o => o.type === 'portal'))
process.stdout.write('.')
}))
process.stdout.write('_')
await sleep(200)
}
/**/
await Promise.all(Object.entries(shards).map(([shard, { roomInfo, roomMaps, portals, users }]) => Promise.all([
fs.writeFile(`${shard}.roominfo.json`, JSON.stringify(roomInfo)),
fs.writeFile(`${shard}.roommaps.json`, JSON.stringify(roomMaps)),
fs.writeFile(`${shard}.portals.json`, JSON.stringify(portals)),
fs.writeFile(`${shard}.users.json`, JSON.stringify(users)),
])))
await api.socket.disconnect()
}

run().catch(console.error)

async function getSectors(shard) {
const size = shard == 'shard0' ? 90 : 60
const infoRooms = []
const mapRooms = []
for(let y = 0; y <= size; y++) {
for(let x = 0; x <= size; x++) {
// if(x % 10 == 5 && y % 10 == 5) {
mapRooms.push(`E${x}N${y}`, `W${x}N${y}`, `E${x}S${y}`, `W${x}S${y}`)
// }
infoRooms.push(`E${x}N${y}`, `W${x}N${y}`, `E${x}S${y}`, `W${x}S${y}`)
}
}
const { stats: roomInfo, users } = await api.raw.game.mapStats(infoRooms, 'owner0', shard)
const roomMaps = {}
await Promise.all(mapRooms.map(async room => {
roomMaps[room] = await roomMap(shard, room)
}))
return {
roomInfo,
roomMaps,
users,
}
}

async function roomMap(shard, room) {
return new Promise((resolve, reject) => {
const key = `roomMap2:${shard}/${room}`
api.socket.once(key, ({ data }) => {
api.socket.unsubscribe(key)
resolve(data)
})
api.socket.subscribe(key)
})
}

async function getRoomObjects(shard, room) {
return new Promise((resolve, reject) => {
const key = `room:${shard}/${room}`
api.socket.once(key, ({ data, error }) => {
api.socket.unsubscribe(key)
resolve(data)
})
api.socket.subscribe(key)
})
}

async function sleep(ms) {
return new Promise(res => setTimeout(() => res(), ms))
}
const scanner = spawn("node", ["scanner.js"], { stdio: 'inherit'})
scanner.on("exit", () => {
spawn("node", ["refine.js"], { stdio: 'inherit'})
spawn("node", ["novice.js"], { stdio: 'inherit'})
})
27 changes: 21 additions & 6 deletions novice.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';
const { ScreepsAPI } = require('screeps-api')
const { ScreepsAPI } = require('screeps-api');
const { getConfig } = require('./shared');
const fs = require('fs').promises
const path = require('path')
/*
// Node 8 shim for local testing
const {promisify} = require('util');
Expand Down Expand Up @@ -39,17 +41,30 @@ const outputFormat2 = {
*/

async function run() {
const [,,server,segment,segmentArea] = process.argv;
let [,,server,segment,segmentArea] = process.argv;

const config = await getConfig();
const outDir = config.configs['sector-scanner']['output-dir'] ?? '.'
if (!server) {
server = config.configs['sector-scanner']['server'] ?? 'main'
}
if (!segment) {
segment = Number(config.servers[server].noviceSegment)
}
if (!segmentArea) {
segmentArea = Number(config.servers[server].areaSegment)
}

const api = await ScreepsAPI.fromConfig(server);
const files = await fs.readdir('.');
const files = await fs.readdir(outDir);
const shardFiles = files.filter(f => f.endsWith('.roominfo.json'))
for(const file of shardFiles) {
console.log(`Processing ${file}`)
const [shard] = file.split('.')
const data = JSON.parse(await fs.readFile(file, 'utf8'))
const data = JSON.parse(await fs.readFile(path.join(outDir, file), 'utf8'))
const raw=parseZones(data);
await fs.writeFile(`${shard}.novice.json`, raw[0])
await fs.writeFile(`${shard}.novice.area.json`, raw[1])
await fs.writeFile(path.join(outDir, `${shard}.novice.json`), raw[0])
await fs.writeFile(path.join(outDir, `${shard}.novice.area.json`), raw[1])
if(server && segment) {
console.log(`Uploading to segment ${segment} on ${shard} of ${server}`)
await api.memory.segment.set(+segment, raw[0], shard)
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"main": "index.js",
"license": "MIT",
"dependencies": {
"screeps-api": "^1.8.1"
"screeps-api": "^1.8.1",
"yaml": "^2.8.0"
},
"scripts": {
"start": "node index.js",
Expand Down
21 changes: 17 additions & 4 deletions refine.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
const { ScreepsAPI } = require('screeps-api')
const { getConfig } = require('./shared')
const fs = require('fs').promises
const path = require('path')

const ROOM_REGEX = /^[EW][0-9]*[05][NS][0-9]*[05]$/


async function run() {
const [,,server,segment] = process.argv
let [,,server,segment] = process.argv

const config = await getConfig();
const outDir = config.configs['sector-scanner']['output-dir'] ?? '.'
if (!server) {
server = config.configs['sector-scanner']['server'] ?? 'main'
}
if (!segment) {
segment = Number(config.servers[server].portalSegment)
}

const api = await ScreepsAPI.fromConfig(server)
const files = await fs.readdir('.')
const files = await fs.readdir(outDir)
const shardFiles = files.filter(f => f.endsWith('.portals.json'))
for(const file of shardFiles) {
console.log(`Processing ${file}`)
const [shard] = file.split('.')
const data = JSON.parse(await fs.readFile(file, 'utf8'))
const data = JSON.parse(await fs.readFile(path.join(outDir, file), 'utf8'))
const map = new Map()
for(const portal of data) {
const {
Expand All @@ -33,7 +46,7 @@ async function run() {
map.set(key, rec)
}
const raw = JSON.stringify(Array.from(map.values()))
await fs.writeFile(`${shard}.portals.min.json`, raw)
await fs.writeFile(path.join(outDir, `${shard}.portals.min.json`), raw)
if(server && segment) {
console.log(`Uploading to segment ${segment} on ${shard} of ${server}`)
await api.memory.segment.set(+segment, raw, shard)
Expand Down
121 changes: 121 additions & 0 deletions scanner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const axios = require('axios')
const { ScreepsAPI } = require('screeps-api')
const { getConfig } = require('./shared')
const fs = require('fs').promises
const path = require('path')
const debug = false

let api

async function run () {
let [,,server] = process.argv

const config = await getConfig();
const outDir = config.configs['sector-scanner']['output-dir']
if (!server) {
server = config.configs['sector-scanner']['server'] ?? 'main'
}

api = await ScreepsAPI.fromConfig(server)
const log = (...a) => debug ? console.log(...a) : ''
await api.me()
await api.socket.connect()
const shardNames = (await api.raw.game.shards.info()).shards.map(s => s.name)
/** /
const shards = JSON.parse(await fs.readFile('output.json'))
/**/
console.log('scanning sectors')
const shards = {}
for(const shard of shardNames) {
const data = await getSectors(shard)
shards[shard] = data
}
/**/
console.log('scanning portal rooms')
const portalRooms = []
for (const [shard, { roomMaps }] of Object.entries(shards)) {
const time = Math.floor((await api.raw.game.time(shard)).time / 100) * 100 - 200
shards[shard].portals = []
let count = 0
for(const room in roomMaps) {
if(roomMaps[room].p && roomMaps[room].p.length) {
portalRooms.push([shard, room])
}
}
}

const BATCH_SIZE=500
const batches = []
while(portalRooms.length) {
batches.push(portalRooms.splice(0, BATCH_SIZE))
}
for(const batch of batches) {
await Promise.all(batch.map(async ([shard, room]) => {
const { objects } = await getRoomObjects(shard, room)
shards[shard].portals.push(...Object.values(objects).filter(o => o.type === 'portal'))
process.stdout.write('.')
}))
process.stdout.write('_')
await sleep(200)
}
/**/
await Promise.all(Object.entries(shards).map(([shard, { roomInfo, roomMaps, portals, users }]) => Promise.all([
fs.writeFile(path.join(outDir, `${shard}.roominfo.json`), JSON.stringify(roomInfo)),
fs.writeFile(path.join(outDir, `${shard}.roommaps.json`), JSON.stringify(roomMaps)),
fs.writeFile(path.join(outDir, `${shard}.portals.json`), JSON.stringify(portals)),
fs.writeFile(path.join(outDir, `${shard}.users.json`), JSON.stringify(users)),
])))
await api.socket.disconnect()
}

run().catch(console.error)

async function getSectors(shard) {
const size = shard == 'shard0' ? 90 : 60
const infoRooms = []
const mapRooms = []
for(let y = 0; y <= size; y++) {
for(let x = 0; x <= size; x++) {
// if(x % 10 == 5 && y % 10 == 5) {
mapRooms.push(`E${x}N${y}`, `W${x}N${y}`, `E${x}S${y}`, `W${x}S${y}`)
// }
infoRooms.push(`E${x}N${y}`, `W${x}N${y}`, `E${x}S${y}`, `W${x}S${y}`)
}
}
const { stats: roomInfo, users } = await api.raw.game.mapStats(infoRooms, 'owner0', shard)
const roomMaps = {}
await Promise.all(mapRooms.map(async room => {
roomMaps[room] = await roomMap(shard, room)
}))
return {
roomInfo,
roomMaps,
users,
}
}

async function roomMap(shard, room) {
return new Promise((resolve, reject) => {
const key = `roomMap2:${shard}/${room}`
api.socket.once(key, ({ data }) => {
api.socket.unsubscribe(key)
resolve(data)
})
api.socket.subscribe(key)
})
}

async function getRoomObjects(shard, room) {
return new Promise((resolve, reject) => {
const key = `room:${shard}/${room}`
api.socket.once(key, ({ data, error }) => {
api.socket.unsubscribe(key)
resolve(data)
})
api.socket.subscribe(key)
})
}

async function sleep(ms) {
return new Promise(res => setTimeout(() => res(), ms))
}
Loading