syncing without SyncVar - can't wrap my head around it

Hey there,

I am trying to understand the way the HLAPI networking is functioning, but I am running into problems when I try to sync more complex data (think: two-dimensional array with game objects, instead of the int, used in the example).

I broke down my problem to the following:

I am using the Network Lobby Manager, so i have a lobby scene and a play scene.

this game object is located in the play scene
2484105--171201--2016-01-27 17_29_26-.png (GameObject with NetworkIdentity with local player authority and GameController)

this is the script:

public class GameController : NetworkBehaviour
{
    public int someNumber;

    void Start ()
    {
        test();
    }

    private void test()
    {
        if (!isServer && hasAuthority)
        {
            Debug.Log("calling CmdTest");
            CmdTest();
        }
        if (isServer)
        {
            Debug.Log("calling RpcTest");
            RpcTest();
        }
    }

    [Command]
    private void CmdTest()
    {
        Debug.Log("running CmdTest");
        RpcTest();
    }

    [ClientRpc]
    private void RpcTest()
    {
        Debug.Log("running RpcTest");
        someNumber = 3;
    }
}

and this is the output when i run this as host:

2484105--171200--2016-01-27 17_40_12-Search.png (calling and running RpcTest)
someNumber is 3 in the inspector.

on the client side though, nothing is shown and someNumber is 0 in the inspector.

what am I doing wrong?

thanks in advance.

Try

    [Command]
    private void CmdTest()
    {
        Debug.Log("running CmdTest");
        RpcTest(3);
    }
    [ClientRpc]
    private void RpcTest(int newNumber)
    {
        Debug.Log("running RpcTest");
        someNumber = newNumber;
    }

Hey Munchy, thanks for your answer.

I tried your suggestion, but I have the same problem: On the client is not a single debug message.

I didn’t ask previously, but your script is attached to your networked player prefab, yes?

Checking for isServer when the script starts will always return false, so as it is your second condition in your test() function will never run.

I’ve made a few changes to your script, so both conditions will run under the right circumstances. But this still won’t reproduce exactly what a syncvar does, as it won’t synchronize existing players variables to new players that join, only the other way around.

To be honest I haven’t tried manually coding exact syncvar behaviour, as using actual syncvars is so easy anyway.

But maybe this will help you with what you are trying to do anyway.

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class GameController : NetworkBehaviour
{
    public int someNumber;

    public override void OnStartLocalPlayer ()
    {
        base.OnStartLocalPlayer ();
        Debug.Log("Start Local Player");
        test();
    }

    public override void OnStartServer ()
    {
        base.OnStartServer ();
        Debug.Log("Start Server");
        test();
    }

    private void test()
    {
        if (!isServer && hasAuthority)
        {
            Debug.Log("calling CmdTest");
            CmdTest();
        }
        if (isServer)
        {
            Debug.Log("calling RpcTest");
            someNumber = 3;
            RpcTest(someNumber);
        }
    }

    [Command]
    private void CmdTest()
    {
        someNumber = 3;
        Debug.Log("running CmdTest: " + someNumber);
        RpcTest(someNumber);
    }

    [ClientRpc]
    private void RpcTest(int newNumber)
    {
        Debug.Log("running RpcTest: " + newNumber);
        someNumber = newNumber;
    }
}

Note: OnStartServer will only be called for a dedicated server when the first client joins.

Hey Munchy, thanks again.

The script is attached to a scene object in the play scene. This is the problem?

It will make a difference in regards to the script I just posted yes, as that assumes it’s attached to a player object.

However I can’t figure out a way to get state synchronization to work the way you are approaching it, so if it was me I’d forget RPCs and use syncvars.

I’ve whipped up a quick example of a syncvar that uses a hook to change a property on the object based on the value of the syncvar, and both the variable and gameobject property are synchronised properly for new and existing clients.

I apologise if this is repeating something you already knew.

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class GameController : NetworkBehaviour
{
    [SyncVar(hook = "OnSomeNumberChanged")]
    public float someNumber;
    Renderer rend;

    void Awake()
    {
        rend = GetComponent<Renderer>();
    }

    public override void OnStartClient ()
    {
        Debug.Log("Scene Object Start Client");
        OnSomeNumberChanged(someNumber);
    }

    public override void OnStartServer ()
    {
        base.OnStartServer ();
        Debug.Log("Scene Object Start Server");
        test();
    }

    [Server]
    private void test()
    {
        someNumber = Random.Range(0f,1f);
        OnSomeNumberChanged(someNumber);
    }
       
    void OnSomeNumberChanged(float newNumber)
    {
        someNumber = newNumber;
        rend.material.color = new Color(someNumber, 1f, 1f-someNumber);
    }
}

problem is: in the project I am working on, it’s not a simple variable that needs to get synced, but many gameobjects (think: hex-tiles) stored to an 2d-array (called Map).

the hex tiles have this script:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;


////////////////////////////////////////////////////////////
/// base class for all tiles
////////////////////////////////////////////////////////////
public class Tile : NetworkBehaviour
{
    // reference to game grid
    protected GFHexGrid grid;
    protected TileSystem tileSystem;
    protected PlayerSystem playerSystem;
    protected GUIController gui;

    public SpriteRenderer tileGraphic;
    public SpriteRenderer flagGraphic;

    public Sprite[] tileGraphics;

    [SyncVar]
    public int ownerNumber = -1;
    [SyncVar]
    protected int ownerIndex = -1;
    public int OwnerIndex
    {
        get { return ownerIndex; }
        set
        {
            ChangeOwner(value);
        }
    }

    private int upgradeLevel;
    public int UpgradeLevel
    {
        get { return upgradeLevel; }
        set
        {
            ChangeUpgradeLevel(value);
        }
    }

    private int strength;
    public int Strength
    {
        get { return strength; }
        set
        {
            strength = value;
        }
    }

    private bool changedOwner;
    public bool ChangedOwner
    {
        get { return changedOwner; }
        set
        {
            changedOwner = value;
        }
    }

    private bool upgradedThisTurn = false;
    public bool UpgradedThisTurn
    {
        get { return upgradedThisTurn; }
        set
        {
            upgradedThisTurn = value;
        }
    }

    public Vector2 MapCoords;

    ////////////////////////////////////////////////////////////
    /// Awake
    ////////////////////////////////////////////////////////////
    protected void Awake()
    {
        grid = GameObject.FindGameObjectWithTag("Grid").GetComponent<GFHexGrid>();
        gui = GameObject.FindGameObjectWithTag("GUI").GetComponent<GUIController>();
        GameObject game = GameObject.FindGameObjectWithTag("GameController");
        tileSystem = game.GetComponent<TileSystem>();
        playerSystem = game.GetComponent<PlayerSystem>();
        upgradeLevel = 0;
    }

    ////////////////////////////////////////////////////////////
    /// Start
    ////////////////////////////////////////////////////////////
    protected void Start()
    {
        // align object to grid
        transform.position = grid.AlignVector3(transform.position);
    }

    ////////////////////////////////////////////////////////////
    /// Update
    ////////////////////////////////////////////////////////////
    protected void Update()
    {

    }

    ////////////////////////////////////////////////////////////
    /// OnMouseDown
    ////////////////////////////////////////////////////////////
    void OnMouseDown()
    {
        if (EventSystem.current.IsPointerOverGameObject())
        {
            // nothing to do here, because GUI elements will handle
        }
        else // normal behaviour
        {
            if (this != null)
            {
                gui.showPopupMenu(this, tileSystem.isTileAttackable(this), tileSystem.isTileClaimable(this), tileSystem.isTileUpgradable(this));
                //Debug.Log(grid.WorldToGrid(transform.position));
            }
            else
            {
                Debug.Log("something went horribly wrong: this is null (or at least not not null)");
            }
        }
    }

    ////////////////////////////////////////////////////////////
    /// ChangeOwner
    ////////////////////////////////////////////////////////////
    protected void ChangeOwner(int playerIndex)
    {
        // if there is a previous owner
        if (ownerIndex != -1)
        {
            // remove this ressource from him
            playerSystem.Players[ownerIndex].RemoveRessource(this.transform.name);
        }
        else
        {
            UpgradeLevel = 1;
        }
        // add this ressource to new owner
        playerSystem.Players[playerIndex].AddRessource(this.transform.name);
        // set new flag
        SetOwnerFlag(playerSystem.Players[playerIndex]);
        // set new owner
        ownerIndex = playerIndex;
        ownerNumber = playerSystem.Players[playerIndex].PlayerNumber;
        changedOwner = true;
    }

    private void SetOwnerFlag(Player newOwner)
    {
        flagGraphic.sprite = playerSystem.playerFlags[newOwner.PlayerNumber];
        flagGraphic.color = Color.white;
    }

    private void ChangeUpgradeLevel(int value)
    {
        upgradeLevel = value;
        tileSystem.AddTileToUpdateQueue(this);
        SetBuilding();
    }

    private void SetBuilding()
    {
        tileGraphic.sprite = tileGraphics[upgradeLevel];
    }
}

and are managed by this script, which would be the script attached to the scene object… the method I am having problems with is at line 208 and adds the tiles to the map (or at least should)

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;

public class TileSystem : NetworkBehaviour
{
    private GameController game;
    private GameObject tileParent;
    public GameObject clay;
    public GameObject grain;
    public GameObject grassland;
    public GameObject stone;
    public GameObject water;
    public GameObject wood;
    private Tile[,] map;
    public Tile[,] Map
    {
        get { return map; }
    }
    private int mapSizeX;
    private int mapSizeY;
    private int mapMaxIndexX;
    private int mapMaxIndexY;
    private List<Tile> tileUpdateQueue;

    ////////////////////////////////////////////////////////////
    /// Awake
    ////////////////////////////////////////////////////////////
    protected void Awake()
    {
        game = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameController>();
        tileParent = GameObject.FindGameObjectWithTag("TileParent");
        tileUpdateQueue = new List<Tile>();
        mapSizeX = -(int)Mathf.RoundToInt(game.grid.renderFrom.x) + 1 + (int)Mathf.RoundToInt(game.grid.renderTo.x);
        mapSizeY = -(int)Mathf.RoundToInt(game.grid.renderFrom.y) + 1 + (int)Mathf.RoundToInt(game.grid.renderTo.y);
        map = new Tile[mapSizeX, mapSizeY];
        mapMaxIndexX = mapSizeX - 1;
        mapMaxIndexY = mapSizeY - 1;
    }

    internal void SpawnTiles()
    {
        if (hasAuthority)
        {
            CmdSpawnTiles();
        }
       
    }

    ////////////////////////////////////////////////////////////
    /// CmdSpawnTiles
    ////////////////////////////////////////////////////////////
    [Command]
    internal void CmdSpawnTiles()
    {
        Debug.Log("CmdSpawnTiles");
        if (true)
        {
            for (int x = (int)game.grid.renderFrom.x; x <= (int)game.grid.renderTo.x; x++)
            {
                for (int y = (int)game.grid.renderFrom.y; y <= (int)game.grid.renderTo.y; y++)
                {
                    if (x == game.grid.renderFrom.x
                        || x == game.grid.renderTo.x
                        || y == game.grid.renderFrom.y
                        || y == game.grid.renderTo.y)
                    {
                        GameObject go = InstantiateWaterTile(x, y);
                        NetworkServer.Spawn(go);
                        //AddTileToMap(x, y, go);
                        //RpcAddTileToMap(x, y, go);
                    }
                    else if (
                           (x == game.grid.renderFrom.x + 3 && y == game.grid.renderFrom.y + 3)
                        || (x == game.grid.renderFrom.x + 3 && y == game.grid.renderTo.y - 3)
                        || (x == game.grid.renderTo.x - 3 && y == game.grid.renderFrom.y + 3)
                        || (x == game.grid.renderTo.x - 3 && y == game.grid.renderTo.y - 3)

                        || (x == game.grid.renderFrom.x + 2 && y == game.grid.renderFrom.y + 1)
                        || (x == game.grid.renderFrom.x + 2 && y == game.grid.renderTo.y - 1)
                        || (x == game.grid.renderTo.x - 2 && y == game.grid.renderFrom.y + 1)
                        || (x == game.grid.renderTo.x - 2 && y == game.grid.renderTo.y - 1)
                        )
                    {
                        GameObject go = InstantiateClayTile(x, y);
                        NetworkServer.Spawn(go);
                        AddTileToMap(x, y, go);
                        RpcAddTileToMap(x, y, go);
                    }
                    else if (
                       (x == game.grid.renderFrom.x + 1 && y == game.grid.renderFrom.y + 1)
                    || (x == game.grid.renderFrom.x + 1 && y == game.grid.renderTo.y - 1)
                    || (x == game.grid.renderTo.x - 1 && y == game.grid.renderFrom.y + 1)
                    || (x == game.grid.renderTo.x - 1 && y == game.grid.renderTo.y - 1)
                    || (x == game.grid.renderFrom.x + 3 && y == game.grid.renderTo.y - 4)
                    || (x == game.grid.renderTo.x - 3 && y == game.grid.renderTo.y - 4)
                    || (x == game.grid.renderFrom.x + 3 && y == game.grid.renderFrom.y + 4)
                    || (x == game.grid.renderTo.x - 3 && y == game.grid.renderFrom.y + 4)
                    )
                    {
                        GameObject go = InstantiateGrainTile(x, y);
                        NetworkServer.Spawn(go);
                        AddTileToMap(x, y, go);
                        RpcAddTileToMap(x, y, go);
                    }
                    else if (
                       (x == game.grid.renderFrom.x + 1 && y == game.grid.renderFrom.y + 2)
                    || (x == game.grid.renderFrom.x + 2 && y == game.grid.renderTo.y - 2)
                    || (x == game.grid.renderTo.x - 1 && y == game.grid.renderFrom.y + 2)
                    || (x == game.grid.renderTo.x - 2 && y == game.grid.renderTo.y - 2)
                    || (x == game.grid.renderFrom.x + 4 && y == game.grid.renderTo.y - 4)
                    || (x == game.grid.renderTo.x - 4 && y == game.grid.renderTo.y - 4)
                    || (x == game.grid.renderFrom.x + 4 && y == game.grid.renderFrom.y + 3)
                    || (x == game.grid.renderTo.x - 4 && y == game.grid.renderFrom.y + 3)
                    )
                    {
                        GameObject go = InstantiateWoodTile(x, y);
                        NetworkServer.Spawn(go);
                        AddTileToMap(x, y, go);
                        RpcAddTileToMap(x, y, go);
                    }
                    else if (
                       (x == game.grid.renderFrom.x + 4 && y == game.grid.renderFrom.y + 4)
                    || (x == game.grid.renderFrom.x + 4 && y == game.grid.renderTo.y - 5)
                    || (x == game.grid.renderTo.x - 4 && y == game.grid.renderFrom.y + 4)
                    || (x == game.grid.renderTo.x - 4 && y == game.grid.renderTo.y - 5)
                    || (x == game.grid.renderFrom.x + 5 && y == game.grid.renderTo.y - 4)
                    || (x == game.grid.renderFrom.x + 5 && y == game.grid.renderFrom.y + 4)
                    || (x == game.grid.renderFrom.x + 5 && y == game.grid.renderFrom.y + 5)
                    )
                    {
                        GameObject go = InstantiateStoneTile(x, y);
                        NetworkServer.Spawn(go);
                        AddTileToMap(x, y, go);
                        RpcAddTileToMap(x, y, go);
                    }
                    else
                    {
                        GameObject go = InstantiateGrasslandTile(x, y);
                        NetworkServer.Spawn(go);
                        AddTileToMap(x, y, go);
                        RpcAddTileToMap(x, y, go);
                    }
                }
            }
        }
    }

    private GameObject InstantiateWaterTile(int x, int y)
    {
        GameObject go = Instantiate(water, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
        go.transform.parent = tileParent.transform;
        go.name = "Water";
        return go;
    }

    private GameObject InstantiateClayTile(int x, int y)
    {
        GameObject go = Instantiate(clay, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
        go.transform.parent = tileParent.transform;
        go.name = "Clay";
        return go;
    }

    private GameObject InstantiateGrainTile(int x, int y)
    {
        GameObject go = Instantiate(grain, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
        go.transform.parent = tileParent.transform;
        go.name = "Grain";
        return go;
    }

    private GameObject InstantiateWoodTile(int x, int y)
    {
        GameObject go = Instantiate(wood, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
        go.transform.parent = tileParent.transform;
        go.name = "Wood";
        return go;
    }

    private GameObject InstantiateStoneTile(int x, int y)
    {
        GameObject go = Instantiate(stone, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
        go.transform.parent = tileParent.transform;
        go.name = "Stone";
        return go;
    }

    private GameObject InstantiateGrasslandTile(int x, int y)
    {
        GameObject go = Instantiate(grassland, game.grid.GridToWorld(new Vector3(x, y, 0)), Quaternion.Euler(0, 0, 0)) as GameObject;
        go.transform.parent = tileParent.transform;
        go.name = "Grassland";
        return go;
    }

    [ClientRpc]
    private void RpcAddTileToMap(int x, int y, GameObject go)
    {
        Debug.Log("RpcAddTileToMap");
        Tile tile = go.GetComponent<Tile>();
        map[makeArraySafeX(x), makeArraySafeY(y)] = tile;
        tile.MapCoords.x = makeArraySafeX(x);
        tile.MapCoords.y = makeArraySafeY(y);
    }

    private void AddTileToMap(int x, int y, GameObject go)
    {
        Debug.Log("AddTileToMap");
        Tile tile = go.GetComponent<Tile>();
        map[makeArraySafeX(x), makeArraySafeY(y)] = tile;
        tile.MapCoords.x = makeArraySafeX(x);
        tile.MapCoords.y = makeArraySafeY(y);
    }

    public int makeArraySafeY(int y)
    {
        return y + (-(int)Mathf.RoundToInt(game.grid.renderFrom.y));
    }

    public int makeArraySafeX(int x)
    {
        return x + (-(int)Mathf.RoundToInt(game.grid.renderFrom.x));
    }

    ////////////////////////////////////////////////////////////
    /// Attack the tile
    ////////////////////////////////////////////////////////////
    public void Attack()
    {
        Debug.Log("attack");
    }

    ////////////////////////////////////////////////////////////
    /// Claim the tile
    ////////////////////////////////////////////////////////////
    public void Claim()
    {
        //Debug.Log("claim");
        Tile tile = game.gui.getTile();
        if (tile != null)
        {
            if (tile.OwnerIndex == -1)
            {
                Player player = game.playerSystem.Players[game.playerSystem.CurrentPlayer];
                tile.OwnerIndex = game.playerSystem.CurrentPlayer;
                tile.UpgradeLevel = 1;
                player.UseRessource("Clay");
                player.UseRessource("Grain");
                player.UseRessource("Wood");
            }
        }
        else
        {
            Debug.Log("something went horribly wrong: Claim working with null tile");
        }
    }

    ////////////////////////////////////////////////////////////
    /// Upgrade the tile
    ////////////////////////////////////////////////////////////
    public void Upgrade()
    {
        Tile tile = game.gui.getTile();

        if (tile != null)
        {
            //Debug.Log("upgrade");
            if (tile.UpgradeLevel < 3)
            {
                tile.UpgradeLevel += 1;
                Player player = game.playerSystem.Players[game.playerSystem.CurrentPlayer];
                player.UseRessource("Clay");
                player.UseRessource("Grain");
                player.UseRessource("Wood");
                player.UseRessource("Stone");
                tile.UpgradedThisTurn = true;
                AddTileToUpdateQueue(tile);

                Debug.Log(tile.UpgradeLevel);

            }
        }
        else
        {
            Debug.Log("something went horribly wrong: Upgrade working with null tile");
        }
    }

    ////////////////////////////////////////////////////////////
    /// returns wether the tile is able to attack or not
    ////////////////////////////////////////////////////////////
    public bool isTileAbleToAttack(Tile tile)
    {
        if (tile != null)
        {
            return true;
        }
        else
        {
            Debug.Log("something went horribly wrong: isTileAbleToAttack got null tile");
            return false;
        }
    }

    ////////////////////////////////////////////////////////////
    /// returns wether the tile is attackable or not
    ////////////////////////////////////////////////////////////
    public bool isTileAttackable(Tile tile)
    {
        if (tile != null)
        {
            if (!isTileOwnedByCurrentPlayer(tile)
            && tile.OwnerIndex != -1
            && isTileAdjacentToTerritory(tile))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            Debug.Log("something went horribly wrong: isTileAttackable got null tile");
            return false;
        }
    }

    ////////////////////////////////////////////////////////////
    /// returns wether the tile is claimable or not
    ////////////////////////////////////////////////////////////
    public bool isTileClaimable(Tile tile)
    {
        if (tile != null)
        {
            if (!isTileOwnedByCurrentPlayer(tile)
            && tile.OwnerIndex == -1
            && isTileAdjacentToTerritory(tile)
            && game.playerSystem.isPlayerAbleToBuild())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            Debug.Log("something went horribly wrong: isTileClaimable got null tile");
            return false;
        }
    }

    ////////////////////////////////////////////////////////////
    /// returns wether the tile is upgradable or not
    ////////////////////////////////////////////////////////////
    public bool isTileUpgradable(Tile tile)
    {
        if (tile != null)
        {
            if (isTileOwnedByCurrentPlayer(tile)
                && tile.UpgradeLevel < 3
                && game.playerSystem.isPlayerAbleToUpgrade()
                && !tile.ChangedOwner
                && !tile.UpgradedThisTurn)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            Debug.Log("something went horribly wrong: isTileUpgradable got null tile");
            return false;
        }
    }

    ////////////////////////////////////////////////////////////
    /// returns wether the tile is owned by the current player or not
    ////////////////////////////////////////////////////////////
    private bool isTileOwnedByCurrentPlayer(Tile tile)
    {
        if (tile != null)
        {
            if (tile.OwnerIndex == game.playerSystem.CurrentPlayer)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            Debug.Log("something went horribly wrong: isTileOwnedByCurrentPlayer got null tile");
            return false;
        }
    }

    ////////////////////////////////////////////////////////////
    /// returns wether the tile is adjacent to territory (2 tiles) or not
    ////////////////////////////////////////////////////////////
    private bool isTileAdjacentToTerritory(Tile tile)
    {
        if (tile != null)
        {
            // counter has to be 2 or higher!
            int counter = 0;

            if (tile.MapCoords.x % 2 == 0)
            {
                // check clockwise, beginning in the north
                // N => 0 1
                if (isNeighbourUnderControl(tile, 0, 1))
                {
                    //Debug.Log("neighbour found N");
                    counter++;
                }
                // NE => 1 1
                if (isNeighbourUnderControl(tile, 1, 1))
                {
                    //Debug.Log("neighbour found NE");
                    counter++;
                }
                // SE => 1 0
                if (isNeighbourUnderControl(tile, 1, 0))
                {
                    //Debug.Log("neighbour found SE");
                    counter++;
                }
                // S => 0 -1
                if (isNeighbourUnderControl(tile, 0, -1))
                {
                    //Debug.Log("neighbour found S");
                    counter++;
                }
                // SW => -1 0
                if (isNeighbourUnderControl(tile, -1, 0))
                {
                    //Debug.Log("neighbour found SW");
                    counter++;
                }
                // NW => -1 1
                if (isNeighbourUnderControl(tile, -1, 1))
                {
                    //Debug.Log("neighbour found NW");
                    counter++;
                }
            }
            else
            {
                // check clockwise, beginning in the north
                // N => 0 1
                if (isNeighbourUnderControl(tile, 0, 1))
                {
                    //Debug.Log("neighbour found N");
                    counter++;
                }
                // NE => 1 0
                if (isNeighbourUnderControl(tile, 1, 0))
                {
                    //Debug.Log("neighbour found NE");
                    counter++;
                }
                // SE => 1 -1
                if (isNeighbourUnderControl(tile, 1, -1))
                {
                    //Debug.Log("neighbour found SE");
                    counter++;
                }
                // S => 0 -1
                if (isNeighbourUnderControl(tile, 0, -1))
                {
                    //Debug.Log("neighbour found S");
                    counter++;
                }
                // SW => -1 -1
                if (isNeighbourUnderControl(tile, -1, -1))
                {
                    //Debug.Log("neighbour found SW");
                    counter++;
                }
                // NW => -1 0
                if (isNeighbourUnderControl(tile, -1, 0))
                {
                    //Debug.Log("neighbour found NW");
                    counter++;
                }
            }

            if (counter >= 2)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            Debug.Log("something went horribly wrong: isTileAdjacentToTerritory got null tile");
            return false;
        }
    }

    ////////////////////////////////////////////////////////////
    /// returns wether the neighbour is under control of the current player or not
    ////////////////////////////////////////////////////////////
    private bool isNeighbourUnderControl(Tile tile, int x, int y)
    {
        if (tile != null)
        {
            int mapX = (int)Mathf.RoundToInt(tile.MapCoords.x);
            int mapY = (int)Mathf.RoundToInt(tile.MapCoords.y);
            if (mapX + x > 0
                && mapX + x < mapMaxIndexX
                && mapY + y > 0
                && mapY + y < mapMaxIndexY)
            {
                if (isTileOwnedByCurrentPlayer(map[mapX + x, mapY + y]))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            Debug.Log("something went horribly wrong: isNeighbourUnderControl got null tile");
            return false;
        }
    }

    public void AddTileToUpdateQueue(Tile tile)
    {
        if (tile != null)
        {
            tileUpdateQueue.Add(tile);
        }
        else
        {
            Debug.Log("something went horribly wrong: AddTileToUpdateQueue got null tile");
        }
    }

    public void ProcessUpdateQueue()
    {
        for (int i = 0; i < tileUpdateQueue.Count; i++)
        {
            tileUpdateQueue[i].Strength = tileUpdateQueue[i].UpgradeLevel;
            tileUpdateQueue[i].ChangedOwner = false;
            tileUpdateQueue[i].UpgradedThisTurn = false;
        }
    }
}