nwn-lib 0.4.5 → 0.4.6
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 +1 -1
- data/CHANGELOG +39 -1
- data/CHEATSHEET +20 -6
- data/README +29 -12
- data/Rakefile +3 -3
- data/SETTINGS +3 -69
- data/bin/nwn-dsl +2 -7
- data/lib/nwn/all.rb +1 -0
- data/lib/nwn/erf.rb +19 -192
- data/lib/nwn/gff.rb +0 -1
- data/lib/nwn/gff/field.rb +53 -14
- data/lib/nwn/gff/reader.rb +2 -2
- data/lib/nwn/gff/struct.rb +27 -9
- data/lib/nwn/res.rb +275 -0
- data/lib/nwn/settings.rb +0 -4
- data/lib/nwn/tlk.rb +1 -1
- data/lib/nwn/twoda.rb +36 -17
- data/lib/nwn/yaml.rb +13 -198
- data/spec/cexolocstr_spec.rb +15 -0
- data/spec/erf_spec.rb +87 -0
- data/spec/field_spec.rb +21 -0
- data/spec/gff_spec.rb +22 -0
- data/spec/res_spec.rb +59 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/struct_spec.rb +61 -0
- data/spec/tlk_spec.rb +47 -0
- data/spec/twoda_spec.rb +146 -0
- data/spec/wellformed_gff.binary +0 -0
- metadata +13 -8
- data/DATA_STRUCTURES +0 -50
- data/TYPE_VALUE_INFERRING +0 -93
- data/data/gff-common-nwn1.yaml +0 -982
- data/lib/nwn/infer.rb +0 -125
data/spec/field_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Gff::Field" do
|
4
|
+
GffFieldValidations.each do |t, values|
|
5
|
+
valid, invalid = *values
|
6
|
+
# No field type ever accepts nil as valid
|
7
|
+
invalid << nil
|
8
|
+
|
9
|
+
it "accepts good values for type '#{t.inspect}'" do
|
10
|
+
valid.each do |v|
|
11
|
+
Gff::Field.valid_for?(v, t).should == true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "rejects bad values for type '#{t.inspect}'" do
|
16
|
+
invalid.each do |v|
|
17
|
+
Gff::Field.valid_for?(v, t).should == false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/gff_spec.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
WELLFORMED_GFF = IO.read(File.dirname(__FILE__) + "/wellformed_gff.binary").freeze
|
4
|
+
|
5
|
+
describe "Gff::*" do
|
6
|
+
|
7
|
+
def wellformed_verify binary
|
8
|
+
t = Gff::Reader.read(binary)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "reads wellformed GFF data" do
|
12
|
+
wellformed_verify WELLFORMED_GFF
|
13
|
+
end
|
14
|
+
|
15
|
+
it "reproduces correct GFF binary data" do
|
16
|
+
t = Gff::Reader.read(WELLFORMED_GFF)
|
17
|
+
v = Gff::Writer.dump(t)
|
18
|
+
t2 = wellformed_verify v
|
19
|
+
t2.should == t
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/spec/res_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
class StubContainer < Resources::Container
|
4
|
+
def initialize files
|
5
|
+
super()
|
6
|
+
files.each {|fn, content|
|
7
|
+
io = StringIO.new(content)
|
8
|
+
@content << Resources::ContentObject.new_from(fn, io)
|
9
|
+
}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "ContentObject" do
|
14
|
+
subject do
|
15
|
+
Resources::ContentObject.new_from("case.txt", StringIO.new("test"))
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns filenames lowercase" do
|
19
|
+
subject.filename.should == "case.txt"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns the proper size for StringIO" do
|
23
|
+
subject.size.should == 4
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "Resources::Container" do
|
28
|
+
subject do
|
29
|
+
StubContainer.new('a_1.txt' => 'a', 'CASE.tXt' => 'case', 't_1.txt' => 'a')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "disregards case" do
|
33
|
+
subject.get('case.txt').should == "case"
|
34
|
+
subject.get('CASE.txt').should == "case"
|
35
|
+
subject.get('CASE.tXt').should == "case"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe Resources::Manager do
|
40
|
+
before do
|
41
|
+
subject.add_container StubContainer.new('a_1.txt' => 'a', 'CASE.tXt' => 'case', 't_1.txt' => 'a')
|
42
|
+
subject.add_container StubContainer.new('b_1.txt' => 'b', 't_1.txt' => 'b')
|
43
|
+
end
|
44
|
+
|
45
|
+
it "observes ordering of added containers" do
|
46
|
+
subject.get('a_1.txt').should == "a"
|
47
|
+
subject.get('t_1.txt').should == "b"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "fails on invalid filenames" do
|
51
|
+
proc {subject.get('invalid')}.should raise_error Errno::ENOENT
|
52
|
+
end
|
53
|
+
|
54
|
+
it "disregards case" do
|
55
|
+
subject.get('case.txt').should == "case"
|
56
|
+
subject.get('CASE.txt').should == "case"
|
57
|
+
subject.get('CASE.tXt').should == "case"
|
58
|
+
end
|
59
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
Thread.abort_on_exception = true
|
4
|
+
|
5
|
+
unless Object.const_defined?('NWN')
|
6
|
+
$:.unshift(File.join(File.dirname(__FILE__), "../lib/"))
|
7
|
+
require 'nwn/all'
|
8
|
+
include NWN
|
9
|
+
end
|
10
|
+
|
11
|
+
GffFieldValidations = {
|
12
|
+
:void => [[""], []],
|
13
|
+
:byte => [[0, 255], [256, -1]],
|
14
|
+
:char => [[0, 255], [256, -1]],
|
15
|
+
:resref => [["", "a" * 16], ["a" * 17]],
|
16
|
+
:double => [[0.0], ["x"]],
|
17
|
+
:dword => [[0, 0xffffffff], [-1, 0xffffffff + 1]],
|
18
|
+
:dword64 => [[0, 0xffffffffffff], [-1, 0xffffffffffff + 1]],
|
19
|
+
:float => [[0.0], ["x"]],
|
20
|
+
:int => [[-0x80000000, 0x7fffffff], [0x80000001, 0x7fffffff + 1]],
|
21
|
+
:int64 => [[-0x800000000000, 0x7fffffffffff], [0x800000000001, 0x7fffffffffff + 1]],
|
22
|
+
:short => [[-0x8000, 0x7fff], [-0x8001, 0x7fff + 1]],
|
23
|
+
:word => [[0, 0xffff], [-1, 0xffff + 1]],
|
24
|
+
}.freeze
|
data/spec/struct_spec.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Gff::Struct" do
|
4
|
+
|
5
|
+
it "accepts a block and yields the resulting struct" do
|
6
|
+
ret = Gff::Struct.new(0xdeadbeef) do |s|
|
7
|
+
s.add_byte 'Halp', 0xff
|
8
|
+
end
|
9
|
+
ret.should == {"Halp"=>{"label"=>"Halp", "value"=>255, "type"=>:byte}}
|
10
|
+
ret.struct_id.should == 0xdeadbeef
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can retrieve list entries by_path" do
|
14
|
+
ret = Gff::Struct.new
|
15
|
+
ret.add_list 'Path', [] do |list|
|
16
|
+
list.v << Gff::Struct.new do |s|
|
17
|
+
s.add_byte 'Val', 0xff
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ret.by_path('Path[0]/Val').should == {"label"=>"Val", "value"=>255, "type"=>:byte}
|
22
|
+
proc {
|
23
|
+
ret.by_path('Path[1]/Val')
|
24
|
+
}.should raise_error Gff::GffPathInvalidError
|
25
|
+
proc {
|
26
|
+
ret.by_path('PathWTF/$55?')
|
27
|
+
}.should raise_error Gff::GffPathInvalidError
|
28
|
+
|
29
|
+
ret.by_path('Path[0]/Val').should equal ret.by_path('/Path[0]/Val')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "sets proper parent/child tree links" do
|
33
|
+
ret = Gff::Struct.new
|
34
|
+
list = ret.add_list 'Path', []
|
35
|
+
list.add_struct 1 do |l|
|
36
|
+
l.add_byte 'Val', 0xff
|
37
|
+
end
|
38
|
+
|
39
|
+
list = ret.by_path('/Path')
|
40
|
+
list.parent.should == ret
|
41
|
+
|
42
|
+
struct = ret.by_path('/Path[0]')
|
43
|
+
struct.element.should == list
|
44
|
+
|
45
|
+
byte = ret.by_path('/Path[0]/Val')
|
46
|
+
byte.parent.should == struct
|
47
|
+
|
48
|
+
ret.by_path('/Path[0]/Val').path.should == '/Path[0]/Val'
|
49
|
+
end
|
50
|
+
|
51
|
+
GffFieldValidations.each {|type, values|
|
52
|
+
valid, invalid = * values
|
53
|
+
|
54
|
+
it "can create #{type.inspect} fields dynamically" do
|
55
|
+
ret = Gff::Struct.new
|
56
|
+
ret.send('add_' + type.to_s, 'Test', valid[0])
|
57
|
+
ret.should == {"Test"=>{"label"=>"Test", "value"=>valid[0], "type"=>type}}
|
58
|
+
end
|
59
|
+
}
|
60
|
+
|
61
|
+
end
|
data/spec/tlk_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
WELLFORMED_TLK = ([
|
4
|
+
"TLK", "V3.0",
|
5
|
+
language_id = 0,
|
6
|
+
string_count = 5,
|
7
|
+
offset_to_str = 21,
|
8
|
+
].pack("a4 a4 I I I") + [ # string data table
|
9
|
+
# flags, soundresref, volvariance, pitchvariance, offset_to_str, sz, soundlen
|
10
|
+
0x1, "", 0, 0, -1 + 40 * string_count, 1, 0.0,
|
11
|
+
0x3, "textsnd", 0, 0, -1 + 40 * string_count + 1, 2, 0.0,
|
12
|
+
0x7, "textsndlen", 0, 0, -1 + 40 * string_count + 3, 3, 2.0,
|
13
|
+
0x1, "", 0, 0, -1 + 40 * string_count + 6, 4, 0.0,
|
14
|
+
0x2, "justsnd", 0, 0, -1 + 40 * string_count + 10, 0, 0.0,
|
15
|
+
].pack("I A16 I I I I f" * string_count) + [
|
16
|
+
"1", "22", "333", "4444"
|
17
|
+
].join("")).freeze
|
18
|
+
|
19
|
+
|
20
|
+
describe "Tlk::Tlk" do
|
21
|
+
|
22
|
+
def wellformed_verify binary
|
23
|
+
t = Tlk::Tlk.new(StringIO.new binary)
|
24
|
+
|
25
|
+
t.language.should == 0
|
26
|
+
t.highest_id.should == 4
|
27
|
+
t[0].should == {:pitch_variance=>0, :text=>"1", :sound=>"", :sound_length=>0.0, :volume_variance=>0}
|
28
|
+
t[1].should == {:pitch_variance=>0, :text=>"22", :sound=>"textsnd", :sound_length=>0.0, :volume_variance=>0}
|
29
|
+
t[2].should == {:pitch_variance=>0, :text=>"333", :sound=>"textsndlen", :sound_length=>2.0, :volume_variance=>0}
|
30
|
+
t[3].should == {:pitch_variance=>0, :text=>"4444", :sound=>"", :sound_length=>0.0, :volume_variance=>0}
|
31
|
+
t[4].should == {:pitch_variance=>0, :text=>"", :sound=>"justsnd", :sound_length=>0.0, :volume_variance=>0}
|
32
|
+
proc { t[5] }.should raise_error ArgumentError
|
33
|
+
end
|
34
|
+
|
35
|
+
it "reads wellformed TalkTables" do
|
36
|
+
wellformed_verify WELLFORMED_TLK
|
37
|
+
end
|
38
|
+
|
39
|
+
it "reproduces correct TalkTable binary data" do
|
40
|
+
t = Tlk::Tlk.new(StringIO.new WELLFORMED_TLK)
|
41
|
+
io = StringIO.new
|
42
|
+
t.write_to(io)
|
43
|
+
io.seek(0)
|
44
|
+
wellformed_verify io.read
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/spec/twoda_spec.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
TWODA_WELLFORMED = <<-EOT
|
4
|
+
2DA V2.0
|
5
|
+
|
6
|
+
Col1 Col2
|
7
|
+
0 a b
|
8
|
+
1 c d
|
9
|
+
EOT
|
10
|
+
|
11
|
+
TWODA_MISALIGNED = <<-EOT
|
12
|
+
2DA V2.0
|
13
|
+
|
14
|
+
Col1
|
15
|
+
0 a
|
16
|
+
1 b
|
17
|
+
2 c
|
18
|
+
3 d
|
19
|
+
4 e
|
20
|
+
6 f
|
21
|
+
2 g
|
22
|
+
7 h
|
23
|
+
EOT
|
24
|
+
|
25
|
+
TWODA_WHITESPACE = <<-EOT
|
26
|
+
2DA V2.0
|
27
|
+
|
28
|
+
|
29
|
+
Col1
|
30
|
+
0 4
|
31
|
+
EOT
|
32
|
+
|
33
|
+
TWODA_MISSING_COLUMN = <<-EOT
|
34
|
+
2DA V2.0
|
35
|
+
|
36
|
+
Col1 Col2 Col3
|
37
|
+
0 a1 b1 c1
|
38
|
+
1 a2 b2
|
39
|
+
EOT
|
40
|
+
|
41
|
+
TWODA_TOO_MANY_CELLS = <<-EOT
|
42
|
+
2DA V2.0
|
43
|
+
|
44
|
+
Col1
|
45
|
+
0 a1 b1 c1
|
46
|
+
1 a2 b2
|
47
|
+
2 "a2 b2 c1"
|
48
|
+
EOT
|
49
|
+
|
50
|
+
|
51
|
+
TWODA_EMPTY_AND_QUOTES = <<-EOT
|
52
|
+
2DA V2.0
|
53
|
+
|
54
|
+
Col1 Col2
|
55
|
+
0 **** b
|
56
|
+
1 c d
|
57
|
+
2 "" f
|
58
|
+
3 "g g" h
|
59
|
+
EOT
|
60
|
+
|
61
|
+
TWODA_MISSING_ID = <<-EOT
|
62
|
+
2DA V2.0
|
63
|
+
|
64
|
+
Col1
|
65
|
+
a
|
66
|
+
0 b
|
67
|
+
1 c
|
68
|
+
2 d
|
69
|
+
EOT
|
70
|
+
|
71
|
+
describe TwoDA::Table do
|
72
|
+
|
73
|
+
it "parses wellformed files" do
|
74
|
+
proc { subject.parse(TWODA_WELLFORMED) }.should_not raise_error ArgumentError
|
75
|
+
end
|
76
|
+
|
77
|
+
it "parses misnumbered IDs as NWN does" do
|
78
|
+
subject.parse(TWODA_MISALIGNED)
|
79
|
+
subject.rows.map {|v| v.Col1 }.should == %w{a b c d e f g h}
|
80
|
+
end
|
81
|
+
|
82
|
+
it "skips rows with missing IDs as NWN does" do
|
83
|
+
subject.parse(TWODA_MISSING_ID)
|
84
|
+
subject.rows.map {|v| v.Col1 }.should == ["", "b", "c", "d"]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "parses whitespace in tables correctly" do
|
88
|
+
proc { subject.parse(TWODA_WHITESPACE) }.should_not raise_error
|
89
|
+
end
|
90
|
+
|
91
|
+
it "fills in missing columns correctly" do
|
92
|
+
subject.parse(TWODA_MISSING_COLUMN)
|
93
|
+
subject.rows[1].Col3.should == ""
|
94
|
+
end
|
95
|
+
|
96
|
+
it "ignores superflous cell values" do
|
97
|
+
subject.parse(TWODA_TOO_MANY_CELLS)
|
98
|
+
subject.rows[0].size.should == 1
|
99
|
+
subject.rows[1].size.should == 1
|
100
|
+
end
|
101
|
+
|
102
|
+
it "parses non-quoted and quoted trailing cells with whitespaces correctly" do
|
103
|
+
subject.parse(TWODA_TOO_MANY_CELLS)
|
104
|
+
subject.rows[0].Col1.should == "a1"
|
105
|
+
subject.rows[1].Col1.should == "a2"
|
106
|
+
subject.rows[2].Col1.should == "a2 b2 c1"
|
107
|
+
end
|
108
|
+
|
109
|
+
it "parses starred values correctly" do
|
110
|
+
subject.parse(TWODA_EMPTY_AND_QUOTES)
|
111
|
+
subject.rows[0].Col1.should == ""
|
112
|
+
end
|
113
|
+
|
114
|
+
it "parses quoted cells correctly" do
|
115
|
+
subject.parse(TWODA_EMPTY_AND_QUOTES)
|
116
|
+
subject.rows[2].Col1.should == ""
|
117
|
+
subject.rows[3].Col1.should == "g g"
|
118
|
+
subject.rows[3].Col2.should == "h"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "allows setting a whole row by column id, and cast arguments" do
|
122
|
+
subject.parse(TWODA_WELLFORMED)
|
123
|
+
subject[0] = [1, 2]
|
124
|
+
subject[0].should == ["1", "2"]
|
125
|
+
proc { subject[0] = [1, 2, 3] }.should raise_error ArgumentError
|
126
|
+
end
|
127
|
+
|
128
|
+
it "allows setting a cell by id and column name, and cast arguments" do
|
129
|
+
subject.parse(TWODA_WELLFORMED)
|
130
|
+
subject[0, 'Col1'] = "a"
|
131
|
+
subject[0, 'Col1'].should == "a"
|
132
|
+
proc { subject['Col1', 0] = "a" }.should raise_error TypeError
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should print newlines as specified in NWN_LIB_2DA_NEWLINE" do
|
136
|
+
subject.parse(TWODA_WELLFORMED)
|
137
|
+
ENV['NWN_LIB_2DA_NEWLINE'] = nil
|
138
|
+
subject.to_2da.should =~ /^2DA V2.0\r\n\r\n +C/
|
139
|
+
ENV['NWN_LIB_2DA_NEWLINE'] = "0"
|
140
|
+
subject.to_2da.should =~ /^2DA V2.0\r\n\r\n +C/
|
141
|
+
ENV['NWN_LIB_2DA_NEWLINE'] = "1"
|
142
|
+
subject.to_2da.should =~ /^2DA V2.0\n\n +C/
|
143
|
+
ENV['NWN_LIB_2DA_NEWLINE'] = "2"
|
144
|
+
subject.to_2da.should =~ /^2DA V2.0\r\r +C/
|
145
|
+
end
|
146
|
+
end
|
Binary file
|
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.6
|
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-05-18 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -25,10 +25,8 @@ extensions: []
|
|
25
25
|
extra_rdoc_files:
|
26
26
|
- README
|
27
27
|
- BINARIES
|
28
|
-
- DATA_STRUCTURES
|
29
28
|
- SCRIPTING
|
30
29
|
- SETTINGS
|
31
|
-
- TYPE_VALUE_INFERRING
|
32
30
|
- CHEATSHEET
|
33
31
|
- CHANGELOG
|
34
32
|
- COPYING
|
@@ -41,8 +39,18 @@ files:
|
|
41
39
|
- bin/nwn-gff
|
42
40
|
- bin/nwn-irb
|
43
41
|
- bin/nwn-erf
|
42
|
+
- spec/gff_spec.rb
|
43
|
+
- spec/res_spec.rb
|
44
|
+
- spec/wellformed_gff.binary
|
44
45
|
- spec/spec.opts
|
46
|
+
- spec/erf_spec.rb
|
47
|
+
- spec/field_spec.rb
|
48
|
+
- spec/cexolocstr_spec.rb
|
49
|
+
- spec/struct_spec.rb
|
50
|
+
- spec/spec_helper.rb
|
51
|
+
- spec/tlk_spec.rb
|
45
52
|
- spec/rcov.opts
|
53
|
+
- spec/twoda_spec.rb
|
46
54
|
- lib/nwn
|
47
55
|
- lib/nwn/scripting.rb
|
48
56
|
- lib/nwn/yaml.rb
|
@@ -51,7 +59,7 @@ files:
|
|
51
59
|
- lib/nwn/settings.rb
|
52
60
|
- lib/nwn/gff.rb
|
53
61
|
- lib/nwn/tlk.rb
|
54
|
-
- lib/nwn/
|
62
|
+
- lib/nwn/res.rb
|
55
63
|
- lib/nwn/kivinen.rb
|
56
64
|
- lib/nwn/all.rb
|
57
65
|
- lib/nwn/helpers.rb
|
@@ -70,12 +78,9 @@ files:
|
|
70
78
|
- scripts/clean_locstrs.rb
|
71
79
|
- scripts/extract_all_items.rb
|
72
80
|
- scripts/debug_check_objid.rb
|
73
|
-
- data/gff-common-nwn1.yaml
|
74
81
|
- BINARIES
|
75
|
-
- DATA_STRUCTURES
|
76
82
|
- SCRIPTING
|
77
83
|
- SETTINGS
|
78
|
-
- TYPE_VALUE_INFERRING
|
79
84
|
- CHEATSHEET
|
80
85
|
has_rdoc: true
|
81
86
|
homepage: http://nwn-lib.elv.es
|