CitiesSkylinesMods / TMPE

Cities: Skylines Traffic Manager: President Edition
https://steamcommunity.com/sharedfiles/filedetails/?id=1637663252
MIT License
571 stars 85 forks source link

MPH vs. KPH speed display #13

Closed originalfoo closed 5 years ago

originalfoo commented 5 years ago

For us Brits, being able to see speed limits as MPH instead of KPH would be a dream

https://github.com/VictorPhilipp/Cities-Skylines-Traffic-Manager-President-Edition/issues/61

krzychu124 commented 5 years ago

Nice addition but since speed values in game are neither KPH nor MPH how could I calculate some these values. Now we have 13 different speed limit values . Please tell me how to translate it to MPH since I don't want to create signs with strange values like ~37mph which is 60kph πŸ˜ƒ It would be great if if we persist the same number of signs for easier interchange 1 : 1

An in-game speed limit of 2.0 (e.g. on highway) is hereby translated into a discrete speed limit value of 100 (km/h). https://github.com/krzychu124/Cities-Skylines-Traffic-Manager-President-Edition/blob/fae45d3306ee0ba17053d355838797b4236c5e88/TLM/TLM/Manager/Impl/SpeedLimitManager.cs#L266-L281

If we want to convert it back(e.g. to apply to road segment) we have to divide our discrete limit by 50 (100(kph)/50 == 2.0(in-game)

originalfoo commented 5 years ago

Agreed, weird numbers on signs would be bad.

I'll ask author of 'UK Roads Revived' project what approach he's taking. There was also some discussion back in the Traffic++ days so I'll see if I can find that too.

originalfoo commented 5 years ago

Also, the icon used to denote 'max speed limit' is confusing, at least to UK drivers.

120px-unlimited

In UK, that means: "National speed limit" or, more specifically, 'use the correct speed limit for your vehicle on this type of road in this kind of area' which, more verbosely, means:

In a built-up area – a road with β€œa system of street lighting furnished by means of lamps placed not more than 200 yards apart” – the speed limit is 30mph for all vehicles; on a single carriageway, the speed limit is 60mph for cars and vans (50mph if towing or driving a bus, minibus or lorry less than 7.5 tonnes; 40mph for lorries over 7.5 tonnes); or 70mph on dual carriageways and motorways for cars and vans (it’s 60mph or 70mph for heavier or longer vehicles).

*stares blankly at whoever invented that street sign*

krzychu124 commented 5 years ago

https://en.wikipedia.org/wiki/Speed_limits_in_Germany πŸ˜‰

originalfoo commented 5 years ago

Author of "UK Roads Revived" assets has been treating the km/h values as mph values (ie. for a 30 mph road, he sets 30 km/h). This actually results in the road being a lot slower (it should be closer to 40 or 50 km/h) but it at least means the TM:PE speed tool is matching the road speeds.

I guess it might be worth just ignoring mph vs. km/h for now? Plenty of other stuff to be getting on with.

For reference, I dug out an old discussion from the Traffic++ days, in case it's of any future use: https://github.com/joaofarias/csl-traffic/issues/8#issuecomment-101854431 (there's like 500 comments in that issue along with hundreds of images and icons so it may grind a bit while loading).

krzychu124 commented 5 years ago

In game speed is represented by range from 0.1 to 2.0, so there is no km/h nor mph. It seems to me that max speed in mph would be 85. I think I can make some sort of mapper that could round km/h to mph with rounding to closest speed sign values. If there will be the same number of signs it would work interchangeably: kph =>mph => kph, I think. What values you suggest in this case? We can start from 5 and then choose most popular to fill the rest missing values to match current number of signs

krzychu124 commented 5 years ago

oh... πŸ˜„ I've just saw your comment in discussion you've referenced πŸ˜†

originalfoo commented 5 years ago

I'd have to check which countries still operate in imperial units for road speeds.

In UK, fastest road speed allowed is 70mph.

In km/h, there are currently 14 speeds to choose from in TM:PE.

Maybe in mp/h we provide only 7? (ie. one row disappears from the speed selection panel).

I'll do some googling to see whether that would be feasible.

krzychu124 commented 5 years ago

Maybe in mp/h we provide only 7? (ie. one row disappears from the speed selection panel).

What about compatibility with current user save games ? What if they'd set value that we won't show in mph version, what should we display? To switch from mph to kph we can apply rounding but not in reverse πŸ˜•

originalfoo commented 5 years ago

Lots of places use it: https://en.wikipedia.org/wiki/Miles_per_hour

It's also used on rail systems, which is going to be a problem if you want trains going faster than 85mph.

I grinded through all the paces listed on that wikipedia page to find out what their common road speeds are... Behold:

Not sure if that is help or hindrance lol.

originalfoo commented 5 years ago

Fastest trains (mph):

FireController1847 commented 5 years ago

It appears to me that the current speed options are in KPH. 25 MPH = ~40 KPH. When looking at the speed of the cars compared to how fast they pass buildings, it seems very similar to MPH.

Also, here's how speed limits work here in Utah and in many parts of America:

All of these are in MPH. Hope this helps :)

originalfoo commented 5 years ago

In UK it's a tad more straightforward:

Ultimately it's up to user what speeds they set for their roads. The dilemma is how to translate between km/h and mph within TM:PE.

FireController1847 commented 5 years ago

Well since it appears that the velocity of cars relates to KPH in its current form, could we base it off of that? Then we'd only need to convert from KPH (which we already know, due to the assumption that the current values relate to KPH) to MPH.

Also, for this, are we planning on allowing 5 intervals (5, 10, 15, etc) instead of 10 (10, 20, 30)? Because that's something I've been longing for a long time.

originalfoo commented 5 years ago

It should be feasible to do a fairly accurate mapping...

krzychu124 wrote:

In game speed is represented by range from 0.1 to 2.0, so there is no km/h nor mph. It seems to me that max speed in mph would be 85. I think I can make some sort of mapper that could round km/h to mph with rounding to closest speed sign values. If there will be the same number of signs it would work interchangeably: kph =>mph => kph, I think. What values you suggest in this case? We can start from 5 and then choose most popular to fill the rest missing values to match current number of signs

Based on my research the speed range for roads in mph is: 10 .. 85 mph

That would mean, in 5mph increments: 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85

So we can definitely map across, but there will be 3 of the mph options that don't directly convert to km/h options. Do we ditch 3 of the mph options? That's one issue.

The other issue is what to do with trains? There is a need for up to 185mph (for existing trains IRL), but things like Hyperloop (USA) or HS2 (UK) could demand even faster. Do we just use the "unlimited" option for those? What happens if there's a "sharp" bend in a train track and the only way to slow down is to go from "no speed limit" to 85mph. That's a lot of brake screeching sounds!

Speaking of trains, we should investigate what Other Rail Track Speed Increaser mod does. It purports to change "Max speed possible increased from 450 to 1000" - whatever that means?

It would also be nice if I could filter out signs I don't want somehow - maybe a pop-up panel that lets me toggle various speed options on or off? Those speeds could still appear on the map, but they would be hidden from the "speed palette" to make it easier to find speeds I actually use.

FireController1847 commented 5 years ago

@aubergine10 Have you checked the source code of that mod using ILSpy? It appears to be that each lane contains its own "speedLimit" value, as seen in this mod. All the mod appears to do is take updated speeds (possibly numbers above 2, I'd assume) and set the speedLimit of every lane for Tracks and Rails to be larger. Also, to make the value option, they add a slider to their options UI that slides between what speed they want.

See the following code examples from the mod.

private Dictionary < SubService, float > _subServiceSpeedMap = new Dictionary < SubService, float > {
 {
  11,
  11.25 f
 },
 {
  12,
  11.25 f
 }
};
float num2 = _subServiceSpeedMap[subService2];
if (!_ingame) {
 _prefabSpeedMap.Add(prefab, prefab.m_averageVehicleLaneSpeed);
 _Log("Increasing speed of " + prefab.get_name() + " to " + num2);
}
for (int j = 0; j < prefab.m_lanes.Length; j++) {
 Lane val = prefab.m_lanes[j];
 if (val != null && (int) val.m_laneType == 1) {
  val.m_speedLimit = num2;
 }
}
prefab.m_averageVehicleLaneSpeed = num2;
originalfoo commented 5 years ago

Their source code is on pastebin (dunno if it's up-to-date): https://pastebin.com/sDbefj5J

I have no idea what happens with speed values above 2.0. I guess it would be problem on roads, where there are lots of bends, but might be viable for train tracks? If that's the case, how would we prevent train-related speeds being applied to roads?

FireController1847 commented 5 years ago

I've been messing with the VehicleAI and CarAI to see if there's anything that controls the maximum speed limits for vehicles and if there's any way to make it higher. It appears that I can modify the SpeedLimitManager to make "80" set a speed limit of "160," (equiv of 100 MPH) and this does work. However, for whatever reason cars refuse to speed up (I wonder if they hit the car's "max Speed Limit"). So, assuming the cars couldn't go faster, I tried to see if they could. Within VehicleAI's main pathfinding stuff, there's a "nextMaxSpeed" variable that gets passed into a "CalculateNode" or whatever function. This function checks for "position.w," which happens to be the speed of the vehicle moving to the next node. It also happens to check if it's greater than 4f, and if so, it sets it to 4f. If we could raise this value by making a custom method for it, we could possibly make the maximum speed limit of the vehicle larger. However when I attempted to make the method and add it to LoadingExtension, it did not call my custom method. I could have been making a mistake. The below is the changes I've made to the code.

CustomCarAI.cs, starting at line 388 (after CheckCitizen function)

/// ////////////////////////////////////////////////////////////////////B DWQJ!HLBFJF$@!

// CustomUpdateNodeTargetPos relies on private method "CalculateCrosswalk," which I copied and pasted here.

// Most of this is stock code.
public void CustomUpdateNodeTargetPos(ushort vehicleID, ref Vehicle vehicleData, ushort nodeID, ref NetNode nodeData, ref Vector4 targetPos, int index) {
 if ((nodeData.m_flags & NetNode.Flags.LevelCrossing) == NetNode.Flags.None) {
  return;
 }
// I commented this out to see what it could do, then attempted to log when this was called. It did not log.
 /*
 if (targetPos.w > 4f) {
     targetPos.w = 4f;
 }
 */
 if (Options.turnOnRedEnabledByDefault) {
  Log._Debug($ "CustomCarAI.UpdateNodeTargetPos({vehicleID}): targetPos.w={targetPos.w}");
 }
 if (index > 0) {
  return;
 }
 NetManager instance = Singleton < NetManager > .instance;
 for (int i = 0; i < 7; i++) {
  ushort segment = nodeData.GetSegment(i);
  if (segment == 0) {
   continue;
  }
  NetInfo info = instance.m_segments.m_buffer[segment].Info;
  if (info.m_class.m_service != ItemClass.Service.PublicTransport || !CalculateCrossing(info, segment, ref instance.m_segments.m_buffer[segment], nodeID, out Vector3 position, out Vector3 direction, out float radius)) {
   continue;
  }
  for (int j = i + 1; j < 8; j++) {
   ushort segment2 = nodeData.GetSegment(j);
   if (segment2 == 0) {
    continue;
   }
   NetInfo info2 = instance.m_segments.m_buffer[segment2].Info;
   if (info2.m_class.m_service != ItemClass.Service.PublicTransport || !CalculateCrossing(info2, segment2, ref instance.m_segments.m_buffer[segment2], nodeID, out Vector3 position2, out Vector3 direction2, out float radius2)) {
    continue;
   }
   // This function happily errors with any version of .NET below 7.2. Easy fix, instead of replace the two default names of "myItem: true, myItem2: true" to just be "true, true". You can see my change here.
   NetSegment.CalculateMiddlePoints(position, direction, position2, direction2, true, true, out Vector3 middlePos, out Vector3 middlePos2);
   float u;
   float num = Mathf.Sqrt(Bezier2.XZ(position, middlePos, middlePos2, position2).DistanceSqr(VectorUtils.XZ(targetPos), out u));
   float num2 = radius + (radius2 - radius) * u;
   if (num < num2 + 1 f) {
    float num3 = position.y + (position2.y - position.y) * u + 0.1 f;
    if (num > num2 - 1 f) {
     num3 -= (num - num2 + 1 f) * 0.3 f;
    }
    if (num3 > targetPos.y) {
     targetPos.y = num3;
    }
   }
  }
 }
}

LoadingExtension.cs, starting at line 2033, following the CarAI::StartPathFind calls.

Log.Info("Redirection CarAI::UpdateNodeTargetPos calls");
try {
 Detours.Add(new Detour(typeof(CarAI).GetMethod("UpdateNodeTargetPos",
   BindingFlags.NonPublic | BindingFlags.Instance,
   null,
   new [] {
    typeof(ushort),
    typeof(Vehicle).MakeByRefType(),
     typeof(ushort),
     typeof(NetNode).MakeByRefType(),
     typeof(Vector4).MakeByRefType(),
     typeof(int)
   },
   null),
  typeof(CustomCarAI).GetMethod("CustomUpdateNodeTargetPos")));
} catch (Exception) {
 Log.Error("Could not redirect CarAI::UpdateNodeTargetPos calls");
 detourFailed = true;
}

SpeedLimitManager.cs, starting at line 591, following the debug statement.

if (speedLimit == 80) {
 Flags.setLaneSpeedLimit(curLaneId, 160);
} else {
 Flags.setLaneSpeedLimit(curLaneId, speedLimit);
}

SpeedLimitsTool.cs, starting at line 365. Must check if the speed is not there since we're setting the non-existent speed of "160."

if (!SpeedLimitManager.Instance.AvailableSpeedLimits.Contains(speedLimitToSet)) return false;

I'm getting on my laptop now, which means I'm going to lose my changes. Hopefully my experimentation helps you guys figure out something.

originalfoo commented 5 years ago

The only real issue with cars is the fact they fly off sharp bends if they're going to fast (see #23 for some discussion on that). We wouldn't need road vehicles going faster than 85mph (136 km/h) as far as I can tell (unless someone is trying to replicate Formula1 in CSL).

The main issue with the speed limits is trains, I think. I've not experimented with fast trains, so I can't say for sure, With fastest trains IRL, we'd be looking at speeds of 320 km/h (Shinkansen), 360 km/h (HS2), 1,200 km/h (Hyperloop).

I have no idea if the game can handle such fast moving objects in a reliable manner without them flying off tracks. I assume we can rule out the Hyperloop scenario as CSL maps just aren't big enough for trains moving that fast.

@Ronyx69 is working on some new Shinkansen rail tracks so maybe he could give some advice on this matter?

originalfoo commented 5 years ago

Here's a video showing what happens when trains go too fast - quite amusing:

https://www.youtube.com/watch?v=PKFrJtFa7sE