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

Call stack grows to enormous sizes and crashes the game #17

Closed
CptMoore opened this issue Jul 30, 2018 · 3 comments
Closed

Call stack grows to enormous sizes and crashes the game #17

CptMoore opened this issue Jul 30, 2018 · 3 comments
Labels
HBS Ready This issue is ready for HBS Review Sev 3 Problems that break a MODDED game in ANY WAY

Comments

@CptMoore
Copy link

Describe the problem

There seems to be another issue that closes/crashes the game immediately on games with lots of components.

The call stack count can grow to enormous numbers, this happens because components that are finished loading directly call other components OnLoaded callbacks, which again directly call other components.

The problem here is two fold

  1. many of the components with dependencies subscribe to a generic callback
dataManager.MessageCenter.AddSubscriber(MessageCenterMessageType.DataManagerRequestCompleteMessage, new ReceiveMessageCenterMessage(this.CheckDependenciesAfterLoad));
  1. components, once all dependencies are loaded, call the following directly
this.dataManager.MessageCenter.PublishMessage(new DataManagerRequestCompleteMessage<T>(this.resourceType, this.resourceId, this.GetResource()));

This can produce a cascade effect with lots of callers.

e.g. if a SVG is finally loaded, a weapondef could finally met its dependencies and is finished loaded. then the onloaded method is called which again finds another weapondefs dependency check to call.
so a trace like
SVGAsset loaded -> WeaponDef complete -> WeaponDef complete ... can come about.

It can then even continue after ~4500 stack frames with a MechDef.Refresh call (at which point I wasn't logging anymore).

Provide an example of the code where the problem occurs

Part of a stack trace (just some lines, these can easily grow to the thousands of stack frames for a single call)

   at MessageCenter.SendMessagesForType(MessageCenterMessageType messageType, .MessageCenterMessage message)
   at MessageCenter.PublishMessage(.MessageCenterMessage message)
   at BattleTech.Data.DataManager+ResourceLoadRequest`1.NotifyLoadComplete()
   at BattleTech.Data.DataManager+WeaponDefLoadRequest.OnLoaded()
   at BattleTech.MechComponentDef.CheckDependenciesAfterLoad(.MessageCenterMessage message)
   at BattleTech.WeaponDef.CheckDependenciesAfterLoad(.MessageCenterMessage message)
   at MessageCenter.SendMessagesForType(MessageCenterMessageType messageType, .MessageCenterMessage message)
   at MessageCenter.PublishMessage(.MessageCenterMessage message)
   at BattleTech.Data.DataManager+ResourceLoadRequest`1.NotifyLoadComplete()
   at BattleTech.Data.DataManager+WeaponDefLoadRequest.OnLoaded()
   at BattleTech.MechComponentDef.CheckDependenciesAfterLoad(.MessageCenterMessage message)
   at BattleTech.WeaponDef.CheckDependenciesAfterLoad(.MessageCenterMessage message)
   at MessageCenter.SendMessagesForType(MessageCenterMessageType messageType, .MessageCenterMessage message)
   at MessageCenter.PublishMessage(.MessageCenterMessage message)
   at BattleTech.Data.DataManager+ResourceLoadRequest`1.NotifyLoadComplete()
   at BattleTech.Data.DataManager+WeaponDefLoadRequest.OnLoaded()
   at BattleTech.MechComponentDef.CheckDependenciesAfterLoad(.MessageCenterMessage message)
   at BattleTech.WeaponDef.CheckDependenciesAfterLoad(.MessageCenterMessage message)
   at MessageCenter.SendMessagesForType(MessageCenterMessageType messageType, .MessageCenterMessage message)
   at MessageCenter.PublishMessage(.MessageCenterMessage message)
   at BattleTech.Data.DataManager+ResourceLoadRequest`1.NotifyLoadComplete()
   at BattleTech.Data.DataManager+SVGAssetLoadRequest.OnLoaded()
   at BattleTech.Data.DataManager+SVGAssetLoadRequest.AssetLoaded(SVGImporter.SVGAsset resource)
   at BattleTech.Data.DataManager+GenericResourceRequestHelper`1[[SVGImporter.SVGAsset, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].Complete()
   at BattleTech.Data.DataManager.Update(Single deltaTime)
   at BattleTech.GameInstance.Update(Single deltaTime)
   at BattleTech.UnityGameInstance.Update()

Provide an example of your proposed solution

Seems to be a fundamental issue, instead of directly calling the completion, one would need to queue the notification and then only the top-most caller of the in the call stack should do some kind of iteration. Well you know the issue with recursion vs iteration.

Leave any additional comments here

smaller call stack example:
weapondef_loop_sample.txt

larger call stack example:
mechdef_loop_sample.txt

@Morphyum Morphyum added Sev 3 Problems that break a MODDED game in ANY WAY HBS Ready This issue is ready for HBS Review labels Jul 30, 2018
@Sheep-y
Copy link

Sheep-y commented Aug 1, 2018

For now I did a quick hack by capturing and managing mechdef dependencies at the data manager level. It works quite well and can really trim the stack. A more generic version can potentially be done for all ResourceLoadRequest which will make more sense.

https://github.com/Sheep-y/BattleTech_Turbine/

@caardappel-hbs
Copy link
Collaborator

A fix for this has been submitted for the next patch.

@Morphyum
Copy link
Collaborator

Closed because HBS aknowledged and fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
HBS Ready This issue is ready for HBS Review Sev 3 Problems that break a MODDED game in ANY WAY
Projects
None yet
Development

No branches or pull requests

4 participants