0
\$\begingroup\$

I somewhat understand [Command], [ClientRpc], and [TargetRpc]. However, I am currently struggling to determine how to get my SetupInitialHand() method to run. When called from the same area that checks the player count, it just disconnects the 2nd client after the join. Called from anywhere else, it still doesn't work, and it only pulls null.

The current goal is for 3 random cards to being drawn into each client's hand. The server should just place the 1st client's Initial hand at the bottom and 2nd client's Initial hand at top (server only will each player will see their cards at bottom). Trying to stay in line with the 1 server + 2 client design approach @Zibelas recommended.

Clients enter image description here

Server enter image description here


public class HandManager : NetworkBehaviour
{
    public GameObject handPanel; // Reference to the panel where cards will be displayed
    public GameObject PlayerCard; // Reference to the prefab for the card UI

    // Networked list to store card IDs in the hand
    public readonly SyncList<int> handCardIds = new SyncList<int>(); // Marked as readonly

    // This method will be called on all clients when the handCardIds list changes
    private void OnHandCardIdsChanged(SyncList<int>.Operation op, int index, int oldItem, int newItem)
    {
        // Update the hand UI when the handCardIds list changes
        UpdateHandUI();
    }

    // Update the hand UI based on the handCardIds list
    void UpdateHandUI()
    {
        // Clear the hand panel
        foreach (Transform child in handPanel.transform)
        {
            Destroy(child.gameObject);
        }

        // Instantiate card UI prefabs for each card ID in the hand
        foreach (int cardId in handCardIds)
        {
            // Find the card data based on the card ID from the card database
            Card cardData = CardDatabase.GetCardById(cardId);
            if (cardData != null)
            {
                GameObject newCard = Instantiate(PlayerCard, handPanel.transform);
                // Set up the card UI based on the card data
                SetupCardUI(newCard, cardData);
            }
        }
    }

    [ClientRpc]
    // Set up the UI of a card based on its data
    void SetupCardUI(GameObject cardUI, Card cardData)
    {
        // Set the sprite of the card UI
        cardUI.GetComponent<Image>().sprite = cardData.spriteImage;
        // Set other card UI elements (name, cost, description, etc.) if needed
        // For example:
        // cardUI.GetComponent<CardUI>().SetName(cardData.cardName);
        // cardUI.GetComponent<CardUI>().SetCost(cardData.cost);
        // cardUI.GetComponent<CardUI>().SetDescription(cardData.cardDescription);
    }


    // Method to set up the player's initial hand
    public void SetupInitialHand()
    {
        Debug.Log("Setting up initial hand...");

        // Randomly select cards from the database and add them to the player's hand
        for (int i = 0; i < 3; i++)
        {
            GameObject card = Instantiate(PlayerCard, new Vector2(0,0), Quaternion.identity);
            card.transform.SetParent(handPanel.transform, false);
        }

        Debug.Log("Initial hand setup complete.");

    }

    // Handle interactions with the cards in the hand (e.g., clicking or dragging)
    // Add methods for handling card interactions as needed

    // AddCardToHand method for local player (not used in networked version)
    [ClientRpc]
    public void AddCardToHand(Sprite cardSprite)
    {

    }

}


public class TurnManager : NetworkBehaviour
{
    // List to hold the identities of players
    List<NetworkIdentity> _identities = new List<NetworkIdentity>();

    // Index of the current player
    private int _currentPlayerIndex = 1;

    // SyncVar to synchronize current player across network
    [SyncVar(hook = nameof(NextTurnEvent))] public uint currentPlayer = 0;

    // UnityEvent to invoke when switching to next player
    public UnityEvent<uint> nextPlayer;

    // UnityEvent to invoke when a player is registered
    public UnityEvent<NetworkIdentity, int> playerRegisteredEvent;
    
    private HandManager handManager;

    // Track the number of players that have joined
    private int playersJoined = 0;

    private void Start()
    {
        // Set the name of the GameObject to TurnManager
        gameObject.name = "TurnManager";

        // If this instance is a server, add a null entry to the identities list
        if (isServer) _identities.Add(null);
    }

    private void Update()
    {
        // Check for the "X" key press
        if (Input.GetKeyDown(KeyCode.X))
        {
            CurrentList();
        }
    }

    [Server]
    public void RegisterPlayer(NetworkConnectionToClient connection)
    {
        //Handle here if reconnects can happen
        Debug.LogFormat("Payer added: {0}", connection.identity);

        // Add the player's identity to the identities list
        _identities.Add(connection.identity);
        
        // Invoke the playerRegisteredEvent UnityEvent with the player's identity and turn
        playerRegisteredEvent?.Invoke(connection.identity, GetPlayerTurn(connection));


        // Increment the count of players that have joined
        playersJoined++;

        // If all players have joined, print the current number of players and whose turn it is
        if (playersJoined == 2)
        {
            Debug.LogFormat("Both players have joined. Current number of players: {0}", playersJoined);
            handManager.SetupInitialHand();
        }
    }

    [Server]
    public void NextPlayer()
    {
        Debug.LogFormat("Previous turn: {0}", currentPlayer + " player");
        Debug.Log(currentPlayer + " is the previous player");

        // Move to the next player
        _currentPlayerIndex++;
       
        // If it exceeds the count of identities, loop back to the second player
        if (_currentPlayerIndex >= _identities.Count) _currentPlayerIndex = 1;
        
        // Set the current player to the next player's netId
        currentPlayer = _identities[_currentPlayerIndex].netId;

        Debug.LogFormat("Current turn: {0}", currentPlayer + " player");
        Debug.Log(currentPlayer + " is the current player");
    }

    [Server]
    public bool IsCurrentTurn(NetworkConnectionToClient connection)
    {
        // Check if the provided connection's identity matches the current player's identity
        if (_identities[_currentPlayerIndex] == connection.identity) return true;
        //Sent a message to the client the action is out of turn
        //_errorManager.TargetErrorMessage(connection, "Not your turn");
        return false;
    }

    [Server]
    public int GetCurrentPlayerIndex()
    {
        // Return the index of the current player
        return _currentPlayerIndex;
    }

    [Server]
    public uint GetPlayerByIndex(int index)
    {
        // Return the netId of the player at the specified index
        return _identities[index].netId;
    }

    public int GetPlayerTurn(NetworkConnectionToClient connection)
    {
        // Return the turn of the player associated with the given connection
        return _identities.IndexOf(connection.identity);
    }

    void NextTurnEvent(uint oldPlayer, uint newPlayer)
    {
        // Invoke the nextPlayer UnityEvent with the new player's netId
        nextPlayer?.Invoke(newPlayer);
    }

    [Server]
    // Function to output the current _identities list
    private void CurrentList()
    {
        // Output who is going first
        if (_identities.Count > 1 && _identities[1] != null)
        {
            Debug.LogFormat("Going first: {0}", _identities[1].name);
        }

        Debug.Log("Current _identities:");
        foreach (NetworkIdentity identity in _identities)
        {
            if (identity != null)
            {
                Debug.Log(identity.name);
            }
        }

        Debug.LogFormat("Current turn: {0}", _identities[_currentPlayerIndex].name);
    }
}
```
\$\endgroup\$
4
  • 1
    \$\begingroup\$ The server is not going to place one card at the bottom and the second at the top. That's the job of the client. The server sends two cards with information of who is the owner (player 1 or 2). Player 1 will place cards that are owned by them at the bottom, else at the top (from the view of Player 1). Player 2 will do the same, except placing Player 2 cards at the bottom and Player 1 cards at the top \$\endgroup\$
    – Zibelas
    Mar 23 at 5:58
  • \$\begingroup\$ I've started to understand more that the server merely holds data and nothing visually, but I'm just having trouble understanding how to write the code for that, even after watching the Mirrors Network Tutorials. It may also just be a fundamental lack of understanding how to code what I want. \$\endgroup\$ Mar 23 at 13:34
  • \$\begingroup\$ I would greatly appreciate that, I'm not sure, if I can take up the help for too long since in 8 hours (2-3 hours past when you're available) I have some place to be. But even a little help with someone whos worked with this before would be appreciated and you have already been a massive one. \$\endgroup\$ Mar 23 at 13:49
  • \$\begingroup\$ You must have 20 reputation on The Stack Exchange Network to talk here. See the faq. \$\endgroup\$ Mar 23 at 17:15

0

You must log in to answer this question.

Browse other questions tagged .