DanisRace_Multiplayer/handler.py
BlenderDumbass 7324bd0b53 Me stupid
2025-03-18 23:35:55 +02:00

157 lines
3.2 KiB
Python

# AGPLv3 or later
import json
import zlib
def encode(data, send_raw=False):
# This will encode data for sending.
# Data should be a writable into JSON.
if not send_raw:
J = json.dumps(data).encode("utf-8")
else:
J = data.encode("utf-8")
C = zlib.compress(J)
zed = len(C)
raw = len(J)
# Sometime compressed is larger than raw.
# We will add a byte saying 69 if it comressed
# and a byte saying 0 if it not sexy like this.
if not send_raw and zed < raw:
return chr(69).encode("utf-8") + C
else:
return chr(0).encode("utf-8") + J
def decode(data):
# This will decode the data
try:
code = data[0]
data = data[1:]
except:
code = 0
# 69 means the data is sexy
# see encode() for more info
if code == 69:
data = zlib.decompress(data).decode()
else:
data = data.decode()
# It should be Json but it could be something else
try:
return json.loads(data)
except:
return data
cache = {}
cache2 = {}
def diff(d1, d2, CHANGED=True):
# Function that checkes for differences
# between two dictionaries
ans = {}
# Comparing dictionaries
for i in d1:
if d1[i] != d2.get(i) and i in d2:
if not type(d2.get(i)) == dict:
ans[i] = d2[i]
else:
try:
ans[i] = diff(d1[i], d2[i], CHANGED=False)
except:
ans[i] = d2[i]
# Adding in new stuff
for i in d2:
if i not in d1:
ans[i] = d2[i]
# Telling it to remove old stuff
remove = []
for i in d1:
if i not in d2:
remove.append(i)
if remove:
ans["DELETED"] = remove
if ans and CHANGED:
ans["CHANGED"] = True
return ans
def combine(d1,d2):
# Function that combines 2 dictionaries
# based on the diff version.
# Changed parts
for i in d1:
if d1[i] != d2.get(i) and i in d2:
if not type(d2.get(i)) == dict:
d1[i] = d2[i]
else:
try:
combine(d1[i], d2[i])
except:
d1[i] = d2[i]
# Add new stuff
for i in d2:
if i in ("DELETED", "CHANGED"):
continue
if i not in d1:
d1[i] = d2[i]
# Deleting stuff
if "DELETED" in d2:
for i in d2["DELETED"]:
try:
del d1[i]
except:
pass
def encodeObj(data, ID, cache=cache):
# encodes Object, stripping it from all data
# that is unecessary
if ID not in cache:
cache[ID] = data
return encode(data)
else:
D = diff(cache[ID], data)
cache[ID] = data
return encode(D)
def decodeObj(data, ID, cache=cache):
data = decode(data)
if ID not in cache:
# TODO: implement the check to see
# if the data is actually CHANGED
# or not. And send back the request for the
# full thing if it is only the part.
cache[ID] = data
return data
else:
combine(cache[ID], data)
return cache[ID]