Reputation: 1010
I am looking for some help getting my game to be multiplayer.
I am just getting started with Photon and while I understand why the documentation focuses on things like player movement first I am getting a little hung up in networking extra data.
For example the game I am creating is a card game and currently a singleton holds the the list that represents each players hand which isn't directly tied to the GUI. It lives on a world game object and then is used to keep track of all the current cards. While I supposed this could live solely as data attached to actual game objects such as each card I thought it would be cleaner to have a set of data that the GUI is then mapped based off.
So if I have p1, p2 and p3, with 3 cards call it k, j, j how can I tell photon that this data should only have one copy that is saved on the host instead of four copies of everyone's hand per device. Assuming i am understanding correctly that p1 will have a Gamecore instance for their scene and p2 will have a game core instance for their scene since even though its a singleton each client has its own instance.
orrrr
Should each client generate its own list of p1, p2 and p3 then communicate a change to be propagated across all the clients to ensure all of them have the same data. If this is the case would it be more like p1 say discards a card, updates itself then sends a message to be received by the clients. For reference here is my current game core and player class trimmed down.
public class GameCore : MonoBehaviour{
public List<Player> playerList = new List<Player>();
public static GameCore Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
Destroy(gameObject);
else
Instance = this;
}
}
public struct Player {
//should initialize with a name and 7 blank cards
public Player(string playerName)
{
name = playerName;
playerCards = new List<Card>();
score = 0;
sticks = new Stick();
}
private string name;
private int score;
public List<Card> playerCards;
public Stick sticks;
}
Upvotes: 0
Views: 57
Reputation: 3346
The main point of Fusion is to use [Networked]
properties, which automatically sync across the network. Networked properties have to be inside a NetworkBehaviour
, have the [Networked]
attribute, and be a compatible serializable type.
So in your case, your Player
struct could instead be a NetworkBehaviour:
public class PlayerData : NetworkBehaviour {
private const int MAX_NAME_SIZE = 16;
private const int MAX_HAND_SIZE = 7;
[Networked, Capacity(MAX_NAME_SIZE)] private string Name { get; set; }
[Networked] private int Score { get; set; }
[Networked, Capacity(MAX_HAND_SIZE)] public NetworkList<Card> PlayerCards => default;
[Networked] public Stick Sticks { get; set; }
}
public struct Card : INetworkStruct {
public CardSuit Suit;
public int Value;
}
public enum CardSuit : byte {
Spades, Clubs, Hearts, Diamonds
}
public struct Stick : INetworkStruct {
// I'm not sure what a "stick" is...
}
and then for each player that joins, you can spawn a copy of your prefab that contains the Player
behaviour (along with a NetworkObject
which coordinates the synchronization) using something like INetworkRunnerCallbacks.OnPlayerJoined:
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player) {
// Only spawn our own copy.
if (runner.LocalPlayer == player) {
Runner.Spawn(yourPlayerPrefab);
}
}
This solution is preferred for "Shared" mode, since each player would have StateAuthority over their own object (they are allowed to modify the networked variables).
If you're instead using Host mode, then the host (or dedicated server) will have StateAuthority over the PlayerData classes, and anything that the player wants to do will be have to be done through inputs or RPCs (with [Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
).
This means that the server will be the one doing the spawning and modifying of the cards, which makes it impossible for clients to cheat by directly modifying their own card variables:
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player) {
if (runner.IsServer) {
Runner.Spawn(yourPlayerPrefab, inputAuthority: player);
}
}
Upvotes: 1