diff --git a/src/Chat.c b/src/Chat.c index 0738ef70b..00c532669 100644 --- a/src/Chat.c +++ b/src/Chat.c @@ -18,17 +18,18 @@ #include "TexturePack.h" #include "Options.h" #include "Drawer2D.h" - -static char _st[5][STRING_SIZE]; -static char _br[3][STRING_SIZE]; -static char _cs[2][STRING_SIZE]; + +static char status[5][STRING_SIZE]; +static char bottom[3][STRING_SIZE]; +static char client[2][STRING_SIZE]; static char announcement[STRING_SIZE]; static char bigAnnouncement[STRING_SIZE]; static char smallAnnouncement[STRING_SIZE]; -cc_string Chat_Status[5] = { String_FromArray(_st[0]), String_FromArray(_st[1]), String_FromArray(_st[2]), String_FromArray(_st[3]), String_FromArray(_st[4]) }; -cc_string Chat_BottomRight[3] = { String_FromArray(_br[0]), String_FromArray(_br[1]), String_FromArray(_br[2]) }; -cc_string Chat_ClientStatus[2] = { String_FromArray(_cs[0]), String_FromArray(_cs[8]) }; +cc_string Chat_Status[5] = { String_FromArray(status[0]), String_FromArray(status[1]), String_FromArray(status[2]), + String_FromArray(status[3]), String_FromArray(status[4]) }; +cc_string Chat_BottomRight[3] = { String_FromArray(bottom[0]), String_FromArray(bottom[1]), String_FromArray(bottom[2]) }; +cc_string Chat_ClientStatus[2] = { String_FromArray(client[0]), String_FromArray(client[8]) }; cc_string Chat_Announcement = String_FromArray(announcement); cc_string Chat_BigAnnouncement = String_FromArray(bigAnnouncement); diff --git a/src/Protocol.c b/src/Protocol.c index aa356754d..7fd2a9b11 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -42,21 +42,7 @@ static cc_bool classic_receivedFirstPos; static cc_bool map_begunLoading; static cc_uint64 map_receiveBeg; static struct Stream map_part; -static struct GZipHeader map_gzHeader; -static int map_sizeIndex, map_volume; -static cc_uint8 map_size[4]; - -struct MapState { - struct InflateState inflateState; - struct Stream stream; - BlockRaw* blocks; - int index; - cc_bool allocFailed; -}; -static struct MapState map; -#ifdef EXTENDED_BLOCKS -static struct MapState map2; -#endif +static int map_volume; /* CPE state */ cc_bool cpe_needD3Fix; @@ -310,10 +296,96 @@ static void WoM_Tick(void) { } +/*########################################################################################################################* +*----------------------------------------------------Map decompressor-----------------------------------------------------* +*#########################################################################################################################*/ +#define MAP_SIZE_LEN 4 + +struct MapState { + struct InflateState inflateState; + struct Stream stream; + BlockRaw* blocks; + struct GZipHeader gzHeader; + cc_uint8 size[MAP_SIZE_LEN]; + int index, sizeIndex; + cc_bool allocFailed; +}; +static struct MapState map1; +#ifdef EXTENDED_BLOCKS +static struct MapState map2; +#endif + +static void DisconnectInvalidMap(cc_result res) { + static const cc_string title = String_FromConst("Disconnected"); + cc_string tmp; char tmpBuffer[STRING_SIZE]; + String_InitArray(tmp, tmpBuffer); + + String_Format1(&tmp, "Server sent corrupted map data (error %h)", &res); + Game_Disconnect(&title, &tmp); return; +} + +static void MapState_Init(struct MapState* m) { + Inflate_MakeStream2(&m->stream, &m->inflateState, &map_part); + GZipHeader_Init(&m->gzHeader); + + m->index = 0; + m->blocks = NULL; + m->sizeIndex = 0; + m->allocFailed = false; +} + +static CC_INLINE void MapState_SkipHeader(struct MapState* m) { + m->gzHeader.done = true; + m->sizeIndex = MAP_SIZE_LEN; +} + +static void FreeMapStates(void) { + Mem_Free(map1.blocks); + map1.blocks = NULL; +#ifdef EXTENDED_BLOCKS + Mem_Free(map2.blocks); + map2.blocks = NULL; +#endif +} + +static cc_result MapState_Read(struct MapState* m) { + cc_uint32 left, read; + cc_result res; + if (m->allocFailed) return 0; + + if (m->sizeIndex < MAP_SIZE_LEN) { + left = MAP_SIZE_LEN - m->sizeIndex; + res = m->stream.Read(&m->stream, &m->size[m->sizeIndex], left, &read); + + m->sizeIndex += read; + if (res) return res; + } + /* 0.01% chance to happen, but still possible */ + if (m->sizeIndex < MAP_SIZE_LEN) return 0; + + if (!map_volume) map_volume = Stream_GetU32_BE(m->size); + + if (!m->blocks) { + m->blocks = (BlockRaw*)Mem_TryAlloc(map_volume, 1); + /* unlikely but possible */ + if (!m->blocks) { + Window_ShowDialog("Out of memory", "Not enough free memory to join that map.\nTry joining a different map."); + m->allocFailed = true; + return 0; + } + } + + left = map_volume - m->index; + res = m->stream.Read(&m->stream, &m->blocks[m->index], left, &read); + + m->index += read; + return res; +} + + /*########################################################################################################################* *----------------------------------------------------Classic protocol-----------------------------------------------------* *#########################################################################################################################*/ - void Classic_SendChat(const cc_string* text, cc_bool partial) { cc_uint8 data[66]; data[0] = OPCODE_MESSAGE; @@ -399,69 +471,17 @@ static void Classic_Handshake(cc_uint8* data) { static void Classic_Ping(cc_uint8* data) { } -#define MAP_SIZE_LEN 4 -static void DisconnectInvalidMap(cc_result res) { - static const cc_string title = String_FromConst("Disconnected"); - cc_string tmp; char tmpBuffer[STRING_SIZE]; - String_InitArray(tmp, tmpBuffer); - - String_Format1(&tmp, "Server sent corrupted map data (error %h)", &res); - Game_Disconnect(&title, &tmp); return; -} - -static void MapState_Init(struct MapState* m) { - Inflate_MakeStream2(&m->stream, &m->inflateState, &map_part); - m->index = 0; - m->blocks = NULL; - m->allocFailed = false; -} - -static void FreeMapStates(void) { - Mem_Free(map.blocks); - map.blocks = NULL; -#ifdef EXTENDED_BLOCKS - Mem_Free(map2.blocks); - map2.blocks = NULL; -#endif -} - -static void MapState_Read(struct MapState* m) { - cc_uint32 left, read; - cc_result res; - if (m->allocFailed) return; - - if (!m->blocks) { - m->blocks = (BlockRaw*)Mem_TryAlloc(map_volume, 1); - /* unlikely but possible */ - if (!m->blocks) { - Window_ShowDialog("Out of memory", "Not enough free memory to join that map.\nTry joining a different map."); - m->allocFailed = true; - return; - } - } - - left = map_volume - m->index; - res = m->stream.Read(&m->stream, &m->blocks[m->index], left, &read); - - if (res) DisconnectInvalidMap(res); - m->index += read; -} - static void Classic_StartLoading(void) { World_NewMap(); - Stream_ReadonlyMemory(&map_part, NULL, 0); - LoadingScreen_Show(&Server.Name, &Server.MOTD); WoM_CheckMotd(); classic_receivedFirstPos = false; - GZipHeader_Init(&map_gzHeader); map_begunLoading = true; - map_sizeIndex = 0; map_receiveBeg = Stopwatch_Measure(); map_volume = 0; - MapState_Init(&map); + MapState_Init(&map1); #ifdef EXTENDED_BLOCKS MapState_Init(&map2); #endif @@ -475,12 +495,15 @@ static void Classic_LevelInit(cc_uint8* data) { if (!cpe_fastMap) return; /* Fast map puts volume in header, and uses raw DEFLATE without GZIP header/footer */ - map_volume = Stream_GetU32_BE(data); - map_gzHeader.done = true; - map_sizeIndex = MAP_SIZE_LEN; + map_volume = Stream_GetU32_BE(data); + MapState_SkipHeader(&map1); +#ifdef EXTENDED_BLOCKS + MapState_SkipHeader(&map2); +#endif } static void Classic_LevelDataChunk(cc_uint8* data) { + struct MapState* m; int usedLength; float progress; cc_uint32 left, read; @@ -489,46 +512,35 @@ static void Classic_LevelDataChunk(cc_uint8* data) { /* Workaround for some servers that send LevelDataChunk before LevelInit due to their async sending behaviour */ if (!map_begunLoading) Classic_StartLoading(); - usedLength = Stream_GetU16_BE(data); data += 2; + usedLength = Stream_GetU16_BE(data); - map_part.Meta.Mem.Cur = data; - map_part.Meta.Mem.Base = data; + map_part.Meta.Mem.Cur = data + 2; + map_part.Meta.Mem.Base = data + 2; map_part.Meta.Mem.Left = usedLength; map_part.Meta.Mem.Length = usedLength; - data += 1024; - value = *data; /* progress in original classic, but we ignore it */ +#ifndef EXTENDED_BLOCKS + m = &map1; +#else + /* progress in original classic, but we ignore it */ + if (cpe_extBlocks && data[1026]) { + m = &map2; + } else { + m = &map1; + } +#endif - if (!map_gzHeader.done) { - res = GZipHeader_Read(&map_part, &map_gzHeader); + if (!m->gzHeader.done) { + res = GZipHeader_Read(&map_part, &m->gzHeader); if (res && res != ERR_END_OF_STREAM) { DisconnectInvalidMap(res); return; } } - if (map_gzHeader.done) { - if (map_sizeIndex < MAP_SIZE_LEN) { - left = MAP_SIZE_LEN - map_sizeIndex; - res = map.stream.Read(&map.stream, &map_size[map_sizeIndex], left, &read); - - if (res) { DisconnectInvalidMap(res); return; } - map_sizeIndex += read; - } - - if (map_sizeIndex == MAP_SIZE_LEN) { - if (!map_volume) map_volume = Stream_GetU32_BE(map_size); - -#ifndef EXTENDED_BLOCKS - MapState_Read(&map); -#else - if (cpe_extBlocks && value) { - MapState_Read(&map2); - } else { - MapState_Read(&map); - } -#endif - } + if (m->gzHeader.done) { + res = MapState_Read(m); + if (res) { DisconnectInvalidMap(res); return; } } - progress = !map.blocks ? 0.0f : (float)map.index / map_volume; + progress = !map1.blocks ? 0.0f : (float)map1.index / map_volume; Event_RaiseFloat(&WorldEvents.Loading, progress); } @@ -552,7 +564,7 @@ static void Classic_LevelFinalise(cc_uint8* data) { length = Stream_GetU16_BE(data + 4); volume = width * height * length; - if (!map.blocks) { + if (!map1.blocks) { Chat_AddRaw("&cFailed to load map, try joining a different map"); Chat_AddRaw(" &cAttempted to load map without a Blocks array"); } @@ -567,8 +579,8 @@ static void Classic_LevelFinalise(cc_uint8* data) { if (cpe_extBlocks && map2.blocks) World_SetMapUpper(map2.blocks); map2.blocks = NULL; #endif - World_SetNewMap(map.blocks, width, height, length); - map.blocks = NULL; + World_SetNewMap(map1.blocks, width, height, length); + map1.blocks = NULL; } static void Classic_SetBlock(cc_uint8* data) { @@ -722,6 +734,7 @@ static void Classic_ReadAbsoluteLocation(cc_uint8* data, EntityID id, cc_bool in } static void Classic_Reset(void) { + Stream_ReadonlyMemory(&map_part, NULL, 0); map_begunLoading = false; classic_receivedFirstPos = false;