demoman 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ script: bundle exec rake
5
+ before_install:
6
+ - gem update --system
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # demoman
2
2
 
3
+
4
+ [![Build Status](https://travis-ci.org/webdestroya/demoman.png)](https://travis-ci.org/webdestroya/demoman)
5
+ [![Code Climate](https://codeclimate.com/github/webdestroya/demoman.png)](https://codeclimate.com/github/webdestroya/demoman)
6
+ [![Coverage Status](https://coveralls.io/repos/webdestroya/demoman/badge.png)](https://coveralls.io/r/webdestroya/demoman)
7
+
3
8
  Demoman allows you to extract metadata from Half-Life and Half-Life 2 demo (.dem) files.
4
9
 
5
10
  ## Installation
@@ -14,37 +19,37 @@ And add the gem to your Gemfile:
14
19
 
15
20
  ## Usage
16
21
 
22
+ ```ruby
23
+ # Load a file
24
+ demo_object = Demoman.from_file("test/test.dem")
17
25
 
18
- # Load a file
19
- demo_object = Demoman.from_file("test/test.dem")
20
-
21
- # OR Load from a string
22
- demo_object = Demoman.from_string("##DEMO_DATA##")
26
+ # OR Load from a string
27
+ demo_object = Demoman.from_string("##DEMO_DATA##")
23
28
 
24
29
 
25
- # Server IP Address
26
- puts demo_object.server_address
30
+ # Server IP Address
31
+ puts demo_object.server_address
27
32
 
28
33
 
29
- # Player who recorded the demo
30
- puts demo_object.player_name
34
+ # Player who recorded the demo
35
+ puts demo_object.player_name
31
36
 
32
- # The map being played
33
- puts demo_object.map
37
+ # The map being played
38
+ puts demo_object.map
34
39
 
35
- # The game directory (dod, tf2, ...)
36
- puts demo_object.game_dir
40
+ # The game directory (dod, tf2, ...)
41
+ puts demo_object.game_dir
37
42
 
38
- # The duration of the demo (in seconds)
39
- puts demo_object.duration
43
+ # The duration of the demo (in seconds)
44
+ puts demo_object.duration
40
45
 
41
- # The number of ticks in the demo
42
- puts demo_object.ticks
46
+ # The number of ticks in the demo
47
+ puts demo_object.ticks
43
48
 
44
- # The total number of frames
45
- puts demo_object.frames
49
+ # The total number of frames
50
+ puts demo_object.frames
51
+ ```
46
52
 
47
- </pre>
48
53
 
49
54
 
50
55
  ## Note on Patches/Pull Requests
@@ -57,6 +62,10 @@ And add the gem to your Gemfile:
57
62
  (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
58
63
  * Send me a pull request. Bonus points for topic branches.
59
64
 
65
+ ## License
66
+
67
+ GPLv3
68
+
60
69
  ## Copyright
61
70
 
62
- Copyright (c) 2012 Mitch Dempsey. See LICENSE for details.
71
+ Copyright (c) 2013 Mitch Dempsey. See LICENSE for details.
data/Rakefile CHANGED
@@ -1,11 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
2
3
 
3
- require 'rake/testtask'
4
-
5
- Rake::TestTask.new do |t|
6
- t.libs << 'lib/demoman'
7
- t.test_files = FileList['test/*_test.rb']
8
- t.verbose = true
9
- end
10
-
11
- task :default => :test
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/demoman.gemspec CHANGED
@@ -17,4 +17,10 @@ Gem::Specification.new do |gem|
17
17
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.require_paths = ["lib"]
20
+
21
+ gem.add_development_dependency "bundler", "~> 1.3"
22
+ gem.add_development_dependency "rake"
23
+ gem.add_development_dependency "rspec", ">= 2.14"
24
+ gem.add_development_dependency "simplecov"
25
+ gem.add_development_dependency "coveralls"
20
26
  end
@@ -1,36 +1,144 @@
1
1
  module Demoman
2
2
 
3
+ # Parses and provides data about a Half life demo file.
4
+ #
5
+ # @see https://developer.valvesoftware.com/wiki/DEM_Format
3
6
  class DemoFile
4
7
 
5
- attr_reader :server_address, :player_name, :map, :game_dir, :demo_protocol, :network_protocol, :type, :duration, :ticks, :frames, :sign_on_length
6
-
8
+
9
+ # If recorded by a client, then this will be the +IPAddress:Port+ of
10
+ # the server.
11
+ #
12
+ # If recorded by SourceTV then this will be the hostname of the server.
13
+ #
14
+ # @return [String]
15
+ attr_reader :server_address
16
+
17
+ # The name of the player recording the demo.
18
+ #
19
+ # If recorded by SourceTV it will be the name of the SourceTV player.
20
+ #
21
+ # @return [String]
22
+ attr_reader :player_name
23
+
24
+ # The current map on the server
25
+ #
26
+ # @return [String]
27
+ attr_reader :map
28
+
29
+ # The game directory as reported by the server.
30
+ # Examples: +tf+, +dod+, etc.
31
+ #
32
+ # @return [String]
33
+ attr_reader :game_dir
34
+
35
+ # This is the demo protocol version.
36
+ # This is almost always +3+
37
+ #
38
+ # @return [Integer]
39
+ attr_reader :demo_protocol
40
+
41
+ # This is the network protocol, which varies by game.
42
+ #
43
+ # @return [Integer]
44
+ attr_reader :network_protocol
45
+
46
+ # The type of demo. This is usually +HL2DEMO+
47
+ #
48
+ # @return [String]
49
+ attr_reader :type
50
+
51
+ # This is the duration of the demo, in seconds.
52
+ #
53
+ # @return [Float]
54
+ attr_reader :duration
55
+
56
+ # This is the number of server ticks that occurred.
57
+ # This is roughly the tick rate of the server multiplied by the duration.
58
+ #
59
+ # @return [Integer]
60
+ attr_reader :ticks
61
+
62
+ # The number of frames in the demo
63
+ #
64
+ # @return [Integer]
65
+ attr_reader :frames
66
+
67
+ # Length of the signon data (Init for first frame)
68
+ #
69
+ # @return [Integer]
70
+ attr_reader :sign_on_length
71
+
72
+ # Initialize a {DemoFile} object.
73
+ # If the +file+ parameter is provided, then the file is read and parsed.
74
+ #
75
+ # @param file [String] path to a demo file
7
76
  def initialize(file=nil)
8
-
77
+ @demodata = nil
9
78
  unless file.nil?
10
79
  io = File.new(file, "r")
11
80
  data = io.sysread(4096)
12
81
  parse_data data
13
82
  end
14
-
83
+
15
84
  end
16
85
 
86
+ # Parses the demo file header.
87
+ #
88
+ # @param data [String] the raw demo file header data.
89
+ #
90
+ # @return [void]
17
91
  def parse_data(data)
18
- demodata = data.unpack("A8/I/I/A260/A260/A260/A260/f/I/I/I/")
19
- @type = demodata[0]
20
- @demo_protocol = demodata[1]
21
- @network_protocol = demodata[2]
22
- @server_address = demodata[3]
23
- @player_name = demodata[4]
24
- @map = demodata[5]
25
- @game_dir = demodata[6]
92
+ @demodata = nil
93
+ # 0 1 2 3 4 5 6 7 8 9 10
94
+ @demodata = data.unpack("A8/I/I/A260/A260/A260/A260/f/I/I/I/")
95
+ @type = @demodata[0]
96
+ @demo_protocol = @demodata[1]
97
+ @network_protocol = @demodata[2]
98
+ @server_address = @demodata[3]
99
+ @player_name = @demodata[4]
100
+ @map = @demodata[5]
101
+ @game_dir = @demodata[6]
102
+
103
+ @duration = @demodata[7]
104
+ @ticks = @demodata[8]
105
+ @frames = @demodata[9]
106
+ @sign_on_length = @demodata[10]
26
107
 
27
- @duration = demodata[7]
28
- @ticks = demodata[8]
29
- @frames = demodata[9]
30
- @sign_on_length = demodata[10]
31
- nil
108
+ return self
109
+ end
110
+
111
+
112
+ # Returns if the demo has been parsed.
113
+ # *Note:* This does not check if the demo was valid.
114
+ #
115
+ # @see #valid?
116
+ #
117
+ # @since 2.0.2
118
+ #
119
+ # @return [Boolean] true
120
+ def parsed?
121
+ !@demodata.nil?
122
+ end
123
+
124
+ # Returns whether or not the parsed demo is considered valid.
125
+ #
126
+ # *Note:* This is a somewhat _educated_ guess. As long as the
127
+ # values appear to be within a specific range, then the demo
128
+ # is assumed to be valid.
129
+ #
130
+ # @since 2.0.2
131
+ #
132
+ # @return [Boolean]
133
+ def valid?
134
+ return false unless self.parsed?
135
+
136
+ return false unless @demodata.compact.size == 11
137
+
138
+ return false unless @type.eql?('HL2DEMO')
139
+
140
+ true
32
141
  end
33
-
34
142
 
35
143
  end
36
144
 
@@ -1,3 +1,5 @@
1
1
  module Demoman
2
- VERSION = "2.0.1"
2
+
3
+ # The current version of the +demoman+ gem.
4
+ VERSION = "2.0.2"
3
5
  end
data/lib/demoman.rb CHANGED
@@ -1,21 +1,32 @@
1
1
  require "demoman/version"
2
2
  require "demoman/demo_file"
3
3
 
4
+ # Handles static creation of {DemoFile} objects
4
5
  module Demoman
5
-
6
6
 
7
+
8
+ # Create a {DemoFile} object from a file path
9
+ #
10
+ # @param file [String] the path to the +.dem+ file.
11
+ #
12
+ # @return [DemoFile]
7
13
  def self.from_file(file)
8
14
  io = File.new(file, "r")
9
15
  data = io.sysread(4096)
10
-
16
+
11
17
  Demoman.from_string(data)
12
18
  end
13
-
19
+
20
+ # Create a {DemoFile} object from a raw string
21
+ #
22
+ # @param data [String] the raw demo file data
23
+ #
24
+ # @return [DemoFile]
14
25
  def self.from_string(data)
15
26
  demo = DemoFile.new
16
27
  demo.parse_data(data)
17
28
  demo
18
29
  end
19
-
20
-
30
+
31
+
21
32
  end
File without changes
File without changes
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Demoman do
4
+ it "read demo" do
5
+ demoman = Demoman::DemoFile.new("spec/data/test.dem")
6
+
7
+ demoman.server_address.should eq("69.90.189.79:27037")
8
+ demoman.player_name.should eq("Ham Salad[AOF]")
9
+ demoman.map.should eq("dod_jagd")
10
+ demoman.game_dir.should eq("dod")
11
+ demoman.demo_protocol.should eq(3)
12
+ demoman.network_protocol.should eq(7)
13
+ demoman.type.should eq("HL2DEMO")
14
+ demoman.duration.should eq(13.242424964904785)
15
+ demoman.ticks.should eq(874)
16
+ demoman.frames.should eq(390)
17
+ demoman.sign_on_length.should eq(115449)
18
+
19
+ demoman.valid?.should be_true
20
+
21
+ end
22
+
23
+ it "new style load demo" do
24
+
25
+ demoman = Demoman.from_file("spec/data/test.dem")
26
+
27
+ demoman.server_address.should eq("69.90.189.79:27037")
28
+ demoman.player_name.should eq("Ham Salad[AOF]")
29
+ demoman.map.should eq("dod_jagd")
30
+ demoman.game_dir.should eq("dod")
31
+ demoman.demo_protocol.should eq(3)
32
+ demoman.network_protocol.should eq(7)
33
+
34
+ demoman.ticks.should eq(874)
35
+ demoman.frames.should eq(390)
36
+ demoman.sign_on_length.should eq(115449)
37
+
38
+ demoman.valid?.should be_true
39
+ end
40
+
41
+ it "read from string" do
42
+ io = File.new("spec/data/test.dem", "r")
43
+ data = io.sysread(4096)
44
+
45
+ demoman = Demoman.from_string(data)
46
+
47
+ demoman.server_address.should eq("69.90.189.79:27037")
48
+ demoman.player_name.should eq("Ham Salad[AOF]")
49
+ demoman.map.should eq("dod_jagd")
50
+ demoman.game_dir.should eq("dod")
51
+ demoman.demo_protocol.should eq(3)
52
+ demoman.network_protocol.should eq(7)
53
+
54
+ demoman.ticks.should eq(874)
55
+ demoman.frames.should eq(390)
56
+ demoman.sign_on_length.should eq(115449)
57
+
58
+ demoman.valid?.should be_true
59
+
60
+ end
61
+
62
+ it "loads a SourceTV demo" do
63
+
64
+ demoman = Demoman.from_file("spec/data/sourcetv.dem")
65
+
66
+ demoman.server_address.should eq("WebDestroya's Stomping Grounds | MitchDB.com")
67
+ demoman.player_name.should eq("SourceTV Demo")
68
+ demoman.map.should eq("ctf_well")
69
+ demoman.game_dir.should eq("tf")
70
+ demoman.network_protocol.should eq(24)
71
+ demoman.valid?.should be_true
72
+ end
73
+
74
+ it 'loads jibberish' do
75
+ demoman = Demoman.from_string("asdasdasdasdasdasdaasdasdasdass")
76
+ demoman.parsed?.should be_true
77
+ demoman.valid?.should be_false
78
+
79
+ puts demoman.inspect
80
+ end
81
+
82
+ end
@@ -0,0 +1,9 @@
1
+ require "simplecov"
2
+ require "coveralls"
3
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
4
+ SimpleCov::Formatter::HTMLFormatter,
5
+ Coveralls::SimpleCov::Formatter
6
+ ]
7
+ SimpleCov.start { add_filter "/spec/" }
8
+
9
+ require "demoman"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: demoman
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,88 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-27 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2013-09-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '2.14'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ - !ruby/object:Gem::Dependency
63
+ name: simplecov
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: coveralls
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
14
94
  description: Library for reading metadata from Half-Life demo files
15
95
  email:
16
96
  - mrdempsey@gmail.com
@@ -20,6 +100,7 @@ extra_rdoc_files: []
20
100
  files:
21
101
  - .document
22
102
  - .gitignore
103
+ - .travis.yml
23
104
  - Gemfile
24
105
  - LICENSE
25
106
  - README.md
@@ -28,10 +109,10 @@ files:
28
109
  - lib/demoman.rb
29
110
  - lib/demoman/demo_file.rb
30
111
  - lib/demoman/version.rb
31
- - test/data/sourcetv.dem
32
- - test/data/test.dem
33
- - test/demoman_test.rb
34
- - test/test_helper.rb
112
+ - spec/data/sourcetv.dem
113
+ - spec/data/test.dem
114
+ - spec/demoman/demoman_spec.rb
115
+ - spec/spec_helper.rb
35
116
  homepage: http://www.mitchdb.com/
36
117
  licenses:
37
118
  - GPL-3
@@ -47,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
47
128
  version: '0'
48
129
  segments:
49
130
  - 0
50
- hash: -983082405090195856
131
+ hash: 4451018120548773554
51
132
  required_rubygems_version: !ruby/object:Gem::Requirement
52
133
  none: false
53
134
  requirements:
@@ -56,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
137
  version: '0'
57
138
  segments:
58
139
  - 0
59
- hash: -983082405090195856
140
+ hash: 4451018120548773554
60
141
  requirements: []
61
142
  rubyforge_project:
62
143
  rubygems_version: 1.8.23
@@ -64,7 +145,7 @@ signing_key:
64
145
  specification_version: 3
65
146
  summary: Library for reading metadata from Half-Life demo files
66
147
  test_files:
67
- - test/data/sourcetv.dem
68
- - test/data/test.dem
69
- - test/demoman_test.rb
70
- - test/test_helper.rb
148
+ - spec/data/sourcetv.dem
149
+ - spec/data/test.dem
150
+ - spec/demoman/demoman_spec.rb
151
+ - spec/spec_helper.rb
data/test/demoman_test.rb DELETED
@@ -1,67 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- describe Demoman do
4
- it "read demo" do
5
- demoman = Demoman::DemoFile.new("test/data/test.dem")
6
-
7
- assert_equal "69.90.189.79:27037", demoman.server_address
8
- assert_equal "Ham Salad[AOF]", demoman.player_name
9
- assert_equal "dod_jagd", demoman.map
10
- assert_equal "dod", demoman.game_dir
11
- assert_equal 3, demoman.demo_protocol
12
- assert_equal 7, demoman.network_protocol
13
-
14
- assert_equal 874, demoman.ticks
15
- assert_equal 390, demoman.frames
16
- assert_equal 115449, demoman.sign_on_length
17
-
18
- #["HL2DEMO", 3, 7, "69.90.189.79:27037", "Ham Salad[AOF]", "dod_jagd", "dod", 13.2424249649048, 874, 390, 115449]
19
-
20
- end
21
-
22
- it "new style load demo" do
23
-
24
- demoman = Demoman.from_file("test/data/test.dem")
25
-
26
- assert_equal "69.90.189.79:27037", demoman.server_address
27
- assert_equal "Ham Salad[AOF]", demoman.player_name
28
- assert_equal "dod_jagd", demoman.map
29
- assert_equal "dod", demoman.game_dir
30
- assert_equal 3, demoman.demo_protocol
31
- assert_equal 7, demoman.network_protocol
32
-
33
- assert_equal 874, demoman.ticks
34
- assert_equal 390, demoman.frames
35
- assert_equal 115449, demoman.sign_on_length
36
- end
37
-
38
- it "read from string" do
39
- io = File.new("test/data/test.dem", "r")
40
- data = io.sysread(4096)
41
-
42
- demoman = Demoman.from_string(data)
43
-
44
- assert_equal "69.90.189.79:27037", demoman.server_address
45
- assert_equal "Ham Salad[AOF]", demoman.player_name
46
- assert_equal "dod_jagd", demoman.map
47
- assert_equal "dod", demoman.game_dir
48
- assert_equal 3, demoman.demo_protocol
49
- assert_equal 7, demoman.network_protocol
50
-
51
- assert_equal 874, demoman.ticks
52
- assert_equal 390, demoman.frames
53
- assert_equal 115449, demoman.sign_on_length
54
-
55
- end
56
-
57
- it "loads a SourceTV demo" do
58
-
59
- demoman = Demoman.from_file("test/data/sourcetv.dem")
60
-
61
- assert_equal "WebDestroya's Stomping Grounds | MitchDB.com", demoman.server_address
62
- assert_equal "SourceTV Demo", demoman.player_name
63
- assert_equal "ctf_well", demoman.map
64
- assert_equal "tf", demoman.game_dir
65
- end
66
-
67
- end
data/test/test_helper.rb DELETED
@@ -1,3 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'minitest/pride'
3
- require File.expand_path('../../lib/demoman.rb', __FILE__)