teeworlds 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 61cf94210fcf13237887b3c092453ff844712ad7
4
+ data.tar.gz: 73a08040c3a9d38aaf5e7ddbd01442a6cb3587bf
5
+ SHA512:
6
+ metadata.gz: a52ce1dc1bb6b94bf1ec0e33d0f54dc87c30cd1a40fccf4dedca6bd45f96885fbd490a8cea938cb3f46751569105b5ce512c80bd26598c3915345a4112bbf232
7
+ data.tar.gz: 7ce80764ea4bcbb11cfcfab309edb4263367b6438cd371b43d419e53832b08a41c019dc46ffc815aef5172e33834213d37cf3cb72e9c89d0cc54ba2f8d0aa252
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ m.rb
3
+ *.swp
4
+ *~
5
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in teeworlds.gemspec
4
+ gemspec
@@ -0,0 +1,44 @@
1
+ # Teeworlds
2
+
3
+ Teeworlds is a multiplayer shooter. This gem allows you to fetch all available game servers and view current status of each.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'teeworlds'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install teeworlds
18
+
19
+ ## Usage
20
+
21
+ ms = Teeworlds::MasterServer.new
22
+
23
+ ms.servers.each do |tw|
24
+ puts "#{tw.server}: #{tw.port}"
25
+ end
26
+
27
+ s = ms.servers.first
28
+ s.connect
29
+
30
+ puts "Server name: #{s.name}, map: #{s.map}, type: #{s.gametype}"
31
+ puts "Num clients: #{s.num_clients}"
32
+ puts "Max clients: #{s.max_clients}"
33
+ puts "Num player: #{s.num_players}"
34
+ puts "Max player: #{s.max_players}"
35
+
36
+ s.players.each { |player| puts player }
37
+
38
+ ## Contributing
39
+
40
+ 1. Fork it
41
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
42
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
43
+ 4. Push to the branch (`git push origin my-new-feature`)
44
+ 5. Create new Pull Request
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ task :default => :spec
5
+ RSpec::Core::RakeTask.new do |t|
6
+ t.rspec_opts = %w(-fp --color)
7
+ end
@@ -0,0 +1,9 @@
1
+ require 'socket'
2
+ require 'timeout'
3
+
4
+ module Teeworlds
5
+ end
6
+
7
+ require 'teeworlds/version'
8
+ require 'teeworlds/masterserver'
9
+ require 'teeworlds/server'
@@ -0,0 +1,33 @@
1
+ module Teeworlds
2
+ class MasterServer
3
+ attr_reader :servers
4
+
5
+ def initialize
6
+ @servers = []
7
+
8
+ 1.upto(4) do |num|
9
+ connect_and_request("master#{num}.teeworlds.com", 8300)
10
+ end
11
+ end
12
+
13
+ private
14
+ def connect_and_request(server, port)
15
+ udp = UDPSocket.new
16
+ udp.connect(server, port)
17
+ udp.send "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xff\x72\x65\x71\x32", 0
18
+
19
+ Timeout.timeout(1) do
20
+ loop { parse_servers udp.recvfrom(1400).first }
21
+ end
22
+ rescue SocketError, Errno::ECONNREFUSED, Timeout::Error
23
+ udp.close
24
+ end
25
+
26
+ def parse_servers(servers_raw)
27
+ servers_raw.bytes.to_a[14..-1].each_slice(18) do |s|
28
+ sp = s.pack('C*').unpack('@12C4n')
29
+ @servers.push Teeworlds::Server.new(server: sp[0..3].join('.'), port: sp.last)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ module Teeworlds
2
+ class Server
3
+ METHODS = [:version, :name, :map, :gametype, :flags, :num_players, :max_players, :num_clients, :max_clients]
4
+ attr_reader :server, :port, :players
5
+
6
+ def initialize(arg)
7
+ @server = arg[:server]
8
+ @port = arg[:port] || 8303
9
+ @players = []
10
+ end
11
+
12
+ def connect
13
+ Timeout.timeout(1) do
14
+ udp = UDPSocket.new
15
+ udp.connect(@server, @port)
16
+ udp.send("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x67\x69\x65\x33\x00", 0)
17
+ create_methods udp.recvfrom(1024).first.split("\x00")[1..-1]
18
+ end
19
+ end
20
+
21
+ private
22
+ def create_methods(recv)
23
+ self.class.class_eval do
24
+ (0...METHODS.size).each do |num|
25
+ define_method(METHODS[num]) { recv[num] }
26
+ end
27
+ end
28
+
29
+ parse_players(recv)
30
+ end
31
+
32
+ def parse_players(recv)
33
+ recv[9..-1].each_slice(5) do |player|
34
+ @players.push(
35
+ name: player[0],
36
+ clan: (player[1].empty?) ? nil : player[1],
37
+ country: (player[2] == '-1') ? nil : player[2].to_i,
38
+ score: player[3].to_i,
39
+ playing?: (player[4] == '1') ? true : false
40
+ )
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module Teeworlds
2
+ VERSION = '1.0.2'
3
+ end
@@ -0,0 +1,182 @@
1
+ require 'teeworlds'
2
+
3
+ describe Teeworlds::MasterServer do
4
+ before do
5
+ master_5_servers = [File.open('spec/fixtures/master_5_servers', 'r:ASCII-8BIT').read]
6
+ @socket_mock = mock
7
+ @socket_mock.should_receive(:connect).exactly(4).times
8
+ @socket_mock.should_receive(:send).exactly(4).times
9
+ @socket_mock.should_receive(:recvfrom).and_return(master_5_servers)
10
+ @socket_mock.should_receive(:recvfrom).at_least(3).times.and_return(['.' * 14])
11
+ @socket_mock.should_receive(:close).exactly(4).times
12
+ UDPSocket.stub(new: @socket_mock)
13
+ end
14
+
15
+ describe '.new' do
16
+ it 'should connect to masterservers 1-4' do
17
+ Teeworlds::MasterServer.new
18
+ end
19
+ end
20
+
21
+ describe '#servers' do
22
+ it 'should be an array of Teeworlds::Server' do
23
+ Teeworlds::MasterServer.new.servers.each do |server|
24
+ server.should be_a(Teeworlds::Server)
25
+ end
26
+ end
27
+
28
+ it 'should return 5 servers' do
29
+ ms = Teeworlds::MasterServer.new
30
+
31
+ [ms.servers[0].server, ms.servers[0].port].should == ['88.198.182.255', 9123]
32
+ [ms.servers[1].server, ms.servers[1].port].should == ['109.73.50.121', 9016]
33
+ [ms.servers[2].server, ms.servers[2].port].should == ['46.38.237.106', 8308]
34
+ [ms.servers[3].server, ms.servers[3].port].should == ['188.233.98.250', 8303]
35
+ [ms.servers[4].server, ms.servers[4].port].should == ['217.29.118.189', 8202]
36
+ end
37
+ end
38
+ end
39
+
40
+ describe Teeworlds::Server do
41
+ context 'when connection failed' do
42
+ it 'raises Errno::ECONNREFUSED if could not connect to server' do
43
+ expect { Teeworlds::Server.new(server: '127.0.0.1', port: 6666).connect }.to raise_error(Errno::ECONNREFUSED)
44
+ end
45
+ end
46
+
47
+ context 'when connection succeeded' do
48
+ before do
49
+ server_3_players = [File.open('spec/fixtures/server_3_players', 'r:ASCII-8BIT').read]
50
+ @socket_mock = mock
51
+ @socket_mock.should_receive(:send).with("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x67\x69\x65\x33\x00", 0)
52
+ @socket_mock.should_receive(:recvfrom).and_return(server_3_players)
53
+ UDPSocket.stub(new: @socket_mock)
54
+ #UDPSocket.should_receive(:new).and_return(@socket_mock)
55
+ end
56
+
57
+ let(:tw_server) { Teeworlds::Server.new(server: '127.0.0.1', port: 8500) }
58
+ let(:tw_server_no_port) { Teeworlds::Server.new(server: '127.0.0.1') }
59
+
60
+ describe '.new' do
61
+ it 'should connect to requested server and port' do
62
+ @socket_mock.should_receive(:connect).with('127.0.0.1', 8500)
63
+ tw_server.connect
64
+ end
65
+
66
+ it "should connect to default port if none is given" do
67
+ @socket_mock.should_receive(:connect).with('127.0.0.1', 8303)
68
+ tw_server_no_port.connect
69
+ end
70
+ end
71
+
72
+ describe 'instance method' do
73
+ before do
74
+ @socket_mock.should_receive(:connect).with('127.0.0.1', 8500)
75
+ tw_server.connect
76
+ end
77
+
78
+ subject { tw_server }
79
+
80
+ describe '#version' do
81
+ it { should respond_to(:version) }
82
+ it 'equals "0.6 trunk, 1.14a"' do
83
+ subject.version.should eql '0.6 trunk, 1.14a'
84
+ end
85
+ end
86
+
87
+ describe '#name' do
88
+ it { should respond_to(:name) }
89
+ it 'equals "FS Server"' do
90
+ subject.name.should eql 'FS Server'
91
+ end
92
+ end
93
+
94
+ describe '#map' do
95
+ it { should respond_to(:map) }
96
+ it 'equals "xyz_ddrace2"' do
97
+ subject.map.should eql 'xyz_ddrace2'
98
+ end
99
+ end
100
+
101
+ describe '#gametype' do
102
+ it { should respond_to(:gametype) }
103
+ it 'equals "DDRace"' do
104
+ subject.gametype.should eql 'DDRace'
105
+ end
106
+ end
107
+
108
+ describe '#flags' do
109
+ it { should respond_to(:flags) }
110
+ it 'equals "0"' do
111
+ subject.flags.should eql '0'
112
+ end
113
+ end
114
+
115
+ describe '#num_players' do
116
+ it { should respond_to(:num_players) }
117
+ it 'equals "3"' do
118
+ subject.num_players.should eql '3'
119
+ end
120
+ end
121
+
122
+ describe '#max_players' do
123
+ it { should respond_to(:max_players) }
124
+ it 'equals "15"' do
125
+ subject.max_players.should eql '15'
126
+ end
127
+ end
128
+
129
+ describe '#num_clients' do
130
+ it { should respond_to(:num_clients) }
131
+ it 'equals "3"' do
132
+ subject.num_clients.should eql '3'
133
+ end
134
+ end
135
+
136
+ describe '#max_clients' do
137
+ it { should respond_to(:max_clients) }
138
+ it 'equals "15"' do
139
+ subject.max_clients.should eql '15'
140
+ end
141
+ end
142
+
143
+ describe '#players' do
144
+ it { should respond_to(:players) }
145
+
146
+ it 'returns an array' do
147
+ subject.players.should be_an(Array)
148
+ end
149
+
150
+ it 'has 3 elements' do
151
+ subject.players.should have(3).items
152
+ end
153
+
154
+ it 'is an array of hashes with name, clan, country, score and playing keys' do
155
+ subject.players[0].should == {
156
+ name: 'Jules',
157
+ clan: 'Gangsta',
158
+ country: 616,
159
+ score: -9999,
160
+ playing?: true
161
+ }
162
+
163
+ subject.players[1].should == {
164
+ name: 'Vincent',
165
+ clan: 'Gangsta',
166
+ country: 276,
167
+ score: -9999,
168
+ playing?: false
169
+ }
170
+
171
+ subject.players[2].should == {
172
+ name: 'Butch',
173
+ clan: 'Boxer',
174
+ country: nil,
175
+ score: -9999,
176
+ playing?: true
177
+ }
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'teeworlds/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "teeworlds"
8
+ spec.version = Teeworlds::VERSION
9
+ spec.authors = ["Maciej Borosiewicz"]
10
+ spec.email = ["m.borosiewicz@gmail.com"]
11
+ spec.description = %q{Teeworlds is a multiplayer shooter. This gem allows you to fetch all available game servers and view current status of each.}
12
+ spec.summary = %q{Classes to parse Teeworlds servers.}
13
+ spec.homepage = "https://github.com/xmbr/teeworlds"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "rspec", "~> 2.13"
21
+ spec.add_development_dependency "rake"
22
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: teeworlds
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Maciej Borosiewicz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.13'
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: Teeworlds is a multiplayer shooter. This gem allows you to fetch all
42
+ available game servers and view current status of each.
43
+ email:
44
+ - m.borosiewicz@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - .rspec
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - lib/teeworlds.rb
55
+ - lib/teeworlds/masterserver.rb
56
+ - lib/teeworlds/server.rb
57
+ - lib/teeworlds/version.rb
58
+ - spec/fixtures/master_5_servers
59
+ - spec/fixtures/server_3_players
60
+ - spec/teeworlds_spec.rb
61
+ - teeworlds.gemspec
62
+ homepage: https://github.com/xmbr/teeworlds
63
+ licenses: []
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.0.3
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: Classes to parse Teeworlds servers.
85
+ test_files:
86
+ - spec/fixtures/master_5_servers
87
+ - spec/fixtures/server_3_players
88
+ - spec/teeworlds_spec.rb