working position updates in unity
parent
a9793807be
commit
b5ab2afc7d
|
|
@ -0,0 +1 @@
|
||||||
|
.DS_Store
|
||||||
|
|
@ -40,6 +40,10 @@ public class NetworkGUI : MonoBehaviour
|
||||||
string s = m.type + ":" + m.sender +":" + m.text;
|
string s = m.type + ":" + m.sender +":" + m.text;
|
||||||
messageBuffer.Add(s);
|
messageBuffer.Add(s);
|
||||||
messages.text = "";
|
messages.text = "";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(messageBuffer.Count > 10)
|
if(messageBuffer.Count > 10)
|
||||||
{
|
{
|
||||||
messageBuffer.RemoveAt(0);
|
messageBuffer.RemoveAt(0);
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,12 @@ public class NetworkManager : MonoBehaviour
|
||||||
#region private members
|
#region private members
|
||||||
private TcpClient socketConnection;
|
private TcpClient socketConnection;
|
||||||
private Thread clientReceiveThread;
|
private Thread clientReceiveThread;
|
||||||
public int userid;
|
public int userid = -1;
|
||||||
|
public string room;
|
||||||
int messagesReceived = 0;
|
int messagesReceived = 0;
|
||||||
|
public GameObject playerPrefab;
|
||||||
|
public Dictionary<int, NetworkPlayer> players = new Dictionary<int, NetworkPlayer>();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
// Use this for initialization
|
// Use this for initialization
|
||||||
public class Message
|
public class Message
|
||||||
|
|
@ -27,6 +31,7 @@ public class NetworkManager : MonoBehaviour
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
ConnectToTcpServer();
|
ConnectToTcpServer();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMessage(Message m)
|
private void addMessage(Message m)
|
||||||
|
|
@ -42,6 +47,59 @@ public class NetworkManager : MonoBehaviour
|
||||||
lock(receivedMessages) {
|
lock(receivedMessages) {
|
||||||
foreach(Message m in receivedMessages)
|
foreach(Message m in receivedMessages)
|
||||||
{
|
{
|
||||||
|
if(m.type == 0) //when you join the server
|
||||||
|
{
|
||||||
|
this.userid = m.sender;
|
||||||
|
Debug.Log("joined server");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.type == 2)
|
||||||
|
{
|
||||||
|
//if this message is for me, that means I joined a new room...
|
||||||
|
if (this.userid == m.sender)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<int, NetworkPlayer> kvp in players)
|
||||||
|
{
|
||||||
|
Destroy(kvp.Value.gameObject);
|
||||||
|
}
|
||||||
|
players.Clear(); //we clear the list, but will recreate as we get messages from people in our room
|
||||||
|
|
||||||
|
if (m.text != "")
|
||||||
|
{
|
||||||
|
NetworkPlayer player = GameObject.Instantiate<GameObject>(playerPrefab).GetComponent<NetworkPlayer>();
|
||||||
|
player.userid = m.sender;
|
||||||
|
players.Add(userid, player);
|
||||||
|
player.room = m.text;
|
||||||
|
player.manager = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //not for me, a player is joining or leaving
|
||||||
|
{
|
||||||
|
NetworkPlayer me = players[userid];
|
||||||
|
|
||||||
|
if (me.room != m.text)
|
||||||
|
{
|
||||||
|
//we got a left message, kill it
|
||||||
|
Destroy(players[m.sender].gameObject);
|
||||||
|
players.Remove(m.sender);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//we got a join mesage, create it
|
||||||
|
NetworkPlayer player = GameObject.Instantiate<GameObject>(playerPrefab).GetComponent<NetworkPlayer>();
|
||||||
|
player.room = m.text;
|
||||||
|
player.userid = m.sender;
|
||||||
|
player.manager = this;
|
||||||
|
players.Add(m.sender, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(m.type == 3)
|
||||||
|
{
|
||||||
|
|
||||||
|
players[m.sender]?.handleMessage(m);
|
||||||
|
|
||||||
|
}
|
||||||
messageReceived(m);
|
messageReceived(m);
|
||||||
}
|
}
|
||||||
receivedMessages.Clear();
|
receivedMessages.Clear();
|
||||||
|
|
@ -88,9 +146,9 @@ public class NetworkManager : MonoBehaviour
|
||||||
{
|
{
|
||||||
if(sections.Length > 1)
|
if(sections.Length > 1)
|
||||||
{
|
{
|
||||||
int user_id = int.Parse(sections[1]);
|
|
||||||
m.type = type;
|
m.type = type;
|
||||||
m.sender = user_id;
|
m.sender = int.Parse(sections[1]);
|
||||||
m.text = "";
|
m.text = "";
|
||||||
addMessage(m);
|
addMessage(m);
|
||||||
}
|
}
|
||||||
|
|
@ -109,9 +167,8 @@ public class NetworkManager : MonoBehaviour
|
||||||
m.type = 2;
|
m.type = 2;
|
||||||
int user_id = int.Parse(sections[1]);
|
int user_id = int.Parse(sections[1]);
|
||||||
m.sender = user_id;
|
m.sender = user_id;
|
||||||
|
string new_room = sections[2];
|
||||||
string room_name = sections[2];
|
m.text = new_room;
|
||||||
m.text = room_name;
|
|
||||||
|
|
||||||
addMessage(m);
|
addMessage(m);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class NetworkPlayer : MonoBehaviour
|
||||||
|
{
|
||||||
|
public int userid;
|
||||||
|
public string username;
|
||||||
|
public string room;
|
||||||
|
public NetworkManager manager;
|
||||||
|
Vector3 networkPosition;
|
||||||
|
|
||||||
|
// Start is called before the first frame update
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
if (manager.userid == userid) //this is me, I send updates
|
||||||
|
{
|
||||||
|
StartCoroutine(syncTransformCoroutine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update is called once per frame
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if (userid != manager.userid) //not me, I move to wherever I should
|
||||||
|
{
|
||||||
|
transform.position = Vector3.Lerp(transform.position, networkPosition, .1f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float h = Input.GetAxis("Horizontal");
|
||||||
|
float v = Input.GetAxis("Vertical");
|
||||||
|
Vector3 delta = h * Vector3.right + v * Vector3.up;
|
||||||
|
transform.position = transform.position + delta * Time.deltaTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator syncTransformCoroutine()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
manager.sendTo(0, "1," + transform.position.x + "," + transform.position.y + "," + transform.position.z + ";");
|
||||||
|
yield return new WaitForSeconds(.1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void handleMessage(NetworkManager.Message m)
|
||||||
|
{
|
||||||
|
//we need to parse the message
|
||||||
|
|
||||||
|
//types of messages
|
||||||
|
string[] messages = m.text.Split(';'); //messages are split by ;
|
||||||
|
for(int i = 0; i < messages.Length; i++)
|
||||||
|
{
|
||||||
|
//individual message parameters separated by comma
|
||||||
|
string[] sections = messages[i].Split(',');
|
||||||
|
|
||||||
|
switch (sections[0])
|
||||||
|
{
|
||||||
|
case "1": //update transform of self
|
||||||
|
{
|
||||||
|
float x = float.Parse(sections[1]);
|
||||||
|
float y = float.Parse(sections[2]);
|
||||||
|
float z = float.Parse(sections[3]);
|
||||||
|
networkPosition = new Vector3(x, y, z);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d8d3b6de660834e3e898725928251405
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &6139051692386484099
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 3076416102083120807}
|
||||||
|
- component: {fileID: 8527011532923434593}
|
||||||
|
- component: {fileID: 6854617867369839}
|
||||||
|
- component: {fileID: 5845716565458182149}
|
||||||
|
- component: {fileID: 5713671764962751473}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: PlayerPrefab
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &3076416102083120807
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6139051692386484099}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!33 &8527011532923434593
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6139051692386484099}
|
||||||
|
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!23 &6854617867369839
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6139051692386484099}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!65 &5845716565458182149
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6139051692386484099}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Size: {x: 1, y: 1, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &5713671764962751473
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6139051692386484099}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: d8d3b6de660834e3e898725928251405, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
userid: 0
|
||||||
|
username:
|
||||||
|
room:
|
||||||
|
manager: {fileID: 0}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d4158ab9c4a204cdbba28d3273fc1fb3
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -405,6 +405,7 @@ MonoBehaviour:
|
||||||
sendInput: {fileID: 945446555}
|
sendInput: {fileID: 945446555}
|
||||||
roomInput: {fileID: 711524768}
|
roomInput: {fileID: 711524768}
|
||||||
messages: {fileID: 1894247854}
|
messages: {fileID: 1894247854}
|
||||||
|
messageBuffer: []
|
||||||
--- !u!1 &440509381
|
--- !u!1 &440509381
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -1090,8 +1091,10 @@ MonoBehaviour:
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 80
|
port: 3290
|
||||||
userid: 0
|
userid: 0
|
||||||
|
room:
|
||||||
|
playerPrefab: {fileID: 6139051692386484099, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3}
|
||||||
connected: 0
|
connected: 0
|
||||||
--- !u!1 &1235343400
|
--- !u!1 &1235343400
|
||||||
GameObject:
|
GameObject:
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ PlayerSettings:
|
||||||
m_SplashScreenLogos: []
|
m_SplashScreenLogos: []
|
||||||
m_VirtualRealitySplashScreen: {fileID: 0}
|
m_VirtualRealitySplashScreen: {fileID: 0}
|
||||||
m_HolographicTrackingLossScreen: {fileID: 0}
|
m_HolographicTrackingLossScreen: {fileID: 0}
|
||||||
defaultScreenWidth: 1024
|
defaultScreenWidth: 600
|
||||||
defaultScreenHeight: 768
|
defaultScreenHeight: 400
|
||||||
defaultScreenWidthWeb: 960
|
defaultScreenWidthWeb: 960
|
||||||
defaultScreenHeightWeb: 600
|
defaultScreenHeightWeb: 600
|
||||||
m_StereoRenderingPath: 0
|
m_StereoRenderingPath: 0
|
||||||
|
|
@ -68,7 +68,7 @@ PlayerSettings:
|
||||||
androidRenderOutsideSafeArea: 1
|
androidRenderOutsideSafeArea: 1
|
||||||
androidUseSwappy: 1
|
androidUseSwappy: 1
|
||||||
androidBlitType: 0
|
androidBlitType: 0
|
||||||
defaultIsNativeResolution: 1
|
defaultIsNativeResolution: 0
|
||||||
macRetinaSupport: 1
|
macRetinaSupport: 1
|
||||||
runInBackground: 1
|
runInBackground: 1
|
||||||
captureSingleScreen: 0
|
captureSingleScreen: 0
|
||||||
|
|
@ -82,7 +82,7 @@ PlayerSettings:
|
||||||
bakeCollisionMeshes: 0
|
bakeCollisionMeshes: 0
|
||||||
forceSingleInstance: 0
|
forceSingleInstance: 0
|
||||||
useFlipModelSwapchain: 1
|
useFlipModelSwapchain: 1
|
||||||
resizableWindow: 0
|
resizableWindow: 1
|
||||||
useMacAppStoreValidation: 0
|
useMacAppStoreValidation: 0
|
||||||
macAppStoreCategory: public.app-category.games
|
macAppStoreCategory: public.app-category.games
|
||||||
gpuSkinning: 1
|
gpuSkinning: 1
|
||||||
|
|
@ -93,7 +93,7 @@ PlayerSettings:
|
||||||
xboxEnableFitness: 0
|
xboxEnableFitness: 0
|
||||||
visibleInBackground: 1
|
visibleInBackground: 1
|
||||||
allowFullscreenSwitch: 1
|
allowFullscreenSwitch: 1
|
||||||
fullscreenMode: 1
|
fullscreenMode: 3
|
||||||
xboxSpeechDB: 0
|
xboxSpeechDB: 0
|
||||||
xboxEnableHeadOrientation: 0
|
xboxEnableHeadOrientation: 0
|
||||||
xboxEnableGuest: 0
|
xboxEnableGuest: 0
|
||||||
|
|
@ -145,7 +145,8 @@ PlayerSettings:
|
||||||
resolutionScalingMode: 0
|
resolutionScalingMode: 0
|
||||||
androidSupportedAspectRatio: 1
|
androidSupportedAspectRatio: 1
|
||||||
androidMaxAspectRatio: 2.1
|
androidMaxAspectRatio: 2.1
|
||||||
applicationIdentifier: {}
|
applicationIdentifier:
|
||||||
|
Standalone: com.DefaultCompany.TestVelGameServer
|
||||||
buildNumber:
|
buildNumber:
|
||||||
Standalone: 0
|
Standalone: 0
|
||||||
iPhone: 0
|
iPhone: 0
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,213 @@
|
||||||
|
|
||||||
|
import socket
|
||||||
|
from _thread import *
|
||||||
|
import threading
|
||||||
|
import types
|
||||||
|
|
||||||
|
rooms = {} #will be a list of room objects. #this must be locked when when adding or removing rooms
|
||||||
|
rooms_lock = threading.Lock()
|
||||||
|
client_dict = {} #will be a list of client objects. #this must be locked when adding or removing clients
|
||||||
|
client_lock = threading.Lock()
|
||||||
|
|
||||||
|
HOST = ""
|
||||||
|
PORT = 80
|
||||||
|
|
||||||
|
|
||||||
|
def send_synced_room_message(roomName, message, exclude_client=None): #guaranteed to be received by all clients in order, mostly use for handling ownership
|
||||||
|
rooms_lock.acquire()
|
||||||
|
if roomName in rooms:
|
||||||
|
room_lock = rooms[roomName].room_lock
|
||||||
|
clients = rooms[roomName].clients
|
||||||
|
else:
|
||||||
|
rooms_lock.release()
|
||||||
|
return
|
||||||
|
rooms_lock.release()
|
||||||
|
room_lock.acquire()
|
||||||
|
for c in clients:
|
||||||
|
if (exclude_client != None) and (c.id == exclude_client.id): continue
|
||||||
|
send_client_message(c,message)
|
||||||
|
room_lock.release()
|
||||||
|
|
||||||
|
def send_room_message(roomName, message, exclude_client=None): #not guaranteed to be received by all clients in order
|
||||||
|
rooms_lock.acquire()
|
||||||
|
if roomName in rooms:
|
||||||
|
clients = rooms[roomName].clients
|
||||||
|
else:
|
||||||
|
rooms_lock.release()
|
||||||
|
return
|
||||||
|
rooms_lock.release()
|
||||||
|
for c in clients:
|
||||||
|
if (exclude_client != None) and (c.id == exclude_client.id): continue
|
||||||
|
send_client_message(c,message)
|
||||||
|
|
||||||
|
def send_client_message(client, message):
|
||||||
|
client.message_lock.acquire()
|
||||||
|
client.message_queue.append(message)
|
||||||
|
client.message_lock.release()
|
||||||
|
client.message_ready.set()
|
||||||
|
|
||||||
|
def decode_message(client,message):
|
||||||
|
global rooms
|
||||||
|
global rooms_lock
|
||||||
|
decodedMessage = message.split(":")
|
||||||
|
if len(decodedMessage) < 1: print("Invalid message received"); return
|
||||||
|
messageType = decodedMessage[0]
|
||||||
|
|
||||||
|
if not client.logged_in and messageType == '0' and len(decodedMessage) == 3:
|
||||||
|
client.username = decodedMessage[1]
|
||||||
|
#probaby check password too against a database of some sort where we store lots of good stuff
|
||||||
|
client.logged_in = True
|
||||||
|
send_client_message(client,f"0:{client.id}:\n")
|
||||||
|
|
||||||
|
elif client.logged_in:
|
||||||
|
if messageType == '1':
|
||||||
|
rooms_lock.acquire()
|
||||||
|
response = "1:" + ",".join([room.name+"-"+str(len(room.clients)) for room in rooms.values()]) + "\n"
|
||||||
|
rooms_lock.release()
|
||||||
|
send_client_message(client,response)
|
||||||
|
if messageType == '2' and len(decodedMessage) > 1:
|
||||||
|
|
||||||
|
#join or create a room
|
||||||
|
|
||||||
|
roomName = decodedMessage[1]
|
||||||
|
if client.room == roomName: #don't join the same room
|
||||||
|
pass
|
||||||
|
elif (roomName == '-1') and client.room != '': #can't leave a room if you aren't in one
|
||||||
|
#leave the room
|
||||||
|
rooms_lock.acquire()
|
||||||
|
try:
|
||||||
|
|
||||||
|
rooms[client.room].clients.remove(client)
|
||||||
|
if(len(rooms[client.room].clients) == 0):
|
||||||
|
del rooms[client.room]
|
||||||
|
except Exception as e:
|
||||||
|
print("not in room")
|
||||||
|
rooms_lock.release()
|
||||||
|
send_room_message(client.room, f"2:{client.id}:\n")
|
||||||
|
send_client_message(client,f"2:{client.id}:\n")
|
||||||
|
client.room = ''
|
||||||
|
else: #join or create the room
|
||||||
|
rooms_lock.acquire()
|
||||||
|
if roomName in rooms:
|
||||||
|
#join the room
|
||||||
|
rooms[roomName].clients.append(client)
|
||||||
|
else:
|
||||||
|
#create the room and join
|
||||||
|
rooms[roomName] = types.SimpleNamespace(name=roomName,clients=[client],room_lock=threading.Lock())
|
||||||
|
rooms_lock.release()
|
||||||
|
|
||||||
|
if (client.room != '') and (client.room != roomName): #client left the previous room
|
||||||
|
send_room_message(client.room, f"2:{client.id}:{roomName}:\n")
|
||||||
|
|
||||||
|
client.room = roomName #client joins the new room
|
||||||
|
#send a message to the clients new room that they joined!
|
||||||
|
send_room_message(roomName, f"2:{client.id}:{client.room}\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if messageType == '3' and len(decodedMessage) > 2:
|
||||||
|
subMessageType = decodedMessage[1]
|
||||||
|
if subMessageType == '0':
|
||||||
|
#send a message to everyone in the room (not synced)
|
||||||
|
send_room_message(client.room,f"3:{client.id}:{decodedMessage[2]}\n",client)
|
||||||
|
elif subMessageType == '1':
|
||||||
|
send_room_message(client.room,f"3:{client.id}:{decodedMessage[2]}\n")
|
||||||
|
elif subMessageType == '2':
|
||||||
|
#send a message to everyone in the room (not synced)
|
||||||
|
send_synced_room_message(client.room,f"3:{client.id}:{decodedMessage[2]}\n",client)
|
||||||
|
elif subMessageType == '3':
|
||||||
|
send_synced_room_message(client.room,f"3:{client.id}:{decodedMessage[2]}\n")
|
||||||
|
|
||||||
|
def client_read_thread(conn, addr, client):
|
||||||
|
global rooms
|
||||||
|
global rooms_lock
|
||||||
|
global client_dict
|
||||||
|
global client_lock
|
||||||
|
buffer = bytearray()
|
||||||
|
state = 0
|
||||||
|
buffer_size = 0
|
||||||
|
#valid messages are at least 2 bytes (size)
|
||||||
|
|
||||||
|
while client.alive:
|
||||||
|
try:
|
||||||
|
recv_data = conn.recv(1024)
|
||||||
|
except Exception as e:
|
||||||
|
client.alive = False
|
||||||
|
client.message_ready.set()
|
||||||
|
continue
|
||||||
|
if not recv_data:
|
||||||
|
client.alive = False
|
||||||
|
client.message_ready.set() #in case it's waiting for a message
|
||||||
|
else:
|
||||||
|
buffer.extend(recv_data) #read
|
||||||
|
if (state == 0) and (len(buffer) > 2):
|
||||||
|
buffer_size = int.from_bytes(buffer[0:2], byteorder='big')
|
||||||
|
state = 1
|
||||||
|
if (state == 1) and (len(buffer) >= buffer_size):
|
||||||
|
#we have a complete packet, process it
|
||||||
|
message = buffer[2:buffer_size]
|
||||||
|
decode_message(client,message)
|
||||||
|
buffer = buffer[buffer_size:]
|
||||||
|
state = 0
|
||||||
|
|
||||||
|
while not client.write_thread_dead:
|
||||||
|
client.message_ready.set()
|
||||||
|
pass
|
||||||
|
#now we can kill the client, removing the client from the rooms
|
||||||
|
client_lock.acquire()
|
||||||
|
rooms_lock.acquire()
|
||||||
|
if client.room != '':
|
||||||
|
rooms[client.room].clients.remove(client)
|
||||||
|
if(len(rooms[client.room].clients) == 0):
|
||||||
|
del rooms[client.room]
|
||||||
|
del client_dict[client.id] #remove the client from the list of clients...
|
||||||
|
rooms_lock.release()
|
||||||
|
client_lock.release()
|
||||||
|
send_room_message(client.room, f"2:{client.id}:\n")
|
||||||
|
print("client destroyed")
|
||||||
|
def client_write_thread(conn, addr, client):
|
||||||
|
while client.alive:
|
||||||
|
|
||||||
|
client.message_lock.acquire()
|
||||||
|
for message in client.message_queue:
|
||||||
|
try:
|
||||||
|
conn.sendall(message.encode('utf-8'))
|
||||||
|
except:
|
||||||
|
break #if the client is dead the read thread will catch it
|
||||||
|
client.message_queue = []
|
||||||
|
client.message_lock.release()
|
||||||
|
client.message_ready.wait()
|
||||||
|
client.message_ready.clear()
|
||||||
|
client.write_thread_dead = True
|
||||||
|
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
|
||||||
|
sock.bind((HOST, PORT))
|
||||||
|
sock.listen()
|
||||||
|
next_client_id = 0
|
||||||
|
while True:
|
||||||
|
|
||||||
|
c, addr = sock.accept() #blocks until a connection is made
|
||||||
|
client = types.SimpleNamespace(id=next_client_id,
|
||||||
|
alive=True,
|
||||||
|
message_queue=[],
|
||||||
|
message_lock=threading.Lock(),
|
||||||
|
inb='', #read buffer
|
||||||
|
message_ready=threading.Event(),
|
||||||
|
logged_in=False,
|
||||||
|
username='',
|
||||||
|
room='',
|
||||||
|
write_thread_dead=False
|
||||||
|
)
|
||||||
|
client_lock.acquire()
|
||||||
|
client_dict[next_client_id] = client
|
||||||
|
client_lock.release()
|
||||||
|
|
||||||
|
next_client_id += 1
|
||||||
|
|
||||||
|
start_new_thread(client_read_thread, (c, addr, client))
|
||||||
|
start_new_thread(client_write_thread, (c, addr, client))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -10,7 +10,7 @@ client_dict = {} #will be a list of client objects. #this must be locked when a
|
||||||
client_lock = threading.Lock()
|
client_lock = threading.Lock()
|
||||||
|
|
||||||
HOST = ""
|
HOST = ""
|
||||||
PORT = 80
|
PORT = 3290
|
||||||
|
|
||||||
|
|
||||||
def send_synced_room_message(roomName, message, exclude_client=None): #guaranteed to be received by all clients in order, mostly use for handling ownership
|
def send_synced_room_message(roomName, message, exclude_client=None): #guaranteed to be received by all clients in order, mostly use for handling ownership
|
||||||
|
|
@ -86,14 +86,18 @@ def decode_message(client,message):
|
||||||
send_room_message(client.room, f"2:{client.id}:\n")
|
send_room_message(client.room, f"2:{client.id}:\n")
|
||||||
send_client_message(client,f"2:{client.id}:\n")
|
send_client_message(client,f"2:{client.id}:\n")
|
||||||
client.room = ''
|
client.room = ''
|
||||||
else: #join or create the room
|
elif roomName != '': #join or create the room
|
||||||
rooms_lock.acquire()
|
rooms_lock.acquire()
|
||||||
|
|
||||||
if roomName in rooms:
|
if roomName in rooms:
|
||||||
#join the room
|
#join the room
|
||||||
rooms[roomName].clients.append(client)
|
rooms[roomName].clients.append(client)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
#create the room and join
|
#create the room and join
|
||||||
rooms[roomName] = types.SimpleNamespace(name=roomName,clients=[client],room_lock=threading.Lock())
|
rooms[roomName] = types.SimpleNamespace(name=roomName,clients=[client],room_lock=threading.Lock())
|
||||||
|
|
||||||
|
|
||||||
rooms_lock.release()
|
rooms_lock.release()
|
||||||
|
|
||||||
if (client.room != '') and (client.room != roomName): #client left the previous room
|
if (client.room != '') and (client.room != roomName): #client left the previous room
|
||||||
|
|
@ -103,6 +107,12 @@ def decode_message(client,message):
|
||||||
#send a message to the clients new room that they joined!
|
#send a message to the clients new room that they joined!
|
||||||
send_room_message(roomName, f"2:{client.id}:{client.room}\n")
|
send_room_message(roomName, f"2:{client.id}:{client.room}\n")
|
||||||
|
|
||||||
|
for c in rooms[roomName].clients:
|
||||||
|
if c.id != client.id:
|
||||||
|
send_client_message(client,f"2:{c.id}:{client.room}\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -182,6 +192,7 @@ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
c, addr = sock.accept() #blocks until a connection is made
|
c, addr = sock.accept() #blocks until a connection is made
|
||||||
|
c.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
client = types.SimpleNamespace(id=next_client_id,
|
client = types.SimpleNamespace(id=next_client_id,
|
||||||
alive=True,
|
alive=True,
|
||||||
message_queue=[],
|
message_queue=[],
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ import time
|
||||||
from _thread import *
|
from _thread import *
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
server_addr = ('127.0.0.1', 80)
|
server_addr = ('localhost', 3290)
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
sock.connect_ex(server_addr)
|
sock.connect_ex(server_addr)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -25,7 +26,7 @@ def writeThread(sock):
|
||||||
while True:
|
while True:
|
||||||
sock.sendall(f'3:0:{"thasdl;fjasd;lfjasl;dfjal;skdjlask;dflasd;jkjfjkjfsfjfjakfjafjdfjakjflfjadjf;jfakdjfdjfakdjfsdj;ldjf;laskdflsdjfasdkjfkdjflskdjfskdjflkfjlkdjfskdjfkjfskdjf;kfjs;kfjadkfjas;ldfalsdkfsdkfjasdkjfasdkfjlkdjfkdjflkdjf;djfadkfjaldkfjalkfja;kfja;kfjadkfjadkfja;sdkfa;dkfj;dfkjaslkfjas;dkfs;dkfjsldfjasdfjaldfjaldkfj;lkj"}\n'.encode('utf-8'))
|
sock.sendall(f'3:0:{"thasdl;fjasd;lfjasl;dfjal;skdjlask;dflasd;jkjfjkjfsfjfjakfjafjdfjakjflfjadjf;jfakdjfdjfakdjfsdj;ldjf;laskdflsdjfasdkjfkdjflskdjfskdjflkfjlkdjfskdjfkjfskdjf;kfjs;kfjadkfjas;ldfalsdkfsdkfjasdkjfasdkfjlkdjfkdjflkdjf;djfadkfjaldkfjalkfja;kfja;kfjadkfjadkfja;sdkfa;dkfj;dfkjaslkfjas;dkfs;dkfjsldfjasdfjaldfjaldkfj;lkj"}\n'.encode('utf-8'))
|
||||||
i = i+1
|
i = i+1
|
||||||
time.sleep(0.1)
|
time.sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
from _thread import *
|
||||||
|
import threading
|
||||||
|
|
||||||
|
server_addr = ('127.0.0.1', 80)
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.connect_ex(server_addr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def readThread(sock):
|
||||||
|
|
||||||
|
while True:
|
||||||
|
data = sock.recv(1024)
|
||||||
|
print(data.decode('utf-8'));
|
||||||
|
|
||||||
|
def writeThread(sock):
|
||||||
|
i = 0
|
||||||
|
sock.sendall('0::\n'.encode('utf-8'))
|
||||||
|
sock.sendall('2:myroom\n'.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
sock.sendall(f'3:0:{"thasdl;fjasd;lfjasl;dfjal;skdjlask;dflasd;jkjfjkjfsfjfjakfjafjdfjakjflfjadjf;jfakdjfdjfakdjfsdj;ldjf;laskdflsdjfasdkjfkdjflskdjfskdjflkfjlkdjfskdjfkjfskdjf;kfjs;kfjadkfjas;ldfalsdkfsdkfjasdkjfasdkfjlkdjfkdjflkdjf;djfadkfjaldkfjalkfja;kfja;kfjadkfjadkfja;sdkfa;dkfj;dfkjaslkfjas;dkfs;dkfjsldfjasdfjaldfjaldkfj;lkj"}\n'.encode('utf-8'))
|
||||||
|
i = i+1
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
start_new_thread(readThread,(sock,))
|
||||||
|
start_new_thread(writeThread,(sock,))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue