A Gff::Struct is a hash of label->Element pairs with some meta-information in local variables.
Methods
public class
public instance
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
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.
# File lib/nwn/gff/struct.rb, line 66 def self.new struct_id = 0xffffffff, data_type = nil, data_version = DEFAULT_DATA_VERSION s = {}.extend(self) s.struct_id = struct_id s.data_type = data_type s.data_version = data_version yield(s) if block_given? s end
Deep-unboxes a Hash, e.g. iterating down, converting it to the native charset.
# File lib/nwn/gff/struct.rb, line 226 def self.unbox! o, parent = nil o.extend(NWN::Gff::Struct) o.element = parent if parent o.struct_id = o.delete('__struct_id') o.data_type = o.delete('__data_type') o.data_version = o.delete('__data_version') o.data_version ||= NWN::Gff::Struct::DEFAULT_DATA_VERSION NWN.log_debug("Unboxed without a root data type") if !parent && !o.data_type NWN.log_debug("Unboxed with explicit data type #{o.data_type.inspect}") if parent && o.data_type o.each {|label,element| o[label] = NWN::Gff::Field.unbox!(element, label, o) } o end
Public instance methods
An alias for by_path.
# File lib/nwn/gff/struct.rb, line 220 def / path by_path(path) end
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
# File lib/nwn/gff/struct.rb, line 94 def add_field label, type, value = nil, &block value ||= NWN::Gff::Field::DEFAULT_VALUES[type] || raise(ArgumentError, "type #{type.inspect} requires explicit value") self[label] = NWN::Gff::Field.new(label, type, value) self[label].parent = self yield(self[label]) if block_given? if self[label].field_value.is_a?(NWN::Gff::Struct) self[label].field_value.element = self[label] end self[label] end
Returns a hash of this Struct without the API calls mixed in, converting it from the native charset.
# File lib/nwn/gff/struct.rb, line 248 def box t = Hash[self] t.merge!({ '__struct_id' => self.struct_id }) t.merge!({ '__data_version' => self.data_version, }) if self.data_version && self.data_version != NWN::Gff::Struct::DEFAULT_DATA_VERSION t.merge!({ '__data_type' => self.data_type }) if @data_type t end
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.
# File lib/nwn/gff/struct.rb, line 171 def by_path path struct = self current_path = "" path = path.split('/').map {|v| v.strip }.reject {|v| v.empty?}.join('/') path, mod = $1, $2 if path =~ /^(.+?)([\$\?%])?$/ path.split('/').each_with_index {|v, path_index| if struct.is_a?(NWN::Gff::Field) && struct.field_type == :cexolocstr && v =~ /^\d+$/ && path_index == path.split('/').size - 1 struct = struct.field_value[v.to_i] break end v, index = $1, $2 if v =~ /^(.+?)\[(\d+)\]$/ struct = struct.v if struct.is_a?(NWN::Gff::Field) && struct.field_type == :struct struct = struct[v] if index struct.field_type == :list or raise NWN::Gff::GffPathInvalidError, "Specified a list offset for a non-list item: #{v}[#{index}]." struct = struct.field_value[index.to_i] end raise NWN::Gff::GffPathInvalidError, "Cannot find a path to /#{path} (at: #{current_path})." unless struct current_path += "/" + v current_path += "[#{index}]" if index } case mod when "$" struct.field_value when "?" struct.field_type when "%" struct.has_str_ref? ? struct.str_ref : NWN::Gff::Cexolocstr::DEFAULT_STR_REF else struct end end
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.
# File lib/nwn/gff/struct.rb, line 37 def data_type @data_type end
Overrides the data type (used by the built-in file format readers).
# File lib/nwn/gff/struct.rb, line 42 def data_type= k k = nil if k == "" NWN.log_debug("Setting explicit data_type for parented element") if k && @element @data_type = k end
Example: “/AddCost” => {“type”=>:dword, ..}
# File lib/nwn/gff/struct.rb, line 135 def each_by_flat_path prefix = "/", &block sort.each {|label, field| field.each_by_flat_path do |ll, lv| yield(prefix + label + ll, lv) end } end
# File lib/nwn/gff/struct.rb, line 21 def path if @element @element.path else "/" end end
Dump this struct as GFF binary data.
Optionally specify data_type and data_version
# File lib/nwn/gff/struct.rb, line 56 def to_gff data_type = nil NWN::Gff::Writer.dump(self, data_type) end
# File lib/nwn/json_support.rb, line 4 def to_json(*a) box.to_json(*a) end
# File lib/nwn/gff/struct.rb, line 125 def to_s "<NWN::Gff::Struct #{self.data_type}/#{self.data_version}, #{self.keys.size} fields>" end