barneygale / quarry

Python library that implements the Minecraft network protocol and data types
Other
532 stars 74 forks source link

Create a empty chunk #70

Closed AlexisHuvier closed 5 years ago

AlexisHuvier commented 5 years ago

Hello.

I want to create a empty chunk but i don't know how use chunk_data packet...

Can you help me ?

barneygale commented 5 years ago

There's some docs coming for this soon, but you want something like:

    def send_chunk(self, x, z, full, heightmap, sections, biomes, block_entities):
        self.send_packet(
            'chunk_data',
            self.buff_type.pack('ii?', x, z, full),
            self.buff_type.pack_chunk_bitmask(sections),
            self.buff_type.pack_nbt(heightmap),  # added in 1.14
            self.buff_type.pack_chunk(sections, biomes),
            self.buff_type.pack_varint(len(block_entities)),
            b"".join(self.buff_type.pack_nbt(entity) for entity in block_entities))

sections should be a python list with 16 elements, where each element is either None (an all-air chunk) or a 3-tuple of (blocks, block_light, sky_light). The blocks element is an instance of BlockArray, the others will be either PackedArray or None depending on your dimension and the MC version. You can create an empty BlockArray via BlockArray.empty()

AlexisHuvier commented 5 years ago

Thanks :D

AlexisHuvier commented 5 years ago

I have some problem : First, pack_chunk_bitmask doesn't exist for the 1.14 Buffer Second, What is heightmap ? A list of int ? For the end, what is biomes ?

Thanks for all

barneygale commented 5 years ago

First, pack_chunk_bitmask doesn't exist for the 1.14 Buffer

Try using the latest master.

Second, What is heightmap ? A list of int ?

It's an NBT tag, something like TagRoot --> TagCompound --> TagLongArray. The TagCompound has elements like "MOTION_BLOCKING". You'll probably want to check what vanilla MC does, either by checking out the contents of an .mca file or using a proxy.

For the end, what is biomes ?

List of 256 integers, corresponding to biome IDs for the 16x16 (x, z) chunk

AlexisHuvier commented 5 years ago

With the latest master, i have a error :

Traceback (most recent call last):
  File "D:/Programmation/Python/Projet/PyMine/PyMine/PyMine.py", line 1, in <module>
    from Core import Factory
  File "D:\Programmation\Python\Projet\PyMine\PyMine\Core\__init__.py", line 1, in <module>
    from Core.Protocol import Protocol
  File "D:\Programmation\Python\Projet\PyMine\PyMine\Core\Protocol.py", line 1, in <module>
    from quarry.net.server import ServerProtocol
  File "C:\Users\LavaPower\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quarry\net\server.py", line 5, in <module>
    from quarry.net.protocol import Factory, Protocol, ProtocolError, \
  File "C:\Users\LavaPower\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quarry\net\protocol.py", line 5, in <module>
    from quarry.types.buffer import BufferUnderrun, buff_types
  File "C:\Users\LavaPower\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quarry\types\buffer\__init__.py", line 6, in <module>
    from quarry.types.buffer.v1_9 import Buffer1_9
  File "C:\Users\LavaPower\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quarry\types\buffer\v1_9.py", line 2, in <module>
    from quarry.types.chunk import PackedArray, BlockArray
  File "C:\Users\LavaPower\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quarry\types\chunk.py", line 2, in <module>
    from bitstring import BitArray, Bits
ModuleNotFoundError: No module named 'bitstring'
barneygale commented 5 years ago

pip install bitstring

AlexisHuvier commented 5 years ago

Last question. I have some region file (.mca). How use "RegionFile" to send map to players ?

barneygale commented 5 years ago

TBH I should look into adding that as core functionality, as it's pretty fiddly. I'll get back to you.

AlexisHuvier commented 5 years ago

Yes, it will be interesting to add this.

AlexisHuvier commented 5 years ago

If you want some help, im here

barneygale commented 5 years ago

On second thought, I'm inclined not to add it to the core just to keep chunk handling in quarry nice and generic.

Roughly you'll need to:

Bear in mind you might want to keep some chunks in-memory rather than loading from disk each time.

You'll need to construct the sections list yourself. You can use BlockArray.from_nbt() and pass a section tag (i.e. a TagCompound containing a "BlockStates" field) for each section present in the NBT. I think something like this should work:

sections = [None] * 16
for section in level.value["Sections"].value:
    y = section.value["Y"].value
    sections[y] = BlockArray.from_nbt(section)

You might not want to send all sections in the chunk to the client.

AlexisHuvier commented 5 years ago

With this code, i have an error : File "C:\Users\LavaPower\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quarry\types\chunk.py", line 330, in from_nbt nbt_palette = section.value['Palette'] builtins.KeyError: 'Palette'

barneygale commented 5 years ago

Could you print(section)?

AlexisHuvier commented 5 years ago

TagCompound({'SkyLight': TagByteArray(<PackedArray len=4096 sector=8 value=4 fresh=0 twiddled=0>), 'Y': TagByte(-1)})

barneygale commented 5 years ago

I suppose you need to add a condition like:

if 0 <= y < 16:
    sections[y] = ...

I think light-only sections were added in 1.14. See also here

AlexisHuvier commented 5 years ago

I made a fix but i have an other error : File "C:\Users\LavaPower\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quarry\types\buffer\v1_9.py", line 31, in pack_chunk_bitmask if section and not section[0].is_empty(): builtins.AttributeError: 'dict' object has no attribute 'is_empty'

barneygale commented 5 years ago

Sorry, one more try:

sections = [None] * 16
for section in level.value["Sections"].value:
    y = section.value["Y"].value
    if 0 <= y < 16:
        blocks = BlockArray.from_nbt(section)
        block_light = None
        sky_light = None
        sections[y] = (blocks, block_light, sky_light)

Basically you want the section to be a 3-tuple

AlexisHuvier commented 5 years ago

image

barneygale commented 5 years ago

Probably you need to embed the heightmap compound in a TagRoot. You can use the TagRoot.from_body() constructor for this purpose.

AlexisHuvier commented 5 years ago

It works ! Thanks you !