kianzarrin / myrepo

1 stars 0 forks source link

Personal TASK: Remove crosswalks from individual roads #1

Closed kianzarrin closed 4 years ago

kianzarrin commented 4 years ago

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

EDIT: I'd Phase 1 of this tasks is complete. See https://github.com/kianzarrin/myrepo/issues/1#issuecomment-564182354 Phase 2: https://github.com/boformer/NetworkSkins2/issues/42

related:


https://github.com/krzychu124/Cities-Skylines-Traffic-Manager-President-Edition/issues/27 https://github.com/boformer/NetworkSkins/ https://github.com/krzychu124/Cities-Skylines-Traffic-Manager-President-Edition/issues/27#issuecomment-478048558 https://github.com/krzychu124/Cities-Skylines-Traffic-Manager-President-Edition/issues/40

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

kianzarrin commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

These mods remove crosswalks:

originalfoo commented 4 years ago

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 commented 4 years ago

Remove Road Textures

The same author as NoCrosswalks you can skip checking - obfuscated

kianzarrin commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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

kianzarrin commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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

kianzarrin commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

Refersh - typo?

kianzarrin commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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:

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.

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 commented 4 years ago

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 commented 4 years ago

Screenshot (152) Screenshot (151)

krzychu124 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

Its DONE! Screenshot (178)

kianzarrin commented 4 years ago

posted to https://steamcommunity.com/sharedfiles/filedetails/?id=1934023593