Synchronizing the state of a complex Scene Object

Hello. I'm using Photon Unity Networking for my small maze game.
Feel free to give your opinion on every step of the process.

I will differentiate generating the maze (creating the theoric maze) and building the maze (instantiating the actual walls of the maze in the scene during runtime)

I want to generate the maze at runtime (so that it's different each game).
To generate it, I use a MazeGenerator (see attached)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class MazeGenerator : MonoBehaviour{

	private class Cell
	{
		public bool NORTH_WALL;
		public bool EAST_WALL;
		public bool SOUTH_WALL;
		public bool WEST_WALL;
		public bool VISITED;

		public Cell(){
			NORTH_WALL = true;
			EAST_WALL = true;
			SOUTH_WALL = true;
			WEST_WALL = true;
			VISITED = false;
		}
	}
	
	private int height;
	private int width;
	private int braidFactor;
	public GameObject wallPrefab;

	private int size;
	private Cell[] cells;
	
	public void Initialize(int hgt, int wdt)
	{
		height = hgt;
		width = wdt;
		size = height * width;
		braidFactor = (height + width) / 2;
		cells = new Cell[size];
	}

	public void Generate(){
		//Actual generation of the theoric maze, not important here I guess
		//It works because I succeeded in Building the maze locally
	}

	public void BuildBase(){
		//The ground and the external walls can be built locally, since they are always here
		}

	public void BuildWalls(){
		//This is just what I used to do, but it doesn't work
		//Instantiating too many walls with a photon view in the scene creates QueueIncomingReliableWarning
		/*
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++){
				if (cells[ i * width + j].SOUTH_WALL){
					PhotonNetwork.InstantiateSceneObject(wallPrefab.name, new Vector3(j+0.5f,0.5f,i), Quaternion.Euler(0,90,0), 0, null);
				}
				if (cells[ i * width + j].EAST_WALL){
					PhotonNetwork.InstantiateSceneObject(wallPrefab.name, new Vector3(j+1.0f,0.5f,i+0.5f), Quaternion.identity, 0, null);
				}
			}
		}*/
	}
}

My problem is as follow :
If I generate the maze locally, of course every player will have a different maze and it's pointless.
If the master client generate a maze once (in OnCreatedRoom for exemple) I don't know how to pass the state of the maze (and particularly, the "private Cell[] cells" field) to the other players.

As you can see in the script, I tried using shit load of Photon.InstantiateSceneObject but it created a lot of QueueIncomingReliableWarning. Furthermore, I don't think having ~900 (depending on the dimension of the maze) walls as SceneObjects is a very good idea.

Then I tried to instantiate a single SceneObject to which I attach MazeGenerator, and which will contain the different methods to build the maze, but when I call BuildWalls() in the master client, it doesn't build the walls though it's a Scene Object.

Is there something I'm missing here ? It may be an error in the design and not in the code.

Comments

  • If I generate the maze locally, of course every player will have a different maze and it's pointless.
    If you synchronize between clients just one number - random seed, you will get same mazes everywhere.
    If you still prefer generating on master client, synchronize entire maze as sizes and array of cells.
    In any case you need single object (MazeGenerator itself or some maze manager) with PhotonView attached for data synchronization.
  • That is... actually much more clever.

    And I just synchronize this with a RPC call ?

    I'll test this way and give a feedback. Thank you very much.


    Is my way of identifying the master client the right one ? (I mean making the first initialization in OnCreatedRoom and the synchronization in OnJoinedRoom ?)
  • RPC call is good option among others.
    Consider also using room custom properties for that - they updated automatically everywhere and also pushed to just joined client.
    Is my way of identifying the master client the right one ?
    Probably you need PhotonNetwork.isMasterClient property
  • Hello.

    I tried with RPC and Buffered options so that when a client joins, he synchronizes. However it introduced a bug : if the master client leaves, future joiners won't synchronize (= they don't call the method which was supposed to be RPC buffered). Is it normal ? It's not going a problem, I'll find something or I'll use another way but I just want to know if that's intended behavior.

    I'm going to look into the room custom properties, sounds like an interesting solution. I'm also going to work around a better state machine than (room created/room joined).

    Thank you for your amazing support.
  • Hi,
    if the master client leaves, future joiners won't synchronize
    This behavior is expected and documented in PhotonTargets enum:
    Sends the RPC to everyone. This client does not execute the RPC. New players get the RPC when they join as it's buffered (until this client leaves).

    When master client leaves, next client becomes master. You need send buffered RPC again from new master (handling OnMasterClientSwitched message).
    Or you can send non-buffered RPC form current master to just joined client each time joining occurs (handling OnPhotonPlayerConnected on current master).

    But using room properties is much simpler - just set them and read them, no matter when and where.
  • Wow, I really need to read the documentation better.
    I apologize for asking trivial questions. But to be fair, the PDF isn't the best way to read a documentation. I've always preferred online documentation with one page for each class/enum because it allows you to have multiple pages opened at the same time. However, http://doc-api.exitgames.com/en/pun/current/pun/doc has been removed, and it's the only link I found. Is there an online doc or should I stick to the PDF ?

    And again, thank you very much.
  • Kalissar: About your question "is it normal?":

    Yes, it is intentional that buffered events get deleted when a player leaves. RPCs and Instantiate actions are both events for Photon.
    The idea is that we keep the room's event cache from growing. I see how this is not what you need in your case...


    The automatic clean up can be disabled. Just set RoomOptions.cleanupCacheOnLeave to false for CreateRoom().
    It makes sense to keep the amount of buffered messages small, or else players who join late will get a mass of old messages and might fail to get into the room.

    Player Properties are also cleared but Room Properties are not deleted when someone leaves.

    There is one option to send Events as "belonging to the room", which we use for InstantiateSceneObject. This way, the event is not attached to the player but to the room and you could make events stick in the room - even if cleanupCacheOnLeave is true.


    So. A lot of options :)
    If you made a plan and need help executing it, let us know.

    We will fix the API link. Maybe an updated dropped the docs or something. It's a bug for sure.