yeah, came to the same conclusion just in this moment. Whoops. Thank you ^^
This version only works for vSro 1.188 Servers
So here is my work from yesterday. Maybe my rookie python skills can help someone. Iām sure someone with better python skills could do it better than I have done. Feel free to improve it
What it does is:
- If a character is lvl 40 or above the plugin will delete this chars
- If a char lower than 40 is available the plugin will login this char
- If not it will create a new char and login this char then.
Two files are needed:
academy.py
from phBot import *
from packet import *
import struct
from struct import pack
from threading import Thread
from time import sleep
import string
import random
successfullCharCreated = False
loginChar = False
loginCharname = ""
charsDeleted = False
CHARACTER_TYPE = 'CH'
generalCharCount = 0
def create_character(name):
global CHARACTER_TYPE
if CHARACTER_TYPE == 'CH':
c_model = get_monster_string('CHAR_CH_MAN_ADVENTURER')['model']
chest = get_item_string('ITEM_CH_M_HEAVY_01_BA_A_DEF')['model']
legs = get_item_string('ITEM_CH_M_HEAVY_01_LA_A_DEF')['model']
shoes = get_item_string('ITEM_CH_M_HEAVY_01_FA_A_DEF')['model']
weapon = get_item_string('ITEM_CH_SWORD_01_A_DEF')['model']
elif CHARACTER_TYPE == 'EU':
c_model = get_monster_string('CHAR_EU_MAN_NOBLE')['model']
chest = get_item_string('ITEM_EU_M_HEAVY_01_BA_A_DEF')['model']
legs = get_item_string('ITEM_EU_M_HEAVY_01_LA_A_DEF')['model']
shoes = get_item_string('ITEM_EU_M_HEAVY_01_FA_A_DEF')['model']
weapon = get_item_string('ITEM_EU_DAGGER_01_A_DEF')['model']
else:
log('Invalid character type (CH or EU)')
return
if c_model == 0 or chest == 0 or legs == 0 or shoes == 0 or weapon == 0:
log('Could not retrieve item models')
return
log('Creating character with name %s and type %s' % (name, CHARACTER_TYPE))
p = b'\x01'
p += pack('H', len(name))
p += name.encode('ascii')
p += pack('I', c_model)
p += pack('B', 0)
p += pack('I', chest)
p += pack('I', legs)
p += pack('I', shoes)
p += pack('I', weapon)
inject_joymax(0x7007, p, False)
sleep(1)
inject_joymax(0x7007, b'\x02', False)
def deleteChar(chars):
sleep(2)
for x in chars:
packet = stream_writer()
packet.write_int8(3)
packet.write_uint16(len(x))
packet.write_ascii(x)
inject_joymax(0x7007, packet.data, False)
log('Delete: ' + x)
sleep(0.2)
sleep(2)
inject_joymax(0x7007, b'\x02', False)
def loginChars(chars):
global successfullCharCreated
global generalCharCount
global loginChar
global loginCharname
sleep(2)
if len(chars) > 0:
for x in chars:
log('SelectCharacter: ' + x)
loginChar = True
loginCharname = x
break
else:
log('Can not find any characters for login...Try to create new character')
if successfullCharCreated == False and int(generalCharCount) < 4:
name = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
create_character(name)
else:
log('Can not create a new character. Not enough character space')
def event_loop():
global loginChar, loginCharname
if loginChar:
loginChar = False
select_character(loginCharname)
def handle_joymax(opcode, data):
if opcode == 0xB007:
packet = stream_reader(data)
type = packet.read_uint8()
if type == 2:
if packet.read_uint8() == 1:
charsToDelete = list()
charsToLogin = list()
global charsDeleted
global generalCharCount
count = packet.read_uint8()
generalCharCount = count
x = 0
while x < count:
packet.read_int32() #Model
lng = packet.read_int16()
charname = packet.read_ascii(int(lng)) #Charname
packet.read_uint8() #Volume
level = packet.read_uint8() #Level
packet.read_uint64() #EXP
packet.read_uint16() #STR
packet.read_uint16() #INT
packet.read_uint16() #Stats
packet.read_uint32() #HP
packet.read_uint32() #MP
restoreFlag = packet.read_uint8()
if restoreFlag == 1:
packet.read_uint32() #Delete Time
packet.read_uint8()
packet.read_uint8()
packet.read_uint8()
itemCount = packet.read_uint8()
y = 0
while y < itemCount:
packet.read_uint32()
packet.read_uint8()
y += 1
avatarCount = packet.read_uint8()
z = 0
while z < avatarCount:
packet.read_uint32()
packet.read_uint8()
z += 1
if level >= 40 and restoreFlag != 1:
charsToDelete.append(charname)
elif restoreFlag != 1:
charsToLogin.append(charname)
x += 1
if charsDeleted == False and len(charsToDelete) > 0:
delete = Thread(target = deleteChar, args = (charsToDelete, ))
delete.daemon = True
delete.start()
else:
log('Can not find chars LvL 40 or above...Try to login a character')
loginThread = Thread(target = loginChars, args = (charsToLogin, ))
loginThread.daemon = True
loginThread.start()
charsDeleted = True
elif type == 1:
global successfullCharCreated
successfullCharCreated = True
return False
log('[AcademyLoginHelper]v1.0 Loaded - Credits: CharCreation by Ryan')
packet.py
import struct
import array
class stream_reader(object):
index = 0
data = None
size = 0
def __init__(self, data, index=0):
self.reset(data, index)
def reset(self, data, index=0):
self.data = data
self.size = self.data.__len__()
self.seek_set(index)
def bytes_left(self):
return self.size - self.index
def seek_forward(self, count):
if self.index + count > self.size:
raise Exception('index would be past end of stream')
self.index += count
def seek_backward(self, count):
if self.index - count < 0:
raise Exception('index would be < 0 if seeked further back')
self.index -= count
def seek_set(self, index):
if index > self.size or index < 0:
raise Exception('invalid index')
self.index = index
def read_int8(self):
if self.index + 1 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('b', self.data, self.index)[0]
self.index += 1
return unpacked
def read_uint8(self):
if self.index + 1 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('B', self.data, self.index)[0]
self.index += 1
return unpacked
def read_int16(self):
if self.index + 2 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('h', self.data, self.index)[0]
self.index += 2
return unpacked
def read_uint16(self):
if self.index + 2 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('H', self.data, self.index)[0]
self.index += 2
return unpacked
def read_int32(self):
if self.index + 4 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('i', self.data, self.index)[0]
self.index += 4
return unpacked
def read_uint32(self):
if self.index + 4 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('I', self.data, self.index)[0]
self.index += 4
return unpacked
def read_int64(self):
if self.index + 8 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('q', self.data, self.index)[0]
self.index += 8
return unpacked
def read_uint64(self):
if self.index + 8 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('Q', self.data, self.index)[0]
self.index += 8
return unpacked
def read_float(self):
if self.index + 4 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('f', self.data, self.index)[0]
self.index += 4
return unpacked
def read_double(self):
if self.index + 8 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('d', self.data, self.index)[0]
self.index += 8
return unpacked
def read_char(self):
if self.index + 1 > self.size:
raise Exception('past end of stream')
unpacked = struct.unpack_from('c', self.data, self.index)[0]
self.index += 1
return unpacked
def read_ascii(self, length):
if self.index + length > self.size:
raise Exception('past end of stream')
string = struct.unpack_from(str(length) + 's', self.data, self.index)[0]
self.index += length
return string.decode('ascii', 'replace')
'''
def read_utf8(self, length):
if self.index + length > self.size:
raise Exception('past end of stream')
string = struct.unpack_from(str(length) + 's', self.data, self.index)[0]
self.index += length
return string.decode('utf-8')
'''
def read_utf16(self, length):
length *= 2
if self.index + length > self.size:
raise Exception('past end of stream')
string = struct.unpack_from(str(length) + 's', self.data, self.index)[0]
self.index += length
return string.decode('utf-16le')
def read_utf32(self, length):
length *= 4
if self.index + length > self.size:
raise Exception('past end of stream')
string = struct.unpack_from(str(length) + 's', self.data, self.index)[0]
self.index += length
return string.decode('utf-32le')
class stream_writer(object):
data = array.array('B')
index = 0
size = 0
def __init__(self, data=None):
self.reset(data)
def reset(self, data=None):
if type(data) == array.array:
self.data = data
elif type(data) == list:
self.data = array.array('B', data)
elif data == None:
self.data = array.array('B')
else:
raise Exception('incorrect data type was used to reset the class')
self.size = self.data.__len__()
self.seek_end()
def tostring(self):
return self.data.tostring()
def tolist(self):
return self.data.tolist()
def tofile(self, f):
return self.data.tofile(f)
def toarray(self):
return self.data
def seek_forward(self, count):
if self.index + count > self.size:
raise Exception('index would be past end of stream')
self.index += count
def seek_backward(self, count):
if self.index - count < 0:
raise Exception('index would be < 0 if seeked further back')
self.index -= count
def seek_set(self, index):
if index > self.size or index < 0:
raise Exception('invalid index')
self.index = index
def seek_end(self):
self.index = self.size
def write_int8(self, val):
self.__append(struct.pack('b', val))
def write_uint8(self, val):
self.__append(struct.pack('B', val))
def write_int16(self, val):
self.__append(struct.pack('h', val))
def write_uint16(self, val):
self.__append(struct.pack('H', val))
def write_int32(self, val):
self.__append(struct.pack('i', val))
def write_uint32(self, val):
self.__append(struct.pack('I', val))
def write_int64(self, val):
self.__append(struct.pack('q', val))
def write_uint64(self, val):
self.__append(struct.pack('Q', val))
def write_float(self, val):
self.__append(struct.pack('f', val))
def write_double(self, val):
self.__append(struct.pack('d', val))
def write_char(self, val):
self.__append(struct.pack('c', val))
def write_ascii(self, val):
self.__append(bytes(val, 'ascii', 'replace'))
'''
def write_utf8(self, val):
self.__append(bytes(val, 'utf-8'))
'''
def write_utf16(self, val):
self.__append(val.encode('utf-16le'))
def write_utf32(self, val):
self.__append(val.encode('utf-32le'))
def write(self, val):
self.__append(val)
def __append(self, packed):
for x in packed:
self.data.insert(self.index, x)
self.index += 1
self.size += 1
Have fun
One issue is the character listing is different on different locales. So whatever you coded it for it will only work on that type of server.
Iām a sbot user and I want to move to phbot because of this academy plugin . I downloaded the phbot , I made all the settings , I even learned how to add quests in script , now I need to learn about this . What should I do after downloading python ?
Use the installer and enable the āPluginsā option which will install Python for you; then copy the plugin code into SublimeText/Notepad++ and save it into the Plugins folder.
welcom on the project hax =)
here u have some help for add your .py on your folder
because it does not select characters, DC becomes
Are you using the plugin correctly? It does select characters.
creates the character,does not select the character it creates
EU do you have a bug?
from phBot import *
from struct import pack
import string
import random
CHARACTER_TYPE = āEUā
create = False
request_listing = False
def create_character(name):
global CHARACTER_TYPE
if CHARACTER_TYPE == 'CH':
c_model = get_monster_string('CHAR_CH_MAN_ADVENTURER')['model']
chest = get_item_string('ITEM_CH_M_HEAVY_01_BA_A_DEF')['model']
legs = get_item_string('ITEM_CH_M_HEAVY_01_LA_A_DEF')['model']
shoes = get_item_string('ITEM_CH_M_HEAVY_01_FA_A_DEF')['model']
weapon = get_item_string('ITEM_CH_SWORD_01_A_DEF')['model']
elif CHARACTER_TYPE == 'EU':
c_model = get_monster_string('CHAR_EU_MAN_NOBLE')['model']
chest = get_item_string('ITEM_EU_M_HEAVY_01_BA_A_DEF')['model']
legs = get_item_string('ITEM_EU_M_HEAVY_01_LA_A_DEF')['model']
shoes = get_item_string('ITEM_EU_M_HEAVY_01_FA_A_DEF')['model']
weapon = get_item_string('ITEM_EU_DAGGER_01_A_DEF')['model']
else:
log('Invalid character type (CH or EU)')
return
if c_model == 0 or chest == 0 or legs == 0 or shoes == 0 or weapon == 0:
log('Could not retrieve item models')
return
log('Creating character with name %s and type %s' % (name, CHARACTER_TYPE))
p = b'\x01'
p += pack('H', len(name))
p += name.encode('ascii')
p += pack('I', c_model)
p += pack('B', 0)
p += pack('I', chest)
p += pack('I', legs)
p += pack('I', shoes)
p += pack('I', weapon)
inject_joymax(0x7007, p, False)
request_listing = True
def character_listing(args):
global create
if len(args) == 0:
create = True
else:
deleting = 0
for name in enumerate(args):
if not name.startswith(ā*ā):
log(āSelecting %sā % name)
select_character(name)
deleting = -1
break
else:
deleting += 1
if deleting != -1 and deleting < 4:
create = True
else:
log(āAccount full, all your chars are at deleting modeā)
return 0
def event_loop():
global create, request_listing
if create:
create = False
name = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
create_character(name)
elif request_listing:
request_listing = False
inject_joymax(0x7007, b'\x02', False)
log(ā[%s] Loadedā % name)
I do not understand why you copy and pasted the entire plugin.
EU do you have a bug?
Use this: Character Select / Creator
Iām using that too ,creates the character,does not select the character it creates dc 2. he chooses the character he creates when he logs in.
I just changed something which may work.
Iām using it wrong?
Yes, reinstall that plugin.
bro, i have one problem, i make condition on current lvl 41>disconnect but any time with only 1 char on account the pluguin said āCan not create a new character. Not enough character spaceā you can revise this method ? thanks alot
is the code working? it gives me the error.
do you have char in delete time on this acount ?