Determine if the newly connected player is a client or the server player(host) and remove a msg on the server - c#

I want to determine if the newly connected player is a client and on server player(host) remove a msg. In UNET i want there to be two players over LAN. The first player is the server player and then their opponent connects.
The player searches for a LAN match to join like so:
public void StartPlayerClient() {
Debug.Log ("client set up");
discovery.Initialize ();
discovery.StartAsClient ();
searching = true;
}
Once a match is found it receives displays it like this:
void Update() {
if (searching) {
if (discovery.broadcastsReceived != null) {
foreach (var addr in discovery.broadcastsReceived.Keys) {
var value = discovery.broadcastsReceived [addr];
//instantiate ui button to connect...
GameObject ui = Instantiate (GameController.instance.multiplayerMatchConnect) as GameObject;
ui.GetComponent<ConnectToMatch> ().Initialize (value);
ui.transform.SetParent (GameController.instance.matchListParent.transform, false);
}
if (discovery.broadcastsReceived.Keys.Count > 0) {
searching = false;
}
} else {
searching = false;
}
}
}
then the player is able to connect by clicking the button that was just instantiated like so:
public void Initialize(NetworkBroadcastResult value) {
res = value;
GetComponent<Button> ().onClick.AddListener (Connect);
}
void Connect() {
Debug.Log ("connecting...");
string dataString = BytesToString (res.broadcastData);
var items = dataString.Split(':');
if (items.Length == 3 && items[0] == "NetworkManager") {
if (NetworkManager.singleton != null && NetworkManager.singleton.client == null) {
NetworkManager.singleton.networkAddress = items[1];
NetworkManager.singleton.networkPort = Convert.ToInt32(items[2]);
NetworkManager.singleton.StartClient();
}
}
}
Now that all works fine, these are the troublesome parts:
//called on the server when client connects
public override void OnServerConnect(NetworkConnection conn) {
if (NetworkServer.connections.Count > 1) {
GameController.instance.pnlWaitingForOtherPlayer.SetActive (false);
Debug.Log ("player connected");
GameController.instance.pnlMatchList.SetActive (false);
GameController.instance.pnlJoinCreateMenu.SetActive (false);
}
}
on the server client it will say "Waiting for other player" before they connect.. when they do i want the msg to disappear for the server player, this is how im trying to do it and it does not work.
//called on the client when connects to the server
public override void OnClientConnect(NetworkConnection conn) {
if (!discovery.isServer) {
GameController.instance.pnlMatchList.SetActive (false);
Debug.Log("you connected");
}
}

Related

Gameobject not being set active in 'catch'. I've checked everything

Here is what I'm trying to do:
Trying to check if there's internet connection or no. If there is no internet connection, I want to set active a panel showing 'no internet connection'.
I dragged the panel to the inspector. The script which sets this panel active is on a gameobject which is active in hierarchy.
Here is the code:
public GameObject NoInternetConnectionPanel;
private void Start()
{
//Check Internet Connection
InvokeRepeating("CheckInternetConnection", 0f, 1f);
}
private void CheckInternetConnection()
{
var request = WebRequest.Create("http://google.com");
request.Method = "HEAD";
request.BeginGetResponse(result =>
{
try
{
using (var response = request.EndGetResponse(result) as HttpWebResponse)
{
if (response.StatusCode == HttpStatusCode.OK)
{
Debug.Log("Internet connection available");
}
/*else
{
Debug.Log("No internet connection");
}*/
}
}
catch (WebException ex)
{
Debug.Log("No internet connection");
NoInternetConnectionPanel.SetActive(true);
}
}, null);
StartCoroutine(WaitAndCheck());
}
private IEnumerator WaitAndCheck()
{
yield return new WaitForSeconds(1f);
}
The debug log message "no internet connection" is being shown in console. But the 'NoInternetConnectionPanel.SetActive(true)' is not working.
What could be the issue?
That's most probably because it is being executed on another any thread which is not supported by most of the Unity API. In general you shouldn't be using WebRequest at all but rather use UnityWebRequest in a Coroutine.
Also not btw that your WaitAndCheck routine doesn't do anything at all.
I would rather use something like e.g.
public GameObject NoInternetConnectionPanel;
private IEnumerator Start()
{
while(true)
{
yield return CheckInternetConnection();
yield return new WaitForSeconds(1f);
}
}
private IEnumerator CheckInternetConnection()
{
using(var request = UnityWebRequest.Head("http://google.com"))
{
yield return request.SendWebRequest();
var connection = request.result == UnityWebRequest.Result.Success;
NoInternetConnectionPanel.SetActive(! connection);
if(connection)
{
Debug.Log("Internet connection available");
}
else
{
Debug.LogWarning("No internet connection");
}
}
}
Instead of using a we request at all you can also use a simple Ping which is often used with e.g. 8.8.8.8, Google's global DNS server.
private IEnumerator CheckInternetConnection()
{
var ping = new Ping("8.8.8.8");
var maxPingTime = 1f; // maximum time to wait before declaring the ping as failed
var connection = false;
for(var timePassed = 0f; timePassed <= maxPingTime; timePassed += Time.deltaTime)
{
if(ping.isDone)
{
connection = true;
break;
}
}
NoInternetConnectionPanel.SetActive(! connection);
if(connection)
{
Debug.Log("Internet connection available");
}
else
{
Debug.LogWarning("No internet connection");
}
}

My multi-thread online Server gets too slow when multiple clients connect, C#

I'm trying to develop an online game just for fun, with a server and at least 2 clients playing in a single "room". My logic goes as follow, first have the server wait for a client to connect, after the client connects to the server I create a thread for this client (so the client can send messages to the server when it interacts with the main screen). After this if the client wants to play he clicks a button that says "start match" and if another client does the same both goes inside another Thread to play the game only between them. So I create a Thread for each client that connects and a Thread for every 2 clients that want to play.
Now, when i have 2 players playing the game everything goes smooth, the problem is when another 2 players want to play the game the server standalone stops responding (but you can still connect to the server and send messages) and the game gets really slow for the clients.I'm trying to learn about multi-threading that's why i'm doing this project so maybe i'm missing something. I should be creating only 2 threads for each client (when they are actually in game if not only 1) and with 4 clients that's at max 8 Threads, so why is my server getting so slow and crashing?.
This is where I accept my clients:
private void AcceptTcpClient(IAsyncResult ar)
{
TcpListener listener = (TcpListener)ar.AsyncState;
ServerClient sc = new ServerClient(listener.EndAcceptTcpClient(ar));
sc.SetisInGame(false); // not in game, just in the main menu
clients.Add(sc);
new Thread(() => MainPanelRoomThread(sc)).Start();
StartListening();
}
This is my Thread when a client connects:
private void MainPanelRoomThread(ServerClient scThread)
{
while (true)
{
if (!serverStarted)
return;
if (!scThread.GetisInGame()) //check if its not in game so it can receive data
{
NetworkStream stream = scThread.tcp.GetStream();
if (stream.DataAvailable)
{
StreamReader streamReader = new StreamReader(stream, true);
string data = streamReader.ReadLine();
if (data != null)
OnIncomingData(scThread, data); // waiting for that from the client
}
}
}
}
In the OnIncomingData function I wait for a Message saying that the client wants to enter a game so i can start the other thread:
private void OnIncomingData(ServerClient c, string data)
{
Debug.Log("Server = " + data);
string[] aData = data.Split('|');
switch (aData[0])
{
case "CMATCH":
if (aData[1].Contains("true"))
{
queueClients.Enqueue(c);
if (queueClients.Count == 2)
new Thread(new ThreadStart(RoomThread)).Start(); //start the Game only if 2 players are waiting for the game to start.
else
BroadCast("SMATCH|false", c);
}else if (aData[1].Contains("false"))
{
queueClients.Dequeue();
BroadCast("SMATCH|true", c);
}
break;
}
}
Finally the in Game room:
private void RoomThread()
{
string msg = "";
List<ServerClient> players = new List<ServerClient>();
List<ServerClient> disconnected = new List<ServerClient>();
int tamanoCola = queueClients.Count;
for(int i = 0; i < tamanoCola; i++)
{
players.Add(queueClients.Dequeue());
msg = players[i].clientName + "|";
players[i].isMainPlayer = (i == 0);
players[i].SetisInGame(true); //its in game
BroadCast("SWHO|" + msg + ((players[i].isMainPlayer) ? 1 : 0).ToString(), players[i]);
}
while (true)
{
if (!serverStarted)
return;
foreach (ServerClient c in players)
{
//check if client is still playing (either because the connection died or someone won)
if (!IsConnected(c.tcp))
{
c.tcp.Close();
disconnected.Add(c);
continue;
}
else
{
NetworkStream stream = c.tcp.GetStream();
if (stream.DataAvailable)
{
StreamReader streamReader = new StreamReader(stream, true);
string data = streamReader.ReadLine();
if (data != null)
OnIncomingData(c, data, players);
}
}
}
if (disconnected.Count >= 1)
return;
}
}
Any help is really appreciated.

UWP MediaPlayer stops playing sounds

I'm using the MediaPlayer class (https://learn.microsoft.com/en-us/windows/uwp/controls-and-patterns/media-playback) to play sounds in my UWP Project. This all works fine at the beginning but suddenly the Play() call starts "playing" the sound (e.g. the state of the PlaybackSession is "Playing") but there is no sound output...
Dictionary<string, MediaPlayer> Effects = new Dictionary<string, MediaPlayer>();
public async Task LoadEffects()
{
Effects?.Clear();
StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("sounds");
foreach (var effect in await folder.GetFilesAsync())
{
MediaPlayer snd = new MediaPlayer();
snd.AutoPlay = false;
snd.Source = MediaSource.CreateFromStorageFile(effect);
snd.RealTimePlayback = true;
snd.AudioCategory = MediaPlayerAudioCategory.GameMedia;
Effects.Add(effect.DisplayName, snd);
}
IsLoaded = true;
}
public void StartPlaying(string name, float volume = 1.0f, bool force = false)
{
lock (_instance)
{
if (Effects.ContainsKey(name))
{
//if force is true, force the sound to stop and play again otherwise just exit
if (Effects[name].PlaybackSession.PlaybackState == MediaPlaybackState.Playing && !force)
{
return;
}
Effects[name].Pause();
Task.Delay(100).ContinueWith((res) =>
{
Effects[name].Volume = volume;
Effects[name].PlaybackSession.Position = TimeSpan.Zero;
Effects[name].IsLoopingEnabled = true;
Effects[name].Play();
});
}
}
}
public void StopPlaying(string name)
{
lock (_instance)
{
try
{
//if nothing is playing just return
if (Effects[name].PlaybackSession.PlaybackState != MediaPlaybackState.Playing) return;
}
catch(Exception ex)
{
//weird error happens sometimes, catch it and just return
return;
}
if (Effects.ContainsKey(name))
{
Debug.WriteLine($"Stopping {name} now; state before: {Effects[name].PlaybackSession.PlaybackState.ToString()}");
Effects[name].IsLoopingEnabled = false;
Effects[name].Pause();
Effects[name].PlaybackSession.Position = TimeSpan.Zero;
}
}
}
I noticed that it seems to happen more frequently when I'm not using the Task.Delay().
The lock is used, since I have a singleton class.

Unity3d - Node.js tcp connection, Client did not update immediately

I am testing node.js as TCP server and Unity3d as client for my up coming project.
I create a simple chat interface with unity3d that can send and receive data from the server. Everything seems to work fine until I test with 2 clients, one in Unity editor and another with Unity application, whenever I send the message, the server immediately pickup and display in terminal. But the client side only update the display interface when I click to focus on the client, be it Unity editor or the Unity application itself.
Below are my codes:
Node.js
net = require('net');
var clients = [];
net.createServer(function (socket) {
socket.name = socket.remoteAddress + ":" + socket.remotePort
clients.push(socket);
socket.write("Welcome " + socket.name + "\n");
broadcast(socket.name + " joined the chat\n", socket);
socket.on('data', function (data) {
broadcast(socket.name + "> " + data, socket);
});
socket.on('end', function () {
clients.splice(clients.indexOf(socket), 1);
broadcast(socket.name + " left the chat.\n");
});
function broadcast(message, sender) {
clients.forEach(function (client) {
if (client === sender) return;
client.write(message);
});
process.stdout.write(message)
}
}).listen(5000);
// Put a friendly message on the terminal of the server.
console.log("Chat server running at port 5000\n");
client.cs
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Net.Sockets;
using System.IO;
public class client : MonoBehaviour {
private bool socketReady;
private TcpClient socket;
private NetworkStream stream;
private StreamWriter writer;
private StreamReader reader;
public Text servermessage;
public InputField input;
// Use this for initialization
void Start () {
ConnectToServer ();
}
// Update is called once per frame
void Update () {
if(socketReady){
if(stream.DataAvailable){
string data = reader.ReadLine ();
if(data != null){
OnIncomingData (data);
}
}
}
}
public void ConnectToServer(){
if(socketReady)
return;
string host = "127.0.0.1";
int port = 5000;
try
{
socket = new TcpClient(host,port);
stream = socket.GetStream();
writer = new StreamWriter(stream);
reader = new StreamReader(stream);
socketReady = true;
Debug.Log("socket :"+ reader.ToString());
}
catch (System.Exception e)
{
Debug.Log("socket error :"+ e);
}
}
private void OnIncomingData(string data){
Debug.Log ("server : "+ data);
servermessage.text = data;
}
public void OnOutgoingData(string data){
if (!socketReady)
return;
if (input.text == "") {
writer.WriteLine (data);
} else {
writer.WriteLine (input.text);
}
writer.Flush ();
input.text = "";
}
}
What is missing? How can I make it that I can see the immediate update on all my client interface?
This is not caused by your code, but due to the Unity editor. By default the unity editor does not run applications in the background.
You can turn run-in-background on inEdit > Project Settings > Settings-Player
There should be a field Run in background. Turn it on, and it should update even when you are not focused
See Also Run In background

Unity how to find a server from client using NetworkDiscovery

[I work in c#]
In order to decide weather a device should become a server with local client or client alone (for main-server-less networking) I need to find out if there are any other available servers for that device before turning into a server with local client if not for another client device to join by either receiving NetworkDiscovery broadcasts from a server or not - currently I can't get a client to receive broadcast from a server.
I have created two empty gameobjects each with scripts, one script makes it a server and should be broadcasting from its NetworkDiscovery via NetworkDiscovery.StartAsServer() but currently one my client whose NetworkDiscovery has been set to NetworkDiscovery.StartAsClient() is not getting theOnRecievedBroadcast() function called hence not receiving broadcasts from the server.
The two scripts shown below are the client and server:
Client -
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class SearchForServers : MonoBehaviour {
bool serverIsFound;
NetworkDiscovery NetworkDiscovery;
// Use this for initialization
void Start () {
serverIsFound = false;
NetworkClient Client = new NetworkClient();
NetworkDiscovery = gameObject.AddComponent<NetworkDiscovery>();
NetworkDiscovery.Initialize();
NetworkDiscovery.StartAsClient();
}
void OnRecievedBroadcast(string fromAdress, string data)
{
serverIsFound = true;
}
// Update is called once per frame
void Update () {
Debug.Log("Server Found = " + serverIsFound);
}
}
Server -
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class CreateServer : MonoBehaviour
{
bool create;
int minPort = 10000;
int maxPort = 10010;
int defaultPort = 10000;
NetworkDiscovery NetworkDiscovery;
void Start()
{
create = true;
if (create == true)
{
int serverPort = createServer();
if (serverPort != -1)
{
Debug.Log("Server created on port : " + serverPort);
}
else
{
Debug.Log("Failed to create Server");
}
}
NetworkDiscovery = gameObject.AddComponent<NetworkDiscovery>();
NetworkDiscovery.Initialize();
NetworkDiscovery.StartAsServer();
}
//Creates a server then returns the port the server is created with. Returns -1 if server is not created
int createServer()
{
int serverPort = -1;
//Connect to default port
bool serverCreated = NetworkServer.Listen(defaultPort);
if (serverCreated)
{
serverPort = defaultPort;
Debug.Log("Server Created with default port");
}
else
{
Debug.Log("Failed to create with the default port");
//Try to create server with other port from min to max except the default port which we trid already
for (int tempPort = minPort; tempPort <= maxPort; tempPort++)
{
//Skip the default port since we have already tried it
if (tempPort != defaultPort)
{
//Exit loop if successfully create a server
if (NetworkServer.Listen(tempPort))
{
serverPort = tempPort;
break;
}
//If this is the max port and server is not still created, show, failed to create server error
if (tempPort == maxPort)
{
Debug.LogError("Failed to create server");
}
}
}
}
return serverPort;
}
}
These are the console logs with the debug logging
Thanks for reading I hope that you can realise where I have gone wrong or indeed how to complete said task otherwise. #Programmer
First of all you named each server and client script the-same name. You don't need OnRecievedBroadcast in the server code. You only need it in the client code. OnRecievedBroadcast is not being called on the client side because you did not override NetworkDiscovery. You must override it.
Here is a simple Discovering Code:
Client:
public class NetClient : NetworkDiscovery
{
void Start()
{
startClient();
}
public void startClient()
{
Initialize();
StartAsClient();
}
public override void OnReceivedBroadcast(string fromAddress, string data)
{
Debug.Log("Server Found");
}
}
Server:
public class NetServer : NetworkDiscovery
{
// Use this for initialization
void Start()
{
Application.runInBackground = true;
startServer();
}
//Call to create a server
public void startServer()
{
int serverPort = createServer();
if (serverPort != -1)
{
Debug.Log("Server created on port : " + serverPort);
broadcastData = serverPort.ToString();
Initialize();
StartAsServer();
}
else
{
Debug.Log("Failed to create Server");
}
}
int minPort = 10000;
int maxPort = 10010;
int defaultPort = 10000;
//Creates a server then returns the port the server is created with. Returns -1 if server is not created
private int createServer()
{
int serverPort = -1;
//Connect to default port
bool serverCreated = NetworkServer.Listen(defaultPort);
if (serverCreated)
{
serverPort = defaultPort;
Debug.Log("Server Created with deafault port");
}
else
{
Debug.Log("Failed to create with the default port");
//Try to create server with other port from min to max except the default port which we trid already
for (int tempPort = minPort; tempPort <= maxPort; tempPort++)
{
//Skip the default port since we have already tried it
if (tempPort != defaultPort)
{
//Exit loop if successfully create a server
if (NetworkServer.Listen(tempPort))
{
serverPort = tempPort;
break;
}
//If this is the max port and server is not still created, show, failed to create server error
if (tempPort == maxPort)
{
Debug.LogError("Failed to create server");
}
}
}
}
return serverPort;
}
}
The createServer() function is a function from your last question. I don't think you can have both server and client code running at the-same time in the Editor.
For testing, you must build the code in your pc with the server code/NetServer enabled. Run the built program then from your Editor you can run the client/NetClient code. This should discover game on the server.

Categories

Resources