nwn-lib 0.4.12 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.yardopts +1 -0
- data/{BINARIES → BINARIES.rdoc} +0 -0
- data/{CHEATSHEET → CHEATSHEET.rdoc} +0 -0
- data/Gemfile +9 -0
- data/{HOWTO → HOWTO.rdoc} +0 -0
- data/LICENCE +15 -0
- data/{README → README.rdoc} +9 -15
- data/Rakefile +6 -95
- data/{SCRIPTING → SCRIPTING.rdoc} +0 -0
- data/{SETTINGS → SETTINGS.rdoc} +0 -0
- data/bin/nwn-erf +2 -2
- data/lib/nwn/all.rb +1 -0
- data/lib/nwn/erf.rb +4 -4
- data/lib/nwn/gff.rb +1 -1
- data/lib/nwn/gff/field.rb +16 -6
- data/lib/nwn/gff/reader.rb +8 -4
- data/lib/nwn/gff/struct.rb +6 -4
- data/lib/nwn/gff/writer.rb +2 -2
- data/lib/nwn/key.rb +2 -2
- data/lib/nwn/kivinen_support.rb +3 -1
- data/lib/nwn/res.rb +2 -2
- data/lib/nwn/scripting.rb +1 -1
- data/lib/nwn/settings.rb +2 -12
- data/lib/nwn/twoda.rb +46 -8
- data/lib/nwn/version.rb +3 -0
- data/lib/nwn/xml_support.rb +3 -3
- data/lib/nwn/yaml_support.rb +1 -0
- data/nwn-lib.gemspec +18 -0
- data/scripts/reformat_2da +11 -6
- data/spec/bin_dsl_spec.rb +4 -4
- data/spec/bin_erf_spec.rb +17 -22
- data/spec/bin_gff_spec.rb +14 -6
- data/spec/erf_spec.rb +2 -1
- data/spec/field_spec.rb +9 -0
- data/spec/gff_spec.rb +1 -2
- data/spec/key_spec.rb +1 -1
- data/spec/kivinen_spec.rb +1 -1
- data/spec/rcov.opts +0 -0
- data/spec/spec.opts +0 -0
- data/spec/spec_helper.rb +9 -7
- metadata +106 -102
- data/CHANGELOG +0 -354
- data/COPYING +0 -15
data/lib/nwn/scripting.rb
CHANGED
data/lib/nwn/settings.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'iconv'
|
2
|
-
|
3
1
|
module NWN
|
4
2
|
SETTING_DEFAULT_VALUES = {
|
5
3
|
'NWN_LIB_IN_ENCODING' => 'ISO-8859-1',
|
@@ -51,20 +49,12 @@ module NWN
|
|
51
49
|
|
52
50
|
# Converts text from native format (such as json) to Gff (required by NWN).
|
53
51
|
def self.iconv_native_to_gff text
|
54
|
-
|
55
|
-
IconvState[:out] != NWN.setting(:out_encoding)
|
56
|
-
IconvState[:in_i] = Iconv.new(NWN.setting(:in_encoding), NWN.setting(:out_encoding))
|
57
|
-
end
|
58
|
-
IconvState[:in_i].iconv(text)
|
52
|
+
text.encode(NWN.setting(:out_encoding))
|
59
53
|
end
|
60
54
|
|
61
55
|
# Converts text from Gff format to native/external, such as json (usually UTF-8).
|
62
56
|
def self.iconv_gff_to_native text
|
63
|
-
|
64
|
-
IconvState[:out] != NWN.setting(:out_encoding)
|
65
|
-
IconvState[:out_i] = Iconv.new(NWN.setting(:out_encoding), NWN.setting(:in_encoding))
|
66
|
-
end
|
67
|
-
IconvState[:out_i].iconv(text)
|
57
|
+
text.encode('UTF-8')
|
68
58
|
end
|
69
59
|
end
|
70
60
|
|
data/lib/nwn/twoda.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'shellwords'
|
2
|
-
|
3
1
|
class Integer
|
4
2
|
# Returns the level that this amount experience resolves to.
|
5
3
|
# Depends on a set-up TwoDA::Cache, and reads from <tt>exptable</tt>.
|
@@ -41,8 +39,17 @@ module NWN
|
|
41
39
|
end
|
42
40
|
|
43
41
|
def method_missing meth, *args
|
44
|
-
|
45
|
-
|
42
|
+
col = meth.to_s
|
43
|
+
assignment = if col =~ /(.+?)=$/
|
44
|
+
col = $1
|
45
|
+
true
|
46
|
+
else
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
if idx = @table.columns.index(col.downcase) ||
|
51
|
+
idx = @table.columns.index(col)
|
52
|
+
if assignment
|
46
53
|
self[idx] = args.shift or raise ArgumentError,
|
47
54
|
"Need a paramenter for assignments .."
|
48
55
|
else
|
@@ -120,9 +127,9 @@ module NWN
|
|
120
127
|
|
121
128
|
header = data.shift
|
122
129
|
|
123
|
-
header =
|
130
|
+
header = colsplit(header.strip)
|
124
131
|
data.map! {|line|
|
125
|
-
|
132
|
+
colsplit(line.strip)
|
126
133
|
}
|
127
134
|
|
128
135
|
new_row_data = []
|
@@ -277,6 +284,7 @@ module NWN
|
|
277
284
|
row.each_with_index {|cell, column_idx|
|
278
285
|
cell = "****" if cell == ""
|
279
286
|
cell = '"%s"' % cell if cell =~ /\s/
|
287
|
+
cell = cell.to_s
|
280
288
|
rv << cell + " " * (max_cell_size_by_column[column_idx] - cell.size)
|
281
289
|
}
|
282
290
|
ret << rv.join("").rstrip
|
@@ -296,6 +304,35 @@ module NWN
|
|
296
304
|
@newline
|
297
305
|
end)
|
298
306
|
end
|
307
|
+
|
308
|
+
private
|
309
|
+
|
310
|
+
def colsplit(line)
|
311
|
+
line = String.new(line) rescue
|
312
|
+
raise(ArgumentError, "Argument must be a string")
|
313
|
+
line.lstrip!
|
314
|
+
words = []
|
315
|
+
until line.empty?
|
316
|
+
field = ''
|
317
|
+
loop do
|
318
|
+
if line.sub!(/\A"(([^"\\]|\\.)*)"/, '') then
|
319
|
+
snippet = $1.gsub(/\\(.)/, '\1')
|
320
|
+
elsif line =~ /\A"/ then
|
321
|
+
raise ArgumentError, "Unmatched double quote: #{line}"
|
322
|
+
elsif line.sub!(/\A\\(.)?/, '') then
|
323
|
+
snippet = $1 || '\\'
|
324
|
+
elsif line.sub!(/\A([^\s\\"]+)/, '') then
|
325
|
+
snippet = $1
|
326
|
+
else
|
327
|
+
line.lstrip!
|
328
|
+
break
|
329
|
+
end
|
330
|
+
field.concat(snippet)
|
331
|
+
end
|
332
|
+
words.push(field)
|
333
|
+
end
|
334
|
+
words
|
335
|
+
end
|
299
336
|
end
|
300
337
|
|
301
338
|
# An alias for TwoDA::Cache.get
|
@@ -312,7 +349,8 @@ module NWN
|
|
312
349
|
# Call this on application startup.
|
313
350
|
# path spec is a colon-separated list of paths, just like $PATH.
|
314
351
|
def self.setup root_directories
|
315
|
-
@_roots = root_directories.split(
|
352
|
+
@_roots = root_directories.split(File::PATH_SEPARATOR).
|
353
|
+
compact.reject {|x| "" == x.strip }
|
316
354
|
end
|
317
355
|
|
318
356
|
# Get the 2da file with the given name. +name+ is without extension.
|
@@ -327,7 +365,7 @@ module NWN
|
|
327
365
|
|
328
366
|
def self.read_2da name # :nodoc:
|
329
367
|
@_roots.each {|root|
|
330
|
-
file = root +
|
368
|
+
file = root + File::SEPARATOR + name + '.2da'
|
331
369
|
next unless FileTest.exists?(file)
|
332
370
|
return Table.parse(IO.read(file))
|
333
371
|
}
|
data/lib/nwn/version.rb
ADDED
data/lib/nwn/xml_support.rb
CHANGED
@@ -17,7 +17,7 @@ private
|
|
17
17
|
struct.data_version != NWN::Gff::Struct::DEFAULT_DATA_VERSION
|
18
18
|
end
|
19
19
|
|
20
|
-
struct.sort.each {|(
|
20
|
+
struct.sort.each {|(*,v)|
|
21
21
|
s << field_to_xml(v)
|
22
22
|
}
|
23
23
|
s
|
@@ -33,12 +33,12 @@ private
|
|
33
33
|
e['name'] = field.field_label
|
34
34
|
e['type'] = case @format
|
35
35
|
when :modpacker
|
36
|
-
NWN::Gff::Types.
|
36
|
+
NWN::Gff::Types.key(field.field_type).to_s
|
37
37
|
when :nxml
|
38
38
|
field.field_type.to_s
|
39
39
|
end
|
40
40
|
|
41
|
-
|
41
|
+
case field.field_type
|
42
42
|
when :cexolocstr
|
43
43
|
case @format
|
44
44
|
when :modpacker
|
data/lib/nwn/yaml_support.rb
CHANGED
data/nwn-lib.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/nwn/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Bernhard Stoeckner"]
|
6
|
+
gem.email = ["n@e-ix.net"]
|
7
|
+
gem.description = %q{Neverwinter Nights 1/2 file formats ruby library}
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.homepage = "https://github.com/niv/nwn-lib"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "nwn-lib"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = NWN::VERSION
|
17
|
+
gem.required_ruby_version = '>= 1.9.1'
|
18
|
+
end
|
data/scripts/reformat_2da
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
#!/usr/bin/env nwn-dsl
|
2
2
|
# vim: ft=ruby
|
3
3
|
|
4
|
-
ARGV.
|
5
|
-
|
6
|
-
t
|
7
|
-
|
8
|
-
|
9
|
-
}
|
4
|
+
if ARGV.size == 0
|
5
|
+
t = TwoDA::Table.parse($stdin.read)
|
6
|
+
$stdout.puts t.to_2da
|
7
|
+
else
|
8
|
+
ARGV.each {|f|
|
9
|
+
log "Working on #{f} .."
|
10
|
+
t = TwoDA::Table.parse(IO.read(f))
|
11
|
+
File.open(f, "wb") {|n| n.puts t.to_2da }
|
12
|
+
log "done."
|
13
|
+
}
|
14
|
+
end
|
data/spec/bin_dsl_spec.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
3
|
describe "nwn-dsl" do
|
4
|
-
|
4
|
+
include BinHelper
|
5
5
|
|
6
6
|
it "runs empty scripts" do
|
7
|
-
t = Tempfile.new(
|
7
|
+
t = Tempfile.new(["nwn-lib", "dsl"])
|
8
8
|
t.close
|
9
9
|
run(t.path)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "runs want/need scripts" do
|
13
|
-
t = Tempfile.new(
|
13
|
+
t = Tempfile.new(["nwn-lib", "dsl"])
|
14
14
|
t.write("need ARGV.shift, :bic")
|
15
15
|
t.close
|
16
16
|
run_bin(t.path, WELLFORMED_GFF_PATH) do |i,o,e|
|
@@ -22,7 +22,7 @@ describe "nwn-dsl" do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it "logs to stderr" do
|
25
|
-
t = Tempfile.new(
|
25
|
+
t = Tempfile.new(["nwn-lib", "dsl"])
|
26
26
|
t.write("log 'hey'")
|
27
27
|
t.close
|
28
28
|
run_bin(t.path, WELLFORMED_GFF_PATH) do |i,o,e|
|
data/spec/bin_erf_spec.rb
CHANGED
@@ -1,38 +1,33 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
3
|
describe "nwn-erf" do
|
4
|
-
|
5
|
-
|
4
|
+
include BinHelper
|
6
5
|
# Create temporary testcase files.
|
7
6
|
before do
|
8
|
-
@
|
7
|
+
@tmpdir = Dir.mktmpdir
|
8
|
+
|
9
|
+
@target = File.join(@tmpdir, "nwn-lib-spec-target.erf")
|
9
10
|
|
10
11
|
@tmp0s = []
|
11
12
|
@tmp1s = []
|
12
13
|
for x in %w{aaa.tga bbbb.erf ccc.bmp 44.txt} do
|
13
|
-
File.open(File.join(@
|
14
|
+
File.open(File.join(@tmpdir, x), "w") do |fn|
|
14
15
|
fn.write(x)
|
15
16
|
end
|
16
|
-
@tmp0s << File.join(@
|
17
|
+
@tmp0s << File.join(@tmpdir, x)
|
17
18
|
end
|
18
19
|
for x in %w{bbbbbbbbbbbbbbbbbbbb.bmp} do
|
19
|
-
File.open(File.join(@
|
20
|
+
File.open(File.join(@tmpdir, x), "w") do |fn|
|
20
21
|
fn.write(x)
|
21
22
|
end
|
22
|
-
@tmp1s << File.join(@
|
23
|
+
@tmp1s << File.join(@tmpdir, x)
|
23
24
|
end
|
24
25
|
@tmp0s.sort!
|
25
26
|
@tmp1s.sort!
|
26
27
|
end
|
27
28
|
|
28
29
|
after do
|
29
|
-
|
30
|
-
File.unlink(f.path) rescue nil
|
31
|
-
}
|
32
|
-
@tmp1s.each {|f|
|
33
|
-
File.unlink(f.path) rescue nil
|
34
|
-
}
|
35
|
-
File.unlink(@target) rescue nil
|
30
|
+
FileUtils.rm_r @tmpdir
|
36
31
|
end
|
37
32
|
|
38
33
|
it "packs -0" do
|
@@ -66,35 +61,35 @@ describe "nwn-erf" do
|
|
66
61
|
it "extracts -0" do
|
67
62
|
run("-c", "-f", @target, *@tmp0s)
|
68
63
|
@tmp0s.each {|f| File.unlink(f) }
|
69
|
-
run("-
|
64
|
+
run("-x", "-f", @target)
|
70
65
|
@tmp0s.each {|f| FileTest.exists?(f).should == true }
|
71
|
-
@tmp0s.each {|f| IO.read(f).should == File.basename(f) }
|
66
|
+
@tmp0s.each {|f| IO.read(f, :encoding => "BINARY").should == File.basename(f) }
|
72
67
|
end
|
73
68
|
|
74
69
|
it "extracts -1" do
|
75
70
|
workon = @tmp0s + @tmp1s
|
76
71
|
run("-1", "-c", "-f", @target, *workon)
|
77
72
|
workon.each {|f| File.unlink(f) }
|
78
|
-
run("-
|
73
|
+
run("-x", "-f", @target)
|
79
74
|
workon.each {|f| FileTest.exists?(f).should == true }
|
80
|
-
workon.each {|f| IO.read(f).should == File.basename(f) }
|
75
|
+
workon.each {|f| IO.read(f, :encoding => "BINARY").should == File.basename(f) }
|
81
76
|
end
|
82
77
|
|
83
78
|
it "creates haks" do
|
84
79
|
run("-H", "-c", "-f", @target, *@tmp0s)
|
85
|
-
IO.read(@target).should =~ /^HAK/
|
80
|
+
IO.read(@target, :encoding => "BINARY").should =~ /^HAK/
|
86
81
|
end
|
87
82
|
|
88
83
|
it "creates mods" do
|
89
84
|
run("-M", "-c", "-f", @target, *@tmp0s)
|
90
|
-
IO.read(@target).should =~ /^MOD/
|
85
|
+
IO.read(@target, :encoding => "BINARY").should =~ /^MOD/
|
91
86
|
end
|
92
87
|
|
93
88
|
it "creates erfs (by default)" do
|
94
89
|
run("-E", "-c", "-f", @target, *@tmp0s)
|
95
|
-
IO.read(@target).should =~ /^ERF/
|
90
|
+
IO.read(@target, :encoding => "BINARY").should =~ /^ERF/
|
96
91
|
run("-c", "-f", @target, *@tmp0s)
|
97
|
-
IO.read(@target).should =~ /^ERF/
|
92
|
+
IO.read(@target, :encoding => "BINARY").should =~ /^ERF/
|
98
93
|
end
|
99
94
|
|
100
95
|
it "adds files from existing archives" do
|
data/spec/bin_gff_spec.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
3
|
describe "nwn-gff" do
|
4
|
-
|
4
|
+
include BinHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
@tmpdir = Dir.mktmpdir
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
FileUtils.rm_r(@tmpdir)
|
12
|
+
end
|
5
13
|
|
6
14
|
NWN::Gff::InputFormats.each do |in_format, handler|
|
7
15
|
inf = in_format.to_s
|
@@ -11,7 +19,7 @@ describe "nwn-gff" do
|
|
11
19
|
|
12
20
|
it "converts #{inf} to #{otf}" do
|
13
21
|
# prepare the temp file
|
14
|
-
t = Tempfile.new(@
|
22
|
+
t = Tempfile.new('nwn-gff', @tmpdir)
|
15
23
|
t.close
|
16
24
|
|
17
25
|
run("-lg", "-i", WELLFORMED_GFF_PATH, "-k", inf, "-o", t.path)
|
@@ -22,7 +30,7 @@ describe "nwn-gff" do
|
|
22
30
|
end
|
23
31
|
|
24
32
|
it "supports none GNU-style backup" do
|
25
|
-
t = Tempfile.new(@
|
33
|
+
t = Tempfile.new('nwn-gff', @tmpdir)
|
26
34
|
t.close
|
27
35
|
run("-b", "none", "-lg", "-i", WELLFORMED_GFF_PATH, "-kg", "-o", t.path)
|
28
36
|
FileTest.exists?(t.path).should == true
|
@@ -30,7 +38,7 @@ describe "nwn-gff" do
|
|
30
38
|
end
|
31
39
|
|
32
40
|
it "supports numbered GNU-style backup" do
|
33
|
-
t = Tempfile.new(@
|
41
|
+
t = Tempfile.new('nwn-gff', @tmpdir)
|
34
42
|
t.close
|
35
43
|
|
36
44
|
run("-b", "numbered", "-lg", "-i", WELLFORMED_GFF_PATH, "-kg", "-o", t.path)
|
@@ -49,7 +57,7 @@ describe "nwn-gff" do
|
|
49
57
|
end
|
50
58
|
|
51
59
|
it "supports existing with no numbered backups GNU-style backup" do
|
52
|
-
t = Tempfile.new(@
|
60
|
+
t = Tempfile.new('nwn-gff', @tmpdir)
|
53
61
|
t.close
|
54
62
|
|
55
63
|
FileTest.exists?(t.path + "~").should == false
|
@@ -74,7 +82,7 @@ describe "nwn-gff" do
|
|
74
82
|
|
75
83
|
|
76
84
|
it "supports simple GNU-style backup" do
|
77
|
-
t = Tempfile.new(@
|
85
|
+
t = Tempfile.new('nwn-gff', @tmpdir)
|
78
86
|
t.close
|
79
87
|
|
80
88
|
FileTest.exists?(t.path + "~").should == false
|
data/spec/erf_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
|
-
|
3
|
+
shared_examples_for "Erf::Erf" do
|
4
4
|
def wellformed_verify binary, expect_locstr = true
|
5
5
|
t = Erf::Erf.new(StringIO.new binary)
|
6
6
|
|
@@ -40,6 +40,7 @@ describe "Erf::Erf", :shared => true do
|
|
40
40
|
it "reproduces correct ERF binary data" do
|
41
41
|
t = Erf::Erf.new(StringIO.new @erf)
|
42
42
|
io = StringIO.new
|
43
|
+
io.set_encoding 'BINARY'
|
43
44
|
t.write_to(io)
|
44
45
|
io.seek(0)
|
45
46
|
n = io.read
|
data/spec/field_spec.rb
CHANGED
@@ -20,4 +20,13 @@ describe "Gff::Field" do
|
|
20
20
|
NWN.setting(:resref16, nil)
|
21
21
|
end
|
22
22
|
end
|
23
|
+
|
24
|
+
describe ":void" do
|
25
|
+
it "stores data in binary" do
|
26
|
+
gff = Gff::Struct.new do |root|
|
27
|
+
root.add_void 'Test', "\xde\xad\xbe\xef"
|
28
|
+
end.to_gff
|
29
|
+
gff.index("\xde\xad\xbe\xef").should_not be_nil
|
30
|
+
end
|
31
|
+
end
|
23
32
|
end
|
data/spec/gff_spec.rb
CHANGED
@@ -20,8 +20,7 @@ describe "Gff.read/write API" do
|
|
20
20
|
:yaml => %w{yml yaml},
|
21
21
|
:json => %w{json},
|
22
22
|
:nxml => %w{nxml},
|
23
|
-
:kivinen => %w{k kivinen}
|
24
|
-
:marshal => %w{marshal}
|
23
|
+
:kivinen => %w{k kivinen}
|
25
24
|
}.each {|expect, arr|
|
26
25
|
arr.each {|ext|
|
27
26
|
it "guesses the file format #{expect} for extension #{ext} correctly" do
|
data/spec/key_spec.rb
CHANGED