mirror of
https://github.com/Wesley-DeMontigny/WLUS.git
synced 2026-04-29 21:10:18 -05:00
Lots of Stuff
Worked on server architecture, added minifigure creation, ditched server database all together for a pickling system
This commit is contained in:
+8
-8
@@ -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
@@ -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 = {}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
@@ -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.
Reference in New Issue
Block a user