private static void ProcessTileChanges(
            SceneConfiguration configuration,
            GameState gameState,
            GameChange gameChange,
            TasksBatch batch)
        {
            if (gameChange == null || gameState == null)
            {
                return;
            }

            if (!gameState.BoardNames.ContainsKey(configuration.BoardName))
            {
                return;
            }

            IO.Models.Board board = gameState.BoardNames[configuration.BoardName];

            foreach (var change in gameChange.TileItemChanges)
            {
                if (change.BoardId != configuration.BoardName)
                {
                    continue;
                }

                Tile tile = board.Grid[change.X * board.Height + change.Y];
                batch.Add(
                    new UpdateTileItemTask(
                        new Vector2Int(change.X, change.Y),
                        tile.Items.Count > 0));
            }
        }
        private static void ProcessCharacter(
            TasksBatch batch,
            string entity,
            Character character,
            CharacterChange characterChange,
            GameState gameState,
            SceneConfiguration sceneConfiguration,
            BoardPositionLookUp boardPositionLookUp,
            HashSet <string> ignoreForHubUpdate,
            bool isMonster)
        {
            var position = new Vector3Int(
                character.Position.X,
                character.Position.Y,
                0);

            if (characterChange.Died)
            {
                if (character.Position.BoardId == sceneConfiguration.BoardName)
                {
#if UNITY_EDITOR
                    Debug.Log("Character Dies");
#endif
                    ignoreForHubUpdate.Add(entity);
                    batch.Add(new DespawnTask(entity));
                    batch.Add(new EffectTask(EffectType.Death, position));
                }

                return;
            }
            else if (characterChange.Respawned)
            {
                if (character.Position.BoardId == sceneConfiguration.BoardName)
                {
                    ignoreForHubUpdate.Add(entity);

                    if (isMonster)
                    {
                        batch.Add(new SpawnMonsterTask(entity, position, character.Sprite)
                        {
                            Health     = character.CurrentHealth,
                            Level      = character.Level,
                            Experience = character.Experience
                        });
                    }
                    else
                    {
                        batch.Add(new SpawnPlayerTask(entity, position)
                        {
                            Health     = character.CurrentHealth,
                            Level      = character.Level,
                            Experience = character.Experience
                        });
                    }

                    batch.Add(new EffectTask(EffectType.Spawn, position));
                }

                return;
            }

            switch (characterChange.Decision.DecisionType)
            {
            case DecisionType.Move:
                if (character.Position.BoardId != sceneConfiguration.BoardName)
                {
                    return;
                }

                Vector3[] path = GetPath(characterChange.Path, boardPositionLookUp);
                batch.Add(new FollowPathTask(entity, path));
                break;

            case DecisionType.Portal:
                ignoreForHubUpdate.Add(entity);

                if (character.Position.BoardId != sceneConfiguration.BoardName)
                {
                    batch.Add(new DespawnTask(entity));
                }
                else
                {
                    if (isMonster)
                    {
                        batch.Add(new SpawnMonsterTask(entity, position, character.Sprite)
                        {
                            Health     = character.CurrentHealth,
                            Level      = character.Level,
                            Experience = character.Experience
                        });
                    }
                    else
                    {
                        batch.Add(new SpawnPlayerTask(entity, position)
                        {
                            Health     = character.CurrentHealth,
                            Level      = character.Level,
                            Experience = character.Experience
                        });
                    }
                }

                batch.Add(new EffectTask(EffectType.Portal, position));
                break;

            case DecisionType.Attack:
                if (character.Position.BoardId == sceneConfiguration.BoardName)
                {
                    foreach (var location in characterChange.AttackLocations)
                    {
                        var attackPosition = new Vector3Int()
                        {
                            x = location.X,
                            y = location.Y,
                            z = 0
                        };

                        batch.Add(new EffectTask(EffectType.Attack, attackPosition));
                    }
                }
                break;

            case DecisionType.Equip:
                if (character.Position.BoardId == sceneConfiguration.BoardName && !isMonster)
                {
                    ignoreForHubUpdate.Add(entity);

                    Player player = gameState.PlayerNames[entity];

                    batch.Add(new UpdateInventoryTask(entity)
                    {
                        clothes_changed  = characterChange.ClothesChanged,
                        hat_changed      = characterChange.HatChanged,
                        shoes_changed    = characterChange.ShoesChanged,
                        weapon_changed   = characterChange.WeaponChanged,
                        accesory_changed = characterChange.AccessoryChanged,

                        Top       = player.Clothes?.Sprite,
                        Bottom    = player.Shoes?.Sprite,
                        Head      = player.Hat?.Sprite,
                        Weapon    = character.Weapon?.Sprite,
                        Accessory = player.Accessory?.Sprite
                    });
                    return;
                }
                break;

            case DecisionType.None:
                break;

            default:
                Debug.LogWarningFormat("Unrecognized decision type {0}", characterChange.Decision.DecisionType);
                break;
            }
        }
        /// <summary>
        /// Process state
        /// </summary>
        /// <param name="taskBatch">the task batch</param>
        /// <param name="sceneConfiguration">
        /// the configuration of this scene
        /// </param>
        /// <param name="gameState">the current game state</param>
        private static void ProcessGameState(
            TasksBatch taskBatch,
            SceneConfiguration sceneConfiguration,
            GameState gameState,
            HashSet <string> ignoreForHubUpdate)
        {
            if (gameState == null)
            {
                return;
            }

            foreach (var pair in gameState.PlayerNames)
            {
                string entity = pair.Key;
                Player player = pair.Value;

                if (player.Character.Position.BoardId != sceneConfiguration.BoardName)
                {
                    continue;
                }

                if (ignoreForHubUpdate.Contains(entity))
                {
                    continue;
                }

                var task = new UpdateHubTask(entity)
                {
                    Health     = player.Character.CurrentHealth,
                    Level      = player.Character.Level,
                    Experience = player.Character.Experience
                };

                taskBatch.Add(task);
            }

            foreach (var pair in gameState.MonsterNames)
            {
                string  entity  = pair.Key;
                Monster monster = pair.Value;

                if (monster.Character.Position.BoardId != sceneConfiguration.BoardName)
                {
                    continue;
                }

                if (ignoreForHubUpdate.Contains(entity))
                {
                    continue;
                }

                var task = new UpdateHubTask(entity)
                {
                    Health     = monster.Character.CurrentHealth,
                    Level      = monster.Character.Level,
                    Experience = monster.Character.Experience
                };

                taskBatch.Add(task);
            }
        }