public AbstractNavigationAction(string intent, SuperMetroidModel model, InGameState initialInGameState, ExecutionResult executionResult) : this(intent)
        {
            Succeeded = true;

            // Initialize position change
            if (initialInGameState.GetCurrentNode() != executionResult.ResultingState.GetCurrentNode())
            {
                PositionChange = (initialInGameState.GetCurrentNode(), executionResult.ResultingState.GetCurrentNode());
            }

            // Initialize gained and lost items
            ItemInventory gainedInventory = executionResult.ResultingState.GetInventoryExceptWith(initialInGameState);
            ItemsGained = gainedInventory;
            // Cannot lose items, just create an empty inventory
            ItemsLost = new ItemInventory(model.StartConditions.BaseResourceMaximums);

            // Initialize enabled and disabled items
            ItemsDisabledNames = executionResult.ResultingState.GetDisabledItemNames().Except(initialInGameState.GetDisabledItemNames());
            ItemsEnabledNames  = initialInGameState.GetDisabledItemNames().Except(executionResult.ResultingState.GetDisabledItemNames());

            // Initialize flags gained
            GameFlagsGained = GameFlagsGained.Concat(executionResult.ResultingState.GetActiveGameFlagsExceptWith(initialInGameState).Values);

            // Initialize locks opened
            LocksOpened = LocksOpened.Concat(executionResult.ResultingState.GetOpenedNodeLocksExceptWith(initialInGameState).Values);

            // Initialize item locations taken
            ItemLocationsTaken = ItemLocationsTaken.Concat(executionResult.ResultingState.GetTakenItemLocationsExceptWith(initialInGameState).Values);

            // Initialize resources before and after
            ResourcesBefore = initialInGameState.GetCurrentResources();
            ResourcesAfter  = executionResult.ResultingState.GetCurrentResources();

            // Initialize destroyed obstacles, but that's only relevant if we didn't change rooms
            if (executionResult.ResultingState.GetCurrentRoom() == initialInGameState.GetCurrentRoom())
            {
                ObstaclesDestroyed = ObstaclesDestroyed.Concat(
                    executionResult.ResultingState.GetDestroyedObstacleIds()
                    .Except(initialInGameState.GetDestroyedObstacleIds())
                    .Select(obstacleId => executionResult.ResultingState.GetCurrentRoom().Obstacles[obstacleId])
                    );
            }

            // Transfer information data from the ExecutionResult.
            // No need to copy since they are IEnumerable and not supposed to be mutated.
            RunwaysUsed             = executionResult.RunwaysUsed;
            CanLeaveChargedExecuted = executionResult.CanLeaveChargedExecuted;
            OpenedLocks             = executionResult.OpenedLocks;
            BypassedLocks           = executionResult.BypassedLocks;
            KilledEnemies           = executionResult.KilledEnemies;

            // Since the set of items is mutable, do not transfer the instance
            ItemsInvolved.UnionWith(executionResult.ItemsInvolved);
            DamageReducingItemsInvolved.UnionWith(executionResult.DamageReducingItemsInvolved);
        }