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/.gitignore +4 -0
- data/README.rdoc +1 -1
- data/Rakefile +3 -2
- data/VERSION +1 -1
- data/demo-reader.gemspec +30 -7
- data/ext/dm68/README.txt +14 -0
- data/ext/dm68/common.c +797 -0
- data/ext/dm68/common.h +568 -0
- data/ext/dm68/dm68.c +57 -0
- data/ext/dm68/dump.c +196 -0
- data/ext/dm68/extconf.rb +16 -0
- data/ext/dm68/huff.c +542 -0
- data/ext/dm68/huff.h +34 -0
- data/ext/dm68/main.c +175 -0
- data/ext/dm68/main.h +126 -0
- data/ext/dm68/msg.c +1082 -0
- data/ext/dm68/msg.h +114 -0
- data/ext/dm68/parse.c +393 -0
- data/lib/demo-reader.rb +11 -3
- data/lib/demo_reader_defrag.rb +106 -0
- data/lib/demo_reader_warsow.rb +3 -5
- data/test/demo_reader_defrag_dm_68_cpm_test.rb +29 -0
- data/test/demo_reader_defrag_dm_68_vq3_test.rb +29 -0
- data/test/fixtures/defrag/dm_68/cpm/pornchronostar_mdf.cpm_00.49.216_tyaz.germany.dm_68 +0 -0
- data/test/fixtures/defrag/dm_68/cpm/puremotion_df.cpm_00.10.600_eS-Rody.russia.dm_68 +0 -0
- data/test/fixtures/defrag/dm_68/vq3/runkull2_df.vq3_01.05.904_XunderBIRD.Germany.dm_68 +0 -0
- data/test/fixtures/defrag/dm_68/vq3/un-dead029_df.vq3_00.16.912_uN-DeaD!WiNTeR.ru.dm_68 +0 -0
- metadata +43 -9
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
|
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
|
+
|
data/lib/demo_reader_warsow.rb
CHANGED
@@ -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
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
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
|
-
|
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-
|
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.
|
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
|