예제 #1
0
    def send_join_game(self):
        codec = TagRoot({
            '': TagCompound({
                'minecraft:dimension_type': TagCompound({
                    'type': TagString("minecraft:dimension_type"),
                    'value': TagList([
                        TagCompound(self.dimension)
                    ]),
                }),
                'minecraft:worldgen/biome': self.biomes.root_tag.body
            })
        })

        self.protocol.send_packet("join_game",
                                  self.protocol.buff_type.pack("i?BB", 0, False, 3, 3),
                                  self.protocol.buff_type.pack_varint(2),
                                  self.protocol.buff_type.pack_string("rtgame:linking"),
                                  self.protocol.buff_type.pack_string("rtgame:reset"),
                                  self.protocol.buff_type.pack_nbt(codec),
                                  self.protocol.buff_type.pack_nbt(self.current_dimension),
                                  self.protocol.buff_type.pack_string("rtgame:linking"),
                                  self.protocol.buff_type.pack("q", 0),
                                  self.protocol.buff_type.pack_varint(0),
                                  self.protocol.buff_type.pack_varint(32),
                                  self.protocol.buff_type.pack("????", False, True, False, False))
예제 #2
0
    def send_join_game(self):
        codec = TagRoot({
            '': TagCompound({
                'dimension': TagList([
                    TagCompound({
                        'name': TagString("minecraft:overworld"),
                        'natural': TagByte(1),
                        'ambient_light': TagFloat(0.0),
                        'has_ceiling': TagByte(0),
                        'has_skylight': TagByte(1),
                        'shrunk': TagByte(0),
                        'ultrawarm': TagByte(0),
                        'has_raids': TagByte(0),
                        'respawn_anchor_works': TagByte(0),
                        'bed_works': TagByte(0),
                        'piglin_safe': TagByte(0),
                        'logical_height': TagInt(255),
                        'infiniburn': TagString("minecraft:infiniburn_end"),
                    })
                ])
            })
        })

        self.protocol.send_packet("join_game",
                                  self.protocol.buff_type.pack("iBB", 0, 3, 3),
                                  self.protocol.buff_type.pack_varint(1),
                                  self.protocol.buff_type.pack_string("rtgame:linking"),
                                  self.protocol.buff_type.pack_nbt(codec),
                                  self.protocol.buff_type.pack_string("minecraft:overworld"),
                                  self.protocol.buff_type.pack_string("rtgame:linking"),
                                  self.protocol.buff_type.pack("qB", 0, 0),
                                  self.protocol.buff_type.pack_varint(32),
                                  self.protocol.buff_type.pack("????", False, True, False, False))

        self.protocol.send_packet("time_update", self.protocol.buff_type.pack("qq", 1, -18000))
예제 #3
0
    def send_reset_world(self):
        data = [
            self.protocol.buff_type.pack_varint(0),
            b'',
            self.protocol.buff_type.pack_nbt(
                TagRoot({
                    '':
                    TagCompound({
                        "MOTION_BLOCKING":
                        TagLongArray(PackedArray.empty_height())
                    })
                })),
            self.protocol.buff_type.pack_varint(1024),
        ]

        for i in range(1024):
            data.append(self.protocol.buff_type.pack_varint(127))

        data.append(self.protocol.buff_type.pack_varint(0))
        data.append(b'')
        data.append(self.protocol.buff_type.pack_varint(0))
        data.append(b'')

        for x in range(-8, 8):
            for y in range(-8, 8):
                self.protocol.send_packet(
                    "chunk_data", self.protocol.buff_type.pack("ii", x, y),
                    *data)
예제 #4
0
 def send_air_chunk(self, x, z):
     sections = []
     if x == 0 and z == 0:
         sections = [(BlockArray.empty(self.registry), None)
                     for _ in range(16)]
         sections[9][0][0] = {"name": "minecraft:bedrock"}
     sections_data = self.buff_type.pack_chunk(sections)
     motion_world = PackedArray.empty_height()
     motion_blocking = TagLongArray(PackedArray.empty_height())
     world_surface = TagLongArray(PackedArray.empty_height())
     heightmap = TagRoot({
         "":
         TagCompound({
             "MOTION_BLOCKING": motion_blocking,
             "WORLD_SURFACE": world_surface
         })
     })
     biomes = [27 for _ in range(1024)]
     block_entities = []
     self.send_packet(
         "chunk_data",
         self.buff_type.pack("ii?", x, z, True),
         self.buff_type.pack_chunk_bitmask(sections),
         self.buff_type.pack_nbt(heightmap),  # added in 1.14
         self.buff_type.pack_varint(0),
         b"",
         # b"".join(self.buff_type.pack_varint(biome) for biome in biomes),
         # self.buff_type.pack_array("I", biomes),
         self.buff_type.pack_varint(len(sections_data)),
         sections_data,
         self.buff_type.pack_varint(len(block_entities)),
         b""
         # b"".join(self.buff_type.pack_nbt(entity) for entity in block_entities),
     )
예제 #5
0
    def __init__(self, protocol: Protocol, bedrock: False):
        super(Version_1_16_2, self).__init__(protocol, bedrock)
        self.version_name = '1.16.2'

        self.dimension_settings = self.get_dimension_settings()

        self.dimension = {
            'name': TagString("minecraft:overworld"),
            'id': TagInt(0),
            'element': TagCompound(self.dimension_settings),
        }

        self.current_dimension = TagRoot({
            '': TagCompound(self.dimension_settings),
        })

        self.biomes = NBTFile(TagRoot({})).load(os.path.join(path, 'biomes.nbt'))
예제 #6
0
    def __init__(self, protocol: Protocol, bedrock: False):
        super(Version_1_16_2, self).__init__(protocol, bedrock)
        self.version_name = '1.16.2'

        self.dimension_settings = {
            'piglin_safe':
            TagByte(0),
            'natural':
            TagByte(1),
            'ambient_light':
            TagFloat(0.0),
            'infiniburn':
            TagString("minecraft:infiniburn_overworld"),
            'respawn_anchor_works':
            TagByte(0),
            'has_skylight':
            TagByte(0),
            'bed_works':
            TagByte(0),
            "effects":
            TagString("minecraft:overworld")
            if self.is_bedrock else TagString("minecraft:the_nether"),
            'has_raids':
            TagByte(0),
            'logical_height':
            TagInt(256),
            'coordinate_scale':
            TagFloat(1.0),
            'ultrawarm':
            TagByte(0),
            'has_ceiling':
            TagByte(0),
        }

        self.dimension = {
            'name': TagString("minecraft:overworld"),
            'id': TagInt(0),
            'element': TagCompound(self.dimension_settings),
        }

        self.current_dimension = TagRoot({
            '':
            TagCompound(self.dimension_settings),
        })

        self.biomes = NBTFile(TagRoot({})).load('biomes.nbt')
예제 #7
0
 def send_chunk(self, x, z):
     emptyHeight = TagRoot({"": TagCompound({
         "MOTION_BLOCKING": TagLongArray(PackedArray.empty_height())
     })})
     try:
         cdpacket = ChunkDataPacket(self.protocol.buff_type, x, z, False, emptyHeight, [None]*16, [1]*256, [])
         self.protocol.send_packet(cdpacket.type_, *cdpacket.datas)
     except ValueError:
         pass
예제 #8
0
    def send_world(self):
        self.send_spawn()

        # Clear geyser chunk cache from previous server
        if self.is_bedrock:
            data = [
                self.protocol.buff_type.pack_varint(0),
                self.protocol.buff_type.pack_nbt(TagRoot({'':
                                                          TagCompound({})})),
                self.protocol.buff_type.pack_varint(1024),
            ]

            for i in range(0, 1024):
                data.append(self.protocol.buff_type.pack_varint(127))

            data.append(self.protocol.buff_type.pack_varint(0))
            data.append(self.protocol.buff_type.pack_varint(0))

            for x in range(-8, 8):
                for y in range(-8, 8):
                    self.protocol.send_packet(
                        "chunk_data",
                        self.protocol.buff_type.pack("ii?", x, y, True), *data)

        # Chunk packets
        for packet in self.current_world.packets:
            self.protocol.send_packet(packet.get('type'), packet.get('packet'))

        # Start/stop rain as necessary
        if self.current_world.weather == 'rain':
            if self.raining is False:
                self.protocol.send_packet(
                    'change_game_state',
                    self.protocol.buff_type.pack("Bf", 2, 0))
                self.raining = True
        elif self.raining is True:
            self.protocol.send_packet('change_game_state',
                                      self.protocol.buff_type.pack("Bf", 1, 0))
            self.raining = False

        if self.is_bedrock:  # Current versions of geyser seem to ignore the time sometimes. Send repeatedly for now.
            self.protocol.ticker.add_loop(100, self.send_time)
        else:
            self.send_time()
예제 #9
0
    def send_reset_world(self):
        data = [
            self.protocol.buff_type.pack_varint(1),
            self.protocol.buff_type.pack('l', 0),
            self.protocol.buff_type.pack_nbt(TagRoot({'': TagCompound({})})),
            self.protocol.buff_type.pack_varint(1024),
        ]

        for i in range(0, 1024):
            data.append(self.protocol.buff_type.pack_varint(127))

        data.append(self.protocol.buff_type.pack_varint(0))
        data.append(self.protocol.buff_type.pack_varint(0))

        for x in range(-8, 8):
            for y in range(-8, 8):
                self.protocol.send_packet(
                    "chunk_data", self.protocol.buff_type.pack("ii", x, y),
                    *data)
예제 #10
0
    def nbt(self, token: str, bedrock: bool):
        pages = []

        if bedrock:
            for page in self.pages:
                pages.append(TagString(page.replace("[token]", token)))
        else:
            for page in self.pages:
                pages.append(TagString(page.replace("[token]", token)))

        return TagRoot({
            '': TagCompound({
                'resolved': TagInt(1),
                'generation': TagInt(2),
                'author': TagString(self.author),
                'title': TagString(self.title),
                'pages': TagList(pages)
            })
        })
예제 #11
0
    def send_world(self):
        data = [
            self.protocol.buff_type.pack_varint(0),
            self.protocol.buff_type.pack_nbt(TagRoot({'': TagCompound({})})),
            self.protocol.buff_type.pack_varint(1024),
        ]

        for i in range(0, 1024):
            data.append(self.protocol.buff_type.pack_varint(127))

        data.append(self.protocol.buff_type.pack_varint(0))
        data.append(self.protocol.buff_type.pack_varint(0))

        if self.is_bedrock:  # Clear geyser chunk cache from previous server
            for x in range(-8, 8):
                for y in range(-8, 8):
                    self.protocol.send_packet("chunk_data", self.protocol.buff_type.pack("ii?", x, y, True), *data)

            self.protocol.ticker.add_loop(100, self.send_time)
예제 #12
0
    def player_joined(self):
        # Call super. This switches us to "play" mode, marks the player as
        #   in-game, and does some logging.
        ServerProtocol.player_joined(self)
        print(self.protocol_version)

        # Send "Join Game" packet
        dim_name = "minecraft:the_end"

        if self.protocol_version > 736:  # Minecraft 1.16.2
            # Send "Join Game" packet
            biome_codec = TagCompound({
                "type":
                TagString("minecraft:worldgen/biome"),
                "value":
                TagList([
                    TagCompound({
                        "name":
                        TagString(
                            "minecraft:plains"
                        ),  # Client crashes if you do not define plains
                        "id":
                        TagInt(1),
                        "element":
                        TagCompound({
                            "precipitation":
                            TagString("none"),
                            "effects":
                            TagCompound({
                                "sky_color": TagInt(0xFFFFFF),
                                "water_fog_color": TagInt(0),
                                "fog_color": TagInt(0xFFFFFF),
                                "water_color": TagInt(0),
                            }),
                            "depth":
                            TagFloat(0.5),
                            "temperature":
                            TagFloat(1),
                            "scale":
                            TagFloat(0.2),
                            "downfall":
                            TagFloat(0.5),
                            "category":
                            TagString("plains"),
                        }),
                    })
                ]),
            })
            dim_settings = TagCompound({
                "natural":
                TagByte(1),
                "ambient_light":
                TagFloat(1.0),
                "has_ceiling":
                TagByte(0),
                "has_skylight":
                TagByte(1),
                "fixed_time":
                TagLong(9000),
                "ultrawarm":
                TagByte(0),
                "has_raids":
                TagByte(0),
                "respawn_anchor_works":
                TagByte(0),
                "bed_works":
                TagByte(0),
                "piglin_safe":
                TagByte(0),
                "logical_height":
                TagInt(256),
                "infiniburn":
                TagString("minecraft:infiniburn_overworld"),
                "coordinate_scale":
                TagFloat(1.0),
            })
            dim_codec = TagRoot({
                "":
                TagCompound({
                    "minecraft:dimension_type":
                    TagCompound({
                        "type":
                        TagString("minecraft:dimension_type"),
                        "value":
                        TagList([
                            TagCompound({
                                "name": TagString(dim_name),
                                "id": TagInt(0),
                                "element": dim_settings,
                            }),
                        ]),
                    }),
                    "minecraft:worldgen/biome":
                    biome_codec,
                })
            })
            current_dim = TagRoot({
                "": dim_settings,
            })

            self.send_packet(
                "join_game",
                self.buff_type.pack(
                    "i?BB", 0, False, 3,
                    3),  # entity id, hardcore, game mode, previous game mode
                self.buff_type.pack_varint(1),  # world count
                self.buff_type.pack_string(dim_name),  # world name(s)
                self.buff_type.pack_nbt(dim_codec),  # dimension registry
                self.buff_type.pack_nbt(current_dim),  # current dimension
                self.buff_type.pack_string(dim_name),  # world name
                self.buff_type.pack("q", 42),  # hashed seed
                self.buff_type.pack_varint(0),  # max players (unused)
                self.buff_type.pack_varint(2),  # view distance
                self.buff_type.pack("????", True, True, False, True),
            )  # respawn screen, debug world, flat world
        # self.send_packet(
        #     "join_game",
        #     self.buff_type.pack(
        #         "i?Bb",
        #         1,  # entity id
        #         False,
        #         2,  # game mode
        #         -1, # previous game mode
        #     ),
        #     self.buff_type.pack_varint(1),  # world count
        #     self.buff_type.pack_string("minecraft:the_end"), # world identifiers
        #     # self.buff_type.pack("qiB", )
        #     self.buff_type.pack_nbt(TagRoot({})), # dimension codec
        #     self.buff_type.pack_nbt(TagRoot({})), # dimension
        #     self.buff_type.pack_string("holdmusic"), # world identifiers
        #     self.buff_type.pack("L", 12345678),
        #     self.buff_type.pack_varint(0),
        #     self.buff_type.pack_varint(3),  # view distance
        #     self.buff_type.pack("????", False, True, False, False),  # reduced debug info
        # )  # show respawn screen

        for x in range(-7, 8):
            for y in range(-7, 8):
                self.send_air_chunk(x, y)

        self.send_air_chunk(1, 1)

        # Send "Player Position and Look" packet
        self.send_packet(
            "player_position_and_look",
            self.buff_type.pack(
                "dddff?",
                *self.pos,
                self.yaw,
                self.pitch,
                0b00000  # x  # y  # z  # yaw  # pitch
            ),  # flags
            self.buff_type.pack_varint(0),
        )  # teleport id

        # Send "Player Abilities" packet
        self.send_packet(
            "player_abilities",
            self.buff_type.pack("bff", 0b01111, 0.2, 0.1),
        )

        # Send "Server Difficulty" packet
        self.send_packet(
            "server_difficulty",
            self.buff_type.pack("B?", 3, False),
        )

        # Send "World Border" packet
        # self.send_packet(
        #     "world_border",
        #     self.buff_type.pack_varint(0),
        #     self.buff_type.pack("d", 100),
        # )

        # Send "Server Difficulty" packet
        # self.send_packet(
        #     "chat_message",
        #     self.buff_type.pack_chat(Message({"text": "Playing Stal -- C418", "color": "red"})) + self.buff_type.pack("B", 0),
        # )

        items: List[Optional[str]] = [[
            "minecraft:firework_rocket"
            if random() > 0.5 else "minecraft:pumpkin",
            int(random() * 127),
            None,
        ] for _ in range(46)]

        items[36] = [
            "minecraft:written_book",
            1,
            TagRoot({
                "":
                TagCompound({
                    "title":
                    TagString("Server Loading"),
                    "author":
                    TagString("Vin Howe"),
                    "pages":
                    TagList([
                        TagString(
                            "This is a dummy server to keep you distracted while the real server starts running. Hang tight!"
                        )
                    ]),
                })
            }),
        ]
        # items[6] = "minecraft:elytra"
        # items[36:45] = ["minecraft:firework_rocket" for _ in range(36, 45)]

        # self.send_packet(
        #     "window_items",
        #     self.buff_type.pack("Bh", 0, 46),
        #     *[self.buff_type.pack_slot(*item) for item in items]
        # )

        # self.send_packet("open_book", self.buff_type.pack_varint(0))

        self.update_music(create=True)

        # for player in self.factory.players:
        #     player.send_packet(
        #         "player_list_item",
        #         self.buff_type.pack_varint(0),  # action
        #         self.buff_type.pack_varint(1),  # count
        #         self.buff_type.pack_uuid(self.uuid),  # uuid
        #         self.buff_type.pack_string(self.display_name),  # name
        #         self.buff_type.pack_varint(
        #             0
        #         ),  # properties count (not really sure what to do with this)
        #         self.buff_type.pack_varint(0),  # gamemode (survival = 0)
        #         self.buff_type.pack_varint(0),  # ping (in ms)
        #         self.buff_type.pack("?", False),  # Has Display Name
        #     )

        # Start sending "Keep Alive" packets
        self.ticker.add_loop(20, self.update_keep_alive)

        self.ticker.add_loop(2, self.send_position_update)
예제 #13
0
    def player_joined(self):
        # Call super. This switches us to "play" mode, marks the player as
        #   in-game, and does some logging.
        ServerProtocol.player_joined(self)

        if self.protocol_version > 578:  # Minecraft 1.16.1
            # Send "Join Game" packet
            dim_name = "minecraft:the_end"
            dim_codec = TagRoot({
                '': TagCompound({
                    "dimension": TagList([
                        TagCompound({
                            "name"                : TagString(dim_name),
                            "natural"             : TagByte(0),
                            "ambient_light"       : TagFloat(0.0),
                            "has_ceiling"         : TagByte(0),
                            "has_skylight"        : TagByte(0),
                            "fixed_time"          : TagLong(6000),
                            "shrunk"              : TagByte(0),
                            "ultrawarm"           : TagByte(0),
                            "has_raids"           : TagByte(1),
                            "respawn_anchor_works": TagByte(0),
                            "bed_works"           : TagByte(0),
                            "piglin_safe"         : TagByte(0),
                            "logical_height"      : TagInt(256),
                            "infiniburn"          : TagString("minecraft:infiniburn_end"),
                        }),
                    ])
                })
            })
            self.send_packet("join_game",
                             self.buff_type.pack("iBB", 0, 3, 3),                   # entity id, game mode, previous game mode
                             self.buff_type.pack_varint(1),                         # world count
                             self.buff_type.pack_string(dim_name),                  # world name(s)
                             self.buff_type.pack_nbt(dim_codec),                    # dimension registry
                             self.buff_type.pack_string(dim_name),                  # dimension
                             self.buff_type.pack_string(dim_name),                  # world name
                             self.buff_type.pack("qB", 42, 0),                      # hashed seed, max players (unused)
                             self.buff_type.pack_varint(2),                         # view distance
                             self.buff_type.pack("????", True, True, False, True))  # respawn screen, debug world, flat world
        else:  # Minecraft 1.15
            # Send "Join Game" packet
            self.send_packet("join_game",
                self.buff_type.pack("iBiqB",
                    0,                              # entity id
                    3,                              # game mode
                    0,                              # dimension
                    0,                              # hashed seed
                    0),                             # max players
                self.buff_type.pack_string("flat"), # level type
                self.buff_type.pack_varint(1),      # view distance
                self.buff_type.pack("??",
                    False,                          # reduced debug info
                    True))                          # show respawn screen

        # Send "Player Position and Look" packet
        self.send_packet("player_position_and_look",
            self.buff_type.pack("dddff?",
                0,                         # x
                255,                       # y
                0,                         # z
                0,                         # yaw
                0,                         # pitch
                0b00000),                  # flags
            self.buff_type.pack_varint(0)) # teleport id

        # Start sending "Keep Alive" packets
        self.ticker.add_loop(20, self.update_keep_alive)

        # Announce player joined
        self.factory.send_chat(u"\u00a7e%s has joined." % self.display_name)
예제 #14
0
    def player_joined(self):
        # Call super. This switches us to "play" mode, marks the player as
        #   in-game, and does some logging.
        ServerProtocol.player_joined(self)

        dim_name = "minecraft:the_end"

        if self.protocol_version > 736:  # Minecraft 1.16.2
            # Send "Join Game" packet
            biome_codec = TagCompound({
                "type":
                TagString("minecraft:worldgen/biome"),
                "value":
                TagList([
                    TagCompound({
                        'name':
                        TagString(
                            "minecraft:plains"
                        ),  # Client crashes if you do not define plains
                        'id':
                        TagInt(1),
                        'element':
                        TagCompound({
                            'precipitation':
                            TagString("none"),
                            'effects':
                            TagCompound({
                                'sky_color': TagInt(0),
                                'water_fog_color': TagInt(0),
                                'fog_color': TagInt(0),
                                'water_color': TagInt(0),
                            }),
                            'depth':
                            TagFloat(0.1),
                            'temperature':
                            TagFloat(0.5),
                            'scale':
                            TagFloat(0.2),
                            'downfall':
                            TagFloat(0.5),
                            'category':
                            TagString("plains")
                        }),
                    })
                ])
            })
            dim_settings = TagCompound({
                "natural":
                TagByte(1),
                "ambient_light":
                TagFloat(0.0),
                "has_ceiling":
                TagByte(0),
                "has_skylight":
                TagByte(0),
                "fixed_time":
                TagLong(6000),
                "ultrawarm":
                TagByte(0),
                "has_raids":
                TagByte(0),
                "respawn_anchor_works":
                TagByte(0),
                "bed_works":
                TagByte(0),
                "piglin_safe":
                TagByte(0),
                "logical_height":
                TagInt(256),
                "infiniburn":
                TagString("minecraft:infiniburn_end"),
                "coordinate_scale":
                TagFloat(1.0)
            })
            dim_codec = TagRoot({
                '':
                TagCompound({
                    "minecraft:dimension_type":
                    TagCompound({
                        "type":
                        TagString("minecraft:dimension_type"),
                        "value":
                        TagList([
                            TagCompound({
                                "name": TagString(dim_name),
                                "id": TagInt(0),
                                "element": dim_settings
                            }),
                        ]),
                    }),
                    "minecraft:worldgen/biome":
                    biome_codec
                })
            })
            current_dim = TagRoot({
                '': dim_settings,
            })

            self.send_packet(
                "join_game",
                self.buff_type.pack(
                    "i?BB", 0, False, 3,
                    3),  # entity id, hardcore, game mode, previous game mode
                self.buff_type.pack_varint(1),  # world count
                self.buff_type.pack_string(dim_name),  # world name(s)
                self.buff_type.pack_nbt(dim_codec),  # dimension registry
                self.buff_type.pack_nbt(current_dim),  # current dimension
                self.buff_type.pack_string(dim_name),  # world name
                self.buff_type.pack("q", 42),  # hashed seed
                self.buff_type.pack_varint(0),  # max players (unused)
                self.buff_type.pack_varint(2),  # view distance
                self.buff_type.pack(
                    "????", True, True, False,
                    True))  # respawn screen, debug world, flat world

        elif self.protocol_version > 578:  # Minecraft 1.16.1
            # Send "Join Game" packet
            dim_codec = TagRoot({
                '':
                TagCompound({
                    "dimension":
                    TagList([
                        TagCompound({
                            "name":
                            TagString(dim_name),
                            "natural":
                            TagByte(0),
                            "ambient_light":
                            TagFloat(0.0),
                            "has_ceiling":
                            TagByte(0),
                            "has_skylight":
                            TagByte(0),
                            "fixed_time":
                            TagLong(6000),
                            "shrunk":
                            TagByte(0),
                            "ultrawarm":
                            TagByte(0),
                            "has_raids":
                            TagByte(1),
                            "respawn_anchor_works":
                            TagByte(0),
                            "bed_works":
                            TagByte(0),
                            "piglin_safe":
                            TagByte(0),
                            "logical_height":
                            TagInt(256),
                            "infiniburn":
                            TagString("minecraft:infiniburn_end"),
                        }),
                    ])
                })
            })
            self.send_packet(
                "join_game",
                self.buff_type.pack(
                    "iBB", 0, 3,
                    3),  # entity id, game mode, previous game mode
                self.buff_type.pack_varint(1),  # world count
                self.buff_type.pack_string(dim_name),  # world name(s)
                self.buff_type.pack_nbt(dim_codec),  # dimension registry
                self.buff_type.pack_string(dim_name),  # dimension
                self.buff_type.pack_string(dim_name),  # world name
                self.buff_type.pack("qB", 42,
                                    0),  # hashed seed, max players (unused)
                self.buff_type.pack_varint(2),  # view distance
                self.buff_type.pack(
                    "????", True, True, False,
                    True))  # respawn screen, debug world, flat world
        else:  # Minecraft 1.15
            # Send "Join Game" packet
            self.send_packet(
                "join_game",
                self.buff_type.pack(
                    "iBiqB",
                    0,  # entity id
                    3,  # game mode
                    0,  # dimension
                    0,  # hashed seed
                    0),  # max players
                self.buff_type.pack_string("flat"),  # level type
                self.buff_type.pack_varint(1),  # view distance
                self.buff_type.pack(
                    "??",
                    False,  # reduced debug info
                    True))  # show respawn screen

        # Send "Player Position and Look" packet
        self.send_packet(
            "player_position_and_look",
            self.buff_type.pack(
                "dddff?",
                0,  # x
                255,  # y
                0,  # z
                0,  # yaw
                0,  # pitch
                0b00000),  # flags
            self.buff_type.pack_varint(0))  # teleport id

        # Start sending "Keep Alive" packets
        self.ticker.add_loop(20, self.update_keep_alive)

        # Announce player joined
        self.factory.send_chat(u"\u00a7e%s has joined." % self.display_name)