Cities: Skylines

Cities: Skylines

Loading Screen Mod
Strad 14 Apr, 2019 @ 8:29am
OnAssetLoaded is not called
Your mod breaks the IAssetDataExtension interface, which then cannot be used by other mods.
github issue page[github.com]
< >
Showing 1-11 of 11 comments
thale5  [developer] 24 Apr, 2019 @ 1:41am 
@Strad The interface is supported. I just tested with one of my test assets and all three callbacks (OnCreated, OnAssetLoaded, OnReleased) were called.

Did you enable both the asset and the mod extension in Content Manager?

It is useful to know that the Asset Data API is unfortunately broken. Please see my bug report here:

https://forum.paradoxplaza.com/forum/index.php?threads/cities-skylines-steam-bugs-in-the-asset-data-api.1101710/

Especially the OnAssetSaved problem is a serious one. I am already seeing many assets on the workshop that contain UserAssetData although the asset author does not know anything about it. It is literally like a virus that is spreading inside the game.

So, if you publish something with the Asset Data API, you should ensure that your OnAssetLoaded runs fast because the base game will call it many times. My mod fixes that bug and calls it just once. But my mod does not fix OnAssetSaved.
Last edited by thale5; 24 Apr, 2019 @ 1:45am
Strad 24 Apr, 2019 @ 2:00am 
Hi, thanks for the answer. I gave it another quick test now I still have the same problem.
I open the game, open the DNSpy debugger and create a breakpoint on the first line of OnAssetLoaded method in my mod. If I load a game without LSM enabled, everything runs fine. The method is called once for every asset. If I run it with LSM, the breakpoint is never hit.
I will check that link you gave me. In short, what are the risks of incorrect usage of the userData?

There is the pull for the TMPE which I am working on and where I encounter the bug - https://github.com/krzychu124/Cities-Skylines-Traffic-Manager-President-Edition/pull/288

If you have time we can try to solve it over skype/discord or whatever.
Strad 24 Apr, 2019 @ 9:53am 
So I checked the vanilla loading code and found nothing suspicious. I don't know what is wrong about the fact that there is a loop that invokes all OnAssetLoaded methods in all mods? How would you choose the single mod that should be called?
Compare that to the ILoadingExtension. It wouldn't make sense if the OnLevelLoaded(...) method was called for a single mod.
When the asset is saved the same thing happens - all mods that extend the IAssetDataExtension are called. Each mod can pass its dictionary with userData, but watch out, these dictionaries are merged into single one in the AssetDataWrapper.AddData(Dictionary<string, byte[]> data) method! So then when the asset is loaded all the mods receive the same dictionary which contains all the data.
By the way, I made a quick scan of the LSM mod, but I didn't find the place in the code where you invoke the OnAssetLoaded methods? (Maybe you use reflection or call some higher level methods instead)
In any case, maybe I understand it wrong.
thale5  [developer] 24 Apr, 2019 @ 11:33pm 
"How would you choose the single mod that should be called?" : LSM matches assets and IAssetDataExtensions by directory path. So you need to put the asset and the IAssetDataExtension in the same directory and publish them in the same workshop item.

"I didn't find the place in the code where you invoke OnAssetLoaded" : AssetLoader.cs.

"In short, what are the risks of incorrect usage of the userData" : The problem is not incorrect usage. The problem is the serious bug in the base game that has not been fixed.
thale5  [developer] 24 Apr, 2019 @ 11:40pm 
Here's an example that describes the bugs in the base game.

I have created three test assets, each published with an IAssetDataExtension.

With LSM enabled, each OnAssetLoaded is invoked once, with the correct userData as argument.

Without LSM, each OnAssetLoaded is invoked three times, for all combinations of userData. So there are a total of 3*3=9 invocations. You can see where this leads with a large number of userDatas.

Because of the save bug I explained in my forum post, there are already many orphan userDatas in workshop assets.

Let's assume your asset with an IAssetDataExtension becomes very popular so that everyone subscribes to it. Because of the save bug, eventually all new and updated assets on the workshop will contain your userData, plus userDatas from other popular IAssetDataExtensions. That's crazy.
Last edited by thale5; 24 Apr, 2019 @ 11:46pm
Strad 25 Apr, 2019 @ 1:27am 
For me it makes perfect sense that OnAssetLoaded is invoked n * m times. Each mod is responsible for something else. For example, one could load road signs, the other could set up the animations, some other apply custom textures. Even if you had 200 assets and 10 mods this would barely take 2 seconds, unless thete is an error in some of the mods (which could be anywhere else anyway).
It doesn't make any sense to ship the IAssetDataExt with every asset, when they are all the same. Imagine you have 10 mods, each of them them needs to be copied to every asset. Isn't this the bloating you are afraid of? This is even worse because you have to load extra files, which greatly reduces performance. All this userData thing was made so that you didn't have to load no extra files. This completly turns it around.
I think you understood it wrong. What alternative do I have now when I want to save data with assets than to save and load them from extra files which takes x times longer? (As for example RICO mod does)
There still could be the save bug you were talking about, could you be then more concrete and name the classes and methods which are responsible for it?
liang.ang11122 25 Apr, 2019 @ 10:10pm 
tem.NullReferenceException: Object reference not set to an instance of an object
at PloppableRICO.PloppableCommercial.GetConstructionCost () [0x00000] in <filename unknown>:0
at BuildingAI.GetLocalizedTooltip () [0x00000] in <filename unknown>:0
at PrefabInfo.GetLocalizedTooltip () [0x00000] in <filename unknown>:0
at RealTime.Simulation.Statistics.RefreshBuildingsButtons () [0x00000] in <filename unknown>:0
at RealTime.Simulation.Statistics.RefreshUI () [0x00000] in <filename unknown>:0
at RealTime.Simulation.Statistics.RefreshUnits () [0x00000] in <filename unknown>:0
at RealTime.Core.RealTimeCore.Run (SkyTools.Configuration.ConfigurationProvider`1 configProvider, System.String rootPath, ILocalizationProvider localizationProvider, Boolean setDefaultTime, RealTime.Core.Compatibility compatibility) [0x00000] in <filename unknown>:0
at RealTime.Core.RealTimeMod.OnLevelLoaded (LoadMode mode) [0x00000] in <filename unknown>:0
at LoadingWrapper.OnLevelLoaded (UpdateMode mode) [0x00000] in <filename unknown>:0
have any ppl know how to fix it?
thale5  [developer] 26 Apr, 2019 @ 12:00am 
@Strad I see your point and I always consider all viewpoints. The API has now been around for almost a year and the developers haven't changed it or commented on its specification. So it is not going to change. For compatibility, I better follow their lead.

Please don't assume userData will be good for performance. Asset deserialization is based on reflection. Most new assets now have userData, almost all of them are empty, yet they need to be decoded. This solution does not beat the RICO way.

The obvious bug in this API is the dictionary (with strings as keys) that collects data from all mods by iterating over them. There will be key collisions. The API does not warn against using simple keys such as "data". No developer would propose an API like that on purpose.
Strad 27 Apr, 2019 @ 3:02am 
Thank you. I think too that the best thing is to follow how it is by default. It is nice that you tried to improve the API, but unfortunately it isn't probable that many modders would use it, as in the end it doesn't make matters much easier (while it requires everybody to install the LSM).
About the strings as keys - I completely understand your point, but on the other hand the same thing happens when saving data to savegame files (which is there for years already). In my opinion developers made it on purpose, putting the responsibility on the shoulders of modders. You can think about it whatever you want, but I must admit that the game code is not of the prettiest things ever created - when I was working on the Smart Intersection Builder mod and had to deal with a method that had over 1100 lines I wasn't too happy either (NetTool.CreateNode). But this is a topic for another day. (And who am I to say anything about it?)
Finally, modders who would use simple keys as "data" wouldn't cause much harm to anyone else than themselves, would they? To inflict a significant damage to the integrity of the game itself would require a much greater blunder.
Gabrielium 28 Apr, 2019 @ 6:28pm 
I understand I am coming into this discussion rather late, but I think it's also important to note that there are very few mods that do/will actually use this functionality, so I very much doubt that the IAssetDataExtension interface exponentiation will occur, especially now that we're four years into this game's life. I'm using it for a mod I'm working on, but I can't think of any other mods that use it or will use it; the only reason I'm using it is to prevent asset creators from having to create/place extra xml configurations in the upload folder.

Either way I respect your decision on how you'll approach this, (of course I'd prefer if you could make it more closely resemble vanilla so that I don't have to do extra work :P) and I'm looking forward to future releases of LSM.
Strad 27 May, 2019 @ 12:23pm 
Thanks for the update :)
< >
Showing 1-11 of 11 comments
Per page: 1530 50