character creation partial, misread char select data

This commit is contained in:
Ra 2022-03-12 02:27:35 -07:00
parent 285abf1985
commit 6207766662
8 changed files with 16644 additions and 90 deletions

8926
.names Normal file

File diff suppressed because it is too large Load Diff

7618
.words Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,15 @@
__all__ = "Character", "ClientBase", "Client", "Helpers", "Packet", "iPacket", "oPacket"
__all__ = "Character", "ClientBase", "Client", "Helpers", "Packet", "iPacket", "oPacket", "NAMES"
from .character import Character
from .client_base import ClientBase
from .client import Client
from .packet import Packet, iPacket, oPacket
from .packet_helper import Helpers
from .packet_helper import Helpers
NAMES = []
with open("clb/.names", "r") as f:
NAMES.extend([l.rstrip("\n") for l in f.readlines()])
with open("clb/.words", "r") as f:
NAMES.extend([l.rstrip("\n") for l in f.readlines()])

View File

@ -1,5 +1,5 @@
from random import randint
from asyncio import sleep
from random import choice, randint
from asyncio import sleep, Event, Queue
from rich import print
@ -12,7 +12,7 @@ from .packet_helper import Helpers
class Client(ClientBase):
def __init__(self, loop=None, username=None, password=None):
def __init__(self, names=None, loop=None, username=None, password=None):
super().__init__(loop)
self._username = username
self._password = password
@ -22,6 +22,10 @@ class Client(ClientBase):
self._channel_count = 0
self._channel_id = 0
self._characters = []
self._can_login = Event()
self._NAMES = names
self._char_name = ""
async def begin(self):
while self._loop.is_running() and self._sock.fileno():
@ -48,8 +52,12 @@ class Client(ClientBase):
await self.send_packet(opkt)
@packet_handler(RecvOps.LOGIN_STATUS)
async def login_second(self, ipkt: iPacket):
ipkt.decode_byte()
async def login_first(self, ipkt: iPacket):
r1 = ipkt.decode_byte()
if r1 != 0:
print(f"Login Response code: {r1}")
return
ipkt.decode_byte()
ipkt.decode_int()
self._account_id = ipkt.decode_int()
@ -73,6 +81,10 @@ class Client(ClientBase):
await self.send_packet(oPacket(SendOps.SERVERLIST_REQUEST))
@packet_handler(RecvOps.LOGIN_SECOND)
async def login_second(self, ipkt: iPacket):
self._can_login.set()
@packet_handler(RecvOps.SERVERLIST)
async def serverlist(self, ipkt: iPacket):
if (world_id := ipkt.decode_byte()) == 0xFF:
@ -82,7 +94,6 @@ class Client(ClientBase):
# self.schedule_action(SendOps.CHARLIST_REQUEST, 3.0)
return
world_name = ipkt.decode_string()
world_flag = ipkt.decode_byte()
event_message = ipkt.decode_string()
@ -107,6 +118,7 @@ class Client(ClientBase):
w_id = ipkt.decode_byte()
ch_id = ipkt.decode_short()
self._worlds[w_id]["load"] += load
self._worlds[w_id]["channels"][ch_id] = {}
self._worlds[w_id]["channels"][ch_id]["load"] = load
self._worlds[w_id]["channels"][ch_id]["name"] = ch_name
@ -133,13 +145,36 @@ class Client(ClientBase):
@packet_handler(RecvOps.CHARLIST)
async def char_list(self, ipkt: iPacket):
self._characters = Helpers.character_entries(ipkt)
await self._can_login.wait()
if not self._characters: # create char
...
await self.check_name()
else: # login to char
...
print(self._characters)
@packet_handler(RecvOps.ADD_NEW_CHAR_ENTRY)
async def add_new_char(self, ipkt: iPacket):
success = ipkt.decode_byte() == 0
print(f"Response to character creation: {success}")
if not success:
return
self._characters.append(Helpers.character_entry(ipkt))
print(self._characters)
@packet_handler(RecvOps.CHAR_NAME_RESPONSE)
async def char_name_resp(self, ipkt: iPacket):
name = ipkt.decode_string()
taken = ipkt.decode_byte() == 1
print(taken, name)
if taken:
await self.check_name()
else:
self._char_name = name
await self.create_char()
async def do_login(self):
opkt = oPacket(SendOps.LOGIN_PASSWORD)
opkt.encode_string(self._username)
@ -150,8 +185,45 @@ class Client(ClientBase):
async def request_char_list(self):
opkt = oPacket(SendOps.CHARLIST_REQUEST)
opkt.encode_byte(2)
self._channel_id = randint(0, self._channel_count - 1)
self._channel_id = randint(0, self._channel_count - 1) + 1
opkt.encode_byte(self._world_id)
opkt.encode_short(self._channel_id)
await self.send_packet(opkt)
async def check_name(self):
opkt = oPacket(SendOps.CHECK_CHAR_NAME)
opkt.encode_string(choice(self._NAMES))
await self.send_packet(opkt)
async def create_char(self):
opkt = oPacket(SendOps.CREATE_CHAR)
opkt.encode_string(self._char_name)
job = 1
opkt.encode_int(job) # job
opkt.encode_short(0) # dual blade
opkt.encode_byte(0) # gender
opkt.encode_byte(1) # skin color
opkt.encode_byte(8)
faces = [20000, 20001, 20002]
hairs = [30030, 30020, 30000]
hair_colors = [0, 2, 3, 7]
eye_colors = [0, 1, 2, 3]
shirts = [1040002, 1040006, 1040010]
ds_marks = [1012277, 1012278, 1012279, 1012280]
shorts = [1060002, 1060006]
shoes = [1072001, 1072005, 1072037, 1072038]
weapons = [1302000, 1322005, 1312004]
opkt.encode_int(choice(faces)) # face
opkt.encode_int(choice(hairs)) # hair
if job not in [5, 6]:
opkt.encode_int(choice(hair_colors)) # hair color
opkt.encode_int(choice(eye_colors)) # eye color
if job == 6:
opkt.encode_int(choice(ds_marks))
opkt.encode_int(choice(shirts))
opkt.encode_int(choice(shorts))
opkt.encode_int(choice(shoes))
opkt.encode_int(choice(weapons))
await self.send_packet(opkt)

View File

@ -70,7 +70,6 @@ class ClientBase:
async def _sock_recv(self):
# 51.222.56.169
await self._ready.wait()
self._recv_size = -1
while self._loop.is_running():

View File

@ -1,5 +1,5 @@
from .character import Character
from .packet import iPacket
from .packet import iPacket, oPacket
class Helpers:
@ -9,7 +9,7 @@ class Helpers:
chars = []
ipkt.decode_byte()
for i in range(ipkt.decode_byte()):
chars.append(Character.fill(Helpers.character_entry(ipkt, view_all)))
chars.append(Helpers.character_entry(ipkt, view_all))
return chars
@staticmethod
@ -23,14 +23,12 @@ class Helpers:
rank = {}
if ranked := ipkt.decode_byte():
rank |= {
"rank": ipkt.decode_int(),
"rank_move": ipkt.decode_int(),
"job_rank": ipkt.decode_int(),
"job_rank_move": ipkt.decode_int()
}
rank["rank"] = ipkt.decode_int()
rank["rank_move"] = ipkt.decode_int()
rank["job_rank"] = ipkt.decode_int()
rank["job_rank_move"] = ipkt.decode_int()
return stats | look_useful | rank
return Character.fill(stats | look_useful | rank)
@staticmethod
def character_stats(ipkt: iPacket):
@ -114,4 +112,4 @@ class Helpers:
if marking := ipkt.decode_int():
look["demon_marking"] = marking
return look
return look

View File

@ -1,3 +1,4 @@
pycryptodome==3.14.1
Pygments==2.11.2
rich==12.0.0
rich==12.0.0
attrs==21.4.0

View File

@ -1,6 +1,3 @@
from asyncio import sleep
from dataclasses import dataclass, is_dataclass
from random import randint
@ -50,76 +47,11 @@ def get(iterable, **attrs):
return find(predicate, iterable)
def filter_out_to(func, iters, out):
new = []
for item in iters:
if func(item):
new.append(item)
else:
out.append(item)
return new
def first_or_default(list_, f):
return next((val for val in list_ if f(val)), None)
def fix_dict_keys(dict_):
copy = dict(dict_)
for key, value in copy.items():
if key.isdigit():
value = dict_.pop(key)
key = int(key)
if isinstance(value, dict):
dict_[key] = fix_dict_keys(value)
else:
dict_[key] = value
return dict_
def to_string(bytes_):
return " ".join([
bytes_.hex()[i:i + 2].upper() for i in range(0, len(bytes_.hex()), 2)
])
async def wakeup():
while True:
await sleep(0.01)
def nested_dataclass(*args, **kwargs):
def wrapper(cls):
cls = dataclass(cls, **kwargs)
original_init = cls.__init__
def __init__(self, *args, **kwargs):
for name, value in kwargs.items():
field_type = cls.__annotations__.get(name, None)
if is_dataclass(field_type) and isinstance(value, dict):
new_obj = field_type(**value)
kwargs[name] = new_obj
original_init(self, *args, **kwargs)
cls.__init__ = __init__
return cls
return wrapper(args[0]) if args else wrapper
class Manager(list):
def get(self, search):
return first_or_default(self, search)
def first_or_default(self, func):
return next((val for val in self if func(val)), None)