steam_hlds_log_parser 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +69 -0
- data/Rakefile +6 -0
- data/example/example-1.rb +22 -0
- data/example/example-2.rb +24 -0
- data/lib/.DS_Store +0 -0
- data/lib/locales/en.yml +42 -0
- data/lib/locales/fr.yml +42 -0
- data/lib/steam_hlds_log_parser/client.rb +52 -0
- data/lib/steam_hlds_log_parser/displayer.rb +37 -0
- data/lib/steam_hlds_log_parser/handler.rb +103 -0
- data/lib/steam_hlds_log_parser/version.rb +3 -0
- data/lib/steam_hlds_log_parser.rb +16 -0
- data/spec/client_spec.rb +69 -0
- data/spec/displayer_spec.rb +59 -0
- data/spec/handler_spec.rb +138 -0
- data/spec/helper_spec.rb +39 -0
- data/steam_hlds_log_parser.gemspec +31 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 30af9317dcddbf6bebd31d3bb02ff5df117db707
|
4
|
+
data.tar.gz: ab06662bf153b61c2cdab5b9d64209ced673e4e9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 774c7685110aca35822f3642a5a93bbca4bd196f6ddad776345938e29a76df62f3f3b72c866898925f64ed0128a064b8046e9581db9553e6eb4719ea200a07aa
|
7
|
+
data.tar.gz: 5b8c66867b180997d6769fbff9f047346a270bddfce355fc842eafe55c3af72df5a4ab0deaf3f21112704609393682cba8e5b064a9c2e97420e7631d10ece3f9
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
repo_token: WVARN24eiGJQ6GenqWAsqNQEZroHGj2SP
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Thomas VIAL
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Steam Hlds Log Parser
|
2
|
+
|
3
|
+
Creates a server with EventMachine which listens to HLDS logs, parse and returns readable content from your game server.
|
4
|
+
The returned content can be sent to a website, IRC or flowdock for match live streaming.
|
5
|
+
|
6
|
+
Mostly tested on Steam HLDS for Counter-Strike.
|
7
|
+
|
8
|
+
Note : content is sent in english or french at this time. Need i18n contributors!
|
9
|
+
|
10
|
+
## Build Status
|
11
|
+
|
12
|
+
[![Build Status](https://travis-ci.org/tomav/steam_hlds_log_parser.png?branch=master)](https://travis-ci.org/tomav/steam_hlds_log_parser)
|
13
|
+
[![Gem Version](https://badge.fury.io/rb/steam_hlds_log_parser.png)](http://badge.fury.io/rb/steam_hlds_log_parser)
|
14
|
+
[![Coverage Status](https://coveralls.io/repos/tomav/steam_hlds_log_parser/badge.png)](https://coveralls.io/r/tomav/steam_hlds_log_parser)
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
gem 'steam_hlds_log_parser'
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install steam_hlds_log_parser
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
1. Create your own displayer callback `class` which will receive parsed data
|
33
|
+
Ask this `class` to write a file, send content to IRC or flowdock... whatever... and give it as `:displayer` Hash option
|
34
|
+
2. Create a new client on desired IP / Port / Options
|
35
|
+
3. In your HLDS server: `logaddress 127.0.0.1 27035`
|
36
|
+
|
37
|
+
## Example
|
38
|
+
|
39
|
+
require "rubygems"
|
40
|
+
require "steam_hlds_log_parser"
|
41
|
+
|
42
|
+
class Formatter
|
43
|
+
def initialize(data)
|
44
|
+
# will 'puts' the translated content
|
45
|
+
SteamHldsLogParser::Displayer.new(data).display_translation
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
## These are default options
|
51
|
+
options = {
|
52
|
+
:locale => :en,
|
53
|
+
:display_kills => true,
|
54
|
+
:display_actions => true,
|
55
|
+
:display_changelevel => true,
|
56
|
+
:displayer => Formatter
|
57
|
+
}
|
58
|
+
|
59
|
+
parser = SteamHldsLogParser::Client.new("127.0.0.1", 27035, options)
|
60
|
+
parser.start
|
61
|
+
|
62
|
+
|
63
|
+
## Contributing
|
64
|
+
|
65
|
+
1. Fork it
|
66
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
67
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
68
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
69
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "steam_hlds_log_parser"
|
3
|
+
|
4
|
+
class Formatter
|
5
|
+
def initialize(data)
|
6
|
+
# will 'puts' the translated content
|
7
|
+
SteamHldsLogParser::Displayer.new(data).display_translation
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
## These are default options
|
13
|
+
options = {
|
14
|
+
:locale => :en,
|
15
|
+
:display_kills => true,
|
16
|
+
:display_actions => true,
|
17
|
+
:display_changelevel => true,
|
18
|
+
:displayer => Formatter
|
19
|
+
}
|
20
|
+
|
21
|
+
parser = SteamHldsLogParser::Client.new("127.0.0.1", 27035, options)
|
22
|
+
parser.start
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "steam_hlds_log_parser"
|
3
|
+
# require "flowdock"
|
4
|
+
|
5
|
+
## The displayer class that will be used to send content to Flowdock
|
6
|
+
class FlowdockPusher
|
7
|
+
def initialize(data)
|
8
|
+
# Get translated data
|
9
|
+
content = SteamHldsLogParser::Displayer.new(data).get_translation
|
10
|
+
# Source: https://github.com/flowdock/flowdock-api
|
11
|
+
flow = Flowdock::Flow.new(:api_token => "12345678901234567890123456789012", :external_user_name => "HLDS-Live")
|
12
|
+
flow.push_to_chat(:content => content)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
options = {
|
17
|
+
:locale => :fr,
|
18
|
+
:display_kills => true,
|
19
|
+
:display_actions => true,
|
20
|
+
:display_changelevel => true,
|
21
|
+
:displayer => FlowdockPusher
|
22
|
+
}
|
23
|
+
|
24
|
+
SteamHldsLogParser::Client.new("127.0.0.1", 27035, options).start
|
data/lib/.DS_Store
ADDED
Binary file
|
data/lib/locales/en.yml
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
en:
|
2
|
+
# client
|
3
|
+
client_connect: "HLDS connected and sending data"
|
4
|
+
client_disconnect: "HLDS disconnected? No data is received."
|
5
|
+
client_stop: "HLDS Log Parser stopped."
|
6
|
+
# team
|
7
|
+
full_team_name_te: "Terrorist"
|
8
|
+
full_team_name_ct: "Counter-Terrorist"
|
9
|
+
short_team_name_te: "TE"
|
10
|
+
short_team_name_ct: "CT"
|
11
|
+
# round conclusion types
|
12
|
+
all_hostages_rescued: "All hostages have been rescued"
|
13
|
+
bomb_defused: "Bomb has been defused"
|
14
|
+
cts_preventescape: "The CT's have prevented most of the terrorists from escaping"
|
15
|
+
cts_win: "Counter-Terrorists Win"
|
16
|
+
hostages_not_rescued: "Hostages have not been rescued"
|
17
|
+
target_bombed: "Target Successfully Bombed!"
|
18
|
+
target_saved: "Target has been saved"
|
19
|
+
terrorists_escaped: "Terrorists have escaped"
|
20
|
+
terrorists_not_escaped: "Terrorists have not escaped"
|
21
|
+
terrorists_win: "Terrorists Win"
|
22
|
+
vip_assassinated: "The VIP has been assassinated"
|
23
|
+
vip_escaped: "The VIP has escaped"
|
24
|
+
vip_not_escaped: "VIP has not escaped"
|
25
|
+
# user actions
|
26
|
+
begin_bomb_defuse_with_kit: "begin bomb defuse with kit"
|
27
|
+
begin_bomb_defuse_without_kit: "begin bomb defuse without kit"
|
28
|
+
defused_the_bomb: "defused the bomb"
|
29
|
+
dropped_the_bomb: "dropped the bomb"
|
30
|
+
got_the_bomb: "got the bomb"
|
31
|
+
killed_a_hostage: "killed a hostage"
|
32
|
+
planted_the_bomb: "planted the bom"
|
33
|
+
rescued_a_hostage: "rescued a hostage"
|
34
|
+
spawned_with_the_bomb: "spawned with the bomb"
|
35
|
+
touched_a_hostage: "touched a hostage"
|
36
|
+
# events
|
37
|
+
map_ends: "Map ends: %{winner} => %{score}"
|
38
|
+
victory: "[CT] %{score_ct} - %{score_t} [T]"
|
39
|
+
kill: "[%{killer_team}] %{killer} killed [%{killed_team}] %{killed} with %{weapon}"
|
40
|
+
suicide: "%{killed} commited suicide"
|
41
|
+
event: "[%{person_team}] %{person} %{event_i18n}"
|
42
|
+
loading_map: "Loading %{map}"
|
data/lib/locales/fr.yml
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
fr:
|
2
|
+
# client
|
3
|
+
client_connect: "HLDS vient de se connecter et transmets des données."
|
4
|
+
client_disconnect: "HLDS s'est déconnecté ?"
|
5
|
+
client_stop: "HLDS Log Parser stoppé."
|
6
|
+
# team
|
7
|
+
full_team_name_te: "Terroriste"
|
8
|
+
full_team_name_ct: "Anti-Terroriste"
|
9
|
+
short_team_name_te: "TE"
|
10
|
+
short_team_name_ct: "CT"
|
11
|
+
# round conclusion types
|
12
|
+
all_hostages_rescued: "Tous les otages ont été sauvés"
|
13
|
+
bomb_defused: "La bombe a été désamorçée"
|
14
|
+
cts_preventescape: "Les CT ont empéché l'évasion des Terroristes"
|
15
|
+
cts_win: "Victoire des Anti-Terroristes"
|
16
|
+
hostages_not_rescued: "Les otages n'ont pas été sauvés"
|
17
|
+
target_bombed: "La cible a été détruite !"
|
18
|
+
target_saved: "La cible a été protégée"
|
19
|
+
terrorists_escaped: "Les Terroristes se sont échappés"
|
20
|
+
terrorists_not_escaped: "Les Terroristes ne se sont pas échappés"
|
21
|
+
terrorists_win: "Victoire des Terroristes"
|
22
|
+
vip_assassinated: "Le VIP a été assassiné"
|
23
|
+
vip_escaped: "Le VIP s'est échappé"
|
24
|
+
vip_not_escaped: "Le VIP ne s'est pas échappé"
|
25
|
+
# user actions
|
26
|
+
begin_bomb_defuse_with_kit: "commence à désamorcer la bombe avec un kit"
|
27
|
+
begin_bomb_defuse_without_kit: "commence à désamorcer la bombe sans kit"
|
28
|
+
defused_the_bomb: "a désamorcé la bombe"
|
29
|
+
dropped_the_bomb: "a perdu la bombe"
|
30
|
+
got_the_bomb: "a récupéré la bombe"
|
31
|
+
killed_a_hostage: "a tué un otage"
|
32
|
+
planted_the_bomb: "a posé la bombe"
|
33
|
+
rescued_a_hostage: "a sauvé un otage"
|
34
|
+
spawned_with_the_bomb: "a la bombe"
|
35
|
+
touched_a_hostage: "a récupéré un otage"
|
36
|
+
# events
|
37
|
+
map_ends: "Fin de partie : Score des %{winner} => %{score}"
|
38
|
+
victory: "[CT] %{score_ct} - %{score_t} [TE]"
|
39
|
+
kill: "[%{killer_team}] %{killer} a tué [%{killed_team}] %{killed} au %{weapon}"
|
40
|
+
suicide: "%{killed} s'est tué"
|
41
|
+
event: "[%{person_team}] %{person} %{event_i18n}"
|
42
|
+
loading_map: "Chargement de %{map}"
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module SteamHldsLogParser
|
2
|
+
|
3
|
+
class Client
|
4
|
+
|
5
|
+
attr_reader :host, :port, :options
|
6
|
+
|
7
|
+
# Creates a new client
|
8
|
+
#
|
9
|
+
# @host [String] Hostname / IP Address the server will be running
|
10
|
+
# @port [Integer] Port to listen to
|
11
|
+
# @options [Hash] Other options
|
12
|
+
#
|
13
|
+
# ==== Options
|
14
|
+
#
|
15
|
+
# * +locale+ - Set the language of returned content
|
16
|
+
# * +display_kills+ Enable kills / frags detail (default=true)
|
17
|
+
# * +display_actions+ Enable players actions / defuse / ... detail (default=true)
|
18
|
+
# * +display_changelevel+ Enable changelevel (map) display (default=true)
|
19
|
+
# * +displayer+ Class that will be use to display content (default=HldsReturnDisplayer)
|
20
|
+
#
|
21
|
+
def initialize(host, port, options = {})
|
22
|
+
default_options = {
|
23
|
+
:locale => :en,
|
24
|
+
:display_kills => true,
|
25
|
+
:display_actions => true,
|
26
|
+
:display_changelevel => true
|
27
|
+
}
|
28
|
+
@host, @port = host, port
|
29
|
+
@options = default_options.merge(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Starts the client which will receive HLDS logs (using UDP)
|
33
|
+
def start
|
34
|
+
# setting locale
|
35
|
+
I18n.locale = @options[:locale] || I18n.default_locale
|
36
|
+
EM.run {
|
37
|
+
# catch CTRL+C
|
38
|
+
Signal.trap("INT") { EM.stop }
|
39
|
+
Signal.trap("TERM") { EM.stop }
|
40
|
+
# Let's start
|
41
|
+
EM::open_datagram_socket(@host, @port, Handler, @host, @port, @options)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Stops the client
|
46
|
+
def stop
|
47
|
+
puts "## #{@host}:#{@port} => #{I18n.t('client_stop')}"
|
48
|
+
EM::stop_event_loop
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module SteamHldsLogParser
|
2
|
+
|
3
|
+
# Default Displayer
|
4
|
+
#
|
5
|
+
# @data [Hash] Data returned by 'receive_data'
|
6
|
+
#
|
7
|
+
class Displayer
|
8
|
+
|
9
|
+
attr_reader :data
|
10
|
+
|
11
|
+
def initialize(data)
|
12
|
+
@data = data
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return data
|
16
|
+
def get_data
|
17
|
+
return @data
|
18
|
+
end
|
19
|
+
|
20
|
+
# Display data
|
21
|
+
def display_data
|
22
|
+
puts get_data
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return data translation
|
26
|
+
def get_translation
|
27
|
+
return I18n.t(@data[:type], @data[:params]) unless @data[:type].nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Display data translation
|
31
|
+
def display_translation
|
32
|
+
puts get_translation
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module SteamHldsLogParser
|
2
|
+
|
3
|
+
class Handler < EM::Connection
|
4
|
+
|
5
|
+
attr_reader :host, :port, :options
|
6
|
+
|
7
|
+
# Initialize Handler from Client options
|
8
|
+
#
|
9
|
+
# @host [String] Hostname / IP Address the server will be running
|
10
|
+
# @port [Integer] Port to listen to
|
11
|
+
# @options [Hash] Other options
|
12
|
+
#
|
13
|
+
def initialize(host, port, options)
|
14
|
+
@host, @port, @options = host, port, options
|
15
|
+
end
|
16
|
+
|
17
|
+
# Triggered when HLDS connects
|
18
|
+
def post_init
|
19
|
+
puts "## #{@host}:#{@port} => #{I18n.t('client_connect')}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Triggered when HLDS disconnects
|
23
|
+
def unbind
|
24
|
+
puts "## #{@host}:#{@port} => #{I18n.t('client_disconnect')}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get data from Client and parse using Regexp
|
28
|
+
#
|
29
|
+
# * match end of map, with winner team and score
|
30
|
+
# * match the end of round, with score and victory type
|
31
|
+
# * match who killed who with what (frags)
|
32
|
+
# * match suicides
|
33
|
+
# * match who did what (defuse, drop the bomb...)
|
34
|
+
# * match changelevel
|
35
|
+
#
|
36
|
+
# @data [String] Data received by Client from HLDS server (a line of log)
|
37
|
+
#
|
38
|
+
def receive_data(data)
|
39
|
+
|
40
|
+
# L 05/10/2000 - 12:34:56: Team "CT" scored "17" with "0" players
|
41
|
+
if data.gsub(/Team "(.+)" scored "(\d+)" with "(\d+)"/).count > 0
|
42
|
+
winner, winner_score = data.match(/Team "(.+)" scored "(\d+)" with/).captures
|
43
|
+
content = { :type => 'map_ends', :params => { :winner => get_short_team_name(winner), :score => winner_score } }
|
44
|
+
|
45
|
+
# L 05/10/2000 - 12:34:56: Team "CT" triggered "CTs_Win" (CT "3") (T "0")
|
46
|
+
elsif data.gsub(/(: Team ")/).count > 0
|
47
|
+
winner, type, score_ct, score_t = data.match(/Team "([A-Z]+)" triggered "([A-Za-z_]+)" \(CT "(\d+)"\) \(T "(\d+)"\)/i).captures
|
48
|
+
content = { :type => 'victory', :params => { :score_ct => score_ct, :score_t => score_t } }
|
49
|
+
|
50
|
+
# L 05/10/2000 - 12:34:56: "Killer | Player<66><STEAM_ID_LAN><TERRORIST>" killed "Killed | Player<60><STEAM_ID_LAN><CT>" with "ak47"
|
51
|
+
elsif @options[:display_kills] && data.gsub(/(\>" killed ")/).count > 0
|
52
|
+
killer, killer_team, killed, killed_team, weapon = data.match(/"(.+)<\d+><STEAM_ID_LAN><(.+)>" killed "(.+)<\d+><STEAM_ID_LAN><(.+)>" with "(.+)"/i).captures
|
53
|
+
content = { :type => 'kill', :params => { :killer_team => get_short_team_name(killer_team), :killer => killer, :killed_team => get_short_team_name(killed_team), :killed => killed, :weapon => weapon } }
|
54
|
+
|
55
|
+
# L 05/10/2000 - 12:34:56: "Player<66><STEAM_ID_LAN><TERRORIST>" committed suicide with "worldspawn" (world)
|
56
|
+
elsif @options[:display_kills] && data.gsub(/>" committed suicide/).count > 0
|
57
|
+
killed = data.match(/: "(.+)<\d+>/).captures.first
|
58
|
+
content = { :type => 'suicide', :params => { :killed => killed } }
|
59
|
+
|
60
|
+
# L 05/10/2000 - 12:34:56: "Killer | Player<66><STEAM_ID_LAN><CT>" triggered "Defused_The_Bomb"
|
61
|
+
elsif @options[:display_actions] && data.gsub(/<STEAM_ID_LAN><.+>" triggered "(.+)"$/).count > 0
|
62
|
+
person, person_team, event = data.match(/: "(.+)<\d+><STEAM_ID_LAN><(.+)>" triggered "(.+)"/i).captures
|
63
|
+
content = { :type => 'event', :params => { :person_team => get_short_team_name(person_team), :person => person, :event_item => event, :event_i18n => I18n.t(event.downcase)} }
|
64
|
+
|
65
|
+
# L 05/10/2000 - 12:34:56: Loading map "de_dust2"
|
66
|
+
elsif @options[:display_changelevel] && data.gsub(/: Loading map "(.+)"/).count > 0
|
67
|
+
map = data.match(/: Loading map "(.+)"/i).captures.first
|
68
|
+
content = { :type => 'loading_map', :params => { :map => map } }
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
if @options[:displayer].nil?; return(content) else @options[:displayer].new(content) end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
# Format team name with long format (textual)
|
77
|
+
#
|
78
|
+
# @winner [String] Round winner (+CT+ or +T+) from logs
|
79
|
+
#
|
80
|
+
def get_full_team_name(winner)
|
81
|
+
case winner
|
82
|
+
when "T"
|
83
|
+
return "#{I18n.t('full_team_name_te')}"
|
84
|
+
else
|
85
|
+
return "#{I18n.t('full_team_name_ct')}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Format team name with short format (initials)
|
90
|
+
#
|
91
|
+
# @team [String] Round winner (+CT+ or +TERRORIST+) from logs
|
92
|
+
#
|
93
|
+
def get_short_team_name(team)
|
94
|
+
case team
|
95
|
+
when "TERRORIST"
|
96
|
+
return "#{I18n.t('short_team_name_te')}"
|
97
|
+
else
|
98
|
+
return "#{I18n.t('short_team_name_ct')}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "eventmachine"
|
3
|
+
require "i18n"
|
4
|
+
require "rdoc"
|
5
|
+
|
6
|
+
require "steam_hlds_log_parser/version"
|
7
|
+
require "steam_hlds_log_parser/client"
|
8
|
+
require "steam_hlds_log_parser/handler"
|
9
|
+
require "steam_hlds_log_parser/displayer"
|
10
|
+
|
11
|
+
module SteamHldsLogParser
|
12
|
+
|
13
|
+
I18n.load_path = Dir.glob( File.dirname(__FILE__) + "/locales/*.yml" )
|
14
|
+
I18n.default_locale = :en
|
15
|
+
|
16
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require "helper_spec"
|
2
|
+
|
3
|
+
module SteamHldsLogParser
|
4
|
+
|
5
|
+
describe "SteamHldsLogParser" do
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
@client = Client.new("0.0.0.0", 27035)
|
9
|
+
@options = @client.options
|
10
|
+
@custom_options = custom_options
|
11
|
+
@custom_client = Client.new("127.0.0.1", 27045, @custom_options)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Client" do
|
15
|
+
|
16
|
+
it "raises an exception when parameters are missing" do
|
17
|
+
expect { Client.new }.to raise_error(ArgumentError)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { @client }
|
21
|
+
context "when a 'Client' is created without options"
|
22
|
+
it { should be_an_instance_of Client }
|
23
|
+
it "has a 'host'" do
|
24
|
+
@client.host.should_not be_nil
|
25
|
+
@client.host.should eq("0.0.0.0")
|
26
|
+
end
|
27
|
+
it "has a 'port'" do
|
28
|
+
@client.port.should_not be_nil
|
29
|
+
@client.port.should eq(27035)
|
30
|
+
end
|
31
|
+
it "has a default 'options' Hash" do
|
32
|
+
@client.options.should_not be_nil
|
33
|
+
@client.options.should_not be(nil)
|
34
|
+
@client.options.class.should be(Hash)
|
35
|
+
@client.options.should eq(@options)
|
36
|
+
end
|
37
|
+
|
38
|
+
subject(:custom_client) { @custom_client }
|
39
|
+
context "when custom options are given"
|
40
|
+
it "can get a custom 'options' Hash" do
|
41
|
+
@custom_client.options.should_not be_nil
|
42
|
+
@custom_client.options.class.should be(Hash)
|
43
|
+
@custom_client.options.should eq(@custom_options)
|
44
|
+
@custom_client.options[:displayer].should eq(RSpecDisplayer)
|
45
|
+
@custom_client.options[:locale].should be(:fr)
|
46
|
+
@custom_client.options[:display_kills].should be(false)
|
47
|
+
@custom_client.options[:display_actions].should be(false)
|
48
|
+
@custom_client.options[:display_changelevel].should be(false)
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#start and #stop" do
|
52
|
+
|
53
|
+
context "when 'start' and 'stop' are triggered one after the other"
|
54
|
+
it "starts then stops an eventmachine with appropriate messages" do
|
55
|
+
EM.run {
|
56
|
+
capture_stdout { @client.start }.should eq("## 0.0.0.0:27035 => HLDS connected and sending data\n")
|
57
|
+
EM.add_timer(0.2) {
|
58
|
+
capture_stdout { @client.stop }.should eq("## 0.0.0.0:27035 => HLDS Log Parser stopped.\n")
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "helper_spec"
|
2
|
+
|
3
|
+
module SteamHldsLogParser
|
4
|
+
|
5
|
+
describe "SteamHldsLogParser" do
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
@data = {:type=>"victory", :params=>{:score_ct=>"3", :score_t=>"0"}}
|
9
|
+
@displayer = Displayer.new(@data)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "Displayer" do
|
13
|
+
|
14
|
+
context "when 'data' is missing" do
|
15
|
+
it "raises an exception" do
|
16
|
+
expect { Displayer.new }.to raise_error(ArgumentError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when 'data' is given" do
|
21
|
+
|
22
|
+
it "creates a 'Displayer'" do
|
23
|
+
@displayer.should be_an_instance_of Displayer
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#get_data" do
|
27
|
+
it "returns 'data' given as argument" do
|
28
|
+
@displayer.get_data.should_not be_nil
|
29
|
+
@displayer.get_data.should be(@data)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#display_data" do
|
34
|
+
it "displays 'data' given as argument" do
|
35
|
+
eval(capture_stdout { @displayer.display_data }).should eq(@data)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#get_translation" do
|
40
|
+
it "returns translated 'data' given as argument" do
|
41
|
+
@displayer.get_translation.should_not be_nil
|
42
|
+
@displayer.get_translation.class.should be(String)
|
43
|
+
@displayer.get_translation.should eq("[CT] 3 - 0 [T]")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#display_translation" do
|
48
|
+
it "displays translated 'data' given as argument" do
|
49
|
+
capture_stdout { @displayer.display_translation }.should eq("[CT] 3 - 0 [T]\n")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require "helper_spec"
|
2
|
+
|
3
|
+
module SteamHldsLogParser
|
4
|
+
|
5
|
+
describe "SteamHldsLogParser" do
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
@client = Client.new("0.0.0.0", 27035)
|
9
|
+
@options = @client.options
|
10
|
+
@handler = Handler.new("", "0.0.0.0", 27035, @options)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Handler" do
|
14
|
+
|
15
|
+
context "when parameters are missing" do
|
16
|
+
it "raises an exception" do
|
17
|
+
expect { Handler.new }.to raise_error(ArgumentError)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when parameters are given" do
|
22
|
+
subject { @handler }
|
23
|
+
|
24
|
+
context "when 'host' and 'port' are given"
|
25
|
+
it { should be_an_instance_of Handler }
|
26
|
+
it "has a 'host'" do
|
27
|
+
@handler.host.should_not be_nil
|
28
|
+
@handler.host.should eq("0.0.0.0")
|
29
|
+
end
|
30
|
+
it "has a 'port'" do
|
31
|
+
@handler.port.should_not be_nil
|
32
|
+
@handler.port.should eq(27035)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#post_init" do
|
36
|
+
it "displays a console message when hlds connects" do
|
37
|
+
capture_stdout { @handler.post_init }.should eq("## 0.0.0.0:27035 => HLDS connected and sending data\n")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#unbind" do
|
42
|
+
it "displays a console message when hlds disconnects" do
|
43
|
+
capture_stdout { @handler.unbind }.should eq("## 0.0.0.0:27035 => HLDS disconnected? No data is received.\n")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#receive_data" do
|
48
|
+
|
49
|
+
context "when data is not supported" do
|
50
|
+
it "returns anything" do
|
51
|
+
data = '# L 05/10/2000 - 12:34:56: I am a fake line of log'
|
52
|
+
@handler.receive_data(data).should eq(nil)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when data is 'map_ends'" do
|
57
|
+
it "returns Hash on map_ends" do
|
58
|
+
data = '# L 05/10/2000 - 12:34:56: Team "CT" scored "17" with "0" players"'
|
59
|
+
expected = {:type=>"map_ends", :params=>{:winner=>"CT", :score=>"17"}}
|
60
|
+
@handler.receive_data(data).class.should eq(Hash)
|
61
|
+
@handler.receive_data(data).should eq(expected)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when data is 'victory'" do
|
66
|
+
it "returns Hash on victory" do
|
67
|
+
data = '# L 05/10/2000 - 12:34:56: Team "CT" triggered "CTs_Win" (CT "3") (T "0")'
|
68
|
+
expected = {:type=>"victory", :params=>{:score_ct=>"3", :score_t=>"0"}}
|
69
|
+
@handler.receive_data(data).class.should eq(Hash)
|
70
|
+
@handler.receive_data(data).should eq(expected)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when data is 'killed'" do
|
75
|
+
it "returns Hash on killed" do
|
76
|
+
data = '# L 05/10/2000 - 12:34:56: "Killer | Player<66><STEAM_ID_LAN><TERRORIST>" killed "Killed | Player<60><STEAM_ID_LAN><CT>" with "ak47"'
|
77
|
+
expected = {:type=>"kill", :params => {:killer_team=>"TE", :killer=>"Killer | Player", :killed_team=>"CT", :killed=>"Killed | Player", :weapon=>"ak47"}}
|
78
|
+
@handler.receive_data(data).class.should eq(Hash)
|
79
|
+
@handler.receive_data(data).should eq(expected)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "when data is 'suicide'" do
|
84
|
+
it "returns Hash on suicide" do
|
85
|
+
data = '# L 05/10/2000 - 12:34:56: "Player<66><STEAM_ID_LAN><TERRORIST>" committed suicide with "worldspawn" (world)'
|
86
|
+
expected = {:type=>"suicide", :params=>{:killed=>"Player"}}
|
87
|
+
@handler.receive_data(data).class.should eq(Hash)
|
88
|
+
@handler.receive_data(data).should eq(expected)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when data is 'event'" do
|
93
|
+
it "returns Hash on event" do
|
94
|
+
data = '# L 05/10/2000 - 12:34:56: "Killer | Player<66><STEAM_ID_LAN><CT>" triggered "Defused_The_Bomb"'
|
95
|
+
expected = {:type=>"event", :params=> {:person_team=>"CT", :person=>"Killer | Player", :event_item=>"Defused_The_Bomb", :event_i18n=>"defused the bomb"}}
|
96
|
+
@handler.receive_data(data).class.should eq(Hash)
|
97
|
+
@handler.receive_data(data).should eq(expected)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when data is 'changelevel'" do
|
102
|
+
it "returns Hash on changelevel" do
|
103
|
+
data = '# L 05/10/2000 - 12:34:56: Loading map "de_dust2"'
|
104
|
+
expected = {:type=>"loading_map", :params=>{:map=>"de_dust2"}}
|
105
|
+
@handler.receive_data(data).class.should eq(Hash)
|
106
|
+
@handler.receive_data(data).should eq(expected)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#get_full_team_name" do
|
113
|
+
|
114
|
+
context "when short name is given"
|
115
|
+
it "returns full name" do
|
116
|
+
@handler.get_full_team_name("T").should eq("Terrorist")
|
117
|
+
@handler.get_full_team_name("CT").should eq("Counter-Terrorist")
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "#get_short_team_name" do
|
123
|
+
|
124
|
+
context "when full name is given"
|
125
|
+
it "returns short name" do
|
126
|
+
@handler.get_short_team_name("TERRORIST").should eq("TE")
|
127
|
+
@handler.get_short_team_name("CT").should eq("CT")
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
data/spec/helper_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "simplecov"
|
2
|
+
require "coveralls"
|
3
|
+
require "rspec"
|
4
|
+
|
5
|
+
# Simplecov / Coverall configuration
|
6
|
+
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter "/example/"
|
9
|
+
add_filter "/spec/"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get ouput content of the given block
|
13
|
+
# Source: https://github.com/cldwalker/hirb/blob/master/test/test_helper.rb
|
14
|
+
def capture_stdout(&block)
|
15
|
+
original_stdout = $stdout
|
16
|
+
$stdout = fake = StringIO.new
|
17
|
+
begin
|
18
|
+
yield
|
19
|
+
ensure
|
20
|
+
$stdout = original_stdout
|
21
|
+
end
|
22
|
+
fake.string
|
23
|
+
end
|
24
|
+
|
25
|
+
class RSpecDisplayer
|
26
|
+
end
|
27
|
+
|
28
|
+
require "steam_hlds_log_parser"
|
29
|
+
|
30
|
+
# Returns custom options as a Hash
|
31
|
+
def custom_options
|
32
|
+
options = {
|
33
|
+
:locale => :fr,
|
34
|
+
:display_kills => false,
|
35
|
+
:display_actions => false,
|
36
|
+
:display_changelevel => false,
|
37
|
+
:displayer => RSpecDisplayer
|
38
|
+
}
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'steam_hlds_log_parser/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "steam_hlds_log_parser"
|
8
|
+
spec.version = SteamHldsLogParser::VERSION
|
9
|
+
spec.authors = ["Thomas VIAL"]
|
10
|
+
spec.email = ["github@ifusio.com"]
|
11
|
+
spec.description = %q{Steam HLDS Log Parser receives logs from your Steam game server and parses them in real time to give you usable content for your website, irc channel / flowdock... Works well with Counter-Strike and others Half-life based games.}
|
12
|
+
spec.summary = %q{Steam HLDS Log Parser receives logs from your Steam game server and parses them in real time to give you usable content for your website, irc channel / flowdock... Works well with Counter-Strike and others Half-life based games.}
|
13
|
+
spec.homepage = "https://github.com/tomav/steam_hlds_log_parser"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
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_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_dependency "rake"
|
23
|
+
spec.add_dependency "eventmachine", "~> 1.0.3"
|
24
|
+
spec.add_dependency "i18n"
|
25
|
+
|
26
|
+
spec.add_development_dependency "simplecov"
|
27
|
+
spec.add_development_dependency "coveralls"
|
28
|
+
spec.add_development_dependency "rspec-core"
|
29
|
+
spec.add_development_dependency "rspec"
|
30
|
+
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: steam_hlds_log_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thomas VIAL
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2013-08-13 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
prerelease: false
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: "1.3"
|
22
|
+
type: :runtime
|
23
|
+
version_requirements: *id001
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: rake
|
26
|
+
prerelease: false
|
27
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- &id004
|
30
|
+
- ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id002
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: eventmachine
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.0.3
|
43
|
+
type: :runtime
|
44
|
+
version_requirements: *id003
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: i18n
|
47
|
+
prerelease: false
|
48
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- *id004
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id005
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: simplecov
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- *id004
|
59
|
+
type: :development
|
60
|
+
version_requirements: *id006
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: coveralls
|
63
|
+
prerelease: false
|
64
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- *id004
|
67
|
+
type: :development
|
68
|
+
version_requirements: *id007
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-core
|
71
|
+
prerelease: false
|
72
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- *id004
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id008
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: rspec
|
79
|
+
prerelease: false
|
80
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- *id004
|
83
|
+
type: :development
|
84
|
+
version_requirements: *id009
|
85
|
+
description: Steam HLDS Log Parser receives logs from your Steam game server and parses them in real time to give you usable content for your website, irc channel / flowdock... Works well with Counter-Strike and others Half-life based games.
|
86
|
+
email:
|
87
|
+
- github@ifusio.com
|
88
|
+
executables: []
|
89
|
+
|
90
|
+
extensions: []
|
91
|
+
|
92
|
+
extra_rdoc_files: []
|
93
|
+
|
94
|
+
files:
|
95
|
+
- .coveralls.yml
|
96
|
+
- .gitignore
|
97
|
+
- .rspec
|
98
|
+
- .travis.yml
|
99
|
+
- Gemfile
|
100
|
+
- LICENSE.txt
|
101
|
+
- README.md
|
102
|
+
- Rakefile
|
103
|
+
- example/example-1.rb
|
104
|
+
- example/example-2.rb
|
105
|
+
- lib/.DS_Store
|
106
|
+
- lib/locales/en.yml
|
107
|
+
- lib/locales/fr.yml
|
108
|
+
- lib/steam_hlds_log_parser.rb
|
109
|
+
- lib/steam_hlds_log_parser/client.rb
|
110
|
+
- lib/steam_hlds_log_parser/displayer.rb
|
111
|
+
- lib/steam_hlds_log_parser/handler.rb
|
112
|
+
- lib/steam_hlds_log_parser/version.rb
|
113
|
+
- spec/client_spec.rb
|
114
|
+
- spec/displayer_spec.rb
|
115
|
+
- spec/handler_spec.rb
|
116
|
+
- spec/helper_spec.rb
|
117
|
+
- steam_hlds_log_parser.gemspec
|
118
|
+
homepage: https://github.com/tomav/steam_hlds_log_parser
|
119
|
+
licenses:
|
120
|
+
- MIT
|
121
|
+
metadata: {}
|
122
|
+
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- *id004
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- *id004
|
134
|
+
requirements: []
|
135
|
+
|
136
|
+
rubyforge_project:
|
137
|
+
rubygems_version: 2.0.3
|
138
|
+
signing_key:
|
139
|
+
specification_version: 4
|
140
|
+
summary: Steam HLDS Log Parser receives logs from your Steam game server and parses them in real time to give you usable content for your website, irc channel / flowdock... Works well with Counter-Strike and others Half-life based games.
|
141
|
+
test_files:
|
142
|
+
- spec/client_spec.rb
|
143
|
+
- spec/displayer_spec.rb
|
144
|
+
- spec/handler_spec.rb
|
145
|
+
- spec/helper_spec.rb
|