CO

Xspriter

Por colex, 25 de nov. de 2009 em Outras Linguagens

tibia
script
otserv
3
3.3k
colexC
25 de novembro de 2009 às 00:28
XSpriterv0.1
Extractor de Sprites em Lua



O que é o XSpriter?
O XSpriter foi desenvolvido com um intuito de aprendizagem. Este script mostra como ler ficheiros binários e, no caso de conter imagens, como extrair-las. Através deste script você poderá também adiquirir mais conhecimentos sobre a estrutura do Tibia.spr.

Este script só foi testado na versão 8.50 e 8.53, porém deverá funcionar em outras versões.

O projeto XSpriter é constituído por dois scripts (de minha autoria):
  • BinaryStream - permite criar, ler e editar ficheiros binários
  • XSpriter - o próprio extractor transforma o binário em imagens

(Para criar as imagens utilizo a biblioteca GD)

Como funciona?

Para extrair as imagens do Tibia.spr basta colocar o ficheiro na pasta do script e executar-lo. Será, então, criada uma nova pasta com o nome de Sprites, com as sprites dentro.

Scripts:
  • BinaryStream.lua


--[[
    Binary Stream
Allows you to read, edit and create new binary files
Developed by Colex (Alexandre Santos)
]]--

require("bit")

_BINARY_STREAM = {
    Position = 0
}

BinaryStream = function(filename)
    local obj = {}
    local file = io.open(filename, "rb")

    if not (file) then
        return nil
    end

    setmetatable(obj, _BINARY_STREAM)
    _BINARY_STREAM.__index = _BINARY_STREAM

    obj["Buffer"] = file:read("*all")
    obj["Length"] = obj.Buffer:len()
    obj["FileName"] = filename
    file:close()
    return obj
end

CreateBinary = function(filename)
    local obj = {}

    setmetatable(obj, _BINARY_STREAM)
    _BINARY_STREAM.__index = _BINARY_STREAM

    obj["Buffer"] = ""
    obj["Length"] = 0
    obj["FileName"] = filename

    return obj
end

---Read Functions

_BINARY_STREAM.ReadByte = function(self)
    self.Position = self.Position + 1
    return self.Buffer:byte(self.Position)
end

_BINARY_STREAM.ReadInt16 = function(self)

    local l1 = self:ReadByte()
    local l2 = bit.lshift(self:ReadByte(), 8)


    return l1 + l2
end

_BINARY_STREAM.ReadInt32 = function(self)
    local l1 = self:ReadByte()
    local l2 = bit.lshift(self:ReadByte(), 8)
    local l3 = bit.lshift(self:ReadByte(), 16)
    local l4 = bit.lshift(self:ReadByte(), 24)


    return l1 + l2 + l3 + l4
end

--Write Functions

_BINARY_STREAM.WriteByte = function(self, byte, insert)
    self.Position = self.Position + 1
    if not(insert) then
        self.Buffer = self.Buffer:sub(0,self.Position-1)..string.char(byte)..self.Buffer:sub(self.Position+1)
    else
        self.Buffer = self.Buffer:sub(0,self.Position-1)..string.char(byte)..self.Buffer:sub(self.Position)
    end
end

_BINARY_STREAM.WriteInt16 = function(self, int16, insert)
    local l1 = bit.rshift(bit.lshift(int16, 24), 24)
    local l2 = bit.rshift(bit.lshift(int16, 16), 24)


    WriteByte(l1, insert)
    WriteByte(l2, insert)
end

_BINARY_STREAM.WriteInt32 = function(self, int32, insert)
    local l1 = bit.rshift(bit.lshift(int32, 24), 24)
    local l2 = bit.rshift(bit.lshift(int32, 16), 24)
    local l3 = bit.rshift(bit.lshift(int32, 8), 24)
    local l4 = bit.rshift(int32, 24)

    WriteByte(l1, insert)
    WriteByte(l2, insert)
    WriteByte(l3, insert)
    WriteByte(l4, insert)
end

--Insert Function

_BINARY_STREAM.InsertByte = function(self, byte)
    self:WriteByte(byte, true)
end

_BINARY_STREAM.InsertInt16 = function(self, int16)
    self:WriteInt16(int16, true)
end

_BINARY_STREAM.InsertInt32 = function(self, int32)
    self:WriteInt32(int32, true)
end



--Position Functions

_BINARY_STREAM.Skip = function(self, bytes)
    self.Position = self.Position + bytes
end

_BINARY_STREAM.Seek = function(self, pos, origin)
    if (origin == 0) then --Begin
        self.Position = pos
    elseif (origin == 1) then --Current Position
        self.Position = self.Position + pos
    elseif (origin == 2) then --End
        self.Position = self.length + pos
    end
end


--Save function

_BINARY_STREAM.Save = function(self, filename)
    filename = filename or self.FileName
    local file = io.open(filename, "wb")
    file:write(self.Buffer)
    file:close()
end


  • XSpriter.lua

--[[
    XSpriter v0.1
Extract Sprites from a Tibia.spr

Developed by Colex (Alexandre Santos)
]]--

require("bit")
require("gd")
require("os")
require("BinaryStream")



---------Sprite Reader---------

local ExtractSprites = function()
    spriter = BinaryStream("Tibia.spr")
    if not(spriter) then
        print("Ficheiro Tibia.spr não encontrado!")
        return
    end

    spriter:Skip(4)

    local n_sprites = spriter:ReadInt16()
    os.execute("mkdir Sprites")

    print("Iniciando extração...")
    for n_sprite=1, n_sprites do

        print("Extraindo: " .. (math.floor(n_sprite/n_sprites*100)) .. "%")

        spriter:Seek(6 + n_sprite * 4, 0)

        spriter:Seek(spriter:ReadInt32() + 3, 0)

        local pixel = 0
        local r, g, b, color

        local sprite = gd.createTrueColor(32, 32)
        sprite:filledRectangle(0, 0, 32, 32, sprite:colorAllocate(255, 0,255))

        local offset = spriter.Position + spriter:ReadInt16();

        while spriter.Position < offset do
            local tp = spriter:ReadInt16()
            local colored = spriter:ReadInt16()
            pixel = pixel + tp
            for x = 1, colored do
                r = spriter:ReadByte()
                g = spriter:ReadByte()
                b = spriter:ReadByte()
                color = sprite:colorAllocate(r, g, b)
                sprite:setPixel(pixel%32, math.floor(pixel/32), color)
                pixel = pixel + 1
            end
        end

        sprite:png("Sprites\\"..n_sprite..".png")

    end
end



ExtractSprites()


Para executar-lo poderá utilizar o programa SciTE, ponha o XSpriter.lua do BinaryStream.lua e execute o XSpriter.lua.

Créditos a Jo3 pela estrutura do Tibia.spr

Editado Novembro 25 por Colex

KydraiK
25 de novembro de 2009 às 00:46

Muito bom, realmente da pra tirar um proveito disso.

Dps vo dar uma olhada sobre essa BinaryStream.lua

 

Pra melhorar um pouco acho que deveria ter um modo de extrair somente 1 sprite, mas com algumas modificações consegue-se facil.

 

Bom script :smile_positivo:

Editado Novembro 25 por kydrai

5 anos depois...
MatheusEnjoyM
14 de setembro de 2015 às 18:53

Olha que massa. Muito interessante e o Colex era foda...