DanisRace/Scripts/Multiplayer_Client.py

271 lines
7.6 KiB
Python
Raw Permalink Normal View History

2024-07-13 15:15:50 +02:00
# GPLv3 or later
# (C) J.Y.Amihud ( blenderdumbass ) 2024
# Multiplayer client functions
import bge
import time
import json
import zlib
import traceback
from Scripts import Vehicle
from Scripts import Character_Controll
from Scripts import Opt
from Scripts import Settings
from Scripts.Multiplayer_Shared import *
from Scripts import Reuse
from Scripts.Common import *
settings = Settings.load_settings()
host = settings.get("mp-host", "")
def DescribeScene():
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
cam = scene.active_camera
garage = scene.objects["GarageColider"]
garageDistance = 31
chunksize = 250
data = {}
addr = Opt.Address(dani.position, chunksize)
if addr not in data:
data[addr] = []
danidata = Character_Controll.Encode(dani)
data[addr].append(danidata)
userId = bge.logic.globalDict.get("userId")
for car in bge.logic.globalDict["allcars"]:
if car.get("inview") and car.getDistanceTo(garage) > garageDistance:
if car.get("ownerId") and car.get("ownerId") != userId:
continue
addr = Opt.Address(car.position, chunksize)
cardata = Vehicle.Encode(car)
if addr not in data:
data[addr] = []
data[addr].append(cardata)
return data
def MainLoop():
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
cam = scene.active_camera
chunksize = 250
bge.logic.globalDict["networkQueue"] = {}
while True:
try:
# A bit of delay, to not owerwhelm the server
time.sleep(0.1)
# Testing if the game is still runing.
# it will fail when the game engine stops.
try: bge.logic.getRealTime()
except: return
if bge.logic.globalDict.get("restore-physics-timer"):
continue
if bge.logic.globalDict.get("network-scene"):
continue
######### SENDING THE DATA TO SERVER ############
data = {}
# Login
LoginEncode(data)
# Scene
data["scene"] = DescribeScene()
data["vision"] = Opt.Surround(cam.position,
chunksize,
cam.orientation.to_euler())
2024-08-27 14:34:26 +02:00
2024-07-13 15:15:50 +02:00
# Queue
networkQueue = bge.logic.globalDict["networkQueue"]
for key in networkQueue:
if networkQueue[key]:
data[key] = networkQueue[key].pop(0)
######### DEALING WITH RESPONSE ############
2024-08-27 14:34:26 +02:00
beforeSend = time.time()
2024-07-13 15:15:50 +02:00
data = Send(host, data)
2024-08-27 14:34:26 +02:00
afterSend = time.time()
PING = afterSend - beforeSend
bge.logic.globalDict["ping"] = PING
2024-07-13 15:15:50 +02:00
for key in data:
payload = data[key]
if key == "login":
LoginDecode(payload)
elif key == "scene":
bge.logic.globalDict["network-scene"] = payload
elif key == "message":
bge.logic.globalDict["print"] = payload
2024-08-27 14:34:26 +02:00
elif key == "timing":
bge.logic.globalDict["netTiming"] = payload
elif key == "serverTime":
bge.logic.globalDict["serverTime"] = payload
bge.logic.globalDict["recievedTime"] = time.time()
2024-07-13 15:15:50 +02:00
else:
print(key, payload)
except Exception:
print("\n\nNETWORK CLIENT ERROR:", clr["bold"]+clr["tdrd"], traceback.format_exc(), clr["bold"])
def SecondaryLoop():
# This loop runs in the game loop, not the separate thread.
# And it deals with updates sent by the other thread.
if bge.logic.globalDict.get("network-scene"):
data = bge.logic.globalDict["network-scene"]
SceneDecode(data)
bge.logic.globalDict["network-scene"] = None
def LoginEncode(data):
data["login"] = {}
data["login"]["userId"] = bge.logic.globalDict.get("userId")
data["login"]["username"] = settings.get("mp-name")
data["login"]["room"] = settings.get("mp-room")
2024-08-27 14:34:26 +02:00
data["login"]["ping"] = bge.logic.globalDict.get("ping", 0)
2024-07-13 15:15:50 +02:00
def LoginDecode(data):
if data.get("userId"):
bge.logic.globalDict["userId"] = data["userId"]
if data.get("room"):
settings["mp-room"] = data["room"]
def SceneDecode(data):
netObjects = bge.logic.globalDict["netObjects"]
if not data:
return
2024-08-27 14:34:26 +02:00
rIds = [] # Recieved netIds
2024-07-13 15:15:50 +02:00
for addr in data:
chunk = data[addr]
for obj in chunk:
# update = True
# if obj.get("netId") in netObjects["netId"]:
# if obj.get("ownerId"):
# netObjects["netId"][obj.get("netId")]["ownerId"] = obj.get("ownerId")
# obj["ID"] = id(netObjects["netId"][obj.get("netId")])
# Sometimes we want to update some things like netId.
if obj.get("ID") in netObjects["pythonId"]\
and obj.get("name") == netObjects["pythonId"][obj["ID"]].name:
netObjects["pythonId"][obj["ID"]]["netId"] = obj.get("netId")
netObjects["netId"][obj.get("netId")] = netObjects["pythonId"][obj["ID"]]
if obj.get("type") == "veh":
Vehicle.Decode(obj, network=True)
elif obj.get("type") == "chr":
Character_Controll.Decode(obj, network=True)
2024-08-27 14:34:26 +02:00
rIds.append(obj.get("netId"))
# Cleaning objects that disappeared
delete = []
for netId in netObjects["netId"]:
if netId not in rIds and netObjects["netId"][netId].get("ownerId") and netObjects["netId"][netId].get("ownerId") != bge.logic.globalDict.get("userId"):
delete.append(netId)
for netId in delete:
netObjects["netId"][netId]["netId"] = None
Reuse.Delete(netObjects["netId"][netId])
del netObjects["netId"][netId]
2024-07-13 15:15:50 +02:00
def QueueToSend(key, data):
networkQueue = bge.logic.globalDict["networkQueue"]
if key not in networkQueue:
networkQueue[key] = []
networkQueue[key].append(data)
def GrabOwnership(obj):
# This function grabs ownership of an object.
# Like when a player steals a car spawned by
# another player.
userId = bge.logic.globalDict["userId"]
ownerId = obj.get("ownerId")
netId = obj.get("netId")
# First we will check that the ownership isn't ours.
if userId != ownerId and netId:
QueueToSend("change-ownership",{
"netId" :netId,
"userId":userId
})
obj["ownerId"] = userId
2024-08-27 14:34:26 +02:00
def Latency(obj):
# Calculates latency of the object.
ping = bge.logic.globalDict.get("ping", 0)
ownerId = obj.get("ownerId", "")
netTiming = bge.logic.globalDict.get("netTiming", 0)
serverTime = bge.logic.globalDict.get("serverTime", 0)
recievedTime = bge.logic.globalDict.get("recievedTime")
owner = netTiming.get(ownerId, {})
ownerTimeStamp = owner.get("timestamp",0)
ownerPing = owner.get("ping",0)
serverLatency = ( serverTime - ownerTimeStamp )
clientLatency = ( time.time() - recievedTime )
latency = ping + ownerPing + serverLatency + clientLatency
return latency