Posts filled under: bot
WordSquared bot
Looks like i wrote a good enough bot for http://wordsquared.com/
Version 0.1b at youtube: http://www.youtube.com/watch?v=NilCjtRIvng
It was more laggy, than current :)
As below log shows, its completing words with 2-4w per 1s, but this affected only by my current internet connection.
Later i’ll move it to dedicated server in hetzner.de to test European’s speed.
P.S. from 3k point to 10k in 10 mins :) P.S.S. Still using http://wordsolver.net/ word’s database -.-
Logged as Bubonic Pestilence
Loading game .. OK
@ws.tiles: 1.678851842880249 parse: 0.00460505485534668
9958 6998 A DIRECTION: bottom SIZE: 11 WORD: ALB
9918 6997 H DIRECTION: left SIZE: 11 WORD: LECH
9958 6997 L DIRECTION: left SIZE: 11 WORD: EXCEL
9958 6996 B DIRECTION: right SIZE: 11 WORD: BECK
9959 6996 E DIRECTION: bottom SIZE: 11 WORD: EMEU
9961 6996 K DIRECTION: bottom SIZE: 11 WORD: KAYO
9921 6995 O DIRECTION: bottom SIZE: 11 WORD: OAT
9923 6995 E DIRECTION: top SIZE: 3 WORD: DYE
9961 6995 A DIRECTION: right SIZE: 11 WORD: AFT
9963 6995 T DIRECTION: bottom SIZE: 11 WORD: TAXI
9921 6994 A DIRECTION: left SIZE: 11 WORD: RAJA
9950 6994 J DIRECTION: right SIZE: 8 WORD: JAWS
9951 6994 A DIRECTION: top SIZE: 9 WORD: HANSA
9952 6994 W DIRECTION: top SIZE: 8 WORD: SHAW
9953 6994 S DIRECTION: bottom SIZE: 5 WORD: SAINS
9959 6994 E DIRECTION: left SIZE: 5 WORD: HAME
9963 6994 A DIRECTION: right SIZE: 11 WORD: AHI
9921 6993 T DIRECTION: right SIZE: 2 WORD: TI
9922 6993 I DIRECTION: bottom SIZE: 3 WORD: IRE
9945 6993 R DIRECTION: left SIZE: 3 WORD: PUR
9950 6993 A DIRECTION: left SIZE: 3 WORD: BA
9953 6993 A DIRECTION: right SIZE: 3 WORD: AVE
9955 6993 E DIRECTION: bottom SIZE: 6 WORD: EDS
9953 6992 I DIRECTION: left SIZE: 2 WORD: TI
9963 6992 I DIRECTION: right SIZE: 11 WORD: IN
9922 6991 E DIRECTION: left SIZE: 11 WORD: RE
9925 6990 E DIRECTION: bottom SIZE: 11 WORD: EF
9926 6990 A DIRECTION: bottom SIZE: 11 WORD: ADZ
9951 6985 E DIRECTION: bottom SIZE: 11 WORD: EF
9957 7029 I DIRECTION: left SIZE: 11 WORD: QI
9959 7029 I DIRECTION: right SIZE: 11 WORD: IF
9891 7028 R DIRECTION: right SIZE: 2 WORD: RE
9897 7028 B DIRECTION: bottom SIZE: 2 WORD: BE
9940 7028 E DIRECTION: right SIZE: 4 WORD: ED
9897 7027 E DIRECTION: left SIZE: 5 WORD: DICE
9897 7025 E DIRECTION: left SIZE: 11 WORD: WE
9942 7025 O DIRECTION: bottom SIZE: 3 WORD: OS
9961 7025 D DIRECTION: right SIZE: 11 WORD: DIG
9962 7025 I DIRECTION: top SIZE: 11 WORD: QI
9963 7025 G DIRECTION: bottom SIZE: 11 WORD: GINKS
9954 7024 Y DIRECTION: top SIZE: 11 WORD: BY
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.
MovementRequestMessage -> AutoBan for 2 hours
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…
Oh yeah!
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
Dofus «login -> game» sequence
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
Output
[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 :)
Unpacking Dofus’ d2p files… the source of PakProtocol2
Generally, d2p files looks like splitted archives and each one have some pack of maps in it.
.d2p or PakProtocol2 files
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
chunks of .d2p is .dlm:
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
Starting reading dlm structure… Map class!
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 :)
Fixture, Layer classes
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
And at last… CellData class!
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.
Usage
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
Output
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…
Native (packet-based) bot for Dofus
P.S. Currently in proxy-stage :)

