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.
@@ -0,0 +1,87 @@
1
+ module RubyCraft
2
+ class IndexOutOfBoundsError < StandardError
3
+
4
+ end
5
+
6
+ class Matrix3d
7
+ include Enumerable
8
+
9
+ def bounds
10
+ [@xlimit, @ylimit, @zlimit]
11
+ end
12
+
13
+ def initialize(d1,d2,d3)
14
+ @xlimit = d1
15
+ @ylimit = d2
16
+ @zlimit = d3
17
+ @data = Array.new(d1) { Array.new(d2) { Array.new(d3) } }
18
+ end
19
+
20
+ def [](x, y, z)
21
+ @data[x][y][z]
22
+ end
23
+
24
+ def []=(x, y, z, value)
25
+ @data[x][y][z] = value
26
+ end
27
+
28
+ def put(index, value)
29
+ ar = indexToArray(index)
30
+ self[*ar] = value
31
+ end
32
+
33
+ def get(index)
34
+ ar = indexToArray(index)
35
+ self[*ar]
36
+ end
37
+
38
+ def each(&block)
39
+ for z in @data
40
+ for y in z
41
+ for x in y
42
+ yield x
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def each_triple_index(&block)
49
+ return enum_for:each_triple_index unless block_given?
50
+ @data.each_with_index do |plane, x|
51
+ plane.each_with_index do |column, y|
52
+ column.each_with_index do |value, z|
53
+ yield value, x ,y ,z
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ #Actually from any iterable
60
+ def fromArray(ar)
61
+ ar.each_with_index { |obj,i| put i, obj }
62
+ return self
63
+ end
64
+
65
+
66
+ def to_a(default = nil)
67
+ map do |x|
68
+ if x.nil?
69
+ default
70
+ else
71
+ x
72
+ end
73
+ end
74
+ end
75
+
76
+ protected
77
+ def indexToArray(index)
78
+ x = index / (@zlimit * @ylimit)
79
+ index -= x * (@zlimit * @ylimit)
80
+ y = index / @zlimit
81
+ z = index % @zlimit
82
+ return x, y, z
83
+ end
84
+
85
+
86
+ end
87
+ end
@@ -0,0 +1,49 @@
1
+ require 'nbtfile'
2
+ require 'zlib'
3
+ require 'rubycraft/byte_converter'
4
+ # Patching nbtfile clases so that they don't gzip/ungzip incorrectly the zlib bytes from
5
+ #mcr files. Use the methods from ZlibHelper
6
+ class NBTFile::Private::Tokenizer
7
+ def initialize(io)
8
+ @gz = io
9
+ @state = NBTFile::Private::TopTokenizerState.new
10
+ end
11
+ end
12
+
13
+ class NBTFile::Emitter
14
+ def initialize(stream)
15
+ @gz = stream
16
+ @state = NBTFile::Private::TopEmitterState.new
17
+ end
18
+ end
19
+
20
+ module RubyCraft
21
+ module ZlibHelper
22
+ def compress(str)
23
+ Zlib::Deflate.deflate(str)
24
+ end
25
+
26
+ def decompress(str)
27
+ Zlib::Inflate.inflate(str)
28
+ end
29
+ extend self
30
+ end
31
+
32
+ # Handles converting bytes to/from nbt regions, which are compressesed/decompress
33
+ module NbtHelper
34
+ extend ByteConverter
35
+ extend ZlibHelper
36
+
37
+ module_function
38
+ def fromNbt(bytes)
39
+ NBTFile.read stringToIo decompress toByteString bytes
40
+ end
41
+
42
+ def toBytes(nbt)
43
+ output = StringIO.new
44
+ name, body = nbt
45
+ NBTFile.write(output, name, body)
46
+ stringToByteArray compress output.string
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,259 @@
1
+ require 'rubycraft/chunk'
2
+
3
+ module RubyCraft
4
+ class LazyChunkDelegate
5
+ include ByteConverter
6
+ include ZlibHelper
7
+
8
+ def initialize(bytes)
9
+ @bytes = bytes
10
+ @chunk = nil
11
+ end
12
+
13
+ def each(&block)
14
+ _getchunk.each &block
15
+ end
16
+
17
+ def block_map(&block)
18
+ _getchunk.block_map &block
19
+ end
20
+ def block_type_map(&block)
21
+ _getchunk.block_type_map &block
22
+ end
23
+
24
+ def [](z, x, y)
25
+ _getchunk[z, x, y]
26
+ end
27
+
28
+ def []=(z, x, y, value)
29
+ _getchunk[z, x, y] = value
30
+ end
31
+
32
+ def export
33
+ _getchunk.export
34
+ end
35
+
36
+
37
+ def toNbt
38
+ return @bytes if @chunk.nil?
39
+ @chunk.toNbt
40
+ end
41
+
42
+
43
+ # unloacs the loaded chunk. Needed for memory optmization
44
+ def _unload
45
+ return if @chunk.nil?
46
+ @bytes = @chunk.toNbt
47
+ @chunk = nil
48
+ end
49
+
50
+ protected
51
+ def _getchunk
52
+ if @chunk.nil?
53
+ @chunk = Chunk.fromNbt @bytes
54
+ end
55
+ @chunk
56
+ end
57
+
58
+ end
59
+
60
+ # Enumerable over chunks
61
+ class Region
62
+ include Enumerable
63
+ include ByteConverter
64
+ include ZlibHelper
65
+
66
+ class RegionWritter
67
+ def initialize(io)
68
+ @io = io
69
+ end
70
+
71
+ def pad(count, value = 0)
72
+ self << Array.new(count) { value }
73
+ end
74
+
75
+ def <<(o)
76
+ input = o.kind_of?(Array) ? o : [o]
77
+ @io << ByteConverter.toByteString(input)
78
+ end
79
+
80
+ def close
81
+ @io.close
82
+ end
83
+ end
84
+
85
+ def self.fromFile(filename)
86
+ new ByteConverter.stringToByteArray IO.read filename
87
+ end
88
+
89
+ def initialize(bytes)
90
+ raise "Must be an io" if bytes.kind_of?(String)
91
+ @bytes = bytes
92
+ @chunks = Array.new(32) { Array.new(32) }
93
+ readChunks bytes
94
+ end
95
+
96
+ def chunk(z, x)
97
+ @chunks[z][x]
98
+ end
99
+
100
+ def unloadChunk(z, x)
101
+ @chunks[z][x]._unload
102
+ end
103
+
104
+ def each(&block)
105
+ @chunks.each do |line|
106
+ line.each do |chunk|
107
+ yield chunk
108
+ end
109
+ end
110
+ end
111
+
112
+ def cube(z, y, x, opts = {}, &block)
113
+ c = ChunkCube.new(self, [z, y, x], opts[:width], opts[:length], opts[:height])
114
+ return c unless block_given?
115
+ c.each &block
116
+ end
117
+
118
+ def exportTo(io)
119
+ output = RegionWritter.new io
120
+ chunks = getChunks
121
+ writeChunkOffsets output, chunks
122
+ output.pad blockSize, dummytimestamp
123
+ writeChunks output, chunks
124
+ output.close
125
+ end
126
+
127
+ def exportToFile(filename)
128
+ File.open(filename, "wb") { |f| exportTo f }
129
+ end
130
+
131
+
132
+ protected
133
+ def readChunks(bytes)
134
+ bytes[0..(blockSize - 1)].each_slice(4).each_with_index do |ar, i|
135
+ offset = bytesToInt [0] + ar[0..-2]
136
+ count = ar.last
137
+ if count > 0
138
+ @chunks[i / 32][i % 32 ] = readChunk(offset, bytes)
139
+ end
140
+ end
141
+ end
142
+
143
+ def readChunk(offset, bytes)
144
+ o = offset * blockSize
145
+ bytecount = bytesToInt bytes[o..(o + 4)]
146
+ o += 5
147
+ nbtBytes = bytes[o..(o + bytecount - 2)]
148
+ LazyChunkDelegate.new nbtBytes
149
+ end
150
+
151
+ def chunkSize(chunk)
152
+ chunk.size + chunkMetaDataSize
153
+ end
154
+
155
+ def chunkBlocks(chunk)
156
+ ((chunkSize chunk).to_f / blockSize).ceil
157
+ end
158
+
159
+ def writeChunks(output, chunks)
160
+ for chunk in chunks
161
+ next if chunk.nil?
162
+ output << intBytes(chunk.size + 1)
163
+ output << defaultCompressionType
164
+ output << chunk
165
+ remaining = blockSize - chunkSize(chunk)
166
+ output.pad remaining % blockSize
167
+ end
168
+ end
169
+
170
+ def writeChunkOffsets(output, chunks)
171
+ lastVacantPosition = 2
172
+ for chunk in chunks
173
+ if chunk
174
+ sizeCount = chunkBlocks chunk
175
+ output << intBytes(lastVacantPosition)[1..3]
176
+ output << sizeCount
177
+ lastVacantPosition += sizeCount
178
+ else
179
+ output.pad 4
180
+ end
181
+ end
182
+ end
183
+
184
+ def getChunks
185
+ map do |chunk|
186
+ if chunk.nil?
187
+ nil
188
+ else
189
+ chunk.toNbt
190
+ end
191
+ end
192
+ end
193
+
194
+ def chunkMetaDataSize
195
+ 5
196
+ end
197
+
198
+ def defaultCompressionType
199
+ 2
200
+ end
201
+
202
+ def dummytimestamp
203
+ 0
204
+ end
205
+
206
+ def blockSize
207
+ 4096
208
+ end
209
+
210
+ end
211
+
212
+
213
+ class ChunkCube
214
+ include Enumerable
215
+
216
+ # width corresponds do z, length to x, and height to y.
217
+ def initialize(region, initialPos, width, length, height)
218
+ @region = region
219
+ @initialPos = initialPos
220
+ @width = width || 1
221
+ @length = length || 1
222
+ @height = height || 1
223
+ end
224
+
225
+ def each(&block)
226
+ z, x, y = @initialPos
227
+ firstChunkX = x / chunkSide
228
+ firstChunkZ = z / chunkSide
229
+ lastChunkX = (x + @length - 1) / chunkSide
230
+ lastChunkZ = (z + @width - 1) / chunkSide
231
+ for j in firstChunkZ..lastChunkZ
232
+ for i in firstChunkX..lastChunkX
233
+ iterateOverChunk j, i, &block
234
+ end
235
+ end
236
+ end
237
+
238
+ protected
239
+ def iterateOverChunk(j, i, &block)
240
+ chunk = @region.chunk(j, i)
241
+ return if chunk.nil?
242
+ z, x, y = @initialPos
243
+ chunk.each do |b|
244
+ globalZ = b.z + (j * chunkSide)
245
+ globalX = b.x + (i * chunkSide)
246
+ if globalZ.between?(z, z + @width - 1) and
247
+ globalX.between?(x, x + @length - 1) and
248
+ b.y.between?(y, y + @height - 1)
249
+ yield b, globalZ - z, globalX - x , b.y - y
250
+ end
251
+ end
252
+ @region.unloadChunk(j, i)
253
+ end
254
+
255
+ def chunkSide
256
+ 16
257
+ end
258
+ end
259
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubycraft
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Daniel Ribeiro
@@ -48,13 +48,14 @@ files:
48
48
  - README.md
49
49
  - Rakefile
50
50
  - VERSION
51
- - lib/block.rb
52
- - lib/block_type.rb
53
- - lib/byte_converter.rb
54
- - lib/chunk.rb
55
- - lib/matrix3d.rb
56
- - lib/nbt_helper.rb
57
- - lib/region.rb
51
+ - lib/rubycraft.rb
52
+ - lib/rubycraft/block.rb
53
+ - lib/rubycraft/block_type.rb
54
+ - lib/rubycraft/byte_converter.rb
55
+ - lib/rubycraft/chunk.rb
56
+ - lib/rubycraft/matrix3d.rb
57
+ - lib/rubycraft/nbt_helper.rb
58
+ - lib/rubycraft/region.rb
58
59
  has_rdoc: true
59
60
  homepage: http://github.com/danielribeiro/RubyCraft
60
61
  licenses: []
@@ -1,77 +0,0 @@
1
- require 'block_type'
2
-
3
- # A minecraft block. Its position is given by a coord[x, z, y]
4
- class Block
5
-
6
- attr_accessor :block_type, :pos, :data
7
- def initialize(blockType, data = 0)
8
- @blockType = blockType
9
- @data = 0
10
- end
11
-
12
- def self.get(key)
13
- new BlockType.get key
14
- end
15
-
16
- def self.of(key)
17
- self[key]
18
- end
19
-
20
- def self.[](key)
21
- new BlockType[key]
22
- end
23
-
24
-
25
- def color=(color)
26
- @data = BlockColor::InvertedColor[color]
27
- end
28
-
29
- def color
30
- BlockColor.typeColor[@data].name
31
- end
32
-
33
- def blockColor
34
- BlockColor.typeColor[@data]
35
- end
36
-
37
- def is(name)
38
- self.name == name.to_s
39
- end
40
-
41
- def name
42
- @blockType.name
43
- end
44
-
45
- def id
46
- @blockType.id
47
- end
48
-
49
- def transparent
50
- @blockType.transparent
51
- end
52
-
53
- #sets block type by name
54
- def name=(newName)
55
- return if name == newName.to_s
56
- @blockType = BlockType[newName]
57
- end
58
-
59
- #sets block type by id
60
- def id=(id)
61
- return if id == id
62
- @blockType = BlockType.get id
63
- end
64
-
65
- def y
66
- pos[2]
67
- end
68
-
69
- def z
70
- pos[1]
71
- end
72
-
73
- def x
74
- pos[0]
75
- end
76
- end
77
-