222 lines
5.9 KiB
Python
222 lines
5.9 KiB
Python
# 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())
|
|
|
|
# Queue
|
|
networkQueue = bge.logic.globalDict["networkQueue"]
|
|
for key in networkQueue:
|
|
if networkQueue[key]:
|
|
data[key] = networkQueue[key].pop(0)
|
|
|
|
|
|
######### DEALING WITH RESPONSE ############
|
|
|
|
data = Send(host, data)
|
|
|
|
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
|
|
|
|
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")
|
|
|
|
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
|
|
|
|
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)
|
|
|
|
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
|