int dumpNBT_list(NBT_list *input, uint8 *buffer) { int curpos=0; buffer[curpos]=TAG_LIST; curpos++; curpos+=dumpNBT_string(&buffer[curpos],input->name); buffer[curpos]=input->tagId; curpos++; putSint32(&buffer[curpos],input->length); curpos+=4; for(int i=0; i<input->length; i++) { switch(input->tagId) { case TAG_BYTE: buffer[curpos]=*(char *)input->items[i]; curpos++; break; case TAG_SHORT: putSint16(&buffer[curpos], *(int *)input->items[i]); curpos+=2; break; case TAG_INT: putSint32(&buffer[curpos], *(int *)input->items[i]); curpos+=4; break; case TAG_LONG: putSint64(&buffer[curpos], *(long long *)input->items[i]); curpos+=8; break; case TAG_FLOAT: putFloat(&buffer[curpos], *(float *)input->items[i]); curpos+=4; break; case TAG_DOUBLE: putDouble(&buffer[curpos], *(double *)input->items[i]); curpos+=8; break; case TAG_STRING: curpos+=dumpNBT_string(&buffer[curpos],*(std::string *)input->items[i]); break; case TAG_BYTE_ARRAY: curpos+=dumpNBT_byte_array((NBT_byte_array *)input->items[i], &buffer[curpos],true); break; case TAG_COMPOUND: curpos+=dumpNBT_struct((NBT_struct *)input->items[i], &buffer[curpos],true); break; } } return curpos; }
void PacketHandler::arm_animation(uint8 *data, User *user) { char forward = data[4]; uint8 animationPackage[6]; animationPackage[0] = 0x12; putSint32(&animationPackage[1], user->UID); animationPackage[5] = forward; user->sendOthers(&animationPackage[0], 6); }
User::~User() { if(this->nick.size()) { //Send signal to everyone that the entity is destroyed uint8 entityData[5]; entityData[0] = 0x1d; //Destroy entity; putSint32(&entityData[1], this->UID); this->sendOthers(&entityData[0], 5); } }
void PacketHandler::holding_change(uint8 *data, User *user) { int itemID = getUint16(&data[4]); //Send holding change to others uint8 holdingPackage[7]; holdingPackage[0] = 0x10; putSint32(&holdingPackage[1], user->UID); putSint16(&holdingPackage[5], itemID); user->sendOthers(&holdingPackage[0], 7); }
bool User::updateLook(float yaw, float pitch) { uint8 lookdata[7]; lookdata[0] = 0x20; putSint32(&lookdata[1], (sint32)this->UID); lookdata[5] = (char)(yaw); lookdata[6] = (char)(pitch); this->sendOthers(&lookdata[0], 7); this->pos.yaw = yaw; this->pos.pitch = pitch; return true; }
int dumpNBT_byte_array(NBT_byte_array *input, uint8 *buffer, bool list) { int curpos=0; if(!list) { buffer[curpos]=TAG_BYTE_ARRAY; curpos++; curpos+=dumpNBT_string(&buffer[curpos],input->name); } putSint32(&buffer[curpos],input->length); curpos+=4; memcpy(&buffer[curpos],input->data, input->length); curpos+=input->length; return curpos; }
int dumpNBT_value(NBT_value *input, uint8 *buffer) { int curpos=0; buffer[curpos]=input->type; curpos++; curpos+=dumpNBT_string(&buffer[curpos],input->name); switch(input->type) { case TAG_BYTE: buffer[curpos]=*(char *)input->value; curpos++; break; case TAG_SHORT: putSint16(&buffer[curpos], *(int *)input->value); curpos+=2; break; case TAG_INT: putSint32(&buffer[curpos], *(int *)input->value); curpos+=4; break; case TAG_LONG: putSint64(&buffer[curpos], *(long long *)input->value); curpos+=8; break; case TAG_FLOAT: putFloat(&buffer[curpos], *(float *)input->value); curpos+=4; break; case TAG_DOUBLE: putDouble(&buffer[curpos], *(double *)input->value); curpos+=8; break; case TAG_STRING: curpos+=dumpNBT_string(&buffer[curpos],*(std::string *)input->value); break; } return curpos; }
void NBT_Value::Write(std::vector<uint8> &buffer) { int storeAt = buffer.size();; switch(m_type) { case TAG_BYTE: buffer.push_back(m_value.byteVal); break; case TAG_SHORT: buffer.resize(storeAt + 2); putSint16(&buffer[storeAt], m_value.shortVal); break; case TAG_INT: buffer.resize(storeAt + 4); putSint32(&buffer[storeAt], m_value.intVal); break; case TAG_LONG: buffer.resize(storeAt + 8); putSint64(&buffer[storeAt], m_value.longVal); break; case TAG_FLOAT: buffer.resize(storeAt + 4); putFloat(&buffer[storeAt], m_value.floatVal); break; case TAG_DOUBLE: buffer.resize(storeAt + 8); putDouble(&buffer[storeAt], m_value.doubleVal); break; case TAG_BYTE_ARRAY: { int arraySize = m_value.byteArrayVal ? m_value.byteArrayVal->size() : 0; buffer.resize(storeAt + 4 + arraySize); putSint32(&buffer[storeAt], arraySize); storeAt += 4; if(arraySize) memcpy(&buffer[storeAt], &(*m_value.byteArrayVal)[0], arraySize); break; } case TAG_STRING: { int stringLen = m_value.stringVal ? m_value.stringVal->size() : 0; buffer.resize(storeAt + 2 + stringLen); putSint16(&buffer[storeAt], (sint16)stringLen); storeAt += 2; if(stringLen>0) memcpy(&buffer[storeAt], m_value.stringVal->c_str(), stringLen); break; } case TAG_LIST: { buffer.resize(storeAt + 5); int listCount = m_value.listVal.data ? m_value.listVal.data->size() : 0; buffer[storeAt] = m_value.listVal.type; storeAt++; putSint32(&buffer[storeAt], listCount); for(int i=0;i<listCount;i++) (*m_value.listVal.data)[i]->Write(buffer); break; } case TAG_COMPOUND: { int compoundCount = m_value.compoundVal ? m_value.compoundVal->size() : 0; if(compoundCount) { std::map<std::string, NBT_Value*>::iterator iter = m_value.compoundVal->begin(), end = m_value.compoundVal->end(); for( ; iter != end; iter++) { const std::string &key = iter->first; int keySize = key.size(); NBT_Value *val = iter->second; int curPos = buffer.size(); buffer.resize(curPos + 3 + keySize); buffer[curPos] = (uint8)val->GetType(); curPos++; putSint16(&buffer[curPos], keySize); curPos += 2; if(keySize) memcpy(&buffer[curPos], key.c_str(), keySize); val->Write(buffer); } } buffer.push_back(TAG_END); break; } case TAG_END: break; //for completeness } }
int PacketHandler::complex_entities(User *user) { if(user->buffer.size() < 12) return PACKET_NEED_MORE_DATA; int curpos = 0; unsigned int i; uint8 intArray[4]; uint8 shortArray[2]; std::copy(user->buffer.begin()+curpos, user->buffer.begin()+curpos+4, intArray); int x = getSint32(&intArray[0]); curpos += 4; std::copy(user->buffer.begin()+curpos, user->buffer.begin()+curpos+2, shortArray); int y = getSint16(&shortArray[0]); curpos += 2; std::copy(user->buffer.begin()+curpos, user->buffer.begin()+curpos+4, intArray); int z = getSint32(&intArray[0]); curpos += 4; std::copy(user->buffer.begin()+curpos, user->buffer.begin()+curpos+2, shortArray); int len = getSint16(&shortArray[0]); curpos += 2; // Wait for whole message if(user->buffer.size() < (unsigned int)curpos+len) return PACKET_NEED_MORE_DATA; //ToDo: check len uint8 *buffer = new uint8[len]; for(i = 0; i < (uint32)len; i++) { buffer[i] = user->buffer[curpos+i]; } curpos += len; user->buffer.erase(user->buffer.begin(), user->buffer.begin()+curpos); uint8 block, meta; Map::get().getBlock(x, y, z, &block, &meta); //We only handle chest for now if(block != BLOCK_CHEST) { delete[] buffer; return curpos; } //Calculate uncompressed size and allocate memory uLongf uncompressedSize = ALLOCATE_NBTFILE; //buffer[len-3] + (buffer[len-2]<<8) + (buffer[len-1]<<16) + (buffer[len]<<24); uint8 *uncompressedBuffer = new uint8[uncompressedSize]; //Initialize zstream to handle gzip format z_stream zstream; zstream.zalloc = (alloc_func)0; zstream.zfree = (free_func)0; zstream.opaque = (voidpf)0; zstream.next_in = buffer; zstream.next_out = uncompressedBuffer; zstream.avail_in = len; zstream.avail_out = uncompressedSize; zstream.total_in = 0; zstream.total_out = 0; zstream.data_type = Z_BINARY; inflateInit2(&zstream, 1+MAX_WBITS); //Uncompress if(/*int state=*/inflate(&zstream, Z_FULL_FLUSH)!=Z_OK) { inflateEnd(&zstream); } //Get size uncompressedSize = zstream.total_out; //Push data to NBT struct NBT_struct newObject; TAG_Compound(uncompressedBuffer, &newObject, true); //These are not needed anymore delete[] buffer; delete[] uncompressedBuffer; //Get chunk position int block_x = blockToChunk(x); int block_z = blockToChunk(z); uint32 chunkID; NBT_struct *theEntity = 0; //Load map if(Map::get().loadMap(block_x, block_z)) { Map::get().posToId(block_x, block_z, &chunkID); NBT_struct mapData = Map::get().maps[chunkID]; //Try to find entitylist from the chunk NBT_list *entitylist = get_NBT_list(&mapData, "TileEntities"); //If list exists if(entitylist) { //Verify list type if(entitylist->tagId != TAG_COMPOUND) { //If wrong type, recreate freeNBT_list(entitylist); for(i = 0; i < mapData.lists.size(); i++) { if(mapData.lists[i].name == "TileEntities") { //Destroy old list freeNBT_list(&mapData.lists[i]); mapData.lists.erase(mapData.lists.begin()+i); break; } } //New list NBT_list newlisting; newlisting.name = "TileEntities"; newlisting.tagId = TAG_COMPOUND; newlisting.length = 0; mapData.lists.push_back(newlisting); entitylist = get_NBT_list(&mapData, "TileEntities"); } NBT_struct **entities = (NBT_struct **)entitylist->items; bool entityExists = false; int existingID = -1; //Search for mathing entity in the list for(int i = 0; i < entitylist->length; i++) { NBT_struct *entity = entities[i]; std::string id; //Get ID if(get_NBT_value(entity, "id", &id)) { int entity_x, entity_y, entity_z; if(!get_NBT_value(entity, "x", &entity_x) || !get_NBT_value(entity, "y", &entity_y) || !get_NBT_value(entity, "z", &entity_z)) { continue; } //Check for mathing blocktype and ID if(block == BLOCK_CHEST && id == "Chest") { if(x == entity_x && y == entity_y && z == entity_z) { entityExists = true; theEntity = entity; existingID = i; break; } } } } //End For entitylist //Generate struct theEntity = new NBT_struct; NBT_value value; //Push ID value.type = TAG_STRING; value.name = "id"; std::string *name = new std::string; value.value = (void *)name; *(std::string *)value.value = "Chest"; theEntity->values.push_back(value); //Position value.type = TAG_INT; value.name = "x"; value.value = (void *)new int; *(int *)value.value = x; theEntity->values.push_back(value); value.name = "y"; value.value = (void *)new int; *(int *)value.value = y; theEntity->values.push_back(value); value.name = "z"; value.value = (void *)new int; *(int *)value.value = z; theEntity->values.push_back(value); //Put special chest items if(block == BLOCK_CHEST) { NBT_list *newlist = get_NBT_list(&newObject, "Items"); if(!newlist) { //std::cout << "Items not found!" << std::endl; return curpos; } NBT_list itemlist; itemlist.name = "Items"; itemlist.tagId = TAG_COMPOUND; itemlist.length = newlist->length; itemlist.items = (void **)new NBT_struct *[itemlist.length]; NBT_struct **structlist = (NBT_struct **)itemlist.items; for(int i = 0; i < itemlist.length; i++) { structlist[i] = new NBT_struct; char type_char; sint16 type_sint16; //Generate struct value.type = TAG_BYTE; value.name = "Count"; get_NBT_value((NBT_struct *)((NBT_struct **)newlist->items)[i], "Count", &type_char); value.value = (void *)new char; *(char *)value.value = type_char; structlist[i]->values.push_back(value); value.type = TAG_BYTE; value.name = "Slot"; get_NBT_value((NBT_struct *)((NBT_struct **)newlist->items)[i], "Slot", &type_char); value.value = (void *)new char; *(char *)value.value = type_char; structlist[i]->values.push_back(value); value.type = TAG_SHORT; value.name = "Damage"; get_NBT_value((NBT_struct *)((NBT_struct **)newlist->items)[i], "Damage", &type_sint16); value.value = (void *)new sint16; *(sint16 *)value.value = type_sint16; structlist[i]->values.push_back(value); value.type = TAG_SHORT; value.name = "id"; get_NBT_value((NBT_struct *)((NBT_struct **)newlist->items)[i], "id", &type_sint16); value.value = (void *)new sint16; *(sint16 *)value.value = type_sint16; structlist[i]->values.push_back(value); } theEntity->lists.push_back(itemlist); } //If entity doesn't exist in the list, resize the list to fit it in if(!entityExists) { //ToDo: try this! NBT_struct **newlist = new NBT_struct *[entitylist->length+1]; NBT_struct **oldlist = (NBT_struct **)entitylist->items; uint8 *structbuffer = new uint8[ALLOCATE_NBTFILE]; for(int i = 0; i < entitylist->length; i++) { newlist[i] = new NBT_struct; dumpNBT_struct(oldlist[i],structbuffer); TAG_Compound(structbuffer, newlist[i],true); freeNBT_struct(oldlist[i]); oldlist[i] = NULL; } delete [] structbuffer; entitylist->length++; entitylist->items = (void **)newlist; delete [] (NBT_struct **)oldlist; newlist[entitylist->length-1] = theEntity; } //If item exists, replace the old with the new else { //Destroy old entitylist NBT_struct **oldlist = (NBT_struct **)entitylist->items; freeNBT_struct(oldlist[existingID]); //Replace with the new oldlist[existingID] = theEntity; } //Mark chunk as changed Map::get().mapChanged[chunkID] = true; } //If entity exists } //If loaded map //Send complex entity packet to others if(theEntity) { uint8 *structdump = new uint8[ALLOCATE_NBTFILE]; uint8 *packetData = new uint8[ALLOCATE_NBTFILE]; int dumped = dumpNBT_struct(theEntity, structdump); uLongf written = ALLOCATE_NBTFILE; z_stream zstream2; zstream2.zalloc = Z_NULL; zstream2.zfree = Z_NULL; zstream2.opaque = Z_NULL; zstream2.next_out = &packetData[13]; zstream2.next_in = structdump; zstream2.avail_in = dumped; zstream2.avail_out = written; zstream2.total_out = 0; zstream2.total_in = 0; deflateInit2(&zstream2, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15+MAX_WBITS, 8, Z_DEFAULT_STRATEGY); if(int state=deflate(&zstream2,Z_FULL_FLUSH)!=Z_OK) { std::cout << "Error in deflate: " << state << std::endl; deflateEnd(&zstream2); } else { written = zstream2.total_out; packetData[0] = 0x3b; //Complex Entities putSint32(&packetData[1],x); putSint16(&packetData[5],y); putSint32(&packetData[7],z); putSint16(&packetData[11], (sint16)written); user->sendAll((uint8 *)&packetData[0], 13+written); } delete [] packetData; delete [] structdump; } return curpos; }
// Login request (http://mc.kev009.com/wiki/Protocol#Login_Request_.280x01.29) int PacketHandler::login_request(User *user) { //Check that we have enought data in the buffer if(user->buffer.size() < 12) return PACKET_NEED_MORE_DATA; uint32 curpos = 0; int i; //Client protocol version uint8 tmpIntArray[4] = {0}; for(i = 0; i < 4; i++) tmpIntArray[i] = user->buffer[curpos+i]; int version = getUint32(&tmpIntArray[0]); curpos += 4; //Player name length uint8 tmpShortArray[2] = {0}; for(i = 0; i < 2; i++) tmpShortArray[i] = user->buffer[curpos+i]; int len = getUint16(&tmpShortArray[0]); curpos += 2; //Check for data if(user->buffer.size() < curpos+len+2) return PACKET_NEED_MORE_DATA; std::string player; //Read player name for(int pos = 0; pos < len; pos++) { player += user->buffer[curpos+pos]; } curpos += len; //Password length for(i = 0; i < 2; i++) tmpShortArray[i] = user->buffer[curpos+i]; len = getUint16(&tmpShortArray[0]); curpos += 2; std::string passwd; //Check for data if(user->buffer.size() < curpos+len) return PACKET_NEED_MORE_DATA; //Read password for(int pos = 0; pos < len; pos++) { passwd += user->buffer[curpos+pos]; } curpos += len; //Package completely received, remove from buffer user->buffer.erase(user->buffer.begin(), user->buffer.begin()+curpos); std::cout << "Player " << user->UID << " login v." << version <<" : " << player <<":"<< passwd << std::endl; // If version is not 2 or 3 if(version != 4 && version != 3 && version != 2) { user->kick(Conf::get().sValue("wrong_protocol_message")); return curpos; } // If userlimit is reached if((int)Users.size() >= Conf::get().iValue("userlimit")) { user->kick(Conf::get().sValue("server_full_message")); return curpos; } user->changeNick(player); //Load user data user->loadData(); //Login OK package char data[9] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; putSint32((uint8 *)&data[1], user->UID); bufferevent_write(user->buf_ev, (char *)&data[0], 9); //Send server time (after dawn) uint8 data3[9] = {0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00}; bufferevent_write(user->buf_ev, (char *)&data3[0], 9); //Inventory uint8 data4[7+36*5]; data4[0] = 0x05; putSint32(&data4[1], -1); data4[5] = 0; data4[6] = 36; int curpos2 = 7; //Send main inventory for(i = 0; i < 36; i++) { if(user->inv.main[i].count) { putSint16(&data4[curpos2], user->inv.main[i].type); //Type curpos2 += 2; data4[curpos2] = user->inv.main[i].count; //Count curpos2++; putSint16(&data4[curpos2], user->inv.main[i].health); //Health curpos2 += 2; } else { //Empty slot putSint16(&data4[curpos2], -1); curpos2 += 2; } } bufferevent_write(user->buf_ev, (char *)&data4[0], curpos2); //Send equipped inventory putSint32(&data4[1], -3); data4[6] = 4; curpos2 = 7; for(i = 0; i < 4; i++) { if(user->inv.equipped[i].count) { putSint16(&data4[curpos2], user->inv.equipped[i].type); //Type curpos2 += 2; data4[curpos2] = user->inv.equipped[i].count; //Count curpos2++; putSint16(&data4[curpos2], user->inv.equipped[i].health); //Health curpos2 += 2; } else { //Empty slot putSint16(&data4[curpos2], -1); curpos2 += 2; } } bufferevent_write(user->buf_ev, (char *)&data4[0], curpos2); //Send crafting inventory putSint32(&data4[1], -2); data4[6] = 4; curpos2 = 7; for(i = 0; i < 4; i++) { if(user->inv.crafting[i].count) { putSint16(&data4[curpos2], user->inv.crafting[i].type); //Type curpos2 += 2; data4[curpos2] = user->inv.crafting[i].count; //Count curpos2++; putSint16(&data4[curpos2], user->inv.crafting[i].health); //Health curpos2 += 2; } else { //Empty slot putSint16(&data4[curpos2], -1); curpos2 += 2; } } bufferevent_write(user->buf_ev, (char *)&data4[0], curpos2); // Send motd std::ifstream motdfs( MOTDFILE.c_str()); std::string temp; while(getline( motdfs, temp )) { // If not commentline if(temp[0] != COMMENTPREFIX) Chat::get().sendMsg(user, temp, Chat::USER); } motdfs.close(); //Teleport player user->teleport(user->pos.x, user->pos.y+2, user->pos.z); //Put nearby chunks to queue for(int x = -user->viewDistance; x <= user->viewDistance; x++) { for(int z = -user->viewDistance; z <= user->viewDistance; z++) { user->addQueue((sint32)user->pos.x/16+x, (sint32)user->pos.z/16+z); } } // Push chunks to user user->pushMap(); //Spawn this user to others user->spawnUser((sint32)user->pos.x*32, ((sint32)user->pos.y+2)*32, (sint32)user->pos.z*32); //Spawn other users for connected user user->spawnOthers(); //Send "On Ground" signal char data6[2] = {0x0A, 0x01}; bufferevent_write(user->buf_ev, (char *)&data6[0], 2); user->logged = true; Chat::get().sendMsg(user, player+" connected!", Chat::ALL); return curpos; }
bool User::updatePos(double x, double y, double z, double stance) { if(nick.size() && logged) { //Do we send relative or absolute move values if(0) //abs(x-this->pos.x)<127 //&& abs(y-this->pos.y)<127 //&& abs(z-this->pos.z)<127) { uint8 movedata[8]; movedata[0] = 0x1f; //Relative move putSint32(&movedata[1], (sint32)this->UID); movedata[5] = (char)(x-this->pos.x); movedata[6] = (char)(y-this->pos.y); movedata[7] = (char)(z-this->pos.z); this->sendOthers(&movedata[0], 8); } else { this->pos.x = x; this->pos.y = y; this->pos.z = z; this->pos.stance = stance; uint8 teleportData[19]; teleportData[0] = 0x22; //Teleport putSint32(&teleportData[1], this->UID); putSint32(&teleportData[5], (int)(this->pos.x*32)); putSint32(&teleportData[9], (int)(this->pos.y*32)); putSint32(&teleportData[13], (int)(this->pos.z*32)); teleportData[17] = (char)this->pos.yaw; teleportData[18] = (char)this->pos.pitch; this->sendOthers(&teleportData[0], 19); } //Check if there are items in this chunk! sint32 chunk_x = blockToChunk((sint32)x); sint32 chunk_z = blockToChunk((sint32)z); uint32 chunkHash; Map::get().posToId(chunk_x, chunk_z, &chunkHash); if(Map::get().mapItems.count(chunkHash)) { //Loop through items and check if they are close enought to be picked up for(sint32 i = Map::get().mapItems[chunkHash].size()-1; i >= 0; i--) { //No more than 2 blocks away if(abs((sint32)x-Map::get().mapItems[chunkHash][i]->pos.x()/32) < 2 && abs((sint32)z-Map::get().mapItems[chunkHash][i]->pos.z()/32) < 2 && abs((sint32)y-Map::get().mapItems[chunkHash][i]->pos.y()/32) < 2) { //Dont pickup own spawns right away if(Map::get().mapItems[chunkHash][i]->spawnedBy != this->UID || Map::get().mapItems[chunkHash][i]->spawnedAt+2 < time(0)) { //Check player inventory for space! if(checkInventory(Map::get().mapItems[chunkHash][i]->item, Map::get().mapItems[chunkHash][i]->count)) { //Send player collect item packet uint8 *packet = new uint8[9]; packet[0] = PACKET_COLLECT_ITEM; putSint32(&packet[1], Map::get().mapItems[chunkHash][i]->EID); putSint32(&packet[5], this->UID); buffer.addToWrite(packet, 9); //Send everyone destroy_entity-packet packet[0] = PACKET_DESTROY_ENTITY; putSint32(&packet[1], Map::get().mapItems[chunkHash][i]->EID); //ToDo: Only send users in range this->sendAll(packet, 5); packet[0] = PACKET_ADD_TO_INVENTORY; putSint16(&packet[1], Map::get().mapItems[chunkHash][i]->item); packet[3] = Map::get().mapItems[chunkHash][i]->count; putSint16(&packet[4], Map::get().mapItems[chunkHash][i]->health); buffer.addToWrite(packet, 6); //We're done, release packet memory delete[] packet; Map::get().items.erase(Map::get().mapItems[chunkHash][i]->EID); delete Map::get().mapItems[chunkHash][i]; Map::get().mapItems[chunkHash].erase(Map::get().mapItems[chunkHash].begin()+i); } } } } } //Chunk position changed, check for map updates if((int)(x/16) != curChunk.x() || (int)(z/16) != curChunk.z()) { //This is not accurate chunk!! curChunk.x() = (int)(x/16); curChunk.z() = (int)(z/16); for(int mapx = -viewDistance+curChunk.x(); mapx <= viewDistance+curChunk.x(); mapx++) { for(int mapz = -viewDistance+curChunk.z(); mapz <= viewDistance+curChunk.z(); mapz++) { addQueue(mapx, mapz); } } for(unsigned int i = 0; i < mapKnown.size(); i++) { //If client has map data more than viesDistance+1 chunks away, remove it if(mapKnown[i].x() < curChunk.x()-viewDistance-1 || mapKnown[i].x() > curChunk.x()+viewDistance+1 || mapKnown[i].z() < curChunk.z()-viewDistance-1 || mapKnown[i].z() > curChunk.z()+viewDistance+1) addRemoveQueue(mapKnown[i].x(), mapKnown[i].z()); } } } this->pos.x = x; this->pos.y = y; this->pos.z = z; this->pos.stance = stance; return true; }