Source: Info
Language: ActionScript 3 (Not sure)
Generally, d2p files looks like splitted archives and each one have some pack of maps in it.
Chunks of .d2p is .dlm:Code: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
Starting reading dlm structure… Map class!Code: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
Generally, i don’t care about colors & other info… i just need to get @cells informationCode: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
Fixture, Layer classes
And at last… CellData class!Code: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
You can detect “move-ability” of cell using methods: mov, nonWalkableDuringRP and nonWalkableDuringFight.Code: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
Usage
OutputCode: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
DofusInvoker (Game Flash Loader) Decompile with Sothink SWF Decompiler or somethingCode: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 ...> ]
Please register or login to download attachments.