Ir para conteúdo
Entre para seguir isso  
dalvorsn

Sprite Extractor

Recommended Posts

dalvorsn    46
dalvorsn

  • Autor: Dalvo

  • Nome: Sprite Extractor

  • Descrição: É um extrator de sprites dos arquivos spr padrões do tibia.

  • Como funciona: Primeiramente lê-se o arquivo em modo binário, pegam-se os dados de signatura e numero de sprites, apos isso é feita uma varredura nos bytes que os offsets dos ids apontam, iterando sobre eles e gravando-os em seus respectivos pixels, e salvando como bmp. O sistema foi feito completamente em lua, não é muito vantajoso se comparado com extratores feitas em outras linguagens, mas como o objetivo era ser objeto de estudo e não uma ferramente de utilização não vejo problema nisso e estou compartilhando com a comunidade, para os que estão a aprender lua possam analisar.

 

 

 

Sprite Extractor

divisor.png

O sistema é composto de dois arquivos:

# readBytes.lua

require "SpriteReader"

function convert(num, count)
   local array = {}
   local aux = 0
   for i = count, 2, -1 do
       local val = math.floor(num/(256^(i-1)))
       array[i] = val
       num = num - (val*(256^(i-1)))
   end
   array[1] = num
   return unpack(array)
end




function saveBMP(filename, width, height, pixels)

   sizeArrayColors = 4 * width * height
   size_1, size_2, size_3, size_4 = convert(sizeArrayColors+54, 4)
   width_1, width_2, width_3, width_4 = convert(width, 4)
   height_1, height_2, height_3, height_4 = convert(height, 4)

   size_array_1, size_array_2, size_array_3, size_array_4 = convert(sizeArrayColors, 4)
   local byteArray =
   {
   --bmp header
   0x42, 0x4D, -- magic numbers
   size_1, size_2, size_3, size_4, --0x00, 0x12, 0x00, 0x00, -- tamanho em bytes da imagem (3072)
   0x00, 0x00, 0x00, 0x00, -- sem uso
   0x36, 0x00, 0x00, 0x00, -- endereço de onde começam as cores
   --dib header
   0x28, 0x00, 0x00, 0x00, -- tamanho do dib header em bytes - 40
   width_1, width_2, width_3, width_4, -- largura
   height_1, height_2, height_3, height_4, -- altura
   0x01, 0x00,
   0x18, 0x00,    -- numero de bits por pixel (24bits/pixel)
   0x00, 0x00, 0x00, 0x00,
   size_array_1, size_array_2, size_array_3, size_array_4, -- numeros de bytes no array de cores
   0x13, 0x0B, 0x00, 0x00, -- resolução horizontal bit/meter
   0x13, 0x0B, 0x00, 0x00, -- resolução horizontal bit/meter
   0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00
   }

   local file = io.open(filename..".bmp", "w+b")
   for _, byte in pairs(byteArray) do
       file:write(type(byte) == "number" and string.char(byte) or byte)
   end

   for y = height , 1, -1 do
       for x = 1, width do
           for _, byte in pairs(pixels[x][y]) do 
               file:write(string.char(byte))
           end
       end
   end
   file:close()
end

function main()
   local file = io.open("./Tibia.spr", "rb")
   if(file)then
       reader = SpriteReader:load(file)
       reader.version = reader:getUint32()
       reader.numberOfSprites = reader:getUint16()
       io.write("Version: ",reader.version,"\nNumber Of Sprites: ", reader.numberOfSprites, "\n")

       if not(type(io.open("./Sprites")) == "userdata")then
           os.execute("mkdir Sprites")
       end

       for id = 1, reader.numberOfSprites do 
           print("Extraindo: "..id.."/"..reader.numberOfSprites)
           saveBMP("./Sprites/"..tostring(id), 32, 32, reader:getPixelsData(id))
       end
       print("Tempos gasto na extração: "..os.clock())
       reader:closeData()
   else
       print("Arquivo .spr não encontrado")
   end
end

main()


 

# SpriteReader.lua

SpriteReader = {}

--[[
   * Inicia classe com atributo do tipo userdata 'data'
   * Seta atributos default e le data no modo "*a"
--]]
function SpriteReader:load(data)
   attr = {version = 0, numberOfSprites = 0, posByte = 1,file = data, data = data:read("*a"), id = 1}
   return setmetatable(attr, {__index = self})
end

--[[
   * Pega os valores minimo e maximos para numero de bytes fornecidos
   * signed é uma variavel boolean, quando true rearranja os limites para tipo signed
--]]
function SpriteReader:getRanges(byte, signed)
   local min, max = 0, ((256^byte) -1)
   if(signed)then
       min = -max/2
       max = max/2
   end
   return min, max
end


--[[
   * le byte a byte somando seus valores 'byte' numero de vezes
   * se signed é true, reajusta o valor para signed
--]]
function SpriteReader:readBytes(byte, signed)
   local min, _ = self:getRanges(byte, signed)
   local value = 0
   for var = 1, byte do
       value = value +  ( self:nextByte() * (256^(var-1)) )
   end
   return value + min
end

--[[
   * le 'posByte', que é um atributo de controle, serve apaenas para armazenar o proximo byte
   * reajusta 'posByte' para posição seguinte
   * retorna 'byte'
--]]
function SpriteReader:nextByte()
   local byte = self.data:byte(self.posByte)
   self.posByte = self.posByte + 1
   return tonumber(byte)
end


function SpriteReader:seek(offset)
   self.posByte = offset + 1
end
--[[
   * faz a leitura byte a byte 8 vezes somando seus valores pela progressão:
   * (byte) ^ 1 + (byte) ^ 2 + ... + (byte) ^ n
   * valido para todos unsigneds abaixo
--]]
function SpriteReader:getUint64()
   return self:readBytes(8, false)
end

function SpriteReader:getUint32()
   return self:readBytes(4, false)
end

function SpriteReader:getUint16()
   return self:readBytes(2, false)
end

function SpriteReader:getUint8()
   return self:readBytes(1, false)
end

--[[
   * segue a mesma lógica anterior, com uma unica diferença
   * o valor final é reajustado para signed
--]]
function SpriteReader:getInt64()
   return self:readBytes(8, true)
end

function SpriteReader:getInt32()
   return self:readBytes(4, true)
end

function SpriteReader:getInt16()
   return self:readBytes(2, true)
end

function SpriteReader:getInt8()
   return self:readBytes(1, true)
end

--[[
   * fecha o atributo file
--]]
function SpriteReader:closeData()
   return self.file:close()
end

--[[
   * retorna os uma tabela onde table[x][y] representam os respectivos pixels (x, y)
--]]
function SpriteReader:getPixelsData(id)
   self:seek(6 + id * 4)
   self:seek(self:getUint32() + 3)

   local pixel, pixels = 0, {}

   local offset = self.posByte + self:getUint16()
   for x = 1, 32 do
       pixels[x] = {}
       for y = 32 , 1, -1 do
           pixels[x][y] = {255, 0, 255}
       end
   end

   while self.posByte < offset do
       local tp = self:getUint16()
       local colored = self:getUint16()
       pixel = pixel + tp
       for x = 1, colored do
           local r,g,b = self:getUint8(), self:getUint8(), self:getUint8()
           pixels[(pixel % 32)+1][math.floor(pixel/32+1)] = {b, g, r}
           pixel = pixel + 1
       end
   end
   --]]
   return pixels
end


Os arquivos devem ser colocados juntos em uma pasta, e a pasta deve contem o arquivo Tibia.spr, pode ser outros nomes ou diretorios, porem precisará modificar no script (qualquer noob faz).

 

Me sinto na obrigação de atribuir crédito a 3 pessoas:Jo3Bingham (pelo tutorial sobre estrutura do spr), Colex (atravès de um script dele pude intender como são organizados os pixels no spr), baxnie (por me ajudar a entender a estrutura do spr, que não obtive total exito atraves do tutorial de Jo3Bingham).

 

Para usários de Windows aconselho Scite, e para linux gosto de usar o Geany.

Editado por dalvorsn

Compartilhar este post


Link para o post
vHp    6
vHp

Excelente script, obrigado pela contribuição!

Compartilhar este post


Link para o post
Open Sourcer    0
Open Sourcer

aimagem nao esta aparecendo da pra vc arruma a imagem png eu quero ibagens

 

#edit

 

pode usa tbm SciTE para exuta

Editado por Open Sourcer

Compartilhar este post


Link para o post
dalvorsn    46
dalvorsn
aimagem nao esta aparecendo da pra vc arruma a imagem png eu quero ibagens

 

lógico que ta aparecendo, a imagem é só um divisor não é referente ao sistema

é isso aqui:

 

divisor.png
Editado por dalvorsn

Compartilhar este post


Link para o post
Open Sourcer    0
Open Sourcer

qual programa se usa pra compila

Editado por Open Sourcer

Compartilhar este post


Link para o post
dalvorsn    46
dalvorsn
ve direito esse script ae que aq ta dando erro na hora de compila e olha q usei 2 programa diferente da erro nos simbolos

aqui funciona normalmente, esboçe o erro para que eu possa lhe ajudar.

 

#edit

Sou usuário linux, pode ser que o problema seja na função vinculada ao sistema operacional, no caso:

os.execute("mkdir Sprites")

Ela basicamente cria uma pasta com nome 'Sprites' na pasta onde o script está sendo executado, caso seja isso, remova a linha e crie a pasta manualmente, não sei o comando em windows para criar pasta, e nem sei identificar a plataforma em lua.

 

qual programa se usa pra compila

Não precisa compilar, só precisa de um debugger.

 

 

#edit

Verifiquei aqui, o comando mkdir vale pras duas plataformas, porem reparei que quando a pasta já existe, dá erro, então adaptei o codigo de tal maneira que não dê erros nesse ponto, peço que copie ou baixe novamente e teste para ver se o problema foi solucionado.

Editado por dalvorsn

Compartilhar este post


Link para o post
Lwkass    1
Lwkass

Excelente trabalho dalvo =D

Sempre tive curiosidade de mexer a fundo com binario (sabia algumas coisinhas só), mas nunca tive a disposição necessária para me dedicar a isso (já que é bem complexo e tals), e já agradeço, aproveitei que você postou e dei uma profunda estudada no código pra entender e comecei a projetar um sprite extractor próprio baseado no estudo que eu fiz do seu, deu ótimos resultados, só preciso terminar ahuahuhuahuahua

 

Só pra avisar, quando eu rodei aqui no linux pra extrair as sprites do 8.6, deu o seguinte erro (cópia do terminal):

[b]$[/b] lua readBytes.lua
Version: 1277298068
Number Of Sprites: 36386
Extraindo: 1/36386
lua: ./SpriteReader.lua:125: attempt to index field '?' (a nil value)
stack traceback:
   ./SpriteReader.lua:125: in function 'getPixelsData'
   readBytes.lua:76: in function 'main'
   readBytes.lua:85: in main chunk
   [C]: ?

 

Mas parabéns ae :D

Compartilhar este post


Link para o post
dalvorsn    46
dalvorsn
Excelente trabalho dalvo =D

Sempre tive curiosidade de mexer a fundo com binario (sabia algumas coisinhas só), mas nunca tive a disposição necessária para me dedicar a isso (já que é bem complexo e tals), e já agradeço, aproveitei que você postou e dei uma profunda estudada no código pra entender e comecei a projetar um sprite extractor próprio baseado no estudo que eu fiz do seu, deu ótimos resultados, só preciso terminar ahuahuhuahuahua

 

Só pra avisar, quando eu rodei aqui no linux pra extrair as sprites do 8.6, deu o seguinte erro (cópia do terminal):

[b]$[/b] lua readBytes.lua
Version: 1277298068
Number Of Sprites: 36386
Extraindo: 1/36386
lua: ./SpriteReader.lua:125: attempt to index field '?' (a nil value)
stack traceback:
   ./SpriteReader.lua:125: in function 'getPixelsData'
   readBytes.lua:76: in function 'main'
   readBytes.lua:85: in main chunk
   [C]: ?

 

Mas parabéns ae :D

 

Postei errado e não notei

pixels[pixel+1][math.floor(pixel/32+1)] = {b, g, r}

Aqui o correto seria pegar no primeiro index o resto da divisão de 32, na copia pro forum provavelmente apaguei sem perceber, deixe assim:

pixels[(pixel % 32) +1][math.floor(pixel/32+1)] = {b, g, r}

 

#edit

intendi porque foi errado, quando postei dentro da tag php %3, ele sumiu, não sei porque motivos

Editado por dalvorsn

Compartilhar este post


Link para o post
luigilc    0
luigilc

não entendi como eu faço pra usar isso tem q usar um debugger? e como é isso, q q é debugger?

Compartilhar este post


Link para o post
Open Sourcer    0
Open Sourcer
luigilc isso dai é pra linux

Compartilhar este post


Link para o post
dalvorsn    46
dalvorsn
não entendi como eu faço pra usar isso tem q usar um debugger? e como é isso, q q é debugger?

 

Lua é uma linguagem interpretada, ela não comunica diretamente com o computador, precisa de um intermedio, ai que entra o debugger.

Vou deixar aqui um link para você baixar: http://code.google.com/p/luaforwindows/downloads/list

 

#Open Sourcer

Um amigo meu que usa Windows testou em casa, e disse que funcionou normal, tinha um erro no daqui por conta do forum, que modificou alguns caracteres.

Compartilhar este post


Link para o post
Conde2    0
Conde2

Eta porra parabéns dalvo, você ta fazendo coisas cada vez mais profissionais continue assim você já ta profissa só me fala ai onde tu acho as informações dos bytes da spr?

Compartilhar este post


Link para o post
dalvorsn    46
dalvorsn
Eta porra parabéns dalvo, você ta fazendo coisas cada vez mais profissionais continue assim você já ta profissa só me fala ai onde tu acho as informações dos bytes da spr?

 

no tpforums

http://tpforums.org/forum/thread-9309.html?highlight=spr

eu me guiei por esse ae, mas é provavel que haja outros

Compartilhar este post


Link para o post
rui_miguel    0
rui_miguel

Cara, aqui deu esse erro. Tenho um interpretador de lua instalado (Com o SciTe e tals...) e executei pelo cmd... (lua readBytes.lua) e ai deu isso:

 

2vkx3sj.png

Compartilhar este post


Link para o post
dalvorsn    46
dalvorsn
Cara, aqui deu esse erro. Tenho um interpretador de lua instalado (Com o SciTe e tals...) e executei pelo cmd... (lua readBytes.lua) e ai deu isso:

 

2vkx3sj.png

esse spr parece estar fora do padrão dos que eu testei, tanto porque é um spr de 63mb, como pode estar marcando apenas 1024 sprites, tente testar com outros sprs e veja se o problema persiste

Compartilhar este post


Link para o post
Kydrai    0
Kydrai

É porque nas novas versões do Tibia a estrutura mudou. Pelo que sei o tamanho do "numberOfSprites" mudou.

Testa assim:

 

readBytes.lua

Troca:

reader.numberOfSprites = reader:getUint16()

Por:

reader.numberOfSprites = reader:getUint32()

 

SpriteReader.lua:

Troca:

self:seek(6 + id * 4)

Por:

self:seek(8 + id * 4)

Compartilhar este post


Link para o post
Visitante
Este tópico está impedido de receber novos posts.
Entre para seguir isso  
  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.

×