Skip to content

Instantly share code, notes, and snippets.

@tompng
Last active August 29, 2015 14:01
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tompng/734b9562c8f3a10ad639 to your computer and use it in GitHub Desktop.
Save tompng/734b9562c8f3a10ad639 to your computer and use it in GitHub Desktop.
require 'net/http'
require 'json'
module Minecraft
class Client
def initialize host
@host = host
end
def get path
Net::HTTP.get URI.parse("http://#{@host}#{path}")
end
def post path, params
http = Net::HTTP.new *@host.split(':')
http.post(path, params.to_json, {'Content-Type' => 'application/json'}).body
end
#setblock 'minecraft:glass', x:1, y:1, z:1
def setblock name, pos
setblocks [name: name, position: pos]
end
def setblocks blocks
post '/setblocks', blocks: blocks
end
def getblock pos
getblocks([pos]).first
end
def getblocks positions
begin
blocks = JSON.parse post('/getblocks', positions: positions)
blocks.map{|name|
if Minecraft::Block.const_defined?(name)
Minecraft::Block.const_get(name)
else
name
end
}
rescue => e
[]
end
end
#find name: 'tompng' #=> {x: 123.456, y: 62, z: 9.876}
def find name
begin
res = get "/find/#{name}"
pos = JSON.parse(res)
{x: pos['x'], y: pos['y'], z: pos['z']} if pos
rescue
end
end
#move 'tompng', x: 1, y: 62, z: 3
#move 'tompng', dx: 0, dy: 1, dz: 0
def move name, pos
post "/move/#{name}", position: pos
end
#summon 'Zombie', x:1, y:100, z:2
def summon name, pos
post '/summon', name: name, position: pos
end
def call command
post '/call', command: command
end
end
end
module Minecraft
module Block
block_types = %w(air stone grass dirt cobblestone planks sapling bedrock flowing_water water flowing_lava lava sand gravel gold_ore iron_ore coal_ore log leaves sponge glass lapis_ore lapis_block dispenser sandstone noteblock bed golden_rail detector_rail sticky_piston web tallgrass deadbush piston piston_head wool piston_extension yellow_flower red_flower brown_mushroom red_mushroom gold_block iron_block double_stone_slab stone_slab brick_block tnt bookshelf mossy_cobblestone obsidian torch fire mob_spawner oak_stairs chest redstone_wire diamond_ore diamond_block crafting_table wheat farmland furnace lit_furnace standing_sign wooden_door ladder rail stone_stairs wall_sign lever stone_pressure_plate iron_door wooden_pressure_plate redstone_ore lit_redstone_ore unlit_redstone_torch redstone_torch stone_button snow_layer ice snow cactus clay reeds jukebox fence pumpkin netherrack soul_sand glowstone portal lit_pumpkin cake unpowered_repeater powered_repeater stained_glass trapdoor monster_egg stonebrick brown_mushroom_block red_mushroom_block iron_bars glass_pane melon_block pumpkin_stem melon_stem vine fence_gate brick_stairs stone_brick_stairs mycelium waterlily nether_brick nether_brick_fence nether_brick_stairs nether_wart enchanting_table brewing_stand cauldron end_portal end_portal_frame end_stone dragon_egg redstone_lamp lit_redstone_lamp double_wooden_slab wooden_slab cocoa sandstone_stairs emerald_ore ender_chest tripwire_hook tripwire emerald_block spruce_stairs birch_stairs jungle_stairs command_block beacon cobblestone_wall flower_pot carrots potatoes wooden_button skull anvil trapped_chest light_weighted_pressure_plate heavy_weighted_pressure_plate unpowered_comparator powered_comparator daylight_detector redstone_block quartz_ore hopper quartz_block quartz_stairs activator_rail dropper stained_hardened_clay stained_glass_pane leaves2 log2 acacia_stairs dark_oak_stairs hay_block carpet hardened_clay coal_block packed_ice double_plant)
block_types.each{|name|
const_set name.split('_').map(&:capitalize).join, "minecraft:#{name}"
}
end
end
require 'pry'
m = Minecraft::Client.new '192.168.1.3:4567'
binding.pry
# loop{
# begin
# pos = m.find(:tompng)
# m.setblocks (-1..1).to_a.product((-1..1).to_a).map{|x,z|
# {
# name: Minecraft::Block::Leaves,
# position: {x: pos[:x]+x, y: [pos[:y]-1, 70].min, z: pos[:z]+z}
# }
# }
# rescue => e
# sleep 1
# end
# sleep 0.25
# }
require 'pry'
require 'timeout'
require 'json'
require 'sinatra'
require 'active_support/core_ext/hash/indifferent_access'
command = 'cd bin;java -Xmx1024M -Xms1024M -jar minecraft_server.1.7.9.jar nogui'
module Minecraft
refine Hash do
def to_minecraft
'[' + map{|key, value|"#{key}=#{value}"}.join(',') + ']'
end
end
end
module Minecraft
Events = []
Events << (/.+ joined the game$/)
end
class Minecraft::CommandExecutor
def initialize command
@queue = Queue.new
@mutex = Mutex.new
@io = IO.popen command, "r+"
Thread.new{
begin
@io.each_line do |line|
p line
next unless /^\[..:..:..\] \[Server thread\/INFO\]: (?<response>.+)$/ =~ line.chomp
next if Minecraft::Events.any?{|pattern|pattern =~ response}
notify response
end
exit
rescue => e
p e
end
}
end
def notify response
@queue << response
end
def call command, option={}
p command
@mutex.synchronize do
@queue.clear
@io.puts command
unless option.key?(:response) && !option[:response]
return timeout(0.1){@queue.pop}
end
end
rescue
end
def find name
if /^Teleported .+ to (?<x>[\d.-]+),(?<y>[\d.-]+),(?<z>[\d.-]+)/ =~ call("tp #{name} ~0 ~0 ~0")
{x: x.to_f, y: y.to_f, z: z.to_f}
end
rescue
end
def move name, pos
x = pos[:x] || (pos[:dx] ? "~#{pos[:dx]}" : '~0')
y = pos[:y] || (pos[:dy] ? "~#{pos[:dy]}" : '~0')
z = pos[:z] || (pos[:dz] ? "~#{pos[:dz]}" : '~0')
call "tp #{name} #{x} #{y} #{z}", response: false
end
def setblock name, pos
call "setblock #{pos[:x].floor} #{pos[:y].floor} #{pos[:z].floor} #{name}", response: false
end
def getblock pos
response = call "testforblock #{pos[:x].floor} #{pos[:y].floor} #{pos[:z].floor} minecraft:air"
if /^Successfully/ =~ response
'Air'
elsif /^The block at .+ is (?<name>[^ ]+)/ =~ response
name
end
end
def summon name, pos
call "summon #{name} #{pos[:x]} #{pos[:y]} #{pos[:z]}", response: false
end
def test name, pos, r
result = call("xp 0 @p[name=#{name},x=#{pos[:x].round},y=#{pos[:y].round},z=#{pos[:z].round},r=#{r.ceil}]")
!!result.match(/^Given 0 experience to/)
end
def stop
call 'stop', response: false
end
end
minecraft = Minecraft::CommandExecutor.new command
before do
return unless request.content_type == 'application/json'
body = HashWithIndifferentAccess.new JSON.parse request.body.read
body.each{|key, value|
params[key] ||= value
}
end
set :bind, '0.0.0.0'
get '/find/:name' do
minecraft.find(params[:name]).to_json
end
post '/move/:name' do
minecraft.move(params[:name], params[:position])
end
post '/setblocks' do
params[:blocks].each{|block|
minecraft.setblock(block[:name], block[:position])
}
nil
end
post '/getblocks' do
params[:positions].map{|pos|
minecraft.getblock pos
}.to_json
end
post '/summon' do
minecraft.summon(params[:name], params[:position])
end
post '/call' do
minecraft.call(params[:command]).to_s
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment