Module NWN::Gff::Struct

  1. lib/nwn/json_support.rb
  2. lib/nwn/gff/struct.rb
  3. show all

A Gff::Struct is a hash of label->Element pairs with some meta-information in local variables.

Constants

DEFAULT_DATA_VERSION = "V3.2"

Attributes

data_version [RW] The file version. Usually “V3.2“. If not given in a source format, DEFAULT_DATA_VERSION is inferred and set for all structs.
element [R] The field this struct is value of. It is most likely a Field of :list, or :nil if it is the root struct. Setting this to a value detaches this struct from the old parent (though the old parent Field may still point to this object).
struct_id [RW] GFF struct type. The default is 0xffffffff.

Public class methods

new (struct_id = 0xffffffff, data_type = nil, data_version = DEFAULT_DATA_VERSION) {|s| ...}

Create a new struct. Usually, you can leave out data_type and data_version for non-root structs, because that will be guess-inherited based on the existing associations.

You can pass a block to this method, which will receive the newly-created Struct as the only argument.

[show source]
    # File lib/nwn/gff/struct.rb, line 66
66:   def self.new struct_id = 0xffffffff, data_type = nil, data_version = DEFAULT_DATA_VERSION
67:     s = {}.extend(self)
68:     s.struct_id = struct_id
69:     s.data_type = data_type
70:     s.data_version = data_version
71:     yield(s) if block_given?
72:     s
73:   end
unbox! (o, parent = nil)

Deep-unboxes a Hash, e.g. iterating down, converting it to the native charset.

[show source]
     # File lib/nwn/gff/struct.rb, line 226
226:   def self.unbox! o, parent = nil
227:     o.extend(NWN::Gff::Struct)
228:     o.element = parent if parent
229:     o.struct_id = o.delete('__struct_id')
230:     o.data_type = o.delete('__data_type')
231:     o.data_version = o.delete('__data_version')
232:     o.data_version ||= NWN::Gff::Struct::DEFAULT_DATA_VERSION
233: 
234:     NWN.log_debug("Unboxed without a root data type") if
235:       !parent && !o.data_type
236:     NWN.log_debug("Unboxed with explicit data type #{o.data_type.inspect}") if
237:       parent && o.data_type
238: 
239:     o.each {|label,element|
240:       o[label] = NWN::Gff::Field.unbox!(element, label, o)
241:     }
242: 
243:     o
244:   end

Public instance methods

/ (path)

An alias for by_path.

[show source]
     # File lib/nwn/gff/struct.rb, line 220
220:   def / path
221:     by_path(path)
222:   end
add_field (label, type, value = nil) {|self[label]| ...}

Create a new field. Alternatively, you can use the shorthand methods:

add_#{type} - add_int, add_byte, ..

For example:

some_struct.add_field 'ID', :byte, 5

is equivalent to:

some_struct.add_byte 'ID', 5

You can pass a block to this method, which will receive the newly-created Field as an argument.

This allows for code like this:

Gff::Struct.new(0) do |s|
  s.add_byte "Byte", 5
  s.add_list "Some_List", [] do |l|
    l.v << Gff::Struct.new ...
    ..
  end
end
[show source]
     # File lib/nwn/gff/struct.rb, line 94
 94:   def add_field label, type, value = nil, &block
 95:     value ||= NWN::Gff::Field::DEFAULT_VALUES[type] || raise(ArgumentError,
 96:       "type #{type.inspect} requires explicit value")
 97:     self[label] = NWN::Gff::Field.new(label, type, value)
 98:     self[label].parent = self
 99:     yield(self[label]) if block_given?
100:     if self[label].field_value.is_a?(NWN::Gff::Struct)
101:       self[label].field_value.element = self[label]
102:     end
103:     self[label]
104:   end
box ()

Returns a hash of this Struct without the API calls mixed in, converting it from the native charset.

[show source]
     # File lib/nwn/gff/struct.rb, line 248
248:   def box
249:     t = Hash[self]
250:     t.merge!({
251:       '__struct_id' => self.struct_id
252:     })
253:     t.merge!({
254:       '__data_version' => self.data_version,
255:     }) if self.data_version && self.data_version !=
256:       NWN::Gff::Struct::DEFAULT_DATA_VERSION
257:     t.merge!({
258:       '__data_type' => self.data_type
259:     }) if @data_type
260:     t
261:   end
by_path (path)

Retrieve an object from within the given tree. Path is a slash-separated destination, given as a string

Prefixed/postfixed slashes are optional.

You can retrieve CExoLocString values by giving the language ID as the last label:

/FirstName/0

You can retrieve list values by specifying the index in square brackets:

/SkillList[0]
/SkillList[0]/Rank   => {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}

You can directly retrieve field values and types instead of the field itself:

/SkillList[0]/Rank$  => 0
/SkillList[0]/Rank?   => :byte

This will raise an error for non-field paths, naturally:

SkillList[0]$        => undefined method `field_value' for {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}:Hash
SkillList[0]?        => undefined method `field_type' for {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}:Hash

For CExoLocStrings, you can retrieve the str_ref:

FirstName%           => 4294967295

This will return DEFAULT_STR_REF (0xffffffff) if the given path does not have a str_ref.

[show source]
     # File lib/nwn/gff/struct.rb, line 171
171:   def by_path path
172:     struct = self
173:     current_path = ""
174:     path = path.split('/').map {|v| v.strip }.reject {|v| v.empty?}.join('/')
175: 
176:     path, mod = $1, $2 if path =~ /^(.+?)([\$\?%])?$/
177: 
178:     path.split('/').each_with_index {|v, path_index|
179:       if struct.is_a?(NWN::Gff::Field) && struct.field_type == :cexolocstr &&
180:           v =~ /^\d+$/ && path_index == path.split('/').size - 1
181:         struct = struct.field_value[v.to_i]
182:         break
183:       end
184: 
185:       v, index = $1, $2 if v =~ /^(.+?)\[(\d+)\]$/
186: 
187:       struct = struct.v if struct.is_a?(NWN::Gff::Field) &&
188:         struct.field_type == :struct
189: 
190:       struct = struct[v]
191:       if index
192:         struct.field_type == :list or raise NWN::Gff::GffPathInvalidError,
193:           "Specified a list offset for a non-list item: #{v}[#{index}]."
194: 
195:         struct = struct.field_value[index.to_i]
196:       end
197: 
198: 
199:       raise NWN::Gff::GffPathInvalidError,
200:         "Cannot find a path to /#{path} (at: #{current_path})." unless struct
201: 
202:       current_path += "/" + v
203:       current_path += "[#{index}]" if index
204:     }
205: 
206:     case mod
207:       when "$"
208:         struct.field_value
209:       when "?"
210:         struct.field_type
211:       when "%"
212:         struct.has_str_ref? ? struct.str_ref :
213:           NWN::Gff::Cexolocstr::DEFAULT_STR_REF
214:       else
215:         struct
216:     end
217:   end
data_type ()

Each Gff::Struct has a data_type, which describes the type of data the struct contains. For top-level structs, this equals the data type written to the GFF file (“UTI”, for example); for sub structures, this is usually nil, but can be overriden by users explicitly to carry some meta-data (e.g. explicitly set UTC/ItemList[0] to UTI). This is not done automatically, however.

Scripts could use this, for example, to reliably re-attach a Item within /ItemList/ somewhere else, or export it as .uti.

[show source]
    # File lib/nwn/gff/struct.rb, line 37
37:   def data_type
38:     @data_type
39:   end
data_type= (k)

Overrides the data type (used by the built-in file format readers).

[show source]
    # File lib/nwn/gff/struct.rb, line 42
42:   def data_type= k
43:     k = nil if k == ""
44:     NWN.log_debug("Setting explicit data_type for parented element") if k && @element
45:     @data_type = k
46:   end
each_by_flat_path (prefix = "/") {|prefix + label + ll, lv| ...}

Example: “/AddCost” => {“type”=>:dword, ..}

[show source]
     # File lib/nwn/gff/struct.rb, line 135
135:   def each_by_flat_path prefix = "/", &block
136:     sort.each {|label, field|
137:       field.each_by_flat_path do |ll, lv|
138:         yield(prefix + label + ll, lv)
139:       end
140:     }
141:   end
path ()
[show source]
    # File lib/nwn/gff/struct.rb, line 21
21:   def path
22:     if @element
23:       @element.path
24:     else
25:       "/"
26:     end
27:   end
to_gff (data_type = nil)

Dump this struct as GFF binary data.

Optionally specify data_type and data_version

[show source]
    # File lib/nwn/gff/struct.rb, line 56
56:   def to_gff data_type = nil
57:     NWN::Gff::Writer.dump(self, data_type)
58:   end
to_json (*a)
[show source]
   # File lib/nwn/json_support.rb, line 4
4:   def to_json(*a)
5:     box.to_json(*a)
6:   end
to_s ()
[show source]
     # File lib/nwn/gff/struct.rb, line 125
125:   def to_s
126:     "<NWN::Gff::Struct #{self.data_type}/#{self.data_version}, #{self.keys.size} fields>"
127:   end