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

Road Restrictions for buildings and districts #1700

Open
marcin7848 opened this issue Nov 27, 2022 · 1 comment
Open

Road Restrictions for buildings and districts #1700

marcin7848 opened this issue Nov 27, 2022 · 1 comment
Labels
feature A new distinct feature triage Awaiting issue categorisation

Comments

@marcin7848
Copy link

Hi, the feature I'm going to present here I've already discussed with @krzychu124. He made some very good suggestions. While I'm trying to learn how to make mods and create this one, maybe someone more experienced is willing to pick it up, maybe discuss the usage and potential issues, so I'm putting it here.

If I understood everything correctly, the current way of working with TM:PE Road restrictions look like this:

  1. You pick up the TM:PE Road Restriction tool from the TM:PE menu
  2. You click on the road to block the segment for trucks
  3. The function adds another segment to the storage with restricted segments, it looks like this:
[segment][bus-lane mode (3 options)][segment lane count] -> Vehicle Type (combined bit flag) {cargo truck is 2}
for e.g.:
[X][0][2] -> 2
  1. The truck spawns and runs the pathfinding algorithm
  2. While finding the correct path, the data with restricted segments is loaded, it looks like this for e.g.:
[X][0][2] -> 2
[A][0][2] -> 11
[B][0][2] -> 1
[C][0][2] -> 2
[D][0][2] -> 7
[E][0][2] -> 11
  1. The pathfinding algorithm avoids using segments that were just loaded and creates the path.

And now the new feature I suggest.
Instead of restricting segments for every truck (or any other kind of vehicle), let's make it per building/district.

Firstly, I made a very simple paint example of usage of this feature:
tmperest1

How do I see it working?

  1. You click on the building/district name
  2. You click on the TM:PE Road Restriction Icon
    2b. When you click it, every restricted segment for this building/district is shown on roads (similar to the way it is now, but instead of the icon for blocked segment for trucks, it shows the icon for blocked segments for truck only for the chosen building/district)
  3. It allows you to click on road segments and restrict them (similar to current TM:PE restriction)
  4. You block a segment for the building 121 for trucks {vehicle type: 2}
  5. It generates a new line in format:
[segment][bus-lane mode (3 options)][segment lane count][buildingIDs] -> Vehicle Type (combined bit flag)
for example:
[X][0][2][121] -> 2

5a. If the segment X is already restricted for other buildingIDs, for e.g.:
[X][0][2][5,8,10] -> 2
instead of adding a new row, it adds a new element to [3] element of the variable, so for building 121 this row will looks like this now:
[X][0][2][5,8,10,121] -> 2

5b. If you restrict the road for the district instead of building, we make another storage for blocked districts like:
[segment][bus-lane mode (3 options)][segment lane count][districtIDs] -> Vehicle Type (combined bit flag)

  1. The new (or edited) row is added to the database

  2. The truck from the {buildingID: 121} spawns and runs the pathfinding algorithm

  3. The data provided at the beginning of the pathfinding algorithm: {buildingID: 121} and every districtIDs where this building is located, for e.g.: {districtID: 5} and {districtID: 12}

  4. While finding the correct path, the data with restricted segments by standard TM:PE is loaded, it could look like this:

[A][0][2] -> 2
[B][0][2] -> 11
[C][0][2] -> 2
  1. Now the data with restricted segments for specific buildings is loaded:

10a. If we can do filtering while fetching the data from the database, we provide to the query the {buildingID: 121}
and we get:
[X][0][2][5,8,10,121] -> 2

10b. If we cannot do filtering while fetching the data, we load everything:

[X][0][2][5,8,10,121] -> 2
[D][0][2][57] -> 2
[E][0][2][33] -> 2

10c. If we load everything (10b), we filter the data after the loading, so instead of 10b. rows, we get only:
[X][0][2][5,8,10,121] -> 2
why?
Because we don't need another segments for our {buildingID: 121}, no other segment contains it, so we remove them

  1. The storage with segments restricted for districts is loaded too (look at 5b.)
  2. So now you have 3 sources of restricted segments: 9., 10., and 11.

12a. You have prepared data from the 9 and 10 point, the 11 needs to be made.
You provided the districtIDs where the {buildingID: 121} is located (look 8.), so it's {districtID: 5} and {districtID: 12}
While getting the data in 11. point or now, we filter the data from 11. to get only segments where the {districtID: 5} and {districtID: 12} are restricted, so we get for example:

[segment][bus-lane mode (3 options)][segment lane count][districtIDs] -> Vehicle Type (combined bit flag)
[Z][0][2][5] -> 2
  1. Now, when you have all the data, you provide it to the pathfinding algorithm and you make these segments invisible while the pathfinding algorithm is working. It looks like this:
[A][0][2] -> 2
[C][0][2] -> 2
[X][0][2][5,8,10,121] -> 2
[Z][0][2][5] -> 2

Different 3 rules decide to avoid the segments: A, C, X and Z for the truck when the source of it is the {buildingID: 121}.

To check:
If the source of the truck changes when it reaches the train station (and other way of travel)
So for e.g. when the truck from an Oil Industry Pomp -> goes to train station -> and leaves at another train station (is the truck building source still the Oil Industry Pomp or is it the train station where it leaves? - if the second one, make the possibility of restricting roads for trains stations etc. so we block a segment for a truck when its source is the train station)

The feature seems not so hard to make. It would use most of the tools that already exists in the TM:PE. The biggest "if" is in the 8. point, so providing the building id and district id to the pathfinding algorithm while the car is spawned (so where to get that data?).

The example I've just shown is for trucks and - in general - cargo, but - of course - it could be used for any other vehicle, like cars or service vehicles.
The potential huge usage is for cars but it would require additional work to make an ability to restrict roads (sidewalks) for pedestrians because if we restrict all roads for cars to force citizens to use a tram station, there is currently no way to prevent them from just walking to their destination.

@marcin7848 marcin7848 added feature A new distinct feature triage Awaiting issue categorisation labels Nov 27, 2022
@krzychu124
Copy link
Member

Thanks for feature suggestion.

I see couple of quite complex challenges and I'm pretty sure I already pointed out few of them but I'll repeat;

  1. Game can use from 1 to 10+ pathfinding threads.
  2. The only way to get info about district where the building is located is by "querying" District Manager with the building position. District Id is not stored in any structure other than District Manager itself - it's area based, two dimensional array of cells describe district bounds and as you can see (it's not the only place where similar way of storing info applies) data structures were designed and optimized for specific flow which means going against the flow might be insanely time consuming or might require challenges in synchronization or memory consumption to map everything.
  3. Pathfinding is lane based, so to generate path it has to check every single lane of the segment, moving in both direction (via segment nodes), plus additional traversing by segment lane connection (game can connect additional node(s) and segments to the segment - invisible connection)
  4. Since pathfinding threads are running concurrently the data structure for vehicle restrictions was designed to avoid looping at all cost, because introducing loop would have to introduce resource locking == bottleneck, and since restricted vehicle type is stored in 3rd dimension access to whole array would have to be locked per thread. Searching for path across whole map takes usually about 1-20ms obviously with much slower results in dense areas where ton of networks were used.
  5. Vehicle restriction data is not fetched at a start of pathfinding task, but accessed directly from the thread to save CPU cycles and most importantly to completely eliminate memory garbage generation - Pathfinding thread doesn't create any objects when running which means it doesn't allocate any new memory that would have to be released later.
  6. With regards to 10c it's bad idea. Since you've already reached 6th point while reading you should know why, if you are not sure, let me know I'll explain it in short 🙃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature A new distinct feature triage Awaiting issue categorisation
Projects
None yet
Development

No branches or pull requests

2 participants