Bonjour à tous,
Après quelques jours de réflexions sur le sujet, j'ai enfin réussi à recréer les classes Map, Fixture, Layer, Cell, CellData et les classes Elements.
Mon objectif final consiste à obtenir la position des éléments interactifs, dont les ressources, sur les cartes.
Cela fait un bon moment déjà que j'essayais de décrypter les d2p, j'ai enfin compris cette histoire de zlib et j'obtiens bien le header à 77.
Au début tout se passe bien, mais comme je vais le détailler par la suite, j'obtiens des résultats incohérents.
Je pense que j'ai raté une étape quelque part, et j'en appelle à votre bienveillance pour m'aider à l'identifier.
J'obtiens un cryptage à vrai, en version 1 et avec 8236 de dataLenght. Etant en position 12, et ayant 8248 de données, jusque là tout semble bon.
Donc ensuite on décrypte les données, qu'on peut traiter. Sauf qu'à la fin, j'arrive seulement en position 7294 !
Les points sur lesquels je m'interroge :
- les boucles sur les backgrounds, foregrounds, layers et celldata vont-elle de 0 à *count ou de 0 à *count -1 ?
- les unsignedbyte, quelle est la différence avec un simple readbyte ? -128 ?
Cela fait deux jours maintenant que je n'avance plus, je me permets donc de solliciter l'aide d'experts pour m'aider ! Je vous remercie d'avance :P
Voici mes classes actuellement, j'en appelle à votre indulgence, je débute avec le langage :p
On part d'un flux décompressé via ionic.zlib.decompress contenant les bytes du d2p (je fais mes tests sur 0/103549440.dlm et 0/119013380.dlm jusqu'à présent).
Imports System.IO
Imports System.Text
Public Class Map
Private zipReader As BigEndianReader
'Attributes
Private header As Integer
Private mapVersion As Integer
Private id As Integer
Private encrypted As Boolean
Private encryptionVersion As Integer
Private dataLen As Integer
Private relativeId As Integer
Private mapType As Integer
Private subAreaId As Integer
Private topNeighbourId As Integer
Private bottomNeighbourId As Integer
Private leftNeighbourId As Integer
Private rightNeighbourId As Integer
Private shadowBonusOnEntities 'As ULong
Private backgroundAlpha 'As Integer
Private backgroundRed 'As Integer
Private backgroundGreen 'As Integer
Private backgroundBlue ' As Integer
Private gridColor 'As Integer
Private backgroundColor 'As Integer
Private zoomScale As Double
Private zoomOffsetX As Integer
Private zoomOffsetY As Integer
Private tacticalModeTemplateId As Integer
Private useLowPassFilter As Boolean
Private useReverb As Boolean
Private presetId As Integer
Private backgroundsCount As Integer
Private foregroundsCount As Integer
Private cellsCount As Integer
Private groundCRC As Integer
Private layersCount As Integer
Public backgroundFixtures As Dictionary(Of Integer, Fixture)
Public foregroundFixtures As Dictionary(Of Integer, Fixture)
Public layers As Dictionary(Of Integer, Layer)
Public cells As Dictionary(Of Integer, CellData)
Public elements As Dictionary(Of Integer, BasicElement)
Public Sub New(ByVal str As Stream)
Dim decryptionKey As Byte()
Dim decryptionKeyString As String
decryptionKeyString = "649ae451ca33ec53bbcbcc33becf15f4"
'decryptionKey = Hex.toArray(Hex.fromString(decryptionKeyString))
decryptionKey = Encoding.UTF8.GetBytes(decryptionKeyString)
Dim i As Integer
zipReader = New BigEndianReader(str)
zipReader.Seek(0)
header = zipReader.ReadBytes(1)(0)
If header = 77 Then
mapVersion = zipReader.ReadBytes(1)(0)
id = zipReader.readUInt
If mapVersion >= 7 Then
encrypted = zipReader.ReadBoolean
encryptionVersion = zipReader.ReadBytes(1)(0)
dataLen = zipReader.ReadInt32
Dim encryptedData As Byte()
encryptedData = zipReader.ReadBytes(dataLen)
For i = 0 To encryptedData.Length - 1
encryptedData(i) = encryptedData(i) Xor decryptionKey(i Mod decryptionKey.Length)
Next
zipReader = New BigEndianReader(New MemoryStream(encryptedData))
zipReader.Seek(0)
End If
relativeId = zipReader.readUInt
mapType = zipReader.ReadBytes(1)(0)
subAreaId = zipReader.ReadInt32
topNeighbourId = zipReader.ReadInt32
bottomNeighbourId = zipReader.ReadInt32
leftNeighbourId = zipReader.ReadInt32
rightNeighbourId = zipReader.ReadInt32
shadowBonusOnEntities = zipReader.readUInt 'uint mais ça chie
Dim readColor 'As Long
Dim gridAlpha 'As Long
Dim gridRed 'As Long
Dim gridGreen ' As Long
Dim gridBlue 'As Long
If mapVersion >= 9 Then
readColor = zipReader.ReadInt32
backgroundAlpha = (readColor And 4278190080) >> 32
backgroundRed = (readColor And 16711680) >> 16
backgroundGreen = (readColor And 65280) >> 8
backgroundBlue = readColor And 255
readColor = zipReader.readUInt
gridAlpha = (readColor And 4278190080) >> 32
gridRed = (readColor And 16711680) >> 16
gridGreen = (readColor And 65280) >> 8
gridBlue = readColor And 255
gridColor = ((gridAlpha And 255) << 32) Or ((gridRed And 255) << 16) Or ((gridGreen And 255) << 8) Or (gridBlue And 255)
ElseIf mapVersion >= 3 Then
backgroundAlpha = 0
backgroundRed = zipReader.ReadInt32
backgroundGreen = zipReader.ReadInt32
backgroundBlue = zipReader.ReadInt32
End If
backgroundColor = ((backgroundAlpha And 255) << 32) Or ((backgroundRed And 255) << 16) Or ((backgroundGreen And 255) << 8) Or (backgroundBlue And 255)
If mapVersion >= 4 Then
zoomScale = zipReader.readUShort / 100
zoomOffsetX = zipReader.ReadShort
zoomOffsetY = zipReader.ReadShort
If zoomScale < 1 Then
zoomScale = 1
zoomOffsetX = 0
zoomOffsetY = 0
End If
End If
If mapVersion > 10 Then
tacticalModeTemplateId = zipReader.ReadInt32
End If
useLowPassFilter = zipReader.ReadBoolean
useReverb = zipReader.ReadBoolean
If useReverb = True Then
presetId = zipReader.ReadInt32
Else
presetId = -1
End If
backgroundsCount = zipReader.ReadBytes(1)(0)
backgroundFixtures = New Dictionary(Of Integer, Fixture)
'If backgroundsCount > 0 Then
For i = 0 To backgroundsCount
backgroundFixtures.Add(i, New Fixture(zipReader))
Next
'End If
foregroundsCount = zipReader.ReadBytes(1)(0)
foregroundFixtures = New Dictionary(Of Integer, Fixture)
'If foregroundsCount > 0 Then
For i = 0 To foregroundsCount
foregroundFixtures.Add(i, New Fixture(zipReader))
Next
'End If
cellsCount = 560 'Original dans map.as, c'est une constante dans AtouinConstants
zipReader.ReadInt32() 'Original dans maps.as
groundCRC = zipReader.ReadInt32
layersCount = zipReader.ReadBytes(1)(0)
layers = New Dictionary(Of Integer, Layer)
For i = 0 To layersCount
layers.Add(i, New Layer(zipReader, mapVersion))
Next
cells = New Dictionary(Of Integer, CellData)
For i = 0 To cellsCount
cells.Add(i, New CellData(zipReader, i, mapVersion))
'un truc sur le système de movement, skip
Next
End If
End Sub
End Class
Public Class Fixture
Private fixtureId As Integer
Private offset As Point
Private rotation As Integer
Private xScale As Integer
Private yScale As Integer
Private redMultiplier As Integer
Private greenMultiplier As Integer
Private blueMultiplier As Integer
Private hue As Integer
Private alpha As Integer
Public Sub New(ByVal reader As BigEndianReader)
fixtureId = reader.ReadInt32
Dim offsetX As Integer
Dim offsetY As Integer
offsetX = reader.ReadShort
offsetY = reader.ReadShort
offset = New Point(offsetX, offsetY)
rotation = reader.ReadShort
xScale = reader.ReadShort
yScale = reader.ReadShort
redMultiplier = reader.ReadBytes(1)(0) - 128
greenMultiplier = reader.ReadBytes(1)(0) - 128
blueMultiplier = reader.ReadBytes(1)(0) - 128
hue = redMultiplier Or greenMultiplier Or blueMultiplier
alpha = reader.ReadBytes(1)(0)
End Sub
End Class
Public Class Layer
Private layerId As Integer
Private cellsCount As Integer
Public cells As Dictionary(Of Integer, Cell)
Public Sub New(ByVal reader As BigEndianReader, ByVal mapVersion As Integer)
If mapVersion >= 9 Then
layerId = reader.ReadBytes(1)(0)
Else
layerId = reader.ReadInt32
End If
cellsCount = reader.ReadShort()
If cellsCount > 0 Then
Dim i As Integer
cells = New Dictionary(Of Integer, Cell)
For i = 0 To cellsCount
cells.Add(i, New Cell(reader, mapVersion))
Next
Dim maxMapCellId As Integer
maxMapCellId = 560 - 1
'si la dernière cellule est inférieure à 560, créer des cellules vides jusqu'à la 560ème
End If
End Sub
End Class
Public Class Cell
Private cellId As Integer
Private elementsCount As Integer
Private elements As Dictionary(Of Integer, BasicElement)
Public Sub New(ByVal reader As BigEndianReader, ByVal mapVersion As Integer)
Dim be As BasicElement
Dim i As Integer
cellId = reader.ReadShort
elementsCount = reader.ReadShort
elements = New Dictionary(Of Integer, BasicElement)
For i = 0 To elementsCount
be = New BasicElement().getElementFromType(reader, mapVersion)
elements.Add(i, be)
Next
End Sub
End Class
Public Class CellData
Private id As Integer
Private _floor As Integer
Private _mov As Boolean
Private _nonWalkableDuringFight As Boolean
Private _nonWalkableDuringRP As Boolean
Private _los As Boolean
Private _blue As Boolean
Private _red As Boolean
Private _visible As Boolean
Private _farmCell As Boolean
Private _havenbagCell As Boolean
Private _losmov As Integer = 3
Private speed As Integer
Private mapChangeData As Integer
Private moveZone As Integer
Private _linkedZone As Integer
Private _arrow As Integer = 0
Public Sub New(ByVal reader As BigEndianReader, ByVal cellId As Integer, ByVal mapVersion As Integer)
id = cellId
_floor = reader.ReadBytes(1)(0) * 10
If _floor = -1280 Then
Exit Sub
End If
Dim tmpbytesv9 As Integer
Dim topArrow As Boolean = False
Dim bottomArrow As Boolean = False
Dim rightArrow As Boolean = False
Dim leftArrow As Boolean = False
Dim tmpBits As Integer = 0
If mapVersion >= 9 Then
tmpbytesv9 = reader.ReadBytes(1)(0)
_mov = (tmpbytesv9 & 1) = 0
_nonWalkableDuringFight = (tmpbytesv9 & 2) <> 0
_nonWalkableDuringRP = (tmpbytesv9 & 4) <> 0
_los = (tmpbytesv9 & 8) = 0
_blue = (tmpbytesv9 & 16) <> 0
_red = (tmpbytesv9 & 32) <> 0
_visible = (tmpbytesv9 & 64) <> 0
_farmCell = (tmpbytesv9 & 128) <> 0
If mapVersion >= 10 Then
_havenbagCell = (tmpbytesv9 & 256) <> 0
topArrow = (tmpbytesv9 & 512) <> 0
bottomArrow = (tmpbytesv9 & 1024) <> 0
rightArrow = (tmpbytesv9 & 2048) <> 0
leftArrow = (tmpbytesv9 & 4096) <> 0
Else
topArrow = (tmpbytesv9 & 256) <> 0
bottomArrow = (tmpbytesv9 & 512) <> 0
rightArrow = (tmpbytesv9 & 1024) <> 0
leftArrow = (tmpbytesv9 & 2048) <> 0
End If
Else
_losmov = reader.ReadBytes(1)(0)
_los = (_losmov & 2) >> 1 = 1
_mov = (_losmov & 1) = 1
_visible = (_losmov & 64) >> 6 = 1
_farmCell = (_losmov & 32) >> 5 = 1
_blue = (_losmov & 16) >> 4 = 1
_red = (_losmov & 8) >> 3 = 1
_nonWalkableDuringRP = (_losmov & 128) >> 7 = 1
_nonWalkableDuringFight = (_losmov & 4) >> 2 = 1
End If
speed = reader.ReadBytes(1)(0)
mapChangeData = reader.ReadBytes(1)(0)
If mapVersion > 5 Then
moveZone = reader.ReadBytes(1)(0)
End If
If mapVersion > 10 And ((_mov And Not _farmCell) Or (_mov And Not _nonWalkableDuringFight And Not _farmCell And Not _havenbagCell)) Then
_linkedZone = reader.ReadBytes(1)(0)
End If
If mapVersion = 8 Then
tmpBits = reader.ReadBytes(1)(0)
_arrow = 15 & tmpBits
End If
End Sub
End Class
Public Class BasicElement
Public Function getBe(ByVal be As BasicElement)
Return be
End Function
Public Function getElementFromType(ByVal reader As BigEndianReader, ByVal mapVersion As Integer) As BasicElement
Dim type As Integer
type = reader.ReadBytes(1)(0)
If type = 2 Then
Return New GraphicalElement(reader, mapVersion)
ElseIf type = 33 Then
Return New SoundElement(reader, mapVersion)
Else
Return Nothing
End If
End Function
End Class
Public Class GraphicalElement
Inherits BasicElement
Private elementId As Integer
Private hue As Integer
Private shadow As Integer
Private offset As Point
Private pixelOffset As Point
Private altitude As Integer
Private identifier As Integer
Public Sub New(ByVal reader As BigEndianReader, ByVal mapVersion As Integer)
elementId = reader.readUInt
'hue colormultiplicator skip
hue = reader.ReadBytes(1)(0)
hue = reader.ReadBytes(1)(0)
hue = reader.ReadBytes(1)(0)
'shadow colormultiplicator skip
shadow = reader.ReadBytes(1)(0)
shadow = reader.ReadBytes(1)(0)
shadow = reader.ReadBytes(1)(0)
offset = New Point(0, 0)
pixelOffset = New Point(0, 0)
If mapVersion <= 4 Then
offset.x = reader.ReadBytes(1)(0)
offset.y = reader.ReadBytes(1)(0)
pixelOffset.x = offset.x * 43
pixelOffset.y = offset.y * 21.5
Else
pixelOffset.x = reader.ReadShort
pixelOffset.y = reader.ReadShort
offset.x = pixelOffset.x / 43 'atouin half width const
offset.y = pixelOffset.y / 21.5 'atouin half height const
End If
altitude = reader.ReadBytes(1)(0)
identifier = reader.readUInt
'CalculateFinalTeint
End Sub
End Class
Public Class SoundElement
Inherits BasicElement
Private soundId As Integer
Private baseVolume As Integer
Private fullVolumeDistance As Integer
Private nullVolumeDistance As Integer
Private minDelayBetweenLoops As Integer
Private maxDelayBetweenLoops As Integer
Public Sub New(ByVal reader As BigEndianReader, ByVal mapVersion As Integer)
soundId = reader.ReadInt32
baseVolume = reader.ReadShort
fullVolumeDistance = reader.ReadInt32
nullVolumeDistance = reader.ReadInt32
minDelayBetweenLoops = reader.ReadShort
maxDelayBetweenLoops = reader.ReadShort
End Sub
End Class
Imports System.IO
Imports System.Text
Public Class BigEndianReader
Protected self As BinaryReader
'Flash info on how to read binary data
'http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/IDataInput.html
Public Sub New(Stream As Stream) 'old: filestream
self = New BinaryReader(Stream, Encoding.UTF8)
End Sub
Public Function ReadInt32()
Dim Bits As Byte() = self.ReadBytes(4)
Array.Reverse(Bits)
Return BitConverter.ToInt32(Bits, 0)
End Function
Public Function ReadBoolean()
Dim bool As Boolean = BitConverter.ToBoolean(self.ReadBytes(1), 0)
If bool Then
Return 1
Else
Return 0
End If
End Function
Public Function ReadShort()
Dim Bits As Byte() = self.ReadBytes(2)
Array.Reverse(Bits)
Return BitConverter.ToInt16(Bits, 0)
End Function
Public Function ReadUTF()
Dim n As Integer = ReadShort()
Dim Bits As Byte() = self.ReadBytes(n)
Return Encoding.UTF8.GetString(Bits)
End Function
Public Function ReadBytes(ByVal Number As Integer)
Return self.ReadBytes(Number)
End Function
Public Function readDouble()
Dim Bits As Byte() = self.ReadBytes(8)
Array.Reverse(Bits)
Return BitConverter.ToDouble(Bits, 0)
End Function
Public Function readUInt()
Dim Bits As Byte() = self.ReadBytes(4)
Array.Reverse(Bits)
Return BitConverter.ToUInt32(Bits, 0)
End Function
Public Function readUShort()
Dim Bits As Byte() = self.ReadBytes(2)
Array.Reverse(Bits)
Return BitConverter.ToUInt16(Bits, 0)
End Function
Public Function Position()
Return self.BaseStream.Position
End Function
Public Function Seek(ByVal offset As Long)
self.BaseStream.Seek(offset, SeekOrigin.Begin)
Return True
End Function
End Class
Etant novice, les conseils tant sur la forme que sur le fond du code sont également fort bienvenus ! Merci