Jump to content
Strdate

Modding - net segments, net nodes & other

9 posts in this topic Last Reply

Highlighted Posts

Posted:
Last Online:  
 

Hi guys! For a long time I wanted to start developing mods (I have a few ideas in my head). I have some experience with Java, but anyway, I spent dozens of hours in pain before I understood at lest a little bit of what is going on. (btw, thanks very much for Boformer's tutorials)

Now I encountered a few problems which maybe somebody had already encountered before. Unfortunately, I wasn't able to find much about it on the Internet. I looked into the source code of existing mods as well, but either I missed the right mod or there is nothing as such I am looking for.

As I understand it, the route of a net segment is characterized by the position of the two nodes and by two direction vectors. Now I have two net segments which cross each other at some point, but there is no junction (node). Is there any easy way how to create a node at that exact position? If both of the segments are straight, it would be still quite manageable, as it is like searching for an intersection of two linear equations. But if they are curved, not only you have to find the intersection, but calculate the direction vectors as well.

I don't even know how to relate the direction vectors and node positions with the function of some parameter of the segment in the plane, which would be a great help alone. I am sure that at least outside the context of c:s this must be a very well-known problem, but unfortunately I don't know how to ask Google about it...

I would appreciate every advice or link to any resource. If you have something unrelated, I would be glad for that as well. Everything is better than browsing through source code without much comments. Cheers!

Share this post


Link to post
Share on other sites
Posted:
Last Online:  
 

You can find out if a segment is straight arbitrarily by using NetSegment.IsStraight() with no parameters. That will save a lot of calculation.

 

Net segments can also be defined as a cubic bezier with the middle points (bezier.b and bezier.c) being found by the function NetSegment.CalculateMiddlePoints, so you're in luck, because you don't have to use much complex math. I tried to explain how to do at least the intersection process, but I couldn't even understand my own explanations, so here's some code that roughly finds the intersection point and places to split each NetSegment:

// First segment data
NetSegment yourSegmentHere;
Bezier3 bezier;

// Second segment data
NetSegment yourSecondSegmentHere;
Bezier3 secondBezier;

// Turn the segment data into a Bezier2 for easier calculations supported by the game
bezier.a = NetManager.instance.m_nodes.m_buffer[yourSegmentHere.m_startNode].position;
bezier.d = NetManager.instance.m_nodes.m_buffer[yourSegmentHere.m_endNode].position;

bool smoothStart = (Singleton<NetManager>.instance.m_nodes.m_buffer[yourSegmentHere.m_startNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None;
bool smoothEnd = (Singleton<NetManager>.instance.m_nodes.m_buffer[yourSegmentHere.m_endNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None;

yourSegmentHere.CalculateMiddlePoints(bezier.a, yourSegmentHere.m_startDirection, bezier.d, yourSegmentHere.m_endDirection, smoothStart, smoothEnd, out Vector3 bezier.b, out Vector3 bezier.c);

Bezier2 xz = Bezier2.XZ(bezier);

// Second segment:
secondBezier.a = NetManager.instance.m_nodes.m_buffer[yourSecondSegmentHere.m_startNode].position;
secondBezier.d = NetManager.instance.m_nodes.m_buffer[yourSecondSegmentHere.m_endNode].position;

bool smoothStart = (Singleton<NetManager>.instance.m_nodes.m_buffer[yourSecondSegmentHere.m_startNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None;
bool smoothEnd = (Singleton<NetManager>.instance.m_nodes.m_buffer[yourSecondSegmentHere.m_endNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None;

yourSegmentHere.CalculateMiddlePoints(secondBezier.a, yourSecondSegmentHere.m_startDirection, secondBezier.d, yourSecondSegmentHere.m_endDirection, smoothStart, smoothEnd, out Vector3 bezier.b, out Vector3 bezier.c);

Bezier2 xz2 = Bezier2.XZ(secondBezier);

if(!xz.Intersect(xz2, out float t1, out float t2, 5)){ // can adjust final parameter "to taste". 5-8 should probably be fine although I haven't tested this to find out.
  return;
}

Vector2 intersectionPoint = xz.Position(t1);

// you will now have two time-based variables, t1, and t2, that are the parametric intersection times for the respective beziers. Then you can split the beziers at their respective points using Bezier2.Divide and create new NetSegments based on the resulting data.
// you also have the coordinates of the place where the segments intersect.

The rest would be relatively simple, but I don't want to write your mod for you :) Psst! I'd suggest taking a look at NetTool.CreateNode for physically placing the new node and segments.

Happy modding, I'm excited to see what you make!

  • Thanks 1

Hello! Salut! Привет! | My Workshop (follow me? :]) • My Github • My Twitter

 

Share this post


Link to post
Share on other sites
  • Original Poster
  • Posted:
    Last Online:  
     

    Oh, you are amazing! Thanks very much. For now I somehow managed to do without it, but I will definitely implement it in some form. I really don't know much about Bezier curves and stuff, so I still have problems understanding what for example direction vectors really mean. I do some very strange calculations in my code and I am really surprised that it somehow works. I found out how to place nodes and segments from the Parallel Road tool, but thanks anyway.

    There is a peek into what I am doing -

    screenshot

    For now it is just a simple roundabout builder, which replaces a selected node with a roundabout. Then it snaps the boundary segments back onto it. (You can see that the whole highway intersection was replaced with a roundabout, although I don't know why would anyone do that) In the future I would like to create more tools like this, but for now I have enough problems with this. By the way, I "borrowed" from your Segment smoother mod the node selection mechanism, I hope you wouldn't mind :D

    I still have a lot of questions, but for now I just need some time to process it all. Hopefully I will release some beta version of the mod this week, but it is still a very big mess, hopefully there are not many leaks with isolated nodes and stuff...

    • Like 1

    Share this post


    Link to post
    Share on other sites
  • Original Poster
  • Posted:
    Last Online:  
     

    Well, in the end I got a little bit impatient and released the mod without that functionality I was talking before. You can check it on steam workshop

    https://steamcommunity.com/sharedfiles/filedetails/?id=1625704117

    Unfortunately I don't have anyone to test it, but hopefully it won't break many saves :lol: For now it computes the intersection point as if the segment was straight. I plan to add the functionality to compute exact intersection as well as things like elliptical roundabouts. I feel a bit dumb for asking this question because with this line of code it is exactly as if you actually wrote that mod for me, but how I then turn the Bezier2 back into an segment? It seems to me that all methods require direction vectors, which I don't have. In the bezier2 I found this method:

    public static Vector2 Tangent(Vector2 a, Vector2 b, Vector2 c, Vector2 d, float t)

    Is that it? Are the Tangents the direction vectors?

    Ok, one of the next problems is when I was iterating over all segments adjacent to a node. Something like this:

    for (int i = 0; i < MAX_SEGMENTS_PER_NODE; i++)
    {
    	ushort segment = netNode.GetSegment(i);
    }

    What is the magical number MAX_SEGMENTS_PER_NODE? I have no idea. I put there some arbitrary number (12).

    And then I had problems with Unity GUI, the GUILayout.Toggle just wouldn't work, after one hour of trying I replaced it with a simple button which changes its label when you click on it. And a lot of other things...

    Anyway, it seems to me that I am all over the place and it doesn't make much sense what I am writing about.

    • Like 1

    Share this post


    Link to post
    Share on other sites
    Posted:
    Last Online:  
     

    Before I begin, are you using ILSpy? If so, are you aware of the Analyze feature? Right click on any method, property, or field you're not sure about and it should bring you back to its declaration.

    (I just realized that I responded to this post backwards, sorry :) )

    4. UI is honestly a pain in the rear and I always have had at least one issue with it for both of my current mods. I'd suggest using ModTools to get field values of UI that you want to "copy", and since you mentioned boformer's tutorials I'd suggest looking at SamsamTS' UIUtils that is mentioned briefly in Tutorial 4 to get a better idea of the inner workings of the stuff. I'm not really sure how the Unity GUI specifically works with this game, though-- I've always found ColossalFramework.UI to differ from generic UnityUI in very subtle and annoying ways.

    3. MAX_SEGMENTS_PER_NODE is 8, although netNode.GetSegment() with a higher number should return 0 anyway, so you're fine to keep it as 12 if you don't feel like updating it, since you're already doing a nullcheck.

    2. Lol, I'm happy to help wherever I can. As for the tangent function, I haven't personally tried it out, but the first overload:

    public Vector2 Tangent(float t)

    at t=0f should give you the first of the two directional vectors. Beziers are basically just a graph of a parametric curve function with respect to time on the interval 0 to 1, so I'd make an educated guess and say that the same function at t=1f should give you the second directional vector.

    If that doesn't give you the correct directional vectors, try instantiating new vectors based on the control points of the Bezier curves (so one vector from Bezier.a to Bezier.b and the other from Bezier.d to Bezier.c) and using those as directional vectors.

    The vectors may or may not need to be normalized as well. (I honestly have no idea.)

    Otherwise, I have no idea, sorry :(

    1.Awesome, I'm going to use that a ton! Have you considered adding the ability to change what road is used, like a dropdown or something?

    • Thanks 1

    Hello! Salut! Привет! | My Workshop (follow me? :]) • My Github • My Twitter

     

    Share this post


    Link to post
    Share on other sites
  • Original Poster
  • Posted:
    Last Online:  
     

    I am using ILSpy, but I still don't have much experience with it. I looked at the Tangent method and saw some "math" and wasn't sure what is it doing. The best thing would be to stop talking and test it in game, which I hopefully will do in the following days. Anyway, with all this I think I will be able to implement it.

    I am really happy that you like my mod! Concerning the ability to change the type of the road, I would like to add it at some point, but for now you can very easily upgrade it after the roundabout is built.

    • Like 1

    Share this post


    Link to post
    Share on other sites
  • Original Poster
  • Posted:
    Last Online:  
     

    @Elektrix I've just released an update implementing the piece of code you gave me week ago.

    It took me way too long to debug the new code and overall the mod seems now less stable, although I resolved most of the issues. Please let me know if you see any difference to better or worse. :)

    Share this post


    Link to post
    Share on other sites
    Posted:
    Last Online:  
     

    All right, cool! I'm still really enjoying using the mod, and the elliptical roundabouts are a nice touch! :) 

    I'm currently testing the new version out on a savegame, here are some things that I noticed:

    1. Easy to fix: Decimal +/- (On the digit row on top of the keyboard) do not increase the radius of the circle but the numpad (far right) +/- do.
    2. If the window is open over a node when you click on one of the roundabout types (or anything else for that matter), the node under the window is selected whether you like it or not. This can be fixed by restricting what mouse positions are open to raytracing. If the mouse is over the UI window, simply don't allow the tool to be used.
    3. One can select pedestrian path nodes even though roundabouts don't work properly on them.
    4. Pressing "back" on Step 2/3 of the elliptic roundabout generator goes back to the very beginning, not to the previous step, and there's no clear way to return to the previous step.
    5. Easy to fix: The window does not disappear when you enter cinematic camera mode. Parenting the window to something that does disappear should resolve the issue.
    6. If the radii on the ellipse are equal to each other, then normal circle mode should be used (if that's not being done already).
    7. In my opinion, holding a modifier key while pressing +/- should allow you to change the major/minor radii of the ellipse instead of increasing both at once. (Not really a bug report, but something I wished I had while using the mod)
    • Thanks 1

    Hello! Salut! Привет! | My Workshop (follow me? :]) • My Github • My Twitter

     

    Share this post


    Link to post
    Share on other sites
  • Original Poster
  • Posted:
    Last Online:  
     

    Thank you :)

    1. Well, it was intended to work only with keys on numpad, but I can add support for the keys on main keyboard as well.

    2. Good catch, I will look at that. With this you can actually build a roundabout where you don't want to.

    3. For now it is the user's problem. Of course in the final version (which is definitely not coming soon) this shouldn't be.

    4. I know about this. Overall, I am not too happy with the ellipse UI as it is not very intuitive. It is a provisional solution.

    5. May look at that. I am not sure how parenting works when standard unity windows are combined with the game UI.

    6. That's how it works already. (sort of)

    7. Very good idea.

    Anyway, my much bigger concerns regard bugs that can potentially break savegames. When you start doing crazy things with the mod, like building many tiny roundabouts on top of each other, you can cause resource leakage like phantom unreleased nodes and roads that lead to nowhere glitching through the map. I tried to prevent this as much as I could, but nonetheless, after enough time I ended up with NullPointerExceptions and other very unpleasant stuff. I am not aware how much can bugs like this accumulate in the savegame as a timed bomb. Of course, when you are using the mod in the manner you should then this is not (hopefully!) a big threat, but sometimes it is not the user's fault - in some cases the constellation of the nodes and segments is the sole cause. I think that people wouldn't be very happy when after a week the game suddenly just didn't load. I dread to think about that. So, if you encountered something suspicious, please let me know :D

    • Like 1

    Share this post


    Link to post
    Share on other sites

    Sign In or register to comment...

    To comment in reply, you must be a community member

    Sign In  

    Already have an account? Sign in here.

    Sign In Now

    Create an Account  

    Sign up to join our friendly community. It's easy!  

    Register a New Account


    ×

    Thank You for the Continued Support!

    Simtropolis depends on donations to fund site maintenance costs.
    Without your support, we just would not be in our 24th year online!  You really help make this a great community. *:thumb:

    But we still need your support to stay online. If you're able to, please consider a donation to help us stay up and running. This helps sustain a platform where we can share our community creations for years to come.

    Make a Donation, Get a Gift!

    Expand your city with the best from the Simtropolis Exchange.
    Make a Donation and get one or all three discs today!

    STEX Collections

    By way of a "Thank You" gift, we'd like to send you our STEX Collector's DVD. It's some of the best buildings, lots, maps and mods collected for you over the years. Check out the STEX Collections for more info.

    Each donation helps keep Simtropolis online, open and free!

    Thank you for reading and enjoy the site!

    More About STEX Collections