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 CHANGED
@@ -43,6 +43,6 @@ Usage is simple: just pass all old .yml files to the script, it will convert the
43
43
  in-place (read: make a backup!).
44
44
 
45
45
  This uses nwn-gff-convert and nwn-gff, so all environment variables are taken into
46
- consideration. You will want to point NWN_LIB_INFER_DATA_FILE to something useful.
46
+ consideration.
47
47
 
48
48
  Backup and testing is ADVISED!
data/CHANGELOG CHANGED
@@ -164,4 +164,42 @@ Bernhard Stoeckner (14):
164
164
  Scripting: ask: fix return value of hash and arrays
165
165
  TwoDA: add disclaimer for Cache references
166
166
  TwoDA: add Table#[], Table#[]=
167
-
167
+ 0.4.5-rel
168
+
169
+ === 0.4.6
170
+ Bernhard Stoeckner <elven@swordcoast.net> (26):
171
+ bin/nwn-dsl: always print backtraces
172
+ tests: add rspec stub for later test introduction
173
+ Field: complete valid_for?, add checks in readers, add rspec
174
+ Field: #path prints proper list indices
175
+ ResourceManager: generic implementation as per bioware docs
176
+ TwoDA: read 2da header with arbitary spaces between magic and version
177
+ TwoDA: make id mismatch parsing more robust
178
+ TwoDA: nwn does not fill in missing row IDs
179
+ TwoDA: fix typo preventing #to_2da with NWN_LIB_2DA_NEWLINE absent
180
+ TwoDA: only print to $stderr when -d/$DEBUG is set
181
+ TwoDA: do not raise error on misshaped ID column, add documentation
182
+ TwoDA: do not compact multiple nonquoted cells in last column
183
+ TwoDA: add specs
184
+ Erf: skip over lid and strz to read locstrs correctly
185
+ Erf: seek to offsets instead of depending on constants, handle IOErrors
186
+ Erf: add specs
187
+ Tlk: fix reading last strref in a tlk
188
+ Tlk: add specs
189
+ Cexolocstr: add specs
190
+ Struct: .new accepts a block
191
+ Struct: add specs
192
+ Gff: add specs
193
+ feature kill: remove type/value inferring, NWN_LIB_INFER_*
194
+ Revert "add env setting NWN_LIB_FILTER_EMPTY_EXOLOCSTR"
195
+ Rakefile/rdoc: use mislav-hanna if available
196
+ update all documentation to reflect current situation
197
+ 0.4.6-rel
198
+
199
+ This release changes a few features; most prominent of all is the
200
+ infer mechanism - it is removed completely for sanity reasons.
201
+
202
+ Also, quite a few bugfixes found their way into this release, thanks
203
+ to the newly-added specs.
204
+
205
+ Please browse the commit log for a full list of changes.
data/CHEATSHEET CHANGED
@@ -1,9 +1,23 @@
1
1
  ==== Convert all item files in the current directory to yaml and back
2
2
 
3
- for x in *.uti; do
4
- nwn-gff-convert -i"$x" -o"$x.yml" -lg -ky
5
- done
3
+ for x in *.uti; do
4
+ nwn-gff -i"$x" -o"$x.yml"
5
+ done
6
6
 
7
- for x in *.uti.yml; do
8
- nwn-gff-convert -i"$x" -o"$(basename $x .yml)" -ly -kg
9
- done
7
+ for x in *.uti.yml; do
8
+ nwn-gff -i"$x" -o"$(basename $x .yml)"
9
+ done
10
+
11
+ ==== A Makefile that rebuilds only changed resources
12
+
13
+ This can be done with a GNU Makefile too, with the added benefit that
14
+ it will keep track of changes automagically and only rebuild those resources
15
+ that you have changed (saving you a lot of time).
16
+
17
+ yml = $(wildcard *.yml)
18
+ gff = $(basename $(yml))
19
+
20
+ all: $(gff)
21
+
22
+ % : %.yml
23
+ nwn-gff -i $< -o $@
data/README CHANGED
@@ -4,36 +4,41 @@ This package provides a library for reading, changing, and writing common file f
4
4
 
5
5
  They should work with NWN2 just as well, since the file format specifications did not change.
6
6
 
7
- === Upgrade from 0.3.6 to 0.4.x
8
7
 
9
- With the release of 0.4.0, the API changed significantly. Previous yaml dumps made with 0.3.x are INCOMPATIBLE, and so are all scripts.
10
- I can't help you with your API bindings, but for your YAML dumps, a converter script has been provided (see BINARIES).
8
+ === Features of nwn-lib
11
9
 
12
- === A word on version numbers
10
+ ==== nwn-lib reads and writes the following file formats (hopefully bug-free!), both with an API and useful command-line tools:
13
11
 
14
- Please consider all version releases below 1.0.0 to be unstable, even though the code is fully functional - further API changes may not be avoidable between major revisions - such as is the case with 0.3 -> 0.4.
12
+ * GFF 3.2 (are, git, gic, dlg, itp, ifo, jrl, fac, ssf, ut*, among others)
13
+ * ERF (mod, hak, erf, among others)
14
+ * 2DA V2.0
15
+ * TLK
15
16
 
16
- === Features of nwn-lib
17
+ ==== nwn-lib can read and write the following representations of GFF data:
17
18
 
18
- * a feature-complete parser and generator of valid GFF V3.2 data
19
- * shell scripts and tools to simplify your life (see BINARIES)
20
19
  * kivinen-style ("gffprint.pl") presentation of data
21
20
  * yaml presentation of data
22
21
  * ruby-native marshalling of gff data
22
+
23
+ ==== Also in the box:
24
+
25
+ * shell scripts and tools to simplify your life (see BINARIES)
23
26
  * extensive developer API
24
27
  * a powerful get-out-of-my-way scripting system for data transformation (see SCRIPTING)
25
- * guessing of field-types and -values for shorter plaintext data dumps (see TYPE_AND_VALUE_INFERRING)
26
28
 
27
- Also in the box:
28
29
 
29
- * a CHEATSHEET showing off some cool tricks
30
- * some gadgetry for working with 2da files
30
+ === Upgrade from 0.3.6 to 0.4.x
31
+
32
+ With the release of 0.4.0, the API changed significantly. Previous yaml dumps made with 0.3.x are INCOMPATIBLE, and so are all scripts.
33
+ I can't help you with your API bindings, but for your YAML dumps, a converter script has been provided (see BINARIES).
34
+
31
35
 
32
36
  === Attention Unicode/UTF-users
33
37
 
34
38
  ruby 1.8 does not support character sets natively, and as such nwn-gff-irb will <b>FAIL</b> to encode non-standard characters properly on non-latin1 shells.
35
39
  This will be worked around in a future release until the release of ruby 1.9, which will provide native charset support.
36
40
 
41
+
37
42
  === Quickstart
38
43
 
39
44
  To use it, simply install the gem (available on rubyforge):
@@ -45,4 +50,16 @@ And do the following in a script of your own devising:
45
50
  require 'rubygems'
46
51
  require 'nwn/all'
47
52
 
53
+ Also, Read BINARIES.
54
+
48
55
  For nwn-lib scripts, see SCRIPTING.
56
+
57
+ For using the developer API, I suggest you start reading NWN::Gff::Struct.
58
+
59
+ === Latest code & developer contact
60
+
61
+ The latest source is available through git[http://git.swordcoast.net/?p=nwn/nwn-lib.git;a=summary].
62
+
63
+ All stable releases are tagged properly.
64
+
65
+ You can reach me via email[mailto:elven@swordcoast.net].
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require "rake"
2
2
  require "rake/clean"
3
3
  require "rake/gempackagetask"
4
- require "rake/rdoctask"
4
+ require "hanna/rdoctask" rescue require "rake/rdoctask"
5
5
  require "fileutils"
6
6
  include FileUtils
7
7
 
@@ -9,13 +9,13 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "nwn-lib"
12
- VERS = "0.4.5"
12
+ VERS = "0.4.6"
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", "DATA_STRUCTURES", "SCRIPTING", "SETTINGS", "TYPE_VALUE_INFERRING", "CHEATSHEET", "CHANGELOG", "COPYING"]
18
+ DOCS = ["README", "BINARIES", "SCRIPTING", "SETTINGS", "CHEATSHEET", "CHANGELOG", "COPYING"]
19
19
 
20
20
  Rake::RDocTask.new do |rdoc|
21
21
  rdoc.rdoc_dir = "rdoc"
data/SETTINGS CHANGED
@@ -1,82 +1,16 @@
1
1
  There are various environment variables you can configure to adjust various parts of nwn-lib.
2
2
 
3
- <b>All of them are optional!</b>
3
+ <b>All of them are optional, and, in fact, can waste your time!</b>
4
4
 
5
5
  Under linux, just add them to your shell environment (usually .bashrc), like so:
6
6
 
7
- export NWN_LIB_INFER_DATA_FILE=/usr/lib/ruby/gems/1.8/gems/nwn-lib-0.4.0/data/gff-common-nwn1.yaml
7
+ export NWN_LIB_FILTER_EMPTY_EXOLOCSTR=1
8
8
 
9
9
 
10
- == NWN_LIB_INFER_DATA_FILE
11
-
12
- The path to the type/value inferring data file. See TYPE_VALUE_INFERRING for a definition.
13
-
14
- Please be advised that inferring support for YAML is <b>EXPERIMENTAL</b> and may result in
15
- <b>module and gff file corruption</b>.
16
-
17
- == NWN_LIB_DONT_COMPACT_FIELDS
18
-
19
- Set to non-nil ("1" will do) to prevent nwn-lib from compacting scalar fields into a more-readable
20
- (but still fully parseable) format, if type inferring data is available.
21
-
22
- === Without compacting
23
- ItemList:
24
- value:
25
- - !nwn-lib.elv.es,2008-12/struct
26
- __data_type: UTC/ItemList
27
- __struct_id: 0
28
- InventoryRes: {value: herb053}
29
- PaletteID: {value: 6}
30
- SkillList: [{value: 0}, {value: 0}, {value: 0}, {value: 0}, ...
31
-
32
- === With compacting
33
- ItemList:
34
- - !nwn-lib.elv.es,2008-12/struct
35
- __data_type: UTC/ItemList
36
- InventoryRes: herb053
37
- PaletteID: 6
38
- SkillList: [0, 0, 0, 0, 0, 0, 2, 0, 0, 0 ...
39
-
40
-
41
- == NWN_LIB_DONT_COMPACT_LIST_STRUCTS
42
-
43
- Setting this to non-nil ("1" will do) will prevent nwn-lib from compacting lists that contain
44
- structs, if type inferring data is available.
45
-
46
- === Without compacting
47
- SkillList:
48
- - !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
49
- - !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
50
- - !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
51
- - !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
52
- - !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
53
- - !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
54
- - !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 2}
55
- - !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
56
- ...
57
-
58
- === With compacting
59
- SkillList: [0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, ...
60
-
61
-
62
- == NWN_LIB_CLEAR_KNOWN_VALUES
63
-
64
- Set to non-nil ("1" will do) to make nwn-lib omit fields that resolve to default values
65
- as configured in $NWN_LIB_INFER_DATA_FILE.
66
-
67
- The default is to not omit known-value data fields.
68
-
69
- == NWN_LIB_FILTER_EMPTY_EXOLOCSTR
70
-
71
- Set to non-nil ("1" will do) to make nwn-lib filter out empty exolocstr fields from
72
- input files on reading.
73
-
74
- The default is to keep them as-is.
75
-
76
10
  == NWN_LIB_2DA_LOCATION
77
11
 
78
12
  Set to a path containing all 2da files to initialize the 2da cache. This is needed for
79
- most interactive helpers and a few type infer gizmos.
13
+ most interactive helpers and a few gizmos, and, of course, for TwoDA::Cache.
80
14
 
81
15
  == NWN_LIB_TWODA_NEWLINE
82
16
 
data/bin/nwn-dsl CHANGED
@@ -6,9 +6,6 @@ require 'nwn/all'
6
6
  $backtrace = false
7
7
  OptionParser.new do |o|
8
8
  o.banner = "Usage: nwn-dsl [options] <script> -- [arguments to script]"
9
- o.on "-b", "--backtrace", "Show a backtrace on error" do
10
- $backtrace = true
11
- end
12
9
  end.parse!
13
10
 
14
11
  fail "Not enough arguments (try -h)." unless ARGV.size > 0
@@ -19,9 +16,7 @@ begin
19
16
  NWN::Gff::Scripting.run_script(IO.read($SCRIPT), nil, ARGV)
20
17
  rescue => e
21
18
  $stderr.puts e.message
22
- if $backtrace
23
- $stderr.puts ""
24
- $stderr.puts " " + e.backtrace.join("\n")
25
- end
19
+ $stderr.puts ""
20
+ $stderr.puts " " + e.backtrace.join("\n")
26
21
  exit 1
27
22
  end
data/lib/nwn/all.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'nwn/twoda'
2
+ require 'nwn/res'
2
3
  require 'nwn/gff'
3
4
  require 'nwn/tlk'
4
5
  require 'nwn/erf'
data/lib/nwn/erf.rb CHANGED
@@ -4,123 +4,10 @@ module NWN
4
4
  module Erf
5
5
  ValidTypes = %w{ERF HAK MOD}
6
6
 
7
- Extensions = {
8
- 'res' => 0,
9
- 'bmp' => 1,
10
- 'mve' => 2,
11
- 'tga' => 3,
12
- 'wav' => 4,
13
- 'wfx' => 5,
14
- 'plt' => 6,
15
- 'ini' => 7,
16
- 'mp3' => 8,
17
- 'mpg' => 9,
18
- 'txt' => 10,
19
- 'plh' => 2000,
20
- 'tex' => 2001,
21
- 'mdl' => 2002,
22
- 'thg' => 2003,
23
- 'fnt' => 2005,
24
- 'lua' => 2007,
25
- 'slt' => 2008,
26
- 'nss' => 2009,
27
- 'ncs' => 2010,
28
- 'mod' => 2011,
29
- 'are' => 2012,
30
- 'set' => 2013,
31
- 'ifo' => 2014,
32
- 'bic' => 2015,
33
- 'wok' => 2016,
34
- '2da' => 2017,
35
- 'tlk' => 2018,
36
- 'txi' => 2022,
37
- 'git' => 2023,
38
- 'bti' => 2024,
39
- 'uti' => 2025,
40
- 'btc' => 2026,
41
- 'utc' => 2027,
42
- 'dlg' => 2029,
43
- 'itp' => 2030,
44
- 'btt' => 2031,
45
- 'utt' => 2032,
46
- 'dds' => 2033,
47
- 'bts' => 2034,
48
- 'uts' => 2035,
49
- 'ltr' => 2036,
50
- 'gff' => 2037,
51
- 'fac' => 2038,
52
- 'bte' => 2039,
53
- 'ute' => 2040,
54
- 'btd' => 2041,
55
- 'utd' => 2042,
56
- 'btp' => 2043,
57
- 'utp' => 2044,
58
- 'dft' => 2045,
59
- 'gic' => 2046,
60
- 'gui' => 2047,
61
- 'css' => 2048,
62
- 'ccs' => 2049,
63
- 'btm' => 2050,
64
- 'utm' => 2051,
65
- 'dwk' => 2052,
66
- 'pwk' => 2053,
67
- 'btg' => 2054,
68
- 'utg' => 2055,
69
- 'jrl' => 2056,
70
- 'sav' => 2057,
71
- 'utw' => 2058,
72
- '4pc' => 2059,
73
- 'ssf' => 2060,
74
- 'hak' => 2061,
75
- 'nwm' => 2062,
76
- 'bik' => 2063,
77
- 'ndb' => 2064,
78
- 'ptm' => 2065,
79
- 'ptt' => 2066,
80
- 'bak' => 2067,
81
- 'osc' => 3000,
82
- 'usc' => 3001,
83
- 'trn' => 3002,
84
- 'utr' => 3003,
85
- 'uen' => 3004,
86
- 'ult' => 3005,
87
- 'sef' => 3006,
88
- 'pfx' => 3007,
89
- 'cam' => 3008,
90
- 'lfx' => 3009,
91
- 'bfx' => 3010,
92
- 'upe' => 3011,
93
- 'ros' => 3012,
94
- 'rst' => 3013,
95
- 'ifx' => 3014,
96
- 'pfb' => 3015,
97
- 'zip' => 3016,
98
- 'wmp' => 3017,
99
- 'bbx' => 3018,
100
- 'tfx' => 3019,
101
- 'wlk' => 3020,
102
- 'xml' => 3021,
103
- 'scc' => 3022,
104
- 'ptx' => 3033,
105
- 'ltx' => 3034,
106
- 'trx' => 3035,
107
- 'mdb' => 4000,
108
- 'mda' => 4001,
109
- 'spt' => 4002,
110
- 'gr2' => 4003,
111
- 'fxa' => 4004,
112
- 'fxe' => 4005,
113
- 'jpg' => 4007,
114
- 'pwc' => 4008,
115
- 'ids' => 9996,
116
- 'erf' => 9997,
117
- 'bif' => 9998,
118
- 'key' => 9999,
119
- }.freeze
7
+ # This reads and writes NWN::Resources::Container
8
+ # as valid ERF binary data.
9
+ class Erf < NWN::Resources::Container
120
10
 
121
- class Erf
122
-
123
- attr_accessor :content
124
11
  attr_accessor :localized_strings
125
12
  attr_accessor :description_str_ref
126
13
 
@@ -131,74 +18,16 @@ module NWN
131
18
 
132
19
  # Create a new Erf object, optionally reading a existing file from +io+.
133
20
  def initialize io = nil
134
- @content = []
21
+ super()
135
22
  @localized_strings = {}
136
23
  @io = io
137
24
  @file_type, @file_version = "ERF", "V1.0"
138
25
  @year = Time.now.year
139
26
  @description_str_ref = 0xffffffff
140
- @day_of_year = Time.now.yday # strftime("%j").to_i
27
+ @day_of_year = Time.now.yday
141
28
  read_from io if io
142
29
  end
143
30
 
144
- def add filename
145
- @content << ContentObject.new_from(filename)
146
- end
147
-
148
- def has?(filename)
149
- base = File.basename(filename)
150
- @content.each {|f|
151
- return true if f.filename.downcase == base.downcase
152
- }
153
- return false
154
- end
155
-
156
- class ContentObject
157
- attr_accessor :resref
158
- attr_accessor :res_type
159
- attr_accessor :io
160
- attr_accessor :offset
161
- attr_accessor :size_override
162
-
163
- def self.new_from filename
164
- stat = File.stat(filename)
165
- base = File.basename(filename).split(".")[0..-2].join(".")
166
- ext = File.extname(filename)[1..-1]
167
- res_type = NWN::Erf::Extensions[ext] or raise ArgumentError,
168
- "Not a valid extension: #{ext.inspect} (while packing #{filename})"
169
-
170
- ContentObject.new(base, res_type, filename, 0, stat.size)
171
- end
172
-
173
- def initialize resref, res_type, io = nil, offset = nil, size = nil
174
- @resref, @res_type = resref, res_type
175
- @io, @offset = io, offset
176
- @size_override = size
177
- end
178
-
179
- # Get the size in bytes of this object.
180
- def size
181
- @size_override || (@io.is_a?(IO) ? @io.stat.size : File.stat(@io).size)
182
- end
183
-
184
- def get
185
- if @io.is_a?(IO)
186
- @io.seek(@offset) if @offset
187
- @io.read(self.size)
188
- else
189
- IO.read(@io)
190
- end
191
- end
192
-
193
- def filename
194
- @resref + "." + self.extension
195
- end
196
-
197
- def extension
198
- NWN::Erf::Extensions.index(@res_type)
199
- end
200
- end
201
-
202
31
  private
203
32
 
204
33
  def read_from io
@@ -219,42 +48,40 @@ module NWN
219
48
 
220
49
  if @file_version == "V1.0"
221
50
  @filename_length = 16
222
- # elsif version == "V1.1"
223
- # @filename_length = 32
224
51
  else
225
52
  raise IOError, "Invalid erf version: #{@file_version}"
226
53
  end
227
54
 
228
- raise IOError, "key list not after locstr list" unless
229
- offset_to_keys == offset_to_locstr + locstr_size
230
-
231
- raise IOError, "Offset to locstr list is not after header" if
232
- offset_to_locstr != 160
233
-
55
+ @io.seek(offset_to_locstr)
234
56
  locstr = @io.read(locstr_size)
235
- raise IOError, "Cannot read locstr list" unless
236
- locstr.size == locstr_size
237
57
 
238
58
  for lstr in 0...locstr_count do
59
+ raise IOError, "locstr table does not contain enough entries or locstr_size is too small" if
60
+ locstr.nil? || locstr.size < 8
61
+
239
62
  lid, strsz = locstr.unpack("V V")
240
- str = locstr.unpack("a#{strsz}")[0]
241
- $stderr.puts "Expected string size does not match actual string size (want: #{strsz}, got #{str.size} of #{str.inspect})" if
242
- strsz != str.size
63
+ str = locstr.unpack("x8 a#{strsz}")[0]
64
+ raise IOError,
65
+ "Expected locstr size does not match actual string size (want: #{strsz}, got #{str.size} of #{str.inspect})" if
66
+ strsz != str.size
67
+
243
68
  @localized_strings[lid] = str
244
69
  locstr = locstr[8 + str.size .. -1]
245
- raise IOError, "locstr table does not contain enough entries (want: #{locstr_count}, got: #{lstr + 1})" if locstr.nil? &&
246
- lstr + 1 < locstr_count
247
70
  end
248
71
 
249
72
  keylist_entry_size = @filename_length + 4 + 2 + 2
73
+ @io.seek(offset_to_keys)
250
74
  keylist = @io.read(keylist_entry_size * entry_count)
75
+ raise IOError, "keylist too short" if keylist.size != keylist_entry_size * entry_count
251
76
  keylist = keylist.unpack("A16 V v v" * entry_count)
252
77
  keylist.each_slice(4) {|resref, res_id, res_type, unused|
253
- @content << ContentObject.new(resref, res_type, @io)
78
+ @content << NWN::Resources::ContentObject.new(resref, res_type, @io)
254
79
  }
255
80
 
256
81
  resourcelist_entry_size = 4 + 4
82
+ @io.seek(offset_to_res)
257
83
  resourcelist = @io.read(resourcelist_entry_size * entry_count)
84
+ raise IOError, "resource list too short" if resourcelist.size != resourcelist_entry_size * entry_count
258
85
  resourcelist = resourcelist.unpack("I I" * entry_count)
259
86
  _index = -1
260
87
  resourcelist.each_slice(2) {|offset, size|