Class: McBlocky::Executor

Inherits:
DSL::Commands show all
Defined in:
lib/mcblocky/executor.rb

Constant Summary

Constants inherited from DSL::Commands

DSL::Commands::COMMANDS

Instance Attribute Summary

Attributes inherited from DSL::Commands

#commands, #context, #kind

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from DSL::Commands

#activate, #blockdata, #command, #detect, #disable, #enable, #execute, #gamerule, #initialize, #replaceitem, #scoreboard, #setblock, #tellraw, #title, #to_nbt

Constructor Details

This class inherits a constructor from McBlocky::DSL::Commands

Class Method Details

.to_commands(context, old_context = nil) ⇒ Object



3
4
5
6
7
# File 'lib/mcblocky/executor.rb', line 3

def self.to_commands(context, old_context=nil)
  executor = Executor.new(nil, :final)
  executor.do_context(context, old_context)
  executor.commands
end

Instance Method Details

#do_block(block, old_block = nil) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/mcblocky/executor.rb', line 74

def do_block(block, old_block=nil)
  if old_block and !block
    setblock old_block.x, old_block.y, old_block.z, 'minecraft:air'
    return
  end

  if old_block and old_block.block_kind == block.block_kind and old_block.block_data == block.block_data
    return if old_block.nbt == block.nbt
    blockdata block.x, block.y, block.z, block.nbt unless block.nbt == {}
  else
    setblock block.x, block.y, block.z, block.block_kind, block.block_data, 'replace'
    blockdata block.x, block.y, block.z, block.nbt unless block.nbt == {}
  end
end

#do_context(context, old_context) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/mcblocky/executor.rb', line 9

def do_context(context, old_context)
  # do cleanup first
  if old_context
    old_context.chains.select{|x|x.kind == :cleanup}.each do |c|
      self.commands += c.commands
    end
  end

  # do initial blocks
  old_initials = old_context ? old_context.chains.select{|x|x.kind == :initial} : []
  initials = context.chains.select{|x|x.kind == :initial}
  initials.each_with_index do |chain, i|
    old_chain = old_initials[i]
    if old_chain
      matches = true
      chain.commands.each_with_index do |cmd, j|
        if matches
          old_cmd = old_chain.commands[j]
          next if old_cmd == cmd
          matches = false
          command cmd
        else
          command cmd
        end
      end
    else
      chain.commands.each {|cmd| command cmd}
    end
  end

  rects = (old_context ? old_context.rects.keys : []) + context.rects.keys
  rects.uniq.each do |rect|
    old_block = old_context ? old_context.rects[rect] : nil
    block = context.rects[rect]
    if old_block and !block
      fill rect.x1, rect.y1, rect.z1, rect.x2, rect.y2, rect.z2, 'minecraft:air'
    elsif old_block and old_block != block
      fill rect.x1, rect.y1, rect.z1, rect.x2, rect.y2, rect.z2, block.block_kind, block.block_data, 'replace', old_block.block_kind, old_block.block_data
    else
      fill rect.x1, rect.y1, rect.z1, rect.x2, rect.y2, rect.z2, block.block_kind, block.block_data
    end
  end

  context.chains.select{|x|[:repeat, :impulse_chain].include? x.kind}.each do |c|
    case c.kind
    when :repeat
      do_repeat context, c
    when :impulse_chain
      do_impulse context, c
    end
  end

  locations = (old_context ? old_context.blocks.keys : []) + context.blocks.keys
  locations.uniq.each do |loc|
    old = old_context ? old_context.blocks[loc] : nil
    new = context.blocks[loc]
    do_block(new, old)
  end

  # after blocks are set
  context.chains.select{|x|x.kind == :after}.each do |c|
    self.commands += c.commands
  end
end

#do_impulse(context, chain) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/mcblocky/executor.rb', line 126

def do_impulse(context, chain)
  if chain.rect != @last_area
    @last_area = chain.rect
    @offset = 0
  end
  sequence = fill_space(chain.rect)
  chain.commands << "blockdata #{sequence[@offset].x} #{sequence[@offset].y} #{sequence[@offset].z} {auto:0}"
  if chain.commands.length + @offset > sequence.length
    raise ArgumentError, "Chain is too long for the provided space"
  end
  kind = 'minecraft:command_block'
  nbt = {auto: 0}
  chain.commands.each_with_index do |c,i|
    cursor = sequence[i+@offset]
    next_cursor = if i+1 < sequence.length
                    sequence[i+1]
                  else
                    Location.new(cursor.x, cursor.y+1, cursor.z)
                  end
    facing = if next_cursor.x - cursor.x == 1
               DSL::Facing::EAST
             elsif next_cursor.x - cursor.x == -1
               DSL::Facing::WEST
             elsif next_cursor.y - cursor.y == 1
               DSL::Facing::UP
             elsif next_cursor.y - cursor.y == -1
               DSL::Facing::DOWN
             elsif next_cursor.z - cursor.z == 1
               DSL::Facing::SOUTH
             elsif next_cursor.z - cursor.z == -1
               DSL::Facing::NORTH
             end
    context.blocks[cursor] = DSL::CommandBlock.new(context, cursor.x, cursor.y, cursor.z, facing, kind, nbt)
    context.blocks[cursor].command c
    kind = 'minecraft:chain_command_block'
    nbt = {auto: 1}
  end
  @offset += self.next_power_of_two(chain.commands.length)
end

#do_repeat(context, chain) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/mcblocky/executor.rb', line 89

def do_repeat(context, chain)
  if chain.rect != @last_area
    @last_area = chain.rect
    @offset = 0
  end
  sequence = fill_space(chain.rect)
  if chain.commands.length + @offset > sequence.length
    raise ArgumentError, "Chain is too long for the provided space"
  end
  kind = 'minecraft:repeating_command_block'
  chain.commands.each_with_index do |c,i|
    cursor = sequence[i+@offset]
    next_cursor = if i+1 < sequence.length
                    sequence[i+1]
                  else
                    Location.new(cursor.x, cursor.y+1, cursor.z)
                  end
    facing = if next_cursor.x - cursor.x == 1
               DSL::Facing::EAST
             elsif next_cursor.x - cursor.x == -1
               DSL::Facing::WEST
             elsif next_cursor.y - cursor.y == 1
               DSL::Facing::UP
             elsif next_cursor.y - cursor.y == -1
               DSL::Facing::DOWN
             elsif next_cursor.z - cursor.z == 1
               DSL::Facing::SOUTH
             elsif next_cursor.z - cursor.z == -1
               DSL::Facing::NORTH
             end
    context.blocks[cursor] = DSL::CommandBlock.new(context, cursor.x, cursor.y, cursor.z, facing, kind, {'auto'=>1})
    context.blocks[cursor].command c
    kind = 'minecraft:chain_command_block'
  end
  @offset += self.next_power_of_two(chain.commands.length)
end

#fill_space(rect) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/mcblocky/executor.rb', line 166

def fill_space(rect)
  path = []
  zrange = rect.z1..rect.z2
  zrange.each do |z|
    rz = z - rect.z1
    yrange = rect.y1..rect.y2
    yrange = yrange.to_a.reverse if rz % 2 != 0
    yrange.each do |y|
      ry = y - rect.y1
      xrange = rect.x1..rect.x2
      xrange = xrange.to_a.reverse if (ry+rz) % 2 != 0
      xrange.each do |x|
        path << Location.new(x, y, z)
      end
    end
  end
  path
end