Expose respawn/novice property on Game.map and/or Room
-
Whether or not a room is in a novice zone or a respawn zone is easily visible on the map and is known to the server, but cannot be directly determined from a player's script. In some cases these zones can wreak havoc pathfinding in nearby areas. The ability to check Game.map.isNovice or isRespawn would allow a routeCallback to ignore these rooms.
isNoviceZone(roomName) { if(runtimeData.rooms[roomName].novice > Date.now()) { return true; } else { return false; } }, isRespawnZone(roomName) { if(runtimeData.rooms[roomName].respawnArea > Date.now()) { return true; } else { return false; } },
-
You can only access
runtimeData.rooms
for rooms with visibility, so it cannot be added to the Map API.
-
Could it be added to the controller?
-
@stevetrov Would it really help that much if you needed controller visibility?
-
It would tell you if your bot is in a novice / respawn area.
-
It would also allow rooms found through observers to know the difference.
-
It could be added to the
Room
prototype, but it does much less sense if you aren't able to use it all over the world, since the main purpose for this would be path finding. This is why we haven't implemented it yet.
-
Looking at the server code that creates the runtimeData, it looks like another room query could be used to add an object with this structure to the runtimeData
zones: { [ roomName: string ]: { novice: number, respawn: number } }
Which could then be used in
Game.map
. I am looking at doing this on my local server, but that really won't show the performance cost of this extra query.
-
For example, like this: https://github.com/screeps/engine/pull/89
-
Yes, any such issue can be solved with adding more and more database requests, but this should be done only when you really need it. Adding a separate request for this feature alone doesn't look reasonable.
-
Could this be merged into Game.map.isRoomAvailable ?
It could return a number instead of the bool.
-
@mrfaul said in Expose respawn/novice property on Game.map and/or Room:
Could this be merged into Game.map.isRoomAvailable ?
It could return a number instead of the bool.This is a good solution. With the increase in fully automated AI being able to discern novice/respawn areas without human interaction is a bigger deal (to go along with pathfinding)
-
I think the correct approach is to take a step back and look at the original problem.
You wish to know that a room is in Novice/Respawn so you can use this information in pathfinding.
Why do you need to use this in pathfinding? Because those rooms are walled off.
But the question then is, how does your AI handle trying to go to a normal room that is behind other walled off rooms?
I get the feeling Novice/Respawn is just a more frequent instance of having an area blocked off by walls. You probably should teach your AI to handle that case in pathfinding logic and then you won't need the Novice/Respawn flag.
-
To prove that a room is blocked off (I'll talk later about finding out with high probability), you need to:
a) get visibility at least once of the entire perimeter of the novice area
b) periodically recheck those rooms to verify the walls still exist
c) use some kind of algorithm to prove that you can't reach the room
PathFinder will expand a maximum of 16 rooms, which will not let you visit every location inside a sector to prove you can't get out of the sector (even if you had the CPU to do that much searching!). So you can't use this.
Game.map.findRoute isn't usable because you can only block going from one room to another, but that isn't the information you get from knowing there is a wall. (you know the wall might stop you going from east to west, but not north to south, but you can only tell findRoute whether you can go from room to room). So you can't use this either.
So none of the in-game systems can be used. Perhaps we can write our own system.
If we write our own system we could do something like the following:
-
periodically scan rooms (with observer or a scout creep) for constructed walls with a maxHits set to undefined (which indicates that the walls are non-player constructed walls). This is quite an expensive operation because rooms tend to have a lot of walls and roads and if a room is built up by another player, you might have to check every single one of their walls to be sure there are no non-player constructed walls, on the other hand you don't have to do it very often so the cost over a large number of ticks is probably acceptable.
-
Once you know there is a room with non-player constructed walls, add the room to a list, and then scan all surrounding rooms for the presence of non-player constructed walls.
-
If of all the surrounding rooms, there are more than two that have non-player constructed walls, you've found a junction between two respawn areas. Otherwise, if there are exactly two surrounding rooms with non-player constructed walls, and at least one of them doesn't already appear in your list, then set that as your current room and repeat from step 2). If all of the surrounding rooms with non-player constructed walls already appear in your list, then your list now contains the perimeter of a respawn area.
-
With your list of rooms within the respawn area, you can do some additional work to determine every room that is within the (possibly irregular) perimeter.
That is a lot work to get an exact answer as to whether a room is in a respawn/novice area. And I've skipped over the details of dealing with corners between multiple respawn areas, and the issue of determining whether a room is within the perimeter you've found.
I don't believe there are any other ways to definitively prove that a room is in a respawn area. If anybody has any other ideas, I would be very interested to hear them.
To find out whether a room is a respawn area with only a high probability, you could:
a) if pathfinding fails to a room, then mark it as unreachable for a period of time. It's probably a respawn area or an unreachable base. (pathfinding can often fail just due to length of path or other blockages, without necessarily being a respawn area. And if there is a walled off enemy base that you might wish to attack, it would be unhelpful to mark it as being in a respawn area and hold off an attack you were planning).
b) monitor rooms in a sector for the respawn warning message on the controller, and then have some heuristic that if pathfinding fails to this room and it had this message within the last month, it's probably in a respawn area. (similar problems to a)
c) if you find a room with a non-player constructed wall, then mark the entire sector as a respawn area for a period of time. (will mark some non-respawn rooms as respawn rooms, when the border does not cover an entire sector).
It's a huge amount of work to get an accurate answer as to whether a room or area is walled off. And it's quite easy to get an inaccurate answer, but not without problems.
The inaccurate ways of determining whether a room is in a respawn area might often be good enough, but sometimes they're not good enough.
Contrast to Game.map.isRoomAvailable() - it's absolutely trivial to get an answer to the question of whether a room is grey, but to find out whether it's green or blue? Computer says no! It really ought to be a feature.
-
-
Adding this to
Game.map
isn't possible without adding a lot of burden to the DB. The only viable option is to add it to theRoom
prototype, but you'll need to have visibility.
-
@artch said in Expose respawn/novice property on Game.map and/or Room:
Adding this to
Game.map
isn't possible without adding a lot of burden to the DB. The only viable option is to add it to theRoom
prototype, but you'll need to have visibility.This would be better than what we currently have.
Regarding db burden - couldn't it be done with one bit per room? Obviously that's not going to give us time until expiration, but given terrain data is significantly larger it seems strange that it can't be done efficiently. I guess terrain data doesn't change... but respawn areas don't change much! I'm coming from a place of not having looked at the code at all so this may be an oversimplification...
-
@tigga Terrain data is statically cached in all nodes and is fetched only once on launch. Novice/Respawn status is stored in MongoDB where all rooms info is located, this kind of query is way more expensive.
-
@artch said in Expose respawn/novice property on Game.map and/or Room:
@tigga Terrain data is statically cached in all nodes and is fetched only once on launch. Novice/Respawn status is stored in MongoDB where all rooms info is located, this kind of query is way more expensive.
Right, but as a user I'd just do the following:
if (!global._roomInRespawnNoviceArea || resetRespawnNoviceCache) { global._roomInRespawnNoviceArea = {} for (all ~4000 rooms) global._roomInRespawnNoviceArea[roomName] = isRespawnNoviceArea(roomName) }
Where
resetRespawnNoviceCache
is set on the tick any walls go down or up. There's probably a good reason you can't do this - I'm not at all familiar with the backend and you obviously are! My point is that this array shouldn't come to more than 4kb per user, and populating it once per reset seems fairly cheap.EDIT: I've used an object for simplicity. Pushing this into UInt8Array would be 4kb, packing it into a bitmask could get it down to 500b.