Make so that player see eachothers capsules staticly

This commit is contained in:
Sofia 2017-05-09 06:13:30 +03:00
parent 0df99b4bc8
commit eb23f474c5
10 changed files with 193 additions and 28 deletions

View File

@ -34,7 +34,7 @@ namespace Cyber.Entities {
/// set if they exist already (eg. the server has sent them over). These /// set if they exist already (eg. the server has sent them over). These
/// ids should be from <see cref="SyncDB.GetEntityIDs"/>. To create new /// ids should be from <see cref="SyncDB.GetEntityIDs"/>. To create new
/// ids, leave as the default (null).</param> /// ids, leave as the default (null).</param>
public GameObject Spawn(EntityType type, Vector3 position, uint[] ids = null) { public GameObject Spawn(EntityType type, Vector3 position, int[] ids = null) {
GameObject Spawned = null; GameObject Spawned = null;
switch (type) { switch (type) {
case EntityType.PC: case EntityType.PC:
@ -55,7 +55,6 @@ namespace Cyber.Entities {
} }
private void Start() { private void Start() {
Spawn(EntityType.PC, new Vector3());
} }
private void Update() { private void Update() {

View File

@ -14,6 +14,6 @@ namespace Cyber.Entities {
/// The ID this syncable component can be found with from its parent /// The ID this syncable component can be found with from its parent
/// <see cref="SyncDB"/>. /// <see cref="SyncDB"/>.
/// </summary> /// </summary>
public uint ID; public int ID;
} }
} }

View File

@ -15,8 +15,8 @@ namespace Cyber.Entities {
typeof(Character) typeof(Character)
}; };
private uint IDCounter = 0; private int IDCounter = 0;
private Dictionary<uint, SyncBase> Database = new Dictionary<uint, SyncBase>(); private Dictionary<int, SyncBase> Database = new Dictionary<int, SyncBase>();
/// <summary> /// <summary>
/// Add an entity to the database with the given IDs. /// Add an entity to the database with the given IDs.
@ -24,7 +24,7 @@ namespace Cyber.Entities {
/// <param name="gameObject">Game object.</param> /// <param name="gameObject">Game object.</param>
/// <param name="ids">The IDs. Should be from <see cref="GetEntityIDs"/> or /// <param name="ids">The IDs. Should be from <see cref="GetEntityIDs"/> or
/// <see cref="GetNewEntityIDs"/>, since the order is important.</param> /// <see cref="GetNewEntityIDs"/>, since the order is important.</param>
public void AddEntity(GameObject gameObject, uint[] ids) { public void AddEntity(GameObject gameObject, int[] ids) {
int Index = 0; int Index = 0;
for (int i = 0; i < SyncableClasses.Length; i++) { for (int i = 0; i < SyncableClasses.Length; i++) {
SyncBase Syncable = (SyncBase)gameObject.GetComponent(SyncableClasses[i]); SyncBase Syncable = (SyncBase)gameObject.GetComponent(SyncableClasses[i]);
@ -44,8 +44,8 @@ namespace Cyber.Entities {
/// <param name="newIDs">Whether or not new IDs are created. /// <param name="newIDs">Whether or not new IDs are created.
/// <see cref="GetNewEntityIDs"/> is a shorthand for this function with /// <see cref="GetNewEntityIDs"/> is a shorthand for this function with
/// this parameter set to true.</param> /// this parameter set to true.</param>
public uint[] GetEntityIDs(GameObject gameObject, bool newIDs = false) { public int[] GetEntityIDs(GameObject gameObject, bool newIDs = false) {
List<uint> IDs = new List<uint>(); List<int> IDs = new List<int>();
for (int i = 0; i < SyncableClasses.Length; i++) { for (int i = 0; i < SyncableClasses.Length; i++) {
SyncBase Syncable = (SyncBase)gameObject.GetComponent(SyncableClasses[i]); SyncBase Syncable = (SyncBase)gameObject.GetComponent(SyncableClasses[i]);
if (Syncable != null) { if (Syncable != null) {
@ -55,7 +55,7 @@ namespace Cyber.Entities {
IDs.Add(Syncable.ID); IDs.Add(Syncable.ID);
} }
} }
uint[] IDArray = new uint[IDs.Count]; int[] IDArray = new int[IDs.Count];
for (int i = 0; i < IDs.Count; i++) { for (int i = 0; i < IDs.Count; i++) {
IDArray[i] = IDs[i]; IDArray[i] = IDs[i];
} }
@ -68,7 +68,7 @@ namespace Cyber.Entities {
/// </summary> /// </summary>
/// <returns>The new IDs.</returns> /// <returns>The new IDs.</returns>
/// <param name="gameObject">Game object.</param> /// <param name="gameObject">Game object.</param>
public uint[] GetNewEntityIDs(GameObject gameObject) { public int[] GetNewEntityIDs(GameObject gameObject) {
return GetEntityIDs(gameObject, true); return GetEntityIDs(gameObject, true);
} }
@ -76,7 +76,7 @@ namespace Cyber.Entities {
/// Get a synced component by its ID. /// Get a synced component by its ID.
/// </summary> /// </summary>
/// <param name="id">The ID.</param> /// <param name="id">The ID.</param>
public SyncBase Get(uint id) { public SyncBase Get(int id) {
return Database[id]; return Database[id];
} }
@ -84,17 +84,17 @@ namespace Cyber.Entities {
/// Creates a new ID which isn't in use yet. /// Creates a new ID which isn't in use yet.
/// </summary> /// </summary>
/// <returns>A new, free ID.</returns> /// <returns>A new, free ID.</returns>
public uint CreateID() { public int CreateID() {
uint ID; int ID;
try { try {
ID = IDCounter++; ID = IDCounter++;
} catch (OverflowException) { } catch (OverflowException) {
ID = 0; ID = 0;
IDCounter = 1; IDCounter = 1;
} }
while (Database.ContainsKey(ID) && ID < uint.MaxValue) { while (Database.ContainsKey(ID) && ID < int.MaxValue) {
ID++; ID++;
if (ID < uint.MaxValue - 1) if (ID < int.MaxValue - 1)
IDCounter = ID + 1; IDCounter = ID + 1;
} }
if (Database.ContainsKey(ID)) { if (Database.ContainsKey(ID)) {

View File

@ -1,4 +1,5 @@
using Cyber.Console; using Cyber.Console;
using Cyber.Entities;
using Cyber.Networking.Messages; using Cyber.Networking.Messages;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@ -24,11 +25,13 @@ namespace Cyber.Networking.Clientside {
private static Client Singleton; private static Client Singleton;
private Spawner Spawner;
/// <summary> /// <summary>
/// The player of this client /// The player of this client
/// </summary> /// </summary>
private CConnectedPlayer Player; private CConnectedPlayer Player;
private List<CConnectedPlayer> Players = new List<CConnectedPlayer>(); private Dictionary<int, CConnectedPlayer> Players = new Dictionary<int, CConnectedPlayer>();
/// <summary> /// <summary>
/// Creates the client and sets it as the signleton. /// Creates the client and sets it as the signleton.
@ -86,6 +89,11 @@ namespace Cyber.Networking.Clientside {
return Singleton.NetClient.isConnected; return Singleton.NetClient.isConnected;
} }
private void Start() {
Spawner = GetComponent<Spawner>();
}
private bool LaunchClient(string ip, int port) { private bool LaunchClient(string ip, int port) {
if (Running) { if (Running) {
return false; return false;
@ -104,6 +112,7 @@ namespace Cyber.Networking.Clientside {
NetClient.RegisterHandler(PktType.TextMessage, HandlePacket); NetClient.RegisterHandler(PktType.TextMessage, HandlePacket);
NetClient.RegisterHandler(PktType.Identity, HandlePacket); NetClient.RegisterHandler(PktType.Identity, HandlePacket);
NetClient.RegisterHandler(PktType.MassIdentity, HandlePacket); NetClient.RegisterHandler(PktType.MassIdentity, HandlePacket);
NetClient.RegisterHandler(PktType.SpawnEntity, HandlePacket);
NetClient.RegisterHandler(MsgType.Connect, OnConnected); NetClient.RegisterHandler(MsgType.Connect, OnConnected);
NetClient.RegisterHandler(MsgType.Disconnect, OnDisconnected); NetClient.RegisterHandler(MsgType.Disconnect, OnDisconnected);
@ -134,15 +143,27 @@ namespace Cyber.Networking.Clientside {
Debug.Log(Conn.ConnectionID + " connected!"); Debug.Log(Conn.ConnectionID + " connected!");
Term.Println(Conn.ConnectionID + " connected!"); Term.Println(Conn.ConnectionID + " connected!");
} }
Players.Add(Conn); Players.Add(Conn.ConnectionID, Conn);
break; break;
case (PktType.MassIdentity): case (PktType.MassIdentity):
MassIdentityPkt Identities = new MassIdentityPkt(); MassIdentityPkt Identities = new MassIdentityPkt();
Identities.Deserialize(msg.reader); Identities.Deserialize(msg.reader);
foreach (int currId in Identities.IdList) { foreach (int currId in Identities.IdList) {
Players.Add(new CConnectedPlayer(currId)); Players.Add(currId, new CConnectedPlayer(currId));
} }
break; break;
case (PktType.SpawnEntity):
SpawnEntityPkt SpawnPkt = new SpawnEntityPkt();
SpawnPkt.Deserialize(msg.reader);
EntityType EntityType = SpawnPkt.EntityType;
// Check if you are the owner and if they are spawning an NPC
if (SpawnPkt.OwnerID == Player.ConnectionID && EntityType == EntityType.NPC) {
// Change it into a PC instead.
EntityType = EntityType.PC;
}
Spawner.Spawn(EntityType, SpawnPkt.Position, SpawnPkt.SyncBaseIDList);
break;
default: default:
Debug.LogError("Received an unknown packet, id: " + msg.msgType); Debug.LogError("Received an unknown packet, id: " + msg.msgType);
Term.Println("Received an unknown packet, id: " + msg.msgType); Term.Println("Received an unknown packet, id: " + msg.msgType);

View File

@ -8,16 +8,30 @@ namespace Cyber.Networking.Messages {
/// </summary> /// </summary>
public class MassIdentityPkt : MessageBase { public class MassIdentityPkt : MessageBase {
/// <summary>
/// List of Connection ID's to send
/// </summary>
public int[] IdList; public int[] IdList;
/// <summary>
/// Create a Mass Identity packet used to send a list of currently online connections.
/// </summary>
/// <param name="idList"></param>
public MassIdentityPkt(int[] idList) { public MassIdentityPkt(int[] idList) {
IdList = idList; IdList = idList;
} }
/// <summary>
/// Parameter-less constructor using when deserializing the message.
/// </summary>
public MassIdentityPkt() { public MassIdentityPkt() {
} }
/// <summary>
/// Used to deserialize a message received via networking.
/// </summary>
/// <param name="reader"></param>
public override void Deserialize(NetworkReader reader) { public override void Deserialize(NetworkReader reader) {
byte[][] ByteArray = new byte[4][]; byte[][] ByteArray = new byte[4][];
ByteArray[0] = reader.ReadBytesAndSize(); ByteArray[0] = reader.ReadBytesAndSize();
@ -27,6 +41,10 @@ namespace Cyber.Networking.Messages {
IdList = NetworkHelper.DeserializeIntArray(ByteArray); IdList = NetworkHelper.DeserializeIntArray(ByteArray);
} }
/// <summary>
/// Used to serialize the message before it is sent.
/// </summary>
/// <param name="writer"></param>
public override void Serialize(NetworkWriter writer) { public override void Serialize(NetworkWriter writer) {
byte[][] ByteArray = NetworkHelper.SerializeIntArray(IdList); byte[][] ByteArray = NetworkHelper.SerializeIntArray(IdList);
writer.WriteBytesFull(ByteArray[0]); writer.WriteBytesFull(ByteArray[0]);

View File

@ -0,0 +1,86 @@

using Cyber.Entities;
using UnityEngine;
using UnityEngine.Networking;
namespace Cyber.Networking.Messages {
/// <summary>
/// Packet which tells the client to spawn an entity corresponding to the data inside.
/// </summary>
public class SpawnEntityPkt : MessageBase {
/// <summary>
/// The type of entity to spawn.
/// </summary>
public EntityType EntityType;
/// <summary>
/// The position of the entity, where it should be spawned
/// </summary>
public Vector3 Position;
/// <summary>
/// The List of Sync ID's for the entity.
/// </summary>
public int[] SyncBaseIDList;
/// <summary>
/// Connection ID of the owner of this entity
/// </summary>
public int OwnerID;
/// <summary>
/// Create a packet of information about spawning an entity to send the clients.
/// </summary>
/// <param name="entityType">Type of entity to spawn.</param>
/// <param name="position">Position where the entity will be spawned.</param>
/// <param name="syncIDList">List of Sync ID's for the entity.</param>
/// <param name="ownerID">The Connection ID who owns this entity (or -1).</param>
public SpawnEntityPkt(EntityType entityType, Vector3 position, int[] syncIDList, int ownerID) {
EntityType = entityType;
Position = position;
SyncBaseIDList = syncIDList;
OwnerID = ownerID;
}
/// <summary>
/// Parameter-less constructor using when deserializing the message.
/// </summary>
public SpawnEntityPkt() {
}
/// <summary>
/// Used to deserialize a message received via networking.
/// </summary>
/// <param name="reader"></param>
public override void Deserialize(NetworkReader reader) {
EntityType = (EntityType) reader.ReadInt16();
Position = reader.ReadVector3();
OwnerID = reader.ReadInt32();
byte[][] ByteArray = new byte[4][];
ByteArray[0] = reader.ReadBytesAndSize();
ByteArray[1] = reader.ReadBytesAndSize();
ByteArray[2] = reader.ReadBytesAndSize();
ByteArray[3] = reader.ReadBytesAndSize();
SyncBaseIDList = NetworkHelper.DeserializeIntArray(ByteArray);
}
/// <summary>
/// Used to serialize the message before it is sent.
/// </summary>
/// <param name="writer"></param>
public override void Serialize(NetworkWriter writer) {
writer.Write((short) EntityType);
writer.Write(Position);
writer.Write(OwnerID);
byte[][] ByteArray = NetworkHelper.SerializeIntArray(SyncBaseIDList);
writer.WriteBytesFull(ByteArray[0]);
writer.WriteBytesFull(ByteArray[1]);
writer.WriteBytesFull(ByteArray[2]);
writer.WriteBytesFull(ByteArray[3]);
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: bcdedfecd6ba4a04397852ba038f0939
timeCreated: 1494296640
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -20,5 +20,10 @@ namespace Cyber.Networking {
/// Packet containing the identification details about everyone on the server before the client connected. /// Packet containing the identification details about everyone on the server before the client connected.
/// </summary> /// </summary>
public const short MassIdentity = 202; public const short MassIdentity = 202;
/// <summary>
/// Packet containing necessary information about spawning an entity.
/// </summary>
public const short SpawnEntity = 203;
} }
} }

View File

@ -11,9 +11,10 @@ namespace Cyber.Networking.Serverside {
/// Server-class used to host a server and communicate to clients. /// Server-class used to host a server and communicate to clients.
/// </summary> /// </summary>
/// \todo Change connection channels to Unreliable to optimize ping. /// \todo Change connection channels to Unreliable to optimize ping.
/// \todo Remove PC/NPC and make a Human-type entity instead.
public class Server : MonoBehaviour { public class Server : MonoBehaviour {
private List<SConnectedPlayer> Players = new List<SConnectedPlayer>(); private Dictionary<int, SConnectedPlayer> Players = new Dictionary<int, SConnectedPlayer>();
private static Server Singleton; private static Server Singleton;
private Spawner Spawner; private Spawner Spawner;
@ -131,27 +132,50 @@ namespace Cyber.Networking.Serverside {
// Internal built-in event handler // Internal built-in event handler
private void OnConnected(NetworkMessage msg) { private void OnConnected(NetworkMessage msg) {
// Get client's ID
int Id = msg.conn.connectionId; int Id = msg.conn.connectionId;
Debug.Log(Id + " connected!"); Debug.Log(Id + " connected!");
Term.Println(Id + " connected!"); Term.Println(Id + " connected!");
// Send all other clients a notification and collect their id's
int[] IdList = new int[Players.Count]; int[] IdList = new int[Players.Count];
for (int i = 0; i < Players.Count; i++) { int TempCounter = 0;
SConnectedPlayer P = Players[i]; foreach (SConnectedPlayer P in Players.Values) {
IdList[i] = P.ConnectionID; IdList[TempCounter++] = P.ConnectionID;
NetworkServer.SendToClient(P.ConnectionID, PktType.Identity, new IdentityPkt(Id, false)); NetworkServer.SendToClient(P.ConnectionID, PktType.Identity, new IdentityPkt(Id, false));
} }
foreach (int id in IdList) {
Debug.Log("id: " + id); // Then send the client a list of all other clients
}
NetworkServer.SendToClient(Id, PktType.MassIdentity, new MassIdentityPkt(IdList)); NetworkServer.SendToClient(Id, PktType.MassIdentity, new MassIdentityPkt(IdList));
// Add the player to the list
SConnectedPlayer Player = new SConnectedPlayer(msg.conn.connectionId); SConnectedPlayer Player = new SConnectedPlayer(msg.conn.connectionId);
Players.Add(Player); Players.Add(Id, Player);
// Send the previously collected list to the player
NetworkServer.SendToClient(msg.conn.connectionId, NetworkServer.SendToClient(msg.conn.connectionId,
PktType.Identity, new IdentityPkt(msg.conn.connectionId, true)); PktType.Identity, new IdentityPkt(msg.conn.connectionId, true));
// Spawn the player and collet it's IDs
Vector3 Position = new Vector3(0, 0, 0);
GameObject Obj = Spawner.Spawn(EntityType.NPC, Position);
int[] EntityIdList = Spawner.SyncDB.GetEntityIDs(Obj);
Player.Character = Obj.GetComponent<Character>();
NetworkServer.SendToAll(PktType.SpawnEntity, new SpawnEntityPkt(EntityType.NPC, Position, EntityIdList, Id));
// Send every entity to the player who just connected.
foreach (var Entry in Players) {
if (Entry.Key == Id) {
continue;
}
Character Char = Players[Entry.Key].Character;
GameObject CurrObj = Char.gameObject;
int[] CurrEntityIdList = Spawner.SyncDB.GetNewEntityIDs(CurrObj);
NetworkServer.SendToClient(Id, PktType.SpawnEntity,
new SpawnEntityPkt(EntityType.NPC, CurrObj.transform.position, CurrEntityIdList, Entry.Key));
}
} }
private void OnDisconnected(NetworkMessage msg) { private void OnDisconnected(NetworkMessage msg) {

View File

@ -47,5 +47,5 @@ Version 0.1.0 - Gigantic
- [x] ...With movement capabilities. - [x] ...With movement capabilities.
- [ ] Client-server connectivity, players can see each other moving around. - [ ] Client-server connectivity, players can see each other moving around.
- [x] 1. Client-server connectivity: the clients can connect to the server and send some messages back and forth. - [x] 1. Client-server connectivity: the clients can connect to the server and send some messages back and forth.
- [ ] 2. Players can see eachothers capsule-characters and send commands to move them around. - [x] 2. Players can see eachothers capsule-characters and send commands to move them around.
- [ ] 3. Basic syncing (Send sync packages at certain intervals) in order to sync positions correctly between server and client. - [ ] 3. Basic syncing (Send sync packages at certain intervals) in order to sync positions correctly between server and client.