我在学习网络游戏,但是确实有一些问题。现在我的代码由于学习和尝试自己调试而非常混乱,但是我没有主意。
发生的事情是,当人们登录时,它应该向所有连接的人发送一个SyncPacket,以便我们可以向玩家发送位置信息等等。
最后连接的播放器可以看到所有播放器,但只有在您连接时才会更新为所有人。
通过调试,我可以确定它仅在连接时发送,而不会再次发送。
代码如下
服务器:
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using ServerData;
namespace Server
{
class Server
{
static Socket listenerSocket;
static List<ClientData> _clients;
static void Main(string[] args)
{
listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_clients = new List<ClientData>();
IPAddress ip = IPAddress.Parse(Packet.GetIp4Adress());
IPEndPoint ipEnd = new IPEndPoint(ip, 1337);
Console.WriteLine("Starting server on:" + Packet.GetIp4Adress());
listenerSocket.Bind(ipEnd);
Thread listenerThread = new Thread(ListenThread);
listenerThread.Start();
}
static void ListenThread()
{
for (; ; )
{
listenerSocket.Listen(0);
ClientData client = new ClientData(listenerSocket.Accept());
_clients.Add(client);
client.SendRegistrationPacket();
}
}
public static void Data_IN(object cSocket)
{
Socket clientSocket = (Socket)cSocket;
byte[] buffer;
int readBytes = 0;
for (; ; )
{
try
{
buffer = new byte[clientSocket.SendBufferSize];
readBytes = clientSocket.Receive(buffer);
if (readBytes > 0)
{
Packet p = new Packet(buffer);
DataManager(p);
}
}
catch (SocketException ex)
{
foreach (ClientData c in _clients)
{
if (!c.clientSocket.Connected)
{
c.clientSocket.Close();
_clients.Remove(c);
}
}
}
}
}
public static void DataManager(Packet p)
{
if (p.packetType != PacketType.PlayerPositionUpdate)
{
Console.WriteLine("::> " + p.packetType);
}
switch (p.packetType)
{
case PacketType.PlayerRegistration:
Packet playersUpdate = new Packet(PacketType.SyncAllPlayers, "server");
foreach (ClientData c in _clients)
{
string gDataStr = c.ID + ",";
gDataStr += c.name + ",";
gDataStr += c.x + ",";
gDataStr += c.y;
playersUpdate.gData.Add(gDataStr);
}
for (int i = 0; i < _clients.Count; i++)
{
_clients[i].clientSocket.Send(playersUpdate.toBytes());
}
break;
case PacketType.PlayerShootingRequest:
int clickX = int.Parse(p.gData[0]);
int clickY = int.Parse(p.gData[1]);
int Index = _clients.FindIndex(i => i.ID == p.senderID);
_clients[Index].ammo--;
Packet ShooterStatUpdate = new Packet(PacketType.PlayerStatUpdate, "server", _clients[Index].ammo.ToString());
SendTo(p.senderID, ShooterStatUpdate);
foreach (ClientData c in _clients)
{
float top = c.y + (float.Parse(p.gData[3]) / 2f);
float btm = c.y - (float.Parse(p.gData[3]) / 2f);
float left = c.x - (float.Parse(p.gData[2]) / 2f);
float right = c.x + (float.Parse(p.gData[2]) / 2f);
int chkSum = 0;
chkSum = clickY <= top ? 1 : 0;
chkSum = clickY >= btm ? 1 : 0;
chkSum = clickX >= left ? 1 : 0;
chkSum = clickX <= right ? 1 : 0;
if (chkSum == 4)
{
Index = _clients.FindIndex(j => j == c);
_clients[Index].health -= 7;
Packet ShotStatUpdate = new Packet(PacketType.PlayerStatUpdate, "server", _clients[Index].health.ToString());
SendTo(_clients[Index].ID, ShotStatUpdate);
break;
}
}
break;
case PacketType.PlayerPositionUpdate:
float x = float.Parse(p.gData[0]);
float y = float.Parse(p.gData[1]);
_clients.Find(c => c.ID == p.senderID).x = x;
_clients.Find(c => c.ID == p.senderID).y = y;
SendToAll(p);
break;
case PacketType.PlayerVisualUpdate:
SendToAllExpect(p.senderID, p);
break;
}
}
public static void SendTo(string ID, Packet p)
{
Console.WriteLine("<:: " + p.packetType + ", " + ID);
_clients.Find(x => x.ID == ID).clientSocket.Send(p.toBytes());
}
public static void SendToAllExpect(string ID, Packet p)
{
Console.WriteLine("<:: " + p.packetType + " -Execpt");
foreach (ClientData c in _clients)
{
if (c.ID != ID)
{
c.clientSocket.Send(p.toBytes());
}
}
}
public static void SendToAll(Packet p)
{
foreach (ClientData c in _clients)
{
SendTo(c.ID, p);
}
}
}
class ClientData
{
public Thread clientThread;
public Socket clientSocket;
public string ID;
public string name;
public float x;
public float y;
public int health;
public int ammo;
public float gunRotation;
//??? - TODO: figure out animation values?
public ClientData()
{
ID = Guid.NewGuid().ToString();
clientThread = new Thread(Server.Data_IN);
clientThread.Start(clientSocket);
}
public ClientData(Socket _clientSocket)
{
ID = Guid.NewGuid().ToString();
clientSocket = _clientSocket;
clientThread = new Thread(Server.Data_IN);
clientThread.Start(clientSocket);
}
public void SendRegistrationPacket()
{
Packet p = new Packet(PacketType.PlayerRegistration, "server", ID);
clientSocket.Send(p.toBytes());
}
}
}
客户:
using System.Net;
using System.Net.Sockets;
using UnityEngine;
using ServerData;
using System;
using System.Threading;
using System.Collections.Generic;
public class MPplayer
{
public string ID;
public float x, y;
public float gunRot;
public int state;
public GameObject character;
public Vector2 lastPos;
public MPplayer(string _ID, float _x, float _y)
{
ID = _ID;
x = _x;
y = _y;
state = 0;
}
public void Update()
{
character.transform.position = new Vector2(x, y);
}
}
public class Client : MonoBehaviour
{
public Socket master;
public string name;
public string ID;
public UIHandler uihandler;
public IPAddress ip;
public bool isInit;
private Packet lastMsg;
private Packet currMsg;
public List<MPplayer> players;
public float health { get; set; }
public float ammo { get; set; }
public CharacterController cc;
public GameObject prefab;
public Vector2 lastPos;
private void Awake()
{
uihandler = GetComponent<UIHandler>();
players = new List<MPplayer>();
Application.runInBackground = true;
DontDestroyOnLoad(this);
}
private void Update()
{
if (uihandler.state == 0)
{
name = uihandler.clientName;
}
else if (uihandler.state == 2)
{
ip = IPAddress.Parse(uihandler.ip);
master = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEnd = new IPEndPoint(ip, 1337);
try
{
Debug.Log("connecting");
master.Connect(ipEnd);
uihandler.state = 3;
}
catch (SocketException ex)
{
uihandler.state = 0;
Debug.LogError("Error with connection:");
Debug.Log(ex.ToString());
}
}
else if(uihandler.state == 3)
{
if (!isInit)
{
Thread data_in = new Thread(Data_IN);
data_in.Start();
isInit = true;
}
if(lastMsg != currMsg)
{
DataManager(currMsg);
lastMsg = currMsg;
}
}
else if(uihandler.state == 4)
{
float speed = 5;
float vSpeed = Input.GetAxis("Vertical") * Time.deltaTime * speed;
float hSpeed = Input.GetAxis("Horizontal") * Time.deltaTime * speed;
players.Find(x => x.ID == this.ID).character.transform.Translate(hSpeed, vSpeed, 0);
Vector3 currPos = players.Find(x => x.ID == this.ID).character.transform.position;
if (lastPos != new Vector2(currPos.x, currPos.y))
{
lastPos = new Vector2(currPos.x, currPos.y);
Packet packet = new Packet(PacketType.PlayerPositionUpdate, ID, currPos.x.ToString(), currPos.y.ToString());
master.Send(packet.toBytes());
}
uihandler.stats.text = "Health: " + health + "\n" + "Ammo: " + ammo;
}
}
private void Data_IN()
{
byte[] buffer;
int readBytes;
for (; ; )
{
try
{
buffer = new byte[master.SendBufferSize];
readBytes = master.Receive(buffer);
if (readBytes > 0)
{
currMsg = new Packet(buffer);
}
}
catch (SocketException ex)
{
//TODO: jump over gracefully!
Debug.Log("The server has disconnected");
throw;
}
}
}
private void DataManager(Packet p)
{
Debug.Log("::>" + p.packetType);
switch (p.packetType)
{
case PacketType.SyncAllPlayers:
Debug.Log("Hey");
foreach (string s in p.gData)
{
string[] data = s.Split(',');
float sX = float.Parse(data[2]);
float sY = float.Parse(data[3]);
int ind = players.FindIndex(x => x.ID == data[0]);
if (ind >= 0)
{
players[ind].x = sX;
players[ind].y = sY;
}
else
{
MPplayer mPplayer = new MPplayer(data[0], sX, sY);
GameObject mpPrefab = Instantiate(prefab);
mpPrefab.transform.position = new Vector2(sX, sY);
mPplayer.character = mpPrefab;
players.Add(mPplayer);
Debug.Log("Adding Player: " + mPplayer.ID);
}
lastPos = data[0] == this.ID ? new Vector2(sX, sY) : lastPos;
uihandler.state = 4;
}
break;
case PacketType.PlayerRegistration:
this.ID = p.gData[0];
Packet packet = new Packet(PacketType.PlayerRegistration, this.ID);
master.Send(packet.toBytes());
break;
case PacketType.PlayerPositionUpdate:
int Index = players.FindIndex(i => i.ID == p.senderID);
float px = float.Parse(p.gData[0]);
float py = float.Parse(p.gData[1]);
players[Index].x = px;
players[Index].y = py;
players[Index].Update();
break;
case PacketType.PlayerStatUpdate:
if(p.gData[0] == this.ID)
{
health = float.Parse(p.gData[1]);
ammo = float.Parse(p.gData[2]);
}
break;
case PacketType.PlayerVisualUpdate:
int index = players.FindIndex(i => i.ID == p.gData[0]);
players[index].gunRot = float.Parse(p.gData[1]);
break;
default:
break;
}
}
}
服务器数据:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
namespace ServerData
{
public enum PacketType
{
PlayerRegistration,
PlayerJoined,
PlayerShootingRequest,
PlayerPositionUpdate,
PlayerStatUpdate,
PlayerVisualUpdate,
SyncAllPlayers,
}
[Serializable]
public class Packet
{
public string senderID;
public PacketType packetType;
public List<string> gData;
public int packetInt;
public bool packetBool;
public Packet(PacketType _type, string _senderID, params object[] data)
{
gData = new List<string>();
for (int i = 0; i < data.Length; i++)
{
gData.Add(data[i].ToString());
}
senderID = _senderID;
packetType = _type;
}
public Packet(byte[] bytes)
{
gData = new List<string>();
MemoryStream ms = new MemoryStream(bytes);
BinaryReader br = new BinaryReader(ms);
this.packetType = (PacketType)br.ReadInt32();
this.senderID = br.ReadString();
this.packetInt = br.ReadInt32();
this.packetBool = br.ReadBoolean();
int count = br.ReadInt32();
for (int i = 0; i < count; i++)
{
gData.Add(br.ReadString());
}
br.Close();
ms.Close();
}
public byte[] toBytes()
{
byte[] bytes;
using (MemoryStream ms = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
bw.Write((int)packetType);
bw.Write(senderID);
bw.Write(packetInt);
bw.Write(packetBool);
bw.Write(gData.Count);
for (int i = 0; i < gData.Count; i++)
{
bw.Write(gData[i]);
}
bw.Close();
}
ms.Flush();
bytes = ms.GetBuffer();
ms.Close();
}
return bytes;
}
public static string GetIp4Adress()
{
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress ip in ips)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
return "127.0.0.1";
}
}
}