wowlog 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 23fa9df161b2b00445e4683a520d31bc45ca4565
4
+ data.tar.gz: 80b89738db900bbbc15e23f806a9f471d19e0538
5
+ SHA512:
6
+ metadata.gz: 706c78624bd52c03cea003e96f4a878a90cd6b233e32292efb6d0f6f393234a83d45690c4552ebd70984fe475d7aa00f8e748974be67e11c928d41ec05f066ca
7
+ data.tar.gz: 8bf1b59be8198cf441f66edcada09623e55c293b3be889e5eb5ccbbba7d5123124d7d95e213cdf91e2cfeeb9c28c1d5cf8fb0601b8d30f9881877d86738cafc8
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wowlog.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Masayoshi Mizutani
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,39 @@
1
+ # Wowlog
2
+
3
+ Wowlog is Parser Library for World of Warcraft Combat Log to analyze your combat.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'wowlog'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install wowlog
18
+
19
+ ## Usage
20
+
21
+ require 'wowlog'
22
+ psr = Wowlog::Parser.new
23
+ File.open('/path/to/WowCombatLog.txt', 'r') do |fd|
24
+ fd.each do |line|
25
+ ev = psr.parse_line(line)
26
+ puts ev
27
+ # => {"event"=>"SPELL_HEAL", "sourceGUID"=>"0x0300000007F97AFF", "sourceName"=>"Muret", ...}
28
+ end
29
+ end
30
+
31
+
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it ( https://github.com/[my-github-username]/wowlog/fork )
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Copyright (c) 2014 Masayoshi Mizutani <muret@haeena.net>
5
+ # All rights reserved.
6
+ # *
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ # POSSIBILITY OF SUCH DAMAGE.
27
+ #
28
+
29
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
30
+ require 'wowlog'
31
+ require 'pp'
32
+
33
+ psr = Wowlog::Parser.new
34
+
35
+ File.open(ARGV[0], 'r') { |fd|
36
+ out_fd = nil
37
+ fname = nil
38
+ fd.each { |line|
39
+ ev = psr.parse_line(line)
40
+
41
+ if ev['event'] == 'ENCOUNTER_START'
42
+ enc_name = ev['encounterName'].gsub(/\s/, '_')
43
+ fname = "WowCombatLog_#{ev['timestamp']}_#{enc_name}_#{ev['groupSize']}man.txt"
44
+ out_fd = File.open(fname, "w")
45
+ puts "Open: #{fname}"
46
+ end
47
+
48
+ if !(out_fd.nil?)
49
+ out_fd.write(line)
50
+ end
51
+
52
+ if ev['event'] == 'ENCOUNTER_END'
53
+ puts "Close: #{fname}"
54
+ out_fd.close
55
+ out_fd = nil
56
+ end
57
+ }
58
+ }
59
+
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Copyright (c) 2014 Masayoshi Mizutani <muret@haeena.net>
5
+ # All rights reserved.
6
+ # *
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ # POSSIBILITY OF SUCH DAMAGE.
27
+ #
28
+
29
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
30
+ require 'wowlog'
31
+ require 'pp'
32
+
33
+ psr = Wowlog::Parser.new
34
+
35
+ File.open(ARGV[0], 'r') { |fd|
36
+ fd.each { |line|
37
+ ev = psr.parse_line(line)
38
+ begin
39
+ pp ev
40
+ rescue => e
41
+ # ignore
42
+ end
43
+ }
44
+ }
@@ -0,0 +1,485 @@
1
+ #
2
+ # Copyright (c) 2014 Masayoshi Mizutani <muret@haeena.net>
3
+ # All rights reserved.
4
+ # *
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions
7
+ # are met:
8
+ # 1. Redistributions of source code must retain the above copyright
9
+ # notice, this list of conditions and the following disclaimer.
10
+ # 2. Redistributions in binary form must reproduce the above copyright
11
+ # notice, this list of conditions and the following disclaimer in the
12
+ # documentation and/or other materials provided with the distribution.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
+ # POSSIBILITY OF SUCH DAMAGE.
25
+ #
26
+
27
+ require "wowlog/version"
28
+ require 'csv'
29
+ require 'pp'
30
+
31
+ $unit_stat = Hash.new { |h,k| h[k] = 0 }
32
+ $unit_none = 0
33
+
34
+
35
+ module Wowlog
36
+
37
+ #
38
+ # ---------------------------------------------------------
39
+ # Basic class for all column parser
40
+ # ---------------------------------------------------------
41
+ #
42
+
43
+ class ColumnParser
44
+ UNIT_FLAG_MAP = {
45
+ 0x00000001 => 'AFFILIATION_MINE',
46
+ 0x00000002 => 'AFFILIATION_PARTY',
47
+ 0x00000004 => 'AFFILIATION_RAID',
48
+ 0x00000008 => 'AFFILIATION_OUTSIDER',
49
+ 0x00000010 => 'REACTION_FRIENDLY',
50
+ 0x00000020 => 'REACTION_NEUTRAL',
51
+ 0x00000040 => 'REACTION_HOSTILE',
52
+ 0x00000100 => 'CONTROL_PLAYER',
53
+ 0x00000200 => 'CONTROL_NPC',
54
+ 0x00000400 => 'TYPE_PLAYER',
55
+ 0x00000800 => 'TYPE_NPC',
56
+ 0x00001000 => 'TYPE_PET',
57
+ 0x00002000 => 'TYPE_GUARDIAN',
58
+ 0x00004000 => 'TYPE_OBJECT',
59
+ }
60
+
61
+ OBJECT_SPECIAL_MASK = 0xFFFF0000
62
+ UNIT_SPECIAL_FLAG_MAP = {
63
+ 0x00010000 => 'TARGET',
64
+ 0x00020000 => 'FOCUS',
65
+ 0x00040000 => 'MAINTANK',
66
+ 0x00080000 => 'MAINASSIST',
67
+ 0x00100000 => 'RAIDTARGET1',
68
+ 0x00200000 => 'RAIDTARGET2',
69
+ 0x00400000 => 'RAIDTARGET3',
70
+ 0x00800000 => 'RAIDTARGET4',
71
+ 0x01000000 => 'RAIDTARGET5',
72
+ 0x02000000 => 'RAIDTARGET6',
73
+ 0x04000000 => 'RAIDTARGET7',
74
+ 0x08000000 => 'RAIDTARGET8',
75
+ 0x80000000 => 'NONE',
76
+ }
77
+
78
+ SCHOOL_FLAG_MAP = {
79
+ 0x1 => 'Physical',
80
+ 0x2 => 'Holy',
81
+ 0x4 => 'Fire',
82
+ 0x8 => 'Nature',
83
+ 0x10 => 'Frost',
84
+ 0x20 => 'Shadow',
85
+ 0x40 => 'Arcane',
86
+ }
87
+
88
+ PT_MAP = {
89
+ -2 => 'health',
90
+ 0 => 'mana',
91
+ 1 => 'rage',
92
+ 2 => 'focus',
93
+ 3 => 'energy',
94
+ 4 => 'pet happiness',
95
+ 5 => 'runes',
96
+ 6 => 'runic power'
97
+ }
98
+
99
+ def initialize
100
+ @flag_cache = {}
101
+ end
102
+
103
+ def parse_unit_flag(val)
104
+ f = val.hex
105
+ return [] if f == 0
106
+ return @flag_cache[f] unless @flag_cache[f].nil?
107
+
108
+ res = []
109
+ UNIT_FLAG_MAP.each { |k, v| res.push(v) if (f & k) > 0 }
110
+ if (f & OBJECT_SPECIAL_MASK) > 0
111
+ UNIT_SPECIAL_FLAG_MAP.each { |k, v| res.push(v) if (f & k) > 0 }
112
+ end
113
+
114
+ @flag_cache[f] = res
115
+ return res
116
+ end
117
+
118
+ def parse_school_flag(val)
119
+ f = val.hex
120
+ res = SCHOOL_FLAG_MAP.select { |k, v| (f & k) > 0 }
121
+ return res.values
122
+ end
123
+
124
+ def resolv_power_type(pt); return PT_MAP[pt]; end
125
+
126
+
127
+ def int(v); return v.to_i; end
128
+ def parse(cols, obj = {}); return cols, obj; end
129
+ end
130
+
131
+ class EventParser < ColumnParser
132
+ def parse(cols, obj = {})
133
+ obj['event'] = cols.shift
134
+ return cols, obj
135
+ end
136
+ end
137
+
138
+ class EncountEvent < EventParser
139
+ def parse(cols, obj); end
140
+ end
141
+
142
+ class ActionEvent < EventParser
143
+ def parse(cols, obj)
144
+ cols, obj = super(cols, obj)
145
+ obj['sourceGUID'] = cols.shift
146
+ obj['sourceName'] = cols.shift
147
+ obj['sourceFlags'] = parse_unit_flag(cols.shift)
148
+ obj['sourceFlags2'] = parse_unit_flag(cols.shift)
149
+ obj['destGUID'] = cols.shift
150
+ obj['destName'] = cols.shift
151
+ obj['destFlags'] = parse_unit_flag(cols.shift)
152
+ obj['destFlags2'] = parse_unit_flag(cols.shift)
153
+ return cols, obj
154
+ end
155
+ end
156
+
157
+ #
158
+ # ---------------------------------------------------------
159
+ # Prefix Parser Set
160
+ # ---------------------------------------------------------
161
+ #
162
+
163
+ class SpellParser < ActionEvent
164
+ def parse(cols, obj)
165
+ cols, obj = super(cols, obj)
166
+ obj['spellId'] = cols.shift
167
+ obj['spellName'] = cols.shift
168
+ obj['spellSchool'] = parse_school_flag(cols.shift)
169
+ return cols, obj
170
+ end
171
+ end
172
+
173
+ class SwingParser < ActionEvent
174
+ def parse(cols, obj); return super(cols, obj); end
175
+ end
176
+
177
+ class EnvParser < ActionEvent
178
+ def parse(cols, obj)
179
+ cols, obj = super(cols, obj)
180
+ obj['environmentalType'] = cols.shift
181
+ return cols, obj
182
+ end
183
+ end
184
+
185
+ #
186
+ # ---------------------------------------------------------
187
+ # Suffix Parser Set
188
+ # ---------------------------------------------------------
189
+ #
190
+
191
+ class DamageParser < ColumnParser
192
+ def parse(cols, obj)
193
+ cols, obj = super(cols, obj)
194
+ cols.shift(8) # shift 8 columns because unknown parameters
195
+
196
+ obj['amount'] = int(cols.shift)
197
+ obj['overkill'] = cols.shift
198
+ obj['school'] = parse_school_flag(cols.shift)
199
+ obj['resisted'] = int(cols.shift)
200
+ obj['blocked'] = int(cols.shift)
201
+ obj['absorbed'] = int(cols.shift)
202
+ obj['critical'] = (cols.shift != 'nil')
203
+ obj['glancing'] = (cols.shift != 'nil')
204
+ obj['crushing'] = (cols.shift != 'nil')
205
+ return cols, obj
206
+ end
207
+ end
208
+
209
+ class MissParser < ColumnParser
210
+ def parse(cols, obj)
211
+ cols, obj = super(cols, obj)
212
+ obj['missType'] = cols.shift
213
+ obj['isOffHand'] = cols.shift if cols.size > 0
214
+ obj['amountMissed'] = cols.shift if cols.size > 0
215
+ return cols, obj
216
+ end
217
+ end
218
+
219
+ class HealParser < ColumnParser
220
+ def parse(cols, obj)
221
+ cols, obj = super(cols, obj)
222
+ cols.shift(8) # shift 8 columns because unknown parameters
223
+
224
+ obj['amount'] = int(cols[0])
225
+ obj['overhealing'] = int(cols[1])
226
+ obj['absorbed'] = int(cols[2])
227
+ obj['critical'] = (cols[3] != 'nil')
228
+ cols.shift(4)
229
+ return cols, obj
230
+ end
231
+ end
232
+
233
+ class EnergizeParser < ColumnParser
234
+ def parse(cols, obj)
235
+ cols, obj = super(cols, obj)
236
+ cols.shift(8) # shift 8 columns because unknown parameters
237
+
238
+ obj['amount'] = int(cols[0])
239
+ obj['powerType'] = resolv_power_type(cols[1])
240
+ cols.shift(2)
241
+ return cols, obj
242
+ end
243
+ end
244
+
245
+ class DrainParser < ColumnParser
246
+ def parse(cols, obj)
247
+ cols, obj = super(cols, obj)
248
+ obj['amount'] = int(cols[0])
249
+ obj['powerType'] = resolv_power_type(cols[1])
250
+ obj['extraAmount'] = int(cols[2])
251
+ cols.shift(3)
252
+ return cols, obj
253
+ end
254
+ end
255
+
256
+ class LeechParser < ColumnParser
257
+ def parse(cols, obj)
258
+ cols, obj = super(cols, obj)
259
+ obj['amount'] = int(cols[0])
260
+ obj['powerType'] = resolv_power_type(cols[1])
261
+ obj['extraAmount'] = int(cols[2])
262
+ cols.shift(3)
263
+ return cols, obj
264
+ end
265
+ end
266
+
267
+ class SpellBlockParser < ColumnParser
268
+ def parse(cols, obj)
269
+ cols, obj = super(cols, obj)
270
+ obj['extraSpellID'] = cols[0]
271
+ obj['extraSpellName'] = cols[1]
272
+ obj['extraSchool'] = parse_school_flag(cols[2])
273
+ cols.shift(3)
274
+
275
+ obj['auraType'] = cols.shift if cols.size > 0
276
+ return cols, obj
277
+ end
278
+ end
279
+
280
+ class ExtraAttackParser < ColumnParser
281
+ def parse(cols, obj)
282
+ cols, obj = super(cols, obj)
283
+ obj['amount'] = int(cols.shift)
284
+ return cols, obj
285
+ end
286
+ end
287
+
288
+ class AuraParser < ColumnParser
289
+ def parse(cols, obj)
290
+ cols, obj = super(cols, obj)
291
+ obj['auraType'] = cols.shift
292
+ obj['amount'] = int(cols.shift) if cols.size > 0
293
+ obj['auraExtra1'] = cols.shift if cols.size > 0
294
+ obj['auraExtra2'] = cols.shift if cols.size > 0
295
+ return cols, obj
296
+ end
297
+ end
298
+
299
+ class AuraDoseParser < ColumnParser
300
+ def parse(cols, obj)
301
+ cols, obj = super(cols, obj)
302
+ obj['auraType'] = cols.shift
303
+ obj['powerType'] = resolv_power_type(cols.shift) if cols.size > 0
304
+ return cols, obj
305
+ end
306
+ end
307
+
308
+ class AuraBrokenParser < ColumnParser
309
+ def parse(cols, obj)
310
+ cols, obj = super(cols, obj)
311
+ obj['extraSpellID'] = cols.shift
312
+ obj['extraSpellName'] = cols.shift
313
+ obj['extraSchool'] = parse_school_flag(cols.shift)
314
+ obj['auraType'] = cols.shift
315
+ return cols, obj
316
+ end
317
+ end
318
+
319
+ class CastFailedParser < ColumnParser
320
+ def parse(cols, obj)
321
+ cols, obj = super(cols, obj)
322
+ obj['failedType'] = cols.shift
323
+ return cols, obj
324
+ end
325
+ end
326
+
327
+ #
328
+ # ---------------------------------------------------------
329
+ # Special Event Parser Set
330
+ # ---------------------------------------------------------
331
+ #
332
+
333
+ class EnchantParser < ColumnParser
334
+ def parse(cols, obj)
335
+ cols, obj = super(cols, obj)
336
+ obj['spellName'] = cols[0]
337
+ obj['itemID'] = cols[1]
338
+ obj['itemName'] = cols[2]
339
+ cols.shift(3)
340
+ return cols, obj
341
+ end
342
+ end
343
+
344
+
345
+ class EncountParser < EventParser
346
+ def parse(cols, obj)
347
+ cols, obj = super(cols, obj)
348
+ obj['encounterID'] = cols[0]
349
+ obj['encounterName'] = cols[1]
350
+ obj['difficultyID'] = cols[2]
351
+ obj['groupSize'] = cols[3]
352
+ cols.shift(4)
353
+
354
+ obj['success'] = (cols.shift == '1') if cols.size > 0
355
+ return cols, obj
356
+ end
357
+ end
358
+
359
+ class VoidParser < ColumnParser
360
+ def parse(cols, obj); return super(cols, obj); end
361
+ end
362
+
363
+ #
364
+ # ---------------------------------------------------------
365
+ # Main Parser
366
+ # ---------------------------------------------------------
367
+ #
368
+ class Parser
369
+ def initialize
370
+ @ev_prefix = {
371
+ 'SWING' => [SwingParser.new],
372
+ 'SPELL_BUILDING' => [SpellParser.new],
373
+ 'SPELL_PERIODIC' => [SpellParser.new],
374
+ 'SPELL' => [SpellParser.new],
375
+ 'RANGE' => [SpellParser.new],
376
+ 'ENVIRONMENTAL' => [EnvParser.new],
377
+ 'DAMAGE_SHIELD' => [SpellParser.new, DamageParser.new],
378
+ 'DAMAGE_SPLIT' => [SpellParser.new, DamageParser.new],
379
+ 'DAMAGE_SHIELD_MISSED' => [SpellParser.new, MissParser.new],
380
+ 'ENCHANT_APPLIED' => [EnchantParser.new],
381
+ 'ENCHANT_REMOVED' => [EnchantParser.new],
382
+ 'PARTY_KILL' => [VoidParser.new],
383
+ 'UNIT_DIED' => [VoidParser.new],
384
+ 'UNIT_DESTROYED' => [VoidParser.new],
385
+ 'ENCOUNTER_START' => [EncountParser.new],
386
+ 'ENCOUNTER_END' => [EncountParser.new],
387
+ }
388
+
389
+ @ev_suffix = {
390
+ '_DAMAGE' => DamageParser.new,
391
+ '_MISSED' => MissParser.new,
392
+ '_HEAL' => HealParser.new,
393
+ '_ENERGIZE' => EnergizeParser.new,
394
+ '_DRAIN' => DrainParser.new,
395
+ '_LEECH' => LeechParser.new,
396
+ '_INTERRUPT' => SpellBlockParser.new,
397
+ '_DISPEL' => SpellBlockParser.new,
398
+ '_DISPEL_FAILED' => SpellBlockParser.new,
399
+ '_STOLEN' => SpellBlockParser.new,
400
+ '_EXTRA_ATTACKS' => ExtraAttackParser.new,
401
+ '_AURA_APPLIED' => AuraParser.new,
402
+ '_AURA_REMOVED' => AuraParser.new,
403
+ '_AURA_APPLIED_DOSE' => AuraDoseParser.new,
404
+ '_AURA_REMOVED_DOSE' => AuraDoseParser.new,
405
+ '_AURA_REFRESH' => AuraDoseParser.new,
406
+ '_AURA_BROKEN' => AuraParser.new,
407
+ '_AURA_BROKEN_SPELL' => AuraBrokenParser.new,
408
+ '_CAST_START' => nil,
409
+ '_CAST_SUCCESS' => nil,
410
+ '_CAST_FAILED' => CastFailedParser.new,
411
+ '_INSTAKILL' => nil,
412
+ '_DURABILITY_DAMAGE' => nil,
413
+ '_DURABILITY_DAMAGE_ALL' => nil,
414
+ '_CREATE' => nil,
415
+ '_SUMMON' => nil,
416
+ '_RESURRECT' => nil,
417
+ }
418
+ end
419
+
420
+ def parse_cols(cols)
421
+ orig_txt = cols.join(',')
422
+ ev_orig = cols[0]
423
+ event = cols[0]
424
+
425
+ psr_seq = []
426
+ p_psr = @ev_prefix.inject(['', nil]) { |m, (k, v)|
427
+ (event.start_with?(k) and m[0].size < k.size) ? [k, v] : m
428
+ }
429
+ psr_seq += p_psr[1]
430
+
431
+ event = event[(p_psr[0].size)..-1]
432
+ s_psr = @ev_suffix.inject(['', nil]) { |m, (k, v)|
433
+ (event.start_with?(k) and m[0].size < k.size) ? [k, v] : m
434
+ }
435
+ psr_seq << s_psr[1] unless s_psr[1].nil?
436
+
437
+ obj = {}
438
+ psr_seq.each do |psr|
439
+ cols, obj = psr.parse(cols, obj)
440
+ end
441
+
442
+ return obj
443
+ end
444
+
445
+ def parse_line(line)
446
+ terms = line.split(' ')
447
+ raise "Invalid format, '#{line.strip}'" if terms.size < 3
448
+
449
+ # Parse timestamp and adjust error of milli second
450
+ datetime = terms[0..1].join(' ')
451
+ ms = datetime.scan(/\.(\d+)$/)[0][0]
452
+ parsed_ts = Time.parse(datetime)
453
+ ts = parsed_ts.to_i.to_f + (ms.to_f / 1000)
454
+
455
+ # rebuild CSV part
456
+ csv_txt = terms[2..-1].join(' ')
457
+ cols = CSV.parse(csv_txt)[0]
458
+
459
+ # parse CSV part
460
+ obj = parse_cols(cols)
461
+ obj['timestamp'] = ts
462
+ return obj
463
+ end
464
+ end
465
+
466
+ #
467
+ # ---------------------------------------------------------
468
+ # Utilities
469
+ # ---------------------------------------------------------
470
+ #
471
+
472
+ SCHOOL_COLOR = {
473
+ "Physical" => "#FFFF00",
474
+ "Holy" => "#FFE680",
475
+ "Fire" => "#FF8000",
476
+ "Nature" => "#4DFF4D",
477
+ "Frost" => "#80FFFF",
478
+ "Shadow" => "#8080FF",
479
+ "Arcane" => "#FF80FF",
480
+ }
481
+ def resolv_school_color(school)
482
+ return SCHOOL_COLOR[school]
483
+ end
484
+
485
+ end
@@ -0,0 +1,3 @@
1
+ module Wowlog
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wowlog/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wowlog"
8
+ spec.version = Wowlog::VERSION
9
+ spec.authors = ["Masayoshi Mizutani"]
10
+ spec.email = ["muret@haeena.net"]
11
+ spec.summary = %q{World of Warcraft Combat Log Parser}
12
+ spec.description = %q{Wowlog is Parser Library for World of Warcraft Combat Log to analyze your combat.}
13
+ spec.homepage = "https://github.com/m-mizutani/wowlog"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency 'rake', '~> 0'
23
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wowlog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Masayoshi Mizutani
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Wowlog is Parser Library for World of Warcraft Combat Log to analyze
42
+ your combat.
43
+ email:
44
+ - muret@haeena.net
45
+ executables:
46
+ - wl_extract_encount
47
+ - wowlogpp
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - ".gitignore"
52
+ - Gemfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - bin/wl_extract_encount
57
+ - bin/wowlogpp
58
+ - lib/wowlog.rb
59
+ - lib/wowlog/version.rb
60
+ - wowlog.gemspec
61
+ homepage: https://github.com/m-mizutani/wowlog
62
+ licenses:
63
+ - MIT
64
+ metadata: {}
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.2.2
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: World of Warcraft Combat Log Parser
85
+ test_files: []