class RandTileGenerator def initialize @sections = {} end def section(name) @sections[name] ||= {entries: []} @current_section = @sections[name] yield end def random(range, type=:both, numbers=nil) numbers = range if numbers.nil? @current_section[:entries] << {range: range, type: type, numbers: numbers.to_a} end def pack # first, work out an offset for every section and entry # also, collect the data for each individual entry into an Array current_offset = 8 + (@sections.count * 4) all_entry_data = [] @sections.each_pair do |name, section| section[:offset] = current_offset current_offset += 8 section[:entries].each do |entry| entry[:offset] = current_offset all_entry_data << entry[:numbers] current_offset += 8 end end # assign an offset to each piece of entry data data_offsets = {} all_entry_data.uniq! all_entry_data.each do |data| data_offsets[data] = current_offset current_offset += data.size end # assign an offset to each section name name_offsets = {} @sections.keys.each do |name| name_offsets[name] = current_offset current_offset += name.size + 1 end # now pack it all together header = ['NwRT', @sections.count].pack('a4 N') offsets = @sections.each_value.map{|s| s[:offset]}.pack('N*') section_data = @sections.each_pair.map do |name, section| name_offset = name_offsets[name] - section[:offset] entry_count = section[:entries].count entry_data = section[:entries].map do |entry| lower_bound = entry[:range].min upper_bound = entry[:range].max count = entry[:numbers].count type = [:none, :horz, :vert, :both].index(entry[:type]) num_offset = data_offsets[entry[:numbers]] - entry[:offset] [lower_bound, upper_bound, count, type, num_offset].pack('CCCC N') end [name_offset, entry_count].pack('NN') + entry_data.join end output = [header, offsets] output += section_data output += all_entry_data.map{|data| data.pack('C*')} output << @sections.keys.join("\0") output << "\0" output.join end end g = RandTileGenerator.new g.section('TestTileset') do g.random(1..20) g.random(21..24, :none) g.random(250..255, :vert, 0..5) end File.open('/home/me/Games/Newer/DolphinPatch/NewerRes/RandTiles.bin', 'wb') do |f| f.write g.pack end