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

Clean up Loading extension CustomPathManager #730

Closed
kianzarrin opened this issue Feb 23, 2020 · 5 comments · Fixed by #1072
Closed

Clean up Loading extension CustomPathManager #730

kianzarrin opened this issue Feb 23, 2020 · 5 comments · Fixed by #1072
Labels
code cleanup Refactor code, remove old code, improve maintainability low priority Issue with low priority of work technical Tasks that need to be performed in order to improve quality and maintainability
Milestone

Comments

@kianzarrin
Copy link
Collaborator

kianzarrin commented Feb 23, 2020

There is some untidy code in loading extension that looks like legacy code which no one has bothered to clean up. The code for Custom Path manger has the following problems:


The value assigned to CustomPathManager in OnCreated() is never used. Its overwritten in loading extension. CustomPathManager is unlike other managers and cannot be instantiated in OnCreated(). This line is redundant and should be deleted:

CustomPathManager = new CustomPathManager();

CustomPathManager = new CustomPathManager();


Considering that the Loading extension holds a reference to an Instance of CustomPathManager, accessing the static _Instance field is unnecessary:

CustomPathManager._instance.WaitForAllPaths();

Use This property instead:
public static CustomPathManager CustomPathManager { get; set; }


CustomPathManager needs OnLevelLoaded() and OnLevelUnLoading(). The following code in loading extension needs to go into these new functions:

@kianzarrin kianzarrin added low priority Issue with low priority of work triage Awaiting issue categorisation code cleanup Refactor code, remove old code, improve maintainability labels Feb 23, 2020
@kianzarrin
Copy link
Collaborator Author

Also This line should throw an exception for consistency reasons (don't worry ... its in a try..,catch block):

Log.Error("CustomPathManager null. Error creating it.");

The code for CustomPathManager OnLevelLoaded() and OnLevelUnLoading() could be like this:

       static private FastList<ISimulationManager> GetSimManager =>
            typeof(SimulationManager).GetField("m_managers", BindingFlags.Static | BindingFlags.NonPublic)
                ?.GetValue(null) as FastList<ISimulationManager>;

        public void OnLevelUnloading() {
            Log.Info("CustomPathManager.OnLevelUnloading()");
            // TODO [issue does not exit] uncomment for more clean code and to support ingame unload
            // Custom path manger is destroyed when reloading. That is why the following code is commented out.
            //GetSimManager?.Remove(this);
            //Object.Destroy(this);
            _instance = null;
        }

        static public CustomPathManager OnLevelLoaded() {
            Log.Info("CustomPathManager.OnLevelLoaded() called. Setting up CustomPathManager and SimManager.");
            FieldInfo pathManagerInstance = typeof(Singleton<PathManager>).GetField(
                "sInstance",
                BindingFlags.Static | BindingFlags.NonPublic);
            if (pathManagerInstance == null) {
                throw new Exception("pathManagerInstance is null");
            }

            PathManager stockPathManager = PathManager.instance;
            if (stockPathManager == null) {
                throw new Exception("stockPathManager is null");
            }

            Log._Debug($"Got stock PathManager instance {stockPathManager?.GetName()}");
            // TODO [issue does not exist] restore vanila custom path manager for cleaner code and to support in-game unload 
            _instance = stockPathManager.gameObject.AddComponent<CustomPathManager>();
            Log._Debug("Added CustomPathManager to gameObject List");

            if (_instance == null) {
                throw new Exception("CustomPathManager is null. Error creating it.");
            }

            _instance.UpdateWithPathManagerValues(stockPathManager);
            Log._Debug("UpdateWithPathManagerValues success");

            pathManagerInstance.SetValue(null, _instance);

            Log._Debug("Getting Current SimulationManager");
            var simManager = GetSimManager;
            if (simManager == null) {
                throw new Exception("simManager is null");
            }

            Log._Debug("Removing Stock PathManager");
            simManager.Remove(stockPathManager);

            Log._Debug("Adding Custom PathManager");
            simManager.Add(_instance);

            UnityEngine.Object.Destroy(stockPathManager, 10f);

            Log._Debug("Should be custom: " + Singleton<PathManager>.instance.GetType());

            return _instance;
        }

Then in the loading extension OnLevelLoading():

            try {
                // CustomPathManager must be created while teh level is loading.
                CustomPathManager = CustomPathManager.OnLevelLoaded();
            }
            catch (Exception ex) {
                string error = "Traffic Manager: President Edition failed to load. You can continue " +
                               "playing but it's NOT recommended. Traffic Manager will not work as expected.";
                Log.Error(error);
                Log.Error($"Path manager replacement error: {ex}");

                Singleton<SimulationManager>.instance.m_ThreadingWrapper.QueueMainThread(
                    () => {
                        UIView.library
                              .ShowModal<ExceptionPanel>("ExceptionPanel")
                              .SetMessage(
                            "TM:PE failed to load",
                            error,
                            true);
                    });
            }

@originalfoo
Copy link
Member

Please send in a PR for this and #731 so we can test; it's always good to get the code cleaned up and improved.

@originalfoo originalfoo added technical Tasks that need to be performed in order to improve quality and maintainability and removed triage Awaiting issue categorisation labels Feb 23, 2020
@originalfoo originalfoo added this to the 11.2 milestone Feb 26, 2020
@kianzarrin
Copy link
Collaborator Author

kianzarrin commented Mar 1, 2020

@kian.zarrin Pathfinding object is leaking... I did maybe 4-6 hot-reloads of my second mod while

TM:PE was just enabled
Debug 1,999.0765170: Waking up CustomPathManager.
Debug 1,999.0863329: Creating 256 custom PathFind objects.
Info 1,999.0955972: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1054987: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1156799: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1258537: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1390482: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1506545: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1607004: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1709649: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1814978: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.1920980: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.2021296: Pathfinder logic: Using CustomPathFind_Current
Info 1,999.2125589: Pathfinder logic: Using CustomPathFind_Current

@krzychu124 are you using debug build? is it latest master branch?

@kianzarrin
Copy link
Collaborator Author

kian.zarrinToday at 13:02
@krzychu124 are you using debug build? is it latest master branch?
this might explain the game crashed due too many threads problem
krzychu124Today at 13:07
Full debug, but I am not hot-reloading tm:pe, that's the weirdest thing :)
kian.zarrinToday at 13:12
oh I see!
where is your second mod by the way?
if you have output.log it helps me to see if TMPE was reloaded.
krzychu124Today at 13:21
I think it doesn't matter what other mod you'll try hot-reload
kian.zarrinToday at 13:52
while TM:PE was just enabled
Ambiguine statement. does it mean TM:PE was simply enabled all along or TMPE was enabled at that moment?
krzychu124Today at 13:58
TMPE was enabled all the time, I haven't use it at that time.

I do not observe double hot reload of TrafficManager.dll when I hot reload my HideCrossings.dll
output_log.txt

That said, the traffic manager did load again (maybe after hot reload the serialize data extension is called again?)

Debug 470.5978783: HOT RELOAD ...

TMPE.log

@kianzarrin
Copy link
Collaborator Author

we need something like this:

            if (TrafficManagerMod.Instance.InGameHotReload && !LoadingExtension.IsGameLoaded) {

kianzarrin added a commit to kianzarrin/Cities-Skylines-Traffic-Manager-President-Edition that referenced this issue Mar 1, 2020
@originalfoo originalfoo modified the milestones: 11.2, 11.3 Mar 28, 2020
@originalfoo originalfoo modified the milestones: Planned stuff, 11.6.0 Jan 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
code cleanup Refactor code, remove old code, improve maintainability low priority Issue with low priority of work technical Tasks that need to be performed in order to improve quality and maintainability
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants