1#include <stdlib.h>
2#include <string.h>
3
4#include "util.h"
5#include "net/mc_chunk.h"
6#include "net/packet.h"
7#include "world/chunk.h"
8
9#define MC_CHUNK_SECTION_BLOCK_BYTES 8192
10#define MC_CHUNK_SECTION_LIGHT_BYTES 2048
11#define MC_CHUNK_BIOME_BYTES 256
12
13static i8 mc_chunk_decode_bulk(MCChunkPacket* chunk, PacketReader* reader);
14static i8 mc_chunk_decode_single(MCChunkPacket* chunk, PacketReader* reader);
15static i32 mc_chunk_section_count(u16 mask);
16
17/* decode bulk chunk data from packet
18 returns 1 on success, 0 on failure */
19static i8 mc_chunk_decode_bulk(MCChunkPacket* chunk, PacketReader* reader)
20{
21 i32 update;
22
23 if (!packet_read_u8(reader, &chunk->skylight) || !packet_read_varint(reader, &chunk->update_count)) {
24 mg_log(LOG_ERR, "Malformed Map Chunk Bulk packet");
25 return 0;
26 }
27
28 if (chunk->update_count <= 0 || chunk->update_count > 4096)
29 return 0;
30
31 chunk->updates = malloc((size_t)chunk->update_count * sizeof(*chunk->updates));
32 if (!chunk->updates)
33 return 0;
34
35 /* read chunk updates */
36 for (update = 0; update < chunk->update_count; update++) {
37 if (!packet_read_i32(reader, &chunk->updates[update].x) ||
38 !packet_read_i32(reader, &chunk->updates[update].z) ||
39 !packet_read_u16(reader, &chunk->updates[update].mask)) {
40 mg_log(LOG_ERR, "Malformed Map Chunk Bulk packet");
41 mc_chunk_destroy(chunk);
42 return 0;
43 }
44
45 chunk->updates[update].replace = 1;
46 }
47
48 chunk->bulk = 1;
49 chunk->data = reader->data + reader->cursor;
50 chunk->data_size = reader->size - reader->cursor;
51 return 1;
52}
53
54/* decode single chunk data from packet
55 returns 1 on success, 0 on failure */
56static i8 mc_chunk_decode_single(MCChunkPacket* chunk, PacketReader* reader)
57{
58 MCChunkUpdate* update;
59 i32 declared_size;
60 u8 ground_up;
61
62 update = &chunk->single_update;
63
64 /* read chunk coordinates, mask, size */
65 if (!packet_read_i32(reader, &update->x) || !packet_read_i32(reader, &update->z) ||
66 !packet_read_u8(reader, &ground_up) || !packet_read_u16(reader, &update->mask) ||
67 !packet_read_varint(reader, &declared_size)) {
68 mg_log(LOG_ERR, "Malformed Chunk Data packet");
69 return 0;
70 }
71
72 if (declared_size < 0 || (size_t)declared_size > reader->size - reader->cursor)
73 return 0;
74
75 /* if ground_up set and mask is 0, set chunk for unload */
76 if (ground_up && update->mask == 0) {
77 chunk->unload = 1;
78 chunk->unload_x = update->x;
79 chunk->unload_z = update->z;
80 return 1;
81 }
82
83 update->replace = ground_up;
84 chunk->updates = update;
85 chunk->update_count = 1;
86 chunk->data = reader->data + reader->cursor;
87 chunk->data_size = declared_size;
88 return 1;
89}
90
91/* count number of chunk sections mask
92 returns section count */
93static i32 mc_chunk_section_count(u16 mask)
94{
95 i32 section;
96 i32 count;
97
98 count = 0;
99
100 for (section = 0; section < CHUNK_SECTION_COUNT; section++) {
101 if (mask & (1U << section)) /* section present in mask */
102 count++;
103 }
104
105 return count;
106}
107
108i8 mc_chunk_decode(MCChunkPacket* chunk, const MCPacket* packet)
109{
110 PacketReader reader;
111
112 if (!chunk || !packet)
113 return 0;
114
115 memset(chunk, 0, sizeof(*chunk));
116 reader = packet_reader_init(packet->data, packet->size);
117
118 switch (packet->id) {
119 case 0x21:
120 return mc_chunk_decode_single(chunk, &reader);
121 case 0x26:
122 return mc_chunk_decode_bulk(chunk, &reader);
123 }
124
125 return 0;
126}
127
128void mc_chunk_destroy(MCChunkPacket* chunk)
129{
130 if (!chunk)
131 return;
132
133 if (chunk->updates != &chunk->single_update)
134 free(chunk->updates);
135
136 memset(chunk, 0, sizeof(*chunk));
137}
138
139size_t mc_chunk_update_size(u16 mask, u8 skylight, i8 bulk)
140{
141 i32 sections;
142 size_t size;
143
144 sections = mc_chunk_section_count(mask);
145 size = sections * MC_CHUNK_SECTION_BLOCK_BYTES;
146 if (bulk) {
147 size += sections * MC_CHUNK_SECTION_LIGHT_BYTES;
148 size += MC_CHUNK_BIOME_BYTES;
149 if (skylight)
150 size += sections * MC_CHUNK_SECTION_LIGHT_BYTES;
151 }
152
153 return size;
154}