Feature Request: Concurrent ARS room build
roberestarkk opened this issue ยท 17 comments
Describe the feature request
It would be great if we could build more than one TARDIS room at the same time.
I used to do this by selecting one, hitting reconfigure, then repeat, but it doesn't let you do this any more.
Yes, doing too much of it will cause performance issues, but through experimentation I worked out that our server could handle at least 10 when only I was online, so I limited myself to 3-5 at once for the most part when first building my behemoth.
The only other issue with building more than one at once is that if you do it to two adjacent rooms, they sometimes don't mesh properly, which I avoided by only ever building rooms at the same time if they were not cardinally adjacent.
If I needed to build a set of rooms where some were to be cardinally adjacent, I'd use a chessboard pattern where I'd first do 'white' tiles, then 'black' tiles, so it was only ever diagonal adjacencies that were being built concurrently.
So my initial naive suggestion would be:
Have a setting, like ars_sametime_limit which defaults to one.
If you decide your server can handle more, you can up that limit and when you specify multiple rooms to be built it'll spawn up to that limit of ARS room build processes and allocate them an assigned room from the 'white' tiles, then when those are done, do the same for the 'black' tiles.
ie:
ars_limit: 10
ars_sametime_limit: 5
If you then specify that the following pattern of rooms should be built:
Empty | Empty | Empty | Empty | Empty
Empty | Empty | Empty | Empty | Empty
What it'll do is start these in allcaps to be built all at once:
EMPTY | empty | EMPTY | empty | EMPTY
empty | EMPTY | empty | EMPTY | empty
Then when those are all finished, do the others.
Obviously it'd be much cooler (and inevitably more effort) if it did a first pass of adjacency detection, and only applied the chessboard pattern for when there were adjacent rooms, so if you had an existing hallway:
Empty | Empty | Empty | Empty
And you wanted to add
empty | empty | empty | empty
VAULT | | | SMELTER
It would be able to build both the Vault and the Smelter at the same time, because it knows there's no adjacency of 'to be built' rooms which could cause issues, so it need not apply the chessboard pattern which would otherwise cause those rooms to be built sequentially.
Describe alternatives you've considered
Another possibility would be to have the ars_sametime_limit be the number of times you're allowed to reconfigure with another process running before it stops you (including the first process).
That would then mean I'd want to do something like
ars_limit: 2
ars_sametime_limit: 5
And then if I wanted the same pattern:
Empty | Empty | Empty | Empty | Empty
Empty | Empty | Empty | Empty | Empty
I'd need to queue up these 5 jobs one after the other:
Empty | Empty | | |
| | | |
| | Empty | Empty |
| | | |
| | | | Empty
Empty | | | |
| | | |
| Empty | Empty | |
| | | |
| | | Empty | Empty
Assuming I specified them in right to left, bottom to top order, as I assume it does it in reverse order of user input, rather than left to right, top to bottom.
Which would (probably?) be less effort to implement, and more effort on the players to work out how to make it not collide.
Which would be fine by me, but might cause confusion or upset if/when someone chose a pattern that meant two adjacent rooms were being built at the same time.
Haha fair enough.
Well I am through trial and error, attempting to zero in on roughly two at a time, it's somewhere between 1.5 and 2 I think...
But it does definitely do it concurrently, so thank you, and I assume we can close the ticket :)
Ah thanks, I think I'm getting close to understanding...
So the way concurrency would work is just shortening the time in between when it triggers the next room, so it'll gradually build up from 1 to max_concurrency
, and there'll be no need to do special handling for doors or trying to sort which rooms start first or anything, it'll all just work fine with no additional required complexity?
Sounds great!
Probably easier to just adjust the delay between when each room growing task starts...
At the moment each room growing is delayed by the average time it takes to grow a room, currently:
long period = 2400L * (Math.round(20 / plugin.getConfig().getDouble("growth.room_speed")));
this could be changed to:
long period = (2400L / plugin.getConfig().getLong("growth.room_concurrent")) * (Math.round(20 / plugin.getConfig().getDouble("growth.room_speed")));
to shorten the period and allow multiple rooms to grow concurrently.
building more than one at once is that if you do it to two adjacent rooms, they sometimes don't mesh properly
And fix this? Though I can't say I've had it happen to me.
How exactly do they not mesh?
Order of room growing is random as the ARS grid changes are stored in an unordered map - only the changes are stored not the whole grid, so calculated white/black chess grids is not possible with current setup.
And fix this? Though I can't say I've had it happen to me.
How exactly do they not mesh?
This was happening when I was doing the cheaty concurrent room builds many many moons ago, which is now disallowed by the message that goes something like "You can't trigger an ARS change while an ARS change is running".
I basically used to run it multiple times which would result in concurrent room builds, but if you built the rooms adjacent to each other concurrently, it'd muck with the doors somehow or other to make them not work.
I assume there is/was some sort of merge-handling when you place a room next to an existing room, that doesn't happen if it thinks the adjacent cell is empty because a separate ARS process is mid-build...?
Either that or it was just that the schematics were overlapping and overwriting each other inconsistently...?
I'm not really sure, I found it to be a problem if I built rooms adjacently in that manner, but at the time I just avoided it rather than report it because it felt like I was gaming the system anyway building more than one room at once like that
Which seems to be the case as it's now prevented by the plugin, so it's only really a theoretical concern at this stage, something to consider if you start looking at making the rooms build concurrently in a supported way.
For all I know it was a WorldEdit problem, and I notice you don't use that for building rooms any more?
So maybe it's a non-issue from the start and your new build method handles schematic door overlap just fine if it were to build rooms concurrently?
Probably easier to just adjust the delay between when each room growing task starts...
Math is not my strong point, what would that end up actually doing?
Order of room growing is random as the ARS grid changes are stored in an unordered map - only the changes are stored not the whole grid, so calculated white/black chess grids is not possible with current setup.
Oh I see, does it just store a list of co-ordinates and what block to set it to?
I assumed it'd be something like a list of type 'room', with properties 'position', 'type', and 'schematic/block changes' defined for it, which you could then have derived a chessboard pattern for based on the position of each room.
Just to be clear the ars_limit is per player.
Yes, that's fine.
I was using what is effectively single-player server as an example because it's simpler, but also because while mine has multiple players, in practise only one person tends to be building more rooms at any given time, so that's what it's calibrated to.
Oh I see, does it just store a list of co-ordinates and what block to set it to?
It stores a TARDISARSSlot
(basically chunk, x, y, z) and the room type to grow there.
It then loops through the slots and grows the rooms - the server processes the loop code as fast as it can, so I start the room growing code in a timed Bukkit task - the first room starts immediately (zero delay), the second room starts (at a minimum) 120 seconds later, the third 240 seconds later etc etc...
Math is not my strong point, what would that end up actually doing?
Currently the math above takes the minimum time (120 seconds or 2400 ticks) and multiplies it by the room speed factor to get the delay between starting room builds e.g.:
room_speed
=4
(the default) -> 2400 * (20 / 4) = 2400 * 5 = 12000 ticks or 10 minutesroom_speed
=20
(the maximum) -> 2400 * (20 / 20) = 2400 * 1 = 2400 ticks or 2 minutes
Adding the room_current
factor to the equation will speed up the delay e.g.:
room_speed
=4
,room_concurrent
=3
-> (2400 / 3) * (20 / 4) = 800 * 5 = 4000 ticks or 3.33 minutesroom_speed
=20
,room_concurrent
=5
-> (2400 / 5) * (20 / 20) = 480 * 1 = 480 ticks or 24 seconds
Perhaps delay_factor
would be a better config key than room_concurrent
...
Yep, exactly that. max_concurrency
would be equivalent to the current ars_limit
value
I set delay_factor = 2
and left room_speed = 4
I then queued up 3 rooms to build.
My assumption is that delay_factor of two means up to two rooms build concurrently... So it would start the first room, then the second room at 50% of the first room, then the third room at 100% of the first room and 50% of the second.
What's happened instead is that the second room has started somewhere between 25% and 34% of the first room:
While the third room started when the first room was between 67% and 75% done, and the second room was between 25% and 34% done:
Is this how that's supposed to work?
room_speed
= 4
, delay_factor
= 2
-> (2400 / 2) * (20 / 4) = 1200 * 5 = 6000 ticks or 5 minutes
3 rooms, one starts at 0 minutes, second starts at 5 minutes, third starts at 10 minutes
So the higher the delay_factor
the less time it takes before the next room starts?
Doesn't room_speed = 4
mean room_build_time = 10 minutes
and therefore the second room starting at 5 minutes should be when the first room is at 50%?
It seems like the room_build_time
is closer to 15 minutes if the second room is starting at what is probably pretty close to 33.3%?
Is that because my server is dropping TPS or because my math is wrong?
Anyway, the point is that you can now get rooms to run asynchronously, so thank you for that :)
Rather than incur further math related headaches, I will just randomly pick values for those settings until I strike the "build two rooms at a time at a sensible build speed" balance that I previously determined will work for our server/user count.