Class: NEXXT::Parser::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/nexxt/parser/session.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(text) ⇒ Session

Returns a new instance of Session.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/nexxt/parser/session.rb', line 14

def initialize(text)
  @text = text
  lines = text.lines(chomp: true).compact
  @flat_table = lines.grep(/=/).to_h { |line| line.split('=', 2) }
  @table = Session.parse_table(@flat_table)
  @chr_main = Session.decode_hex(@table.dig('CHR', 'Main'))
  @chr_copy = Session.decode_hex(@table.dig('CHR', 'Copy'))
  @chr_undo = Session.decode_hex(@table.dig('CHR', 'Undo'))
  @metasprites_offset = @table.dig('Var', 'Sprite', 'Grid').then do |grid|
    {
      x: grid['X'].to_i,
      y: grid['Y'].to_i
    }
  end
  @metasprites = Session.make_metasprites(
    names: Session.metasprite_names(@table.dig('Meta', 'Sprite')),
    bytes: Session.decode_hex(@table.dig('Meta', 'Sprites')),
    offset: @metasprites_offset
  )
end

Instance Attribute Details

#chr_copyObject (readonly)

Returns the value of attribute chr_copy.



11
12
13
# File 'lib/nexxt/parser/session.rb', line 11

def chr_copy
  @chr_copy
end

#chr_mainObject (readonly)

Returns the value of attribute chr_main.



11
12
13
# File 'lib/nexxt/parser/session.rb', line 11

def chr_main
  @chr_main
end

#flat_tableObject (readonly)

Returns the value of attribute flat_table.



11
12
13
# File 'lib/nexxt/parser/session.rb', line 11

def flat_table
  @flat_table
end

#metaspritesObject (readonly)

Returns the value of attribute metasprites.



11
12
13
# File 'lib/nexxt/parser/session.rb', line 11

def metasprites
  @metasprites
end

#metasprites_offsetObject (readonly)

Returns the value of attribute metasprites_offset.



11
12
13
# File 'lib/nexxt/parser/session.rb', line 11

def metasprites_offset
  @metasprites_offset
end

#tableObject (readonly)

Returns the value of attribute table.



11
12
13
# File 'lib/nexxt/parser/session.rb', line 11

def table
  @table
end

#textObject (readonly)

Returns the value of attribute text.



11
12
13
# File 'lib/nexxt/parser/session.rb', line 11

def text
  @text
end

Class Method Details

.build_map(flat_table) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'lib/nexxt/parser/session.rb', line 52

def self.build_map(flat_table)
  tiles = decode_hex(flat_table['NameTable'])
  attributes = decode_hex(flat_table['AttrTable']) || []
  return nil if tiles.nil? || tiles.empty?

  width = flat_table['VarNameW'].to_i
  height = flat_table['VarNameH'].to_i
  Map.new(tiles + attributes, width: width, height: height)
end

.decode_hex(string) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/nexxt/parser/session.rb', line 83

def self.decode_hex(string)
  return if string.nil? || string.empty?

  string = string['_root'] if string.is_a?(Hash)
  return if string.nil? || string.empty?

  scanner = StringScanner.new(string)
  values = []
  last = 0
  until scanner.eos?
    if (hex = scanner.scan(/[0-9a-f]{2}/))
      last = hex.to_i(16)
      values << last
    elsif scanner.scan(/\[([0-9a-f]+)\]/)
      values.concat(Array.new(scanner[1].to_i(16) - 1, last))
    else
      raise "Invalid string #{scanner.rest}"
    end
  end
  values
end

.decompose_key(key) ⇒ Object



79
80
81
# File 'lib/nexxt/parser/session.rb', line 79

def self.decompose_key(key)
  key.split(/(?<=[^A-Z0-9])(?=[A-Z0-9])|(?<=CHR)/).map { |part| part.delete('_') }
end

.make_metasprites(names:, bytes:, offset:) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/nexxt/parser/session.rb', line 112

def self.make_metasprites(names:, bytes:, offset:)
  return [] if bytes.nil? || bytes.empty?

  sprites = bytes.each_slice(256)
                 .to_a
                 .map do |meta_bytes|
    meta_bytes.each_slice(4)
              .reject { |row| row[0] == 255 && row[2] == 255 && row[3] == 255 }
              .map do |y, tile, attribute, x|
      raise "Invalid bytes #{bytes}" if y.nil? || tile.nil? || attribute.nil? || x.nil?

      Sprite.new(y: y - offset[:y], tile: tile, attribute: attribute, x: x - offset[:x])
    end
  end
  names.map do |name, index|
    Metasprite.new(name: name, sprites: sprites[index])
  end
end

.metasprite_names(table) ⇒ Object



105
106
107
108
109
110
# File 'lib/nexxt/parser/session.rb', line 105

def self.metasprite_names(table)
  return {} if table.nil?

  table.select { |key, value| value.is_a?(String) && key =~ /\d/ }
       .to_h { |key, value| [value, key.to_i] }
end

.parse_table(flat_table) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/nexxt/parser/session.rb', line 62

def self.parse_table(flat_table)
  table = {}
  flat_table.each do |key, value|
    path = decompose_key(key)
    path.reduce(table) do |a, e|
      a[e] = { '_root' => a[e] } unless a[e].nil? || a[e].is_a?(Hash)
      a[e] ||= {}
    end
    if path.size > 1
      table.dig(*path[..-2])[path[-1]] = value
    else
      table[path.first] = value
    end
  end
  table
end

.read(file) ⇒ Object



35
36
37
# File 'lib/nexxt/parser/session.rb', line 35

def self.read(file)
  new(File.read(file))
end

Instance Method Details

#export_png(path) ⇒ Object



47
48
49
50
# File 'lib/nexxt/parser/session.rb', line 47

def export_png(path, **)
  require_relative 'png_exporter'
  PngExporter.export(self, path, **)
end

#mapObject



39
40
41
# File 'lib/nexxt/parser/session.rb', line 39

def map
  @map ||= Session.build_map(@flat_table)
end

#paletteObject



43
44
45
# File 'lib/nexxt/parser/session.rb', line 43

def palette
  @palette ||= Session.decode_hex(@flat_table['Palette']) || []
end