added message group, and bad example of using them for voice comms
parent
51538416e6
commit
d18ddf1dba
|
|
@ -2257,7 +2257,6 @@ GameObject:
|
|||
- component: {fileID: 1434745019}
|
||||
- component: {fileID: 1434745022}
|
||||
- component: {fileID: 1434745023}
|
||||
- component: {fileID: 1434745024}
|
||||
m_Layer: 0
|
||||
m_Name: Dissonance
|
||||
m_TagString: Untagged
|
||||
|
|
@ -2278,7 +2277,7 @@ MonoBehaviour:
|
|||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
dissonanceId:
|
||||
comms: {fileID: 0}
|
||||
comms: {fileID: 1434745021}
|
||||
manager: {fileID: 1099803616}
|
||||
--- !u!4 &1434745020
|
||||
Transform:
|
||||
|
|
@ -2368,25 +2367,6 @@ MonoBehaviour:
|
|||
_tokens: []
|
||||
_roomName: Global
|
||||
_useTrigger: 0
|
||||
--- !u!114 &1434745024
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1434745018}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 03a4d4e1a7fd74c7ab2eccca4ce168db, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
host:
|
||||
port: 0
|
||||
userid: -1
|
||||
room:
|
||||
playerPrefab: {fileID: 0}
|
||||
prefabs: []
|
||||
connected: 0
|
||||
--- !u!1 &1484033255
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class NetworkGUI : MonoBehaviour
|
|||
{
|
||||
if(sendInput.text != "")
|
||||
{
|
||||
networkManager.sendTo(0,sendInput.text);
|
||||
networkManager.sendTo(NetworkManager.MessageType.OTHERS,sendInput.text);
|
||||
}
|
||||
}
|
||||
public void handleLogin()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using UnityEngine;
|
|||
using Dissonance;
|
||||
public class NetworkManager : MonoBehaviour
|
||||
{
|
||||
public enum MessageType { OTHERS=0,ALL=1,OTHERS_ORDERED=2,ALL_ORDERED=3};
|
||||
public string host;
|
||||
public int port;
|
||||
#region private members
|
||||
|
|
@ -363,10 +364,19 @@ public class NetworkManager : MonoBehaviour
|
|||
}
|
||||
public void leave()
|
||||
{
|
||||
SendNetworkMessage("2:-1\n");
|
||||
SendNetworkMessage("2:-1");
|
||||
}
|
||||
public void sendTo(int type, string message)
|
||||
public void sendTo(MessageType type, string message)
|
||||
{
|
||||
SendNetworkMessage("3:" + type + ":" + message);
|
||||
SendNetworkMessage("3:" + (int)type + ":" + message);
|
||||
}
|
||||
public void sendToGroup(string group, string message)
|
||||
{
|
||||
SendNetworkMessage("4:" + group + ":" + message);
|
||||
}
|
||||
//changes the designated group that sendto(4) will go to
|
||||
public void setupMessageGroup(string groupname, int[] userids)
|
||||
{
|
||||
SendNetworkMessage("5:" + groupname + ":" + String.Join(":", userids));
|
||||
}
|
||||
}
|
||||
|
|
@ -32,8 +32,8 @@ public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
|||
public bool IsTracking => true;
|
||||
bool isMaster = false;
|
||||
|
||||
|
||||
|
||||
public List<int> closePlayers = new List<int>(); //for testing audio communications
|
||||
public bool changeClosePlayers = true;
|
||||
void Start()
|
||||
{
|
||||
myObject.owner = this;
|
||||
|
|
@ -47,19 +47,23 @@ public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
|||
//handle dissonance comms
|
||||
if(isLocal)
|
||||
{
|
||||
|
||||
//if we're not speaking, and the comms say we are, send a speaking event, which will be received on other network players and sent to their comms accordingly
|
||||
if(commsNetwork.comms.FindPlayer(dissonanceID).IsSpeaking != isSpeaking) //unfortunately, there does not seem to be an event for this
|
||||
if (commsNetwork.comms.FindPlayer(dissonanceID).IsSpeaking != isSpeaking) //unfortunately, there does not seem to be an event for this
|
||||
{
|
||||
isSpeaking = !isSpeaking;
|
||||
manager.sendTo(0, "4," + (isSpeaking?1:0) + ";");
|
||||
manager.sendTo(NetworkManager.MessageType.OTHERS, "4," + (isSpeaking?1:0) + ";");
|
||||
if (!isSpeaking)
|
||||
{
|
||||
lastAudioId = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void handlePlayerJoined(NetworkPlayer player)
|
||||
|
|
@ -71,7 +75,7 @@ public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
|||
{
|
||||
if(kvp.Value.owner == this && kvp.Value.prefabName != "")
|
||||
{
|
||||
manager.sendTo(0, "7," + kvp.Value.networkId + "," + kvp.Value.prefabName);
|
||||
manager.sendTo(NetworkManager.MessageType.OTHERS, "7," + kvp.Value.networkId + "," + kvp.Value.prefabName);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -206,14 +210,21 @@ public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
|||
|
||||
public void sendAudioData(ArraySegment<byte> data)
|
||||
{
|
||||
if (changeClosePlayers)
|
||||
{
|
||||
manager.setupMessageGroup("close", closePlayers.ToArray());
|
||||
changeClosePlayers = false;
|
||||
}
|
||||
string b64_data = Convert.ToBase64String(data.Array,data.Offset,data.Count);
|
||||
manager.sendTo(0, "2,"+b64_data + ","+ (lastAudioId++) +";");
|
||||
//manager.sendTo(NetworkManager.MessageType.OTHERS, "2," + b64_data + "," + (lastAudioId++) + ";");
|
||||
manager.sendToGroup("close", "2,"+b64_data + ","+ (lastAudioId++) +";");
|
||||
}
|
||||
|
||||
public void setDissonanceID(string id) //this sort of all initializes dissonance
|
||||
{
|
||||
dissonanceID = id;
|
||||
manager.sendTo(0, "3," + id+";");
|
||||
Debug.Log("here");
|
||||
manager.sendTo(NetworkManager.MessageType.OTHERS, "3," + id+";");
|
||||
commsNetwork.comms.TrackPlayerPosition(this);
|
||||
}
|
||||
|
||||
|
|
@ -228,12 +239,12 @@ public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
|||
byte[] data = obj.getSyncMessage();
|
||||
if (obj == myObject)
|
||||
{
|
||||
manager.sendTo(0, "1," + Convert.ToBase64String(data));
|
||||
manager.sendTo(NetworkManager.MessageType.OTHERS, "1," + Convert.ToBase64String(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
manager.sendTo(0, "5," + obj.networkId + "," + Convert.ToBase64String(data));
|
||||
manager.sendTo(NetworkManager.MessageType.OTHERS, "5," + obj.networkId + "," + Convert.ToBase64String(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +266,7 @@ public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
|||
instance.owner = this;
|
||||
manager.objects.Add(instance.networkId, instance);
|
||||
|
||||
manager.sendTo(0, "7," + networkId + "," + prefabName);
|
||||
manager.sendTo(NetworkManager.MessageType.OTHERS, "7," + networkId + "," + prefabName); //only sent to others, as I already instantiated this. Nice that it happens immediately.
|
||||
return instance;
|
||||
}
|
||||
return null;
|
||||
|
|
@ -264,7 +275,7 @@ public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
|||
public void networkDestroy(string networkId)
|
||||
{
|
||||
if (!manager.objects.ContainsKey(networkId) || manager.objects[networkId].owner != this || !isLocal) return; //must be the local owner of the object to destroy it
|
||||
manager.sendTo(3, "8," + networkId); //send to all, which will make me delete as well
|
||||
manager.sendTo(NetworkManager.MessageType.ALL_ORDERED, "8," + networkId); //send to all, which will make me delete as well
|
||||
}
|
||||
|
||||
public void takeOwnership(string networkId)
|
||||
|
|
@ -272,7 +283,7 @@ public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
|||
if (!manager.objects.ContainsKey(networkId) || !isLocal) return; //must exist and be the the local player
|
||||
|
||||
manager.objects[networkId].owner = this; //immediately successful
|
||||
manager.sendTo(2, "6," + networkId); //must be ordered, so that ownership transfers are not confused
|
||||
manager.sendTo(NetworkManager.MessageType.ALL_ORDERED, "6," + networkId); //must be ordered, so that ownership transfers are not confused. Also sent to all players, so that multiple simultaneous requests will result in the same outcome.
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ using UnityEngine;
|
|||
|
||||
namespace Dissonance
|
||||
{
|
||||
[RequireComponent(typeof(DissonanceComms),typeof(NetworkManager))]
|
||||
public class VelCommsNetwork : MonoBehaviour, ICommsNetwork
|
||||
{
|
||||
public ConnectionStatus Status
|
||||
|
|
@ -95,6 +94,7 @@ namespace Dissonance
|
|||
|
||||
public void playerJoined(string id)
|
||||
{
|
||||
Debug.Log("dissonance player joined");
|
||||
PlayerJoined(id, initSettings);
|
||||
RoomEvent re = new RoomEvent();
|
||||
re.Joined = true;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ INCOMING MESSSAGES (sent by clients)
|
|||
|
||||
Join server - Provide a username and password. If valid, the server will create a new session for you, and send you message saying connected with the session id. It will mark that session as logged in. All subsequent commands require logged in. If you are in another session, it will end that session.
|
||||
|
||||
0:username:password\n (note, usernames and passwords cannot contain :s)
|
||||
0:username:password\n (note, usernames and passwords cannot contain colons :s)
|
||||
|
||||
Get rooms - Assuming the session is logged in, you can get a list of public rooms. The server will retrieve the list of public rooms from its database, including who is in those rooms and send them to the client.
|
||||
|
||||
|
|
@ -46,19 +46,25 @@ rooms - a list of rooms on the server, with counts
|
|||
|
||||
Unity-side.
|
||||
|
||||
Instantiate message creates a network id, assigning that player as owner
|
||||
--A network id is a creator_id + incrementing number, which uniquely identifies it. -1 is used for scene objects.
|
||||
The server is relatively stupid, by design, as it's just a relay (for now). The Unity side is pretty complex.
|
||||
|
||||
Take ownership reassigns a player as owner. Must use the order_maintained parts above.
|
||||
NetworkManager - Deals with instantiating NetworkPlayers, and dealing with join, left, new master client events. Also manages the list of NetworkObjects. It maintains a list of prefabs that can be instantiated, as well as the prefab to use for players.
|
||||
|
||||
Update network id sends a packet to specifically serialize parts of an object that have changed. A change flag indicates what parts have changed.
|
||||
NetworkPlayer - One of these will be instantiated for each player that joins the "room". Most application communication happens by calling methods on this object. Voice comms are also handled within this object. Only one NetworkPlayer "isLocal". The others are remote. The local network player is the one that can modify it's "owned" network objects. It also has a special networkobject representing itself (setup within the prefab, not part of the networkmanager list). This is where most of the user behavior is going to go (e.g. an avatar).
|
||||
|
||||
NetworkObject - Something that can be owned by a network player, who is responsible for updating it. Only the owner network player can/should modify a network object, whether locally or in response to a received message from the local version. NetworkObjects are delineated by an session-unique id, which consists of the creator's userid + "-" + an increasing number designated by the creator. Only local NetworkPlayers should send instantiate message, which contain this id. This class should be extended to sync and send messages. Scenes are basically built from NetworkObjects. Scene's can also start with network objects. Those are known by all, and start with "-1-increasing". That should happen the same on all clients, and is done locally at the start of the networkmanager. An example of a NetworkObject is SyncTransform, which is a simple one that keeps an object's position and orientation synchronized.
|
||||
|
||||
Ownership of objects changes regularly. Any local networkplayer can send a message to take ownership of a networkid. That client immediately assumes ownership. The message is sent to the network, and will be ordered with any other ownership messages. So, if two clients try to get ownership at the same time, both will assume ownership, but one will happen after the other. This means that the one who was first will quickly lose ownership.
|
||||
|
||||
An interesting problem is what to do when new clients join. This is partially left up to the developer. Any objects that are instantiated (or scene objects that are deleted) will be automatically handled. (todo-include an instantiation packet).
|
||||
|
||||
Todo:
|
||||
|
||||
Demonstrate how to deal with partial updates
|
||||
Scene objects that are destroyed need to be buffered to new clients.
|
||||
No physics yet
|
||||
Need to address what happens when you join a new room
|
||||
Need to add something like an RPC message that gets delivered through the network object, rather than the player. Could be used for syncing
|
||||
Documentation
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,13 @@ def send_room_message(roomName, message, exclude_client=None): #not guaranteed t
|
|||
if (exclude_client != None) and (c.id == exclude_client.id): continue
|
||||
send_client_message(c,message)
|
||||
|
||||
def send_group_message(group, message):
|
||||
for client_id in group:
|
||||
if client_id in client_dict:
|
||||
client = client_dict[client_id] #not sure if we need to lock this...I've heard that basic dictionary access is thread safe
|
||||
send_client_message(client, message)
|
||||
|
||||
|
||||
def send_client_message(client, message):
|
||||
client.message_lock.acquire()
|
||||
client.message_queue.append(message)
|
||||
|
|
@ -153,6 +160,17 @@ def decode_message(client,message):
|
|||
send_synced_room_message(client.room,f"3:{client.id}:{decodedMessage[2]}\n",client)
|
||||
elif subMessageType == '3': #everyone including the client, ensuring order
|
||||
send_synced_room_message(client.room,f"3:{client.id}:{decodedMessage[2]}\n")
|
||||
if messageType == '4' and len(decodedMessage) > 2:
|
||||
if decodedMessage[1] in client.groups:
|
||||
send_group_message(client.groups[decodedMessage[1]],f"3:{client.id}:{decodedMessage[2]}\n")
|
||||
if messageType == '5' and len(decodedMessage) > 2:
|
||||
#specify a new group of clients
|
||||
group_clients = []
|
||||
for c in decodedMessage[2:]:
|
||||
try: group_clients.append(int(c))
|
||||
except: pass
|
||||
client.groups[decodedMessage[1]] = group_clients
|
||||
print("got new group: " + str(client.groups))
|
||||
|
||||
def client_read_thread(conn, addr, client):
|
||||
global rooms
|
||||
|
|
@ -221,6 +239,7 @@ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|||
logged_in=False,
|
||||
username='',
|
||||
room='',
|
||||
groups={}, # a dictionary of groups that you may send to. groups are lists of user ids
|
||||
write_thread_dead=False
|
||||
)
|
||||
client_lock.acquire()
|
||||
|
|
|
|||
Loading…
Reference in New Issue