Author Topic: Post Match Cleanup  (Read 8104 times)

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Post Match Cleanup
« on: June 26, 2017, 12:48:38 PM »
It seems TNet is geared more towards a MMO persistent type game, so I'm hoping to get some direction on how I might handle the cleanup of my 2D arena shooter game which has short 5 minute matches which load a new map and reloads fresh characters each match.

Does TNet have any built in functionality to automatically cleanup dynamically created network objects? Or do I need to keep track of those myself and call tno.DestroySelf() on those objects before I change scenes and load up a new match?

Just looking for some general guidance on best practices for a game that is creating / destroying player avatars frequently.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Post Match Cleanup
« Reply #1 on: June 26, 2017, 05:38:59 PM »
TNManager.LoadLevel(int channelID, string sceneName)
Will reset the channel to its initial state (all objects destroyed serverside) and force all clients to load the new scene.
Clientside, all objects will be destroyed by Unity upon scene load (except those marked with DontDestroyOnLoad).

Some issues you may face:
Problem: Clientside objects marked with DontDestroyOnLoad exist but have been destroyed serverside so any RFCs on them will fail.
Solution: Keep these objects in a separate channel. Or don't place RFCs on them.
Problem: My global GameManager isn't keeping state properly.
Solution: use Unity's SceneManager.sceneLoaded callback to handle state if necessary.

Note: only call TNManager.LoadLevel on the host.

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Post Match Cleanup
« Reply #2 on: June 28, 2017, 01:38:59 PM »
Thanks for the guidance.
I am noticing however that when my host calls TNManager.LoadLevel(1, "sceneName") that while this triggers all clients to load the level, that the network objects that have been created on the same channel are not being cleaned up. Is that for sure how TNManager.LoadLevel should act? It seems that I need to manually call tno.DestroySelf() on network objects that were dynamically created.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Post Match Cleanup
« Reply #3 on: June 28, 2017, 08:52:24 PM »
Try placing a Debug.Log in your Awake, Start, or OnEnable functions. I believe Unity will show the instantiation in the callstack. tno.DestroySelf isn't the solution in this case.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Post Match Cleanup
« Reply #4 on: July 03, 2017, 03:31:26 PM »
  1. private void Update()
  2. {
  3.         if (Input.GetKeyDown(KeyCode.G))
  4.         {
  5.                 TNManager.Instantiate(9, "Prefabs/NetCube", true, new Vector3(Random.Range(-100f, 100f), 0f, Random.Range(-100f, 100f)));
  6.         }
  7.         if (Input.GetKeyDown(KeyCode.L))
  8.         {
  9.                 TNManager.LoadLevel("world");
  10.         }
  11. }
  12.  
  13. [RCC(9)]
  14. static GameObject CreateNetworkedCube(GameObject prefab, Vector3 pos)
  15. {
  16.         Debug.Log("[GameManager] Log: Created networked cube using prefab '" + prefab.name + "' for player#" + TNManager.packetSourceID + " @ " + pos);
  17.         GameObject go = Instantiate(prefab, pos, Quaternion.identity);
  18.         return go;
  19. }
  20.  

Works as expected for me, even when already in the "world" level. Everything that doesn't exist in the scene as a static object (eg; placed there from the Unity Editor) is destroyed.
Marking the channel as persistent and marking the instantiation as persistent results in everything being destroyed, too, which seems like it might be a bug, I dunno.

Could it be that you have some script in the scene that calls Instantiate during its initialization? Remember: Awake, Start, and OnEnable will be called every time the level is loaded. That's why I suggested putting a Debug.Log in your object's Awake function to see who's instantiating it.
Example callstack from a network instantiated object:

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Post Match Cleanup
« Reply #5 on: July 06, 2017, 06:28:07 AM »
@cmifwdll: Marking the object and channel as persistent won't prevent the object from being destroyed when you leave the channel. It'd be silly if the object was still there when you went to another channel, no? :P

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Post Match Cleanup
« Reply #6 on: July 25, 2017, 01:34:08 PM »
Sorry to be resurecting this thread again, but I never actually got this working as it should. (I've had to keep manual references to my tno objects and then call DestroySelf() on each one in a foreach loop at the end of my matches)

One thing I thought might be an issue is that I don't load the scenes where my tno objects are created with TNManager.LoadLevel (Each client just loads using unity's standard scene loading). Do I have to use that to load my levels for TNet to then be able to handle cleaning up any tno objects when I then call TNManager.LoadLevel at the end of my match?

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Post Match Cleanup
« Reply #7 on: July 25, 2017, 03:34:02 PM »
TNManager.LoadLevel calls Channel.Reset on the GameServer which does clear RFCs and tno's. I'd suggest using it for all scene loads, yeah.

Again, though, the best way to get to the root of the problem is to place a Debug.Log in any one of your script component's Awake() functions and paste the callstack for us here. This'll show if the object is being marked as persistent, if it's being instantiated through Unity, or if it's being instantiated through TNet.

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Post Match Cleanup
« Reply #8 on: July 25, 2017, 03:41:24 PM »
Hey cmifwdll!

I just finished putting together a small sample project that illustrates the issue I'm having. Hoping you or ArenMook can take a look at it.

It has a main menu, which loads a Game scene, which loads Levels and dynamically instantiates a Network Controller tno, but you'll see it doesn't get cleaned up by TNManager.LoadLevel.

It's a really simple sample so I'm hoping you can see what silly thing I must be doing wrong.

Here is a dropbox link to the project (Unity 5.6):  {snip}

I'll try the debug log you've suggested right now.
« Last Edit: July 25, 2017, 03:58:15 PM by cmifwdll »

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Post Match Cleanup
« Reply #9 on: July 25, 2017, 03:47:53 PM »
Here is the call stack from Awake() on my Network Controller object

Quote
Network Controller Spawned!
UnityEngine.Debug:Log(Object)
NetworkController:Awake() (at Assets/$ProjectAssets/Scripts/Forge/NetworkController.cs:34)
UnityEngine.Object:Instantiate(GameObject)
TNet.UnityTools:Instantiate(GameObject) (at Assets/TNet/Client/TNUnityTools.cs:224)
RefreshManager:NetworkControllerCreate(GameObject) (at Assets/RefreshManager.cs:78)
System.Reflection.MethodBase:Invoke(Object, Object[])
TNet.CachedFunc:Execute(Object[]) (at Assets/TNet/Client/TNRFC.cs:80)
TNet.TNManager:OnCreateObject(Int32, Int32, UInt32, BinaryReader) (at Assets/TNet/Client/TNManager.cs:1825)
TNet.GameClient:ProcessPacket(Buffer, IPEndPoint) (at Assets/TNet/Client/TNGameClient.cs:1255)
TNet.GameClient:ProcessPackets() (at Assets/TNet/Client/TNGameClient.cs:943)
TNet.TNManager:<ProcessPackets>m__5() (at Assets/TNet/Client/TNManager.cs:587)
TNet.TNManager:Update() (at Assets/TNet/Client/TNManager.cs:1918)

And I instantiate it like so, so it shouldn't be persistent

TNManager.Instantiate(1, "NetworkControllerCreate", "NetworkController", false);

The cleanup issue is happening with all my tno objects as well, including my player avatars, and weapon drops that happen when they die.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Post Match Cleanup
« Reply #10 on: July 25, 2017, 04:55:11 PM »
In TNManager.cs, comment out both line 1834 and 1835. Not sure if this is something you added or if it's default. It isn't in my version of TNet (ver 3.0.6).
This fixes your problem, but I'd urge you to re-evaluate your design, too. Having 3 scenes, one whose sole purpose is to load another, and then hooking up to onSceneLoaded to load the third seems a little redundant. Couldn't you use an RFC to load both Game and Level1 at the same time? Then get rid of the RefreshGame scene altogether. I don't know though, maybe it makes more sense in your actual project.

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Post Match Cleanup
« Reply #11 on: July 27, 2017, 05:00:12 PM »
Woah yea, that is really strange. The code and comment say

  1. // Network objects should only be destroyed when leaving their channel
  2.                         go.transform.parent = null;
  3.                         DontDestroyOnLoad(go);
  4.  

I did not add this, I am on version 3.0.9

rxmarcus

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 62
    • View Profile
Re: Post Match Cleanup
« Reply #12 on: July 27, 2017, 05:50:13 PM »
Commenting out those lines does indeed fix the issue as the objects are no longer marked "DontDestroyOnLoad". Can ArenMook chime in on if I'm ok to remove these lines or what reason they were added?

So by just changing scenes and letting the tno objects get cleaned up by the scene change, that will handle destroying a tno object correctly?
Is TNManager.LoadLevel(...) any different than SceneManager.LoadLevel(...) other than that it tells all clients to change scene automatically?

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Post Match Cleanup
« Reply #13 on: July 27, 2017, 05:57:06 PM »
TNManager.LoadLevel cleans up tno's and saved RFCs on the server, so it's necessary.

Hopefully ArenMook will take a look at this. It seems like it might have been added for a very specific use case and inadvertently breaks other use cases.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Post Match Cleanup
« Reply #14 on: August 03, 2017, 04:16:56 AM »
The DontDestroyOnLoad is intentional there. I want TNet to control the object's lifetime, not Unity's scenes. The object must be destroyed when the user leaves the channel, not when Unity loads another scene. Remember, TNet supports multiple channels (and this also lets you load multiple scenes).

Whether the object is instantiated as persistent or not, this flag ("persistent") controls whether the object will remain in the channel after the player leaves or not. In your case you pass '1' as the channel ID, meaning the object will only be destroyed after you leave channel 1.