nwn-lib 0.3.6 → 0.4.0
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/BINARIES +40 -45
- data/CHANGELOG +4 -0
- data/CHEATSHEET +7 -73
- data/COPYING +1 -1
- data/DATA_STRUCTURES +50 -0
- data/README +27 -37
- data/Rakefile +7 -5
- data/SCRIPTING +44 -0
- data/SETTINGS +80 -0
- data/TYPE_VALUE_INFERRING +93 -0
- data/bin/nwn-dsl +28 -0
- data/bin/nwn-gff +192 -0
- data/bin/nwn-irb +51 -0
- data/data/gff-common-nwn1.yaml +982 -0
- data/lib/nwn/all.rb +7 -0
- data/lib/nwn/gff.rb +47 -861
- data/lib/nwn/gff/api.rb +88 -0
- data/lib/nwn/gff/cexolocstr.rb +28 -0
- data/lib/nwn/gff/field.rb +105 -0
- data/lib/nwn/gff/list.rb +2 -0
- data/lib/nwn/gff/reader.rb +220 -0
- data/lib/nwn/gff/struct.rb +34 -0
- data/lib/nwn/gff/writer.rb +201 -0
- data/lib/nwn/helpers.rb +1 -30
- data/lib/nwn/infer.rb +125 -0
- data/lib/nwn/kivinen.rb +55 -0
- data/lib/nwn/scripting.rb +129 -0
- data/lib/nwn/settings.rb +7 -0
- data/lib/nwn/twoda.rb +105 -7
- data/lib/nwn/yaml.rb +276 -5
- data/scripts/clean_locstrs.rb +46 -0
- data/scripts/extract_all_items.rb +19 -0
- data/scripts/fix_facings.rb +22 -0
- data/scripts/truncate_floats.rb +18 -0
- data/tools/migrate_03x_to_04x.sh +17 -0
- data/tools/verify.sh +35 -0
- metadata +36 -8
- data/bin/nwn-gff-import +0 -69
- data/bin/nwn-gff-irb +0 -62
- data/bin/nwn-gff-print +0 -133
@@ -0,0 +1,201 @@
|
|
1
|
+
class NWN::Gff::Writer
|
2
|
+
include NWN
|
3
|
+
include NWN::Gff
|
4
|
+
|
5
|
+
attr_reader :bytes
|
6
|
+
|
7
|
+
def initialize(gff, data_type = nil)
|
8
|
+
@gff = gff
|
9
|
+
@data_type = data_type
|
10
|
+
|
11
|
+
@structs = []
|
12
|
+
@fields = []
|
13
|
+
@labels = []
|
14
|
+
@field_indices = []
|
15
|
+
@list_indices = []
|
16
|
+
@field_data = ""
|
17
|
+
|
18
|
+
write_all
|
19
|
+
end
|
20
|
+
|
21
|
+
# Takes a NWN::Gff::Gff object and dumps it as raw bytes,
|
22
|
+
# including the header.
|
23
|
+
def self.dump(gff, data_type = nil)
|
24
|
+
self.new(gff, data_type).bytes
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def get_label_id_for_label str
|
30
|
+
@labels << str unless @labels.index(str)
|
31
|
+
@labels.index(str)
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_data_field type, label, content
|
35
|
+
label_id = get_label_id_for_label label
|
36
|
+
@fields.push Types.index(type), label_id, content
|
37
|
+
(@fields.size - 1) / 3
|
38
|
+
end
|
39
|
+
|
40
|
+
def write_all
|
41
|
+
data = []
|
42
|
+
write_struct @gff
|
43
|
+
|
44
|
+
c_offset = 0
|
45
|
+
data << [
|
46
|
+
@data_type || @gff.data_type,
|
47
|
+
@gff.data_version,
|
48
|
+
|
49
|
+
# Offset of Struct array as bytes from the beginning of the file
|
50
|
+
c_offset += 56,
|
51
|
+
# Number of elements in Struct array
|
52
|
+
@structs.size / 3,
|
53
|
+
|
54
|
+
# Offset of Field array as bytes from the beginning of the file
|
55
|
+
fields_start = c_offset += @structs.size / 3 * 12,
|
56
|
+
# Number of elements in Field array
|
57
|
+
@fields.size / 3,
|
58
|
+
|
59
|
+
# Offset of Label array as bytes from the beginning of the file
|
60
|
+
c_offset += @fields.size / 3 * 12,
|
61
|
+
# Number of elements in Label array
|
62
|
+
@labels.size,
|
63
|
+
|
64
|
+
# Offset of Field Data as bytes from the beginning of the file
|
65
|
+
c_offset += @labels.size * 16,
|
66
|
+
# Number of bytes in Field Data block
|
67
|
+
@field_data.size,
|
68
|
+
|
69
|
+
# Offset of Field Indices array as bytes from the beginning of the file
|
70
|
+
c_offset += @field_data.size,
|
71
|
+
# Number of bytes in Field Indices array
|
72
|
+
@field_indices.size * 4,
|
73
|
+
|
74
|
+
# Offset of List Indices array as bytes from the beginning of the file
|
75
|
+
c_offset += @field_indices.size * 4,
|
76
|
+
# Number of bytes in List Indices array
|
77
|
+
@list_indices.size * 4
|
78
|
+
|
79
|
+
].pack("A4a4 VV VV VV VV VV VV")
|
80
|
+
|
81
|
+
data << @structs.pack("V*")
|
82
|
+
data << @fields.pack("V*")
|
83
|
+
data << @labels.pack("a16" * @labels.size)
|
84
|
+
data << @field_data
|
85
|
+
data << @field_indices.pack("V*")
|
86
|
+
data << @list_indices.pack("V*")
|
87
|
+
|
88
|
+
@bytes = data.join("")
|
89
|
+
end
|
90
|
+
|
91
|
+
def write_struct struct
|
92
|
+
raise GffError, "struct invalid: #{struct.inspect}" unless struct.is_a?(NWN::Gff::Struct)
|
93
|
+
raise GffError, "struct_id missing from struct" unless struct.struct_id
|
94
|
+
|
95
|
+
# This holds all field label ids this struct has as a member
|
96
|
+
fields_of_this_struct = []
|
97
|
+
|
98
|
+
# This will hold the index of this struct
|
99
|
+
index = @structs.size / 3
|
100
|
+
|
101
|
+
@structs.push struct.struct_id, 0, 0
|
102
|
+
|
103
|
+
struct.sort.each {|k,v|
|
104
|
+
raise GffError, "Empty label." if !k || k == ""
|
105
|
+
|
106
|
+
case v.field_type
|
107
|
+
# simple data types
|
108
|
+
when :byte, :char, :word, :short, :dword, :int, :float
|
109
|
+
format = Formats[v.field_type]
|
110
|
+
fields_of_this_struct << add_data_field(v.field_type, k, [v.field_value].pack(format).unpack("V")[0])
|
111
|
+
|
112
|
+
# complex data types
|
113
|
+
when :dword64, :int64, :double, :void
|
114
|
+
fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size)
|
115
|
+
format = Formats[v.field_type]
|
116
|
+
@field_data << case v.field_type
|
117
|
+
when :dword64
|
118
|
+
[
|
119
|
+
( v.field_value / (2**32) ) & 0xffffffff,
|
120
|
+
v.field_value % (2**32)
|
121
|
+
].pack("II")
|
122
|
+
when :void
|
123
|
+
[ v.field_value.size / 2, v.field_value ].pack("VH*")
|
124
|
+
else
|
125
|
+
[v.field_value].pack(format)
|
126
|
+
end
|
127
|
+
|
128
|
+
when :struct
|
129
|
+
raise GffError, "type = struct, but value not a hash" unless
|
130
|
+
v.field_value.is_a?(Gff::Struct)
|
131
|
+
|
132
|
+
fields_of_this_struct << add_data_field(v.field_type, k, write_struct(v.field_value))
|
133
|
+
|
134
|
+
when :list
|
135
|
+
raise GffError, "type = list, but value not an array" unless
|
136
|
+
v.field_value.is_a?(Array)
|
137
|
+
|
138
|
+
fields_of_this_struct << add_data_field(v.field_type, k, 4 * @list_indices.size)
|
139
|
+
|
140
|
+
count = v.field_value.size
|
141
|
+
tmp = @list_indices.size
|
142
|
+
@list_indices << count
|
143
|
+
count.times {
|
144
|
+
@list_indices << 0
|
145
|
+
}
|
146
|
+
|
147
|
+
v.field_value.each_with_index do |kk, idx|
|
148
|
+
vv = write_struct(kk)
|
149
|
+
@list_indices[ idx + tmp + 1 ] = vv
|
150
|
+
end
|
151
|
+
|
152
|
+
when :resref
|
153
|
+
fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size)
|
154
|
+
@field_data << [v.field_value.size, v.field_value].pack("Ca*")
|
155
|
+
|
156
|
+
when :cexostr
|
157
|
+
fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size)
|
158
|
+
@field_data << [v.field_value.size, v.field_value].pack("Va*")
|
159
|
+
|
160
|
+
when :cexolocstr
|
161
|
+
raise GffError, "type = cexolocstr, but value not a hash (#{v.field_value.class})" unless
|
162
|
+
v.field_value.is_a?(Hash)
|
163
|
+
|
164
|
+
fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size)
|
165
|
+
|
166
|
+
# total size (4), str_ref (4), str_count (4)
|
167
|
+
total_size = 8
|
168
|
+
v.field_value.each {|kk,vv|
|
169
|
+
total_size += vv.size + 8
|
170
|
+
}
|
171
|
+
@field_data << [
|
172
|
+
total_size,
|
173
|
+
v.str_ref,
|
174
|
+
v.field_value.size
|
175
|
+
].pack("VVV")
|
176
|
+
|
177
|
+
v.field_value.each {|k,v|
|
178
|
+
@field_data << [k, v.size, v].pack("VVa*")
|
179
|
+
}
|
180
|
+
|
181
|
+
else
|
182
|
+
raise GffError, "Unknown data type: #{v.field_type}"
|
183
|
+
end
|
184
|
+
}
|
185
|
+
|
186
|
+
# id/type, data_or_offset, nr_of_fields
|
187
|
+
@structs[3 * (index) + 2] = fields_of_this_struct.size
|
188
|
+
|
189
|
+
if fields_of_this_struct.size < 1
|
190
|
+
elsif fields_of_this_struct.size == 1
|
191
|
+
@structs[3 * (index) + 1] = fields_of_this_struct[0]
|
192
|
+
else
|
193
|
+
# Offset into field_indices starting where are number of nr_of_fields
|
194
|
+
# dwords as indexes into @fields
|
195
|
+
@structs[3 * (index) + 1] = 4 * (@field_indices.size)
|
196
|
+
@field_indices.push *fields_of_this_struct
|
197
|
+
end
|
198
|
+
|
199
|
+
index
|
200
|
+
end
|
201
|
+
end
|
data/lib/nwn/helpers.rb
CHANGED
@@ -2,38 +2,9 @@ require 'nwn/gff'
|
|
2
2
|
require 'nwn/twoda'
|
3
3
|
|
4
4
|
module NWN
|
5
|
-
|
6
|
-
module TwoDA
|
7
|
-
|
8
|
-
# This is a simple 2da cache.
|
9
|
-
module Cache
|
10
|
-
|
11
|
-
@_cache = {}
|
12
|
-
@_root = nil
|
13
|
-
|
14
|
-
# Set the file system path where all 2da files reside.
|
15
|
-
# Call this on application startup.
|
16
|
-
def self.setup root
|
17
|
-
@_root = root
|
18
|
-
end
|
19
|
-
|
20
|
-
# Get the 2da file with the given name. +name+ is without extension.
|
21
|
-
def self.get(name)
|
22
|
-
raise Exception, "You need to set up the cache first through Cache.setup." unless @_root
|
23
|
-
@_cache[name.downcase] ||= read_2da(name.downcase)
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.read_2da name # :nodoc:
|
27
|
-
Table.parse IO.read(@_root + '/' + name + '.2da')
|
28
|
-
end
|
29
|
-
|
30
|
-
private_class_method :read_2da
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
5
|
module Gff
|
35
|
-
module Helpers
|
36
6
|
|
7
|
+
module Helpers
|
37
8
|
# This sets up the IPRP cache. Used internally; no need to call this yourself.
|
38
9
|
def self._ip_cache_setup #:nodoc:
|
39
10
|
return if defined? @costtables
|
data/lib/nwn/infer.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
module NWN::Gff
|
2
|
+
@YAMLStructDefaults = {}
|
3
|
+
|
4
|
+
#:stopdoc:
|
5
|
+
# This gets called for each parsed struct to set their container element
|
6
|
+
# values (see also gff/reader.rb, line 233-ish).
|
7
|
+
def self.__yaml_postparse parent, struct
|
8
|
+
struct.each {|label,element|
|
9
|
+
case element.field_type
|
10
|
+
when :list, :struct
|
11
|
+
[element.field_value].flatten.each {|item|
|
12
|
+
__yaml_postparse(element, item)
|
13
|
+
item.element = element
|
14
|
+
}
|
15
|
+
end
|
16
|
+
}
|
17
|
+
end
|
18
|
+
#:startdoc:
|
19
|
+
|
20
|
+
# This loads structs defaults from the given file, which will
|
21
|
+
# be used for field_type inferring and autocompletion/filtering of default values.
|
22
|
+
# A sample file has been provided with nwn-lib, called gff-bioware.yml
|
23
|
+
def self.load_struct_defaults file
|
24
|
+
@YAMLStructDefaults = YAML.load(IO.read(file))
|
25
|
+
new = {}
|
26
|
+
@YAMLStructDefaults.each {|k,v|
|
27
|
+
new[Regexp.new(k + '$')] = v
|
28
|
+
}
|
29
|
+
@YAMLStructDefaults = new
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.get_struct_defaults
|
33
|
+
@YAMLStructDefaults || {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.get_struct_defaults_for path, key
|
37
|
+
sd = NWN::Gff.get_struct_defaults
|
38
|
+
sd.keys.each {|rx|
|
39
|
+
next unless path =~ rx
|
40
|
+
return sd[rx][key] if sd[rx][key] != nil
|
41
|
+
}
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.get_struct_default_type path, key
|
46
|
+
dd = get_struct_defaults_for(path, key)
|
47
|
+
dd.is_a?(Array) ? dd[0] : dd
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.get_struct_default_value path, key
|
51
|
+
dd = get_struct_defaults_for(path, key)
|
52
|
+
dd.is_a?(Array) ? dd[1] : nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module NWN::Gff::Struct
|
57
|
+
# Returns true if we can later infer the struct_id with the given path.
|
58
|
+
def can_infer_struct_id?
|
59
|
+
v = NWN::Gff.get_struct_defaults_for(self.path, '__struct_id')
|
60
|
+
v == @struct_id || v == "iterative" || v == "inline"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns true if we can infer the data version of this struct (if it has parent).
|
64
|
+
def can_infer_data_version?
|
65
|
+
@data_version == DEFAULT_DATA_VERSION || (
|
66
|
+
@element && @element.parent && @element.parent.data_version == @data_version
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module NWN::Gff::Cexolocstr
|
72
|
+
def field_value_as_compact
|
73
|
+
!can_infer_str_ref? ? field_value.merge({'str_ref' => str_ref}) : field_value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module NWN::Gff::Field
|
78
|
+
YAMLCompactableFields = [:byte, :char, :word, :short, :dword, :int, :void,
|
79
|
+
:dword64, :int64, :float, :double, :cexostr, :resref, :cexolocstr, :list]
|
80
|
+
|
81
|
+
# Returns true if we can later infer the field type.
|
82
|
+
def can_infer_type?
|
83
|
+
expected = NWN::Gff.get_struct_default_type(@parent.path, field_label)
|
84
|
+
|
85
|
+
raise NWN::Gff::GffError, "#{field_label} has field_type " +
|
86
|
+
"#{field_type.inspect}, but infer data says #{expected.inspect}." if
|
87
|
+
expected && expected != field_type
|
88
|
+
|
89
|
+
expected == field_type
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns true if we can later infer the default value.
|
93
|
+
def can_infer_value?
|
94
|
+
NWN::Gff.get_struct_default_value(@parent.path, field_label) == field_value
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns true if we can infer the str ref later on.
|
98
|
+
def can_infer_str_ref?
|
99
|
+
!has_str_ref? || (d = NWN::Gff.get_struct_defaults_for(@parent.path, field_label) && d && d[2] != nil)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Can we print this field without any syntactic gizmos?
|
103
|
+
def can_compact_print?
|
104
|
+
|
105
|
+
YAMLCompactableFields.index(field_type) &&
|
106
|
+
# exolocs print their str_ref along with their language keys
|
107
|
+
(field_type == :cexolocstr || can_infer_str_ref?) &&
|
108
|
+
can_infer_type?
|
109
|
+
end
|
110
|
+
|
111
|
+
def can_compact_as_list?
|
112
|
+
NWN::Gff.get_struct_defaults_for(self.path, '__compact') != nil &&
|
113
|
+
field_value.reject {|x|
|
114
|
+
x.can_infer_struct_id?
|
115
|
+
}.size == 0
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_compact_as_list_field
|
119
|
+
NWN::Gff.get_struct_defaults_for(self.path, '__compact')
|
120
|
+
end
|
121
|
+
|
122
|
+
def field_value_as_compact
|
123
|
+
field_value
|
124
|
+
end
|
125
|
+
end
|
data/lib/nwn/kivinen.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module NWN::Gff::Struct
|
2
|
+
|
3
|
+
# yield (key, value) for each element, recursing into substructs.
|
4
|
+
|
5
|
+
# Parses +s+ as an arbitary GFF object and yields for each field found,
|
6
|
+
# with the proper prefix.
|
7
|
+
#
|
8
|
+
# [+prefix+] Supply a prefix to add to the output.
|
9
|
+
# [+types_too+] Yield type definitions as well (gffprint.pl -t).
|
10
|
+
# [+add_prefix+] Add a prefix <tt>(unknown type)</tt> of no type information can be derived from the input.
|
11
|
+
# [+file_type+] File type override. If non-null, add a global struct header with the given file type (useful for passing to gffencode.pl)
|
12
|
+
# [+struct_id+] Provide a struct_id override (if printing a struct).
|
13
|
+
def kivinen_format types_too = false, add_prefix = true, file_type = nil, struct_id = nil, &block
|
14
|
+
|
15
|
+
if types_too
|
16
|
+
yield("/", "")
|
17
|
+
|
18
|
+
ftype = file_type ? file_type : self.data_type
|
19
|
+
yield("/ ____file_type", ftype) if ftype
|
20
|
+
yield("/ ____file_version", self.data_version) if self.data_version
|
21
|
+
|
22
|
+
yield("/ ____struct_type", self.struct_id)
|
23
|
+
end
|
24
|
+
|
25
|
+
self.each_by_flat_path {|path, field|
|
26
|
+
case field
|
27
|
+
when String
|
28
|
+
yield(path, field)
|
29
|
+
|
30
|
+
when NWN::Gff::Struct
|
31
|
+
yield(path + "/", path)
|
32
|
+
yield(path + "/ ____struct_type", field.struct_id)
|
33
|
+
|
34
|
+
when NWN::Gff::Field
|
35
|
+
|
36
|
+
case field.field_type
|
37
|
+
when :list
|
38
|
+
when :struct
|
39
|
+
yield(path + "/", path)
|
40
|
+
yield(path + "/ ____struct_type", field.field_value.struct_id)
|
41
|
+
when :cexolocstr
|
42
|
+
else
|
43
|
+
yield(path, field.field_value)
|
44
|
+
end
|
45
|
+
|
46
|
+
yield(path + ". ____string_ref",field.str_ref) if
|
47
|
+
field.has_str_ref? || field.field_type == :cexolocstr
|
48
|
+
|
49
|
+
yield(path + ". ____type", NWN::Gff::Types.index(field.field_type)) if
|
50
|
+
types_too
|
51
|
+
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# This module contains scripting functions and helpers.
|
2
|
+
#
|
3
|
+
# Include this if you want to eval nwn-gff-dsl scripts.
|
4
|
+
module NWN::Gff::Scripting
|
5
|
+
|
6
|
+
class Sandbox
|
7
|
+
include NWN
|
8
|
+
include NWN::Gff::Scripting
|
9
|
+
end
|
10
|
+
|
11
|
+
# Run a script in a sandboxish environ.
|
12
|
+
# Returns true if the code modified run_on in any way.
|
13
|
+
def self.run_script code, run_on = nil, arguments = []
|
14
|
+
$code = code
|
15
|
+
$argv = arguments
|
16
|
+
$standalone = run_on.nil?
|
17
|
+
run_on ||= Sandbox.new
|
18
|
+
|
19
|
+
$script_obj_hash = run_on.hash
|
20
|
+
catch(:exit) {
|
21
|
+
begin
|
22
|
+
run_on.instance_eval $code
|
23
|
+
rescue => e
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
}
|
27
|
+
$script_obj_hash != run_on.hash
|
28
|
+
end
|
29
|
+
|
30
|
+
# This script only runs for the following conditions (see #satisfy).
|
31
|
+
def want *what
|
32
|
+
obj = satisfy(*what)
|
33
|
+
unless obj
|
34
|
+
log "Wants #{what.inspect}, cannot satisfy - continuing."
|
35
|
+
throw(:exit)
|
36
|
+
end
|
37
|
+
obj
|
38
|
+
end
|
39
|
+
|
40
|
+
# Same as want, but error out (don't continue processing).
|
41
|
+
def need *what
|
42
|
+
satisfy(*what) or raise ArgumentError, "Needs #{what.inspect}, cannot satisfy - aborting."
|
43
|
+
end
|
44
|
+
|
45
|
+
# Call this to prevent nwn-gff from emitting output.
|
46
|
+
def stop_output
|
47
|
+
if $standalone
|
48
|
+
log "warn: no need to stop_output on standalone scripts"
|
49
|
+
else
|
50
|
+
log "#{$base_script}: not emitting any data."
|
51
|
+
end
|
52
|
+
$stop_output = true
|
53
|
+
end
|
54
|
+
|
55
|
+
def will_output?
|
56
|
+
!$stop_output
|
57
|
+
end
|
58
|
+
|
59
|
+
# This checks if the currently-operating field or struct
|
60
|
+
# satisfies one of the given conditions.
|
61
|
+
#
|
62
|
+
# When you're running in standalone mode, the first argument
|
63
|
+
# is expected to be a file or IO stream that needs to satisfy
|
64
|
+
# the given conditions.
|
65
|
+
#
|
66
|
+
# Example:
|
67
|
+
# need ARGV.shift, :bic, :utc, :uti
|
68
|
+
# will require the user to supply a filename as the first argument
|
69
|
+
# to the standalone script, which needs to resolve to a bic, utc, or
|
70
|
+
# uti data_type.
|
71
|
+
#
|
72
|
+
# Conditions can be:
|
73
|
+
# * A symbol describing the data_type, eg :utc
|
74
|
+
# * A symbol describing the field_type, eg :int
|
75
|
+
# * A module or class name
|
76
|
+
#
|
77
|
+
# Returns the object that satisfies the asked-for conditions,
|
78
|
+
# or nil if none can be given.
|
79
|
+
def satisfy *what
|
80
|
+
if $standalone
|
81
|
+
fn = what.shift
|
82
|
+
io = case fn
|
83
|
+
when String
|
84
|
+
IO.read(fn)
|
85
|
+
when IO
|
86
|
+
fn
|
87
|
+
else
|
88
|
+
return nil
|
89
|
+
#raise ArgumentError, "When running in standalone mode, " +
|
90
|
+
# "`need', `want' and `satisfy' need a filename or a IO " +
|
91
|
+
# "object to read from (usually the first script argument)."
|
92
|
+
end
|
93
|
+
obj = NWN::Gff.read(io, NWN::Gff.guess_file_format(fn))
|
94
|
+
else
|
95
|
+
obj = self
|
96
|
+
end
|
97
|
+
|
98
|
+
what.each {|w|
|
99
|
+
case w
|
100
|
+
when Class, Module
|
101
|
+
return obj if obj.is_a?(w)
|
102
|
+
|
103
|
+
when Symbol
|
104
|
+
case obj
|
105
|
+
when NWN::Gff::Struct
|
106
|
+
return obj if obj.data_type.downcase == w.to_s.downcase
|
107
|
+
when NWN::Gff::Field
|
108
|
+
return obj if obj.field_type.to_sdowncase == w.to_s.downcase
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
}
|
113
|
+
|
114
|
+
return nil
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# Log a friendly message to stderr.
|
119
|
+
# Use this instead of puts, since SAFE levels greater than 0
|
120
|
+
# will prevent you from doing logging yourself.
|
121
|
+
def log *args
|
122
|
+
if $options
|
123
|
+
$stderr.puts [$base_script, " on ", $options[:infile], ": ", *args].join("")
|
124
|
+
else
|
125
|
+
$stderr.puts [$base_script, ": ", *args].join("")
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|