glowstone 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +57 -0
- data/Rakefile +2 -0
- data/glowstone.gemspec +19 -0
- data/lib/glowstone.rb +12 -0
- data/lib/glowstone/packets.rb +35 -0
- data/lib/glowstone/server.rb +57 -0
- data/lib/glowstone/version.rb +3 -0
- metadata +72 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Tom Heinan
|
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,57 @@
|
|
1
|
+
# Glowstone
|
2
|
+
|
3
|
+
This tiny gem implements the [GameSpy query protocol](http://int64.org/docs/gamestat-protocols/gamespy2.html) to access pertinent real-time information hidden away inside your Minecraft server. You give Glowstone your server info, and Glowstone gives you:
|
4
|
+
- which players are currently online
|
5
|
+
- the base map name and default gamemode
|
6
|
+
- what plugins you're running
|
7
|
+
- even more stuff you probably don't care about!
|
8
|
+
|
9
|
+
All credit goes to [Dinnerbone](http://dinnerbone.com/) for his [excellent post](http://dinnerbone.com/blog/2011/10/14/minecraft-19-has-rcon-and-query/) on the inner workings of the protocol. Check out his Python implementation [here](https://github.com/Dinnerbone/mcstatus).
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'glowstone'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install glowstone
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Glowstone's interface is super simple. Just instantiate yourself a new server object, like so:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
my_server = Glowstone::Server.new "minecraft.tomheinan.com"
|
31
|
+
```
|
32
|
+
|
33
|
+
... and Glowstone will whip you up a server object full of all that delicious realtime data you've been craving:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
=> #<Glowstone::Server:0x007ffe250099b8 @host="minecraft.tomheinan.com", @port=25565, @timeout=3, @socket=#<UDPSocket:fd 8>, @motd="Welcome to Arkenfall!", @gamemode="SMP", @version="1.2.5", @plugins=["CraftBukkit on Bukkit 1.2.5-R4.1-MCPC-SNAPSHOT: mod_MinecraftForge ForgeMod", "AdminCmd 6.0.1 (BUILD 01.06.2012 @ 10:41:06)", "WorldEdit 5.3", "ExtraBiomes XL ForgeMod", "WorldGuard 5.5.3", "PermissionsBukkit 1.6"], @map_name="arkenfall", @num_players=1, @max_players=16, @players=["tomheinan"]>
|
37
|
+
```
|
38
|
+
|
39
|
+
And that's all there is to it! No fancy bukkit plugins or server-side scripts required. If your server object is particularly long-lived and you find yourself wanting to refresh its data, just do `my_server.refresh` and it'll pull down the latest information for you.
|
40
|
+
|
41
|
+
## Troubleshooting
|
42
|
+
|
43
|
+
**Help! I'm not receiving any data!**
|
44
|
+
|
45
|
+
The first thing to do is make sure your server is set up to send it. Check your `server.properties` file and make sure the `enable-query` flag is set to `true`. Then, make sure your server's firewall allows connections on UDP port `25565`. If you've changed that value via the `query.port` flag, then you'll also need to specify it when instantiating Glowstone, like so:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
my_server = Glowstone::Server.new("myminecraftserver.com", 12345)
|
49
|
+
```
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
1. Fork it
|
54
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
55
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
56
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
57
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/glowstone.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/glowstone/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "glowstone"
|
6
|
+
gem.authors = ["Tom Heinan"]
|
7
|
+
gem.email = ["me@tomheinan.com"]
|
8
|
+
gem.description = "Glowstone helps shed light on your Minecraft server!"
|
9
|
+
gem.summary = "This tiny gem implements the Gamespy query protocol to access pertinent real-time information hidden away inside your Minecraft server."
|
10
|
+
gem.homepage = "http://tomheinan.com"
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Glowstone::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "bindata", "~> 1.4.5"
|
19
|
+
end
|
data/lib/glowstone.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "glowstone/version"
|
2
|
+
require "glowstone/server"
|
3
|
+
require "glowstone/packets"
|
4
|
+
|
5
|
+
module Glowstone
|
6
|
+
|
7
|
+
MAGIC_BYTES = [0xFE, 0xFD]
|
8
|
+
REQUEST_BYTE = {:challenge => [0x09], :query => [0x00]}
|
9
|
+
CLIENT_ID = [0x67, 0x6C, 0x6F, 0x77]
|
10
|
+
SOCKET_TIMEOUT = 3 # seconds
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
|
3
|
+
class StatusPacket < BinData::Record
|
4
|
+
endian :big
|
5
|
+
|
6
|
+
int8 :request_type
|
7
|
+
string :client_id, :length => 4
|
8
|
+
|
9
|
+
skip :length => 9 # "splitnum\0"
|
10
|
+
uint8 :world_height # maybe?
|
11
|
+
skip :length => 10 # "\0hostname\0"
|
12
|
+
stringz :motd
|
13
|
+
skip :length => 9 # "gametype\0"
|
14
|
+
stringz :gametype
|
15
|
+
skip :length => 26 # "game_id\0MINECRAFT\0version\0"
|
16
|
+
stringz :version
|
17
|
+
skip :length => 8 # "plugins\0"
|
18
|
+
stringz :plugins
|
19
|
+
skip :length => 4 # "map\0"
|
20
|
+
stringz :map_name
|
21
|
+
skip :length => 11 # "numplayers\0"
|
22
|
+
stringz :num_players
|
23
|
+
skip :length => 11 # "maxplayers\0"
|
24
|
+
stringz :max_players
|
25
|
+
skip :length => 9 # "hostport\0"
|
26
|
+
stringz :port
|
27
|
+
stringz :host_label
|
28
|
+
stringz :host
|
29
|
+
int8 :na1
|
30
|
+
int8 :na2
|
31
|
+
stringz :na3
|
32
|
+
skip :length => 1
|
33
|
+
array :players, :type => :stringz, :initial_length => lambda { num_players.to_i }
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Glowstone
|
4
|
+
|
5
|
+
class Server
|
6
|
+
|
7
|
+
attr_reader :host, :port
|
8
|
+
attr_accessor :timeout
|
9
|
+
|
10
|
+
def initialize(host="localhost", port=25565)
|
11
|
+
@host = host
|
12
|
+
@port = port
|
13
|
+
@timeout = SOCKET_TIMEOUT
|
14
|
+
|
15
|
+
@socket = UDPSocket.new
|
16
|
+
@socket.connect(@host, @port)
|
17
|
+
refresh
|
18
|
+
end
|
19
|
+
|
20
|
+
def refresh
|
21
|
+
response = perform_request(MAGIC_BYTES + REQUEST_BYTE[:query] + CLIENT_ID + get_session_id + CLIENT_ID)
|
22
|
+
status = StatusPacket.read response
|
23
|
+
|
24
|
+
@motd = status.motd
|
25
|
+
@gamemode = status.gametype
|
26
|
+
@version = status.version
|
27
|
+
@plugins = status.plugins.split(/;\s*/)
|
28
|
+
@map_name = status.map_name
|
29
|
+
@num_players = status.num_players.to_i
|
30
|
+
@max_players = status.max_players.to_i
|
31
|
+
@players = status.players
|
32
|
+
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
protected ##################### helper methods and other such shenanigans #
|
37
|
+
|
38
|
+
def get_session_id
|
39
|
+
response = perform_request(MAGIC_BYTES + REQUEST_BYTE[:challenge] + CLIENT_ID)
|
40
|
+
|
41
|
+
# the challenge token comes back as a series of bytes that represent the
|
42
|
+
# integer we want, so we have to convert it to the actual 32bit int
|
43
|
+
[response.slice(5..-2).to_i].pack("l>").bytes.to_a
|
44
|
+
end
|
45
|
+
|
46
|
+
def perform_request(request)
|
47
|
+
@socket.send(request.pack("c*"), 0)
|
48
|
+
packet = if select([@socket], nil, nil, @timeout)
|
49
|
+
@socket.recvfrom(2048)
|
50
|
+
end
|
51
|
+
raise SocketError if packet == nil
|
52
|
+
packet.first
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: glowstone
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tom Heinan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bindata
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.4.5
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.4.5
|
30
|
+
description: Glowstone helps shed light on your Minecraft server!
|
31
|
+
email:
|
32
|
+
- me@tomheinan.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- LICENSE
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- glowstone.gemspec
|
43
|
+
- lib/glowstone.rb
|
44
|
+
- lib/glowstone/packets.rb
|
45
|
+
- lib/glowstone/server.rb
|
46
|
+
- lib/glowstone/version.rb
|
47
|
+
homepage: http://tomheinan.com
|
48
|
+
licenses: []
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.8.23
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: This tiny gem implements the Gamespy query protocol to access pertinent real-time
|
71
|
+
information hidden away inside your Minecraft server.
|
72
|
+
test_files: []
|