mcblocky 0.1.0.pre.alpha.pre.6
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.
- checksums.yaml +15 -0
- data/.gitignore +11 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/README.md +34 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/workon.cmd +1 -0
- data/doc/Introduction.md +144 -0
- data/examples/ctf/arena.rb +14 -0
- data/examples/ctf/config.example.yml +15 -0
- data/examples/ctf/ctf.rb +316 -0
- data/examples/ctf/lobby.rb +20 -0
- data/examples/hello/config.example.yml +14 -0
- data/examples/hello/hello.rb +81 -0
- data/examples/hello/helpers/bar.rb +3 -0
- data/examples/hello/helpers/foo.rb +3 -0
- data/exe/mcblocky +6 -0
- data/lib/mcblocky/cli.rb +108 -0
- data/lib/mcblocky/config.rb +63 -0
- data/lib/mcblocky/context.rb +87 -0
- data/lib/mcblocky/dsl/block.rb +13 -0
- data/lib/mcblocky/dsl/command_block.rb +23 -0
- data/lib/mcblocky/dsl/commands.rb +152 -0
- data/lib/mcblocky/dsl/container.rb +24 -0
- data/lib/mcblocky/dsl/repeat_chain.rb +9 -0
- data/lib/mcblocky/dsl/selector.rb +29 -0
- data/lib/mcblocky/dsl.rb +146 -0
- data/lib/mcblocky/executor.rb +149 -0
- data/lib/mcblocky/listener.rb +69 -0
- data/lib/mcblocky/location.rb +95 -0
- data/lib/mcblocky/logging.rb +45 -0
- data/lib/mcblocky/server.rb +143 -0
- data/lib/mcblocky/version.rb +3 -0
- data/lib/mcblocky.rb +23 -0
- data/mcblocky.gemspec +28 -0
- metadata +151 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
require_relative 'helpers/foo'
|
2
|
+
|
3
|
+
helper 'hello' do |args, user|
|
4
|
+
server.say "Hello, #{user}!"
|
5
|
+
end
|
6
|
+
|
7
|
+
helper 'clean' do |args, user|
|
8
|
+
Executor.to_commands($context).each{|c| server.command c}
|
9
|
+
end
|
10
|
+
|
11
|
+
initial do
|
12
|
+
gamerule 'doDaylightCycle', false
|
13
|
+
gamerule 'commandBlockOutput', false
|
14
|
+
gamerule 'logAdminCommands', false
|
15
|
+
time :set, 'day'
|
16
|
+
|
17
|
+
['red', 'blue', 'yellow', 'green'].each do |color|
|
18
|
+
scoreboard :teams do
|
19
|
+
add color.capitalize
|
20
|
+
option color.capitalize, :color, color
|
21
|
+
end
|
22
|
+
end
|
23
|
+
scoreboard :teams do
|
24
|
+
add 'Spectators'
|
25
|
+
option 'Spectators', :color, 'gray'
|
26
|
+
end
|
27
|
+
scoreboard :objectives do
|
28
|
+
add 'SwitchingTeam', 'dummy'
|
29
|
+
end
|
30
|
+
|
31
|
+
tellraw @a[team: 'Red'], {text: "Hello world", color: "red"}
|
32
|
+
end
|
33
|
+
|
34
|
+
repeat 171, 82, 242, 175, 84, 247 do
|
35
|
+
scoreboard :players, :set, @a[x: 172, y: 81, z: 236, r: 1, team: '!Red'], 'SwitchingTeam', 1
|
36
|
+
scoreboard :players, :set, @a[x: 170, y: 81, z: 236, r: 1, team: '!Blue'], 'SwitchingTeam', 1
|
37
|
+
execute @a[x: 170, y: 81, z: 236, r: 1, score_SwitchingTeam_min: 1], '~ ~ ~', 'scoreboard teams join Blue @p'
|
38
|
+
execute @a[x: 170, y: 81, z: 236, r: 1, score_SwitchingTeam_min: 1], '~ ~ ~', :tellraw, @a, JSON.dump([
|
39
|
+
{selector: @p},
|
40
|
+
{text: ' joined the ', color: 'reset'},
|
41
|
+
{text: 'Blue', color: 'blue'},
|
42
|
+
{text: ' team', color: 'reset'}
|
43
|
+
])
|
44
|
+
execute @a[x: 172, y: 81, z: 236, r: 1, score_SwitchingTeam_min: 1], '~ ~ ~', 'scoreboard teams join Red @p'
|
45
|
+
execute @a[x: 172, y: 81, z: 236, r: 1, score_SwitchingTeam_min: 1], '~ ~ ~', :tellraw, @a, JSON.dump([
|
46
|
+
{selector: @p},
|
47
|
+
{text: ' joined the ', color: 'reset'},
|
48
|
+
{text: 'Red', color: 'red'},
|
49
|
+
{text: ' team', color: 'reset'}
|
50
|
+
])
|
51
|
+
scoreboard :players, :reset, @a[score_SwitchingTeam_min: 1], 'SwitchingTeam'
|
52
|
+
#tellraw @a[team: 'Red'], {text: "Hello", color: "red"}
|
53
|
+
end
|
54
|
+
|
55
|
+
fill 171, 78, 242, 181, 78, 252, 'minecraft:stained_glass', Color::BLUE
|
56
|
+
|
57
|
+
cleanup do
|
58
|
+
fill 172, 80, 243, 174, 80, 243, 'minecraft:air', 0, 'replace'
|
59
|
+
end
|
60
|
+
|
61
|
+
at 172, 79, 243 do
|
62
|
+
fill '~', '~1', '~', '~2', '~1', '~', 'minecraft:stone'
|
63
|
+
end
|
64
|
+
|
65
|
+
at 172, 81, 243 do
|
66
|
+
fill '~ ~-1 ~ ~2 ~-1 ~', 'minecraft:redstone_block'
|
67
|
+
end
|
68
|
+
|
69
|
+
setblock 175, 79, 248, 'minecraft:standing_sign', 0, 'replace', {'Text1'=>'{"text":"hello friends"}'}
|
70
|
+
|
71
|
+
furnace 176, 79, 248 do
|
72
|
+
item 'minecraft:diamond', 64
|
73
|
+
item 'minecraft:spawn_egg', 1, 0, {'EntityTag'=>{'id'=>'Chicken', 'CustomName'=>'Chickfila'}, 'display'=>{'Name'=>'Chicken Egg'}}
|
74
|
+
item 'minecraft:gold_ingot'
|
75
|
+
end
|
76
|
+
|
77
|
+
after do
|
78
|
+
# setblock 175, 79, 248, 'minecraft:standing_sign', 0, 'replace'
|
79
|
+
# blockdata 175, 79, 248, {'Text1'=>'{"text":"hola mundo"}'}
|
80
|
+
setblock 172, 80, 243, 'minecraft:redstone_block', 0, 'replace'
|
81
|
+
end
|
data/exe/mcblocky
ADDED
data/lib/mcblocky/cli.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "thor"
|
3
|
+
|
4
|
+
module McBlocky
|
5
|
+
class Cli < Thor
|
6
|
+
include Logging
|
7
|
+
|
8
|
+
class_option :config,
|
9
|
+
desc: 'Path to config file',
|
10
|
+
default: 'config.yml',
|
11
|
+
type: :string,
|
12
|
+
aliases: '-f'
|
13
|
+
|
14
|
+
desc "list", "List commands that would be sent to the server"
|
15
|
+
option :watch, aliases: '-w'
|
16
|
+
option :diff
|
17
|
+
def list
|
18
|
+
begin
|
19
|
+
Config.load(options[:config])
|
20
|
+
rescue ArgumentError => e
|
21
|
+
log_error "Error in #{File.basename Config.config_path}:"
|
22
|
+
log_error e.message
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
if options[:watch]
|
26
|
+
$old_context = nil
|
27
|
+
listener = Listener.from_config do |context|
|
28
|
+
Executor.to_commands(context, options[:diff] ? $old_context : nil).each{|c| puts c}
|
29
|
+
$old_context = context
|
30
|
+
end
|
31
|
+
listener.start
|
32
|
+
while true; end
|
33
|
+
else
|
34
|
+
context = Context.run_file(Config.config['code']['main'], File.dirname(Config.config_path))
|
35
|
+
Executor.to_commands(context).each{|c| puts c}
|
36
|
+
end
|
37
|
+
rescue Interrupt
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "start", "Start the server"
|
41
|
+
def start
|
42
|
+
begin
|
43
|
+
Config.load(options[:config])
|
44
|
+
rescue ArgumentError => e
|
45
|
+
log_error "Error in #{File.basename Config.config_path}:"
|
46
|
+
log_error e.message
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
$server = Server.from_config
|
50
|
+
log_status "Starting server..."
|
51
|
+
$server.start
|
52
|
+
log_status "Server is ready! Connect to 127.0.0.1:25565"
|
53
|
+
reader = Thread.new do
|
54
|
+
until $stdin.closed?
|
55
|
+
line = $stdin.gets.chomp
|
56
|
+
$server.command line unless line.empty?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
$server.say("McBlocky is ready")
|
60
|
+
$server.on_message '!stop' do
|
61
|
+
log_status "Stopping server..."
|
62
|
+
$server.stop
|
63
|
+
end
|
64
|
+
$server.on_message /^!/ do |message, user|
|
65
|
+
next unless $context
|
66
|
+
command, _, args = message.partition(/\s+/)
|
67
|
+
$context.helpers.each do |aliases, block|
|
68
|
+
aliases = [aliases] if String === aliases
|
69
|
+
aliases.each do |a|
|
70
|
+
if command == "!#{a}"
|
71
|
+
block.call(args, user, a)
|
72
|
+
break
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
listener = Listener.from_config do |context|
|
78
|
+
old_context = $context
|
79
|
+
$context = context
|
80
|
+
$context.server = $server # needed by helpers
|
81
|
+
Executor.to_commands(context, old_context).each{|c| $server.command c}
|
82
|
+
end
|
83
|
+
listener.start
|
84
|
+
$server.loop!
|
85
|
+
rescue SystemExit
|
86
|
+
if $server
|
87
|
+
log_status "Stopping server..."
|
88
|
+
$server.stop
|
89
|
+
end
|
90
|
+
reader.kill if reader
|
91
|
+
rescue Interrupt
|
92
|
+
if $server
|
93
|
+
log_status "Stopping server..."
|
94
|
+
$server.stop
|
95
|
+
end
|
96
|
+
reader.kill if reader
|
97
|
+
rescue Exception
|
98
|
+
log_error "Caught error, stopping server..."
|
99
|
+
begin
|
100
|
+
$server.stop if $server
|
101
|
+
reader.kill if reader
|
102
|
+
rescue
|
103
|
+
end
|
104
|
+
log_error "Error trace:"
|
105
|
+
raise
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module McBlocky
|
4
|
+
class Config
|
5
|
+
class << self
|
6
|
+
attr_reader :config
|
7
|
+
attr_reader :config_path
|
8
|
+
def load(filename)
|
9
|
+
@valid = false
|
10
|
+
filename = File.expand_path('config.yml', filename) if File.directory? filename
|
11
|
+
@config_path = filename
|
12
|
+
open(filename) do |f|
|
13
|
+
@config = YAML.safe_load(f)
|
14
|
+
end
|
15
|
+
validate
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate
|
19
|
+
return if @valid
|
20
|
+
raise ArgumentError, "No config loaded" unless config
|
21
|
+
raise ArgumentError, "No server section" unless config['server']
|
22
|
+
config['code'] ||= {}
|
23
|
+
|
24
|
+
if config['server']['ops']
|
25
|
+
raise ArgumentError, "server.ops must be an array" unless Array === config['server']['ops']
|
26
|
+
end
|
27
|
+
|
28
|
+
config['server']['properties'] = {'enable-command-block' => 'true'}.merge(config['server']['properties'] || {})
|
29
|
+
|
30
|
+
Dir.chdir File.dirname(config_path) do
|
31
|
+
unless which 'java'
|
32
|
+
java = config['server']['java']
|
33
|
+
raise ArgumentError, "Java not found. Specify the full path in server.java" if !java or java.empty?
|
34
|
+
raise ArgumentError, "Java specified in server.java is not executable" unless File.executable? java
|
35
|
+
end
|
36
|
+
|
37
|
+
jar = config['server']['jar']
|
38
|
+
raise ArgumentError, "No server.jar specified" if !jar or jar.empty?
|
39
|
+
raise ArgumentError, "Jar specified in server.jar does not exist" unless File.exist? jar
|
40
|
+
|
41
|
+
config['code']['main'] ||= "#{File.basename File.dirname(config_path)}.rb"
|
42
|
+
main = config['code']['main']
|
43
|
+
raise ArgumentError, "No code.main specified" if !main or main.empty?
|
44
|
+
raise ArgumentError, "#{main} does not exist" unless File.exist? main or File.exist? "#{main}.rb"
|
45
|
+
end
|
46
|
+
|
47
|
+
@valid = true
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
def which(cmd)
|
52
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
53
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
54
|
+
exts.each { |ext|
|
55
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
56
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
57
|
+
}
|
58
|
+
end
|
59
|
+
return nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'mcblocky/dsl'
|
2
|
+
|
3
|
+
module McBlocky
|
4
|
+
class Context
|
5
|
+
attr_accessor :server
|
6
|
+
|
7
|
+
def self.run_file(file, dir=nil)
|
8
|
+
dir = File.dirname(file) unless dir
|
9
|
+
Dir.chdir dir do
|
10
|
+
begin
|
11
|
+
ctx = Context.new
|
12
|
+
f = open(file)
|
13
|
+
ctx.instance_eval(f.read, file)
|
14
|
+
return ctx
|
15
|
+
ensure
|
16
|
+
f.close if f
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.run_block(&block)
|
22
|
+
ctx = Context.new
|
23
|
+
ctx.instance_exec &block
|
24
|
+
return ctx
|
25
|
+
end
|
26
|
+
|
27
|
+
def helpers
|
28
|
+
@helpers ||= []
|
29
|
+
end
|
30
|
+
|
31
|
+
def required_files
|
32
|
+
@required_files ||= Set.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def chains
|
36
|
+
@chains ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
def blocks
|
40
|
+
@blocks ||= {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def rects
|
44
|
+
@rects ||= {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def areas
|
48
|
+
@areas ||= []
|
49
|
+
end
|
50
|
+
|
51
|
+
def context
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def require(file)
|
56
|
+
if file.start_with? './'
|
57
|
+
file = "#{file.sub('./','')}.rb" unless file.end_with? '.rb'
|
58
|
+
required_files << file
|
59
|
+
begin
|
60
|
+
f = open(file)
|
61
|
+
instance_eval(f.read, file)
|
62
|
+
true
|
63
|
+
ensure
|
64
|
+
f.close if f
|
65
|
+
end
|
66
|
+
else
|
67
|
+
Kernel.require(file)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def require_relative(file)
|
72
|
+
path = File.dirname caller[0].split('.rb')[0]
|
73
|
+
file = "#{file}.rb" unless file.end_with? '.rb'
|
74
|
+
file = File.expand_path(file, path)
|
75
|
+
required_files << file
|
76
|
+
begin
|
77
|
+
f = open(file)
|
78
|
+
instance_eval(f.read, file)
|
79
|
+
true
|
80
|
+
ensure
|
81
|
+
f.close if f
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
include McBlocky::DSL
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module McBlocky::DSL
|
2
|
+
class CommandBlock < Commands
|
3
|
+
attr_reader :x, :y, :z, :block_data, :block_kind
|
4
|
+
def initialize(x, y, z, facing, kind, nbt={})
|
5
|
+
super(:at)
|
6
|
+
@x = x
|
7
|
+
@y = y
|
8
|
+
@z = z
|
9
|
+
@block_data = facing
|
10
|
+
@block_kind = kind
|
11
|
+
@nbt = nbt
|
12
|
+
end
|
13
|
+
|
14
|
+
def command(*args)
|
15
|
+
raise ArgumentError, "Only one command is allowed per block" unless commands.empty?
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def nbt
|
20
|
+
return @nbt.merge({'Command'=>commands[0] || ''})
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module McBlocky::DSL
|
2
|
+
class Commands
|
3
|
+
attr_reader :kind
|
4
|
+
attr_accessor :commands
|
5
|
+
|
6
|
+
def initialize(kind, *args)
|
7
|
+
@kind = kind
|
8
|
+
@args = args
|
9
|
+
@commands = []
|
10
|
+
@a = Selector.new '@a'
|
11
|
+
@p = Selector.new '@p'
|
12
|
+
@r = Selector.new '@r'
|
13
|
+
@e = Selector.new '@e'
|
14
|
+
end
|
15
|
+
|
16
|
+
def command(*args)
|
17
|
+
commands << args.map(&:to_s).join(' ')
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_nbt(obj)
|
21
|
+
McBlocky::DSL.to_nbt(obj)
|
22
|
+
end
|
23
|
+
|
24
|
+
COMMANDS = [:achievement, :ban, :ban_ip, :banlist, :blockdata, :clear, :clone, :debug, :defaultgamemode, :deop, :difficulty, :effect, :enchant, :entitydata, :execute, :fill, :gamemode, :gamerule, :give, :help, :kick, :kill, :list, :me, :op, :pardon, :pardon_ip, :particle, :playsound, :replaceitem, :save_all, :save_off, :save_on, :say, :scoreboard, :seed, :setblock, :setidletimeout, :setworldspawn, :spawnpoint, :spreadplayers, :stats, :stop, :summon, :tell, :tellraw, :testfor, :testforblock, :testforblocks, :time, :title, :toggledownfall, :tp, :trigger, :weather, :whitelist, :worldborder, :xp]
|
25
|
+
|
26
|
+
def blockdata(*args)
|
27
|
+
args[-1] = to_nbt(args[-1]) if Hash === args[-1]
|
28
|
+
command :blockdata, *args
|
29
|
+
end
|
30
|
+
|
31
|
+
def detect(selector, *args, &block)
|
32
|
+
if block
|
33
|
+
chain = Commands.new(:detect)
|
34
|
+
chain.instance_exec &block
|
35
|
+
chain.commands.each do |c|
|
36
|
+
command :execute, selector, '~ ~ ~', :detect, *args, c
|
37
|
+
end
|
38
|
+
else
|
39
|
+
command :execute, selector, '~ ~ ~', :detect, *args
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def execute(selector, *args, &block)
|
44
|
+
if args.empty?
|
45
|
+
args = ['~ ~ ~']
|
46
|
+
end
|
47
|
+
if block
|
48
|
+
chain = Commands.new(:execute)
|
49
|
+
chain.instance_exec &block
|
50
|
+
chain.commands.each do |c|
|
51
|
+
command :execute, selector, *args, c
|
52
|
+
end
|
53
|
+
else
|
54
|
+
command :execute, selector, *args
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def gamerule(rule=nil, value=nil, &block)
|
59
|
+
if (rule and block) or (rule and value.nil?)
|
60
|
+
raise ArgumentError
|
61
|
+
end
|
62
|
+
unless block
|
63
|
+
command :gamerule, rule, value
|
64
|
+
else
|
65
|
+
o = PartialCommand.new(self, :gamerule)
|
66
|
+
o.instance_exec &block
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def replaceitem(*args)
|
71
|
+
args[-1] = to_nbt(args[-1]) if Hash === args[-1]
|
72
|
+
command :replaceitem, *args
|
73
|
+
end
|
74
|
+
|
75
|
+
def scoreboard(*args, &block)
|
76
|
+
if block
|
77
|
+
d = SimpleDelegator.new(self)
|
78
|
+
d.instance_variable_set :@a, @a
|
79
|
+
d.instance_variable_set :@p, @p
|
80
|
+
d.instance_variable_set :@r, @r
|
81
|
+
d.instance_variable_set :@e, @e
|
82
|
+
d.instance_variable_set :@args, args
|
83
|
+
def d.method_missing(m, *a)
|
84
|
+
super
|
85
|
+
rescue NoMethodError
|
86
|
+
command :scoreboard, *@args, m, *a
|
87
|
+
end
|
88
|
+
d.instance_exec(&block)
|
89
|
+
else
|
90
|
+
command :scoreboard, *args
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def setblock(*args)
|
95
|
+
args[-1] = to_nbt(args[-1]) if Hash === args[-1]
|
96
|
+
command :setblock, *args
|
97
|
+
end
|
98
|
+
|
99
|
+
def tellraw(player, *args)
|
100
|
+
if args.length < 1
|
101
|
+
raise ArgumentError, "No message given in tellraw"
|
102
|
+
end
|
103
|
+
obj = []
|
104
|
+
args.each do |arg|
|
105
|
+
if Array === arg
|
106
|
+
obj += arg
|
107
|
+
else
|
108
|
+
obj << arg
|
109
|
+
end
|
110
|
+
end
|
111
|
+
command :tellraw, player, JSON.dump(obj)
|
112
|
+
end
|
113
|
+
|
114
|
+
def title(selector, subcommand, *args)
|
115
|
+
if args.length < 1
|
116
|
+
raise ArgumentError, "No message given in title"
|
117
|
+
end
|
118
|
+
obj = []
|
119
|
+
args.each do |arg|
|
120
|
+
if Array === arg
|
121
|
+
obj += arg
|
122
|
+
else
|
123
|
+
obj << arg
|
124
|
+
end
|
125
|
+
end
|
126
|
+
command :title, selector, subcommand, JSON.dump(obj)
|
127
|
+
end
|
128
|
+
|
129
|
+
COMMANDS.each do |c|
|
130
|
+
unless method_defined? c
|
131
|
+
define_method c do |*args|
|
132
|
+
command c.to_s.gsub('_', '-'), *args
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class PartialCommand
|
139
|
+
def initialize(context, *args)
|
140
|
+
@context = context
|
141
|
+
@args = args
|
142
|
+
@a = Selector.new '@a'
|
143
|
+
@p = Selector.new '@p'
|
144
|
+
@r = Selector.new '@r'
|
145
|
+
@e = Selector.new '@e'
|
146
|
+
end
|
147
|
+
|
148
|
+
def method_missing(m, *args)
|
149
|
+
@context.command *(@args + [m] + args)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module McBlocky::DSL
|
2
|
+
class Container
|
3
|
+
attr_reader :x, :y, :z, :block_data, :block_kind, :nbt
|
4
|
+
def initialize(x, y, z, kind, data=0, nbt={})
|
5
|
+
@x = x
|
6
|
+
@y = y
|
7
|
+
@z = z
|
8
|
+
@block_kind = kind
|
9
|
+
@block_data = data
|
10
|
+
@nbt = nbt
|
11
|
+
@last_slot = -1
|
12
|
+
end
|
13
|
+
|
14
|
+
def item_in_slot(slot, kind, count=1, damage=0, tag={})
|
15
|
+
nbt['Items'] ||= []
|
16
|
+
nbt['Items'] << {'Slot'=>slot, 'id'=>kind, 'Count'=>count, 'Damage'=>damage, 'tag'=>tag}
|
17
|
+
@last_slot = slot if slot > @last_slot
|
18
|
+
end
|
19
|
+
|
20
|
+
def item(kind, count=1, damage=0, tag={})
|
21
|
+
item_in_slot(@last_slot+1, kind, count, damage, tag)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module McBlocky::DSL
|
2
|
+
class Selector
|
3
|
+
def initialize(name, **kwargs)
|
4
|
+
@name = name
|
5
|
+
if kwargs[:loc]
|
6
|
+
loc = kwargs[:loc]
|
7
|
+
raise ArgumentError, "Relative locations are not allowed in selectors" if loc.is_relative?
|
8
|
+
kwargs[:x] = loc.x
|
9
|
+
kwargs[:y] = loc.y
|
10
|
+
kwargs[:z] = loc.z
|
11
|
+
kwargs.delete :loc
|
12
|
+
end
|
13
|
+
@args = kwargs
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](**args)
|
17
|
+
Selector.new(@name, @args.merge(args))
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
if @args.empty?
|
22
|
+
@name
|
23
|
+
else
|
24
|
+
pairs = @args.map{|k,v| "#{k}=#{v}"}
|
25
|
+
"#{@name}[#{pairs.join(',')}]"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|