Lots of Stuff

Worked on server architecture, added minifigure creation, ditched server database all together for a pickling system
This commit is contained in:
wesleyd1124
2018-05-28 14:55:11 -04:00
committed by GitHub
parent 23171a427a
commit cf038762b8
13 changed files with 671 additions and 180 deletions
+8 -8
View File
@@ -1,10 +1,12 @@
import pyraknet.server as Server
from pyraknet.messages import Address
from pyraknet.bitstream import *
from Enum import *
from GameManager import Session, SessionState
from ServerUtilities import *
import uuid
from passlib.hash import sha256_crypt
from core import GameServer, CString
def HandleHandshake(Server : GameServer, data : bytes, address : Address):
stream = ReadStream(data)
@@ -19,24 +21,22 @@ def HandleLogin(Server : GameServer, data : bytes, address : Address):
username = stream.read(str, allocated_length=33)
password = stream.read(str, allocated_length=41)
packet, response, userKey, ID = LoginResponse(Server, username, password)
packet, response, userKey = LoginResponse(Server, username, password)
Server.send(packet, address)
if(response == LoginResponseEnum.Success):
session = Session()
session = Session(Server.Game)
session.address = address
session.userKey = userKey
session.accountID = ID
session.State = SessionState.LoggingIn
session.accountUsername = username
Server.GameManager.activeSessions.append(session)
Server.Game.Sessions.append(session)
def LoginResponse(Server : Server, Username : str, Password: str):
packet = WriteStream()
DB = Server.GameManager.ServerDB
userInfo = DB.Tables["Accounts"].select(["Banned", "Password", "ID"], "Username = '{}'".format(Username))[0]
userInfo = Server.Game.getAccountByUsername(Username)
print("Attempted login with username '{}' and password '{}'".format(Username, Password))
response = None
if (userInfo["Banned"] != 1 and sha256_crypt.verify(Password, userInfo["Password"])):#Success
if(userInfo is not None and userInfo.Banned != True and sha256_crypt.verify(Password, userInfo.Password)):#Success
response = LoginResponseEnum.Success
print("Login accepted!")
else:#Just put wrong info for now
@@ -64,4 +64,4 @@ def LoginResponse(Server : Server, Username : str, Password: str):
packet.write("Hello there ;D", length_type=c_uint16)#Custom error message
packet.write(c_uint16(0))
packet.write(c_ulong(4))
return packet, response, userKey[0:18], userInfo["ID"]
return packet, response, userKey[0:18]
+4 -4
View File
@@ -1,16 +1,16 @@
import pyraknet.server as Server
from pyraknet.messages import Address
from pyraknet.bitstream import *
from typing import Any, Callable
from GameManager import *
import AuthPackets
from PacketHeaders import PacketHeader
import threading
from ServerUtilities import *
from core import GameServer
from GameDB import GameDB
class AuthServer(GameServer):
def __init__(self, address: Address, max_connections: int, incoming_password: bytes, GameManager : GameManager):
super().__init__(address, max_connections, incoming_password, GameManager)
def __init__(self, address: Address, max_connections: int, incoming_password: bytes, GameManager : GameManager, CDClient : GameDB):
super().__init__(address, max_connections, incoming_password, GameManager, CDClient)
self.add_handler(Server.Event.UserPacket, self.handlePacket)
self.AuthHandlers = {}
+100
View File
@@ -0,0 +1,100 @@
from enum import *
class ClothingLOT(IntEnum):
#Shirts
SHIRT_BRIGHT_RED = 4049
SHIRT_BRIGHT_BLUE = 4083
SHIRT_BRIGHT_YELLOW = 4117
SHIRT_DARK_GREEN = 4151
SHIRT_BRIGHT_ORANGE = 4185
SHIRT_BLACK = 4219
SHIRT_DARK_STONE_GRAY = 4253
SHIRT_MEDIUM_STONE_GRAY = 4287
SHIRT_REDDISH_BROWN = 4321
SHIRT_WHITE = 4355
SHIRT_MEDIUM_BLUE = 4389
SHIRT_DARK_RED = 4423
SHIRT_EARTH_BLUE = 4457
SHIRT_EARTH_GREEN = 4491
SHIRT_BRICK_YELLOW = 4525
SHIRT_SAND_BLUE = 4559
SHIRT_SAND_GREEN = 4593
#Pants
PANTS_BRIGHT_RED = 2508
PANTS_BRIGHT_ORANGE = 2509
PANTS_BRICK_YELLOW = 2511
PANTS_MEDIUM_BLUE = 2513
PANTS_SAND_GREEN = 2514
PANTS_DARK_GREEN = 2515
PANTS_EARTH_GREEN = 2516
PANTS_EARTH_BLUE = 2517
PANTS_BRIGHT_BLUE = 2519
PANTS_SAND_BLUE = 2520
PANTS_DARK_STONE_GRAY = 2521
PANTS_MEDIUM_STONE_GRAY = 2522
PANTS_WHITE = 2523
PANTS_BLACK = 2524
PANTS_REDDISH_BROWN = 2526
PANTS_DARK_RED = 2527
class DisconnectionReasons(IntEnum):
UnknownError = 0x00
DuplicateLogin = 0x04
ServerShutdown = 0x05
ServerCannotLoadMap = 0x06
InvalidSessionKey = 0x07
CharacterNotFound = 0x09
CharacterCorruption = 0x0a
Kicked = 0x0b
class LoginResponseEnum(IntEnum):
Success = 0x01
Banned = 0x02
InvalidPerm = 0x03
InvalidLoginInfo = 0x06
AccountLocked = 0x07
class ZoneID(IntEnum):
VentureExplorer = 1000
ReturnToVentureExplorer = 1001
AvantGardens = 1100
AvantGardensSurvival = 1101
SpiderQueenBattle = 1102
BlockYard = 1150
AvantGrove = 1151
NimbusStation = 1200
PetCove = 1201
VertigoLoop = 1203
BattleOfNimbusStation = 1204
NimbusRock = 1250
NimbusIsle = 1251
GnarledForest = 1300
CanyonCove = 1302
KeelhaulCanyon = 1303
ChanteyShantey = 1350
ForbiddenValley = 1400
ForbiddenValleyDragon = 1402
DragonmawChasm = 1403
RavenBluff = 1450
Starbase3001 = 1600
DeepFreeze = 1601
RobotCity = 1602
MoonBase = 1603
Portabello = 1604
LEGOClub = 1700
CruxPrime = 1800
NexusTower = 1900
Ninjago = 2000
FrakjawBattle = 2001
class SessionState(IntEnum):
LoggingIn = 0
CharacterScreen = 1
InGame = 3
class MinifigureCreationResponse(IntEnum):
Success = 0x00
IDNotWorking = 0x01
NameNotAllowed = 0x02
PredefinedNameInUse = 0x03
NameInUse = 0x04
+70
View File
@@ -0,0 +1,70 @@
import sqlite3
import re
class DBTable():
def __init__(self, Name : str, Connection : sqlite3.Connection):
self.Name : str = Name
self.Connection : sqlite3.Connection = Connection
def select(self, Fields : list, Condition : str):
queryString = "SELECT"
for i in range(len(Fields)):
if(i != (len(Fields) -1)):
queryString += " " + Fields[i] + ","
else:
queryString += " " + Fields[i]
queryString += " FROM " + self.Name
if(Condition != None):
queryString += " WHERE " + Condition
c = self.Connection.cursor()
query = c.execute(queryString)
result = query.fetchall()
rows = []
for i in range(len(result)):
dictionary = {}
for x in range(len(result[i])):
dictionary[Fields[x]] = result[i][x]
rows.append(dictionary)
return rows
def selectAll(self, Condition : str):
queryString = "SELECT * FROM " + self.Name
if(Condition != None):
queryString += " WHERE " + Condition
c = self.Connection.cursor()
query = c.execute(queryString)
result = query.fetchall()
rows = []
fieldQuery = c.execute("SELECT sql FROM sqlite_master WHERE name = '{}'".format(self.Name))
fieldResult = fieldQuery.fetchone()[0]
Fields = re.findall(r'`(.*?)`', fieldResult)
for i in range(len(result)):
dictionary = {}
for x in range(len(result[i])):
dictionary[Fields[x]] = result[i][x]
rows.append(dictionary)
return rows
def insert(self, Values : dict):
queryString = "INSERT INTO " + self.Name + " ("
keys = list(Values.keys())
for i in range(len(keys)):
if(i != (len(keys) -1)):
queryString += keys[i] + ","
else:
queryString += keys[i] + ")"
queryString += " VALUES ("
for x in range(len(keys)):
if (x != (len(keys) - 1)):
queryString += Values[keys[x]] + ","
else:
queryString += Values[keys[x]] + ")"
c = self.Connection.cursor()
c.execute(queryString)
self.Connection.commit()
class GameDB():
def __init__(self, Connection : sqlite3.Connection):
self.connection : sqlite3.Connection = Connection
c = self.connection.cursor()
tableList = c.execute("SELECT name FROM sqlite_master")
self.Tables : dict = {}
for table in tableList:
self.Tables[table[0]] = DBTable(table[0], self.connection)
+209 -103
View File
@@ -1,142 +1,248 @@
import pyraknet.server
import sqlite3
from typing import Callable, Any
from enum import IntEnum
from passlib.hash import sha256_crypt
from pyraknet.replicamanager import Replica
from pyraknet.messages import Address
import re
from pyraknet.bitstream import *
import random
from Enum import SessionState, ZoneID
from ServerUtilities import getPantsID, getShirtID
class World():
def __init__(self, zoneID : int, LUZ : str):
self.zoneID : int = zoneID
self.LUZ : str = LUZ
class GameObject():
def __init__(self, ObjectID, LOT):
self.ObjectID : int = ObjectID
self.LOT : int = LOT
def __init__(self, Parent):
self.Parent = Parent
self.ObjectID : int = 0
self.LOT : int = 0
self.Name : str = None
self.Tag : str = None
self.ReplicaComponents : list = []
self.onInteraction : Callable = None
class SessionState(IntEnum):
LoggingIn = 0
CharacterScreen = 1
InGame = 3
class Spawner(GameObject):
def __init__(self, Parent):
super().__init__(Parent)
self.Tag = "Spawner"
self.SpawnedObject : GameObject = None
class Zone():
def __init__(self, Parent):
self.ZoneID : ZoneID = None
self.Parent = Parent
self.Objects : list = []
def createObject(self, Object : GameObject):
if(Object.ObjectID == None):
Object.ObjectID = random.randint(100000000000000000, 999999999999999999)
self.Objects.append(Object)
def getObjectByName(self, Name : str):
for Object in self.Objects:
if(Object.Name == Name):
return Object
return None
def getObjectByID(self, ID : int):
for Object in self.Objects:
if(Object.ObjectID == ID):
return Object
return None
def deleteObject(self, Object : GameObject):
for GameObject in self.Objects:
if(Object == GameObject):
del GameObject
class Vector3():
def __init__(self, X : int, Y : int, Z : int):
self.X : int = X
self.Y : int = Y
self.Z : int = Z
def translate(self, X : int, Y : int, Z : int):
self.X += X
self.Y += Y
self.Z += Z
def set(self, X : int, Y : int, Z : int):
self.X = X
self.Y = Y
self.Z = Z
class Vector4():
def __init__(self, X : int, Y : int, Z : int, W : int):
self.X : int = X
self.Y : int = Y
self.Z : int = Z
self.W : int = W
def translate(self, X : int, Y : int, Z : int, W : int):
self.X += X
self.Y += Y
self.Z += Z
self.W += W
def set(self, X : int, Y : int, Z : int, W : int):
self.X = X
self.Y = Y
self.Z = Z
self.W = W
class ReplicaObject(GameObject):
def __init__(self, Parent):
super().__init__(Parent)
self.ReplicaComponents : list = []
self.ObjectConfig : dict = {"Position": Vector3(0,0,0), "Rotation": Vector4(0,0,0,0)}
self.Replica : GameReplica = GameReplica()
def initializeReplica(self):
self.Replica.setComponents(self.ReplicaComponents)
class GameReplica(Replica):
def __init__(self):
self.Components = None
def setComponents(self, Components):
self.Components = Components
def write_construction(self, stream: WriteStream):
for Component in self.Components:
stream.write(Component.construct())
def serialize(self, stream: WriteStream):
for Component in self.Components:
stream.write(Component.serialize())
def on_destruction(self):
"""Not sure what to put here yet"""
class ReplicaComponent():
def __init__(self, Parent):
self.Parent = Parent
self.Name = None
def construct(self) -> None:
raise NotImplementedError
def serialize(self) -> None:
raise NotImplementedError
class Session():
def __init__(self):
self.world : World = None
def __init__(self, Parent):
self.Parent = Parent
self.ZoneID : int = None
self.character : Character = None
self.userKey : str = None
self.accountUsername : str = None
self.address : Address = None
self.accountID : int = None
self.isAdmin : bool = False
self.State : SessionState = None
class Character():
def __init__(self):
self.gameObject : GameObject = None
self.accountID : int = None
class Account():
def __init__(self, Parent):
self.Parent = Parent
self.Username : str = None
self.Password : str = None
self.Banned : bool = False
self.Characters : list = []
def CreateMinifigure(self, Name : str, ShirtColor : int, ShirtStyle : int, PantsColor : int, HairColor : int, HairStyle : int, lh : int, rh : int, Eyebrows : int, Eyes : int, Mouth : int):
Minifigure = Character(self)
Minifigure.Name = Name
Minifigure.ShirtColor = ShirtColor
Minifigure.ShirtStyle = ShirtStyle
Minifigure.PantsColor = PantsColor
Minifigure.HairColor = HairColor
Minifigure.HairStyle = HairStyle
Minifigure.lh = lh
Minifigure.rh = rh
Minifigure.ObjectID = random.randint(100000000000000000, 999999999999999999)
Minifigure.Eyebrows = Eyebrows
Minifigure.Eyes = Eyes
Minifigure.Mouth = Mouth
shirtLOT = getShirtID(ShirtColor, ShirtStyle)
pantsLOT = getPantsID(PantsColor)
Minifigure.Inventory.addItem(shirtLOT, Equipped=True)
Minifigure.Inventory.addItem(pantsLOT, Equipped=True)
self.Characters.append(Minifigure)
class DBTable():
def __init__(self, Name : str, Connection : sqlite3.Connection):
self.Name : str = Name
self.Connection : sqlite3.Connection = Connection
def select(self, Fields : list, Condition : str):
queryString = "SELECT"
for i in range(len(Fields)):
if(i != (len(Fields) -1)):
queryString += " " + Fields[i] + ","
else:
queryString += " " + Fields[i]
queryString += " FROM " + self.Name
if(Condition != None):
queryString += " WHERE " + Condition
c = self.Connection.cursor()
query = c.execute(queryString)
result = query.fetchall()
rows = []
for i in range(len(result)):
dictionary = {}
for x in range(len(result[i])):
dictionary[Fields[x]] = result[i][x]
rows.append(dictionary)
return rows
def selectAll(self, Condition : str):
queryString = "SELECT * FROM " + self.Name
if(Condition != None):
queryString += " WHERE " + Condition
c = self.Connection.cursor()
query = c.execute(queryString)
result = query.fetchall()
rows = []
fieldQuery = c.execute("SELECT sql FROM sqlite_master WHERE name = '{}'".format(self.Name))
fieldResult = fieldQuery.fetchone()[0]
Fields = re.findall(r'`(.*?)`', fieldResult)
for i in range(len(result)):
dictionary = {}
for x in range(len(result[i])):
dictionary[Fields[x]] = result[i][x]
rows.append(dictionary)
return rows
def insert(self, Values : dict):
queryString = "INSERT INTO " + self.Name + " ("
keys = list(Values.keys())
for i in range(len(keys)):
if(i != (len(keys) -1)):
queryString += keys[i] + ","
else:
queryString += keys[i] + ")"
queryString += " VALUES ("
for x in range(len(keys)):
if (x != (len(keys) - 1)):
queryString += Values[keys[x]] + ","
else:
queryString += Values[keys[x]] + ")"
c = self.Connection.cursor()
c.execute(queryString)
self.Connection.commit()
class Character(ReplicaObject):
def __init__(self, Parent):
super().__init__(Parent)
self.Zone : int = 0
self.LOT = 1
self.ShirtColor : int = 0
self.ShirtStyle : int = 0
self.PantsColor : int = 0
self.HairColor : int = 0
self.HairStyle : int = 0
self. lh : int = 0
self.rh : int = 0
self.Eyebrows : int = 0
self.Eyes : int = 0
self.Mouth : int = 0
self.Inventory : Inventory = Inventory(self)
class GameDB():
def __init__(self, Connection : sqlite3.Connection):
self.connection : sqlite3.Connection = Connection
c = self.connection.cursor()
tableList = c.execute("SELECT name FROM sqlite_master")
self.Tables : dict = {}
for table in tableList:
self.Tables[table[0]] = DBTable(table[0], self.connection)
class Inventory():
def __init__(self, Parent):
self.Parent = Parent
self.InventoryList = []
self.Space = 24
def addItem(self, LOT : int, Slot : int = None, Equipped : bool = False, Linked : bool = False):
if(Slot != None):
self.InventoryList.append({"LOT":LOT, "Slot":Slot, "Equipped":Equipped, "Linked":Linked})
else:
takenSlots = []
for item in self.InventoryList:
takenSlots.append(item["Slot"])
for i in range(self.Space):
if(i not in takenSlots):
self.InventoryList.append({"LOT": LOT, "Slot": i, "Equipped": Equipped, "Linked":Linked})
return
print("No Space Left In Inventory!")
def getEquippedItems(self):
equippedItems = []
for item in self.InventoryList:
if(item["Equipped"] == True):
equippedItems.append(item)
return equippedItems
class GameManager():
def __init__(self):
self.activeServers : dict = {}
self.activeSessions : list = []
self.CDClientDB : GameDB = GameDB(sqlite3.connect("cdclient.sqlite", check_same_thread=False))
self.ServerDB : GameDB = GameDB(sqlite3.connect("server.sqlite", check_same_thread=False))
self.Sessions : list = []
self.Accounts : list = []
self.Zones : list = []
def registerServer(self, ServerName : str, Server : pyraknet.server.Server):
self.activeServers[ServerName] = Server
def getAccountByUsername(self, Username : str):
for Account in self.Accounts:
if(Account.Username == Username):
return Account
return None
def unregisterServer(self, ServerName : str):
del self.activeServers[ServerName]
def purgePlayers(self):
for Zone in self.Zones:
for Object in Zone.Objects:
if(Object.LOT == 1):
del Object
def registerAccount(self, Username : str, Password : str):
account = Account(self)
account.Username = Username
account.Password = sha256_crypt.encrypt(Password)
account.Banned = False
self.Accounts.append(account)
def registerSession(self, Session : Session):
self.activeSessions.append(Session)
self.Sessions.append(Session)
def getSessionByAddress(self, address):
for session in self.activeSessions:
for session in self.Sessions:
if(session.address == address):
return session
return None
def clearSessions(self):
self.Sessions = []
def getSessionByCharacterID(self, characterID):
for session in self.activeSessions:
for session in self.Sessions:
if(session.character.objectID == characterID):
return session
return None
def clearZones(self):
self.Zones = []
def registerZone(self, ZoneObject : Zone):
for Zone in self.Zones:
if(Zone.ZoneID == ZoneObject.ZoneID):
print("Canceled New Zone Registration of Zone {} Because it Already Existed!".format(ZoneObject.ZoneID))
return Exception
self.Zones.append(ZoneObject)
def getSessionByUsername(self, username):
for session in self.activeSessions:
for session in self.Sessions:
if(session.accountUsername == username):
return session
return None
+2
View File
@@ -16,3 +16,5 @@ class PacketHeader(Enum):
ClientUserSessionInfo = b"S\x04\x00\x01\x00\x00\x00\x00"
ClientMinifigureListRequest = b"S\x04\x00\x02\x00\x00\x00\x00"
MinifigureList = b"S\x05\x00\x06\x00\x00\x00\x00"
ClientMinifigureCreateRequest = b"S\x04\x00\x03\x00\x00\x00\x00"
MinifigureCreationResponse = b"S\x05\x00\x08\x00\x00\x00\x00"
+136 -38
View File
@@ -2,50 +2,148 @@ from pyraknet.bitstream import *
from PacketHeaders import PacketHeader
import os
import socket
import pyraknet.server as Server
from GameManager import GameManager
from pyraknet.messages import Address
from enum import IntEnum
from Enum import *
"""
This entire file is really just Misc functions and classes
"""
#Returns shirt lots needed for minifigure creation
def getShirtID(shirtColor : int, shirtStyle : int):
shirtID = 0
if(shirtColor == 0):
if(shirtStyle >= 35):
shirtID = 5730
else:
shirtID = ClothingLOT.SHIRT_BRIGHT_RED.value
elif(shirtColor == 1):
if(shirtStyle >= 35):
shirtID = 5736
else:
shirtID = ClothingLOT.SHIRT_BRIGHT_BLUE.value
elif (shirtColor == 3):
if(shirtStyle >= 35):
shirtID = 5808
else:
shirtID = ClothingLOT.SHIRT_DARK_GREEN.value
elif (shirtColor == 5):
if(shirtStyle >= 35):
shirtID = 5754
else:
shirtID = ClothingLOT.SHIRT_BRIGHT_ORANGE.value
elif (shirtColor == 6):
if(shirtStyle >= 35):
shirtID = 5760
else:
shirtID = ClothingLOT.SHIRT_BLACK.value
elif (shirtColor == 7):
if(shirtStyle >= 35):
shirtID = 5766
else:
shirtID = ClothingLOT.SHIRT_DARK_STONE_GRAY.value
elif (shirtColor == 8):
if(shirtStyle >= 35):
shirtID = 5772
else:
shirtID = ClothingLOT.SHIRT_MEDIUM_STONE_GRAY.value
elif (shirtColor == 9):
if(shirtStyle >= 35):
shirtID = 5778
else:
shirtID = ClothingLOT.SHIRT_REDDISH_BROWN.value
elif (shirtColor == 10):
if(shirtStyle >= 35):
shirtID = 5784
else:
shirtID = ClothingLOT.SHIRT_WHITE.value
elif (shirtColor == 11):
if(shirtStyle >= 35):
shirtID = 5802
else:
shirtID = ClothingLOT.SHIRT_MEDIUM_BLUE.value
elif (shirtColor == 13):
if(shirtStyle >= 35):
shirtID = 5796
else:
shirtID = ClothingLOT.SHIRT_DARK_RED.value
elif (shirtColor == 14):
if(shirtStyle >= 35):
shirtID = 5802
else:
shirtID = ClothingLOT.SHIRT_EARTH_BLUE.value
elif (shirtColor == 15):
if(shirtStyle >= 35):
shirtID = 5808
else:
shirtID = ClothingLOT.SHIRT_EARTH_GREEN.value
elif (shirtColor == 16):
if(shirtStyle >= 35):
shirtID = 5814
else:
shirtID = ClothingLOT.SHIRT_BRICK_YELLOW.value
elif (shirtColor == 84):
if(shirtStyle >= 35):
shirtID = 5820
else:
shirtID = ClothingLOT.SHIRT_SAND_BLUE.value
elif (shirtColor == 96):
if(shirtStyle >= 35):
shirtID = 5826
else:
shirtID = ClothingLOT.SHIRT_SAND_GREEN.value
editedShirtColor = shirtID
if(shirtStyle >= 35):
finalShirtID = editedShirtColor + (shirtStyle - 35)
else:
finalShirtID = editedShirtColor + (shirtStyle - 1)
return finalShirtID
#Returns pants LOTS needed for minifigure creation
def getPantsID(pantsColor : int):
if(pantsColor == 0):
return ClothingLOT.PANTS_BRIGHT_RED.value
elif(pantsColor == 1):
return ClothingLOT.PANTS_BRIGHT_BLUE.value
elif(pantsColor == 3):
return ClothingLOT.PANTS_DARK_GREEN.value
elif(pantsColor == 5):
return ClothingLOT.PANTS_BRIGHT_ORANGE.value
elif(pantsColor == 6):
return ClothingLOT.PANTS_BLACK.value
elif(pantsColor == 7):
return ClothingLOT.PANTS_DARK_STONE_GRAY.value
elif(pantsColor == 8):
return ClothingLOT.PANTS_MEDIUM_STONE_GRAY.value
elif(pantsColor == 9):
return ClothingLOT.PANTS_REDDISH_BROWN.value
elif(pantsColor == 10):
return ClothingLOT.PANTS_WHITE.value
elif(pantsColor == 11):
return ClothingLOT.PANTS_MEDIUM_BLUE.value
elif(pantsColor == 13):
return ClothingLOT.PANTS_DARK_RED.value
elif(pantsColor == 14):
return ClothingLOT.PANTS_EARTH_BLUE.value
elif(pantsColor == 15):
return ClothingLOT.PANTS_EARTH_GREEN.value
elif(pantsColor == 16):
return ClothingLOT.PANTS_BRICK_YELLOW.value
elif(pantsColor == 84):
return ClothingLOT.PANTS_SAND_BLUE.value
elif(pantsColor == 96):
return ClothingLOT.PANTS_SAND_GREEN.value
else:
return 2508
class GameServer(Server.Server):
def __init__(self, address: Address, max_connections: int, incoming_password: bytes, GameManager : GameManager):
super().__init__(address, max_connections, incoming_password)
self.GameManager = GameManager
#This is used to write standard packet headers
def writeHeader(Stream : WriteStream, Header : PacketHeader):
Stream.write(Header.value)
#Ripped this straight off of PYLUS Because I had no idea how to make the char_size of strings equal to 1. Idk why it was removed as a parameter but whatever I guess
class CString(Serializable):
def __init__(self, data='', allocated_length=None, length_type=None):
self.data = data
self.allocated_length = allocated_length
self.length_type = length_type
def serialize(self, stream):
stream.write(self.data if isinstance(self.data, bytes) else bytes(self.data, 'latin1'),
allocated_length=self.allocated_length, length_type=self.length_type)
def deserialize(self, stream):
return stream.read(bytes, allocated_length=self.allocated_length, length_type=self.length_type).decode('latin1')
class DisconnectionReasons(IntEnum):
UnknownError = 0x00
DuplicateLogin = 0x04
ServerShutdown = 0x05
ServerCannotLoadMap = 0x06
InvalidSessionKey = 0x07
CharacterNotFound = 0x09
CharacterCorruption = 0x0a
Kicked = 0x0b
class LoginResponseEnum(IntEnum):
Success = 0x01
Banned = 0x02
InvalidPerm = 0x03
InvalidLoginInfo = 0x06
AccountLocked = 0x07
def getHandshake(ClientVersion : int, ConnectionType : int):
packet = WriteStream()
+55 -20
View File
@@ -1,5 +1,8 @@
from ServerUtilities import *
from GameManager import *
from Enum import *
import time
from core import GameServer, CString
def HandleHandshake(Server : GameServer, data : bytes, address : Address):
stream = ReadStream(data)
@@ -12,7 +15,7 @@ def HandleSessionKey(Server : GameServer, data : bytes, address : Address):
username = stream.read(str, allocated_length=33)
userKey = stream.read(str, allocated_length=33)
session = Server.GameManager.getSessionByAddress(address)
session = Server.Game.getSessionByAddress(address)
if(session is not None and session.userKey == userKey and session.accountUsername == username):
print(address, "sent the following valid key:", userKey)
session.State = SessionState.CharacterScreen
@@ -20,37 +23,69 @@ def HandleSessionKey(Server : GameServer, data : bytes, address : Address):
Server.send(getDisconnect(DisconnectionReasons.InvalidSessionKey.value))
def HandleMinifigListRequest(Server : GameServer, data : bytes, address : Address):
session = Server.GameManager.getSessionByAddress(address)
session = Server.Game.getSessionByAddress(address)
if(session.State == SessionState.CharacterScreen):
characters = Server.GameManager.ServerDB.Tables["Characters"].selectAll("AccountID = {}".format(session.accountID))
characters = Server.Game.getAccountByUsername(session.accountUsername).Characters
packet = WriteStream()
writeHeader(packet, PacketHeader.MinifigureList)
packet.write(c_uint8(len(characters)))
packet.write(c_uint8(0))
for character in characters:
print(character)
packet.write(c_longlong(character["ObjectID"]))#Object ID
packet.write(c_longlong(character.ObjectID))#Object ID
packet.write(c_ulong(0))
packet.write(character["Name"], allocated_length=33)#Character Name
packet.write(character.Name, allocated_length=33)#Character Name
packet.write("", allocated_length=33)#Name to show up in paranthesis
packet.write(c_bool(False))#Name rejected
packet.write(c_bool(False))#Free to play
packet.write(CString("", allocated_length=10))#Unknown
packet.write(c_ulong(character["ShirtColor"]))
packet.write(c_ulong(character["ShirtStyle"]))
packet.write(c_ulong(character["PantsColor"]))
packet.write(c_ulong(character["HairStyle"]))
packet.write(c_ulong(character["HairColor"]))
packet.write(c_ulong(character["lh"]))
packet.write(c_ulong(character["rh"]))
packet.write(c_ulong(character["Eyebrows"]))
packet.write(c_ulong(character["Eyes"]))
packet.write(c_ulong(character["Mouth"]))
packet.write(c_ulong(character.ShirtColor))
packet.write(c_ulong(character.ShirtStyle))
packet.write(c_ulong(character.PantsColor))
packet.write(c_ulong(character.HairStyle))
packet.write(c_ulong(character.HairColor))
packet.write(c_ulong(character.lh))
packet.write(c_ulong(character.rh))
packet.write(c_ulong(character.Eyebrows))
packet.write(c_ulong(character.Eyes))
packet.write(c_ulong(character.Mouth))
packet.write(c_ulong(0))
packet.write(c_uint16(character["LastZone"]))
packet.write(c_uint16(character["MapInstance"]))
packet.write(c_ulong(character["MapClone"]))
packet.write(c_uint16(character.Zone))
packet.write(c_uint16(0))#MapInstance
packet.write(c_ulong(0))#MapClone
packet.write(c_ulonglong(0))
packet.write(c_ushort(0))
equippedItems = character.Inventory.getEquippedItems()
packet.write(c_ushort(len(equippedItems)))
for item in equippedItems:
packet.write(c_ulong(item["LOT"]))
Server.send(packet, address)
def HandleMinifigureCreation(Server : GameServer, data : bytes, address : Address):
session : Session = Server.Game.getSessionByAddress(address)
account : Account = Server.Game.getAccountByUsername(session.accountUsername)
stream = ReadStream(data)
name = stream.read(str, allocated_length=33)
predefName1 = stream.read(c_ulong)
predefName2 = stream.read(c_ulong)
predefName3 = stream.read(c_ulong)
stream.read(bytes, allocated_length=9)
ShirtColor = stream.read(c_ulong)
ShirtStyle = stream.read(c_ulong)
PantsColor = stream.read(c_ulong)
HairStyle = stream.read(c_ulong)
HairColor = stream.read(c_ulong)
lh = stream.read(c_ulong)
rh = stream.read(c_ulong)
Eyebrows = stream.read(c_ulong)
Eyes = stream.read(c_ulong)
Mouth = stream.read(c_ulong)
account.CreateMinifigure(name, ShirtColor, ShirtStyle, PantsColor, HairColor, HairStyle, lh, rh, Eyebrows, Eyes, Mouth)
time.sleep(.5)
SendCreationResponse(Server, address, MinifigureCreationResponse.Success)
HandleMinifigListRequest(Server, b"", address)
def SendCreationResponse(Server : GameServer, address : Address, Response : MinifigureCreationResponse):
packet = WriteStream()
writeHeader(packet, PacketHeader.MinifigureCreationResponse)
packet.write(c_uint8(Response.value))#Just going to leave it at success for now
Server.send(packet, address)
+24 -3
View File
@@ -1,24 +1,45 @@
from typing import Callable
import WorldPackets
from PacketHeaders import PacketHeader
from Enum import ZoneID
from GameManager import GameManager
from GameDB import GameDB
import threading
from ServerUtilities import *
import pyraknet
from GameManager import Zone
from pyraknet.replicamanager import *
from core import GameServer
class WorldServer(GameServer):
def __init__(self, address: Address, max_connections: int, incoming_password: bytes, GameManager : GameManager):
super().__init__(address, max_connections, incoming_password, GameManager)
self.add_handler(Server.Event.UserPacket, self.handlePacket)
def __init__(self, address: Address, max_connections: int, incoming_password: bytes, GameManager : GameManager, CDClient : GameDB):
super().__init__(address, max_connections, incoming_password, GameManager, CDClient)
self.add_handler(pyraknet.server.Event.UserPacket, self.handlePacket)
self.WorldHandlers = {}
self.ReplicaManagers = {}
self.registerWorldHandler(PacketHeader.ClientUserSessionInfo.value, WorldPackets.HandleSessionKey)
self.registerWorldHandler(PacketHeader.ClientMinifigureListRequest.value, WorldPackets.HandleMinifigListRequest)
self.registerWorldHandler(PacketHeader.ClientMinifigureCreateRequest.value, WorldPackets.HandleMinifigureCreation)
self.registerWorldHandler(PacketHeader.Handshake.value, WorldPackets.HandleHandshake)
print("World Server Started")
self.registerZone(ZoneID.VentureExplorer.value)
def handlePacket(self, data : bytes, address):
if(data[0:8] in self.WorldHandlers):
t = threading.Thread(target=self.WorldHandlers[data[0:8]], args=[self, data[8:], address])
t.start()
else:
print("Header {} Has No Handler!".format(data[0:8]))
def registerReplicaManager(self, WorldID : int):
self.ReplicaManagers[WorldID] = ReplicaManager(self)
def registerWorldHandler(self, header : PacketHeader, function : Callable):
self.WorldHandlers[header] = function
def registerZone(self, WorldID : int, lvlFiles : list = None):
World = Zone(self.Game)
World.ZoneID = WorldID
self.registerReplicaManager(WorldID)
if(lvlFiles != None):
"""Parse Lvl Files"""
result = self.Game.registerZone(World)
if(result is not Exception): print("Registered Zone {}".format(WorldID))
+39 -4
View File
@@ -1,14 +1,49 @@
import AuthServer
from GameManager import GameManager
from GameManager import *
import asyncio
import WorldServer
import pickle
import threading
from pathlib import Path
import os
import time
import sqlite3
from GameDB import GameDB
import pyraknet
def pickleGame(GM):
pickledFile = open(os.getcwd() + "/Game.pickle", "wb")
pickle.dump(GM, pickledFile, pickle.HIGHEST_PROTOCOL)
def saveGame(GM):
while True:
pickleGame(GM)
print("Game Was Autosaved")
time.sleep(30)
if __name__ == "__main__":
GM = GameManager()
pickledGame = Path(os.getcwd() + "/Game.pickle")
GM = None
if(pickledGame.exists() != True):
GM = GameManager()
AuthServer.AuthServer(("localhost", 1001), max_connections=10, incoming_password=b"3.25 ND1", GameManager=GM)
WorldServer.WorldServer(("localhost", 2002), max_connections=10, incoming_password=b"3.25 ND1", GameManager=GM)
GM.registerAccount("wesley", "play")
pickleGame(GM)
else:
print("Loaded Pickled Game")
pickledFile = open(pickledGame, "rb")
GM = pickle.load(pickledFile)
GM.purgePlayers()
GM.clearSessions()
pickleThread = threading.Thread(target=saveGame, args=[GM,])
pickleThread.start()
CDClientDB : GameDB = GameDB(sqlite3.connect("resources/cdclient.sqlite", check_same_thread=False))
Auth = AuthServer.AuthServer(("localhost", 1001), max_connections=10, incoming_password=b"3.25 ND1", GameManager=GM, CDClient=CDClientDB)
World = WorldServer.WorldServer(("localhost", 2002), max_connections=10, incoming_password=b"3.25 ND1", GameManager=GM, CDClient=CDClientDB)
loop = asyncio.get_event_loop()
loop.run_forever()
+24
View File
@@ -0,0 +1,24 @@
import pyraknet
import GameManager
import GameDB
from pyraknet.bitstream import *
class GameServer(pyraknet.server.Server):
def __init__(self, address: pyraknet.messages.Address, max_connections: int, incoming_password: bytes, GameManager : GameManager.GameManager, CDClient : GameDB.GameDB):
super().__init__(address, max_connections, incoming_password)
self.Game : GameManager = GameManager
self.CDClient : GameDB.GameDB = CDClient
#Ripped this straight off of PYLUS Because I had no idea how to make the char_size of strings equal to 1. Idk why it was removed as a parameter but whatever I guess
class CString(Serializable):
def __init__(self, data='', allocated_length=None, length_type=None):
self.data = data
self.allocated_length = allocated_length
self.length_type = length_type
def serialize(self, stream):
stream.write(self.data if isinstance(self.data, bytes) else bytes(self.data, 'latin1'),
allocated_length=self.allocated_length, length_type=self.length_type)
def deserialize(self, stream):
return stream.read(bytes, allocated_length=self.allocated_length, length_type=self.length_type).decode('latin1')
Binary file not shown.
Binary file not shown.