rubycraft 0.1.0 → 0.1.1
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 +3 -1
- data/VERSION +1 -1
- data/lib/rubycraft.rb +5 -0
- data/lib/rubycraft/block.rb +78 -0
- data/lib/rubycraft/block_type.rb +193 -0
- data/lib/rubycraft/byte_converter.rb +48 -0
- data/lib/rubycraft/chunk.rb +120 -0
- data/lib/rubycraft/matrix3d.rb +87 -0
- data/lib/rubycraft/nbt_helper.rb +49 -0
- data/lib/rubycraft/region.rb +259 -0
- metadata +11 -10
- data/lib/block.rb +0 -77
- data/lib/block_type.rb +0 -191
- data/lib/byte_converter.rb +0 -46
- data/lib/chunk.rb +0 -118
- data/lib/matrix3d.rb +0 -86
- data/lib/nbt_helper.rb +0 -48
- data/lib/region.rb +0 -257
data/README.md
CHANGED
@@ -2,7 +2,9 @@ RubyCraft
|
|
2
2
|
==============
|
3
3
|
|
4
4
|
RubyCraft is a simple library for manipulating [Minecraft](http://www.minecraft.net/)
|
5
|
-
region files.
|
5
|
+
region files. Installation is as simple as:
|
6
|
+
|
7
|
+
$ gem install rubycraft
|
6
8
|
|
7
9
|
Region files are files with the mcr extension on the region folder of a save folder. The
|
8
10
|
save folders are located below the saves folder of the minecraft data folder (for
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/lib/rubycraft.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'rubycraft/block_type'
|
2
|
+
|
3
|
+
module RubyCraft
|
4
|
+
# A minecraft block. Its position is given by a coord[x, z, y]
|
5
|
+
class Block
|
6
|
+
|
7
|
+
attr_accessor :block_type, :pos, :data
|
8
|
+
def initialize(blockType, data = 0)
|
9
|
+
@blockType = blockType
|
10
|
+
@data = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.get(key)
|
14
|
+
new BlockType.get key
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.of(key)
|
18
|
+
self[key]
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.[](key)
|
22
|
+
new BlockType[key]
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def color=(color)
|
27
|
+
@data = BlockColor::InvertedColor[color]
|
28
|
+
end
|
29
|
+
|
30
|
+
def color
|
31
|
+
BlockColor.typeColor[@data].name
|
32
|
+
end
|
33
|
+
|
34
|
+
def blockColor
|
35
|
+
BlockColor.typeColor[@data]
|
36
|
+
end
|
37
|
+
|
38
|
+
def is(name)
|
39
|
+
self.name == name.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
def name
|
43
|
+
@blockType.name
|
44
|
+
end
|
45
|
+
|
46
|
+
def id
|
47
|
+
@blockType.id
|
48
|
+
end
|
49
|
+
|
50
|
+
def transparent
|
51
|
+
@blockType.transparent
|
52
|
+
end
|
53
|
+
|
54
|
+
#sets block type by name
|
55
|
+
def name=(newName)
|
56
|
+
return if name == newName.to_s
|
57
|
+
@blockType = BlockType[newName]
|
58
|
+
end
|
59
|
+
|
60
|
+
#sets block type by id
|
61
|
+
def id=(id)
|
62
|
+
return if id == id
|
63
|
+
@blockType = BlockType.get id
|
64
|
+
end
|
65
|
+
|
66
|
+
def y
|
67
|
+
pos[2]
|
68
|
+
end
|
69
|
+
|
70
|
+
def z
|
71
|
+
pos[1]
|
72
|
+
end
|
73
|
+
|
74
|
+
def x
|
75
|
+
pos[0]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
module RubyCraft
|
2
|
+
BlockTypeDSL = proc do
|
3
|
+
transparent_block 0, :air
|
4
|
+
block 1, :stone
|
5
|
+
block 2, :grass
|
6
|
+
block 3, :dirt
|
7
|
+
block 4, :cobblestone
|
8
|
+
block 5, :planks
|
9
|
+
transparent_block 6, :sapling
|
10
|
+
block 7, :bedrock
|
11
|
+
block 8, :watersource
|
12
|
+
block 9, :water
|
13
|
+
block 10, :lavasource
|
14
|
+
block 11, :lava
|
15
|
+
block 12, :sand
|
16
|
+
block 13, :gravel
|
17
|
+
block 14, :goldore
|
18
|
+
block 15, :ironore
|
19
|
+
block 16, :coal
|
20
|
+
block 17, :log
|
21
|
+
block 18, :leaves
|
22
|
+
block 19, :sponge
|
23
|
+
transparent_block 20, :glass
|
24
|
+
block 21, :lapisore
|
25
|
+
block 22, :lapis
|
26
|
+
block 23, :dispenser
|
27
|
+
block 24, :sandstone
|
28
|
+
block 25, :note
|
29
|
+
block 26, :bed
|
30
|
+
transparent_block 27, :powered_rail
|
31
|
+
transparent_block 28, :detector_rail
|
32
|
+
block 29, :sticky_piston
|
33
|
+
transparent_block 30, :cobweb
|
34
|
+
transparent_block 31, :tall_grass
|
35
|
+
transparent_block 32, :dead_shrubs
|
36
|
+
block 33, :piston
|
37
|
+
block 34, :piston_extension
|
38
|
+
block 35, :wool
|
39
|
+
transparent_block 37, :dandelion
|
40
|
+
transparent_block 38, :rose
|
41
|
+
transparent_block 39, :brown_mushroom
|
42
|
+
transparent_block 40, :red_mushroom
|
43
|
+
block 41, :gold
|
44
|
+
block 42, :iron
|
45
|
+
block 43, :slabs
|
46
|
+
block 44, :slab
|
47
|
+
block 45, :brick
|
48
|
+
block 46, :tnt
|
49
|
+
block 47, :bookshelf
|
50
|
+
block 48, :mossy
|
51
|
+
block 49, :obsidian
|
52
|
+
transparent_block 50, :torch
|
53
|
+
transparent_block 51, :fire
|
54
|
+
block 52, :spawner
|
55
|
+
block 53, :stairs
|
56
|
+
block 54, :chest
|
57
|
+
transparent_block 55, :redstone_wire
|
58
|
+
block 56, :diamond_ore
|
59
|
+
block 57, :diamond_block
|
60
|
+
block 58, :crafting_table
|
61
|
+
block 59, :seeds
|
62
|
+
block 60, :farmland
|
63
|
+
block 61, :furnace
|
64
|
+
block 62, :burning_furnace
|
65
|
+
transparent_block 63, :signpost
|
66
|
+
transparent_block 64, :door
|
67
|
+
transparent_block 65, :ladder
|
68
|
+
transparent_block 66, :rails
|
69
|
+
block 67, :cobblestone_stairs
|
70
|
+
transparent_block 68, :wall_sign
|
71
|
+
transparent_block 69, :lever
|
72
|
+
transparent_block 70, :stone_pressure_plate
|
73
|
+
transparent_block 71, :iron_door
|
74
|
+
transparent_block 72, :wooden_pressure_plate
|
75
|
+
block 73, :redstone_ore
|
76
|
+
block 74, :glowing_redstone_ore
|
77
|
+
transparent_block 75, :redstone_torch_off
|
78
|
+
transparent_block 76, :redstone_torch_on
|
79
|
+
transparent_block 77, :stone_button
|
80
|
+
block 78, :snow
|
81
|
+
block 79, :ice
|
82
|
+
block 80, :snow_block
|
83
|
+
transparent_block 81, :cactus
|
84
|
+
block 82, :clay
|
85
|
+
block 83, :sugar_cane
|
86
|
+
block 84, :jukebox
|
87
|
+
transparent_block 85, :fence
|
88
|
+
block 86, :pumpkin
|
89
|
+
block 87, :netherrack
|
90
|
+
block 88, :soulsand
|
91
|
+
block 89, :glowstone
|
92
|
+
transparent_block 90, :portal
|
93
|
+
block 91, :jock_o_lantern
|
94
|
+
transparent_block 92, :cake
|
95
|
+
transparent_block 93, :repeater_off
|
96
|
+
transparent_block 94, :repeater_on
|
97
|
+
block 95, :locked_chest
|
98
|
+
transparent_block 96, :trapdoor
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
# DSL: color name r, g, b
|
103
|
+
BlockColorDSL = proc do
|
104
|
+
white 221, 221, 221
|
105
|
+
orange 233, 126, 55
|
106
|
+
magenta 179, 75, 200
|
107
|
+
light_blue 103, 137, 211
|
108
|
+
yellow 192, 179, 28
|
109
|
+
light_green 59, 187, 47
|
110
|
+
pink 217, 132, 153
|
111
|
+
dark_gray 66, 67, 67
|
112
|
+
gray 157, 164, 165
|
113
|
+
cyan 39, 116, 148
|
114
|
+
purple 128, 53, 195
|
115
|
+
blue 39, 51, 153
|
116
|
+
brown 85, 51, 27
|
117
|
+
dark_green 55, 76, 24
|
118
|
+
red 162, 44, 42
|
119
|
+
black 26, 23, 23
|
120
|
+
end
|
121
|
+
|
122
|
+
class BlockColor
|
123
|
+
@typeColor = []
|
124
|
+
|
125
|
+
def self.method_missing(name, *args)
|
126
|
+
args << @typeColor.size
|
127
|
+
@typeColor << new(name, *args)
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.typeColor
|
131
|
+
@typeColor
|
132
|
+
end
|
133
|
+
|
134
|
+
attr_reader :name, :r, :g, :b, :data
|
135
|
+
def initialize(name, r, g, b, data)
|
136
|
+
@name = name
|
137
|
+
@r = r
|
138
|
+
@g = g
|
139
|
+
@b = b
|
140
|
+
@data = data
|
141
|
+
end
|
142
|
+
|
143
|
+
def rgb
|
144
|
+
[r, g, b]
|
145
|
+
end
|
146
|
+
|
147
|
+
class_eval &BlockColorDSL
|
148
|
+
InvertedColor = Hash[typeColor.each_with_index.map { |obj, i| [obj.name, i] }]
|
149
|
+
end
|
150
|
+
|
151
|
+
# class methods and dsl for block
|
152
|
+
class BlockType
|
153
|
+
@blocks = {}
|
154
|
+
@blocks_by_name = {}
|
155
|
+
attr_reader :id, :name, :transparent
|
156
|
+
|
157
|
+
def initialize(id, name, transparent)
|
158
|
+
@id = id
|
159
|
+
@name = name.to_s
|
160
|
+
@transparent = transparent
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.block(id, name, transparent = false)
|
164
|
+
block = new id, name, transparent
|
165
|
+
@blocks[id] = block
|
166
|
+
@blocks_by_name[name.to_s] = block
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.transparent_block(id, name)
|
171
|
+
block id, name, true
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.get(key)
|
175
|
+
if @blocks.has_key?(key)
|
176
|
+
return @blocks[key].clone
|
177
|
+
end
|
178
|
+
new(key, "unknown(#{key})", false)
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.of(key)
|
182
|
+
self[key]
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.[](key)
|
186
|
+
key = key.to_s
|
187
|
+
return @blocks_by_name[key] if @blocks_by_name.has_key?(key)
|
188
|
+
raise "no such name: #{key}"
|
189
|
+
end
|
190
|
+
|
191
|
+
class_eval &BlockTypeDSL
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module RubyCraft
|
4
|
+
# Utils for manipulating bytes back and forth as strings, strings and numbers
|
5
|
+
module ByteConverter
|
6
|
+
def toByteString(array)
|
7
|
+
array.pack('C*')
|
8
|
+
end
|
9
|
+
|
10
|
+
def intBytes(i)
|
11
|
+
[i >> 24, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF]
|
12
|
+
end
|
13
|
+
|
14
|
+
def stringToByteArray(str)
|
15
|
+
str.bytes.to_a
|
16
|
+
end
|
17
|
+
|
18
|
+
def arrayToIO(arr)
|
19
|
+
io = StringIO.new
|
20
|
+
io.write toByteString arr
|
21
|
+
io.rewind
|
22
|
+
io
|
23
|
+
end
|
24
|
+
|
25
|
+
def stringToIo(str)
|
26
|
+
arrayToIO stringToByteArray(str)
|
27
|
+
end
|
28
|
+
|
29
|
+
def concat(array, enum)
|
30
|
+
for i in enum
|
31
|
+
array << i
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def bytesToInt(array)
|
36
|
+
array.pack('C*').unpack("N").first
|
37
|
+
end
|
38
|
+
|
39
|
+
def pad(array, count, value = 0)
|
40
|
+
count.times do
|
41
|
+
array << value
|
42
|
+
end
|
43
|
+
array
|
44
|
+
end
|
45
|
+
|
46
|
+
extend self
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# Represents a chunk data
|
2
|
+
require 'rubycraft/nbt_helper'
|
3
|
+
require 'rubycraft/byte_converter'
|
4
|
+
require 'rubycraft/block'
|
5
|
+
require 'rubycraft/matrix3d'
|
6
|
+
|
7
|
+
module RubyCraft
|
8
|
+
# Chunks are enumerable over blocks
|
9
|
+
class Chunk
|
10
|
+
include Enumerable
|
11
|
+
include ZlibHelper
|
12
|
+
|
13
|
+
Width = 16
|
14
|
+
Length = 16
|
15
|
+
Height = 128
|
16
|
+
|
17
|
+
def self.fromNbt(bytes)
|
18
|
+
new NbtHelper.fromNbt bytes
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(nbtData)
|
22
|
+
name, @nbtBody = nbtData
|
23
|
+
bytes = level["Blocks"].value.bytes
|
24
|
+
@blocks = matrixfromBytes bytes
|
25
|
+
@blocks.each_triple_index do |b, z, x, y|
|
26
|
+
b.pos = [z, x, y]
|
27
|
+
end
|
28
|
+
data = level["Data"].value.bytes.to_a
|
29
|
+
@blocks.each_with_index do |b, index|
|
30
|
+
v = data[index / 2]
|
31
|
+
if index % 2 == 0
|
32
|
+
b.data = v & 0xF
|
33
|
+
else
|
34
|
+
b.data = v >> 4
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Iterates over the blocks
|
40
|
+
def each(&block)
|
41
|
+
@blocks.each &block
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# Converts all blocks on data do another type. Gives the block and sets
|
46
|
+
# the received name
|
47
|
+
def block_map(&block)
|
48
|
+
each { |b| b.name = yield b }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Converts all blocks on data do another type. Gives the block name sets
|
52
|
+
# the received name
|
53
|
+
def block_type_map(&block)
|
54
|
+
each { |b| b.name = yield b.name.to_sym }
|
55
|
+
end
|
56
|
+
|
57
|
+
def [](z, x, y)
|
58
|
+
@blocks[z, x, y]
|
59
|
+
end
|
60
|
+
|
61
|
+
def []=(z, x, y, value)
|
62
|
+
@blocks[z, x, y] = value
|
63
|
+
end
|
64
|
+
|
65
|
+
def export
|
66
|
+
level["Data"] = byteArray exportLevelData
|
67
|
+
level["Blocks"] = byteArray @blocks.map { |b| b.id }
|
68
|
+
level["HeightMap"] = byteArray exportHeightMap
|
69
|
+
["", @nbtBody]
|
70
|
+
end
|
71
|
+
|
72
|
+
def toNbt
|
73
|
+
NbtHelper.toBytes export
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
def exportHeightMap
|
78
|
+
zwidth, xwidth, ywidth = @blocks.bounds
|
79
|
+
matrix = Array.new(zwidth) { Array.new(xwidth) { 1 }}
|
80
|
+
@blocks.each_triple_index do |b, z, x, y|
|
81
|
+
unless b.transparent
|
82
|
+
matrix[z][x] = [matrix[z][x], y + 1].max
|
83
|
+
end
|
84
|
+
end
|
85
|
+
ret = []
|
86
|
+
matrix.each do |line|
|
87
|
+
line.each do |height|
|
88
|
+
ret << height
|
89
|
+
end
|
90
|
+
end
|
91
|
+
ret
|
92
|
+
end
|
93
|
+
|
94
|
+
def level
|
95
|
+
@nbtBody["Level"]
|
96
|
+
end
|
97
|
+
|
98
|
+
def exportLevelData
|
99
|
+
data = []
|
100
|
+
@blocks.each_with_index do |b, i|
|
101
|
+
if i % 2 == 0
|
102
|
+
data << b.data
|
103
|
+
else
|
104
|
+
data[i / 2] += (b.data << 4)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
data
|
108
|
+
end
|
109
|
+
|
110
|
+
def byteArray(data)
|
111
|
+
NBTFile::Types::ByteArray.new ByteConverter.toByteString(data)
|
112
|
+
end
|
113
|
+
|
114
|
+
def matrixfromBytes(bytes)
|
115
|
+
Matrix3d.new(Width, Length, Height).fromArray bytes.map {|byte| Block.get(byte) }
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|