public override void ProcessEventsInputs(bool[] inputs, bool[] previousInputs)
        {
            if (!isInFlyingState)
            {
                if (inputs[(int)EnumData.MedusaInputs.Shoot])
                {
                    if (IsHeroAbleToFireProjectiles())
                    {
                        if (!waitingActionForPrimaryMove.Perform())
                        {
                            isFiringPrimaryProjectile = true;
                            waitingActionForPrimaryMove.ReInitialiseTimerToBegin(primaryMoveAttackRateTickRate);
                        }
                        else
                        {
                            isFiringPrimaryProjectile = false;
                        }
                    }
                }
                else if (!inputs[(int)EnumData.MedusaInputs.Shoot] && previousInputs[(int)EnumData.MedusaInputs.Shoot] != inputs[(int)EnumData.MedusaInputs.Shoot])
                {
                    isFiringPrimaryProjectile = false;
                    waitingActionForPrimaryMove.ReInitialiseTimerToEnd(primaryMoveAttackRateTickRate);
                }
                else if (itemToCast != null && itemToCast.castableItemType == EnumData.CastItemTypes.ClientProjectiles)
                {
                    if (itemToCast.itemCount > 0 && inputs[(int)EnumData.MedusaInputs.UseItem])
                    {
                        SpawnClientProjectiles();
                    }
                    else if (itemToCast.itemCount <= 0 || (!inputs[(int)EnumData.MedusaInputs.UseItem] && previousInputs[(int)EnumData.MedusaInputs.UseItem] != inputs[(int)EnumData.MedusaInputs.UseItem]))
                    {
                        ResetClientProjectilesVars();
                    }
                }
            }


            if (!MultiplayerManager.instance.isServer && hasAuthority())
            {
                if (completedMotionToMovePoint)
                {
                    if (isInFlyingState)
                    {
                        if (inputs[(int)EnumData.MedusaInputs.LandPlayer] && previousInputs[(int)EnumData.MedusaInputs.LandPlayer] != inputs[(int)EnumData.MedusaInputs.LandPlayer])
                        {
                            if (isInFlyingState)
                            {
                                //land here
                                flyingTickCountTemp = 0;
                                LandPlayerCommand landPlayerCommand = new LandPlayerCommand(GetLocalSequenceNo());
                                ClientSend.LandPlayer(landPlayerCommand);
                            }
                        }
                    }
                    else
                    {
                        if (inputs[(int)EnumData.MedusaInputs.RespawnPlayer] && previousInputs[(int)EnumData.MedusaInputs.RespawnPlayer] != inputs[(int)EnumData.MedusaInputs.RespawnPlayer])
                        {
                            Vector3Int cellToCheckFor = GridManager.instance.grid.WorldToCell(actorTransform.position);
                            if (IsPlayerSpawnable(cellToCheckFor))
                            {
                                //Respawn player command
                                RespawnPlayerCommand respawnPlayerCommand = new RespawnPlayerCommand(GetLocalSequenceNo());
                                ClientSend.RespawnPlayer(respawnPlayerCommand);
                            }
                            else
                            {
                                Debug.LogError("Invalid location to spawn player");
                            }
                        }
                        else if (inputs[(int)EnumData.MedusaInputs.Push] && previousInputs[(int)EnumData.MedusaInputs.Push] != inputs[(int)EnumData.MedusaInputs.Push])
                        {
                            Vector3Int cellPos     = currentMovePointCellPosition + GridManager.instance.grid.WorldToCell(GridManager.instance.GetFacingDirectionOffsetVector3(Facing));
                            Actor      actorToPush = GridManager.instance.GetActorOnPos(cellPos);

                            if (actorToPush != null)
                            {
                                if (IsActorAbleToPush(Facing) && IsActorPushableInDirection(actorToPush, Facing))
                                {
                                    //Send reliable request of push to server here
                                    PushCommand pushCommand = new PushCommand(GetLocalSequenceNo(), (int)Facing, actorToPush.ownerId);
                                    ClientSend.PushPlayerCommand(pushCommand);
                                }
                            }

                            ClientEnemyManager clientEnemy = GridManager.instance.GetClientEnemyOnPos(cellPos);

                            if (clientEnemy != null)
                            {
                                if (IsClientEnemyPushable(Facing))
                                {
                                    PushCommand pushCommand = new PushCommand(GetLocalSequenceNo(), (int)Facing, clientEnemy.id);
                                    ClientSend.PushPlayerCommand(pushCommand);
                                }
                            }
                        }
                        else if (inputs[(int)EnumData.MedusaInputs.PlaceRemovalBoulder] && previousInputs[(int)EnumData.MedusaInputs.PlaceRemovalBoulder] != inputs[(int)EnumData.MedusaInputs.PlaceRemovalBoulder])
                        {
                            Vector3Int cellToCheckFor = GridManager.instance.grid.WorldToCell(actorTransform.position + GridManager.instance.GetFacingDirectionOffsetVector3(Facing));
                            if (!GridManager.instance.IsCellBlockedForSpawnObjectPlacementAtPos(cellToCheckFor) && !GridManager.instance.HasTileAtCellPoint(cellToCheckFor, EnumData.TileType.NoBoulder) && !GridManager.instance.HasTileAtCellPoint(cellToCheckFor, EnumData.GameObjectEnums.BoulderAppearing))
                            {
                                //send command to server of placement
                                PlaceBoulderCommand placeBoulderCommand = new PlaceBoulderCommand(GetLocalSequenceNo(), cellToCheckFor);
                                ClientSend.PlaceBoulderCommand(placeBoulderCommand);
                            }
                            else if (GridManager.instance.HasTileAtCellPoint(cellToCheckFor, EnumData.TileType.Boulder) && !GridManager.instance.HasTileAtCellPoint(cellToCheckFor, EnumData.TileType.NoBoulder) && !GridManager.instance.HasTileAtCellPoint(cellToCheckFor, EnumData.GameObjectEnums.BoulderDisappearing))
                            {
                                RemoveBoulderCommand removeBoulderCommand = new RemoveBoulderCommand(GetLocalSequenceNo(), cellToCheckFor);
                                ClientSend.RemoveBoulderCommand(removeBoulderCommand);
                            }
                        }
                        else if (itemToCast != null && itemToCast.itemCount > 0 && itemToCast.castableItemType == EnumData.CastItemTypes.SpawnnableItems)
                        {
                            if (inputs[(int)EnumData.MedusaInputs.UseItem] && previousInputs[(int)EnumData.MedusaInputs.UseItem] != inputs[(int)EnumData.MedusaInputs.UseItem])
                            {
                                SpawnItem();
                            }
                        }
                    }
                }

                bubbleShieldAttackReady = !waitingActionForBubbleShieldItemMove.Perform();

                if (!isInFlyingState)
                {
                    if (itemToCast != null && itemToCast.itemCount > 0 && itemToCast.castableItemType == EnumData.CastItemTypes.ServerProjectiles)
                    {
                        if (inputs[(int)EnumData.MedusaInputs.UseItem] && previousInputs[(int)EnumData.MedusaInputs.UseItem] != inputs[(int)EnumData.MedusaInputs.UseItem])
                        {
                            SpawnServerProjectiles();
                        }
                    }
                }
            }
        }
        void UpdateWorld(WorldUpdate newWorldUpdate)
        {
            if (latestWorldUpdate.worldGridItems != null)
            {
                if (updateRateTemp >= updateRate)
                {
                    updateRateTemp = 0;
                    //implement
                    for (int i = 0; i < latestWorldUpdate.worldGridItems.Length; i++)
                    {
                        for (int j = 0; j < latestWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList.Count; j++)
                        {
                            if (!newWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList.Contains(latestWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList[j]))
                            {
                                //delete old
                                GridManager.instance.SetTile(latestWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList[j], (EnumData.TileType)latestWorldUpdate.worldGridItems[i].tileType, false, true);
                            }
                        }
                    }
                    for (int i = 0; i < newWorldUpdate.worldGridItems.Length; i++)
                    {
                        for (int j = 0; j < newWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList.Count; j++)
                        {
                            if (!latestWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList.Contains(newWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList[j]))
                            {
                                //add new
                                GridManager.instance.SetTile(newWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList[j], (EnumData.TileType)newWorldUpdate.worldGridItems[i].tileType, true, true);
                            }
                        }
                    }
                    latestWorldUpdate.worldGridItems = newWorldUpdate.worldGridItems;
                }
                else
                {
                    updateRateTemp++;
                }


                foreach (KeyValuePair <int, ProjectileData> kvp in latestWorldUpdate.projectileDatas)
                {
                    if (!newWorldUpdate.projectileDatas.ContainsKey(kvp.Key))
                    {
                        //delete old
                        ProjectileManager projectileManagerToRemove;
                        if (projectileDatasDic.TryGetValue(kvp.Key, out projectileManagerToRemove))
                        {
                            Destroy(projectileManagerToRemove.gameObject);
                            projectileDatasDic.Remove(kvp.Key);
                        }
                        else
                        {
                            Debug.LogError("Could not find object to remove");
                        }
                    }
                }

                foreach (KeyValuePair <int, ProjectileData> kvp in newWorldUpdate.projectileDatas)
                {
                    if (!latestWorldUpdate.projectileDatas.ContainsKey(kvp.Key))
                    {
                        //add new
                        ProjectileManager projectileManagerToAdd;
                        if (projectileDatasDic.TryGetValue(kvp.Key, out projectileManagerToAdd))
                        {
                            Debug.LogError("Already contains item to add");
                        }
                        else
                        {
                            //intantiate here
                            GameObject gToSpawn = Resources.Load("ClientOnly/" + ((EnumData.Projectiles)(kvp.Value.projectileType)).ToString()) as GameObject;
                            if (gToSpawn == null)
                            {
                                Debug.LogError("gToSpawn is null " + ((EnumData.Projectiles)(kvp.Value.projectileType)).ToString());
                                return;
                            }
                            ProjectileManager newProjectileManager = GridManager.InstantiateGameObject(gToSpawn).GetComponent <ProjectileManager>();
                            newProjectileManager.OnInititialise(kvp.Key);
                            newProjectileManager.SetPosition(kvp.Value.projectilePosition);
                            newProjectileManager.SetFaceDirection(kvp.Value.faceDirection);

                            projectileDatasDic.Add(kvp.Key, newProjectileManager);
                        }
                    }

                    ProjectileManager projectileManager;
                    if (projectileDatasDic.TryGetValue(kvp.Key, out projectileManager))
                    {
                        projectileManager.SetPosition(kvp.Value.projectilePosition);
                        projectileManager.SetFaceDirection(kvp.Value.faceDirection);
                    }
                    else
                    {
                        Debug.LogError("Could not find the projectile manager top alter");
                    }
                }

                foreach (KeyValuePair <int, EnemyData> kvp in latestWorldUpdate.enemyDatas)
                {
                    if (!newWorldUpdate.enemyDatas.ContainsKey(kvp.Key))
                    {
                        //delete old
                        ClientEnemyManager enemyManagerToRemove;
                        if (enemyDatasDic.TryGetValue(kvp.Key, out enemyManagerToRemove))
                        {
                            //Debug.LogError("Deleting here");
                            Destroy(enemyManagerToRemove.gameObject);
                            enemyDatasDic.Remove(kvp.Key);
                        }
                        else
                        {
                            Debug.LogError("Could not find object to remove");
                        }
                    }
                }

                foreach (KeyValuePair <int, EnemyData> kvp in newWorldUpdate.enemyDatas)
                {
                    if (!latestWorldUpdate.enemyDatas.ContainsKey(kvp.Key))
                    {
                        //add new
                        ClientEnemyManager clientEnemyManagerToAdd;
                        if (enemyDatasDic.TryGetValue(kvp.Key, out clientEnemyManagerToAdd))
                        {
                            Debug.LogError("Already contains item to add");
                        }
                        else
                        {
                            //intantiate here
                            GameObject gToSpawn = Resources.Load("ClientEnemy") as GameObject;
                            if (gToSpawn == null)
                            {
                                Debug.LogError("gToSpawn is null " + ((EnumData.Projectiles)(kvp.Value.enemyType)).ToString());
                                return;
                            }
                            ClientEnemyManager newClientManager = GridManager.InstantiateGameObject(gToSpawn).GetComponent <ClientEnemyManager>();
                            newClientManager.SetEnemyColor(kvp.Value.leaderNetworkId, kvp.Value.leadercharacterType);
                            newClientManager.SetEnemyData(kvp.Value);

                            enemyDatasDic.Add(kvp.Key, newClientManager);
                        }
                    }

                    ClientEnemyManager clientEnemyManager;
                    if (enemyDatasDic.TryGetValue(kvp.Key, out clientEnemyManager))
                    {
                        clientEnemyManager.SetEnemyData(kvp.Value);
                    }
                    else
                    {
                        Debug.LogError("Could not find the enemy manager top alter");
                    }
                }


                foreach (KeyValuePair <int, AnimatingStaticTile> kvp in latestWorldUpdate.animatingTileDatas)
                {
                    if (!newWorldUpdate.animatingTileDatas.ContainsKey(kvp.Key))
                    {
                        //delete old
                        StaticAnimatingTileManager staticAnimatingTileManager;
                        if (staticAnimatingTileDic.TryGetValue(kvp.Key, out staticAnimatingTileManager))
                        {
                            Destroy(staticAnimatingTileManager.gameObject);
                            staticAnimatingTileDic.Remove(kvp.Key);
                        }
                        else
                        {
                            Debug.LogError("Could not find object to remove");
                        }
                    }
                }

                foreach (KeyValuePair <int, AnimatingStaticTile> kvp in newWorldUpdate.animatingTileDatas)
                {
                    if (!latestWorldUpdate.animatingTileDatas.ContainsKey(kvp.Key))
                    {
                        //add new
                        StaticAnimatingTileManager staticAnimatingTileManager;
                        if (staticAnimatingTileDic.TryGetValue(kvp.Key, out staticAnimatingTileManager))
                        {
                            Debug.LogError("Already contains item to add");
                        }
                        else
                        {
                            //intantiate here
                            GameObject gToSpawn = Resources.Load("ClientOnly/" + ((EnumData.StaticAnimatingTiles)(kvp.Value.tileType)).ToString()) as GameObject;
                            if (gToSpawn == null)
                            {
                                Debug.LogError("gToSpawn is null");
                                return;
                            }
                            StaticAnimatingTileManager newStaticAnimatingTile = GridManager.InstantiateGameObject(gToSpawn).GetComponent <StaticAnimatingTileManager>();
                            newStaticAnimatingTile.SetPosition(kvp.Value.pos);
                            newStaticAnimatingTile.SetID(kvp.Value.uid);
                            newStaticAnimatingTile.SetSprite(kvp.Value.animationSpriteIndex);

                            staticAnimatingTileDic.Add(kvp.Key, newStaticAnimatingTile);
                        }
                    }

                    StaticAnimatingTileManager staticAnimatingTileManagerRefresh;
                    if (staticAnimatingTileDic.TryGetValue(kvp.Key, out staticAnimatingTileManagerRefresh))
                    {
                        staticAnimatingTileManagerRefresh.SetSprite(kvp.Value.animationSpriteIndex);
                    }
                    else
                    {
                        Debug.LogError("Could not find the projectile manager top alter");
                    }
                }
            }
            GridManager.instance.portalTracker.portalEntranceDic = newWorldUpdate.portalEntranceDic;

            MultiplayerManager.instance.matchStartTimeText.text = Mathf.RoundToInt(newWorldUpdate.gameData.matchStartTime * Time.fixedDeltaTime).ToString();

            latestWorldUpdate.sequenceNumber     = newWorldUpdate.sequenceNumber;
            latestWorldUpdate.animatingTileDatas = newWorldUpdate.animatingTileDatas;
            latestWorldUpdate.enemyDatas         = newWorldUpdate.enemyDatas;
            latestWorldUpdate.gameData           = newWorldUpdate.gameData;
            latestWorldUpdate.portalEntranceDic  = newWorldUpdate.portalEntranceDic;
            latestWorldUpdate.projectileDatas    = newWorldUpdate.projectileDatas;
        }
        public void OnTriggerEnter2D(Collider2D collision)
        {
            TileData collidedTile = collision.GetComponent <TileData>();

            if (collidedTile != null)
            {
                if (collidedTile is Actor collidedActorWithMyHead)
                {
                    if (!collidedActorWithMyHead.isPushed && !collidedActorWithMyHead.isPhysicsControlled)
                    {
                        if (pU.gameObjectInstanceId != collidedActorWithMyHead.gameObject.GetInstanceID() && pU.ownerId != collidedActorWithMyHead.ownerId)
                        {
                            if (collidedActorWithMyHead is MirrorKnight)
                            {
                                DealProjectileOnMirrorKnight(collidedActorWithMyHead);
                            }
                            else
                            {
                                DealProjectileOnActor(collidedActorWithMyHead);
                            }
                        }
                    }
                }
            }
            ClientEnemyManager clientEnemyManager = collision.GetComponent <ClientEnemyManager>();

            if (clientEnemyManager != null)
            {
                if (selfDestroyOnTargetTouch)
                {
                    if (pU.projectileTypeThrown == EnumData.Projectiles.FireBall)
                    {
                        if (clientEnemyManager.enemyType == EnumData.MonsterBreed.MirrorKnight)
                        {
                            if (GridManager.instance.IsPureHeadOn(transform.position, clientEnemyManager))
                            {
                                Destroy(gameObject);
                            }
                            else if (GridManager.instance.IsPureBackOrSideStab(transform.position, clientEnemyManager))
                            {
                                GridManager.instance.Disperse(
                                    dispersedGO
                                    , dispersionRadius
                                    , dispersionSpeed
                                    , pU.ownerId
                                    , GridManager.instance.grid.WorldToCell(transform.position));
                                Destroy(gameObject);
                            }
                        }
                        else
                        {
                            GridManager.instance.Disperse(
                                dispersedGO
                                , dispersionRadius
                                , dispersionSpeed
                                , pU.ownerId
                                , GridManager.instance.grid.WorldToCell(transform.position));
                            Destroy(gameObject);
                        }
                    }
                    else if (pU.projectileTypeThrown == EnumData.Projectiles.EyeLaser)
                    {
                        Destroy(gameObject);
                    }
                    else if (pU.projectileTypeThrown == EnumData.Projectiles.StarShower)
                    {
                        Destroy(gameObject);
                    }
                    else if (pU.projectileTypeThrown == EnumData.Projectiles.CentaurBow)
                    {
                        Destroy(gameObject);
                    }
                }
            }
        }
        void UpdateWorldStart(WorldUpdate newWorldUpdate)
        {
            for (int i = 0; i < newWorldUpdate.worldGridItems.Length; i++)
            {
                for (int j = 0; j < newWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList.Count; j++)
                {
                    GridManager.instance.SetTile(newWorldUpdate.worldGridItems[i].updatedCellGridWorldPositionList[j], (EnumData.TileType)newWorldUpdate.worldGridItems[i].tileType, true, false);
                }
            }

            foreach (KeyValuePair <int, ProjectileData> kvp in newWorldUpdate.projectileDatas)
            {
                ProjectileManager projectileManager;
                if (projectileDatasDic.TryGetValue(kvp.Key, out projectileManager))
                {
                    //assign position
                    projectileManager.SetPosition(kvp.Value.projectilePosition);
                    projectileManager.SetFaceDirection(kvp.Value.faceDirection);
                }
                else
                {
                    //intantiate here
                    GameObject gToSpawn = Resources.Load("ClientOnly/" + ((EnumData.Projectiles)(kvp.Value.projectileType)).ToString()) as GameObject;
                    if (gToSpawn == null)
                    {
                        Debug.LogError("gToSpawn is null");
                        return;
                    }
                    ProjectileManager newProjectileManager = GridManager.InstantiateGameObject(gToSpawn).GetComponent <ProjectileManager>();
                    newProjectileManager.OnInititialise(kvp.Key);
                    newProjectileManager.SetPosition(kvp.Value.projectilePosition);
                    projectileManager.SetFaceDirection(kvp.Value.faceDirection);
                    projectileDatasDic.Add(kvp.Key, newProjectileManager);
                }
            }

            foreach (KeyValuePair <int, EnemyData> kvp in newWorldUpdate.enemyDatas)
            {
                ClientEnemyManager clientEnemyManager;
                if (enemyDatasDic.TryGetValue(kvp.Key, out clientEnemyManager))
                {
                    //assign position
                    clientEnemyManager.SetEnemyData(kvp.Value);
                }
                else
                {
                    //intantiate here
                    GameObject gToSpawn = Resources.Load("ClientEnemy") as GameObject;
                    if (gToSpawn == null)
                    {
                        Debug.LogError("gToSpawn is null");
                        return;
                    }
                    ClientEnemyManager newClientEnemyManager = GridManager.InstantiateGameObject(gToSpawn).GetComponent <ClientEnemyManager>();

                    newClientEnemyManager.SetEnemyColor(kvp.Value.leaderNetworkId, kvp.Value.leadercharacterType);
                    newClientEnemyManager.SetEnemyData(kvp.Value);
                    enemyDatasDic.Add(kvp.Key, newClientEnemyManager);
                }
            }

            foreach (KeyValuePair <int, AnimatingStaticTile> kvp in newWorldUpdate.animatingTileDatas)
            {
                StaticAnimatingTileManager staticAnimatingTileManager;
                if (staticAnimatingTileDic.TryGetValue(kvp.Key, out staticAnimatingTileManager))
                {
                    //assign position
                    staticAnimatingTileManager.SetPosition(kvp.Value.pos);
                    staticAnimatingTileManager.SetID(kvp.Value.uid);
                    staticAnimatingTileManager.SetSprite(kvp.Value.animationSpriteIndex);
                }
                else
                {
                    //intantiate here
                    GameObject gToSpawn = Resources.Load("ClientOnly/" + ((EnumData.StaticAnimatingTiles)(kvp.Value.tileType)).ToString()) as GameObject;
                    if (gToSpawn == null)
                    {
                        Debug.LogError("gToSpawn is null");
                        return;
                    }
                    StaticAnimatingTileManager newstaticAnimatingTileManager = GridManager.InstantiateGameObject(gToSpawn).GetComponent <StaticAnimatingTileManager>();
                    newstaticAnimatingTileManager.SetPosition(kvp.Value.pos);
                    newstaticAnimatingTileManager.SetID(kvp.Value.uid);
                    newstaticAnimatingTileManager.SetSprite(kvp.Value.animationSpriteIndex);
                    staticAnimatingTileDic.Add(kvp.Key, newstaticAnimatingTileManager);
                }
            }

            GridManager.instance.portalTracker.portalEntranceDic = newWorldUpdate.portalEntranceDic;
            MultiplayerManager.instance.matchStartTimeText.text  = Mathf.RoundToInt(newWorldUpdate.gameData.matchStartTime * Time.fixedDeltaTime).ToString();
            latestWorldUpdate = newWorldUpdate;
        }