I'm new to unity multiplayer so just learning it's concepts. I have this script on my player
private void Start()
{
if (isServer)
{
//run when if it's server
} else
{
//run if its client
this.InstantiateBullet();
}
}
[Command]
void InstantiateBullet()
{
Debug.Log("Test Command");
}
I'm getting a warning "Trying to send command for object without authority. ShootHooks.InstantiateBullet" My question is do I have to assign my host player prefab to client an authority so it can call InstantiateBullet() without getting warning? Or can I just ignore the warning
As the error/warning tells you you may only call commands from an object you have the authority over.
Currently it is running on all instances of your player prefab, also the ones that belong to the other connected players and you don't have the authority over those but they do!
So simply make an additional check
private void Start()
{
if(hasAuthority)
{
if(isServer)
{
...
}
else
{
InstantiateBullet();
}
}
}
Related
I have been trying to spawn gameObject(Specifically Player gameObject) in Server using this player.GetComponent().Spawn() and then tried to change ownership. It didn't works for me. So frustrated. Can anyone help on this.
I want to spawn two different player in server and client. So I tried to spawn all the players in server only and tried to change the ownership using ownerclientId, LocalClientId. Nothing worked. What happens is that it spawns two players in both server and client screen but only server has the ownership.
Code snippet:
private void Start()
{
var playerSelected = GameObject.Find("PlayerSelected");
int selectedPlayer = playerSelected.GetComponent<PlayerSelected>().selectPlayer;
if (NetworkManager.Singleton.IsServer)
{
PlayerSpawner(selectedPlayer, OwnerClientId);
}
else
{
PlayerSpawnerOnServerRpc(selectedPlayer, OwnerClientId);
}
}
[ServerRpc(RequireOwnership = false)]
void PlayerSpawnerOnServerRpc(int selectedPlayer, ulong clientId)
{
PlayerSpawner(selectedPlayer, clientId);
}
void PlayerSpawner(int selectedPlayer, ulong clientId)
{
GameObject player;
switch(selectedPlayer)
{
case 0:
player = Instantiate(player1Prefab, spawnPositionPlayer1);
player.GetComponent<NetworkObject>().Spawn();
player.GetComponent<NetworkObject>().ChangeOwnership(clientId);
break;
case 1:
player = Instantiate(player2Prefab, spawnPositionPlayer2);
player.GetComponent<NetworkObject>().Spawn();
player.GetComponent<NetworkObject>().ChangeOwnership(clientId);
break;
}
}
The reason this doesn't work is that the server is sending two messages in quick succession.
player.GetComponent<NetworkObject>().Spawn();
player.GetComponent<NetworkObject>().ChangeOwnership(clientId);
The first tells the clients to spawn an object. The second gives ownership to the object. You cannot guarantee (even running locally) that the Spawn() has finished when the ChangeOwnership() is called. So when ChangeOwnership() is called, the client may not have finished initialising the object that's spawned.
Unity were aware of this, and provided you with SpawnWithOwnership (docs). Replace your two lines with one:
player.GetComponent<NetworkObject>().SpawnWithOwnership(clientId);
I am developing a VR game on Unity, SignalR is working with all the methods in my Hub.
The problem is that one method is not working as expected. The method should return some info about the game at the end of the game but I get this error:
Failed to invoke 'SessionReport' due to an error on the server.
But if I try to call the method at the start of the game it works as expected.
Here's the code in Unity used to Invoke my method 'SessionReport'.
public async static void SendReportInfo()
{
HubConnection hubConnection = SignalRInitConnection.hubConnection;
if (hubConnection != null && hubConnection.State == HubConnectionState.Connected)
{
Debug.Log("SignalR: Method SendReportInfo invoked");
try
{
await hubConnection.InvokeAsync("SessionReport", MapStats.riskHistory, MapStats.scoreHistory, MapStats.envHistory, MapStats.difficultyLvlByEnv, MapStats.mapNameByEnv);
}
catch(Exception e)
{
Debug.Log("EXCEPTION SESSION REPORT:" + e.Message);
}
}
else
{
Debug.Log("SignalR: hubCon is ko for SendReportInfo");
}
}
Here's the method in my SignalR Hub:
public void SessionReport(List<List<Risk>> riskHistory, List<int> scoreHistory, List<int> envHistory, List<int> difficultyLvlByEnv, List<string> mapNameByEnv)
{
//Insert into DB
Console.WriteLine("Nice session report there.");
}
The connection to the Hub is still established when I invoke the 'SessionReport' method at the end of the game.
Why is the method 'SessionReport' working at the start of the game but not at the end?
The problem was that the class Risk on the server didn't have a default constructor. Without the constructor SignalR can't copy what's sent from Unity to an object on the server.
I am making a multiplayer game and I want to have player to interact with a non-player object (whose transform can be changed by any player). When I interact them with the player who joined first (or the guy who is hosting) its working but if I try to interact it with the another player (the one who joined second) the objects goes back to the location that the first player left him at.
So what I tried is to shift the authority of non-player object but I am having the following errors.
Anyone is having the same issue or knows any other way to do the above task? I am using the following code to change the authority:
[Command]
void Cmd_AssignLocalAuthority(GameObject obj)
{
print("shifting authority successfully");
NetworkInstanceId nIns = obj.GetComponent<NetworkIdentity>().netId;
GameObject client = NetworkServer.FindLocalObject(nIns);
NetworkIdentity ni = client.GetComponent<NetworkIdentity>();
ni.AssignClientAuthority(connectionToClient);
}
[Command]
void Cmd_RemoveLocalAuthority(GameObject obj)
{
print("reverting authority successfully");
NetworkInstanceId nIns = obj.GetComponent<NetworkIdentity>().netId;
GameObject client = NetworkServer.FindLocalObject(nIns);
NetworkIdentity ni = client.GetComponent<NetworkIdentity>();
ni.RemoveClientAuthority(ni.clientAuthorityOwner);
}
And the error I am getting is this
You need to know that the changes SHOULD be called from a player object, not the object itself, as it do not have authority.
For setting authority you should do something like this:
[Command]
public void CmdSetAuth(NetworkInstanceId objectId, NetworkIdentity player)
{
GameObject iObject = NetworkServer.FindLocalObject(objectId);
NetworkIdentity networkIdentity = iObject.GetComponent<NetworkIdentity>();
//Checks if anyone else has authority and removes it and lastly gives the authority to the player who interacts with object
NetworkConnection otherOwner = networkIdentity.clientAuthorityOwner;
if (otherOwner == player.connectionToClient)
{
return;
}
else
{
if (otherOwner != null)
{
networkIdentity.RemoveClientAuthority(otherOwner);
}
networkIdentity.AssignClientAuthority(player.connectionToClient);
}
networkIdentity.AssignClientAuthority(player.connectionToClient);
}
I am trying to implement skill based matchmaking using Photon in Unity. It seems
I got most of this code from the documentation and it works but not well.
The problem is that you can't use JoinOrCreate() with the sql lobby type so my logic here is try and find a room, if it fails create one.
void init()
{
_client = Game.Context.GetComponent<SocketConnectionManager>().client;
joinRoom();
}
public void joinRoom()
{
TypedLobby sqlLobby = new TypedLobby("skillLobby", LobbyType.SqlLobby);
string sqlLobbyFilter = "C0 BETWEEN 100 AND 200";
_client.OpJoinRandomRoom(null, MatchMaker.MaxPlayers, MatchmakingMode.FillRoom, sqlLobby, sqlLobbyFilter);
}
public void createRoom()
{
RoomOptions o = new RoomOptions();
o.MaxPlayers = MatchMaker.MaxPlayers;
o.CustomRoomProperties = new Hashtable() { { "C0", Game.Me.getInt("trophies") } };
o.CustomRoomPropertiesForLobby = new string[] { "C0" }; // this makes "C0" available in the lobby
TypedLobby sqlLobby = new TypedLobby("skillLobby", LobbyType.SqlLobby);
_client.OpCreateRoom("", o, sqlLobby);
}
private void onEvent(EventData obj)
{
if (_client.CurrentRoom != null)
{
if (_client.CurrentRoom.PlayerCount >= _client.CurrentRoom.MaxPlayers)
{
// sweet I am good to go.
}
}
else
{
createRoom();
}
}
The problem is this is pretty unreliable. Say two players try to find a game at the same time they will both search fail and then both create. Now I have two players sitting in empty rooms instead of playing each other.
Any ideas on a better system?
Thanks all.
Thank you for choosing Photon!
First of all, there are few things that you should understand about Photon:
you can't use JoinOrCreate() with the sql lobby type
This is not correct.
Where did you read such thing?
Did you test this yourself? What did you test exactly?
onEvent (LoadBalancingClient.OnEventAction) callback cannot be used to be notified of a failed join random room operation. Instead, you should make use of the LoadBalancingClient.OnOpResponseAction callback, as follows:
private void OnOpResponse(OperationResponse operationResponse)
{
switch (operationResponse.Code)
{
case OperationCode.JoinRandomGame:
if (operationResponse.ReturnCode == ErrorCode.NoMatchFound)
{
createRoom();
}
break;
}
}
To detect a join event inside a room (local or remote player entered a room):
private void onEvent(EventData eventData)
{
switch (eventData.Code)
{
case EventCode.Join:
int actorNr = (int)eventData[ParameterCode.ActorNr];
PhotonPlayer originatingPlayer = this.GetPlayerWithId(actorNr);
if (originatingPlayer.IsLocal)
{
}
else
{
}
break;
}
}
To answer your question:
Say two players try to find a game at the same time they will both
search fail and then both create.
Any ideas on a better system?
No.
This issue happens only during the development phase where you use a few clients to run some tests. Once you have enough user base you won't notice this issue.
I am having an issue with forge networking.I have finished beginner tutorials and now I wanted to create my own project.It is very simple:I create a local game on one of my devices and client connects.Each of them(client and host) enter their number, and then host's number is displayed to client and vice versa.However, client's number never gets saved and host always sees 0 for client's number, while the actual number is different(the host's number is getting saved and synchronized through the network properly and client CAN read it). I took these steps in creating this project: 1) in forge network contract wizard I have created 2 variables for storing numbers 2) i created a simple script for saving and loading those 2 numbers(this script is attached to an empty game object) :
public void UpdateNumber(Text Nmbr)//Button!
{
if (!networkObject.IsServer) {
networkObject.clientNmbr = int.Parse (Nmbr.text);
} else {
networkObject.hostNmbr = int.Parse (Nmbr.text);
}
}
public void ShowText(Text text)
{
if (networkObject.IsServer ) {
text.text = "client:" + networkObject.clientNmbr;
} else {
text.text = "host:" + networkObject.hostNmbr;
}
}
I don't see why this works for host but doesn't work for the client