Games not Syncing with Photon

I am totally new to Photon or networking of any sort, so please forgive me if I’m just being stupid lol

So, I have a chess game that’s just supposed to be 2 players max, I’m designing it for a client. I seem to have everything working up until the game starts. So I attached photonviews to everything that is supposed to be synced, I have it joining a room at start when you select a player, and if the current room’s player count is more than 1, it activates the "player 2 joined " text. This works, and then it calls an RPC from the photon view, to use this method,

    [PunRPC]
    public void ChangeScene(int sceneName)
    {
            PhotonNetwork.LoadLevel(sceneName);
    }

This appears to work, as it loads the scene on both players. The network manager is set to not destroy on scene change, and I can confirm it’s still present in the heirarchy. It loads both scenes for both players, and even successfully disables the computer player, which is set to disable if the player count is more than 1 in the room(same method that enables/disables the text).

But then when I move a piece, it does not sync anything up between players. Like I said, I have photon views on everything, and a photonview transfrom that is set to sync position on the chess pieces, but it doesn’t move the pieces, or even properly change the players turn. Am I supposed to put RPCs on every single method that I want synced? Because if so I think I would need a huge amount of RPCs lol. I could be wrong, but I thought putting a photonview on the chess board, which handles all the movement and everything, would be enough to sync players.

Or is it perhaps somehow joining them to unique scenes? I am testing it out by building it and then running it in the editor. I just tested it out, started the game in the build, and the start game RPC was successfully called in the editor…

Edit: Here’s my board script, if anybody could give me some advice on what I might need to synchronize manually, I would appreciate it… I’m totally new to networking, and no matter how much I read on it everything just flies over my head lol. It does appear to be joining the same room, but it’s spawning one piece for every player, even though I set it to only initiate the board if the board hadn’t been initiated, also it’s not properly changing their sprites… The movement does seem to be syncing though, although, there is an extra piece under every piece.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;

public class Board : MonoBehaviourPunCallbacks
{
    [SerializeField]
    int boardSize = 8;

    public Vector2[,] boardGrid;
    public ChessPiece[,] pieces;
    [SerializeField]
    Transform chessPieceContainer;
    [SerializeField]
    float spaceBetweenPieces = 1;
    [SerializeField]
    GameObject chessPiece, capturedChessPiece;
    TeamColor currentTeam, onePlayerTeam, computerTeam;

    ChessPiece selectedPiece;
    Vector2 mousePos;
    Camera cam;

    [SerializeField]
    GameObject highlighter, movementBox;
    List<GameObject> boxes;
    SpeechBubble bubble;
    [SerializeField]
    RectTransform[] onePlayerPiecesGraveyard, twoPlayerPiecesGraveyard;

    int numCapturedWhite, numCapturedBlack;

    bool gameOver, blackKingDown,blackQueenDown, firstpawnBlack,firstPawnWhite, enemyTurn, boardInitiated;


    private void Awake()
    {
        bubble = FindObjectOfType<SpeechBubble>();
        boxes = new List<GameObject>();
        cam = Camera.main;
        currentTeam = TeamColor.White;
        boardGrid = new Vector2[boardSize, boardSize];
        pieces = new ChessPiece[boardSize,boardSize];
        if (!boardInitiated)
        {
            InitiateBoard();
        }
        onePlayerTeam = GameManager.team;
        if (onePlayerTeam == TeamColor.Black)
        {
            computerTeam = TeamColor.White;
            if (GameManager.isSinglePlayer)
            {
                StartCoroutine(ComputerTurn());
            }
            bubble.SpeechBubbleDisplay(13);
        }
        else
        {
            bubble.SpeechBubbleDisplay(12);
            computerTeam = TeamColor.Black;
         
        }
     
    }


    void InitiateBoard()
        {
        boardInitiated = true;
            for (int x = 0; x < boardGrid.GetLength(0); x++)
            {
         
                for (int y = 0; y < boardGrid.GetLength(1); y++)
                {
                    boardGrid[x, y] = new Vector3(chessPieceContainer.position.x + x * spaceBetweenPieces, chessPieceContainer.position.y + y * spaceBetweenPieces,0);

                    if (y < 2 || y > 5)
                    {
                 
                        GameObject spawnedPiece = PhotonNetwork.Instantiate("Prefabs/Piece", boardGrid[x,y],transform.rotation);
                        pieces[x, y] = spawnedPiece.GetComponent<ChessPiece>();
                        pieces[x, y].posOnBoard = new Vector2Int(x, y);
                    }
                }
            }
        CheckAllLegalMoves();
        }



    private void Update()
    {

        if(selectedPiece == null && highlighter.activeInHierarchy)
        {
            highlighter.SetActive(false);
        }
        if (Input.GetMouseButtonDown(0))
        {
            OnMouse();
        }
    }

    void OnMouse()
    {
        mousePos = Input.mousePosition;
        RemoveSelectionBoxes();
        if (!gameOver)
        {
            if (onePlayerTeam == currentTeam)
            {
                if (CheckIfCoordsAreOnGrid(mousePos))
                {
                    if (GetPieceAtCoords(mousePos) != null && selectedPiece == null && pieces[CheckGridPosAtCoords(mousePos).x, CheckGridPosAtCoords(mousePos).y].team == currentTeam)
                    {
                        Vector2Int pieceToSelectIndex = CheckGridPosAtCoords(mousePos);
                        SelectPiece(pieces[pieceToSelectIndex.x, pieceToSelectIndex.y]);
                    }
                    else if (selectedPiece != null)
                    {
                        if (pieces[CheckGridPosAtCoords(mousePos).x, CheckGridPosAtCoords(mousePos).y] == null)
                        {
                            MovePiece(CheckGridPosAtCoords(mousePos), selectedPiece);
                        }

                        else if (GetPieceAtCoords(mousePos).team == selectedPiece.team)
                        {
                            SelectPiece(GetPieceAtCoords(mousePos));
                        }
                        else if (selectedPiece != null)
                        {
                            CapturePiece(GetPieceAtCoords(mousePos));
                        }
                    }
                }
            }
        }
    }
    void SwitchActiveTeam()
    {
        if(currentTeam == computerTeam)
        {
            currentTeam = onePlayerTeam;
        }
        else
        {
            currentTeam = computerTeam;
        }
    }

    ChessPiece GetPieceAtCoords(Vector2 coords)
    {
        return pieces[CheckGridPosAtCoords(coords).x, CheckGridPosAtCoords(coords).y];
    }

    Vector2Int CheckGridPosAtCoords(Vector2 coords)
    {
        float distance = 2;
        Vector2Int pieceInd = Vector2Int.one * -1;
        for (int x = 0; x < boardGrid.GetLength(0); x++)
        {

            for (int y = 0; y < boardGrid.GetLength(1); y++)
            {
                if (Vector2.Distance(cam.ScreenToWorldPoint(coords), boardGrid[x, y]) < distance)
                {
                    distance = Vector2.Distance(cam.ScreenToWorldPoint(coords), boardGrid[x, y]);
                    pieceInd = new Vector2Int(x, y);
                }
            }

        }if(pieceInd == Vector2Int.one * -1)
        {
            RemoveSelectionBoxes();
            print("Something when wrong in selecting?");
         
        }
        return new Vector2Int(pieceInd.x,pieceInd.y);
    }

    void CheckAllLegalMoves()
    {
        for (int i = 0; i < pieces.GetLength(0); i++)
        {
            for (int j = 0; j < pieces.GetLength(1); j++)
            {
                if (pieces[i, j] != null)
                {
                    pieces[i, j].CalculateLegalMoves();
                }
            }
        }
    }

    void MovePiece(Vector2Int pos, ChessPiece pieceToMove)
    {
        if (pieces[pos.x, pos.y] == null && pieceToMove.legalMoves.Contains(pos))
        {
            Vector2Int previousPos = pieceToMove.posOnBoard;
            if (pieceToMove.firstMove)
            {
                pieceToMove.firstMove = false;
            }
            pieces[previousPos.x, previousPos.y] = null;
            pieceToMove.posOnBoard = pos;
            pieceToMove.transform.position = boardGrid[pos.x,pos.y];
            pieces[pos.x,pos.y] = pieceToMove;
            DeselectPiece();

            StartNewTurn();

        }else if(pieces[pos.x, pos.y] != null && pieces[pos.x, pos.y].team != selectedPiece.team)
        {

            CapturePiece(pieces[pos.x, pos.y]);

        }
        else if(!selectedPiece.legalMoves.Contains(pos))
        {
            print("Something when wrong in moving?");
        }
    }

    void CapturePiece(ChessPiece pieceToCapture)
    {
        Vector2Int posToMoveTo = Vector2Int.zero;
        if(pieceToCapture.team == TeamColor.White)
        {
            ChessPieceEvent(pieceToCapture.pieceIndex,pieceToCapture.GetComponent<SpriteRenderer>().sprite);
        }
        else
        {
            ChessPieceEvent(pieceToCapture.pieceIndex + 6, pieceToCapture.GetComponent<SpriteRenderer>().sprite);
        }
        for (int x = 0; x < pieces.GetLength(0); x++)
        {
            for (int y = 0; y < pieces.GetLength(1); y++)
            {
                if(pieces[x,y] == pieceToCapture)
                {
                    posToMoveTo = pieces[x, y].posOnBoard;
                    pieces[x, y] = null;
                    Destroy(pieceToCapture.gameObject);
                }
            }
        }

        Destroy(pieceToCapture.gameObject);
        MovePiece(posToMoveTo,selectedPiece);
    }

    public int PosX(Vector2Int coords)
    {
        return CheckGridPosAtCoords(coords).x;
    }

    public int PosY(Vector2Int coords)
    {
        return CheckGridPosAtCoords(coords).y;
    }


    public void SelectPiece(ChessPiece piece)
    {
        if(selectedPiece == null)
        {
            RemoveSelectionBoxes();
        }
        selectedPiece = piece;
        HighlightSelectedPiece();
        for (int i = 0; i < selectedPiece.legalMoves.Count; i++)
        {
            boxes.Add(Instantiate(movementBox, boardGrid[selectedPiece.legalMoves[i].x, selectedPiece.legalMoves[i].y], transform.rotation));
        }
    }

    void HighlightSelectedPiece()
    {
        highlighter.SetActive(true);
        highlighter.transform.position = selectedPiece.transform.position;
    }

    public void DeselectPiece()
    {
        selectedPiece = null;
        RemoveSelectionBoxes();
    }

    void RemoveSelectionBoxes()
    {
        for (int i = 0; i < boxes.Count; i++)
        {
            Destroy(boxes[i]);
        }
    }

    public bool CheckIfArrayIsOutOfBounds(Vector2Int pos)
    {
        return pos.x > -1 && pos.x < 8 && pos.y > -1 && pos.y < 8;
    }
 
    public bool CheckIfCoordsAreOnGrid(Vector2 coords)
    {

        float distance = 2;
        Vector2Int pieceInd = Vector2Int.one * -1;
        for (int x = 0; x < boardGrid.GetLength(0); x++)
        {

            for (int y = 0; y < boardGrid.GetLength(1); y++)
            {
                if (Vector2.Distance(cam.ScreenToWorldPoint(coords), boardGrid[x, y]) < distance)
                {
                    distance = Vector2.Distance(cam.ScreenToWorldPoint(coords), boardGrid[x, y]);
                    pieceInd = new Vector2Int(x, y);
                    return true;
                }
            }

        }
        if (pieceInd == Vector2Int.one * -1)
        {
            return false;

        }

        return false;
    }

    void StartNewTurn()
    {
        SwitchActiveTeam();

        for (int i = 0; i < pieces.GetLength(0); i++)
        {
            for (int j = 0; j < pieces.GetLength(1); j++)
            {
                if(pieces[i,j] != null)
                {
                    pieces[i, j].CalculateLegalMoves();
                }
            }
        }
        if(currentTeam != onePlayerTeam && !enemyTurn && GameManager.isSinglePlayer)
        {
            StopAllCoroutines();
            StartCoroutine(ComputerTurn());
        }
    }

    IEnumerator ComputerTurn()
    {
        if (!gameOver)
        {
            enemyTurn = true;
            float random = UnityEngine.Random.Range(1f, 5f);
            yield return new WaitForSeconds(random);
            CheckAllLegalMoves();

            ComputerRandomMove();
            enemyTurn = false;
        }
    }

    public void ComputerRandomMove()
    {
        ChessPiece pieceToMove = GetRandomPieceOfTeam();
        int highestNumber = 1;
        for (int i = 0; i < 500; i++)
        {
            pieceToMove = GetRandomPieceOfTeam();
            if ( pieceToMove.legalMoves.Count > 0)
            {
                break;
            }
            highestNumber = i + 1;
        }
        bool moving = false; ;
        List<Vector2Int> moves = new List<Vector2Int>();

        for (int i = 0; i < pieceToMove.legalMoves.Count; i++)
        {
            moves.Add(pieceToMove.legalMoves[i]);
            if(pieces[pieceToMove.legalMoves[i].x, pieceToMove.legalMoves[i].y] != null)
            {
                SelectPiece(pieceToMove);
                moving = true;
                CapturePiece(pieces[pieceToMove.legalMoves[i].x, pieceToMove.legalMoves[i].y]);
                break;
            }
        }
        if (!moving)
        {

            int random = UnityEngine.Random.Range(0, moves.Count);
            SelectPiece(pieceToMove);
            MovePiece(pieceToMove.legalMoves[random], selectedPiece);
        }
    }

    ChessPiece GetRandomPieceOfTeam()
    {
        List<ChessPiece> piecesToCycle = new List<ChessPiece>();
        for (int i = 0; i < pieces.GetLength(0); i++)
        {
            for (int j = 0; j < pieces.GetLength(1); j++)
            {
                    if (pieces[i, j] != null && pieces[i, j].team != onePlayerTeam)
                    {
                        piecesToCycle.Add(pieces[i, j]);
                    }
            }
        }
        int random = UnityEngine.Random.Range(0, piecesToCycle.Count);
     
        return piecesToCycle[random];
    }

    void ChessPieceEvent(int pieceIndex, Sprite sprite)
    {
        if (pieceIndex < 5) {
            numCapturedWhite++;
            GameObject deadPiece = Instantiate(Resources.Load("Prefabs/CapturedPiece") as GameObject,onePlayerPiecesGraveyard[numCapturedWhite % 2]);
            deadPiece.GetComponent<Image>().sprite = sprite;
            if(pieceIndex == 0)
            {
                EndGame(TeamColor.Black);
            }
        }
        else
        {
            numCapturedBlack++;
            GameObject deadPiece = Instantiate(Resources.Load("Prefabs/CapturedPiece") as GameObject, twoPlayerPiecesGraveyard[numCapturedBlack % 2]);
            deadPiece.GetComponent<Image>().sprite = sprite;
            if(pieceIndex == 6)
            {
                print("King died?");
                blackKingDown = true;
            }
            if(pieceIndex == 11)
            {
                blackQueenDown = true;
            }
            if(blackKingDown && blackQueenDown)
            {
                EndGame(TeamColor.White);
            }
        }
        bubble.SpeechBubbleDisplay(pieceIndex);
    }

    public void EndGame(TeamColor victor)
    {
        print("Game over, man");
        gameOver = true;
    }


}


Here is what my board looks like, sorry to bump, idk why it wouldn’t let me attach a screenshot while editing the post. So, I even added a check, to see if there already was a piece at the point, but it’s still instantiating two pieces, and for some reason, not initializing the second set of pieces properly(it sets them all to white rook, which is handled in the pieces script). These rooks appear to be the pieces instantiated on the other players screen?

I can’t figure out why, but the team is not switching either, even thought the team is switching properly.(I can tell because unique screens pop up depending on which team you are, and also player cannot move more than once, but black team is just never activated.)… Or it might just be selecting that white pawn that’s being spawned everywhere?

This game worked perfectly fine in single player, so the issue is because I’m trying to make it multiplayer…

So, I’ve fixed most the issues, but I have one major issue that I have no idea how to fix it.

In the initiate board method up there, I am instantiating the chess pieces through photon, and then assigning the chess pieces’ “positions” in their scripts by getting the ChessPiece component, at line 85 up there, it is getting a null reference exception, presumably at the get component? So I am unable to assign their positions, and it is just setting all their sprites and teams to 0,0 which is the white rook, hence, why it was spawning a bunch of white rooks in the above screenshot.

I have it so it only spawns one piece per square now, but does anyone know why I can’t get a reference to the component? The error only occurs on the build, and if I am playing multiplayer, strangely, the sprites look fine in the editor(while in play mode), but if I head to the build, it’s just a bunch of white rooks. Also, if I play single player on either the build or the editor, it works just fine(despite the fact the script is the exact same, all playing multiplayer does is remove the AI)

Could someone please help with this? I have no idea how to fix this…