TMPE icon indicating copy to clipboard operation
TMPE copied to clipboard

Cars Pulling Over for Emergency Vehicles (Emergency Vehicle Evasion - EVE)

Open FireController1847 opened this issue 6 years ago • 70 comments

As found in many countries, vehicles must pull to the side of the road and stop if there is an emergency vehicle behind them or coming toward them. If at an intersection, all vehicles must STOP at the intersection regardless of the light color until the emergency vehicles has exited. Reckless drivers could possibly ignore this rule entirely (as seen in real life, people can refuse to pull over. My parents always honk at those guys lol).

I plan on implementing this, but I must research a lot more into how to do it. Mostly making this issue for logging sakes and so nobody steals it ;)

FireController1847 avatar Feb 11 '19 18:02 FireController1847

Hahaha I'm sure nobody wants to steal this task

krzychu124 avatar Feb 11 '19 19:02 krzychu124

Which milestone do you want ? 1.10.16? 😆 🤣

krzychu124 avatar Feb 11 '19 19:02 krzychu124

Heh, I don't know if I'd be able to get it done in time for 1.10.16. I think we should hold off the milestone for now and maybe 1.10.17 / 1.11.0. I can confirm to you if I can get it done for 1.10.16 when I make the PR xD

FireController1847 avatar Feb 11 '19 19:02 FireController1847

Just joking, great, feel free to ask for help, maybe I would find something while digging in other places 😉

krzychu124 avatar Feb 11 '19 19:02 krzychu124

This is very very helpful in the game.

pcfantasy avatar Feb 11 '19 23:02 pcfantasy

@krzychu124 I do have a question and one thing for you to look for, if you can.

  1. What is a "Simulation Step" and how does it work?
  2. If you can find out how to get cars within a segment, that'd be awesome. I think I asked about this in Turn on Red, but didn't need it to do what was tasked. Now, to do this, I'd need to detect if there's an emergency vehicle in a nearby segment, which means I need to get the cars from within a certain segment.

FireController1847 avatar Feb 12 '19 00:02 FireController1847

@FireController1847

uint num2 = vehicleData.m_path;
byte b = vehicleData.m_pathPositionIndex;
byte b2 = vehicleData.m_lastPathOffset;

PathUnit.Position position;
instance.m_pathUnits.m_buffer[(int)((UIntPtr)num2)].GetPosition(b >> 1, out position)

   You can find vehicle is in Position.m_segment.  You need a for {} to find cars within a certain segment

pcfantasy avatar Feb 12 '19 02:02 pcfantasy

@pcfantasy Haha, thank you so much! I was trying my best to understand this and I saw this but was completely lost by what it meant. This helped a lot.

FireController1847 avatar Feb 12 '19 02:02 FireController1847

@FireController1847

VehicleAI.UpdatePathTargetPositions

In fact, those data can be read in everywhere, For example

You can do it in onBeforeSimulationFrame();

for (i = 0; i< 16384, i++) { vehicle vehicleData = Singleton<VehicleManager>.instance.m_vehicles.m_buffer[i]; var instance = Singleton<PathManager>.instance; uint num2 = vehicleData.m_path; byte b = vehicleData.m_pathPositionIndex; byte b2 = vehicleData.m_lastPathOffset;

PathUnit.Position position; instance.m_pathUnits.m_buffer[(int)((UIntPtr)num2)].GetPosition(b >> 1, out position) //then you can get everything use my above codes }

pcfantasy avatar Feb 12 '19 02:02 pcfantasy

@pcfantasy I hate to ask of this, but do you also know how to get the targetNodeId? I need to detect whether or not the vehicle's target is the intersection, or if the vehicle has left the intersection and everything can return to normal.

FireController1847 avatar Feb 12 '19 03:02 FireController1847

Okay, now I need some opinions because there's a few ways I can do this. I'm currently implementing the "stop at a light no matter what if oncoming," not the pulling over aspect.

  1. The first way is that I can use the VehicleBehaviorManager to check and see if there's an emergency vehicles within the opposing segments, and if their targets are the intersection. This would not only require a loop and filtering of all vehicles to find the ones on the segments, it has to happen for every segment connected to a node, AND it has to recalculate the position of the emergency vehicle.
  2. I can add an attribute to segments with traffic lights like "HasEmergencyVehicleApproaching." Then, I can use the VehicleBehaviorManager to handle accordingly. This would require a modification of the emergency vehicle AI to where if the target node has traffic lights to update that node that it's approaching, and then when that node is no longer its target to set the boolean back to zero.

These are my two suggestions on how to do this. Do you guys have any ideas? I've been attempting the first one without realizing what a huge task it is, so I think I want to go with the second one. But if you guys can come up with better ideas, then please let me know.

Also, do any of you guys have Discord? If so, would you mind if we chatted about it? I'm FireController1847#3577

FireController1847 avatar Feb 12 '19 03:02 FireController1847

@FireController1847

//you can try blow codes, I have not test this.

targetNodeId = Singleton<NetManager>.instance.m_segments.m_buffer[(int)this.SegmentId].m_endNode

//maybe there will be a reverse targetNodeId = Singleton<NetManager>.instance.m_segments.m_buffer[(int)this.SegmentId].m_startNode

//So there must be another vehicle direction to decide which is the correct targetNodeId

pcfantasy avatar Feb 12 '19 11:02 pcfantasy

Why not add an EmergencyWeight integer to segments?

Emergency vehicles then increment the value a certain number of segments ahead (in diagram below, 4 segments, but could be any number depending on what works best) and decrements the number behind it.

      4     3     2     1
V -> ____  ____  ____  ____

So the emergency vehicle would create sort of a wave or ripple ahead of itself, warning segments that it's on the way.

If multiple emergency vehicles are heading the same way (common with fire engines) then that would create multiple overlapping waves, ensuring 'moved to the side' vehicles know to wait before continuing their journey.

Other vehicle AIs would check the EmergencyWeight for the segment they are on and take action accordingly. Likewise, traffic lights would also take account of the value. Even toll booths could prepare themselves by allowing a lane of traffic to pass without paying to ensure the emergency vehicle has clear route. Busses could avoid pulling out of bus stops... anything that's travelling on, or is part of, the road network, can adapt by looking at the EmergencyWeight value.

Note: I'm hopeless at monomorphic coding (like C#) so if what I've said above is stupid don't hesitate to ignore it (I know enough to know that I don't know enough!).

originalfoo avatar Feb 12 '19 13:02 originalfoo

Generally I like your idea 👍 , but I think it would look quite strange when vehicles were started to pulling over up to 3 junctions ahead of ambulance (imagine that ambulance has to follow this route:

                * <- target
                |
        *-------*
        |
V ------*

krzychu124 avatar Feb 12 '19 13:02 krzychu124

They only need to start pulling over when it the weight reaches a certain value (for example, 3 or 4).

But other things might need to adapt sooner, such as traffic lights and toll booths (they would start acting when the weight is lower, for example 1 or 2).

There are some problems with the general approach I propose, for example what if an emergency vehicle despawns for some reason (eg. user uses "Clear Traffic" tool)? So what it might need to do is at the start of each frame clear all the weight values; that way emergency vehicles don't need to worry about clearing up after themselves so much.

Furthermore, remember that once a vehicle passes, if there are others nearby on same route, you don't want "pulled over vehicles" to start driving back in to the road, they should wait for 'weight = 0' before doing that. This is particularly important for fire engines, but also important on roads near the emergency service buildings which might be spawning multiple vehicles.

Another thing: The "pulling over" should only happen where necessary, perhaps on smaller roads. On larger roads, or roads with bus lanes, it's less important as the emergency vehicle can lane swap.

originalfoo avatar Feb 12 '19 13:02 originalfoo

I would say that the important part of this code is to know when to trigger the vehicle pathfinding recalculation. I don't know if there is a list of vehicles on current nodes, but it should be because how would otherwise traffic lights and stuff like that work? I recommend looking at their source code. It think that for this to work well you would need to allow the vehicle to use the opposite direction lanes. Overall, this feature is one of the most difficult tasks. Then there is the limitation that vehicles cannot switch lanes anywhere else than on junctions (taking into consideration the virtual ones as well). (Or am I wrong?) So it is a question how realistic the behavior will be.

Strdate avatar Feb 12 '19 14:02 Strdate

When vehicles park, or when things like ambulances and hearses pull on to pavement, the code that does those things would be worth inspecting.

IMO it would be worth doing some mini mods, like on that just deals with making vehicles on a segment pull over when segment is clicked, and then resume driving when segment clicked a second time. People could test that out and report back any obvious bugs or issues. I think if we try and release this feature in one big update, there will be so many bugs that we won't know where to look.

originalfoo avatar Feb 12 '19 14:02 originalfoo

I agree with this. I think that slowing down is ok, but anything more complex like going on the side is something which requires more than what usually happens in TMPE mod.

Strdate avatar Feb 12 '19 14:02 Strdate

AFAIK ambulances and hearses pull on to pavement because every building in game has set spawn point there which in this case is used as destination target

In regards to problem that vehicles cannot change lanes maybe we should create these nodes (before and after accident) if it's possible (I didn't tried yet)

krzychu124 avatar Feb 12 '19 14:02 krzychu124

For accident zones: When a road is demolished and new one built nearby, cars will travel from their current location to the new road (if it's near enough) - so we could simply 'block' (somehow) the affected lanes and repath nearby vehicles (they might do it automatically without us needing to repath them?) - they will swerve on to remaining paths.

originalfoo avatar Feb 12 '19 14:02 originalfoo

While yes I agree this is a very complicated feature with many ifs and buts, I don't think it's too much to add to TMPE. TMPE is supposed to give people control over their traffic, right? By allowing people to have cars pull over for emergency vehicles, it gives even more control over their traffic. I don't see this being any smaller of a feature than #46, no? Overall, though, I'll let @krzychu124 decide if I should make this a separate mod or not.

On another note, @aubergine10 I like your idea of having a "weight" for emergency vehicles. However there's one major issue: Segments are huge. If we were to do 3-4 segments down, it would be the equivalent of stopping vehicles miles away. Now I know you said they'd only stop on the highest one, and I think that's a great idea, but that provides us with a problem of needing to calculate three to four segments in advance for the emergency vehicles. I'm having mixed feelings about this but I feel this is our best option, honestly.

When it comes to traffic lights, we will need a way of detecting if there's a blocked path. When in a traffic jam, vehicles cannot pull over or cannot move. Due to this, vehicles must continue moving forward as if there wasn't an emergency vehicle there until there is a clear path to the intersection. I have a great example of a blocked road in one of my maps at home, so later today I'll be able to send an image of it.

Having vehicles pull over and stop does not seem very difficult. Would it not just be setting their trajectory like how busses pull over, like mentioned? Busses do the exact thing that cars need to do.

I agree that this is a daunting task, but I believe you guys are making it more complicated than it needs to be really. There's three major things we need to do for emergency vehicles:

  • Pull over.
    • To implement, we'd need to add a way to get the vehicles to pull over. A toggle test button within their menu, perhaps.
    • We'd also need a way to detect when there's an emergency vehicle approaching.
      • It wouldn't make much sense to pull over if it's not approaching them from either direction, no?
    • To detect is not that difficult, but there's different ways we can do it.
      • The recommended way is a weight system, which sounds complicated, but makes sense for future implementation. It wouldn't be too difficult, either.
      • We just need to figure out the first three segments ahead and the last three segments behind.
      • This would result in us having to speed up pathfinding or get it further ahead, which is certainly possible and not unrealistic.
      • We will definitely need help with this feature, and need an understanding of the pathfinding.
  • Stop at traffic lights.
    • This will also require detection of vehicles.
    • We need the ability to resume traffic if the vehicle is stuck behind them.
  • Resume normal traffic. As seen here, there are many if's and but's when it comes to this feature, and yes there's a lot of test cases, but if we just follow these general three rules without attempting to add more features like toll booths and other things, it gives us a basis to work on. Then we can possibly add features like toll booths.

Don't look at this from a general perspective (unless you're brainstorming about the entire feature, in which case feel free), but look at this from the initial three points. If we add features slowly, step by step, instead of trying to tackle it all at once, we'll actually be able to do something.

FireController1847 avatar Feb 12 '19 14:02 FireController1847

Nobody wants to exclude this from traffic manager, but the idea is that this requires testing of so many features which should be rather done outside TMPE. This is indeed very daunting task, it is connected to half of other features we would like to implement.

Strdate avatar Feb 12 '19 15:02 Strdate

As @Strdate says above, community testing is going too be important for this feature - it has to be tested on all sorts of roads, junctions, etc. What effect does it have on trams, bikes, busses? What about roads with multiple medians and weird lane arrangements... The end result will be in TMPE, but initial dev might be better suited to a separate mod where we can easily roll out changes to a large audience of beta testers rather than waiting for TMPE release cycle.

Anyway, for the cars pulling over, I think the best place to look might be how parking lanes work. That's almost exactly what we want (more so than bus stops), we basically make an entire lane of traffic "park". We could perhaps create fake parking lane for them to park in or something? That way we can reuse vanilla code that does the parking manoeuvres.

If we release a mod with that "pull over" feature, activated by clicking a segment to toggle between "pull over" and "go back to normal", it will allow lots of people to test it out and let us know what happens.

originalfoo avatar Feb 12 '19 15:02 originalfoo

The best would be create separate github repositories and maybe Steam workshop items to test small parts of this feature (As @aubergine10 there would be tenths of different roads types to test with).

Later we could try to merge those small parts to create something bigger and test again.

I've been thinking about splitting TE:PE to be more modular and open on extensions (plugins) like other great big Steam workshop mods. Tell me what do you think. Is it possible and worth effort?

This feature could be a sort of plugin to mod base, but first I need to make some tests to check if it is possible.

krzychu124 avatar Feb 12 '19 15:02 krzychu124

@krzychu124 I don't think it's worth the effort. I know a lot of people would rather have a mod that can be installed with one click and then modified how they wish, versus having to try and find a bunch of different workshop extensions which may or may not be updated and may or may not be listed in the description which may or may not be working. When it's all in one big bundle, you can be sure it will either work or it wont -- or at least, some features will work and some wont. A great example of bundled would be the NeXT mod, as well as how TMPE is now. You can see the total downloads and are sure that it will either work or not. Now look at the mess of a mod called Roads United. There's many different versions of the base mod, some of which work and others don't, there's many extensions that sometimes work and sometimes don't, and there's often confusion between which mods are required and which mods should be enabled. I personally would much rather have a mod like TMPE is now where you can enable and disable settings as you please, all in one place.

@aubergine10 @Strdate Apologies of my misunderstanding. I think it's a good idea to make a separate workshop mod & GitHub repository to test these features, however I would have no idea where to start. How do I access TMPE methods? How do I set up Visual Studio? Do I make it a completely separate mod? Also, what if I need to use protected/private methods?

FireController1847 avatar Feb 12 '19 15:02 FireController1847

With regards to setting up Visual Studio and accessing methods, just add compiled TrafficManager.dll to project references and you will have access to everything (public). Reflection should help with protected/private methods - it's just test it doesn't have to have max performance, I think.

krzychu124 avatar Feb 12 '19 16:02 krzychu124

@krzychu124 I agree with @FireController1847 , I think TMPE is best as single mod for now.

Even back in early T++ and TM days, back in 2015, people were asking for modularisation. But it became clear that doing so actually caused performance issues. The approach TMPE takes currently seems to work well in that it recompiles itself with just the activated features, thus completely removing unnecessary code from runtime.

Imagine if it were a bundle of separate mods, all having to interact with each other to some degree. Also, what if in a year or so, we've all gone off to do other things and someone else takes over with a new branch of the mod. I think this would be confusing for end-users to try and work out what component mods work with the main mod; like @FireController1847 says, we'd end up with a "roads (dis)united" situation.

I can obviously see the benefits of modularisation, however, such as being able to rapidly iterate individual features without needing to roll out the full mod, but in practice I think it always turns out not to be as simple as that. Another example is the various 'extensions' to "Move It" mod that were released; despite the main Move It mod being stable and not changing much any more, those extensions were short lived and in the end it was easier for quboid (sp?) to just release a new Move It with all those features bundled in to the main mod. Compared to TMPE, Move It is a simple mod, so...

originalfoo avatar Feb 12 '19 16:02 originalfoo

Thanks @FireController1847 and @aubergine10 for your opiions 👍 So now we can focus on more important things 😉

krzychu124 avatar Feb 12 '19 16:02 krzychu124

I think I'm not fully understanding this "separation" thing. How do I make a mod that modifies the logic of TM;PE? Particularly, the driving logic? I would need to interrupt the normal driving logic (which, by the way, I have no idea where it is) with the parking logic. Wouldn't that require me to make a modification to the AI, which you can't do if you only extend/use functions within TMPE?

FireController1847 avatar Feb 13 '19 01:02 FireController1847

In this mod we have pathfinding function which finds paths from source to destinations and vehicle behavior which is responsible for their travel along path (stop, move, wait etc.) In case we want to force vehicles to pull over I think vehicle behavior class would be better place to start

Just throwing my ideas below...

I suggest to digging through code to find what is going on when ambulances driving on emergency (Flag.Emergency2 in vanilla). Sometimes I can see that ambulances are moving in-between lanes or turning right with overtaking other vehicles at junctions. There must be a line in code where their path bend is performed.

krzychu124 avatar Feb 13 '19 07:02 krzychu124