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;
|
||||
messageBuffer.Add(s);
|
||||
messages.text = "";
|
||||
|
||||
|
||||
|
||||
|
||||
if(messageBuffer.Count > 10)
|
||||
{
|
||||
messageBuffer.RemoveAt(0);
|
||||
|
|
|
|||
|
|
@ -13,8 +13,12 @@ public class NetworkManager : MonoBehaviour
|
|||
#region private members
|
||||
private TcpClient socketConnection;
|
||||
private Thread clientReceiveThread;
|
||||
public int userid;
|
||||
public int userid = -1;
|
||||
public string room;
|
||||
int messagesReceived = 0;
|
||||
public GameObject playerPrefab;
|
||||
public Dictionary<int, NetworkPlayer> players = new Dictionary<int, NetworkPlayer>();
|
||||
|
||||
#endregion
|
||||
// Use this for initialization
|
||||
public class Message
|
||||
|
|
@ -27,6 +31,7 @@ public class NetworkManager : MonoBehaviour
|
|||
void Start()
|
||||
{
|
||||
ConnectToTcpServer();
|
||||
|
||||
}
|
||||
|
||||
private void addMessage(Message m)
|
||||
|
|
@ -42,6 +47,59 @@ public class NetworkManager : MonoBehaviour
|
|||
lock(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);
|
||||
}
|
||||
receivedMessages.Clear();
|
||||
|
|
@ -88,9 +146,9 @@ public class NetworkManager : MonoBehaviour
|
|||
{
|
||||
if(sections.Length > 1)
|
||||
{
|
||||
int user_id = int.Parse(sections[1]);
|
||||
|
||||
m.type = type;
|
||||
m.sender = user_id;
|
||||
m.sender = int.Parse(sections[1]);
|
||||
m.text = "";
|
||||
addMessage(m);
|
||||
}
|
||||
|
|
@ -109,9 +167,8 @@ public class NetworkManager : MonoBehaviour
|
|||
m.type = 2;
|
||||
int user_id = int.Parse(sections[1]);
|
||||
m.sender = user_id;
|
||||
|
||||
string room_name = sections[2];
|
||||
m.text = room_name;
|
||||
string new_room = sections[2];
|
||||
m.text = new_room;
|
||||
|
||||
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}
|
||||
roomInput: {fileID: 711524768}
|
||||
messages: {fileID: 1894247854}
|
||||
messageBuffer: []
|
||||
--- !u!1 &440509381
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -1090,8 +1091,10 @@ MonoBehaviour:
|
|||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
host: localhost
|
||||
port: 80
|
||||
port: 3290
|
||||
userid: 0
|
||||
room:
|
||||
playerPrefab: {fileID: 6139051692386484099, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3}
|
||||
connected: 0
|
||||
--- !u!1 &1235343400
|
||||
GameObject:
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ PlayerSettings:
|
|||
m_SplashScreenLogos: []
|
||||
m_VirtualRealitySplashScreen: {fileID: 0}
|
||||
m_HolographicTrackingLossScreen: {fileID: 0}
|
||||
defaultScreenWidth: 1024
|
||||
defaultScreenHeight: 768
|
||||
defaultScreenWidth: 600
|
||||
defaultScreenHeight: 400
|
||||
defaultScreenWidthWeb: 960
|
||||
defaultScreenHeightWeb: 600
|
||||
m_StereoRenderingPath: 0
|
||||
|
|
@ -68,7 +68,7 @@ PlayerSettings:
|
|||
androidRenderOutsideSafeArea: 1
|
||||
androidUseSwappy: 1
|
||||
androidBlitType: 0
|
||||
defaultIsNativeResolution: 1
|
||||
defaultIsNativeResolution: 0
|
||||
macRetinaSupport: 1
|
||||
runInBackground: 1
|
||||
captureSingleScreen: 0
|
||||
|
|
@ -82,7 +82,7 @@ PlayerSettings:
|
|||
bakeCollisionMeshes: 0
|
||||
forceSingleInstance: 0
|
||||
useFlipModelSwapchain: 1
|
||||
resizableWindow: 0
|
||||
resizableWindow: 1
|
||||
useMacAppStoreValidation: 0
|
||||
macAppStoreCategory: public.app-category.games
|
||||
gpuSkinning: 1
|
||||
|
|
@ -93,7 +93,7 @@ PlayerSettings:
|
|||
xboxEnableFitness: 0
|
||||
visibleInBackground: 1
|
||||
allowFullscreenSwitch: 1
|
||||
fullscreenMode: 1
|
||||
fullscreenMode: 3
|
||||
xboxSpeechDB: 0
|
||||
xboxEnableHeadOrientation: 0
|
||||
xboxEnableGuest: 0
|
||||
|
|
@ -145,7 +145,8 @@ PlayerSettings:
|
|||
resolutionScalingMode: 0
|
||||
androidSupportedAspectRatio: 1
|
||||
androidMaxAspectRatio: 2.1
|
||||
applicationIdentifier: {}
|
||||
applicationIdentifier:
|
||||
Standalone: com.DefaultCompany.TestVelGameServer
|
||||
buildNumber:
|
||||
Standalone: 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()
|
||||
|
||||
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
|
||||
|
|
@ -86,14 +86,18 @@ def decode_message(client,message):
|
|||
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
|
||||
elif roomName != '': #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
|
||||
|
|
@ -102,6 +106,12 @@ def decode_message(client,message):
|
|||
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")
|
||||
|
||||
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:
|
||||
|
||||
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,
|
||||
alive=True,
|
||||
message_queue=[],
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ import time
|
|||
from _thread import *
|
||||
import threading
|
||||
|
||||
server_addr = ('127.0.0.1', 80)
|
||||
server_addr = ('localhost', 3290)
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
sock.connect_ex(server_addr)
|
||||
|
||||
|
||||
|
|
@ -25,7 +26,7 @@ def writeThread(sock):
|
|||
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)
|
||||
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