nwn-lib 0.4.8 → 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +18 -0
- data/COPYING +1 -1
- data/HOWTO +170 -0
- data/README +1 -1
- data/Rakefile +2 -2
- data/bin/nwn-erf +1 -1
- data/bin/nwn-irb +1 -1
- data/lib/nwn/gff.rb +0 -1
- data/lib/nwn/gff/field.rb +32 -0
- data/lib/nwn/gff/reader.rb +5 -7
- data/lib/nwn/gff/struct.rb +96 -0
- data/lib/nwn/scripting.rb +10 -3
- data/lib/nwn/twoda.rb +2 -2
- data/lib/nwn/yaml.rb +2 -2
- metadata +27 -26
- data/lib/nwn/gff/api.rb +0 -88
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
data/Rakefile
CHANGED
@@ -9,13 +9,13 @@ include FileUtils
|
|
9
9
|
# Configuration
|
10
10
|
##############################################################################
|
11
11
|
NAME = "nwn-lib"
|
12
|
-
VERS = "0.4.
|
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"
|
data/bin/nwn-erf
CHANGED
@@ -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.
|
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
|
|
data/bin/nwn-irb
CHANGED
@@ -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(
|
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)."
|
data/lib/nwn/gff.rb
CHANGED
data/lib/nwn/gff/field.rb
CHANGED
@@ -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
|
data/lib/nwn/gff/reader.rb
CHANGED
@@ -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 = {}
|
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
|
-
|
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
|
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
|
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
|
227
|
+
field['value'] = value
|
230
228
|
|
231
229
|
# We extend all fields and field_values with matching classes.
|
232
230
|
field.extend_meta_classes
|
data/lib/nwn/gff/struct.rb
CHANGED
@@ -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
|
data/lib/nwn/scripting.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
|
data/lib/nwn/twoda.rb
CHANGED
@@ -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
|
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
|
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
|
data/lib/nwn/yaml.rb
CHANGED
@@ -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 = {}
|
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
|
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.
|
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-
|
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-
|
40
|
+
- bin/nwn-gff
|
41
41
|
- bin/nwn-irb
|
42
|
-
-
|
42
|
+
- bin/nwn-erf
|
43
|
+
- spec/wellformed_gff.bic
|
43
44
|
- spec/gff_spec.rb
|
44
|
-
- spec/
|
45
|
-
- spec/
|
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/
|
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
|
-
-
|
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/
|
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/
|
68
|
-
- lib/nwn/gff/
|
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/
|
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/
|
81
|
+
- scripts/debug_check_objid.rb
|
82
82
|
- BINARIES
|
83
|
+
- HOWTO
|
83
84
|
- SCRIPTING
|
84
85
|
- SETTINGS
|
85
86
|
- CHEATSHEET
|
data/lib/nwn/gff/api.rb
DELETED
@@ -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
|