Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- BMV (BizHawk movie) import functions.
- -- Currently supports only SNES movie...
- -- movie base class
- function BaseMovie(filename)
- local self = { meta = {}, data = {} }
- local errorMessage = nil
- if filename ~= nil then
- -- open movie file
- local file = io.open(filename, "r")
- if file == nil then
- return nil, "error opening file \"" .. filename .. "\""
- end
- -- parse lines from beginning
- local line = file:read("*l")
- local lineNo = 1
- while line do
- if string.sub(line, 1, 1) == "|" then
- if #line < 2 or string.sub(line, #line, #line) ~= "|" then
- file:close()
- return nil, filename .. ":" .. lineNo .. ": missing '|' at end of line"
- end
- -- split
- local data = { }
- local sep = 1
- while sep < #line do
- local nextSep = string.find(line, "|", sep + 1, true)
- table.insert(data, string.sub(line, sep + 1, nextSep - 1))
- sep = nextSep
- end
- table.insert(self.data, data)
- elseif line ~= "" then
- -- read key-value pair
- local name, value
- local sep = string.find(line, " ", 1, true)
- if sep ~= nil then
- name = string.sub(line, 1, sep - 1)
- value = string.sub(line, sep + 1)
- else
- name = line
- value = ""
- end
- -- duplication check
- if self.meta[name] ~= nil then
- file:close()
- return nil, filename .. ":" .. lineNo .. ": duplicated item \"" .. name .. "\""
- end
- -- store metadata (as string)
- self.meta[name] = value
- end
- line = file:read("*l")
- lineNo = lineNo + 1
- end
- -- close movie file
- file:close()
- end
- -- start class functions
- self.PreferredMetaDataOrder = {}
- function self.Export(self, filename)
- -- type check
- if type(self) ~= "table" then
- error("bad argument #1 to BaseMovie.Export (table expected, got " .. type(self) .. ")")
- end
- if type(filename) ~= "string" then
- error("bad argument #2 to BaseMovie.Export (string expected, got " .. type(filename) .. ")")
- end
- local file = io.open(filename, "wb")
- if file == nil then
- return false, "error opening file \"" .. filename .. "\""
- end
- -- export metadata
- local exportedMeta
- for i, k in ipairs(self.PreferredMetaDataOrder) do
- local v = self.meta[k]
- if v ~= nil then
- file:write(k .. " " .. tostring(v) .. "\n")
- end
- end
- for k, v in pairs(self.meta) do
- file:write(k .. " " .. tostring(v) .. "\n")
- end
- -- export input stream
- for currentSample, ctlData in ipairs(self.data) do
- if #ctlData > 0 then
- file:write("|")
- end
- for i, v in ipairs(ctlData) do
- file:write(v .. "|")
- end
- file:write("\n")
- end
- file:close()
- return true, ""
- end
- function self.ConvertMetaType(self, typeTable)
- -- type check
- if type(self) ~= "table" then
- error("bad argument #1 to BaseMovie.ConvertType (table expected, got " .. type(self) .. ")")
- end
- if type(typeTable) ~= "table" then
- error("bad argument #2 to BaseMovie.ConvertType (table expected, got " .. type(typeTable) .. ")")
- end
- -- type conversion for each metadata
- for name, typeName in pairs(typeTable) do
- if typeName == "number" then
- self.meta[name] = tonumber(self.meta[name])
- elseif typeName == "string" then
- self.meta[name] = tostring(self.meta[name])
- else
- error("unknown type \"" .. typeName .. "\"")
- end
- end
- end
- function self.SplitInputSample(self, str, charTable)
- if type(str) ~= "string" then
- error("bad argument #2 to BaseMovie.SplitInputSample (string expected, got " .. type(str) .. ")")
- end
- if type(charTable) ~= "table" then
- error("bad argument #3 to BaseMovie.SplitInputSample (table expected, got " .. type(charTable) .. ")")
- end
- if #str > #charTable then
- error("bad argument #2 (too long string)")
- end
- local t = {}
- for i = 1, #str do
- local c = str:sub(i, i)
- if c == charTable[i].key then
- t[charTable[i].name] = true
- elseif c == "." then
- t[charTable[i].name] = false
- else
- return nil, tostring(i) .. ": bad input sample (" .. charTable[i].key .. " expected, got " .. c .. ")"
- end
- end
- return t
- end
- function self.JoinInputSample(self, t, charTable)
- if type(t) ~= "table" then
- error("bad argument #2 to BaseMovie.JoinInputSample (table expected, got " .. type(t) .. ")")
- end
- if type(charTable) ~= "table" then
- error("bad argument #3 to BaseMovie.JoinInputSample (table expected, got " .. type(charTable) .. ")")
- end
- local str = ""
- for i = 1, #charTable do
- if t[charTable[i].name] then
- str = str .. charTable[i].key
- else
- str = str .. "."
- end
- end
- return str
- end
- -- end class functions
- -- success
- return self, nil
- end
- -- bizhawk movie class
- function BizHawkMovie(filename)
- local self, errorMessage = BaseMovie(filename)
- if self == nil then
- return self, errorMessage
- end
- -- format movie params
- if self.meta.Platform == "SNES" then
- -- metadata type conversion
- self.MetaTypeTable = {
- rerecordCount = "number"
- }
- self:ConvertMetaType(self.MetaTypeTable)
- -- list of available input
- self.InputSampleTable = {
- { key = "U", name = "up" },
- { key = "D", name = "down" },
- { key = "L", name = "left" },
- { key = "R", name = "right" },
- { key = "s", name = "select" },
- { key = "S", name = "start" },
- { key = "B", name = "B" },
- { key = "A", name = "A" },
- { key = "X", name = "X" },
- { key = "Y", name = "Y" },
- { key = "L", name = "L" },
- { key = "R", name = "R" }
- }
- self.PreferredMetaDataOrder = {
- "emuVersion",
- "MovieVersion",
- "Platform",
- "GameName",
- "Author",
- "rerecordCount",
- "GUID",
- "SHA1"
- }
- -- convert input samples
- local dataLength = nil
- for dataIndex = 1, #self.data do
- local data = self.data[dataIndex]
- local t = {}
- if #data < 2 then
- return nil, "data[" .. dataIndex .. "]: no joypad input"
- end
- -- TODO move this logic to BaseMovie()?
- if dataLength == nil then
- dataLength = #data
- end
- if #data ~= dataLength then
- return nil, "data[" .. dataIndex .. "]: mismatch number of samples (between " .. #data .. " and " .. dataLength .. ")"
- end
- -- TODO flag field
- if #data[1] ~= 1 then
- return nil, "data[" .. dataIndex .. "][1]: invalid length"
- end
- if data[1] == "." then
- elseif data[1] == "." then
- else
- return nil, "data[" .. dataIndex .. "][1]: bad input sample " .. data[1]
- end
- t.joypad = {}
- local playerHead = 2
- local playerTail = #data - 1
- for player = 1, playerTail do
- t.joypad[player] = self:SplitInputSample(data[player + (playerHead - 1)], self.InputSampleTable)
- end
- self.data[dataIndex] = t
- end
- else
- return nil, "unknown platform \"" .. tostring(self.meta.Platform) .. "\""
- end
- -- start class functions
- function self.Export(self, filename)
- -- type check
- if type(self) ~= "table" then
- error("bad argument #1 to BizHawkMovie.Export (table expected, got " .. type(self) .. ")")
- end
- if type(filename) ~= "string" then
- error("bad argument #2 to BizHawkMovie.Export (string expected, got " .. type(filename) .. ")")
- end
- local file = io.open(filename, "wb")
- if file == nil then
- return false, "error opening file \"" .. filename .. "\""
- end
- -- export metadata
- for k, v in pairs(self.meta) do
- file:write(k .. " " .. tostring(v) .. "\n")
- end
- -- export input stream
- for controller, ctlData in ipairs(self.data) do
- if #ctlData.joypad > 0 then
- file:write("|")
- end
- for currentSample, inputTable in ipairs(ctlData.joypad) do
- local str = self:JoinInputSample(inputTable, self.InputSampleTable)
- file:write(str .. "|")
- end
- file:write("\n")
- end
- file:close()
- return true, ""
- end
- -- end class functions
- return self, errorMessage
- end
- -- test starts here...
- function t2s(t)
- local s = "{"
- for k, v in pairs(t) do
- if s ~= "{" then
- s = s .. ","
- end
- s = s .. tostring(k) .. "=" .. tostring(v)
- end
- return s .. "}"
- end
- self, err = BizHawkMovie("snes.bmv")
- if self == nil then
- error(err)
- end
- self:Export("temp.bmv")
- --[[
- print(#self.meta)
- for k, v in pairs(self.meta) do
- print(k, "=", "\""..v.."\"", type(v))
- end
- print(#self.data)
- for i, v in ipairs(self.data) do
- print(i)
- for j, w in ipairs(v.joypad) do
- -- local ttt = self:SplitInputSample(w, snesbmvInputSampleTable)
- -- local sss = ""
- -- for kkk, vvv in pairs(ttt) do
- -- if vvv then
- -- sss = sss .. kkk .. "=" .. tostring(vvv) .. "; "
- -- end
- -- end
- print(t2s(w))
- end
- end
- ]]
Add Comment
Please, Sign In to add comment