Class: Doom::Wad::Reader

Inherits:
Object
  • Object
show all
Defined in:
lib/doom/wad/reader.rb

Defined Under Namespace

Classes: DirectoryEntry

Constant Summary collapse

IWAD =
'IWAD'
PWAD =
'PWAD'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Reader



13
14
15
16
17
# File 'lib/doom/wad/reader.rb', line 13

def initialize(path)
  @file = File.open(path, 'rb')
  read_header
  read_directory
end

Instance Attribute Details

#directoryObject (readonly)

Returns the value of attribute directory.



11
12
13
# File 'lib/doom/wad/reader.rb', line 11

def directory
  @directory
end

#num_lumpsObject (readonly)

Returns the value of attribute num_lumps.



11
12
13
# File 'lib/doom/wad/reader.rb', line 11

def num_lumps
  @num_lumps
end

#typeObject (readonly)

Returns the value of attribute type.



11
12
13
# File 'lib/doom/wad/reader.rb', line 11

def type
  @type
end

Instance Method Details

#closeObject



96
97
98
99
# File 'lib/doom/wad/reader.rb', line 96

def close
  @file.close
  (@pwad_files || []).each(&:close)
end

#find_lump(name) ⇒ Object



19
20
21
# File 'lib/doom/wad/reader.rb', line 19

def find_lump(name)
  @directory.find { |entry| entry.name == name.upcase }
end

#iwad?Boolean



50
51
52
# File 'lib/doom/wad/reader.rb', line 50

def iwad?
  @type == IWAD
end

#lumps_between(start_marker, end_marker) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/doom/wad/reader.rb', line 38

def lumps_between(start_marker, end_marker)
  start_idx = @directory.index { |e| e.name == start_marker }
  end_idx = @directory.index { |e| e.name == end_marker }
  return [] unless start_idx && end_idx

  @directory[start_idx + 1...end_idx]
end

#merge_pwad(pwad) ⇒ Object

Merge a PWAD on top of this IWAD. PWAD lumps override IWAD lumps with the same name. Map lumps (between map markers) are replaced as a group.

Raises:



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/doom/wad/reader.rb', line 57

def merge_pwad(pwad)
  raise Error, 'Can only merge a PWAD' unless pwad.pwad?

  @lump_cache.clear

  pwad.directory.each do |pwad_entry|
    # Check if this lump already exists in the IWAD
    existing_idx = @directory.index { |e| e.name == pwad_entry.name }
    if existing_idx
      # Replace it -- but we need to read from the PWAD file
      @directory[existing_idx] = pwad_entry
    else
      # Append new lump
      @directory << pwad_entry
    end
  end

  # Keep the PWAD file open for reading its lumps
  @pwad_files ||= []
  @pwad_files << pwad
  @num_lumps = @directory.size
end

#pwad?Boolean



46
47
48
# File 'lib/doom/wad/reader.rb', line 46

def pwad?
  @type == PWAD
end

#read_lump(name) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/doom/wad/reader.rb', line 23

def read_lump(name)
  return @lump_cache[name] if @lump_cache.key?(name)

  entry = find_lump(name)
  return nil unless entry

  # Route through read_lump_at, which reads from the file that actually
  # owns the entry. After merge_pwad a lump the PWAD overrode (PLAYPAL,
  # COLORMAP, TEXTUREx, PNAMES, a patch) lives in the PWAD file, so seeking
  # this reader's own IWAD handle at the entry's offset would read garbage.
  data = read_lump_at(entry)
  @lump_cache[name] = data
  data
end

#read_lump_at(entry) ⇒ Object

Read a lump by directory entry, checking if it belongs to a PWAD file



81
82
83
84
85
86
87
88
# File 'lib/doom/wad/reader.rb', line 81

def read_lump_at(entry)
  # Try PWAD files first (they may own this entry)
  (@pwad_files || []).each do |pwad|
    return pwad.read_lump_own(entry) if pwad.directory.include?(entry)
  end
  @file.seek(entry.offset)
  @file.read(entry.size)
end

#read_lump_own(entry) ⇒ Object

Read a lump that belongs to this WAD's own file



91
92
93
94
# File 'lib/doom/wad/reader.rb', line 91

def read_lump_own(entry)
  @file.seek(entry.offset)
  @file.read(entry.size)
end