nwn-lib 0.4.8 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -251,3 +251,21 @@ Bernhard Stoeckner <elven@swordcoast.net> (6):
251
251
 
252
252
  Another bugfix and compatibility release. This adds real NWN2 support
253
253
  to gff reading, adds a few new SETTINGS, and adds proper IO reading.
254
+
255
+ === 0.4.9
256
+ Bernhard Stoeckner <elven@swordcoast.net> (10):
257
+ Gff::Reader/YAML: do not taint read objects
258
+ Scripting: satisfy win32 compatibility
259
+ nwn-irb: work on IO object instead of string
260
+ nwn-erf: fix typo in -h: -1 saying ERF 1.0 instead of ERF 1.1
261
+ Scripting: satisfy: close opened fds after loading GFF data
262
+ api.rb: merge into field.rb and struct.rb
263
+ Gff::Struct#by_path: print list index in current_path on error
264
+ Gff::Struct#by_path: / alias, $ and % mods, substruct & locname paths
265
+ TwoDA::Table: fix always printing errors for invalid IDs on table reading
266
+ Update documentation, add HOWTO
267
+ 0.4.9-rel
268
+
269
+ Some medium rare bugfixes, and a overloaded operator for GFF structs,
270
+ which can be used to comfortable walk on trees.
271
+
data/COPYING CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2008 Bernhard Stoeckner <elven@swordcoast.net> and contributors
1
+ Copyright (C) 2008-current Bernhard Stoeckner <elven@swordcoast.net> and contributors
2
2
 
3
3
  This program is free software; you can redistribute it and/or modify
4
4
  it under the terms of the GNU General Public License as published by
data/HOWTO ADDED
@@ -0,0 +1,170 @@
1
+ === Writing scripts to do the work for you
2
+
3
+ First, read SCRIPTING. Since an example is more worth than a thousand words,
4
+ here is a quick introduction in the form of a script that handles input
5
+ files from ARGV, does nothing with them, and then saves them back to the same
6
+ file from which they came from.
7
+
8
+ #!/usr/bin/env nwn-dsl
9
+
10
+ ARGV.each_with_index {|file, index|
11
+ # The script will abort hard if file is not an ARE.
12
+ # This looks up the data_type, which are usually the
13
+ # first four bytes of a file.
14
+ gff = need file, :are
15
+
16
+ # This will save gff back to 'file'.
17
+ save gff
18
+
19
+ # This will prefix all lines printed with log with
20
+ # a percentage. It's usage is optional, and the sole
21
+ # reason for using each_with_index instead of each above.
22
+ progress index
23
+ }
24
+
25
+ To run this example, type the following in a directory containing some .are
26
+ files, with script.rb being the name you saved the above script in.
27
+
28
+ nwn-dsl path/to/script.rb *.are
29
+
30
+ The shebang (#!/..) is for unixoid systems and Cygwin, and as such optional.
31
+
32
+ For all available commands to nwn-dsl scripts, see NWN::Gff::Scripting.
33
+
34
+ <b>All code snippets shown here assume that you put <tt>include NWN</tt>
35
+ in your application. It is not needed for nwn-dsl, which imports that
36
+ namespace for you.</b>
37
+
38
+ === Accessing GFF paths
39
+
40
+ You can access GFF paths within structs by using the overloaded division
41
+ operator.
42
+
43
+ #!/usr/bin/env nwn-dsl
44
+
45
+ ARGV.each_with_index {|file, index|
46
+ gff = need file, :are
47
+
48
+ log (gff / 'Name/0')
49
+
50
+ progress index
51
+ }
52
+
53
+ For a full reference of the path syntax, see NWN::Gff::Struct#by_path.
54
+
55
+ You cannot use paths to assign new values to structs - you can only
56
+ modify existing values:
57
+
58
+ (gff / 'Name').v[0] = "New Localized Name with Language ID 0"
59
+
60
+ Wrong, will raise error:
61
+
62
+ (gff / 'Name/0') = "New .."
63
+
64
+ Please note that using the [] method will NOT evaluate paths, just
65
+ access labels in the CURRENT struct (which is actually a hash).
66
+
67
+ === Creating new GFF Structs and Elements
68
+
69
+ You can add new fields to existing structs via NWN::Gff::Struct#add_field:
70
+
71
+ gff.add_field 'LocalVersion', :int, 1
72
+
73
+ # This will print "1"
74
+ log (gff / 'LocalVersion$')
75
+
76
+ You can also the dynamic methods to save some typing:
77
+
78
+ gff.add_int 'LocalVersion', 1
79
+
80
+ You can just as well create whole GFF structures on the fly:
81
+
82
+ Gff::Struct.new do |s|
83
+ s.add_byte 'ImaByte', :int, 1
84
+ list = s.add_list 'ImaList', [] do |l|
85
+ l.add_struct(1) do |ss|
86
+ ss.add_byte 'ImaByteToo', 2
87
+ end
88
+ end
89
+ end
90
+
91
+ Further reading: NWN::Gff::Struct#add_field, NWN::Gff::List#add_struct.
92
+
93
+ === Working with .2da files
94
+
95
+ Working with TwoDA files is easy and painless:
96
+
97
+ #!/usr/bin/env nwn-dsl
98
+
99
+ data = IO.read('path/to/baseitems.2da')
100
+ table = TwoDA::Table.parse(data)
101
+
102
+ # This will print "twobladedsword" with NWN1 1.69
103
+ log table[12].Label
104
+
105
+ # You can re-format (and save) any valid table:
106
+ File.open("/tmp/out", "wb") {|f|
107
+ f.write(table.to_2da)
108
+ # OR
109
+ table.write_to(f)
110
+ }
111
+
112
+ For more documentation, see NWN::TwoDA::Table and
113
+ NWN::TwoDA::Row.
114
+
115
+ You can also set up a default location for 2da files,
116
+ after which you can simply use the following to read
117
+ 2da files:
118
+
119
+ table = TwoDA.get('baseitems')
120
+
121
+ You can set up the TwoDA::Cache by either setting the
122
+ environment variable (recommended, see SETTINGS), or
123
+ like this (see NWN::TwoDA::Cache.setup):
124
+
125
+ TwoDA::Cache.setup("path_a:path_b/blah:path_c")
126
+
127
+ === Accessing .tlk data
128
+
129
+ You can access individual .tlk files, or use a TlkSet,
130
+ which will emulate the way NWN1/2 reads it's .tlk files.
131
+
132
+ Read a simple .tlk file:
133
+
134
+ io = File.open("/path/to/dialog.tlk", "rb")
135
+ tlk = NWN::Tlk::Tlk.new(io)
136
+
137
+ Note that Tlk::Tlk seeks and reads from +io+ as needed,
138
+ so if you close the file handle, any further accesses
139
+ will fail.
140
+
141
+ # Retrieve strref 12
142
+ tlk[12][:text]
143
+
144
+ # Retrieve the attached sound resref, if any:
145
+ tlk[12][:sound]
146
+
147
+ # prints the highest strref used
148
+ log tlk.highest_id
149
+
150
+ # Add a new strrref.
151
+ new_strref = tlk.add 'New text'
152
+
153
+ # And save the new TLK somewhere else.
154
+ File.open("/tmp/new.tlk", "wb") {|another_io|
155
+ tlk.write_to(another_io)
156
+ }
157
+
158
+ Now read-only access with a TlkSet:
159
+
160
+ # The arguments are dialog.tlk, dialogf.tlk,
161
+ # custom.tlk and a customf.tlk each wrapped in
162
+ # a Tlk::Tlk as shown above.
163
+ set = Tlk::TlkSet.new(tlk, tlkf, custom, customf)
164
+
165
+ # Retrieve str_ref 12 as the female variant (dialogf.tlk)
166
+ # if present, :male otherwise.
167
+ log set[12, :female]
168
+
169
+ You cannot use TlkSet to write out .tlk files or modify
170
+ existing entries - it is merely a wrapper.
data/README CHANGED
@@ -50,7 +50,7 @@ And do the following in a script of your own devising:
50
50
  require 'rubygems'
51
51
  require 'nwn/all'
52
52
 
53
- Also, Read BINARIES.
53
+ Also, read BINARIES and HOWTO.
54
54
 
55
55
  For nwn-lib scripts, see SCRIPTING.
56
56
 
data/Rakefile CHANGED
@@ -9,13 +9,13 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "nwn-lib"
12
- VERS = "0.4.8"
12
+ VERS = "0.4.9"
13
13
  CLEAN.include ["**/.*.sw?", "pkg", ".config", "rdoc", "coverage"]
14
14
  RDOC_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', \
15
15
  'nwn-lib: a ruby library for accessing NWN resource files', \
16
16
  '--main', 'README']
17
17
 
18
- DOCS = ["README", "BINARIES", "SCRIPTING", "SETTINGS", "CHEATSHEET", "CHANGELOG", "COPYING"]
18
+ DOCS = ["README", "BINARIES", "HOWTO", "SCRIPTING", "SETTINGS", "CHEATSHEET", "CHANGELOG", "COPYING"]
19
19
 
20
20
  Rake::RDocTask.new do |rdoc|
21
21
  rdoc.rdoc_dir = "rdoc"
@@ -66,7 +66,7 @@ begin OptionParser.new do |o|
66
66
  o.on "-0", "Create (only -c) V1.0 ERF, 16 byte resrefs. (NWN1, default)" do
67
67
  $version = "V1.0"
68
68
  end
69
- o.on "-1", "Create (only -c) V1.0 ERF, 32 byte resrefs. (NWN2)." do
69
+ o.on "-1", "Create (only -c) V1.1 ERF, 32 byte resrefs. (NWN2)." do
70
70
  $version = "V1.1"
71
71
  end
72
72
 
@@ -29,7 +29,7 @@ def read file
29
29
  file = File.expand_path(file || $file)
30
30
  $stderr.puts "Reading `#{file}' .."
31
31
  fmt = NWN::Gff.guess_file_format(file)
32
- $gff = NWN::Gff.read(IO.read(file), fmt)
32
+ $gff = NWN::Gff.read(File.open(file, "rb"), fmt)
33
33
 
34
34
  $stderr.puts "Your GFF file is in `$gff' (data_type: #{$gff.data_type.inspect})."
35
35
  $stderr.puts "Type `save' to save to the filename it came from (make a backup!), `exit' (or Ctrl+D) to exit (without saving)."
@@ -116,4 +116,3 @@ require 'nwn/gff/list'
116
116
  require 'nwn/gff/cexolocstr'
117
117
  require 'nwn/gff/reader'
118
118
  require 'nwn/gff/writer'
119
- require 'nwn/gff/api'
@@ -158,4 +158,36 @@ module NWN::Gff::Field
158
158
  false
159
159
  end
160
160
  end
161
+
162
+ #:stopdoc:
163
+ # Used by NWN::Gff::Struct#by_flat_path
164
+ def each_by_flat_path &block
165
+ case field_type
166
+ when :cexolocstr
167
+ yield("", self)
168
+ field_value.sort.each {|lid, str|
169
+ yield("/" + lid.to_s, str)
170
+ }
171
+
172
+ when :struct
173
+ yield("", self)
174
+ field_value.each_by_flat_path {|v, x|
175
+ yield(v, x)
176
+ }
177
+
178
+ when :list
179
+ yield("", self)
180
+ field_value.each_with_index {|item, index|
181
+ yield("[" + index.to_s + "]", item)
182
+ item.each_by_flat_path("/") {|v, x|
183
+ yield("[" + index.to_s + "]" + v, x)
184
+ }
185
+ }
186
+
187
+ else
188
+ yield("", self)
189
+ end
190
+ end
191
+ #:startdoc:
192
+
161
193
  end
@@ -67,7 +67,7 @@ class NWN::Gff::Reader
67
67
 
68
68
  # This iterates through a struct and reads all fields into a hash, which it returns.
69
69
  def read_struct index, file_type = nil, file_version = nil
70
- struct = {}.taint
70
+ struct = {}
71
71
  struct.extend(NWN::Gff::Struct)
72
72
 
73
73
  type = @structs[index * 3]
@@ -101,9 +101,7 @@ class NWN::Gff::Reader
101
101
 
102
102
  # Reads the field at +index+ and returns [label_name, Gff::Field]
103
103
  def read_field index, parent_of
104
- gff = {}
105
-
106
- field = {}.taint
104
+ field = {}
107
105
  field.extend(NWN::Gff::Field)
108
106
 
109
107
  index *= 3
@@ -184,7 +182,7 @@ class NWN::Gff::Reader
184
182
  len = total_size + 4
185
183
  # Filter out empty strings.
186
184
  exostr.reject! {|k,v| v.nil? || v.empty?}
187
- exostr.taint
185
+ exostr
188
186
 
189
187
  when :void
190
188
  len = @field_data[data_or_offset, 4].unpack("V")[0]
@@ -215,7 +213,7 @@ class NWN::Gff::Reader
215
213
  list << read_struct(@list_indices[i], field.path, field.parent.data_version)
216
214
  end
217
215
 
218
- list.taint
216
+ list
219
217
 
220
218
  end
221
219
 
@@ -226,7 +224,7 @@ class NWN::Gff::Reader
226
224
  [value].compact.flatten.each {|iv|
227
225
  iv.element = field if iv.respond_to?('element=')
228
226
  }
229
- field['value'] = value.taint
227
+ field['value'] = value
230
228
 
231
229
  # We extend all fields and field_values with matching classes.
232
230
  field.extend_meta_classes
@@ -104,4 +104,100 @@ module NWN::Gff::Struct
104
104
  def to_s
105
105
  "<NWN::Gff::Struct #{self.data_type}/#{self.data_version}, #{self.keys.size} fields>"
106
106
  end
107
+
108
+
109
+ # Iterates this struct, yielding flat, absolute
110
+ # paths and the Gff::Field for each element found.
111
+
112
+ # Example:
113
+ # "/AddCost" => {"type"=>:dword, ..}
114
+ def each_by_flat_path prefix = "/", &block
115
+ sort.each {|label, field|
116
+ field.each_by_flat_path do |ll, lv|
117
+ yield(prefix + label + ll, lv)
118
+ end
119
+ }
120
+ end
121
+
122
+ # Retrieve an object from within the given tree.
123
+ # Path is a slash-separated destination, given as
124
+ # a string
125
+ #
126
+ # Prefixed/postfixed slashes are optional.
127
+ #
128
+ # You can retrieve CExoLocString values by giving the
129
+ # language ID as the last label:
130
+ # /FirstName/0
131
+ #
132
+ # You can retrieve list values by specifying the index
133
+ # in square brackets:
134
+ # /SkillList[0]
135
+ # /SkillList[0]/Rank => {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}
136
+ #
137
+ # You can directly retrieve field values and types
138
+ # instead of the field itself:
139
+ # /SkillList[0]/Rank$ => 0
140
+ # /SkillList[0]/Rank? => :byte
141
+ #
142
+ # This will raise an error for non-field paths, naturally:
143
+ # SkillList[0]$ => undefined method `field_value' for {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}:Hash
144
+ # SkillList[0]? => undefined method `field_type' for {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}:Hash
145
+ #
146
+ # For CExoLocStrings, you can retrieve the str_ref:
147
+ # FirstName% => 4294967295
148
+ # This will return DEFAULT_STR_REF (0xffffffff) if the given path does not have
149
+ # a str_ref.
150
+ def by_path path
151
+ struct = self
152
+ current_path = ""
153
+ path = path.split('/').map {|v| v.strip }.reject {|v| v.empty?}.join('/')
154
+
155
+ path, mod = $1, $2 if path =~ /^(.+?)([\$\?%])?$/
156
+
157
+ path.split('/').each_with_index {|v, path_index|
158
+ if struct.is_a?(NWN::Gff::Field) && struct.field_type == :cexolocstr &&
159
+ v =~ /^\d+$/ && path_index == path.split('/').size - 1
160
+ struct = struct.field_value[v.to_i]
161
+ break
162
+ end
163
+
164
+ v, index = $1, $2 if v =~ /^(.+?)\[(\d+)\]$/
165
+
166
+ struct = struct.v if struct.is_a?(NWN::Gff::Field) &&
167
+ struct.field_type == :struct
168
+
169
+ struct = struct[v]
170
+ if index
171
+ struct.field_type == :list or raise NWN::Gff::GffPathInvalidError,
172
+ "Specified a list offset for a non-list item: #{v}[#{index}]."
173
+
174
+ struct = struct.field_value[index.to_i]
175
+ end
176
+
177
+
178
+ raise NWN::Gff::GffPathInvalidError,
179
+ "Cannot find a path to /#{path} (at: #{current_path})." unless struct
180
+
181
+ current_path += "/" + v
182
+ current_path += "[#{index}]" if index
183
+ }
184
+
185
+ case mod
186
+ when "$"
187
+ struct.field_value
188
+ when "?"
189
+ struct.field_type
190
+ when "%"
191
+ struct.has_str_ref? ? struct.str_ref :
192
+ NWN::Gff::Cexolocstr::DEFAULT_STR_REF
193
+ else
194
+ struct
195
+ end
196
+ end
197
+
198
+ # An alias for +by_path+.
199
+ def / path
200
+ by_path(path)
201
+ end
202
+
107
203
  end
@@ -3,7 +3,7 @@
3
3
  # Include this if you want to eval nwn-gff-dsl scripts.
4
4
  module NWN::Gff::Scripting
5
5
 
6
- class Sandbox
6
+ class Sandbox #:nodoc:
7
7
  include NWN
8
8
  include NWN::Gff::Scripting
9
9
  end
@@ -99,11 +99,13 @@ module NWN::Gff::Scripting
99
99
  # If only a filename/string is given and no further arguments,
100
100
  # the read object will be returned as-is.
101
101
  def satisfy *what
102
+ close_me = false
102
103
  if $standalone
103
104
  fn = what.shift
104
105
  io = case fn
105
106
  when String
106
- File.new(fn, "r")
107
+ close_me = true
108
+ File.new(fn, "rb")
107
109
  when IO
108
110
  fn
109
111
  else
@@ -112,7 +114,12 @@ module NWN::Gff::Scripting
112
114
  # "`need', `want' and `satisfy' need a filename or a IO " +
113
115
  # "object to read from (usually the first script argument)."
114
116
  end
115
- obj = NWN::Gff.read(io, NWN::Gff.guess_file_format(fn))
117
+
118
+ obj = begin
119
+ NWN::Gff.read(io, NWN::Gff.guess_file_format(fn))
120
+ ensure
121
+ io.close if close_me
122
+ end
116
123
  log "satisfied #{fn} -> #{obj.to_s}"
117
124
  $satisfy_loaded[obj.object_id] = [fn, obj.hash]
118
125
 
@@ -132,7 +132,7 @@ module NWN
132
132
  data.each_with_index {|row, idx|
133
133
  id = row.shift
134
134
 
135
- NWN.log_debug "Warning: invalid ID in line #{idx}: #{id.inspect}" if $id !~ /^\d+$/
135
+ NWN.log_debug "Warning: invalid ID in line #{idx}: #{id.inspect}" if id !~ /^\d+$/
136
136
 
137
137
  id = id.to_i + id_offset
138
138
 
@@ -310,7 +310,7 @@ module NWN
310
310
 
311
311
  # Set the file system path spec where all 2da files reside.
312
312
  # Call this on application startup.
313
- # path spec is a colon-separated list of pathes, just like $PATH.
313
+ # path spec is a colon-separated list of paths, just like $PATH.
314
314
  def self.setup root_directories
315
315
  @_roots = root_directories.split(':').compact.reject {|x| "" == x.strip }
316
316
  end
@@ -74,7 +74,7 @@ end
74
74
 
75
75
  # This parses the struct and extends all fields with their proper type.
76
76
  YAML.add_domain_type(NWN::YAML_DOMAIN,'struct') {|t,hash|
77
- struct = {}.taint
77
+ struct = {}
78
78
  struct.extend(NWN::Gff::Struct)
79
79
 
80
80
  # The metadata
@@ -96,7 +96,7 @@ YAML.add_domain_type(NWN::YAML_DOMAIN,'struct') {|t,hash|
96
96
  element.extend_meta_classes
97
97
  element.validate
98
98
 
99
- struct[label] = element.taint
99
+ struct[label] = element
100
100
  }
101
101
 
102
102
  struct
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nwn-lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: 0.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernhard Stoeckner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-30 00:00:00 +02:00
12
+ date: 2009-07-19 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -25,6 +25,7 @@ extensions: []
25
25
  extra_rdoc_files:
26
26
  - README
27
27
  - BINARIES
28
+ - HOWTO
28
29
  - SCRIPTING
29
30
  - SETTINGS
30
31
  - CHEATSHEET
@@ -35,51 +36,51 @@ files:
35
36
  - CHANGELOG
36
37
  - README
37
38
  - Rakefile
38
- - bin/nwn-gff
39
39
  - bin/nwn-dsl
40
- - bin/nwn-erf
40
+ - bin/nwn-gff
41
41
  - bin/nwn-irb
42
- - spec/bin_dsl_spec.rb
42
+ - bin/nwn-erf
43
+ - spec/wellformed_gff.bic
43
44
  - spec/gff_spec.rb
44
- - spec/bin_gff_spec.rb
45
- - spec/bin_erf_spec.rb
45
+ - spec/res_spec.rb
46
+ - spec/spec.opts
47
+ - spec/erf_spec.rb
46
48
  - spec/field_spec.rb
47
49
  - spec/cexolocstr_spec.rb
48
- - spec/erf_spec.rb
49
50
  - spec/struct_spec.rb
50
- - spec/spec.opts
51
- - spec/res_spec.rb
51
+ - spec/spec_helper.rb
52
52
  - spec/tlk_spec.rb
53
+ - spec/bin_dsl_spec.rb
54
+ - spec/bin_gff_spec.rb
53
55
  - spec/rcov.opts
56
+ - spec/bin_erf_spec.rb
54
57
  - spec/twoda_spec.rb
55
- - spec/spec_helper.rb
56
- - spec/wellformed_gff.bic
57
- - lib/nwn/erf.rb
58
- - lib/nwn/io.rb
59
- - lib/nwn/settings.rb
58
+ - lib/nwn/scripting.rb
60
59
  - lib/nwn/yaml.rb
61
- - lib/nwn/all.rb
62
- - lib/nwn/res.rb
63
60
  - lib/nwn/twoda.rb
64
- - lib/nwn/tlk.rb
61
+ - lib/nwn/erf.rb
62
+ - lib/nwn/settings.rb
65
63
  - lib/nwn/gff.rb
64
+ - lib/nwn/tlk.rb
65
+ - lib/nwn/io.rb
66
+ - lib/nwn/res.rb
66
67
  - lib/nwn/kivinen.rb
67
- - lib/nwn/scripting.rb
68
- - lib/nwn/gff/api.rb
69
- - lib/nwn/gff/writer.rb
70
- - lib/nwn/gff/struct.rb
71
- - lib/nwn/gff/list.rb
68
+ - lib/nwn/all.rb
69
+ - lib/nwn/gff/field.rb
72
70
  - lib/nwn/gff/reader.rb
73
71
  - lib/nwn/gff/cexolocstr.rb
74
- - lib/nwn/gff/field.rb
72
+ - lib/nwn/gff/struct.rb
73
+ - lib/nwn/gff/list.rb
74
+ - lib/nwn/gff/writer.rb
75
75
  - tools/verify.sh
76
76
  - tools/migrate_03x_to_04x.sh
77
77
  - scripts/truncate_floats.rb
78
+ - scripts/reformat_2da
78
79
  - scripts/clean_locstrs.rb
79
- - scripts/debug_check_objid.rb
80
80
  - scripts/extract_all_items.rb
81
- - scripts/reformat_2da
81
+ - scripts/debug_check_objid.rb
82
82
  - BINARIES
83
+ - HOWTO
83
84
  - SCRIPTING
84
85
  - SETTINGS
85
86
  - CHEATSHEET
@@ -1,88 +0,0 @@
1
-
2
- module NWN::Gff::Field
3
- #:stopdoc:
4
- # Used by NWN::Gff::Struct#by_flat_path
5
- def each_by_flat_path &block
6
- case field_type
7
- when :cexolocstr
8
- yield("", self)
9
- field_value.sort.each {|lid, str|
10
- yield("/" + lid.to_s, str)
11
- }
12
-
13
- when :struct
14
- yield("", self)
15
- field_value.each_by_flat_path {|v, x|
16
- yield(v, x)
17
- }
18
-
19
- when :list
20
- yield("", self)
21
- field_value.each_with_index {|item, index|
22
- yield("[" + index.to_s + "]", item)
23
- item.each_by_flat_path("/") {|v, x|
24
- yield("[" + index.to_s + "]" + v, x)
25
- }
26
- }
27
-
28
- else
29
- yield("", self)
30
- end
31
- end
32
- #:startdoc:
33
- end
34
-
35
- module NWN::Gff::Struct
36
-
37
- # Iterates this struct, yielding flat, absolute
38
- # pathes and the Gff::Field for each element found.
39
-
40
- # Example:
41
- # "/AddCost" => {"type"=>:dword, ..}
42
- def each_by_flat_path prefix = "/", &block
43
- sort.each {|label, field|
44
- field.each_by_flat_path do |ll, lv|
45
- yield(prefix + label + ll, lv)
46
- end
47
- }
48
- end
49
-
50
- # Retrieve an object from within the given tree.
51
- # Path is a slash-separated destination, given as
52
- # a string
53
- #
54
- # Prefixed/postfixed slashes are optional.
55
- #
56
- # Examples:
57
- # /
58
- # /AddCost
59
- # /PropertiesList/
60
- # /PropertiesList[0]/CostValue
61
- def by_path path
62
- struct = self
63
- current_path = ""
64
- path = path.split('/').map {|v| v.strip }.reject {|v| v.empty?}.join('/')
65
-
66
- path.split('/').each {|v|
67
- if v =~ /^(.+?)\[(\d+)\]$/
68
- v, index = $1, $2
69
- end
70
-
71
- struct = struct[v]
72
- if index
73
- struct.field_type == :list or raise NWN::Gff::GffPathInvalidError,
74
- "Specified a list offset for a non-list item: #{v}[#{index}]."
75
-
76
- struct = struct.field_value[index.to_i]
77
- end
78
-
79
- raise NWN::Gff::GffPathInvalidError,
80
- "Cannot find a path to /#{path} (at: /#{current_path})." unless struct
81
-
82
- current_path += v
83
- }
84
-
85
- struct
86
- end
87
-
88
- end