Oh shit! I did it! It so perfectly FARM NOW xDDD
First thanks
I really wish to say thanks to Panagiotis Peikidis for providing me advices, links to algorithms, and patience :) Without you, i couldn’t do anything, Thank you very much.
Oh shit! I did it! It so perfectly FARM NOW xDDD
I really wish to say thanks to Panagiotis Peikidis for providing me advices, links to algorithms, and patience :) Without you, i couldn’t do anything, Thank you very much.
Generally, if you want move using packets, u will notice, that without MovementCompleteMessage, after re-login, you’ll be teleported back to start position.
And 2nd “thing”, after MovementRequestMessage, without sending MovementCompleteMessage, you can’t move anymore xD
Fix… send MovementCompleteMessage… but if u send it too fast, after 20-30 steps u will be kicked and banned for two hours. Why?! Because it will look like you’re using SpeedHack.
That’s why you should use 250ms+ delay for EACH CELL YOU MOVE.
Dofus first AI… Roaming between wheet :) That later it will farm…
Now it can login, move, and say through console :)
[ INFO] [D2I] Parsing i18n_en.d2i
[ INFO] [D2O] Parsing InfoMessages.d2o
[ INFO] [D2O] Parsing Servers.d2o
[ INFO] [D2O] Parsing ChatChannels.d2o
[ INFO] Connected
[ OK] Authentification successful
[ INFO] Connected
[ OK] Ticket accepted
[ INFO] Position in character selection queue: 1 / 1
[ INFO] Position in character selection queue: 0 / 0
[ INFO] Position in character selection queue: 0 / 0
[ INFO] Character weight: 14 / 1000
[ OK] Welcome to DOFUS, and welcome to the World of Twelve! Remember that it is <b>strictly forbidden</b> to disclose your account name or password.
[ OK] This account was last accessed on 13/07/2011 at 05:02.
[CHAT] [GENERAL] : oops
[CHAT] [GENERAL] : like i didn't did it wrong?!
[CHAT] [GENERAL] : heh
[CHAT] [PRIVATE] : asd
[CHAT] [PRIVATE] : wanna join me ? )
say hellow world )
[CHAT] [GENERAL] : hellow world )
say bla bla bla
[CHAT] [GENERAL] : bla bla bla
Just got it…
def check_connection
recv # receive packets
case @state
when STATE_NOT_CONNECTED
reconnect
when STATE_CONNECTED_TO_LOGIN
@packets.pop do |packet|
case packet
when Com::AnkamaGames::Dofus::Network::Messages::Handshake::ProtocolRequired
if packet.requiredVersion > $config.protocol_build
log("Current protocol build: #{$config.protocol_build}, required build: #{packet.requiredVersion}", Logger::FATAL)
end
if packet.currentVersion < $config.protocol_required_build
log("Current protocol build: #{$config.protocol_required_build}, is too new for the server version: #{packet.currentVersion}", Logger::FATAL)
end
when HelloConnectMessage
$config.session_key = packet.sessionKey
im = IdentificationMessage.new
bytes = im.build!({
username: $config.username,
password: $config.password,
version: $config.version,
session_key: $config.session_key
})
send_data bytes
when Com::AnkamaGames::Dofus::Network::Messages::Queues::LoginQueueStatusMessage
l("Position in login queue: #{packet.position} / #{packet.total}")
when IdentificationSuccessMessage
l('Authentification successful', Logger::OK)
@state = STATE_SERVERS_LIST
else
l("Incorrect packet at $net.STATE_CONNECTED_TO_LOGIN: #{packet.class}", Logger::FATAL)
end
end
when STATE_SERVERS_LIST
@packets.pop do |packet|
case packet
when ServersListMessage
if !$config.server_id
"Select server:".to_block(10) {
packet.servers.select { |s| s.status == s.class::STATUS_ONLINE }.each do |s|
printf("%5d %s %d %s\n", s.id, "-", s.charactersCount, s.status_t)
end
}
while line = gets do
line.strip!
next if line.empty?
exit if line.to_i == 0
server = packet.servers.find { |s| s.id == line.to_i }
next unless server
$config.server_id = server.id
break
end
end
ssm = ServerSelectionMessage.new.build!($config.server_id)
send_data ssm
when SelectedServerDataMessage
@ip = packet.address
@port = packet.port
$config.ticket = packet.ticket
reconnect
@state = STATE_CONNECTED_TO_GAME
else
l("Incorrect packet at $net.STATE_SERVERS_LIST: #{packet.class}", Logger::FATAL)
end
end
when STATE_CONNECTED_TO_GAME
@packets.pop do |packet|
case packet
when Com::AnkamaGames::Dofus::Network::Messages::Handshake::ProtocolRequired
if packet.requiredVersion > $config.protocol_build
log("Current protocol build: #{$config.protocol_build}, required build: #{packet.requiredVersion}", Logger::FATAL)
end
if packet.currentVersion < $config.protocol_required_build
log("Current protocol build: #{$config.protocol_required_build}, is too new for the server version: #{packet.currentVersion}", Logger::FATAL)
end
when HelloGameMessage
atm = AuthenticationTicketMessage.new.build!('en', $config.ticket)
send_data atm
when AuthenticationTicketAcceptedMessage
l("Ticket accepted", Logger::OK)
when Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicTimeMessage
# nothing to do, just ignore
when Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::AccountCapabilitiesMessage
$config.account_id = packet.account_id
clrm = Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharactersListRequestMessage.new.build!
send_data clrm
@state = STATE_CHARACTER_SELECTION
else
l("Incorrect packet at $net.STATE_CONNECTED_TO_GAME: #{packet.class}", Logger::FATAL)
end
end
when STATE_CHARACTER_SELECTION
@packets.pop do |packet|
case packet
when Com::AnkamaGames::Dofus::Network::Messages::Queues::QueueStatusMessage
l("Position in character selection queue: #{packet.position} / #{packet.total}")
when Com::AnkamaGames::Dofus::Network::Messages::Secure::TrustStatusMessage,
Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicNoOperationMessage
# nothing to do, ignore
when Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharactersListMessage
characters = packet.characters
if !$config.character_id && characters.size > 0
puts "Choose your character:"
fields = sprintf("%20s | %5s | %5s | %6s", 'Name', 'Level', 'Class', 'Sex')
puts fields, '-' * fields.size
characters.each do |c|
puts sprintf("%20s | %5d | %5d | %6s", c.name, c.level, c.breed, c.sex ? 'Male' : 'Female')
end
while line = gets do
line.strip!
break if line.empty?
character = characters.find { |c| c.name.downcase == line.downcase }
next unless character
$config.character_id = character.id
break
end
csm = Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharacterSelectionMessage.new.build!($config.character_id)
send_data csm
@state = STATE_IN_GAME
elsif characters.size == 0
l("No character created", Logger::FATAL)
exit
end
else
l("Incorrect packet at $net.STATE_CHARACTER_SELECTION: #{packet.class}", Logger::FATAL)
end
end
when STATE_IN_GAME
else
l("Unknown state #{state} for $net", Logger::FATAL);
exit
end
end
[user host-122 ~/Documents/Projects/dofus] ./run.rb
[ INFO] [D2O] Parsing Servers.d2o
[ INFO] Connected
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Handshake::ProtocolRequired
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::HelloConnectMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::IdentificationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::IdentificationSuccessMessage
[ OK] Authentification successful
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::ServersListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::ServerSelectionMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Connection::SelectedServerDataMessage
[ INFO] Connected
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Handshake::ProtocolRequired
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::HelloGameMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::AuthenticationTicketMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::AuthenticationTicketAcceptedMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicTimeMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Approach::AccountCapabilitiesMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Secure::TrustStatusMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicNoOperationMessage
[ OK] Ticket accepted
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharactersListRequestMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Queues::QueueStatusMessage
[ INFO] Position in character selection queue: 1 / 1
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Queues::QueueStatusMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicNoOperationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Queues::QueueStatusMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharactersListMessage
[ INFO] Position in character selection queue: 0 / 0
[ INFO] Position in character selection queue: 0 / 0
Choose your character:
Name | Level | Class | Sex
---------------------------------------------
Char1 | 2 | 5 | Male
Char2 | 4 | 3 | Female
Char3 | 19 | 9 | Female
Char1
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharacterSelectionMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::BasicNoOperationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Context::Notification::NotificationListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Character::Choice::CharacterSelectedSuccessMessage
[ INFO] Selected character: [------] Char1 (2)
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Inventory::Items::InventoryContentMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Inventory::Items::SetUpdateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Shortcut::ShortcutBarContentMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Shortcut::ShortcutBarContentMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Context::Roleplay::Emote::EmoteListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Pvp::AlignmentRankUpdateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Pvp::AlignmentSubAreasListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Chat::Channel::EnabledChannelsMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Inventory::Spells::SpellListMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Shortcut::ShortcutBarContentMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Initialization::SetCharacterRestrictionsMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Inventory::Items::InventoryWeightMessage
[ INFO] Character weight: 14 / 1000
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Friend::FriendWarnOnConnectionStateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Friend::GuildMemberWarnOnConnectionStateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Friend::FriendWarnOnLevelGainStateMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::TextInformationMessage
[ WARN] Check Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::TextInformationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::TextInformationMessage
[ WARN] Check Com::AnkamaGames::Dofus::Network::Messages::Game::Basic::TextInformationMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Initialization::ServerExperienceModificatorMessage
[DEBUG] Com::AnkamaGames::Dofus::Network::Messages::Game::Friend::SpouseStatusMessage
P.S. Please don’t blame my ugly code :)
Generally, d2p files looks like splitted archives and each one have some pack of maps in it.
module Com::AnkamaGames::Jerakine::Resources::Protocols::Impl
class PakProtocol2
include Singleton
attr_accessor :indexes, :properties
def self.method_missing meth, *args
instance.send(meth, *args)
end
def initialize
@indexes = {}
@properties = {}
@adapter = MapsAdapter.new
end
def [](key)
index, subpath = key.to_s.split("/", 2)
read(index, subpath)
end
def read(index, subpath)
i = 0
item = @indexes[index][subpath]
file_stream = item[:stream]
file_stream.pos = item[:offset]
data = file_stream.read(item[:length])
# @adapther is instance of MapsAdapter (see below)
map = @adapter.getResource(data)
end
def parse filepath
raise "[D2P] File doesn't exists #{filepath}" unless File.exists?(filepath)
@stream_name = File.dirname(filepath).gsub("#{RES_ROOT}/", "")
file_stream = nil
unless @indexes[@stream_name]
file_stream = init_stream(filepath)
raise "[D2P] Error while looking for file_stream: #{@stream_name}" unless file_stream
end
end
def init_stream filepath
@indexes[@stream_name] = {}
@properties[@stream_name] = {}
indexes = @indexes[@stream_name]
properties = @properties[@stream_name]
base_pos = 0
base_size = 0
indexes_pos = 0
indexes_size = 0
properties_pos = 0
properties_size = 0
link_filepath = filepath
while File.exists?(link_filepath)
fp = File.open(link_filepath)
raise "[D2P] Incorrect file?!" if fp.read(2) != "\x02\x01"
fp.pos = fp.size - 24
base_pos = fp.readUInt
base_size = fp.readUInt
indexes_pos = fp.readUInt
indexes_size = fp.readUInt
properties_pos = fp.readUInt
properties_size = fp.readUInt
fp.pos = properties_pos
link_filepath = ""
properties_size.times do
prop_type = fp.readUTFString
prop_value = fp.readUTFString
properties[prop_type] = prop_value
if prop_type == "link"
link_filepath = File.join(@stream_name, prop_value)
end
end
fp.pos = indexes_pos
indexes_size.times do
name = fp.readUTFString
offset = fp.readInt
length = fp.readInt
indexes[name] = {
offset: base_pos + offset,
length: length,
stream: fp
}
end
end
return fp
end
end
PakProtocol2.parse "#{RES_ROOT}/maps/maps0.d2p"
end
As first, they’re packed in GZip, with metadata, and simple inflate isn’t working for it. For more descriptive information visit: ActionScript 3 ByteArray and look at compress method.
Generally, we just need to skip till we get 0x77 byte )
module Com::AnkamaGames::Atouin::Resources::Adapters
class MapsAdapter
def getResource orig_data
data = StringIO.new(orig_data)
header = data.readByte
if header != 77
data.pos = 0
data = StringIO.new(Zlib::Inflate.inflate(data.read))
header = data.readByte
raise "Incorrect header file" if header != 77
end
data.pos = 0
# Map class below :)
map = Map.new
map.parse data
map
end
end
end
module Com::AnkamaGames::Atouin::Data::Map
class Map
include Enumerable
attr_accessor :header, :background, :zoomScale, :zoomOffsetX, :zoomOffsetY, :useLowPassFilter, :useReverb, :presetId, :backgroundsCount, :backgroundFixtures, :foregroundsCount, :foregroundFixtures, :cellsCount, :groundCRC, :layersCount, :layers, :cells
def parse data
raise "Incorrect header file" unless data.readByte == 77
@header = {
mapVersion: data.readByte,
id: data.readUInt,
relativeId: data.readUInt,
mapType: data.readByte,
subareaId: data.readInt,
topNeighbourId: data.readInt,
bottomNeighbourId: data.readInt,
leftNeighbourId: data.readInt,
rightNeighbourId: data.readInt,
shadowBonusOnEntities: data.readInt
}
if @header[:mapVersion] >= 3
@background = {
red: data.readByte,
green: data.readByte,
blue: data.readByte
}
@background[:color] = (@background[:red] & 255) << 16 | (@background[:green] & 255) << 8 | @background[:blue] & 255
end
if @header[:mapVersion] >= 4
@zoomScale = data.readUShort / 100
@zoomOffsetX = data.readShort
@zoomOffsetY = data.readShort
end
@useLowPassFilter = data.readByte == 1
@useReverb = data.readByte == 1
@presetId = -1
@presetId = data.readInt if @useReverb
@backgroundsCount = data.readByte
@backgroundFixtures = []
@backgroundsCount.times {
bg = Fixture.new
bg.parse data
@backgroundFixtures << bg
}
@foregroundsCount = data.readByte
@foregroundFixtures = []
@foregroundsCount.times {
fg = Fixture.new
fg.parse data
@foregroundFixtures << fg
}
@cellsCount = 560
data.readInt
@groundCRC = data.readInt
@layersCount = data.readByte
@layers = []
@layersCount.times {
la = Layer.new
la.parse data
@layers << la
}
@cells = []
@cellsCount.times {
cd = CellData.new
cd.parse data
@cells << cd
}
end
end
end
Generally, i don’t care about colors & other info… i just need to get @cells information :)
module Com::AnkamaGames::Atouin::Data::Map
class Fixture
def parse data
@fixtureId = data.readInt
@offset = OpenStruct.new
@offset.x = data.readShort
@offset.y = data.readShort
@rotation = data.readShort
@xScale = data.readShort
@yScale = data.readShort
@redMultiplier = data.readByte
@greenMultiplier = data.readByte
@blueMultiplier = data.readByte
@hue = @redMultiplier | @greenMultiplier | @blueMultiplier
@alpha = data.readUnsignedByte
end
end
end
module Com::AnkamaGames::Atouin::Data::Map
class Layer
def parse data
@layerId = data.readInt
@cellsCount = data.readShort
@cells = []
@cellsCount.times {
c = Cell.new
c.parse data
@cells << c
}
end
end
end
module Com::AnkamaGames::Atouin::Data::Map
class CellData
attr_accessor :floor, :losmov, :speed, :mapChangeData
def parse data
@floor = data.readByte * 10;
@losmov = data.readUnsignedByte
@speed = data.readByte
@mapChangeData = data.readUnsignedByte
end
def nonWalkableDuringRP
(@losmov & 128) >> 7 == 1
end
def nonWalkableDuringFight
(@losmov & 4) >> 2 == 1
end
def visible
(@losmov & 64) >> 6 == 1
end
def farmCell
(@losmov & 32) >> 5 == 1
end
def blue
(@losmov & 16) >> 4 == 1
end
def red
(@losmov & 8) >> 3 == 1
end
def los
(@losmov & 2) >> 1 == 1
end
def mov
(@losmov & 1) == 1
end
end
end
You can detect “move-ability” of cell using methods: mov, nonWalkableDuringRP and nonWalkableDuringFight.
map_id = 21760516
map_path = "maps/#{map_id % 10}/#{map_id}.dlm"
map = PakProtocol2[map_path]
puts map.cells[0].mov # true or false, means movable?
puts map.cells.select { |c| c.mov } # select all movable cells
true
[
#<Com::AnkamaGames::Atouin::Data::Map::CellData:0x0001 ...>,
#<Com::AnkamaGames::Atouin::Data::Map::CellData:0x0002 ...>,
#<Com::AnkamaGames::Atouin::Data::Map::CellData:0x0003 ...>,
#<Com::AnkamaGames::Atouin::Data::Map::CellData:0x0004 ...>,
#<Com::AnkamaGames::Atouin::Data::Map::CellData:0x0005 ...>,
#<Com::AnkamaGames::Atouin::Data::Map::CellData:0x0006 ...>
]
Packet-based Dofus Bot Presentation #2
Added some AI, Map parsing, Pathfinding…
Just some new additions…
Wrote for Ruby class named PakProtocol2 for reading dlm files(maps for dofus).
This means, that i can fetch info about cell, something like… IS MOVABLE??? xD
My visualizer:
And the original dofus screenshot:
As you can see, if you rotate my visualizer by 45° CW, you can find that 3-4 cells(and the bottom one) are same as on screenshot :)
Time to learn A* pathing algorithm…
Are anyone capable to explain usage of this script?
#!/opt/local/bin/ruby
DOFUS_DIR = File.expand_path("~/Documents/Projects/DofusApp/source")
def tabs size = 3
" " * size
end
filepath_rb = ENV["TM_FILEPATH"]
filepath_as = filepath_rb.gsub(File.expand_path('~/Documents/Projects/dofus/includes'), '')
filepath_as = DOFUS_DIR + File.join(File.dirname(filepath_as).downcase, File.basename(filepath_as, File.extname(filepath_as)) + ".as")
raise unless File.exists?(filepath_as)
File.open(filepath_as) do |f|
data = f.read
as_tabs, code = data.scan(/([ \t]+)public function deserializeAs_.+?:void\s*\{\s+(.+?)\s+return.+\1\}/miu).first
new_code = code.lines.
map { |l| l.strip!; tabs + l }.
join("\n").
gsub("this.", "@").
gsub("();", "").
gsub(/var loc\d+:\*=(0|null);\s*/ium, "").
gsub(/super\.deserialize\(arg1\);/ium, "super data\n#{tabs}").
gsub(/com\.ankamagames\.jerakine\.network\.utils\.BooleanByteWrapper\.getFlag\(loc\d+,\s*(\d+)\);/iu, "BBW.get(byte, \\1)").
gsub(/if \([^\(\)]+\) \{\s+throw new Error[^\n]+\s+\}[\s\n\t]*/ium, "").
gsub(/[ \t]+var loc\d+:\*=\s*arg\d+\.readUnsignedShort\s+while.+\s+loc\d+ = arg1.(\w+)\s+(@\w+).+\s+.+\s+\}/u, <<-EOD).
#{tabs}
#{tabs}\\2 = []
#{tabs}data.readUShort.times {
#{tabs} \\2 << data.\\1
#{tabs}}
EOD
gsub(/[ \t]+var loc\d+:\*=\s*arg\d+\.readUnsignedShort\s+while.+\s+\(loc\d+ = new com[^A-Z]+(\w+).+\s+(@\w+).+\s+.+\s+\}/u, <<-EOD).
#{tabs}
#{tabs}\\2 = []
#{tabs}data.readUShort.times {
#{tabs} (obj = \\1.new).deserialize(data)
#{tabs} \\2 << obj
#{tabs}}
EOD
gsub(/[ \t]+var loc\d+:\*=\s*arg\d+\.readUnsignedShort\s+while.+\s*{\s*if \(\(loc\d+ = \w+.(read\w+).+\s*throw new Error.+\s+\}\s.+(@\w+).+\s+\+\+loc\d.+\s.+/iu, <<-EOD).
#{tabs}
#{tabs}\\2 = []
#{tabs}data.readUShort.times {
#{tabs} \\2 << data.\\1
#{tabs}}
EOD
gsub(/[^\n]+var loc\d+:\*=\s*arg\d+\.readUnsignedShort\s+while\s*\([^)]+\)\s*{\s*loc\d+ = \w+\.readUnsignedShort\s\s*\(loc\d+ = [\w\.]+ProtocolTypeManager\.getInstance.+\.deserialize\((.+)\)[^@]+(@\w+)[^}]+}\n/iu, <<-EOD).
#{tabs}
#{tabs}\\2 = []
#{tabs}data.readUShort.times {
#{tabs} type_id = data.readUShort
#{tabs} (obj = Types.get(type_id)).deserialize(\\1)
#{tabs} \\2 << obj
#{tabs}}
#{tabs}
EOD
gsub(/var loc\d:\*=arg1.readUnsignedShort\s+(@\w+) = .+ProtocolTypeManager.getInstance[^A-Z]+(\w+).+\s+\1.+/u, <<-EOD).
#{tabs}
#{tabs}type_id = data.readUShort
#{tabs}(\\1 = Types.get(type_id)).deserialize(data)
#{tabs}
EOD
gsub(/\s+(\S+) = new com.ankamagames[^A-Z]+(\w+)/u, "\n#{tabs}\n#{tabs}\\1 = \\2.new").
gsub(".deserialize(arg1);", ".deserialize(arg1)\n#{tabs}").
gsub("arg1", "data").
strip
print "#{new_code}
#{tabs}
#{tabs}false"
end
Native (packet-based) bot for Dofus
P.S. Currently in proxy-stage :)