Search Unity

Question Implement rollback and working around bug with CopyAndReplaceEntitiesFrom

Discussion in 'Entity Component System' started by nykwil, Jan 1, 2022.

  1. nykwil

    nykwil

    Joined:
    Feb 28, 2015
    Posts:
    49
    I've looked into many ways to do rollback, which is creating a copy of the world at a specific frame and then restoring that world and simulating back to the current frame with updated inputs. The easiest way to implement it was with CopyAndReplaceEntitiesFrom to just copy and replace into a backup world then copy and replace back into the active world. Unfortunately this bug https://issuetracker.unity3d.com/is...eplaceentitiesfrom-and-causes-player-to-crash is preventing me from using that function. I believe the bug is if you try and use the function with shared entities there's a leak or something because it doesn't crash right away but only after a few hundred rollbacks. What other ways can I do this? I've looked a bit into serialization but it seemed like a lot of work, mostly because I have shared components (that I don't need to be serialized since they aren't getting unloaded from memory).
    Thanks.
     
    apkdev likes this.
  2. Selmar

    Selmar

    Joined:
    Sep 13, 2011
    Posts:
    59
    I've also had various ideas to do this, including the use of CopyAndReplaceEntitiesFrom, without success. Tried with the latest pre-release (1.0.0-pre.15).

    Manual serialization is not really an option, because you need to be able to guarantee the order between entities in queries and such (e.g. for randomly selecting an entity from a list). It could be worked around, to some extent, by sorting entity data post-query with custom keys (and paying attention to similar pitfalls), but this is not practical.

    With Unity.Physics, my editor becomes unstable and crashes when using CopyAndReplaceEntities.

    Without Unity.Physics, it seems functional, but I still had problems. After digging a little I found out that an EntityQuery was "invalidated" by the rollback. (edit: this only happens to me if the rollback causes entities to be destroyed). If I make sure to recreate the query, the exception is resolved, however there are plenty of other (internal) systems that don't recreate their queries, so it's still a blocking issue.

    Edit: the exception I get without recreating the entity query was caused by a similar issue to yours: there was an in the list of entities that, for some reason, did not have all its components. It looks like this was the only entity that was missing components, but there were 250 and I didn't look through all of them.

    My test code below:

    Code (csharp):
    1.  
    2. using System.Collections.Generic;
    3. using Unity.Entities;
    4. using Unity.Mathematics;
    5. using UnityEngine;
    6.  
    7. public class RollbackTest : MonoBehaviour
    8. {
    9.     List<World> savedWorlds = new List<World>();
    10.  
    11.     private void OnDestroy()
    12.     {
    13.         foreach (var w in savedWorlds)
    14.         {
    15.             if (w?.IsCreated == true)
    16.                 w.Dispose();
    17.         }
    18.         savedWorlds.Clear();
    19.     }
    20.  
    21.     bool bDoRollback = false;
    22.     private void Update()
    23.     {
    24.         if (Input.GetKeyDown(KeyCode.X))
    25.         {
    26.             bDoRollback = true;
    27.         }
    28.     }
    29.  
    30.     void FixedUpdate()
    31.     {
    32.         World currentWorld = World.DefaultGameObjectInjectionWorld;
    33.  
    34.         if (bDoRollback)
    35.         {
    36.             bDoRollback = false;
    37.             int rollbackFrame = math.max(1, savedWorlds.Count - 10);
    38.             for (int i = savedWorlds.Count - 1; i > rollbackFrame; --i)
    39.             {
    40.                 savedWorlds[i].Dispose();
    41.                 savedWorlds.RemoveAt(i);
    42.             }
    43.  
    44.             EntityManager rem = savedWorlds[rollbackFrame].EntityManager;
    45.             currentWorld.EntityManager.CopyAndReplaceEntitiesFrom(rem);
    46.         }
    47.         else
    48.         {
    49.             World saveWorld = new World($"saved #{savedWorlds.Count}");
    50.             saveWorld.EntityManager.CopyAndReplaceEntitiesFrom(currentWorld.EntityManager);
    51.             savedWorlds.Add(saveWorld);
    52.         }
    53.     }
    54. }
    55.  
     
    Last edited: Jan 23, 2023
    TheOtherMonarch and apkdev like this.
  3. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    866
    You should submit a bug report / reproduction case.
     
    Selmar likes this.
  4. Selmar

    Selmar

    Joined:
    Sep 13, 2011
    Posts:
    59
    Upon further testing today it seems that rebuilding the EntityQuery is not the solution, it seems I was just having a well-timed stroke of luck. I'm not sure why behavior is different today.

    In any case, I've submitted a bug report with repro.
     
  5. nykwil

    nykwil

    Joined:
    Feb 28, 2015
    Posts:
    49
    I've submitted multiple bugs on the issue, they get moved around and resolved by other bugs. Like it was a bug then I updated the repo case that cause the editor to crash, then they fixed the editor crash (ie it doesn't crash) but it still doesn't copy elements. This one got resolved with no repo but I have an updated version of the bug here with latest everything.

    https://github.com/nykwil/EcsRollbackTest
     
  6. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    866
    I also submitted a report with 0.51. I have not updated that test project to 1.0 yet. But I plan to testing with 1.0 soon.

    https://issuetracker.unity3d.com/is...hen-using-copyandreplaceentitiesfrom-function
     
  7. redwren

    redwren

    Joined:
    Aug 2, 2019
    Posts:
    69
    CopyAndReplaceEntitiesFrom is still unusable for rollback with 1.0.0-pre.44 and it's so easy to break that I can't imagine a situation where it actually does work.

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Transforms;
    3. using UnityEngine;
    4.  
    5. public class TestController : MonoBehaviour
    6. {
    7.     private World original;
    8.     private World snapshot;
    9.  
    10.     private void Start()
    11.     {
    12.         original = new World("Original");
    13.         snapshot = new World("Snapshot");
    14.     }
    15.  
    16.     private void Update()
    17.     {
    18.         original.EntityManager.CreateEntity(typeof(WorldTransform)); // permanent
    19.         snapshot.EntityManager.CopyAndReplaceEntitiesFrom(original.EntityManager);
    20.         original.EntityManager.CreateEntity(typeof(WorldTransform)); // ephemeral
    21.         original.EntityManager.CopyAndReplaceEntitiesFrom(snapshot.EntityManager);
    22.     }
    23. }
    Running this in an empty scene and fresh project will immediately start failing assertions:
    See also:
    https://forum.unity.com/threads/des...ing-all-entities-failed.1093930/#post-8572658
     
    TheOtherMonarch and Selmar like this.
  8. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    866
    I updated my code from 0.51 to 1.0.0-pre.47 and I no longer get “AssertionException: Assertion failure. Values are not equal” now I am getting “Exception: System.Exception: It is not possible to do the operation in {0} simulation stage. Required stage is {1}”

    The same issue this guy is getting.

    https://forum.unity.com/threads/custom-rate-world-updates.1387218/
     
  9. redwren

    redwren

    Joined:
    Aug 2, 2019
    Posts:
    69
    I submitted my repro above for the assertion exceptions as Issue ECSB-195 and just confirmed it still happens with 2022.2.11 and Entities 1.0.0-pre.47
     
  10. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    866
    I summitted a bug report for the CopyAndReplaceEntitiesFrom stage 0 and 1 bug.

    I voted on ECSB-195 you should probably vote also.
     
    Last edited: Mar 26, 2023
    redwren likes this.
  11. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    866
    IN-36505 was closed as a duplicate of ECSB-97. Despite the fact that ECSB-97 is on pre-0.51 and will not even function on 1.0.0-pre.65 due to API changes. The whole reproduction case had to be restructured, and the error is different.

    Rant on: So we all know how this will end now ECSB-97 will be closed in a year's time as not reproducible because of changes to ECS. IN-36505 will never even reach the ECS team. I reopened the case but do not have high hopes. The QA team is paid based on how many cases they close; I guess sad.
     
    Last edited: Mar 28, 2023
  12. Selmar

    Selmar

    Joined:
    Sep 13, 2011
    Posts:
    59
    Don't worry, I still have two issues open on this topic, which are set to confirmed. One for a crash that happens when using CopyAndReplaceFrom, and one for "ArgumentException: System.ArgumentException: The entity does not exist.".

    I don't remember if the stage 0 and 1 thingy shows up in these, but I suspect it may be solved along the way, no?

    https://issuetracker.unity3d.com/is...manager-dot-copyandreplaceentitiesfrom-method

    https://issuetracker.unity3d.com/is...ions-appear-when-using-copyandreplaceentities
     
  13. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    866