demo-reader 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/demo-reader.rb CHANGED
@@ -1,15 +1,17 @@
1
1
  require "demo_reader_warsow"
2
+ require "demo_reader_defrag"
2
3
 
3
4
 
4
5
  class DemoReader
5
6
 
6
7
 
7
- # tries to parse the given demo file in order to detect a warsow demo
8
+ # tries to parse the given demo file in order to detect first a warsow,
9
+ # then a defrag demo
8
10
  #
9
- # @returns an instance of DemoReaderWarsow or nil on failure
11
+ # @returns an instance of DemoReaderWarsow or DemoReaderDefrag or nil on failure
10
12
  #
11
13
  def self.parse(filename)
12
- try_warsow(filename)
14
+ try_warsow(filename) || try_defrag(filename)
13
15
  end
14
16
 
15
17
 
@@ -21,5 +23,11 @@ class DemoReader
21
23
  demo.valid ? demo : nil
22
24
  end
23
25
 
26
+ def self.try_defrag(filename)
27
+ demo = DemoReaderDefrag.new(filename)
28
+
29
+ demo.valid ? demo : nil
30
+ end
31
+
24
32
  end
25
33
 
@@ -0,0 +1,106 @@
1
+ require 'yaml'
2
+ require 'ext/dm68/dm68'
3
+
4
+ class DemoReaderDefrag
5
+ attr_reader :filename, :version, :mapname, :time, :playernames, :scoreboards, :gamemode, :player, :basegamedir, :gamedir, :valid
6
+
7
+
8
+
9
+ def initialize(filename)
10
+ @filename = filename
11
+
12
+ @version = -1
13
+ @mapname = nil
14
+ @time = nil
15
+ @time_in_msec = nil
16
+ @playernames = []
17
+ @scoreboards = []
18
+ @gamemode = nil
19
+ @player = nil
20
+ @basegamedir = nil
21
+ @gamedir = nil
22
+ @valid = false
23
+ @raw = nil
24
+
25
+ self.init()
26
+ end
27
+
28
+
29
+
30
+ def init
31
+ out = DM68.parse_file(@filename)
32
+ @raw = YAML.load(out)
33
+
34
+ raise out unless @raw
35
+
36
+ @version = @raw['server_info']['protocol'].to_i
37
+ @mapname = @raw['server_info']['mapname'].downcase
38
+
39
+ # @playernames = []
40
+ @scoreboards = @raw['prints']
41
+ @basegamedir = @raw['server_info']['gamename']
42
+ @gamedir = @raw['system_info']['fs_game']
43
+
44
+ if @raw['server_info']['defrag_vers'].to_i > 0
45
+ @gamemode = @raw['server_info']['df_promode'].to_i.zero? ? 'vq3' : 'cpm'
46
+ @time = extract_time(@raw['prints'])
47
+ @player = extract_player(@raw['prints'])
48
+ @playernames << @player # just support one player atm
49
+ end
50
+
51
+ @valid = true
52
+ end
53
+
54
+
55
+
56
+ def time_in_msec
57
+ return @time_in_msec unless @time_in_msec.nil?
58
+
59
+ # time str to int
60
+ if @time.kind_of? String
61
+ min, sec, msec = @time.scan(/^([0-9]+):([0-9]+)\.([0-9]+)$/).flatten.map { |x| x.to_i }
62
+ @time_in_msec = msec + sec * 1000 + min * 60 * 1000
63
+ end
64
+ end
65
+
66
+
67
+
68
+ protected
69
+
70
+ # extract player from server prints
71
+ # supports only one player atm otherwise raises an exception
72
+ #
73
+ def extract_player(prints)
74
+ players = prints.inject([]) do |arr,p|
75
+ arr << $1 if p =~ /^(.+)\^7 reached the finish line/
76
+ arr << $1 if p =~ /^Time performed by (.+)\^7 :/
77
+ arr
78
+ end
79
+
80
+ raise "Not only one player was found #{players.inspect}." if players.length != 1
81
+
82
+ players.first
83
+ end
84
+
85
+ # extract time from server prints
86
+ # supports only one time atm otherwise raises an exception
87
+ #
88
+ def extract_time(prints)
89
+ times = prints.inject([]) do |arr,p|
90
+ arr << $1 if p =~ /(\^[0-9]+:[\^:0-9]+)/
91
+ arr
92
+ end
93
+
94
+ raise "Not only one time was found #{times.inspect}." if times.length != 1
95
+
96
+ time = plain_text(times.first)
97
+
98
+ time = "0:#{time}" if time.count(":") < 2
99
+ "%02d:%02d.%03d" % time.split(":").map(&:to_i)
100
+ end
101
+
102
+ def plain_text(text)
103
+ text.gsub(/\^\d/, '')
104
+ end
105
+ end
106
+
@@ -61,7 +61,7 @@ class DemoReaderWarsow
61
61
 
62
62
 
63
63
  # detect scoreboard
64
- #
64
+
65
65
  regex = /scb \"([^\"]+)/
66
66
  matchdata = regex.match(content)
67
67
 
@@ -73,7 +73,7 @@ class DemoReaderWarsow
73
73
 
74
74
 
75
75
  # detect game mode
76
- #
76
+
77
77
  if @version == 11
78
78
  @gamemode = gamemode_wd11(content)
79
79
  else
@@ -100,7 +100,6 @@ class DemoReaderWarsow
100
100
 
101
101
 
102
102
  # detect time by sent message string with time from server
103
- #
104
103
  if ['race', 'unknown'].include?(@gamemode)
105
104
  matches = []
106
105
  regex = /(server record|race finished)(?:!.*(?:current|times\^7 ))?:[0-9:\. ]* (\d+):(\d+)\.(\d+)/im
@@ -120,7 +119,6 @@ class DemoReaderWarsow
120
119
 
121
120
 
122
121
  #detect all player names
123
- #
124
122
  matches = []
125
123
  regex = /cs ([0-9]+) \"\\name\\([^\0]*)\\hand/
126
124
  rest_content = content
@@ -146,7 +144,7 @@ class DemoReaderWarsow
146
144
 
147
145
 
148
146
  # detect player
149
- #
147
+
150
148
  playernames = @playernames.compact.sort.uniq
151
149
  if playernames.length == 1
152
150
  @player = playernames.first
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class DemoReaderDefragDm68CpmTest < Test::Unit::TestCase
4
+
5
+ version = 68
6
+ gamemode = "cpm"
7
+
8
+ [
9
+ %w(pornchronostar_mdf.cpm_00.49.216_tyaz.germany pornchronostar 00:49.216 *tyaz*),
10
+ %w(puremotion_df.cpm_00.10.600_eS-Rody.russia puremotion 00:10.600 ^2eS-Rody)
11
+ ].each do |entry|
12
+
13
+ file, map, time, player = entry
14
+
15
+ define_method "test_warsow_wd#{version}_demo_#{file.gsub(/[^a-z_0-9]/, "_")}" do
16
+ demo = DemoReader.parse("test/fixtures/defrag/dm_#{version}/#{gamemode}/#{file}.dm_#{version}")
17
+
18
+ assert demo.valid
19
+ assert_equal gamemode, demo.gamemode
20
+ assert_equal version, demo.version
21
+ assert_equal map, demo.mapname
22
+ assert_equal player, demo.player
23
+ assert_equal time, demo.time
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class DemoReaderDefragDm68Vq3Test < Test::Unit::TestCase
4
+
5
+ version = 68
6
+ gamemode = "vq3"
7
+
8
+ [
9
+ %w(runkull2_df.vq3_01.05.904_XunderBIRD.Germany runkull2 01:05.904 ^2XunderBIRD),
10
+ %w(un-dead029_df.vq3_00.16.912_uN-DeaD!WiNTeR.ru un-dead029 00:16.912 ^2uN-DeaD!WiNTeR)
11
+ ].each do |entry|
12
+
13
+ file, map, time, player = entry
14
+
15
+ define_method "test_warsow_wd#{version}_demo_#{file.gsub(/[^a-z_0-9]/, "_")}" do
16
+ demo = DemoReader.parse("test/fixtures/defrag/dm_#{version}/#{gamemode}/#{file}.dm_#{version}")
17
+
18
+ assert demo.valid
19
+ assert_equal gamemode, demo.gamemode
20
+ assert_equal version, demo.version
21
+ assert_equal map, demo.mapname
22
+ assert_equal player, demo.player
23
+ assert_equal time, demo.time
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: demo-reader
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - aekym
@@ -9,16 +15,16 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-01-23 00:00:00 +01:00
18
+ date: 2010-08-03 00:00:00 +02:00
13
19
  default_executable:
14
20
  dependencies: []
15
21
 
16
- description: A library to read warsow demo files (.wd8, .wd9, .wd10, .wd11 files)
22
+ description: A library to read warsow demo files (.wd8, .wd9, .wd10, .wd11 files) and q3 demo files (*.dm68)
17
23
  email: me@aekym.com
18
24
  executables: []
19
25
 
20
- extensions: []
21
-
26
+ extensions:
27
+ - ext/dm68/extconf.rb
22
28
  extra_rdoc_files:
23
29
  - LICENSE
24
30
  - README.rdoc
@@ -29,11 +35,31 @@ files:
29
35
  - Rakefile
30
36
  - VERSION
31
37
  - demo-reader.gemspec
38
+ - ext/dm68/README.txt
39
+ - ext/dm68/common.c
40
+ - ext/dm68/common.h
41
+ - ext/dm68/dm68.c
42
+ - ext/dm68/dump.c
43
+ - ext/dm68/extconf.rb
44
+ - ext/dm68/huff.c
45
+ - ext/dm68/huff.h
46
+ - ext/dm68/main.c
47
+ - ext/dm68/main.h
48
+ - ext/dm68/msg.c
49
+ - ext/dm68/msg.h
50
+ - ext/dm68/parse.c
32
51
  - lib/demo-reader.rb
52
+ - lib/demo_reader_defrag.rb
33
53
  - lib/demo_reader_warsow.rb
54
+ - test/demo_reader_defrag_dm_68_cpm_test.rb
55
+ - test/demo_reader_defrag_dm_68_vq3_test.rb
34
56
  - test/demo_reader_test.rb
35
57
  - test/demo_reader_warsow_wd10_race_test.rb
36
58
  - test/demo_reader_warsow_wd11_race_test.rb
59
+ - test/fixtures/defrag/dm_68/cpm/pornchronostar_mdf.cpm_00.49.216_tyaz.germany.dm_68
60
+ - test/fixtures/defrag/dm_68/cpm/puremotion_df.cpm_00.10.600_eS-Rody.russia.dm_68
61
+ - test/fixtures/defrag/dm_68/vq3/runkull2_df.vq3_01.05.904_XunderBIRD.Germany.dm_68
62
+ - test/fixtures/defrag/dm_68/vq3/un-dead029_df.vq3_00.16.912_uN-DeaD!WiNTeR.ru.dm_68
37
63
  - test/fixtures/warsow/wd10/racesow_0.42.b2/dinirun2_racesow_0.42.b2.wd10
38
64
  - test/fixtures/warsow/wd10/racesow_local/boris.wd10
39
65
  - test/fixtures/warsow/wd10/racesow_local/die11.7.wd10
@@ -65,25 +91,33 @@ rdoc_options:
65
91
  require_paths:
66
92
  - lib
67
93
  required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
68
95
  requirements:
69
96
  - - ">="
70
97
  - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
71
101
  version: "0"
72
- version:
73
102
  required_rubygems_version: !ruby/object:Gem::Requirement
103
+ none: false
74
104
  requirements:
75
105
  - - ">="
76
106
  - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
77
110
  version: "0"
78
- version:
79
111
  requirements: []
80
112
 
81
113
  rubyforge_project:
82
- rubygems_version: 1.3.5
114
+ rubygems_version: 1.3.7
83
115
  signing_key:
84
116
  specification_version: 3
85
- summary: A library to read warsow demo files
117
+ summary: A library to read warsow and q3 demo files
86
118
  test_files:
119
+ - test/demo_reader_defrag_dm_68_cpm_test.rb
120
+ - test/demo_reader_defrag_dm_68_vq3_test.rb
87
121
  - test/demo_reader_test.rb
88
122
  - test/demo_reader_warsow_wd10_race_test.rb
89
123
  - test/demo_reader_warsow_wd11_race_test.rb