minecraft 0.0.2 → 0.0.3

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/README.md CHANGED
@@ -29,23 +29,27 @@ Current Features
29
29
  - Give the user an item with a quantity of up to 2560 (by default Minecraft
30
30
  will cap at 64).
31
31
  - Use the item ID or item name. http://minecraftwiki.net/wiki/Data_values
32
+ - !giveall <item> <quantity>
32
33
  - !tp <target_user>
34
+ - !tpall
33
35
  - !nom
34
- - !kit
36
+ - !nomall
37
+ - !kit <group>
35
38
  - Diamond
36
39
  - Gold armour
37
40
  - Armour
38
41
  - Ranged
39
42
  - Nether
40
43
  - Portal
44
+ - !kitall <group>
45
+ - !addtimer <item> <frequency>
46
+ - !deltimer <item>
47
+ - !printtimer
48
+ - !list
41
49
 
42
50
  TODO
43
51
  ----
44
52
 
45
- - Improved error handling.
46
- - Log time users have spent on the server.
47
- - !give timers (give user A an item every X seconds).
48
-
49
53
  Contributors
50
54
  ------------
51
55
 
@@ -1,5 +1,6 @@
1
1
  require "minecraft/tools"
2
2
  require "minecraft/data"
3
+ require "minecraft/commands"
3
4
  require "minecraft/extensions"
4
5
  require "minecraft/server"
5
6
 
@@ -0,0 +1,143 @@
1
+ module Minecraft
2
+ module Commands
3
+ include Data
4
+
5
+ def give(user, *args)
6
+ item, quantity = items_arg(1, args)
7
+ item = resolve_item(item)
8
+
9
+ quantify(user, item, quantity)
10
+ end
11
+
12
+ def validate_kit(group = "")
13
+ return true if KITS.include? group.to_sym
14
+ @server.puts "say #{group} is not a valid kit."
15
+ kitlist
16
+ end
17
+
18
+ def kit(user, group)
19
+ KITS[group.to_sym].each do |item|
20
+ if item.is_a? Array
21
+ @server.puts quantify(user, item.first, item.last)
22
+ else
23
+ @server.puts "give #{user} #{item} 1"
24
+ end
25
+ end
26
+ end
27
+
28
+ def tp(user, target)
29
+ @server.puts "tp #{user} #{target}"
30
+ end
31
+
32
+ def tpall(user, *args)
33
+ @users.each { |u| tp(u, user) }
34
+ end
35
+
36
+ def nom(user)
37
+ @server.puts "give #{user} 322 1"
38
+ end
39
+
40
+ def list(user)
41
+ l = @users.inject("") do |s, u|
42
+ if u == user
43
+ pre = "["
44
+ suf = "]"
45
+ end
46
+ suf = "*" + (suf || "") if is_op? u
47
+ s + "#{", " unless s.empty?}#{pre}#{u}#{suf}"
48
+ end
49
+ @server.puts "say #{l}"
50
+ end
51
+
52
+ def addtimer(user, *args)
53
+ item, duration = items_arg(30, args)
54
+ item = resolve_item(item)
55
+ @timers[user] ||= {}
56
+ @timers[user][item] = duration
57
+ @server.puts "say Timer added for #{user}. Giving #{item} every #{duration} seconds."
58
+ end
59
+
60
+ def deltimer(user, *args)
61
+ item = args.join(" ")
62
+ item = resolve_item(item)
63
+ @timers[user][item] = nil if @timers.has_key? user
64
+ end
65
+
66
+ def printtimer(user)
67
+ @server.puts "say Timer is at #{@counter}."
68
+ end
69
+
70
+ def help(*args)
71
+ @server.puts <<-eof
72
+ say !tp target_user
73
+ say !kit kit_name
74
+ say !give item quantity
75
+ say !nom
76
+ say !list
77
+ say !addtimer item frequency
78
+ say !deltimer item
79
+ eof
80
+ end
81
+
82
+ def kitlist(*args)
83
+ @server.puts "say Kits: #{KITS.keys.join(", ")}"
84
+ end
85
+
86
+ def quantify(user, item, quantity)
87
+ if quantity <= 64
88
+ @server.puts "give #{user} #{item} #{quantity}"
89
+ return
90
+ end
91
+
92
+ quantity = 2560 if quantity > 2560
93
+ full_quantity = (quantity / 64.0).floor
94
+ sub_quantity = quantity % 64
95
+ @server.puts "give #{user} #{item} 64\n" * full_quantity
96
+ @server.puts "give #{user} #{item} #{sub_quantity}" if sub_quantity > 0
97
+ end
98
+
99
+ def items_arg(default, args)
100
+ if args.length == 1
101
+ second = default
102
+ first = args.first
103
+ else
104
+ if args.last.to_i.to_s == args.last # Last argument is an integer.
105
+ second = args.last.to_i
106
+ first = args[0..-2].join(" ")
107
+ else
108
+ second = default
109
+ first = args[0..-1].join(" ")
110
+ end
111
+ end
112
+ return [first, second]
113
+ end
114
+
115
+ def resolve_item(item)
116
+ item.to_i.to_s == item ? item.to_i : DATA_VALUE_HASH[resolve_key(item.downcase)]
117
+ end
118
+
119
+ def resolve_key(key)
120
+ bucket = key[0]
121
+ return key if ITEM_BUCKETS[bucket].include? key
122
+
123
+ puts "Finding #{key} approximate in #{ITEM_BUCKETS[bucket]}"
124
+ shortest_diff = nil
125
+ shortest_key = nil
126
+ ITEM_BUCKETS[bucket].each do |test_key|
127
+ if test_key.length > key.length
128
+ diff = test_key.length - key.length if test_key.index(key)
129
+ else
130
+ diff = key.length - test_key.length if key.index(test_key)
131
+ end
132
+ next if diff.nil?
133
+
134
+ if shortest_diff.nil? or diff < shortest_diff
135
+ shortest_key = test_key
136
+ shortest_diff = diff
137
+ end
138
+ end
139
+
140
+ return shortest_key
141
+ end
142
+ end
143
+ end
@@ -70,7 +70,7 @@ module Minecraft
70
70
  "lava" => "10",
71
71
  "dead shrubs" => "32",
72
72
  "double stone slab" => "43",
73
- "furnace " => "61",
73
+ "furnace" => "61",
74
74
  "fence" => "85",
75
75
  "stationary lava " => "11",
76
76
  "piston" => "33",
@@ -246,5 +246,12 @@ module Minecraft
246
246
  "saddle" => "329",
247
247
  "cocoa beans" => "351"
248
248
  }
249
+
250
+ ITEM_BUCKETS = {}
251
+ DATA_VALUE_HASH.each_key do |key|
252
+ bucket = key[0]
253
+ ITEM_BUCKETS[bucket] ||= []
254
+ ITEM_BUCKETS[bucket] << key
255
+ end
249
256
  end
250
257
  end
@@ -1,31 +1,108 @@
1
+ require "json/pure"
2
+
1
3
  module Minecraft
2
4
  class Extensions
3
- include Data
5
+ include Commands
4
6
 
5
- def initialize
6
- @ops = File.readlines("ops.txt").map { |s| s.chop }
7
+ def initialize(server)
8
+ @ops = File.readlines("ops.txt").map { |s| s.chomp }
9
+ @userlog = get_user_log
7
10
  @users = []
11
+ @timers = {}
12
+ @counter = 0
13
+ @logon_time = {}
14
+ @server = server
15
+
16
+ # Command set.
17
+ @commands = {}
18
+ add_command(:give, :ops => true, :all => true, :all_message => "is putting out.")
19
+ add_command(:tp, :ops => false, :all => true, :all_message => "is teleporting all users to their location.")
20
+ add_command(:kit, :ops => true, :all => true, :all_message => "is providing kits to all.")
21
+ add_command(:help, :ops => false, :all => false)
22
+ add_command(:nom, :ops => true, :all => true, :all_message => "is providing noms to all.")
23
+ add_command(:list, :ops => false, :all => false)
24
+ add_command(:addtimer, :ops => true, :all => false)
25
+ add_command(:deltimer, :ops => true, :all => false)
26
+ add_command(:printtimer, :ops => true, :all => false)
27
+ add_command(:kitlist, :ops => false, :all => false)
28
+ end
29
+
30
+ def get_user_log
31
+ if File.exists? "user.log"
32
+ JSON.parse(File.read("user.log"))
33
+ else
34
+ {}
35
+ end
36
+ end
37
+
38
+ def write_log
39
+ File.open("user.log", "w") { |f| f.print @userlog.to_json }
40
+ end
41
+
42
+ def call_command(user, command, *args)
43
+ is_all = command.to_s.end_with? "all"
44
+ root = command.to_s.chomp("all").to_sym
45
+ return invalid_command(command) unless @commands.include? root
46
+
47
+ # Any `all` suffixed command requires ops.
48
+ if @commands[root][:ops] or (is_all and @commands[root][:all])
49
+ return if !validate_ops(user, command)
50
+ end
51
+
52
+ if respond_to? "validate_" + root.to_s
53
+ return unless send("validate_" + root.to_s, *args)
54
+ end
55
+
56
+ if is_all
57
+ @server.puts "say #{user} #{@commands[root][:all_message]}"
58
+ if respond_to? command
59
+ send(command, user, *args)
60
+ else
61
+ @users.each { |u| send(root, u, *args) }
62
+ end
63
+ else
64
+ send(root, user, *args)
65
+ end
66
+ end
67
+
68
+ def add_command(command, opts)
69
+ @commands[command] = opts
8
70
  end
9
71
 
10
72
  def process(line)
11
73
  puts line
12
74
  return info_command(line) if line.index "INFO"
75
+ rescue Exception => e
76
+ puts "An error has occurred."
77
+ puts e
78
+ puts e.backtrace
79
+ end
80
+
81
+ def periodic
82
+ @counter += 1
83
+ @users.each do |user|
84
+ next unless @timers.has_key? user
85
+ @timers[user].each do |item, duration|
86
+ next if duration.nil?
87
+ @server.puts "give #{user} #{item} 64" if @counter % duration == 0
88
+ end
89
+ end
13
90
  end
14
91
 
15
92
  def info_command(line)
16
93
  line.gsub! /^.*?\[INFO\]\s+/, ''
17
- meta_check(line)
94
+ return if meta_check(line)
18
95
  match_data = line.match /^\<(.*?)\>\s+!(.*?)$/
19
96
  return if match_data.nil?
20
97
 
21
98
  user = match_data[1]
22
99
  args = match_data[2].split(" ")
23
- return send(args.slice!(0), user, *args)
100
+ call_command(user, args.slice!(0).to_sym, *args)
24
101
  end
25
102
 
26
103
  def meta_check(line)
27
- return if check_ops(line)
28
- return if check_join_part(line)
104
+ return true if check_ops(line)
105
+ return true if check_join_part(line)
29
106
  end
30
107
 
31
108
  def check_ops(line)
@@ -43,111 +120,44 @@ module Minecraft
43
120
  user = line.split(" ").first
44
121
  if line.index "lost connection"
45
122
  @users.reject! { |u| u == user }
123
+ log_time(user)
46
124
  return true
47
125
  elsif line.index "logged in"
48
126
  @users << user
127
+ @logon_time[user] = Time.now
49
128
  return true
50
129
  end
51
130
  end
52
131
 
53
132
  def method_missing(sym, *args)
54
- if DATA_VALUE_HASH.has_key? sym.downcase
133
+ if DATA_VALUE_HASH.has_key? sym.downcase and is_op? args.first
55
134
  give(args.first, sym, args.last)
56
135
  else
57
136
  puts "Invalid command given."
58
137
  end
59
138
  end
60
139
 
61
- def giveall(user, *args)
62
- return privilege_error(user, "giveall") unless is_op? user
63
- ret = "say #{user} is putting out!\n"
64
- @users.each do |u|
65
- ret += mc_give(u, *args)
66
- end
67
-
68
- return ret
69
- end
70
-
71
- def give(user, *args)
72
- return privilege_error(user, "give") unless is_op? user
73
- return mc_give(user, *args)
74
- end
75
-
76
- def mc_give(user, *args)
77
- if args.length == 1
78
- quantity = 1
79
- item = args.first
80
- else
81
- quantity = args.last.to_i || 1
82
- item = args[0..-2].join(" ")
83
- end
84
- item = (item.to_i.to_s == item) ? item.to_i : DATA_VALUE_HASH[item.downcase]
85
-
86
- return quantify(user, item, quantity)
87
- end
88
-
89
- def kit(user, group)
90
- return privilege_error(user, "kit") unless is_op? user
91
- return "say #{group} is not a valid kit." unless KITS.has_key? group.to_sym
92
- ret = ""
93
-
94
- KITS[group.to_sym].each do |item|
95
- if item.is_a? Array
96
- ret += quantify(user, item.first, item.last)
97
- else
98
- ret += "give #{user} #{item} 1\n"
99
- end
100
- end
101
- return ret.chop
102
- end
103
-
104
- def tp(user, target)
105
- "tp #{user} #{target}"
106
- end
107
-
108
- def tpall(user)
109
- return privilege_error(user, "tpall", "Wow, #{user} actually tried to pull that...") unless is_op? user
110
- ret = "say #{user} is teleporting all users to their location.\n"
111
- @users.each do |u|
112
- ret += tp(u, user)
113
- end
114
- return ret
115
- end
116
-
117
- def nom(user)
118
- return privilege_error(user, "nom", "No noms for you!") unless is_op? user
119
- "give #{user} 322 1"
120
- end
121
-
122
- def help(*args)
123
- <<-eof
124
- say !tp target_user
125
- say !tpall
126
- say !kit kit_name
127
- say !give item quantity
128
- say !giveall item quantity
129
- say !nom
130
- say /help
131
- eof
132
- end
133
-
134
- def quantify(user, item, quantity)
135
- return "give #{user} #{item} #{quantity}" if quantity <= 64
136
-
137
- quantity = 2560 if quantity > 2560
138
- full_quantity = (quantity / 64.0).floor
139
- sub_quantity = quantity % 64
140
- ret = "give #{user} #{item} 64\n" * full_quantity
141
- ret += "give #{user} #{item} #{sub_quantity}"
142
- return ret
140
+ def log_time(user)
141
+ logoff = Time.now
142
+ logon = @logon_time[user]
143
+ time_spent = logoff - logon
144
+ @userlog[user] ||= 0
145
+ @userlog[user] += time_spent
146
+ @server.puts "say #{user} spent #{time_spent} seconds the server, totalling to #{@userlog[user]}."
147
+ write_log
143
148
  end
144
149
 
145
150
  def is_op?(user)
146
151
  @ops.include? user
147
152
  end
148
153
 
149
- def privilege_error(user, command, suffix = "S/he must be humiliated!")
150
- "say #{user} is not an op, cannot use !#{command}. #{suffix}"
154
+ def validate_ops(user, command)
155
+ return true if is_op? user
156
+ @server.puts "say #{user} is not an op, cannot use !#{command}."
157
+ end
158
+
159
+ def invalid_command(command)
160
+ @server.puts "say #{command} is invalid."
151
161
  end
152
162
  end
153
163
  end
@@ -5,18 +5,14 @@ module Minecraft
5
5
  attr_accessor :sin
6
6
 
7
7
  def initialize(command)
8
- @extensions = Extensions.new
9
8
  @sin, @sout, @serr = Open3.popen3(command)
9
+ @extensions = Extensions.new(@sin)
10
10
  threads = []
11
- threads << Thread.new { loop { process(@sout.gets) } }
12
- threads << Thread.new { loop { process(@serr.gets) } }
11
+ threads << Thread.new { loop { @extensions.process(@sout.gets) } }
12
+ threads << Thread.new { loop { @extensions.process(@serr.gets) } }
13
+ threads << Thread.new { loop { @extensions.periodic; sleep 1 } }
13
14
  threads << Thread.new { loop { @sin.puts gets } }
14
15
  threads.each(&:join)
15
16
  end
16
-
17
- def process(line)
18
- result = @extensions.process(line)
19
- @sin.puts(result) unless result.nil?
20
- end
21
17
  end
22
18
  end
@@ -1,3 +1,3 @@
1
1
  module Minecraft
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: minecraft
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.2
5
+ version: 0.0.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Andrew Horsman
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-08-13 00:00:00 -04:00
13
+ date: 2011-08-14 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -40,6 +40,7 @@ files:
40
40
  - Rakefile
41
41
  - bin/minecraft
42
42
  - lib/minecraft.rb
43
+ - lib/minecraft/commands.rb
43
44
  - lib/minecraft/data.rb
44
45
  - lib/minecraft/extensions.rb
45
46
  - lib/minecraft/server.rb