Ir para conteúdo

Posts Recomendados

Tibia: Estrutura do Arquivo Dat

 

Versão em português:

 

Nota: A partir de digitar isso, a estrutura Estarei postando trabalhos com a versão atual do cliente, 9,44, e deve funcionar de volta até a bandeira isSprite (8,54?). Quando eu chegar em tempo eu vou atualizar isso para apoiar as estruturas arquivo DAT, tanto para trás que eu puder.

 

* Todos os nomes que eu uso são o que a CipSoft usa em seu cliente flash. Mas eu também comentou ao lado o que pode ser confuso.

- Os primeiros 4 bytes do arquivo DAT, que eu chamo de DATVERSION, é único para cada versão do cliente para que o cliente sabe que o arquivo Dat correto está sendo usado.

- Em seguida, temos 4 calções (2 bytes cada) que contêm o número de itens, equipamentos, efeitos e projéteis (respectivamente) no arquivo DAT.

- Agora começa os dados reais desses objetos. A primeira coisa que você vai encontrar são o que chamamos Flags. Estas bandeiras deixar o cliente saber se o item pode ser pisado, se ele pode ser pego, se ele emite luz, etc, etc

 

 

Dim Flag_Bank As Byte = 0

Dim Flag_Clip As Byte = 1

Dim Flag_Bottom As Byte = 2

Dim Flag_Top As Byte = 3

Dim Flag_Container As Byte = 4

Dim Flag_Cumulative As Byte = 5

Dim Flag_ForceUse As Byte = 6

Dim Flag_MultiUse As Byte = 7

Dim Flag_Write As Byte = 8

Dim Flag_WriteOnce As Byte = 9

Dim Flag_LiquidContainer As Byte = 10

Dim Flag_LiquidPool As Byte = 11

Dim Flag_Unpass As Byte = 12

Dim Flag_Unmove As Byte = 13

Dim Flag_Unsight As Byte = 14

Dim Flag_Avoid As Byte = 15

Dim Flag_Take As Byte = 16

Dim Flag_Hang As Byte = 17

Dim Flag_HookSouth As Byte = 18

Dim Flag_HookEast As Byte = 19

Dim Flag_Rotate As Byte = 20

Dim Flag_Light As Byte = 21

Dim Flag_DontHide As Byte = 22

Dim Flag_Translucent As Byte = 23

Dim Flag_Shift As Byte = 24

Dim Flag_Height As Byte = 25

Dim Flag_LyingObject As Byte = 26

Dim Flag_AnimateAlways As Byte = 27

Dim Flag_Automap As Byte = 28

Dim Flag_LensHelp As Byte = 29

Dim Flag_FullBank As Byte = 30

Dim Flag_IgnoreLook As Byte = 31

Dim Flag_Clothes As Byte = 32

Dim Flag_Market As Byte = 33

 

- Como você pode ver acima, temos uma bandeira novo mercado. Este foi introduzido com o novo sistema de mercado em que o cliente 9,41. Aqui estão as categorias de mercado associados:

 

Private Enum MarketCategory

Armors = 1

Amulets = 2

Boots = 3

Containers = 4

Decoration = 5

Food = 6

Helmets_Hats = 7

Legs = 8

Others = 9

Potions = 10

Rings = 11

Runes = 12

Shields = 13

Tools = 14

Valuables = 15

Ammunition = 16

Axes = 17

Clubs = 18

DistanceWeapons = 19

Swords = 20

Wands_Rods = 21

MetaWeapons = 22

End Enum

 

- Depois de passar por todos os bytes nos deparamos com as informações necessárias para os sprites do objeto. (altura, largura, camadas, fases, etc)

- Em seguida, loop através de todos os sprites disponíveis associados com o item.

- E é isso. Esperamos que para o próximo objeto e fazê-lo novamente.

 

Agora, aqui está o código usado para ler o arquivo DAT que você pode jogar para VB.Net e correr. Se você tiver alguma dúvida não hesite em perguntar:

 

Public Class Form1

Dim dataArray As ItemData()

 

Dim Flag_Bank As Byte = 0 'ground tile

Dim Flag_Clip As Byte = 1

Dim Flag_Bottom As Byte = 2

Dim Flag_Top As Byte = 3

Dim Flag_Container As Byte = 4

Dim Flag_Cumulative As Byte = 5 'stackable

Dim Flag_ForceUse As Byte = 6 'always used

Dim Flag_MultiUse As Byte = 7 'usable

Dim Flag_Write As Byte = 8 'writeable

Dim Flag_WriteOnce As Byte = 9 'readable

Dim Flag_LiquidContainer As Byte = 10

Dim Flag_LiquidPool As Byte = 11 'splashes

Dim Flag_Unpass As Byte = 12

Dim Flag_Unmove As Byte = 13

Dim Flag_Unsight As Byte = 14 'blocks projectiles

Dim Flag_Avoid As Byte = 15 'blocks creature movements

Dim Flag_Take As Byte = 16 'pickupable

Dim Flag_Hang As Byte = 17

Dim Flag_HookSouth As Byte = 18

Dim Flag_HookEast As Byte = 19

Dim Flag_Rotate As Byte = 20

Dim Flag_Light As Byte = 21

Dim Flag_DontHide As Byte = 22

Dim Flag_Translucent As Byte = 23

Dim Flag_Shift As Byte = 24

Dim Flag_Height As Byte = 25

Dim Flag_LyingObject As Byte = 26

Dim Flag_AnimateAlways As Byte = 27

Dim Flag_Automap As Byte = 28

Dim Flag_LensHelp As Byte = 29

Dim Flag_FullBank As Byte = 30

Dim Flag_IgnoreLook As Byte = 31

Dim Flag_Clothes As Byte = 32

Dim Flag_Market As Byte = 33

 

Private Enum MarketCategory

Armors = 1

Amulets = 2

Boots = 3

Containers = 4

Decoration = 5

Food = 6

Helmets_Hats = 7

Legs = 8

Others = 9

Potions = 10

Rings = 11

Runes = 12

Shields = 13

Tools = 14

Valuables = 15

Ammunition = 16

Axes = 17

Clubs = 18

DistanceWeapons = 19

Swords = 20

Wands_Rods = 21

MetaWeapons = 22 'all weapons

End Enum

 

Private Structure ItemData

Dim ID As Integer

 

Dim isBank As Boolean

Dim Waypoints As Integer

Dim isClip As Boolean

Dim isBottom As Boolean

Dim isTop As Boolean

Dim isContainer As Boolean

Dim isCumulative As Boolean

Dim isForceUse As Boolean

Dim isMultiUse As Boolean

Dim isWriteable As Boolean

Dim MaxTextLength As Integer

Dim isWriteableOnce As Boolean

Dim isLiquidContainer As Boolean

Dim isLiquidPool As Boolean

Dim isUnpassable As Boolean

Dim isUnmoveable As Boolean

Dim isUnsight As Boolean

Dim isAvoid As Boolean

Dim isTakeable As Boolean

Dim isHangable As Boolean

Dim isHookSouth As Boolean

Dim isHookEast As Boolean

Dim isRotateable As Boolean

Dim isLight As Boolean

Dim Brightness As Integer

Dim LightColor As Integer

Dim isDontHide As Boolean

Dim isTranslucent As Boolean

Dim isDisplaced As Boolean

Dim DisplacementX As Integer

Dim DisplacementY As Integer

Dim isHeight As Boolean

Dim Elevation As Integer

Dim isLyingObject As Boolean

Dim isAnimateAlways As Boolean

Dim isAutomap As Boolean

Dim isAutomapColor As Integer

Dim isLensHelp As Boolean

Dim LensHelp As Integer

Dim isFullBank As Boolean

Dim isIgnoreLook As Boolean

Dim isCloth As Boolean

Dim ClothSlot As Integer

Dim isMarket As Boolean

Dim MarketCategory As MarketCategory

Dim MarketTradeAs As Integer

Dim MarketShowAs As Integer

Dim MarketName As String

Dim MarketRestrictProfession As Integer

Dim MarketRestrictLevel As Integer

 

Dim Width As Integer

Dim Height As Integer

Dim ExactSize As Integer

Dim Layers As Integer

Dim PatternWidth As Integer

Dim PatternHeight As Integer

Dim PatternDepth As Integer

Dim Phases As Integer

Dim NumberOfSprites As Integer

 

Dim Sprites As Integer()

End Structure

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim FileName As String = vbNullString

MessageBox.Show("Please locate and open your Tibia.dat file", ".dat Reader")

With OpenFileDialog1

.Filter = "Dat file (*.dat)|*.dat|" & "All files|*.*"

If .ShowDialog = Windows.Forms.DialogResult.OK Then

FileName = .FileName

Else

Application.Exit()

End If

End With

 

Using reader As New IO.BinaryReader(IO.File.OpenRead(FileName))

Dim DatVersion As Integer = reader.ReadUInt32()

Dim Items As Integer = reader.ReadUInt16()

Dim Outfits As Integer = reader.ReadUInt16()

Dim Effects As Integer = reader.ReadUInt16()

Dim Projectiles As Integer = reader.ReadUInt16()

 

Dim maxID As Integer = Items + Outfits + Effects + Projectiles

Dim ID As Integer = 100

 

dataArray = Array.CreateInstance(GetType(ItemData), maxID - ID)

 

Do While (ID < maxID)

Dim itemData As New ItemData

itemData.ID = ID

Do

Dim optByte As Byte

optByte = reader.ReadByte()

Select Case optByte

Case Flag_Bank

itemData.isBank = True

itemData.Waypoints = reader.ReadUInt16() 'ground speed

Case Flag_Clip

itemData.isClip = True

Case Flag_Bottom

itemData.isBottom = True

Case Flag_Top

itemData.isTop = True

Case Flag_Container

itemData.isContainer = True

Case Flag_Cumulative

itemData.isCumulative = True

Case Flag_ForceUse

itemData.isForceUse = True

Case Flag_MultiUse

itemData.isMultiUse = True

Case Flag_Write

itemData.isWriteable = True

itemData.MaxTextLength = reader.ReadUInt16()

Case Flag_WriteOnce

itemData.isWriteableOnce = True

itemData.MaxTextLength = reader.ReadUInt16()

Case Flag_LiquidContainer

itemData.isLiquidContainer = True

Case Flag_LiquidPool

itemData.isLiquidPool = True

Case Flag_Unpass

itemData.isUnpassable = True

Case Flag_Unmove

itemData.isUnmoveable = True

Case Flag_Unsight

itemData.isUnsight = True

Case Flag_Avoid

itemData.isAvoid = True

Case Flag_Take

itemData.isTakeable = True

Case Flag_Hang

itemData.isHangable = True

Case Flag_HookSouth

itemData.isHookSouth = True

Case Flag_HookEast

itemData.isHookEast = True

Case Flag_Rotate

itemData.isRotateable = True

Case Flag_Light

itemData.isLight = True

itemData.Brightness = reader.ReadUInt16()

itemData.LightColor = reader.ReadUInt16()

Case Flag_DontHide

itemData.isDontHide = True

Case Flag_Translucent

itemData.isTranslucent = True

Case Flag_Shift

itemData.isDisplaced = True

itemData.DisplacementX = reader.ReadUInt16()

itemData.DisplacementY = reader.ReadUInt16()

Case Flag_Height

itemData.isHeight = True

itemData.Elevation = reader.ReadUInt16()

Case Flag_LyingObject

itemData.isLyingObject = True

Case Flag_AnimateAlways

itemData.isAnimateAlways = True

Case Flag_Automap

itemData.isAutomap = True

itemData.isAutomapColor = reader.ReadUInt16()

Case Flag_LensHelp

itemData.isLensHelp = True

itemData.LensHelp = reader.ReadUInt16()

Case Flag_FullBank

itemData.isFullBank = True

Case Flag_IgnoreLook

itemData.isIgnoreLook = True

Case Flag_Clothes

itemData.isCloth = True

itemData.ClothSlot = reader.ReadUInt16() 'head, torso, legs, feet, etc.

Case Flag_Market

itemData.isMarket = True

itemData.MarketCategory = reader.ReadUInt16() 'see the MarketCategory enum above

itemData.MarketTradeAs = reader.ReadUInt16()

itemData.MarketShowAs = reader.ReadUInt16()

 

'using the binary reader's ReadString() function returned the correctly lengthed string, but started a character early

'eg. "gold coin" would say " gold coi"

'to bypass this I just read the string length (first 2 bytes) then read that many bytes

'but the string is iso-8859-1 encoded, so you have to decode it to get the actual string

Dim MarketNameLength As Integer = reader.ReadUInt16()

itemData.MarketName = System.Text.Encoding.GetEncoding("iso-8859-1").GetString(reader.ReadBytes(MarketNameLength))

 

itemData.MarketRestrictProfession = reader.ReadUInt16()

itemData.MarketRestrictLevel = reader.ReadUInt16()

Case 255

Exit Do

Case Else

MessageBox.Show("Invalid flag!: " & optByte.ToString)

End Select

Loop

 

itemData.Width = reader.ReadByte()

itemData.Height = reader.ReadByte()

If itemData.Width > 1 Or itemData.Height > 1 Then

itemData.ExactSize = reader.ReadByte()

End If

 

itemData.Layers = reader.ReadByte()

itemData.PatternWidth = reader.ReadByte()

itemData.PatternHeight = reader.ReadByte()

itemData.PatternDepth = reader.ReadByte()

itemData.Phases = reader.ReadByte()

 

Dim numSpr As Integer = itemData.Width * itemData.Height

numSpr *= itemData.Layers * itemData.PatternWidth

numSpr *= itemData.PatternHeight * itemData.PatternDepth

numSpr *= itemData.Phases

 

itemData.NumberOfSprites = numSpr

 

itemData.Sprites = Array.CreateInstance(GetType(Integer), itemData.NumberOfSprites)

For i As Integer = 0 To itemData.NumberOfSprites - 1

itemData.Sprites(i) = reader.ReadUInt16()

Next

 

dataArray(ID - 100) = itemData

ID += 1

Loop

End Using

End Sub

End Class

 

Todos os objetos são armazenados na matriz de dados e você pode acessar objetos de identificação. Aqui está um exemplo:

 

Dim GoldCoin As ItemData = dataArray(3031 - 100) '3031 is the ID of gold coin; we have to subtract 100 because the array is 0-based

 

 

Tibia: Data File Structure

Versão original em inglês:

 

Note: As of typing this, the structure I'll be posting works with the current client version, 9.44, and should work back until the isSprite flag (8.54?). When I get time I'll update this to support Dat file structures as far back as I can.

 

*All the names I use are what CipSoft uses in their flash client. But I also commented beside what may be confusing.

- The first 4 bytes of the Dat file, which I call the DatVersion, is unique for each client version so that the client knows that the correct Dat file is being used.

- Next we have 4 shorts (2 bytes each) that contain the number of items, outfits, effects, and projectiles (respectively) in the Dat file.

- Now starts the actual data of these objects. The first thing you'll encounter are what we call Flags. These Flags let the client know if the item can be walked on, if it can be picked up, if it gives off light, etc. etc.

 

 

Dim Flag_Bank As Byte = 0

Dim Flag_Clip As Byte = 1

Dim Flag_Bottom As Byte = 2

Dim Flag_Top As Byte = 3

Dim Flag_Container As Byte = 4

Dim Flag_Cumulative As Byte = 5

Dim Flag_ForceUse As Byte = 6

Dim Flag_MultiUse As Byte = 7

Dim Flag_Write As Byte = 8

Dim Flag_WriteOnce As Byte = 9

Dim Flag_LiquidContainer As Byte = 10

Dim Flag_LiquidPool As Byte = 11

Dim Flag_Unpass As Byte = 12

Dim Flag_Unmove As Byte = 13

Dim Flag_Unsight As Byte = 14

Dim Flag_Avoid As Byte = 15

Dim Flag_Take As Byte = 16

Dim Flag_Hang As Byte = 17

Dim Flag_HookSouth As Byte = 18

Dim Flag_HookEast As Byte = 19

Dim Flag_Rotate As Byte = 20

Dim Flag_Light As Byte = 21

Dim Flag_DontHide As Byte = 22

Dim Flag_Translucent As Byte = 23

Dim Flag_Shift As Byte = 24

Dim Flag_Height As Byte = 25

Dim Flag_LyingObject As Byte = 26

Dim Flag_AnimateAlways As Byte = 27

Dim Flag_Automap As Byte = 28

Dim Flag_LensHelp As Byte = 29

Dim Flag_FullBank As Byte = 30

Dim Flag_IgnoreLook As Byte = 31

Dim Flag_Clothes As Byte = 32

Dim Flag_Market As Byte = 33

- As you can see above we have a new Market flag. This was introduced with the new Market system in the 9.41 client. Here are the market categories associated with it:

 

Private Enum MarketCategory

Armors = 1

Amulets = 2

Boots = 3

Containers = 4

Decoration = 5

Food = 6

Helmets_Hats = 7

Legs = 8

Others = 9

Potions = 10

Rings = 11

Runes = 12

Shields = 13

Tools = 14

Valuables = 15

Ammunition = 16

Axes = 17

Clubs = 18

DistanceWeapons = 19

Swords = 20

Wands_Rods = 21

MetaWeapons = 22

End Enum

- After we go through all the bytes we come across the information needed for the sprites of the object. (height, width, layers, phases, etc.)

- Then we loop through all the available sprites associated with the item.

- And that's it. We hope on to the next object and do it again.

 

Now, here's code used to read the Dat file that you can throw in to VB.Net and run. If you have any questions feel free to ask:

 

Public Class Form1

Dim dataArray As ItemData()

 

Dim Flag_Bank As Byte = 0 'ground tile

Dim Flag_Clip As Byte = 1

Dim Flag_Bottom As Byte = 2

Dim Flag_Top As Byte = 3

Dim Flag_Container As Byte = 4

Dim Flag_Cumulative As Byte = 5 'stackable

Dim Flag_ForceUse As Byte = 6 'always used

Dim Flag_MultiUse As Byte = 7 'usable

Dim Flag_Write As Byte = 8 'writeable

Dim Flag_WriteOnce As Byte = 9 'readable

Dim Flag_LiquidContainer As Byte = 10

Dim Flag_LiquidPool As Byte = 11 'splashes

Dim Flag_Unpass As Byte = 12

Dim Flag_Unmove As Byte = 13

Dim Flag_Unsight As Byte = 14 'blocks projectiles

Dim Flag_Avoid As Byte = 15 'blocks creature movements

Dim Flag_Take As Byte = 16 'pickupable

Dim Flag_Hang As Byte = 17

Dim Flag_HookSouth As Byte = 18

Dim Flag_HookEast As Byte = 19

Dim Flag_Rotate As Byte = 20

Dim Flag_Light As Byte = 21

Dim Flag_DontHide As Byte = 22

Dim Flag_Translucent As Byte = 23

Dim Flag_Shift As Byte = 24

Dim Flag_Height As Byte = 25

Dim Flag_LyingObject As Byte = 26

Dim Flag_AnimateAlways As Byte = 27

Dim Flag_Automap As Byte = 28

Dim Flag_LensHelp As Byte = 29

Dim Flag_FullBank As Byte = 30

Dim Flag_IgnoreLook As Byte = 31

Dim Flag_Clothes As Byte = 32

Dim Flag_Market As Byte = 33

 

Private Enum MarketCategory

Armors = 1

Amulets = 2

Boots = 3

Containers = 4

Decoration = 5

Food = 6

Helmets_Hats = 7

Legs = 8

Others = 9

Potions = 10

Rings = 11

Runes = 12

Shields = 13

Tools = 14

Valuables = 15

Ammunition = 16

Axes = 17

Clubs = 18

DistanceWeapons = 19

Swords = 20

Wands_Rods = 21

MetaWeapons = 22 'all weapons

End Enum

 

Private Structure ItemData

Dim ID As Integer

 

Dim isBank As Boolean

Dim Waypoints As Integer

Dim isClip As Boolean

Dim isBottom As Boolean

Dim isTop As Boolean

Dim isContainer As Boolean

Dim isCumulative As Boolean

Dim isForceUse As Boolean

Dim isMultiUse As Boolean

Dim isWriteable As Boolean

Dim MaxTextLength As Integer

Dim isWriteableOnce As Boolean

Dim isLiquidContainer As Boolean

Dim isLiquidPool As Boolean

Dim isUnpassable As Boolean

Dim isUnmoveable As Boolean

Dim isUnsight As Boolean

Dim isAvoid As Boolean

Dim isTakeable As Boolean

Dim isHangable As Boolean

Dim isHookSouth As Boolean

Dim isHookEast As Boolean

Dim isRotateable As Boolean

Dim isLight As Boolean

Dim Brightness As Integer

Dim LightColor As Integer

Dim isDontHide As Boolean

Dim isTranslucent As Boolean

Dim isDisplaced As Boolean

Dim DisplacementX As Integer

Dim DisplacementY As Integer

Dim isHeight As Boolean

Dim Elevation As Integer

Dim isLyingObject As Boolean

Dim isAnimateAlways As Boolean

Dim isAutomap As Boolean

Dim isAutomapColor As Integer

Dim isLensHelp As Boolean

Dim LensHelp As Integer

Dim isFullBank As Boolean

Dim isIgnoreLook As Boolean

Dim isCloth As Boolean

Dim ClothSlot As Integer

Dim isMarket As Boolean

Dim MarketCategory As MarketCategory

Dim MarketTradeAs As Integer

Dim MarketShowAs As Integer

Dim MarketName As String

Dim MarketRestrictProfession As Integer

Dim MarketRestrictLevel As Integer

 

Dim Width As Integer

Dim Height As Integer

Dim ExactSize As Integer

Dim Layers As Integer

Dim PatternWidth As Integer

Dim PatternHeight As Integer

Dim PatternDepth As Integer

Dim Phases As Integer

Dim NumberOfSprites As Integer

 

Dim Sprites As Integer()

End Structure

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim FileName As String = vbNullString

MessageBox.Show("Please locate and open your Tibia.dat file", ".dat Reader")

With OpenFileDialog1

.Filter = "Dat file (*.dat)|*.dat|" & "All files|*.*"

If .ShowDialog = Windows.Forms.DialogResult.OK Then

FileName = .FileName

Else

Application.Exit()

End If

End With

 

Using reader As New IO.BinaryReader(IO.File.OpenRead(FileName))

Dim DatVersion As Integer = reader.ReadUInt32()

Dim Items As Integer = reader.ReadUInt16()

Dim Outfits As Integer = reader.ReadUInt16()

Dim Effects As Integer = reader.ReadUInt16()

Dim Projectiles As Integer = reader.ReadUInt16()

 

Dim maxID As Integer = Items + Outfits + Effects + Projectiles

Dim ID As Integer = 100

 

dataArray = Array.CreateInstance(GetType(ItemData), maxID - ID)

 

Do While (ID < maxID)

Dim itemData As New ItemData

itemData.ID = ID

Do

Dim optByte As Byte

optByte = reader.ReadByte()

Select Case optByte

Case Flag_Bank

itemData.isBank = True

itemData.Waypoints = reader.ReadUInt16() 'ground speed

Case Flag_Clip

itemData.isClip = True

Case Flag_Bottom

itemData.isBottom = True

Case Flag_Top

itemData.isTop = True

Case Flag_Container

itemData.isContainer = True

Case Flag_Cumulative

itemData.isCumulative = True

Case Flag_ForceUse

itemData.isForceUse = True

Case Flag_MultiUse

itemData.isMultiUse = True

Case Flag_Write

itemData.isWriteable = True

itemData.MaxTextLength = reader.ReadUInt16()

Case Flag_WriteOnce

itemData.isWriteableOnce = True

itemData.MaxTextLength = reader.ReadUInt16()

Case Flag_LiquidContainer

itemData.isLiquidContainer = True

Case Flag_LiquidPool

itemData.isLiquidPool = True

Case Flag_Unpass

itemData.isUnpassable = True

Case Flag_Unmove

itemData.isUnmoveable = True

Case Flag_Unsight

itemData.isUnsight = True

Case Flag_Avoid

itemData.isAvoid = True

Case Flag_Take

itemData.isTakeable = True

Case Flag_Hang

itemData.isHangable = True

Case Flag_HookSouth

itemData.isHookSouth = True

Case Flag_HookEast

itemData.isHookEast = True

Case Flag_Rotate

itemData.isRotateable = True

Case Flag_Light

itemData.isLight = True

itemData.Brightness = reader.ReadUInt16()

itemData.LightColor = reader.ReadUInt16()

Case Flag_DontHide

itemData.isDontHide = True

Case Flag_Translucent

itemData.isTranslucent = True

Case Flag_Shift

itemData.isDisplaced = True

itemData.DisplacementX = reader.ReadUInt16()

itemData.DisplacementY = reader.ReadUInt16()

Case Flag_Height

itemData.isHeight = True

itemData.Elevation = reader.ReadUInt16()

Case Flag_LyingObject

itemData.isLyingObject = True

Case Flag_AnimateAlways

itemData.isAnimateAlways = True

Case Flag_Automap

itemData.isAutomap = True

itemData.isAutomapColor = reader.ReadUInt16()

Case Flag_LensHelp

itemData.isLensHelp = True

itemData.LensHelp = reader.ReadUInt16()

Case Flag_FullBank

itemData.isFullBank = True

Case Flag_IgnoreLook

itemData.isIgnoreLook = True

Case Flag_Clothes

itemData.isCloth = True

itemData.ClothSlot = reader.ReadUInt16() 'head, torso, legs, feet, etc.

Case Flag_Market

itemData.isMarket = True

itemData.MarketCategory = reader.ReadUInt16() 'see the MarketCategory enum above

itemData.MarketTradeAs = reader.ReadUInt16()

itemData.MarketShowAs = reader.ReadUInt16()

 

'using the binary reader's ReadString() function returned the correctly lengthed string, but started a character early

'eg. "gold coin" would say " gold coi"

'to bypass this I just read the string length (first 2 bytes) then read that many bytes

'but the string is iso-8859-1 encoded, so you have to decode it to get the actual string

Dim MarketNameLength As Integer = reader.ReadUInt16()

itemData.MarketName = System.Text.Encoding.GetEncoding("iso-8859-1").GetString(reader.ReadBytes(MarketNameLength))

 

itemData.MarketRestrictProfession = reader.ReadUInt16()

itemData.MarketRestrictLevel = reader.ReadUInt16()

Case 255

Exit Do

Case Else

MessageBox.Show("Invalid flag!: " & optByte.ToString)

End Select

Loop

 

itemData.Width = reader.ReadByte()

itemData.Height = reader.ReadByte()

If itemData.Width > 1 Or itemData.Height > 1 Then

itemData.ExactSize = reader.ReadByte()

End If

 

itemData.Layers = reader.ReadByte()

itemData.PatternWidth = reader.ReadByte()

itemData.PatternHeight = reader.ReadByte()

itemData.PatternDepth = reader.ReadByte()

itemData.Phases = reader.ReadByte()

 

Dim numSpr As Integer = itemData.Width * itemData.Height

numSpr *= itemData.Layers * itemData.PatternWidth

numSpr *= itemData.PatternHeight * itemData.PatternDepth

numSpr *= itemData.Phases

 

itemData.NumberOfSprites = numSpr

 

itemData.Sprites = Array.CreateInstance(GetType(Integer), itemData.NumberOfSprites)

For i As Integer = 0 To itemData.NumberOfSprites - 1

itemData.Sprites(i) = reader.ReadUInt16()

Next

 

dataArray(ID - 100) = itemData

ID += 1

Loop

End Using

End Sub

End Class

All objects are stored in dataArray and you can access objects by ID. Here's an example:

 

Dim GoldCoin As ItemData = dataArray(3031 - 100) '3031 is the ID of gold coin; we have to subtract 100 because the array is 0-based

 

 

Alguém arruma ai que a porcaria tem limite de quotes eu acho icon2.gif

 

Estrutura Tibia.dat

Versão em potuguês:

 

 

Os primeiros 4 bytes contém informações para a versão dat, eu acho que isso é usado para ver qual a estrutura de usar (7,7 + ou-7,6). Os próximos dois bytes são contagem de itens, os próximos dois bytes são contagem de roupa, os próximos dois bytes são contagem efeito, e os próximos dois bytes são contagem de distância. O byte seguinte começa a informação bandeiras para o primeiro item (ID = 100), estas bandeiras são indicados por um valor entre & H0 e & H1F:

 

& H0 = telha chão

& H1 = em cima

& H2 = percorrer (portas, etc)

& H3 = percorrer (arcos etc)

& H4 = contentor

& H5 = empilhável

& H6 = escada?

& H7 = utilizável

& H8 = rune

& H9 = gravável

& HA = legível

& HB recipiente de fluido =

& HC splash =

& Hd = bloqueio

& HE = imóveis

& HF míssil = blocos

& H10 = movimento monstro blocos

& H11 = equipáveis

& H12 = hangable (item parede)

& H13 = horizontal (item parede)

& H14 = vertical (item parede)

& H15 = rotateable

& H16 Informações luz =

& H17 = desconhecido?

& H18 = mudança no andar de baixo?

& H19 = empate compensar

& H1A = altura

& H1B = desenhar com altura deslocamento para todas as peças (2x2) do sprite,

& H1C = offset vida-bar (para monstros maiores)

& H1D = minimap cor

& H1E mudança chão =?

& H1F = desconhecido?

 

 

Determinados sinalizadores são seguidas por um valor, como mostrado abaixo:

 

& H0 = azulejo chão é seguido por um valor de byte 2 indica a velocidade

& H9 = gravável é seguido por um valor de 2 bytes indicando o comprimento do texto max

& HA = legível é seguido por um valor de 2 bytes indicando o comprimento do texto max

& H16 = info luz é seguido por um valor de 2 bytes indicando o nível de luz, em seguida, um outro valor de byte 2 indicando a cor da luz

& H19 = empate deslocamento é seguido bye um valor de 2 bytes indicando o deslocamento x então um outro valor de 2 bytes indicando o deslocamento Y

& H1A = altura é seguido por um valor de byte 2 indica a altura draw (?)

& H1D = cor minimap é seguido por um valor de byte 2 indicando a cor minimap

& H1E mudança chão =? é seguido por um valor de 1 byte indicando um desses valores (86 - buracos que se abrem, de 77 - pode ser usado para ir para baixo, 76 - pode ser usado para ir para cima, 82 - escadas, 79 - switch), em seguida outro valor 1 byte que sempre retorna 4

 

 

O final dos valores de bandeira são indicados por um byte & HFF, em seguida, começa a informação objetos. O byte seguinte é a largura, o próximo é a altura, se a largura ou a altura é maior que 1, você tem que saltar o próximo byte a byte, então depois que ele é mistura quadros se não, então você não pule o próximo byte porque é mistura frames (eu espero que fez lol sentido), o próximo é divx, o próximo é divy, o próximo é divz, em seguida, o próximo é o comprimento de animação. O resto das informações objetos depende do número de sprites (largura * altura * mistura quadros * DivX * divy * divz * comprimento de animação). Você loop o número de sprites e em cada loop você ler 2 bytes para obter uma ID sprite para o objeto (o ID da imagem do objeto usa no arquivo spr.). Então você vai para o próximo objeto (101) e repita o processo.

 

Aqui está uma lista de bytes básica, incluindo as informações de cabeçalho e as informações para o primeiro objeto (100). [X] = contagem de bytes:

 

Código:

 

[4] - versão dat

[2] - item contagem

[2] - contagem de roupa

[2] - contagem efeito

[2] - contagem de distância

[1] - azulejo chão

[2] - velocidade = 0

[1] - bloqueando

[1] - imóveis

[1] - blocos mísseis

[1] - Informações luz

[2] - nível de luz = 3

[2] - cor da luz = 156

[1] - width = 1

[1] - height = 1

[1] = 1 - blendframes

[1] - = 4 divx

[1] - = 4 divy

[1] - = 1 divz

[1] - comprimento animação = 1

 

[2] - sprite ID = 136

[2] - sprite ID = 137

[2] - sprite ID = 138

[2] - sprite ID = 139

[2] - sprite ID = 140

[2] - sprite ID = 141

[2] - sprite ID = 142

[2] - sprite ID = 143

[2] - sprite ID = 144

[2] - sprite ID = 145

[2] - sprite ID = 146

[2] - sprite ID = 147

[2] - sprite ID = 148

[2] - sprite ID = 149

[2] - sprite ID = 150

[2] - sprite ID = 1512)

 

.dat Reader

 

Depois de estudar a. Estrutura dat eu era capaz de fazer um pequeno programa, mas o trabalho de ler o arquivo Tibia.dat e permitir que você obtenha informações de cada objeto. O programa é escrito em VB.Net e as fontes estão incluídos.

Quando você iniciar o programa, ele irá pedir para localizar e abrir o arquivo Tibia.dat. Assim que terminar o programa irá carregar e os itens, roupas, efeitos e campos de distância será preenchido. Na imagem acima eu carregado o 8,40. Dat. A atual estrutura vai trabalhar de volta para 7.7x versão que eu acredito. Se você quiser verificar a informação de um objeto, que é colocar ID (ID de ouro ou seja, é 3031) no campo ID do Cliente e clique em 'Ok'. O IDs comece em 100, há 9.104 itens para a identificação do item Max é 9204, roupas são 9.205-9.530, os efeitos são 9531-9597, e as distâncias são 9599-9640. Se você colocar um valor inferior a 100 ou superior a 9640 o programa irá falhar porque eu não adicionar qualquer tipo de tratamento de erro. Tudo deve ser auto-explicativo, equipáveis ​​também é pickupable, a caixa suspensa de sprites contém IDs dos sprites que o objeto usa a partir do arquivo spr..

 

Se você tiver alguma dúvida não hesite em perguntar.

 

 

 

 

Tibia.dat Structure

 

Versão original em inglês:

 

 

The first 4 bytes contains information for the dat version, I think this is used to see which structure to use (7.7+ or 7.6-). The next 2 bytes are item count, the next 2 bytes are outfit count, the next 2 bytes are effect count, and the next 2 bytes are distance count. The next byte starts the flags information for the first item (ID = 100), these flags are indicated by a value between &H0 and &H1F:

  • &H0 = ground tile
  • &H1 = on top
  • &H2 = walk through (doors etc.)
  • &H3 = walk through (arches etc.)
  • &H4 = container
  • &H5 = stackable
  • &H6 = ladder?
  • &H7 = usable
  • &H8 = rune
  • &H9 = writeable
  • &HA = readable
  • &HB = fluid container
  • &HC = splash
  • &HD = blocking
  • &HE = immoveable
  • &HF = blocks missile
  • &H10 = blocks monster movement
  • &H11 = equipable
  • &H12 = hangable (wall item)
  • &H13 = horizontal (wall item)
  • &H14 = vertical (wall item)
  • &H15 = rotateable
  • &H16 = light info
  • &H17 = unknown?
  • &H18 = floor change down?
  • &H19 = draw offset
  • &H1A = height
  • &H1B = draw with height offset for all parts (2x2) of the sprite,
  • &H1C = offset life-bar (for larger monsters)
  • &H1D = minimap color
  • &H1E = floor change?
  • &H1F = unknown?

Certain flags are followed by a value, as shown below:

  • &H0 = ground tile is followed by a 2 byte value indicating the speed
  • &H9 = writeable is followed by a 2 byte value indicating the max text length
  • &HA = readable is followed by a 2 byte value indicating the max text length
  • &H16 = light info is followed by a 2 byte value indicating the light level then another 2 byte value indicating the light color
  • &H19 = draw offset is followed bye a 2 byte value indicating the x offset then another 2 byte value indicating the y offset
  • &H1A = height is followed by a 2 byte value indicating the draw height(?)
  • &H1D = minimap color is followed by a 2 byte value indicating the minimap color
  • &H1E = floor change? is followed by a 1 byte value indicating one of these values (86 - openable holes, 77 - can be used to go down, 76 - can be used to go up, 82 - stairs up, 79 - switch) then another 1 byte value that always returns 4

The end of the flag values are indicated by a &HFF byte, then starts the objects information. The next byte is width, the next is height, if the width or height is greater than 1 you have to skip the next byte then the byte after it is blend frames if not then you don't skip the next byte because it is blend frames (i hope that made sense lol), the next is divx, the next is divy, the next is divz, then the next is animation length. The rest of the objects information depends on the number of sprites (width * height * blend frames * divx * divy * divz * animation length). You loop the number of sprites and in each loop you read 2 bytes to get a sprite ID for that object (the ID of the image the object uses in the .spr file). Then you go to the next object (101) and repeat the process.

 

Here's a basic byte list including the header information and the information for the first object (100). [x] = byte count:

Code:

 

[4] - dat version

[2] - item count

[2] - outfit count

[2] - effect count

[2] - distance count

[1] - ground tile

[2] - speed = 0

[1] - blocking

[1] - immoveable

[1] - blocks missiles

[1] - light info

[2] - light level = 3

[2] - light color = 156

[1] - width = 1

[1] - height = 1

[1] - blendframes = 1

[1] - divx = 4

[1] - divy = 4

[1] - divz = 1

[1] - animation length = 1

[2] - sprite ID = 136

[2] - sprite ID = 137

[2] - sprite ID = 138

[2] - sprite ID = 139

[2] - sprite ID = 140

[2] - sprite ID = 141

[2] - sprite ID = 142

[2] - sprite ID = 143

[2] - sprite ID = 144

[2] - sprite ID = 145

[2] - sprite ID = 146

[2] - sprite ID = 147

[2] - sprite ID = 148

[2] - sprite ID = 149

[2] - sprite ID = 150

[2] - sprite ID = 1512) .dat Reader

 

After studying the .dat structure I was able to make a small, but working program to read the Tibia.dat file and allow you to get information for each object. The program is written in VB.Net and the sources are included.

When you first start the program it will ask you to locate and open your Tibia.dat file. Once this is finished the program will load and the items, outfits, effects, and distance fields will be filled. In the above screenshot I've loaded the 8.40 .dat file. The current structure will work back to version 7.7x I believe. If you want to check the information of an object, place it's ID (ie. gold's ID is 3031) in the Client ID field and click 'Go'. The IDs start at 100, there are 9104 items so the max item ID is 9204, outfits are from 9205-9530, effects are from 9531-9597, and distances are from 9599-9640. If you put a value lower than 100 or higher than 9640 the program will crash because I didn't add any type of error handling. Everything should be self explanatory, equipable is also pickupable, the sprites dropdown box contains IDs of the sprites that the object uses from the .spr file.

 

If you have any questions please feel free to ask.

 

 

 

------------------------------------------------------------------------------------------------------------------------------------------------------

 

Tibia: estrutura do Arquivo Sprite

 

Versão em português:

 

Nota: Um grande obrigado a Sketchy pela ajuda com aumentando muito a velocidade de leitura do sprite, especificamente a criação de um bitmap do sprite, substituindo Bitmap.SetPixel () com Bitmap.LockBits () / Bitmap.UnlockBits ().

 

- Como a estrutura do arquivo Dat, o arquivo de sprite começa com 4 bytes, o que eu chamo de SpriteVersion, e é exclusivo para cada versão do cliente de modo que o cliente sabe que o arquivo correto sprite está sendo usado.

- Isto é seguido por dois bytes, que contém o número de sprites no arquivo de sprite.

 

- Imediatamente após isso temos um valor de 4 bytes para cada sprite contendo sua deslocamento de byte no arquivo de sprite.

 

[x] = Número de bytes.

código:

[4] Versão Sprite

[2] Número de sprites

[4] Deslocamento do sprite primeira

[4] Deslocamento do sprite segunda

[4] de Offset o sprite terceiro

---- Continuar isso para cada sprite.

 

- Agora vamos começar a ficar para os dados reais do sprite. Cada sprite começa com a cor dos pixels transparente '. Neste caso, o cliente usa Tibia magenta para os três bytes retornados são 255, 0, 255. Você não precisa deste pixel ao criar o bitmap.

- Após este é 2 bytes indicando o tamanho do sprite. (Todos os sprites são 32x32 pixels, 1024 pixels, então isso nunca deve mudar.)

- Em seguida, começar a ler os dados de pixel reais do sprite. Isso começa com dois bytes segurando o número de pixels transparentes antes de pixel colorido.

 

- Em seguida, dois bytes segurando o número de pixels coloridos antes de um pixel transparente. Imediatamente após este é um três-byte valores que prendem o valor RGB do pixel. Por exemplo, se o número de pixels coloridos retornados é 3, então você leria os próximos 9 bytes (3 bytes para cada pixel) para obter as informações de pixel de cada um.

 

[x] = Número de bytes.

código:

[1] - vermelho valor de pixels transparentes

[1] - valor verde de pixels transparentes

[1] - valor azul de pixels transparentes

[2] - número de pixels transparentes

[2] - número de pixels coloridos (para este exemplo vamos dizer que é 3)

[1] - vermelho valor do primeiro pixel colorido

[1] - valor verde do primeiro pixel colorido

[1] - valor azul do primeiro pixel colorido

[1] - valor de vermelho do segundo pixel colorido

[1] - valor verde do segundo pixel colorido

[1] - valor azul do segundo pixel colorido

[1] - vermelho valor do pixel colorido terceiro

[1] - o valor do pixel verde terceira cor

[1] - valor azul do pixel colorido terceiro

[2] - número de pixels transparentes

[2] - número de pixels coloridos

---- Este irá repetir para todos os pixels da sprite. ----

 

- Na forma que usamos para fazer bitmap a partir dos dados do sprite em TibiaAPI (que você pode ver aqui: http://code.google.c...ce...eReader.cs) usamos Bitmap.SetPixel () para definir a cor do pixel no bitmap. Enquanto esta é uma maneira fácil de conseguir o que queremos, que é também um pouco lento. Mas, graças a esboçado, você pode conseguir um aumento de velocidade de 10x usando Bitmap.LockBits () e Bitmap.UnlockBits (). (Em meus testes, eu poderia carregar o arquivo inteiro 9,44 Sprite em 35 segundos usando Bitmap.SetPixels (), mas eu podia carregá-lo em apenas 3,5 segundos! Usando Bitmap.LockBits () / Bitmap.UnlockBits ().)

 

Agora, aqui está o código usado para ler o arquivo de sprite que você pode jogar para VB.Net e correr. Este usa as LockBits / método UnlockBits, e eu comentei o código para ajudar você a entender o que está acontecendo. A estrutura Sprite tem sido a mesma desde que me lembro, então você não deve ter um problema usando este código para qualquer versão do cliente. Além disso, este código lê e armazena cada sprite em uma matriz, mas você pode modificá-lo como o código TibiaAPI para recuperar somente um sprite específico. Se você tiver alguma dúvida não hesite em perguntar:

 

Public Class Form1

Dim SpriteArray As Image()

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim FileName As String = vbNullString

MessageBox.Show("Please locate and open your Tibia.spr file", ".spr Reader")

With OpenFileDialog1

.Filter = "Spr file (*.spr)|*.spr|" & "All files|*.*"

If .ShowDialog = Windows.Forms.DialogResult.OK Then

FileName = .FileName

Else

Application.Exit()

End If

End With

 

Using reader As New IO.BinaryReader(IO.File.OpenRead(FileName))

Dim SpriteVersion As Integer = reader.ReadUInt32()

Dim NumberOfSprites As Integer = reader.ReadUInt16()

SpriteArray = Array.CreateInstance(GetType(Image), NumberOfSprites)

 

For i As Integer = 0 To NumberOfSprites - 1 'even though sprite IDs start at 2, I started the loop at 0 for the array

Dim Sprite As Bitmap = New Bitmap(32, 32) 'this is the bitmap we'll be storing the sprite in, notice it's 32x32 pixels

Dim SpriteData As Drawing.Imaging.BitmapData = Sprite.LockBits(New Rectangle(0, 0, 32, 32), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb) 'here is where we lock the bits of the bitmap, since sprites are ARGB-based we have to make sure the format is the same

Dim ByteArray As Byte() = New Byte(4096) {} 'this is the array we'll store the pixel data in, even though a 32x32 pixel sprite has 1024 pixels we have to store 4 bits for each pixel (alpha, red, green blue)

Dim currentPixel As UShort = 0

Dim targetOffset As Long

 

'to begin, we have to seek to the sprite to get it's offset

'since I started the loop at 0 I have to add 1 because the sprites aren't 0-based (however, keep in mind sprite IDs begin at 2, not 1)

'each sprite is offset by 4 because the offset is stored as an integer (4 bytes)

'and the +6 is to skip past the SpriteVersion and NumberOfSprites

reader.BaseStream.Seek(6 + (i + 1) * 4, IO.SeekOrigin.Begin)

 

'now that we're at our desired sprite we have to read it's offset address (reader.ReadUInt32()), then we seek the returned value +3

'the +3 is to skip the transparent pixels' color, since we don't need it

reader.BaseStream.Seek(reader.ReadUInt32() + 3, IO.SeekOrigin.Begin)

 

'it seems as though sprite file for clients 7.40 and lower return a out-of-bounds position on the last sprite

'I didn't take the time to figure out why, but you can easily counter this problem with this line of code making sure the position

'of the stream is not beyond the file's size

If reader.BaseStream.Position >= reader.BaseStream.Length Then Continue For

 

targetOffset = reader.BaseStream.Position + reader.ReadUInt16() 'the ReadUInt16() returns the size of the sprite

If reader.BaseStream.Position < 9 Then Continue For 'if we encounter a blank sprite it actually sets the position of the stream at byte-5 and that's actually the beginning of the NumberOfSprites value, so we use Continue For to skip this sprite

 

While reader.BaseStream.Position < targetOffset

Dim transparentPixels As UShort = reader.ReadUInt16()

Dim coloredPixels As UShort = reader.ReadUInt16()

If (transparentPixels > 1024) OrElse (coloredPixels > 1024) Then Exit While 'as an extra padding of protection, I make sure the number of transparent and/or colored pixels doesn't exceed the size of a sprite

currentPixel += transparentPixels

For x As Integer = 0 To coloredPixels - 1

'here's where we get different from TibiaAPI's SetPixel()

'remember what I said about us storing all four pixel colors? here's where we use it

Dim CurrentOffset As Integer = (currentPixel * 4) 'this goes to the offset in ByteArray where the current pixel we're reading is going to be located

'pixel data is actually stored in reverse in bitmaps, so we write the Alpha value first (255) at the end of the pixel data, followed by Red before it, then Green before Red, and finally Blue at the beginning of the pixel data.

ByteArray(CurrentOffset + 3) = 255

ByteArray(CurrentOffset + 2) = reader.ReadByte()

ByteArray(CurrentOffset + 1) = reader.ReadByte()

ByteArray(CurrentOffset) = reader.ReadByte()

currentPixel += 1

Next

End While

 

Runtime.InteropServices.Marshal.Copy(ByteArray, 0, SpriteData.Scan0, 4096) 'here is where we copy the data in the byte array (where we stored the pixel data for the sprite) into our BitmapData

Sprite.UnlockBits(SpriteData) 'then we unlock the sprite so that we can use it

SpriteArray(i) = Sprite 'here I store the sprite in an Image array

Next

End Using

End Sub

End Class

 

Você pode facilmente verificar cada imagem, adicionando uma caixa de imagem, TextBox e Button a sua forma e usando este código:

 

'put this code in the button's click event

If IsNumeric(TextBox1.Text) AndAlso Int(TextBox1.Text) >= 2 Then 'this makes sure the text in the text box is a number and that's not lower than 2 because sprite IDs start at 2 and our array is 0-based

PictureBox1.Image = SpriteArray((Int(TextBox1.Text)) - 2) 'we use -2 here because of our array being 0-based and sprite IDs starting at 2

End If

 

Tibia: Sprite File Structure

 

Versão original em inglês:

 

Note: A big thanks to Sketchy for the help with greatly increasing the speed of reading the sprite, specifically creating a bitmap of the sprite, by replacing Bitmap.SetPixel() with BitMap.LockBits()/Bitmap.UnlockBits().

 

- Like the Dat file structure, the sprite file begins with 4 bytes, which I call the SpriteVersion, and is unique for each client version so that the client knows that the correct sprite file is being used.

- This is followed by 2 bytes that contains the number of sprites in the sprite file.

 

- Immediately following this we have a 4-byte value for each sprite containing it's byte offset in the sprite file.

 

[x] = Number of bytes.

Code:

[4] Sprite Version

[2] Number of sprites

[4] Offset of the first sprite

[4] Offset of the second sprite

[4] Offset of the third sprite

----Continue this for each sprite.

 

- Now we start getting in to the actual sprite data. Each sprite begins with the transparent-pixels' color. In this case, the Tibia client uses magenta so the three bytes returned are 255, 0, 255. You don't need this pixel when creating the bitmap.

- Following this is 2 bytes indicating the size of the sprite. (All sprites are 32x32 pixels, 1024 pixels, so this should never change.)

- Next we start reading the actual pixel data of the sprite. This begins with 2 bytes holding the number of transparent pixels before colored pixel.

 

- Then 2 bytes holding the number of colored pixels before a transparent pixel. Immediately following this is three 1-byte values holding the RGB value of the pixel. For example, if the number of colored pixels returned is 3 then you would read the next 9 bytes (3 bytes for each pixel) to get the pixel information of each.

 

[x] = Number of bytes.

Code:

[1] - red value of transparent pixels

[1] - green value of transparent pixels

[1] - blue value of transparent pixels

[2] - number of transparent pixels

[2] - number of colored pixels (for this example we'll say it's 3)

[1] - red value of the first colored pixel

[1] - green value of the first colored pixel

[1] - blue value of the first colored pixel

[1] - red value of the second colored pixel

[1] - green value of the second colored pixel

[1] - blue value of the second colored pixel

[1] - red value of the third colored pixel

[1] - green value of the third colored pixel

[1] - blue value of the third colored pixel

[2] - number of transparent pixels

[2] - number of colored pixels

----This will repeat for all pixels in the sprite.----

 

- In the way we used to make bitmap's from the sprite data in TibiaAPI (which you can view here: http://code.google.c...ce...eReader.cs ) we used Bitmap.SetPixel() to set the pixel color in the bitmap. While this is an easy way to achieve what we want, it's also a bit slow. But, thanks to Sketchy, you can achieve a 10x speed increase by using Bitmap.LockBits() and Bitmap.UnlockBits(). (In my tests, I could load the whole 9.44 sprite file in 35 seconds using Bitmap.SetPixels(), but I could load it in just 3.5 seconds! using Bitmap.LockBits()/Bitmap.UnlockBits().)

 

Now, here's code used to read the sprite file that you can throw in to VB.Net and run. This uses the LockBits/UnlockBits method, and I have commented the code to help you understand what's going on. The sprite structure has been the same as far back as I can remember, so you shouldn't have a problem using this code for any client version. Also, this code reads and stores each sprite in an array, but you can modify it like the TibiaAPI code to only retrieve a specific sprite. If you have any questions feel free to ask:

 

Public Class Form1

Dim SpriteArray As Image()

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim FileName As String = vbNullString

MessageBox.Show("Please locate and open your Tibia.spr file", ".spr Reader")

With OpenFileDialog1

.Filter = "Spr file (*.spr)|*.spr|" & "All files|*.*"

If .ShowDialog = Windows.Forms.DialogResult.OK Then

FileName = .FileName

Else

Application.Exit()

End If

End With

 

Using reader As New IO.BinaryReader(IO.File.OpenRead(FileName))

Dim SpriteVersion As Integer = reader.ReadUInt32()

Dim NumberOfSprites As Integer = reader.ReadUInt16()

SpriteArray = Array.CreateInstance(GetType(Image), NumberOfSprites)

 

For i As Integer = 0 To NumberOfSprites - 1 'even though sprite IDs start at 2, I started the loop at 0 for the array

Dim Sprite As Bitmap = New Bitmap(32, 32) 'this is the bitmap we'll be storing the sprite in, notice it's 32x32 pixels

Dim SpriteData As Drawing.Imaging.BitmapData = Sprite.LockBits(New Rectangle(0, 0, 32, 32), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb) 'here is where we lock the bits of the bitmap, since sprites are ARGB-based we have to make sure the format is the same

Dim ByteArray As Byte() = New Byte(4096) {} 'this is the array we'll store the pixel data in, even though a 32x32 pixel sprite has 1024 pixels we have to store 4 bits for each pixel (alpha, red, green blue)

Dim currentPixel As UShort = 0

Dim targetOffset As Long

 

'to begin, we have to seek to the sprite to get it's offset

'since I started the loop at 0 I have to add 1 because the sprites aren't 0-based (however, keep in mind sprite IDs begin at 2, not 1)

'each sprite is offset by 4 because the offset is stored as an integer (4 bytes)

'and the +6 is to skip past the SpriteVersion and NumberOfSprites

reader.BaseStream.Seek(6 + (i + 1) * 4, IO.SeekOrigin.Begin)

 

'now that we're at our desired sprite we have to read it's offset address (reader.ReadUInt32()), then we seek the returned value +3

'the +3 is to skip the transparent pixels' color, since we don't need it

reader.BaseStream.Seek(reader.ReadUInt32() + 3, IO.SeekOrigin.Begin)

 

'it seems as though sprite file for clients 7.40 and lower return a out-of-bounds position on the last sprite

'I didn't take the time to figure out why, but you can easily counter this problem with this line of code making sure the position

'of the stream is not beyond the file's size

If reader.BaseStream.Position >= reader.BaseStream.Length Then Continue For

 

targetOffset = reader.BaseStream.Position + reader.ReadUInt16() 'the ReadUInt16() returns the size of the sprite

If reader.BaseStream.Position < 9 Then Continue For 'if we encounter a blank sprite it actually sets the position of the stream at byte-5 and that's actually the beginning of the NumberOfSprites value, so we use Continue For to skip this sprite

 

While reader.BaseStream.Position < targetOffset

Dim transparentPixels As UShort = reader.ReadUInt16()

Dim coloredPixels As UShort = reader.ReadUInt16()

If (transparentPixels > 1024) OrElse (coloredPixels > 1024) Then Exit While 'as an extra padding of protection, I make sure the number of transparent and/or colored pixels doesn't exceed the size of a sprite

currentPixel += transparentPixels

For x As Integer = 0 To coloredPixels - 1

'here's where we get different from TibiaAPI's SetPixel()

'remember what I said about us storing all four pixel colors? here's where we use it

Dim CurrentOffset As Integer = (currentPixel * 4) 'this goes to the offset in ByteArray where the current pixel we're reading is going to be located

'pixel data is actually stored in reverse in bitmaps, so we write the Alpha value first (255) at the end of the pixel data, followed by Red before it, then Green before Red, and finally Blue at the beginning of the pixel data.

ByteArray(CurrentOffset + 3) = 255

ByteArray(CurrentOffset + 2) = reader.ReadByte()

ByteArray(CurrentOffset + 1) = reader.ReadByte()

ByteArray(CurrentOffset) = reader.ReadByte()

currentPixel += 1

Next

End While

 

Runtime.InteropServices.Marshal.Copy(ByteArray, 0, SpriteData.Scan0, 4096) 'here is where we copy the data in the byte array (where we stored the pixel data for the sprite) into our BitmapData

Sprite.UnlockBits(SpriteData) 'then we unlock the sprite so that we can use it

SpriteArray(i) = Sprite 'here I store the sprite in an Image array

Next

End Using

End Sub

End Class

 

You can easily check each image by adding a PictureBox, TextBox, and Button to your form and using this code:

 

'put this code in the button's click event

If IsNumeric(TextBox1.Text) AndAlso Int(TextBox1.Text) >= 2 Then 'this makes sure the text in the text box is a number and that's not lower than 2 because sprite IDs start at 2 and our array is 0-based

PictureBox1.Image = SpriteArray((Int(TextBox1.Text)) - 2) 'we use -2 here because of our array being 0-based and sprite IDs starting at 2

End If

 

 

 

 

 

Alguém ai arruma que ta dando erro que quotes abertos não corespondem com quotes fechados!

!!!Mais TODOS estão corretos!!!



 

Crédito: Jo3Bingham

Editado por DanielBadhu
Link para o comentário
https://xtibia.com/forum/topic/205781-datasprite-file-structure/
Compartilhar em outros sites

×
×
  • Criar Novo...