rubycraft 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-