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

Personal TASK: Remove crosswalks from individual roads #1

Closed
12 tasks done
kianzarrin opened this issue Nov 30, 2019 · 38 comments
Closed
12 tasks done

Personal TASK: Remove crosswalks from individual roads #1

kianzarrin opened this issue Nov 30, 2019 · 38 comments

Comments

@kianzarrin
Copy link
Owner

kianzarrin commented Nov 30, 2019

TMPE removes cross walks functionally but not visually
NoCrosswalks removes all crosswalks. but does not have individual control.
NetworkSkins has individual control over road texture just not crosswalks.
It seems I should mix all these mods together.

Tasks:
Phase 1

  • practice flipping crosswalks on global basis
  • read pedestrianCrossing mod
  • read NetworkSkins mod
  • practice change color on a global basis
  • practice flipping road colors on a segment by segment basis using redirection framework.
  • read boformer's texture replacements
  • remove crosswalk textures using detours.
  • Read Road options mod
  • implement proof of concept: flipping crosswalks on a segment by segment basis.
  • hide crosswalks when camera is far away.
  • Discuss integration options
  • run tests and share mod

EDIT: I'd Phase 1 of this tasks is complete. See #1 (comment)
Phase 2: boformer/NetworkSkins#42

related:

CitiesSkylinesMods/TMPE#27
https://github.com/boformer/NetworkSkins/
CitiesSkylinesMods/TMPE#27 (comment)
CitiesSkylinesMods/TMPE#40

my current code is here https://github.com/kianzarrin/KianHoverTool/tree/toggle-crosswalks
repo : https://github.com/kianzarrin/HideTMPECrosswalks

@kianzarrin
Copy link
Owner Author

kianzarrin commented Nov 30, 2019

Don't know if NoCrosswalks mods has shared code. dnspy results in strange function names.

RenderTexture renderTexture = NoCrosswalks.\u200E\u202B\u202A\u200E\u202E\u206B\u206E\u206B\u206C\u202C\u206F\u206D\u202C\u202B\u206A\u200F\u202E\u202A\u200D\u202A\u202C\u200C\u200D\u202E\u206E\u206A\u200C\u200B\u202A\u202B\u206D\u202A\u202C\u206C\u202D\u200B\u202E\u200E\u206E\u206E\u202E(NoCrosswalks.\u202B\u202D\u206D\u202B\u202D\u200E\u206C\u202E\u202B\u202D\u206B\u202A\u200B\u206E\u200F\u200E\u202E\u202B\u202E\u206C\u206E\u200C\u202D\u206B\u202D\u206E\u200E\u200E\u202A\u200D\u200B\u202D\u202D\u206E\u206E\u206C\u200C\u200E\u202D\u200D\u202E(source), NoCrosswalks.\u202C\u200D\u200C\u200C\u202D\u200E\u202E\u202A\u200D\u202C\u202D\u200D\u206A\u206A\u200B\u206C\u206C\u202C\u200C\u206A\u200E\u206B\u206C\u202B\u202E\u202A\u206E\u200E\u202E\u206A\u200D\u202B\u206E\u206D\u200C\u200F\u200D\u200F\u206F\u206F\u202E(source), 0, 7, 1);

ILspy is no better but DotPeek can actually do it right

           renderTexture1 = NoCrosswalks.NoCrosswalks.\u200E‫‪‎‮‬‬‫‏‮‪‍‪‬‌‍‮‌​‪‫‪‬‭​‮‎‮(NoCrosswalks.NoCrosswalks.\u202B‭‫‭‎‮‫‭‪​‏‎‮‫‮‌‭‭‎‎‪‍​‭‭‌‎‭‍‮((Texture) source), NoCrosswalks.NoCrosswalks.\u202C‍‌‌‭‎‮‪‍‬‭‍​‬‌‎‫‮‪‎‮‍‫‌‏‍‏‮((Texture) source), 0, (RenderTextureFormat) 7, (RenderTextureReadWrite) 1);

Don't know why.

I wish to de-compile numbers to hexadecimal. don't know how?

@krzychu124
Copy link

Code of NoCrosswalks is obfuscated.
I would figure myself how it works instead of trying to read and understand this confused obfuscated code.
The code which adds crosswalks must be somewhere in Assembly-CSharp.dll

@originalfoo
Copy link

These mods remove crosswalks:

@originalfoo
Copy link

Random guess: NetSegment.Flags.CrossingStart and NetSegment.Flags.CrossingEnd

Start and End both refer to ends of a segment based on the direction the segment was drawn in.

@krzychu124
Copy link

Remove Road Textures

The same author as NoCrosswalks you can skip checking - obfuscated

@kianzarrin
Copy link
Owner Author

@krzychu124 I would figure myself how it works instead of trying to read and understand this confused obfuscated code.

Wow! obfuscation is a thing! I probably can use a c# debosfusicator but I am concerned about moral implication of that.

Why do people obfuscate free code anyway? Maybe I can ask the author for help?

@krzychu124
Copy link

krzychu124 commented Nov 30, 2019

Maybe they want to hide something or just want to be the only author of the mod, so other people cannot use it to make it better or share as own code.

@kianzarrin
Copy link
Owner Author

After reading some code I am starting to think this tasks is beyond me. I have never dealt with detours before. I have no experience in mesh and textures either. So don't hold your breaths for me.

I need to learn each of this concept separately one step at a time. I am considering to accept easier issues that require such skills to ease up the learning curve.

@originalfoo
Copy link

originalfoo commented Dec 1, 2019

Cgameworld Today at 04:46
This script by boformer shows how to do network texture replacements:
https://gist.github.com/boformer/6524899363e97cedf45b

Road crosswalks are on the diffuse node texture so the second line in the script would need to be changed to something like this to read the node material
var nodeMaterial = PrefabCollection<NetInfo>.FindLoaded(networkName).m_nodes[0].m_nodeMaterial;

@originalfoo
Copy link

@kianzarrin try toggling the NetSegment.Flags.CrossingStart and NetSegment.Flags.CrossingEnd for a segment and see if that has any effect on crossings (I suspect there are additional checks done by the game, such as segment must be at a junction, but hopefully those two flags above would allow toggling of the crossing decal).

@kianzarrin
Copy link
Owner Author

Cgameworld @kian.zarrin If you flip the existing main and apr node textures vertically for most roads the crosswalks disappear
Working proof of concept: https://gist.github.com/Cgameworld/f22cfe649a222faf8226e1d65a0782e1

@originalfoo
Copy link

My general thoughts are that if it's not possible to remove crosswalks on segment by segment basis, remove them all and then have a way to add (non-distorted!) crosswalk decals where necessary (but also allow for invisible crossings too - eg. on dirt roads).

With decals, if you get them at the right height, they won't overlap pavements. Or we could potentially examine the segment mesh and work out where the road surface is vs. pavement, and crop decals to fit, taking in to account things like medians, etc.

@kianzarrin
Copy link
Owner Author

@aubergine10 My general thoughts are that if it's not possible to remove crosswalks on segment by segment basis, remove them all and then have a way to add (non-distorted!) crosswalk decals where necessary.

I think this can be managed in the same way Network skins manages everything. each road needs to have its own segmentData and detours will access the segmentData to check which texture to use.
I am considering the option of duplicating Netinfo info of the segment and then modifying it so that only one segment is influenced. But I think the detour option may be better memory-wise and serialization-wise.

I am hesitant to create my own detours. wouldn't that create incompatibility with Network skins? I think its best to have network skins to read TMPE or TMPE to use NetworkSkins API.

@kianzarrin
Copy link
Owner Author

@aubergine10 @kianzarrin try toggling the NetSegment.Flags.CrossingStart and NetSegment.Flags.CrossingEnd

according to https://cslmodding.info/asset/network/#flags

CrossingStart
Related to traffic light state. Also active for some "end" segments of cable car networks, canals, or decoration walls.
CrossingEnd
Related to traffic light state. Also active for some "end" segments of cable car networks, canals, or decoration walls.

In any case there is no harm in trying it out.

@kianzarrin
Copy link
Owner Author

I used modtools to check the crossing flags. They are not set at junctions.

@kianzarrin
Copy link
Owner Author

I am trying to " practice change color on a local basis". I patched GetColor but that was not enough to change the road colors. NetInfo.m_color is used in a few more places.

I tried to copy paste the parts of the network skins 2 code that changes color. but I failed to identify them

I even failed in installing harmony by copy pasting Netwrok Skins 2 implementation of ILoading interface.

I gave up on Harmony! I am going to use redirection framework.

@kianzarrin
Copy link
Owner Author

kianzarrin commented Dec 6, 2019

I wonder if I can duplicate netInfo. while i suspect this would be hard hacking the game code is going to be even harder. I will try to search where netInfo code is being initialized.

Some of the netinfo functions are virtual. In such cases I may be able to simply inherit netinfo instead of patching the code.

@kianzarrin
Copy link
Owner Author

kianzarrin commented Dec 6, 2019

I found this code that clones Netinfo. This is part of asset editor utilities:

// AssetEditorRoadUtils
using UnityEngine;

private static NetInfo Instantiate(NetInfo template)
{
    NetInfo netInfo = Object.Instantiate(template);
    netInfo.name = template.name;
    InstantiateLanes(netInfo);
    InstantiateSegments(netInfo);
    InstantiateNodes(netInfo);
    InstantiateModel(netInfo);
    netInfo.gameObject.SetActive(value: false);
    netInfo.gameObject.name = GetUniqueNetInfoName(netInfo.gameObject.name);
    netInfo.m_prefabInitialized = false;
    PrefabCollection<NetInfo>.InitializePrefabs("Custom Assets", netInfo, null);
    netInfo.CheckReferences();
    netInfo.RefreshLevelOfDetail();
    return netInfo;
}

although there are some complications.

TPB:
segments info are not assigned directly as a NetInfo field
if you look at the code its a property that fetches the prefab from the collection by index
so if the prefab is not in the collection it wont work.

This also creates some problems with saving and loading data.

I am thinking Maybe I should inherit Netinfo. then I can simply override its methods.

public class NetInfoExt: NetInfo { } 
something = (NetInfoExt)segment.info;

@kianzarrin
Copy link
Owner Author

Inheriting NetInfo is not beneficial since its NetManager methods that I need to override.

@kianzarrin
Copy link
Owner Author

I managed to make individual roads red by clicking on them. But I have a bit of problem with updating them (although I call UpdateSegment() and UpdateSegmentColor() ).

all these segments should be red but only the end segments get red:
Screenshot (144)

After building more roads segment colors get mostly updated.
Screenshot (147)

@kianzarrin
Copy link
Owner Author

fixed the refresh color issue by making rampant use of update functions :

            Refersh();
            Refersh(HoveredSegmentId);


        protected override void OnSecondaryMouseClicked() {
            throw new System.NotImplementedException();
        }

        public void Refersh(ushort segmentID) {
            Singleton<NetManager>.instance.UpdateSegmentColors(segmentID);
            netMan.UpdateSegment(segmentID);
            Segment(segmentID).UpdateSegment(segmentID);
        }

        public void Refersh() {
            Singleton<NetManager>.instance.UpdateSegmentColors();
            Singleton<NetManager>.instance.UpdateNodeColors();
        }

Screenshot (148)
I used redirection framework and copy pasted hole function code from decompiler to my detours.

@originalfoo
Copy link

Refersh - typo?

@kianzarrin
Copy link
Owner Author

kianzarrin commented Dec 8, 2019

lol! typo in a test code.

I played with the flipping algorithm a bit. The junctions look nicer if you flip "_MainTex" but not "_APRMap".

Flip(nodeMaterial, "_MainTex");
//Flip(nodeMaterial, "_APRMap"); // looks nicer when commented out.

Now I have created detour of NetNode.RenderInstance() and trying to hide crossings only on junctions where my tool has disabled crossings visuals.

private static Material FixMaterial(ushort nodeID, ushort segmentID, NetInfo.Node node) {
    NetNode thisNode = Node(nodeID);
    var info = thisNode.Info;
    var ai = info.m_netAI;
    Material material = node.m_nodeMaterial;
    if (!(ai is RoadAI)) { // or RoadBaseAI ?
        return material;
    }
    // TODO: complete code
    return material;
}

@kianzarrin
Copy link
Owner Author

kianzarrin commented Dec 8, 2019

I manged to hide cross walks on individual basis. right now I flip node textures to hide crosswalks:

        public static Hashtable NodeMaterialTable = new Hashtable(100); // table of flipped node textures

        public static Material HideCrossing(NetInfo.Node node) {
            if (NodeMaterialTable.Contains(node)) {
                return (Material)NodeMaterialTable[node];
            }

            Material material = new Material(node.m_nodeMaterial);
            TextureUtils.Flip(material, "_MainTex");
            NodeMaterialTable[node] = material;
            return material;
        }

        private static Material FixMaterial(ushort nodeID, ushort segmentID, NetInfo.Node node) {
            Material ret = node.m_nodeMaterial;
            //return ret // performance

            if (Node(nodeID).Info.m_netAI is RoadAI && HasCrossingBan(segmentID, nodeID)) {
                ret = HideCrossing(node);
            }

            return ret;

            //MaterialPropertyBlock block = netMan.m_materialBlock;//TODO investigate
            // TODO 2: mess around with NetSegment.RenderLod(cameraInfo, combinedLod); for far distance
        }

Screenshot (149)

It still does not work with far away textures. I think I need to fix NetSegment.RenderLod(cameraInfo, combinedLod) to solve this problem.

Also I think I will not need to flip textures if I utilize MaterialPropertyBlock.

@kianzarrin
Copy link
Owner Author

@boformer @aubergine18 @krzychu124 @kvakvs I would like to discuss integration of this hide crosswalk feature.

Which one of these requirements do we want?
A- Users of Network skins should be able to hide cross walks if they choose to.
B- TMPE should be able to hide cross walks when crossing is banned.

Issue 1:
If we are going with both A and B then what should we do if the user hides cross walks in network skin mod but TMPE wants to show the cross walk? I think we should hide cross walk if at least one mod requires it to be hidden.

Issue 2:
Where should we put the code? should it be in NS2 and TMPE can hide cross walks only if NS2 is installed? should TMPE have its own version? should it be on a third party mod?

Issue 3:
How are we going to handle mod compatibility?

@originalfoo
Copy link

So, I think about this as use cases rather than mods:

  1. User wants to hide crosswalks, but crossing remains
  2. User wants to disable crossing, and that should also hide crosswalk

For scenario 1, there are already numerous mods that allow users to remove crosswalk textures, and there are other methods such as using ploppable asphalt+.

For scenario 2, the pathfinder needs to know - so that's very much TM:PE territory (everything is already set up, the only thing missing is toggling the crossing decals to visually reflect the junction settings).

@kianzarrin
Copy link
Owner Author

@aubergine10

there are already numerous mods that allow users to remove crosswalk textures

Yes but they do it on a global basis rather than individual basis.

a nd there are other methods such as using ploppable asphalt+.

ploppable asphalt+ is manually painting on the road which is a bit time consuming. much better to do it in Network skins. That said I am not sure if there is any use case. If banning crossings by TMPE hides cross walks, then I doubt if people would like to hide cross walks on individual basis for any other reason.

In any case should the functionality to hide crosswalks be implemented in TMPE mod? CurrentlyTMPE only changes functionality not textures. If we do this it would be the first time TMPE influnces textures. Also I am a bit worried in terms of compatibility with other mods since I have took a detour of NetNode.RenderInstance().

@kianzarrin
Copy link
Owner Author

@aubergine10 I want to draw your attension to this comment:

@boformer has indicated he might have a way to remove the crossing decals per segment. He's working on a new version of Network Skins. IMO we should collaborate as we can already achieve removal of the 'path' part of it but not the visual, and network skins will be the opposite - removing visual but not path.

@kianzarrin
Copy link
Owner Author

kianzarrin commented Dec 10, 2019

I have been investigating this LOD issue for a some time and playing around with things. Its really confusing. I do not fully understand what is going on.

So far I think this is whats going on:

  • camera is close: NetNode.RenderInstance() passes Node.m_materialtoDrawMesh()`
  • camera is far : NetNode.RenderInstance() passes Node.m_combinedLod to NetNod.RenderLod() which in turn calls DrawMesh()
  • camera is very far away: Some other part of the code unknown to me is responsible for rendering because I commented out NetNode.RenderInstance() and RenderLod() and everything was still being rendered. ( for close and far camera distance nodes where not being rendered but for very far camera distances everything was being rendered.)

So far I am manged to hide crossing when camera is close and far. But I failed to do anything about when the camera is really far.

Even the Road Options mod fails to hide the road crossings when the camera is very far away.

I have been trying to comment out parts of the code to see which function is responsible for rendering what.

  • I have got my eyes on two functions: NetNode.RenderLod() and NetNode.RenderInstance() as they are the only two functions that pass node.m_material or node.m_combinedLod to DrawMesh().
  • I did not bother with Netsegment.RenderLod() and NetSegment.RenderInstance() because they do not access node.m_material or node.m_combinedLod.
  • there is also NotificationEvent.RenderInstance() which calls instance.m_bufferedItems.Add(item); but I don't know what that does.
  • NetManager.EndRenderingImpl() also passes Node.m_combinedLod to NetNode.RenderLod() so I figured commenting out NetNode.RenderLod() should handle this case too.

There is a difference between commenting out the all of NetNode.RenderLod() and NetNode.RenderInstance() or only commenting out calls to DrawMesh() . It seems that modifications made to data objects are used later on some where else (unknown to me) )in the rendering process.

@kianzarrin
Copy link
Owner Author

snapshots :
screenshot 1: Camera is closed. I can hide crossing
screenshot 2: camera is far. crossing textures come back.
screenshot 3: camera is far. by some furthure modifications to the code, I can still hide crossings.
screenshot 4: camera is VERY far. I have no idea whats going on and how to fix this.
Screenshot (153)
Screenshot (154)
Screenshot (160)
Screenshot (158)

@kianzarrin
Copy link
Owner Author

Screenshot (152)
Screenshot (151)

@krzychu124
Copy link

krzychu124 commented Dec 10, 2019

there is also NotificationEvent.RenderInstance() which calls instance.m_bufferedItems.Add(item); but I don't know what that does.

It's layer for rendering animated icons. On screenshot above you can see one at the end of unfinished highway (dead end).

[Edit]
There are multiple lod values so Node.m_combinedLod has got multiple textures for node of different resolutions

@originalfoo
Copy link

originalfoo commented Dec 10, 2019

Read following guide by author of Loading Screen Mod about how the LOD atlas works. While it's more for asset creators, it will give you better idea of how things are fitting together in the game engine. https://steamcommunity.com/workshop/filedetails/discussion/667342976/1636416951459546732/

Notably, the game can share LOD textures between different assets (roads) if the use same material. So I suspect the "very far" issue is going to be difficult to tackle because if you alter a texture in a material it will affect all roads using that material (maybe?).

There might be some way to change the LOD distance for customised nodes? Although that might have some slight performance impact (hopefully nothing too bad). Effectively at the 'very far' range, find some way to convince those nodes (or the camera rendering them) that they are closer to camera so it uses the more normal LOD or whatever?

@kianzarrin
Copy link
Owner Author

@aubergine10
Notably, the game can share LOD textures between different assets (roads) if the use same material. So I suspect the "very far" issue is going to be difficult to tackle because if you alter a texture in a material it will affect all roads using that material (maybe?).

I don't actually change the material but rather I take a copy of it and store it in a hash-table of cleared materials: Material newMaterial = ClearMaterialTable[oldMaterial].

@aubergine10

Although that might have some slight performance impact (hopefully nothing too bad). Effectively at the 'very far' range, find some way to convince those nodes (or the camera rendering them) that they are closer to camera so it uses the more normal LOD or whatever?

convincing the camera that I am closer than I really am is exactly what I do for now. But only for the cases where the crosswalks are removed. so that does not cause too much performance issue. the convincing approach does not work with when camera is very far away.

@kianzarrin kianzarrin changed the title TASK: Remove crosswalks from individual roads Personal TASK: Remove crosswalks from individual roads Dec 10, 2019
@kianzarrin
Copy link
Owner Author

The screen shots bellow demonstrate that texture flipping works with all roads. including vanilla, Network extension 2, and other custom roads. The crossings can be hidden when camera is close or far but not when it is very far which is as good as the road options mod (and better than all others I could find) except I can do it to individual segment ends. I do not see the need for storing no crossing textures in png files in phase 1.

Screenshot (175)
Screenshot (173)
Screenshot (172)
Screenshot (171)
Screenshot (170)
Screenshot (169)
Screenshot (168)

@originalfoo
Copy link

Looking really good!

IMO even with the very far LODs still showing crossings, it's still a major improvement over what we currently have.

@kianzarrin
Copy link
Owner Author

Its DONE!
Screenshot (178)

@kianzarrin
Copy link
Owner Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants