/************************************************************************************ * * ***********************************************************************************/ bool ScopeDome::SetupParms() { targetAz = 0; readU32(GetImpPerTurn, stepsPerTurn); LOGF_INFO("Steps per turn read as %d", stepsPerTurn); StepsPerRevolutionN[0].value = stepsPerTurn; StepsPerRevolutionNP.s = IPS_OK; IDSetNumber(&StepsPerRevolutionNP, nullptr); readS32(GetHomeSensorPosition, homePosition); LOGF_INFO("Home position read as %d", homePosition); if (UpdatePosition()) IDSetNumber(&DomeAbsPosNP, nullptr); if (UpdateShutterStatus()) IDSetSwitch(&DomeShutterSP, nullptr); UpdateSensorStatus(); UpdateRelayStatus(); if (InitPark()) { // If loading parking data is successful, we just set the default parking // values. SetAxis1ParkDefault(0); } else { // Otherwise, we set all parking data to default in case no parking data is // found. SetAxis1Park(0); SetAxis1ParkDefault(0); } uint8_t calibrationNeeded = false; readU8(IsFullSystemCalReq, calibrationNeeded); CalibrationNeededS[0].s = calibrationNeeded ? ISS_ON : ISS_OFF; CalibrationNeededSP.s = IPS_OK; IDSetSwitch(&CalibrationNeededSP, nullptr); uint16_t fwVersion; readU16(GetVersionFirmware, fwVersion); FirmwareVersionsN[0].value = fwVersion / 100.0; uint8_t fwVersionRotary; readU8(GetVersionFirmwareRotary, fwVersionRotary); FirmwareVersionsN[1].value = (fwVersionRotary + 9) / 10.0; FirmwareVersionsNP.s = IPS_OK; IDSetNumber(&FirmwareVersionsNP, nullptr); return true; }
U32 PInternalQuitApplicationPkt::deserialize( const S8 * buf, S32 offset ) { U32 cur_pos = PPacketBase::deserialize(buf, offset ); const S8 * buff = buf + offset; m_iReaseaon = readS32( buff+ cur_pos ); cur_pos += sizeof(S32); return cur_pos; }
void TestSerialization::testStreamRead() { std::string datastr( (const char *)test_serialized_data, sizeof(test_serialized_data)); std::istringstream is(datastr, std::ios_base::binary); UASSERT(readU8(is) == 0x11); UASSERT(readU16(is) == 0x2233); UASSERT(readU32(is) == 0x44556677); UASSERT(readU64(is) == 0x8899AABBCCDDEEFF); UASSERT(readS8(is) == -128); UASSERT(readS16(is) == 30000); UASSERT(readS32(is) == -6); UASSERT(readS64(is) == -43); UASSERT(readF1000(is) == 53.534f); UASSERT(readF1000(is) == -300000.32f); UASSERT(readF1000(is) == F1000_MIN); UASSERT(readF1000(is) == F1000_MAX); UASSERT(deSerializeString(is) == "foobar!"); UASSERT(readV2S16(is) == v2s16(500, 500)); UASSERT(readV3S16(is) == v3s16(4207, 604, -30)); UASSERT(readV2S32(is) == v2s32(1920, 1080)); UASSERT(readV3S32(is) == v3s32(-400, 6400054, 290549855)); UASSERT(readV2F1000(is) == v2f(500.656f, 350.345f)); UASSERT(deSerializeWideString(is) == L"\x02~woof~\x5455"); UASSERT(readV3F1000(is) == v3f(500, 10024.2f, -192.54f)); UASSERT(readARGB8(is) == video::SColor(255, 128, 50, 128)); UASSERT(deSerializeLongString(is) == "some longer string here"); UASSERT(is.rdbuf()->in_avail() == 2); UASSERT(readU16(is) == 0xF00D); UASSERT(is.rdbuf()->in_avail() == 0); }
/************************************************************************************ * * ***********************************************************************************/ void ScopeDome::TimerHit() { if (!isConnected()) return; // No need to reset timer if we are not connected anymore readU16(GetStatus, currentStatus); // LOGF_INFO("Status: %x", currentStatus); UpdatePosition(); UpdateShutterStatus(); IDSetSwitch(&DomeShutterSP, nullptr); UpdateRelayStatus(); if (status == DOME_HOMING) { if ((currentStatus & 8) == 0 && getInputState(IN_HOME)) { // Found home status = DOME_READY; targetAz = DomeHomePositionN[0].value; // Reset counter writeCmd(ResetCounter); FindHomeSP.s = IPS_OK; DomeAbsPosNP.s = IPS_OK; IDSetSwitch(&FindHomeSP, nullptr); } IDSetNumber(&DomeAbsPosNP, nullptr); } else if (status == DOME_DEROTATING) { if ((currentStatus & 2) == 0) { readS32(GetCounterExt, currentRotation); LOGF_INFO("Current rotation is %d", currentRotation); if (abs(currentRotation) < 100) { // Close enough status = DOME_READY; DerotateSP.s = IPS_OK; DomeAbsPosNP.s = IPS_OK; IDSetSwitch(&DerotateSP, nullptr); } else { if (currentRotation < 0) { writeU16(CCWRotation, compensateInertia(-currentRotation)); } else { writeU16(CWRotation, compensateInertia(currentRotation)); } } } IDSetNumber(&DomeAbsPosNP, nullptr); } else if (DomeAbsPosNP.s == IPS_BUSY) { if ((currentStatus & 2) == 0) { // Rotation idle, are we close enough? double azDiff = targetAz - DomeAbsPosN[0].value; if (azDiff > 180) { azDiff -= 360; } if (azDiff < -180) { azDiff += 360; } if (fabs(azDiff) <= DomeParamN[0].value) { DomeAbsPosN[0].value = targetAz; DomeAbsPosNP.s = IPS_OK; LOG_INFO("Dome reached requested azimuth angle."); if (getDomeState() == DOME_PARKING) { if (ParkShutterS[0].s == ISS_ON && getInputState(IN_CLOSED1) == ISS_OFF) { ControlShutter(SHUTTER_CLOSE); } else { SetParked(true); } } else if (getDomeState() == DOME_UNPARKING) SetParked(false); else setDomeState(DOME_SYNCED); } else { // Refine azimuth MoveAbs(targetAz); } } IDSetNumber(&DomeAbsPosNP, nullptr); } else IDSetNumber(&DomeAbsPosNP, nullptr); // Read temperatures only every 10th time static int tmpCounter = 0; if (--tmpCounter <= 0) { UpdateSensorStatus(); tmpCounter = 10; } SetTimer(POLLMS); }
/* Initialise the map structure */ GAMEMAP *mapLoad(char *filename) { char path[PATH_MAX]; GAMEMAP *map = (GAMEMAP *)malloc(sizeof(*map)); uint32_t i, j, gwVersion; char aFileType[4]; bool littleEndian = true; PHYSFS_file *fp = NULL; bool counted[MAX_PLAYERS]; uint16_t pType; // this cries out for a class based design #define readU8(v) ( littleEndian ? PHYSFS_readULE8(fp, v) : PHYSFS_readUBE8(fp, v) ) #define readU16(v) ( littleEndian ? PHYSFS_readULE16(fp, v) : PHYSFS_readUBE16(fp, v) ) #define readU32(v) ( littleEndian ? PHYSFS_readULE32(fp, v) : PHYSFS_readUBE32(fp, v) ) #define readS8(v) ( littleEndian ? PHYSFS_readSLE8(fp, v) : PHYSFS_readSBE8(fp, v) ) #define readS16(v) ( littleEndian ? PHYSFS_readSLE16(fp, v) : PHYSFS_readSBE16(fp, v) ) #define readS32(v) ( littleEndian ? PHYSFS_readSLE32(fp, v) : PHYSFS_readSBE32(fp, v) ) /* === Load map data === */ strcpy(path, filename); strcat(path, "/game.map"); fp = PHYSFS_openRead(path); map->mGateways = NULL; map->mMapTiles = NULL; if (!fp) { debug(LOG_ERROR, "Could not open %s", path); map->mapVersion = 0; map->width = UINT32_MAX; map->height = UINT32_MAX; map->mMapTiles = NULL; goto mapfailure; } else if (PHYSFS_read(fp, aFileType, 4, 1) != 1 || !readU32(&map->mapVersion) || !readU32(&map->width) || !readU32(&map->height) || aFileType[0] != 'm' || aFileType[1] != 'a' || aFileType[2] != 'p') { debug(LOG_ERROR, "Bad header in %s", path); goto failure; } else if (map->mapVersion <= 9) { debug(LOG_ERROR, "%s: Unsupported save format version %u", path, map->mapVersion); goto failure; } else if (map->mapVersion > 36) { debug(LOG_ERROR, "%s: Undefined save format version %u", path, map->mapVersion); goto failure; } else if (map->width * map->height > MAP_MAXAREA) { debug(LOG_ERROR, "Map %s too large : %d %d", path, map->width, map->height); goto failure; } /* Allocate the memory for the map */ map->mMapTiles = (MAPTILE *)calloc(map->width * map->height, sizeof(*map->mMapTiles)); if (!map->mMapTiles) { debug(LOG_ERROR, "Out of memory"); goto failure; } /* Load in the map data */ for (i = 0; i < map->width * map->height; i++) { uint16_t texture; uint8_t height; if (!readU16(&texture) || !readU8(&height)) { debug(LOG_ERROR, "%s: Error during savegame load", path); goto failure; } map->mMapTiles[i].texture = static_cast<TerrainType>(texture); map->mMapTiles[i].height = height; for (j = 0; j < MAX_PLAYERS; j++) { map->mMapTiles[i].tileVisBits = (uint8_t)(map->mMapTiles[i].tileVisBits &~ (uint8_t)(1 << j)); } } if (!readU32(&gwVersion) || !readU32(&map->numGateways) || gwVersion != 1) { debug(LOG_ERROR, "Bad gateway in %s", path); goto failure; } map->mGateways = (GATEWAY *)calloc(map->numGateways, sizeof(*map->mGateways)); for (i = 0; i < map->numGateways; i++) { if (!readU8(&map->mGateways[i].x1) || !readU8(&map->mGateways[i].y1) || !readU8(&map->mGateways[i].x2) || !readU8(&map->mGateways[i].y2)) { debug(LOG_ERROR, "%s: Failed to read gateway info", path); goto failure; } } PHYSFS_close(fp); mapfailure: /* === Load game data === */ strcpy(path, filename); strcat(path, ".gam"); fp = PHYSFS_openRead(path); if (!fp) { debug(LOG_ERROR, "Game file %s not found", path); goto failure; } else if (PHYSFS_read(fp, aFileType, 4, 1) != 1 || aFileType[0] != 'g' || aFileType[1] != 'a' || aFileType[2] != 'm' || aFileType[3] != 'e' || !readU32(&map->gameVersion)) { debug(LOG_ERROR, "Bad header in %s", path); goto failure; } if (map->gameVersion > 35) // big-endian { littleEndian = false; } if (!readU32(&map->gameTime) || !readU32(&map->gameType) || !readS32(&map->scrollMinX) || !readS32(&map->scrollMinY) || !readU32(&map->scrollMaxX) || !readU32(&map->scrollMaxY) || PHYSFS_read(fp, map->levelName, 20, 1) != 1) { debug(LOG_ERROR, "Bad data in %s", filename); goto failure; } for (i = 0; i < 8; i++) { if (map->gameVersion >= 10) { uint32_t dummy; // extracted power, not used if (!readU32(&map->power[i]) || !readU32(&dummy)) { debug(LOG_ERROR, "Bad power data in %s", filename); goto failure; } } else { map->power[i] = 0; // TODO... is there a default? } } PHYSFS_close(fp); /* === Load feature data === */ littleEndian = true; strcpy(path, filename); strcat(path, "/feat.bjo"); fp = PHYSFS_openRead(path); if (!fp) { debug(LOG_ERROR, "Feature file %s not found", path); map->featVersion = 0; map->numFeatures = 0; map->mLndObjects[IMD_FEATURE] = NULL; goto featfailure; } else if (PHYSFS_read(fp, aFileType, 4, 1) != 1 || aFileType[0] != 'f' || aFileType[1] != 'e' || aFileType[2] != 'a' || aFileType[3] != 't' || !readU32(&map->featVersion) || !readU32(&map->numFeatures)) { debug(LOG_ERROR, "Bad features header in %s", path); goto failure; } map->mLndObjects[IMD_FEATURE] = (LND_OBJECT *)malloc(sizeof(*map->mLndObjects[IMD_FEATURE]) * map->numFeatures); for(i = 0; i < map->numFeatures; i++) { LND_OBJECT *psObj = &map->mLndObjects[IMD_FEATURE][i]; int nameLength = 60; uint32_t dummy; uint8_t visibility[8]; if (map->featVersion <= 19) { nameLength = 40; } if (PHYSFS_read(fp, psObj->name, nameLength, 1) != 1 || !readU32(&psObj->id) || !readU32(&psObj->x) || !readU32(&psObj->y) || !readU32(&psObj->z) || !readU32(&psObj->direction) || !readU32(&psObj->player) || !readU32(&dummy) // BOOL inFire || !readU32(&dummy) // burnStart || !readU32(&dummy)) // burnDamage { debug(LOG_ERROR, "Failed to read feature from %s", path); goto failure; } psObj->player = 0; // work around invalid feature owner if (map->featVersion >= 14 && PHYSFS_read(fp, &visibility, 1, 8) != 8) { debug(LOG_ERROR, "Failed to read feature visibility from %s", path); goto failure; } psObj->type = 0; // IMD LND type for feature // Sanity check data if (psObj->x >= map->width * TILE_WIDTH || psObj->y >= map->height * TILE_HEIGHT) { debug(LOG_ERROR, "Bad feature coordinate %u(%u, %u)", psObj->id, psObj->x, psObj->y); goto failure; } } PHYSFS_close(fp); featfailure: /* === Load terrain data === */ littleEndian = true; strcpy(path, filename); strcat(path, "/ttypes.ttp"); fp = PHYSFS_openRead(path); if (!fp) { map->terrainVersion = 0; goto terrainfailure; } else if (PHYSFS_read(fp, aFileType, 4, 1) != 1 || aFileType[0] != 't' || aFileType[1] != 't' || aFileType[2] != 'y' || aFileType[3] != 'p' || !readU32(&map->terrainVersion) || !readU32(&map->numTerrainTypes)) { debug(LOG_ERROR, "Bad features header in %s", path); goto failure; } if (map->numTerrainTypes >= MAX_TILE_TEXTURES) { // Workaround for fugly map editor bug, since we can't fix the map editor map->numTerrainTypes = MAX_TILE_TEXTURES - 1; } // reset the terrain table memset(terrainTypes, 0, sizeof(terrainTypes)); for (i = 0; i < map->numTerrainTypes; i++) { readU16(&pType); if (pType > TER_MAX) { debug(LOG_ERROR, "loadTerrainTypeMap: terrain type out of range"); goto terrainfailure; } terrainTypes[i] = (uint8_t)pType; } if (terrainTypes[0] == 1 && terrainTypes[1] == 0 && terrainTypes[2] == 2) { map->tileset = TILESET_ARIZONA; } else if (terrainTypes[0] == 2 && terrainTypes[1] == 2 && terrainTypes[2] == 2) { map->tileset = TILESET_URBAN; } else if (terrainTypes[0] == 0 && terrainTypes[1] == 0 && terrainTypes[2] == 2) { map->tileset = TILESET_ROCKIES; } else { debug(LOG_ERROR, "Unknown terrain signature in %s: %u %u %u", path, terrainTypes[0], terrainTypes[1], terrainTypes[2]); goto failure; } PHYSFS_close(fp); terrainfailure: /* === Load structure data === */ map->mLndObjects[IMD_STRUCTURE] = NULL; map->numStructures = 0; littleEndian = true; strcpy(path, filename); strcat(path, "/struct.bjo"); map->mLndObjects[IMD_STRUCTURE] = NULL; fp = PHYSFS_openRead(path); if (fp) { if (PHYSFS_read(fp, aFileType, 4, 1) != 1 || aFileType[0] != 's' || aFileType[1] != 't' || aFileType[2] != 'r' || aFileType[3] != 'u' || !readU32(&map->structVersion) || !readU32(&map->numStructures)) { debug(LOG_ERROR, "Bad structure header in %s", path); goto failure; } map->mLndObjects[IMD_STRUCTURE] = (LND_OBJECT *)malloc(sizeof(*map->mLndObjects[IMD_STRUCTURE]) * map->numStructures); for (i = 0; i < map->numStructures; i++) { LND_OBJECT *psObj = &map->mLndObjects[IMD_STRUCTURE][i]; int nameLength = 60; uint32_t dummy; uint8_t visibility[8], dummy8; int16_t dummyS16; int32_t dummyS32; char researchName[60]; if (map->structVersion <= 19) { nameLength = 40; } if (PHYSFS_read(fp, psObj->name, nameLength, 1) != 1 || !readU32(&psObj->id) || !readU32(&psObj->x) || !readU32(&psObj->y) || !readU32(&psObj->z) || !readU32(&psObj->direction) || !readU32(&psObj->player) || !readU32(&dummy) // BOOL inFire || !readU32(&dummy) // burnStart || !readU32(&dummy) // burnDamage || !readU8(&dummy8) // status - causes structure padding || !readU8(&dummy8) // structure padding || !readU8(&dummy8) // structure padding || !readU8(&dummy8) // structure padding || !readS32(&dummyS32) // currentBuildPts - aligned on 4 byte boundary || !readU32(&dummy) // body || !readU32(&dummy) // armour || !readU32(&dummy) // resistance || !readU32(&dummy) // dummy1 || !readU32(&dummy) // subjectInc || !readU32(&dummy) // timeStarted || !readU32(&dummy) // output || !readU32(&dummy) // capacity || !readU32(&dummy)) // quantity { debug(LOG_ERROR, "Failed to read structure from %s", path); goto failure; } if (map->structVersion >= 12 && (!readU32(&dummy) // factoryInc || !readU8(&dummy8) // loopsPerformed - causes structure padding || !readU8(&dummy8) // structure padding || !readU8(&dummy8) // structure padding || !readU8(&dummy8) // structure padding || !readU32(&dummy) // powerAccrued - aligned on 4 byte boundary || !readU32(&dummy) // dummy2 || !readU32(&dummy) // droidTimeStarted || !readU32(&dummy) // timeToBuild || !readU32(&dummy))) // timeStartHold { debug(LOG_ERROR, "Failed to read structure v12 part from %s", path); goto failure; } if (map->structVersion >= 14 && PHYSFS_read(fp, &visibility, 1, 8) != 8) { debug(LOG_ERROR, "Failed to read structure visibility from %s", path); goto failure; } if (map->structVersion >= 15 && PHYSFS_read(fp, researchName, nameLength, 1) != 1) { // If version < 20, then this causes no padding, but the short below // will still cause two bytes padding; however, if version >= 20, we // will cause 4 bytes padding, but the short below will eat 2 of them, // leaving us again with only two bytes padding before the next word. debug(LOG_ERROR, "Failed to read structure v15 part from %s", path); goto failure; } if (map->structVersion >= 17 && !readS16(&dummyS16)) { debug(LOG_ERROR, "Failed to read structure v17 part from %s", path); goto failure; } if (map->structVersion >= 15 && !readS16(&dummyS16)) // structure padding { debug(LOG_ERROR, "Failed to read 16 bits of structure padding from %s", path); goto failure; } if (map->structVersion >= 21 && !readU32(&dummy)) { debug(LOG_ERROR, "Failed to read structure v21 part from %s", path); goto failure; } psObj->type = IMD_STRUCTURE; // Sanity check data if (psObj->player > MAX_PLAYERS) { debug(LOG_ERROR, "Bad structure owner %u for structure %d id=%u", psObj->player, i, psObj->id); goto failure; } if (psObj->x >= map->width * TILE_WIDTH || psObj->y >= map->height * TILE_HEIGHT) { debug(LOG_ERROR, "Bad structure %d coordinate %u(%u, %u)", i, psObj->id, psObj->x, psObj->y); goto failure; } } PHYSFS_close(fp); } /* === Load droid data === */ map->mLndObjects[IMD_DROID] = NULL; map->numDroids = 0; littleEndian = true; strcpy(path, filename); strcat(path, "/dinit.bjo"); map->mLndObjects[IMD_DROID] = NULL; fp = PHYSFS_openRead(path); if (fp) { if (PHYSFS_read(fp, aFileType, 4, 1) != 1 || aFileType[0] != 'd' || aFileType[1] != 'i' || aFileType[2] != 'n' || aFileType[3] != 't' || !readU32(&map->droidVersion) || !readU32(&map->numDroids)) { debug(LOG_ERROR, "Bad droid header in %s", path); goto failure; } map->mLndObjects[IMD_DROID] = (LND_OBJECT *)malloc(sizeof(*map->mLndObjects[IMD_DROID]) * map->numDroids); for (i = 0; i < map->numDroids; i++) { LND_OBJECT *psObj = &map->mLndObjects[IMD_DROID][i]; int nameLength = 60; uint32_t dummy; if (map->droidVersion <= 19) { nameLength = 40; } if (PHYSFS_read(fp, psObj->name, nameLength, 1) != 1 || !readU32(&psObj->id) || !readU32(&psObj->x) || !readU32(&psObj->y) || !readU32(&psObj->z) || !readU32(&psObj->direction) || !readU32(&psObj->player) || !readU32(&dummy) // BOOL inFire || !readU32(&dummy) // burnStart || !readU32(&dummy)) // burnDamage { debug(LOG_ERROR, "Failed to read droid from %s", path); goto failure; } psObj->type = IMD_DROID; // Sanity check data if (psObj->x >= map->width * TILE_WIDTH || psObj->y >= map->height * TILE_HEIGHT) { debug(LOG_ERROR, "Bad droid coordinate %u(%u, %u)", psObj->id, psObj->x, psObj->y); goto failure; } } PHYSFS_close(fp); } // Count players by looking for the obligatory construction droids map->numPlayers = 0; memset(counted, 0, sizeof(counted)); for(i = 0; i < map->numDroids; i++) { LND_OBJECT *psObj = &map->mLndObjects[IMD_DROID][i]; if (counted[psObj->player] == false && (strcmp(psObj->name, "ConstructorDroid") == 0 || strcmp(psObj->name, "ConstructionDroid") == 0)) { counted[psObj->player] = true; map->numPlayers++; } } return map; failure: mapFree(map); if (fp) { PHYSFS_close(fp); } return NULL; }
/* sender_peer_id given to this shall be quaranteed to be a valid peer */ void Client::ProcessData(NetworkPacket *pkt) { DSTACK(__FUNCTION_NAME); ScopeProfiler sp(g_profiler, "Client::ProcessData"); auto datasize = pkt->getSize(); auto sender_peer_id = pkt->getPeerId(); int command; MsgpackPacket packet; msgpack::unpacked msg; if (!con::parse_msgpack_packet(pkt->getString(0), datasize, &packet, &command, &msg)) { // invalid packet return; } //infostream<<"Client: received command="<<command<<std::endl; m_packetcounter.add((u16)command); /* If this check is removed, be sure to change the queue system to know the ids */ if(sender_peer_id != PEER_ID_SERVER) { infostream<<"Client::ProcessData(): Discarding data not " "coming from server: peer_id="<<sender_peer_id <<std::endl; return; } u8 ser_version = m_server_ser_ver; //infostream<<"Client received command="<<(int)command<<std::endl; if(command == TOCLIENT_INIT) { u8 deployed; packet[TOCLIENT_INIT_DEPLOYED].convert(&deployed); infostream<<"Client: TOCLIENT_INIT received with " "deployed="<<((int)deployed&0xff)<<std::endl; if(!ser_ver_supported(deployed)) { infostream<<"Client: TOCLIENT_INIT: Server sent " <<"unsupported ser_fmt_ver"<<std::endl; return; } m_server_ser_ver = deployed; // Set player position Player *player = m_env.getLocalPlayer(); if(!player) return; packet[TOCLIENT_INIT_SEED].convert(&m_map_seed); infostream<<"Client: received map seed: "<<m_map_seed<<std::endl; packet[TOCLIENT_INIT_STEP].convert(&m_recommended_send_interval); infostream<<"Client: received recommended send interval " <<m_recommended_send_interval<<std::endl; // TOCLIENT_INIT_POS if (m_localserver) { Settings settings; packet[TOCLIENT_INIT_MAP_PARAMS].convert(&settings); m_localserver->getEmergeManager()->params.load(settings); } // Reply to server MSGPACK_PACKET_INIT(TOSERVER_INIT2, 0); m_con.Send(PEER_ID_SERVER, 1, buffer, true); m_state = LC_Init; return; } if(command == TOCLIENT_ACCESS_DENIED_LEGACY) { // The server didn't like our password. Note, this needs // to be processed even if the serialisation format has // not been agreed yet, the same as TOCLIENT_INIT. m_access_denied = true; packet[TOCLIENT_ACCESS_DENIED_CUSTOM_STRING].convert(&m_access_denied_reason); return; } if(ser_version == SER_FMT_VER_INVALID) { infostream<<"Client: Server serialization" " format invalid or not initialized." " Skipping incoming command="<<command<<std::endl; return; } /* Handle runtime commands */ // there's no sane reason why we shouldn't have a player and // almost everyone needs a player reference Player *player = m_env.getLocalPlayer(); if(!player) return; if(command == TOCLIENT_REMOVENODE) { v3s16 p = packet[TOCLIENT_REMOVENODE_POS].as<v3s16>(); removeNode(p, 2); //use light from top node } else if(command == TOCLIENT_ADDNODE) { v3s16 p = packet[TOCLIENT_ADDNODE_POS].as<v3s16>(); MapNode n = packet[TOCLIENT_ADDNODE_NODE].as<MapNode>(); bool remove_metadata = packet[TOCLIENT_ADDNODE_REMOVE_METADATA].as<bool>(); addNode(p, n, remove_metadata, 2); //fast add } else if(command == TOCLIENT_BLOCKDATA) { v3s16 p = packet[TOCLIENT_BLOCKDATA_POS].as<v3s16>(); s8 step = 1; packet[TOCLIENT_BLOCKDATA_STEP].convert(&step); if (step == 1) { std::istringstream istr(packet[TOCLIENT_BLOCKDATA_DATA].as<std::string>(), std::ios_base::binary); MapBlock *block; block = m_env.getMap().getBlockNoCreateNoEx(p); bool new_block = !block; if (new_block) block = new MapBlock(&m_env.getMap(), p, this); block->deSerialize(istr, ser_version, false); s32 h; // for convert to atomic packet[TOCLIENT_BLOCKDATA_HEAT].convert(&h); block->heat = h; packet[TOCLIENT_BLOCKDATA_HUMIDITY].convert(&h); block->humidity = h; if (packet.count(TOCLIENT_BLOCKDATA_CONTENT_ONLY)) block->content_only = packet[TOCLIENT_BLOCKDATA_CONTENT_ONLY].as<content_t>(); if (m_localserver != NULL) { m_localserver->getMap().saveBlock(block); } if (new_block) if (!m_env.getMap().insertBlock(block)) delete block; /* //Add it to mesh update queue and set it to be acknowledged after update. */ //infostream<<"Adding mesh update task for received block "<<p<<std::endl; updateMeshTimestampWithEdge(p); if (block->content_only != CONTENT_IGNORE && block->content_only != CONTENT_AIR) { if (getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS)).getDistanceFrom(p) <= 1) addUpdateMeshTaskWithEdge(p); } /* #if !defined(NDEBUG) if (m_env.getClientMap().m_block_boundary.size() > 150) m_env.getClientMap().m_block_boundary.clear(); m_env.getClientMap().m_block_boundary[p] = block; #endif */ }//step } else if(command == TOCLIENT_INVENTORY) { std::string datastring = packet[TOCLIENT_INVENTORY_DATA].as<std::string>(); std::istringstream is(datastring, std::ios_base::binary); Player *player = m_env.getLocalPlayer(); if(!player) return; player->inventory.deSerialize(is); m_inventory_updated = true; delete m_inventory_from_server; m_inventory_from_server = new Inventory(player->inventory); m_inventory_from_server_age = 0.0; } else if(command == TOCLIENT_TIME_OF_DAY) { u16 time_of_day = packet[TOCLIENT_TIME_OF_DAY_TIME].as<u16>(); time_of_day = time_of_day % 24000; f32 time_speed = packet[TOCLIENT_TIME_OF_DAY_TIME_SPEED].as<f32>(); // Update environment m_env.setTimeOfDay(time_of_day); m_env.setTimeOfDaySpeed(time_speed); m_time_of_day_set = true; u32 dr = m_env.getDayNightRatio(); verbosestream<<"Client: time_of_day="<<time_of_day <<" time_speed="<<time_speed <<" dr="<<dr<<std::endl; } else if(command == TOCLIENT_CHAT_MESSAGE) { std::string message = packet[TOCLIENT_CHAT_MESSAGE_DATA].as<std::string>(); m_chat_queue.push(message); } else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD) { std::vector<u16> removed_objects; packet[TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD_REMOVE].convert(&removed_objects); for (size_t i = 0; i < removed_objects.size(); ++i) m_env.removeActiveObject(removed_objects[i]); std::vector<ActiveObjectAddData> added_objects; packet[TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD_ADD].convert(&added_objects); for (size_t i = 0; i < added_objects.size(); ++i) m_env.addActiveObject(added_objects[i].id, added_objects[i].type, added_objects[i].data); } else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES) { ActiveObjectMessages messages; packet[TOCLIENT_ACTIVE_OBJECT_MESSAGES_MESSAGES].convert(&messages); for (size_t i = 0; i < messages.size(); ++i) m_env.processActiveObjectMessage(messages[i].first, messages[i].second); } else if(command == TOCLIENT_MOVEMENT) { Player *player = m_env.getLocalPlayer(); packet[TOCLIENT_MOVEMENT_ACCELERATION_DEFAULT].convert(&player->movement_acceleration_default); packet[TOCLIENT_MOVEMENT_ACCELERATION_AIR].convert(&player->movement_acceleration_air); packet[TOCLIENT_MOVEMENT_ACCELERATION_FAST].convert(&player->movement_acceleration_fast); packet[TOCLIENT_MOVEMENT_SPEED_WALK].convert(&player->movement_speed_walk); packet[TOCLIENT_MOVEMENT_SPEED_CROUCH].convert(&player->movement_speed_crouch); packet[TOCLIENT_MOVEMENT_SPEED_FAST].convert(&player->movement_speed_fast); packet[TOCLIENT_MOVEMENT_SPEED_CLIMB].convert(&player->movement_speed_climb); packet[TOCLIENT_MOVEMENT_SPEED_JUMP].convert(&player->movement_speed_jump); packet[TOCLIENT_MOVEMENT_LIQUID_FLUIDITY].convert(&player->movement_liquid_fluidity); packet[TOCLIENT_MOVEMENT_LIQUID_FLUIDITY_SMOOTH].convert(&player->movement_liquid_fluidity_smooth); packet[TOCLIENT_MOVEMENT_LIQUID_SINK].convert(&player->movement_liquid_sink); packet[TOCLIENT_MOVEMENT_GRAVITY].convert(&player->movement_gravity); } else if(command == TOCLIENT_HP) { Player *player = m_env.getLocalPlayer(); if(!player) return; u8 oldhp = player->hp; u8 hp = packet[TOCLIENT_HP_HP].as<u8>(); player->hp = hp; if(hp < oldhp) { // Add to ClientEvent queue ClientEvent event; event.type = CE_PLAYER_DAMAGE; event.player_damage.amount = oldhp - hp; m_client_event_queue.push(event); } } else if(command == TOCLIENT_BREATH) { Player *player = m_env.getLocalPlayer(); player->setBreath(packet[TOCLIENT_BREATH_BREATH].as<u16>()) ; } else if(command == TOCLIENT_MOVE_PLAYER) { Player *player = m_env.getLocalPlayer(); if(!player) return; v3f pos = packet[TOCLIENT_MOVE_PLAYER_POS].as<v3f>(); f32 pitch = packet[TOCLIENT_MOVE_PLAYER_PITCH].as<f32>(); f32 yaw = packet[TOCLIENT_MOVE_PLAYER_YAW].as<f32>(); player->setPosition(pos); infostream<<"Client got TOCLIENT_MOVE_PLAYER" <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")" <<" pitch="<<pitch <<" yaw="<<yaw <<std::endl; /* Add to ClientEvent queue. This has to be sent to the main program because otherwise it would just force the pitch and yaw values to whatever the camera points to. */ ClientEvent event; event.type = CE_PLAYER_FORCE_MOVE; event.player_force_move.pitch = pitch; event.player_force_move.yaw = yaw; m_client_event_queue.push(event); // Ignore damage for a few seconds, so that the player doesn't // get damage from falling on ground m_ignore_damage_timer = 3.0; } else if(command == TOCLIENT_DEATHSCREEN) { bool set_camera_point_target = packet[TOCLIENT_DEATHSCREEN_SET_CAMERA].as<bool>(); v3f camera_point_target = packet[TOCLIENT_DEATHSCREEN_CAMERA_POINT].as<v3f>(); ClientEvent event; event.type = CE_DEATHSCREEN; event.deathscreen.set_camera_point_target = set_camera_point_target; event.deathscreen.camera_point_target_x = camera_point_target.X; event.deathscreen.camera_point_target_y = camera_point_target.Y; event.deathscreen.camera_point_target_z = camera_point_target.Z; m_client_event_queue.push(event); } else if(command == TOCLIENT_ANNOUNCE_MEDIA) { if (m_media_downloader == NULL || m_media_downloader->isStarted()) { const char *problem = m_media_downloader ? "we already saw another announcement" : "all media has been received already"; errorstream<<"Client: Received media announcement but " <<problem<<"!" <<std::endl; return; } // Mesh update thread must be stopped while // updating content definitions //assert(!m_mesh_update_thread.IsRunning()); MediaAnnounceList announce_list; packet[TOCLIENT_ANNOUNCE_MEDIA_LIST].convert(&announce_list); for (size_t i = 0; i < announce_list.size(); ++i) m_media_downloader->addFile(announce_list[i].first, base64_decode(announce_list[i].second)); std::vector<std::string> remote_media; std::string remote_media_string = packet[TOCLIENT_ANNOUNCE_MEDIA_REMOTE_SERVER].as<std::string>(); Strfnd sf(remote_media_string); while(!sf.atend()) { std::string baseurl = trim(sf.next(",")); if(baseurl != "") m_media_downloader->addRemoteServer(baseurl); } m_media_downloader->step(this); } else if(command == TOCLIENT_MEDIA) { MediaData media_data; packet[TOCLIENT_MEDIA_MEDIA].convert(&media_data); // Mesh update thread must be stopped while // updating content definitions //assert(!m_mesh_update_thread.IsRunning()); for(size_t i = 0; i < media_data.size(); ++i) m_media_downloader->conventionalTransferDone( media_data[i].first, media_data[i].second, this); } else if(command == TOCLIENT_NODEDEF) { infostream<<"Client: Received node definitions: packet size: " <<datasize<<std::endl; // Mesh update thread must be stopped while // updating content definitions //assert(!m_mesh_update_thread.IsRunning()); packet[TOCLIENT_NODEDEF_DEFINITIONS].convert(m_nodedef); m_nodedef_received = true; } else if(command == TOCLIENT_ITEMDEF) { infostream<<"Client: Received item definitions: packet size: " <<datasize<<std::endl; // Mesh update thread must be stopped while // updating content definitions //assert(!m_mesh_update_thread.IsRunning()); packet[TOCLIENT_ITEMDEF_DEFINITIONS].convert(m_itemdef); m_itemdef_received = true; } else if(command == TOCLIENT_PLAY_SOUND) { s32 server_id = packet[TOCLIENT_PLAY_SOUND_ID].as<s32>(); std::string name = packet[TOCLIENT_PLAY_SOUND_NAME].as<std::string>(); float gain = packet[TOCLIENT_PLAY_SOUND_GAIN].as<f32>(); int type = packet[TOCLIENT_PLAY_SOUND_TYPE].as<u8>(); // 0=local, 1=positional, 2=object v3f pos = packet[TOCLIENT_PLAY_SOUND_POS].as<v3f>(); u16 object_id = packet[TOCLIENT_PLAY_SOUND_OBJECT_ID].as<u16>(); bool loop = packet[TOCLIENT_PLAY_SOUND_LOOP].as<bool>(); // Start playing int client_id = -1; switch(type){ case 0: // local client_id = m_sound->playSound(name, loop, gain); break; case 1: // positional client_id = m_sound->playSoundAt(name, loop, gain, pos); break; case 2: { // object ClientActiveObject *cao = m_env.getActiveObject(object_id); if(cao) pos = cao->getPosition(); client_id = m_sound->playSoundAt(name, loop, gain, pos); // TODO: Set up sound to move with object break; } default: break; } if(client_id != -1){ m_sounds_server_to_client[server_id] = client_id; m_sounds_client_to_server[client_id] = server_id; if(object_id != 0) m_sounds_to_objects[client_id] = object_id; } } else if(command == TOCLIENT_STOP_SOUND) { s32 server_id = packet[TOCLIENT_STOP_SOUND_ID].as<s32>(); std::map<s32, int>::iterator i = m_sounds_server_to_client.find(server_id); if(i != m_sounds_server_to_client.end()){ int client_id = i->second; m_sound->stopSound(client_id); } } else if(command == TOCLIENT_PRIVILEGES) { packet[TOCLIENT_PRIVILEGES_PRIVILEGES].convert(&m_privileges); } else if(command == TOCLIENT_INVENTORY_FORMSPEC) { // Store formspec in LocalPlayer player->inventory_formspec = packet[TOCLIENT_INVENTORY_FORMSPEC_DATA].as<std::string>(); } else if(command == TOCLIENT_DETACHED_INVENTORY) { std::string name = packet[TOCLIENT_DETACHED_INVENTORY_NAME].as<std::string>(); std::string datastring = packet[TOCLIENT_DETACHED_INVENTORY_DATA].as<std::string>(); std::istringstream is(datastring, std::ios_base::binary); infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl; Inventory *inv = NULL; if(m_detached_inventories.count(name) > 0) inv = m_detached_inventories[name]; else{ inv = new Inventory(m_itemdef); m_detached_inventories[name] = inv; } inv->deSerialize(is); } else if(command == TOCLIENT_SHOW_FORMSPEC) { std::string formspec = packet[TOCLIENT_SHOW_FORMSPEC_DATA].as<std::string>(); std::string formname = packet[TOCLIENT_SHOW_FORMSPEC_NAME].as<std::string>(); ClientEvent event; event.type = CE_SHOW_FORMSPEC; // pointer is required as event is a struct only! // adding a std:string to a struct isn't possible event.show_formspec.formspec = new std::string(formspec); event.show_formspec.formname = new std::string(formname); m_client_event_queue.push(event); } else if(command == TOCLIENT_SPAWN_PARTICLE) { v3f pos = packet[TOCLIENT_SPAWN_PARTICLE_POS].as<v3f>(); v3f vel = packet[TOCLIENT_SPAWN_PARTICLE_VELOCITY].as<v3f>(); v3f acc = packet[TOCLIENT_SPAWN_PARTICLE_ACCELERATION].as<v3f>(); float expirationtime = packet[TOCLIENT_SPAWN_PARTICLE_EXPIRATIONTIME].as<float>(); float size = packet[TOCLIENT_SPAWN_PARTICLE_SIZE].as<float>(); bool collisiondetection = packet[TOCLIENT_SPAWN_PARTICLE_COLLISIONDETECTION].as<bool>(); std::string texture = packet[TOCLIENT_SPAWN_PARTICLE_TEXTURE].as<std::string>(); bool vertical = packet[TOCLIENT_SPAWN_PARTICLE_VERTICAL].as<bool>(); ClientEvent event; event.type = CE_SPAWN_PARTICLE; event.spawn_particle.pos = new v3f (pos); event.spawn_particle.vel = new v3f (vel); event.spawn_particle.acc = new v3f (acc); event.spawn_particle.expirationtime = expirationtime; event.spawn_particle.size = size; event.spawn_particle.collisiondetection = collisiondetection; event.spawn_particle.vertical = vertical; event.spawn_particle.texture = new std::string(texture); m_client_event_queue.push(event); } else if(command == TOCLIENT_ADD_PARTICLESPAWNER) { u16 amount; float spawntime, minexptime, maxexptime, minsize, maxsize; v3f minpos, maxpos, minvel, maxvel, minacc, maxacc; bool collisiondetection, vertical; u32 id; std::string texture; packet[TOCLIENT_ADD_PARTICLESPAWNER_AMOUNT].convert(&amount); packet[TOCLIENT_ADD_PARTICLESPAWNER_SPAWNTIME].convert(&spawntime); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINPOS].convert(&minpos); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXPOS].convert(&maxpos); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINVEL].convert(&minvel); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXVEL].convert(&maxvel); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINACC].convert(&minacc); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXACC].convert(&maxacc); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINEXPTIME].convert(&minexptime); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXEXPTIME].convert(&maxexptime); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINSIZE].convert(&minsize); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXSIZE].convert(&maxsize); packet[TOCLIENT_ADD_PARTICLESPAWNER_COLLISIONDETECTION].convert(&collisiondetection); packet[TOCLIENT_ADD_PARTICLESPAWNER_TEXTURE].convert(&texture); packet[TOCLIENT_ADD_PARTICLESPAWNER_VERTICAL].convert(&vertical); packet[TOCLIENT_ADD_PARTICLESPAWNER_ID].convert(&id); ClientEvent event; event.type = CE_ADD_PARTICLESPAWNER; event.add_particlespawner.amount = amount; event.add_particlespawner.spawntime = spawntime; event.add_particlespawner.minpos = new v3f (minpos); event.add_particlespawner.maxpos = new v3f (maxpos); event.add_particlespawner.minvel = new v3f (minvel); event.add_particlespawner.maxvel = new v3f (maxvel); event.add_particlespawner.minacc = new v3f (minacc); event.add_particlespawner.maxacc = new v3f (maxacc); event.add_particlespawner.minexptime = minexptime; event.add_particlespawner.maxexptime = maxexptime; event.add_particlespawner.minsize = minsize; event.add_particlespawner.maxsize = maxsize; event.add_particlespawner.collisiondetection = collisiondetection; event.add_particlespawner.vertical = vertical; event.add_particlespawner.texture = new std::string(texture); event.add_particlespawner.id = id; m_client_event_queue.push(event); } else if(command == TOCLIENT_DELETE_PARTICLESPAWNER) { u32 id = packet[TOCLIENT_DELETE_PARTICLESPAWNER_ID].as<u32>(); ClientEvent event; event.type = CE_DELETE_PARTICLESPAWNER; event.delete_particlespawner.id = id; m_client_event_queue.push(event); } else if(command == TOCLIENT_HUDADD) { //std::string datastring((char *)&data[2], datasize - 2); //std::istringstream is(datastring, std::ios_base::binary); u32 id, number, item, dir; u8 type; v2f pos, scale, align, offset; std::string name, text; v3f world_pos; v2s32 size; packet[TOCLIENT_HUDADD_ID].convert(&id); packet[TOCLIENT_HUDADD_TYPE].convert(&type); packet[TOCLIENT_HUDADD_POS].convert(&pos); packet[TOCLIENT_HUDADD_NAME].convert(&name); packet[TOCLIENT_HUDADD_SCALE].convert(&scale); packet[TOCLIENT_HUDADD_TEXT].convert(&text); packet[TOCLIENT_HUDADD_NUMBER].convert(&number); packet[TOCLIENT_HUDADD_ITEM].convert(&item); packet[TOCLIENT_HUDADD_DIR].convert(&dir); packet[TOCLIENT_HUDADD_ALIGN].convert(&align); packet[TOCLIENT_HUDADD_OFFSET].convert(&offset); packet[TOCLIENT_HUDADD_WORLD_POS].convert(&world_pos); packet[TOCLIENT_HUDADD_SIZE].convert(&size); ClientEvent event; event.type = CE_HUDADD; event.hudadd.id = id; event.hudadd.type = type; event.hudadd.pos = new v2f(pos); event.hudadd.name = new std::string(name); event.hudadd.scale = new v2f(scale); event.hudadd.text = new std::string(text); event.hudadd.number = number; event.hudadd.item = item; event.hudadd.dir = dir; event.hudadd.align = new v2f(align); event.hudadd.offset = new v2f(offset); event.hudadd.world_pos = new v3f(world_pos); event.hudadd.size = new v2s32(size); m_client_event_queue.push(event); } else if(command == TOCLIENT_HUDRM) { u32 id = packet[TOCLIENT_HUDRM_ID].as<u32>(); ClientEvent event; event.type = CE_HUDRM; event.hudrm.id = id; m_client_event_queue.push(event); } else if(command == TOCLIENT_HUDCHANGE) { std::string sdata; v2f v2fdata; v3f v3fdata; v2s32 v2s32data; u32 intdata = 0; u32 id = packet[TOCLIENT_HUDCHANGE_ID].as<u32>(); u8 stat = packet[TOCLIENT_HUDCHANGE_STAT].as<int>(); if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE || stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET) packet[TOCLIENT_HUDCHANGE_V2F].convert(&v2fdata); else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT) packet[TOCLIENT_HUDCHANGE_STRING].convert(&sdata); else if (stat == HUD_STAT_WORLD_POS) packet[TOCLIENT_HUDCHANGE_V3F].convert(&v3fdata); else if (stat == HUD_STAT_SIZE) packet[TOCLIENT_HUDCHANGE_V2S32].convert(&v2s32data); else packet[TOCLIENT_HUDCHANGE_U32].convert(&intdata); ClientEvent event; event.type = CE_HUDCHANGE; event.hudchange.id = id; event.hudchange.stat = (HudElementStat)stat; event.hudchange.v2fdata = new v2f(v2fdata); event.hudchange.v3fdata = new v3f(v3fdata); event.hudchange.sdata = new std::string(sdata); event.hudchange.data = intdata; event.hudchange.v2s32data = new v2s32(v2s32data); m_client_event_queue.push(event); } else if(command == TOCLIENT_HUD_SET_FLAGS) { Player *player = m_env.getLocalPlayer(); if(!player) return; u32 flags = packet[TOCLIENT_HUD_SET_FLAGS_FLAGS].as<u32>(); u32 mask = packet[TOCLIENT_HUD_SET_FLAGS_MASK].as<u32>(); player->hud_flags &= ~mask; player->hud_flags |= flags; } else if(command == TOCLIENT_HUD_SET_PARAM) { u16 param = packet[TOCLIENT_HUD_SET_PARAM_ID].as<u16>(); std::string value = packet[TOCLIENT_HUD_SET_PARAM_VALUE].as<std::string>(); if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4){ s32 hotbar_itemcount = readS32((u8*) value.c_str()); if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX) player->hud_hotbar_itemcount = hotbar_itemcount; } else if (param == HUD_PARAM_HOTBAR_IMAGE) { ((LocalPlayer *) player)->hotbar_image = value; } else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) { ((LocalPlayer *) player)->hotbar_selected_image = value; } } /* else if(command == TOCLIENT_ANIMATIONS) { LocalPlayer *player = m_env.getLocalPlayer(); packet[TOCLIENT_ANIMATIONS_DEFAULT_START].convert(&player->animation_default_start); packet[TOCLIENT_ANIMATIONS_DEFAULT_STOP].convert(&player->animation_default_stop); packet[TOCLIENT_ANIMATIONS_WALK_START].convert(&player->animation_walk_start); packet[TOCLIENT_ANIMATIONS_WALK_STOP].convert(&player->animation_walk_stop); packet[TOCLIENT_ANIMATIONS_DIG_START].convert(&player->animation_dig_start); packet[TOCLIENT_ANIMATIONS_DIG_STOP].convert(&player->animation_dig_stop); packet[TOCLIENT_ANIMATIONS_WD_START].convert(&player->animation_wd_start); packet[TOCLIENT_ANIMATIONS_WD_STOP].convert(&player->animation_wd_stop); } */ else if(command == TOCLIENT_SET_SKY) { video::SColor *bgcolor = new video::SColor(packet[TOCLIENT_SET_SKY_COLOR].as<video::SColor>()); std::string *type = new std::string(packet[TOCLIENT_SET_SKY_TYPE].as<std::string>()); std::vector<std::string> *params = new std::vector<std::string>; packet[TOCLIENT_SET_SKY_PARAMS].convert(params); ClientEvent event; event.type = CE_SET_SKY; event.set_sky.bgcolor = bgcolor; event.set_sky.type = type; event.set_sky.params = params; m_client_event_queue.push(event); } else if(command == TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO) { bool do_override; float day_night_ratio_f; packet[TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_DO].convert(&do_override); packet[TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_VALUE].convert(&day_night_ratio_f); ClientEvent event; event.type = CE_OVERRIDE_DAY_NIGHT_RATIO; event.override_day_night_ratio.do_override = do_override; event.override_day_night_ratio.ratio_f = day_night_ratio_f; m_client_event_queue.push(event); } else if(command == TOCLIENT_LOCAL_PLAYER_ANIMATIONS) { LocalPlayer *player = m_env.getLocalPlayer(); if(!player) return; packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_IDLE].convert(&player->local_animations[0]); packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_WALK].convert(&player->local_animations[1]); packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_DIG].convert(&player->local_animations[2]); packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_WALKDIG].convert(&player->local_animations[3]); packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_FRAME_SPEED].convert(&player->local_animation_speed); } else if(command == TOCLIENT_EYE_OFFSET) { LocalPlayer *player = m_env.getLocalPlayer(); if(!player) return; packet[TOCLIENT_EYE_OFFSET_FIRST].convert(&player->eye_offset_first); packet[TOCLIENT_EYE_OFFSET_THIRD].convert(&player->eye_offset_third); } else { infostream<<"Client: Ignoring unknown command " <<command<<std::endl; } }
void pnVaultNode::read(const unsigned char* buffer, size_t size) { if (size < sizeof(uint64_t)) { plDebug::Error("Invalid node data"); return; } fDirtyMask = 0; fDirtySize = 0; fFieldMask = readU64(buffer, size); fCachedSize = size; for (size_t bit=0; bit<kNumFields; bit++) { if ((fFieldMask & (1ULL<<bit)) == 0) continue; switch (bit) { case kNodeIdx: fNodeIdx = readU32(buffer, size); break; case kCreateTime: fCreateTime = readU32(buffer, size); break; case kModifyTime: fModifyTime = readU32(buffer, size); break; case kCreateAgeName: fCreateAgeName = readString(buffer, size); break; case kCreateAgeUuid: fCreateAgeUuid = readUuid(buffer, size); break; case kCreatorUuid: fCreatorUuid = readUuid(buffer, size); break; case kCreatorIdx: fCreatorIdx = readU32(buffer, size); break; case kNodeType: fNodeType = readU32(buffer, size); break; case kInt32_1: case kInt32_2: case kInt32_3: case kInt32_4: fInt32[bit - kInt32_1] = readS32(buffer, size); break; case kUint32_1: case kUint32_2: case kUint32_3: case kUint32_4: fUint32[bit - kUint32_1] = readU32(buffer, size); break; case kUuid_1: case kUuid_2: case kUuid_3: case kUuid_4: fUuid[bit - kUuid_1] = readUuid(buffer, size); break; case kString64_1: case kString64_2: case kString64_3: case kString64_4: case kString64_5: case kString64_6: fString64[bit - kString64_1] = readString(buffer, size); break; case kIString64_1: case kIString64_2: fIString64[bit - kIString64_1] = readString(buffer, size); break; case kText_1: case kText_2: fText[bit - kText_1] = readString(buffer, size); break; case kBlob_1: case kBlob_2: { size_t len = readU32(buffer, size); fBlob[bit - kBlob_1].setData(len, buffer); buffer += len; size -= len; } break; } } if (size != 0) plDebug::Warning("Incomplete read of node %d", fNodeIdx); }
/* sender_peer_id given to this shall be quaranteed to be a valid peer */ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) { DSTACK(__FUNCTION_NAME); // Ignore packets that don't even fit a command if(datasize < 2) { m_packetcounter.add(60000); return; } ToClientCommand command = (ToClientCommand)readU16(&data[0]); //infostream<<"Client: received command="<<command<<std::endl; m_packetcounter.add((u16)command); /* If this check is removed, be sure to change the queue system to know the ids */ if(sender_peer_id != PEER_ID_SERVER) { infostream<<"Client::ProcessData(): Discarding data not " "coming from server: peer_id="<<sender_peer_id <<std::endl; return; } u8 ser_version = m_server_ser_ver; //infostream<<"Client received command="<<(int)command<<std::endl; if(command == TOCLIENT_INIT) { if(datasize < 3) return; u8 deployed = data[2]; infostream<<"Client: TOCLIENT_INIT received with " "deployed="<<((int)deployed&0xff)<<std::endl; if(deployed < SER_FMT_VER_LOWEST || deployed > SER_FMT_VER_HIGHEST) { infostream<<"Client: TOCLIENT_INIT: Server sent " <<"unsupported ser_fmt_ver"<<std::endl; return; } m_server_ser_ver = deployed; // Get player position v3s16 playerpos_s16(0, BS*2+BS*20, 0); if(datasize >= 2+1+6) playerpos_s16 = readV3S16(&data[2+1]); v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0); { //envlock //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out // Set player position Player *player = m_env.getLocalPlayer(); assert(player != NULL); player->setPosition(playerpos_f); } if(datasize >= 2+1+6+8) { // Get map seed m_map_seed = readU64(&data[2+1+6]); infostream<<"Client: received map seed: "<<m_map_seed<<std::endl; } // Reply to server u32 replysize = 2; SharedBuffer<u8> reply(replysize); writeU16(&reply[0], TOSERVER_INIT2); // Send as reliable m_con.Send(PEER_ID_SERVER, 1, reply, true); return; } if(command == TOCLIENT_ACCESS_DENIED) { // The server didn't like our password. Note, this needs // to be processed even if the serialisation format has // not been agreed yet, the same as TOCLIENT_INIT. m_access_denied = true; m_access_denied_reason = L"Unknown"; if(datasize >= 4) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); m_access_denied_reason = deSerializeWideString(is); } return; } if(ser_version == SER_FMT_VER_INVALID) { infostream<<"Client: Server serialization" " format invalid or not initialized." " Skipping incoming command="<<command<<std::endl; return; } // Just here to avoid putting the two if's together when // making some copypasta {} if(command == TOCLIENT_REMOVENODE) { if(datasize < 8) return; v3s16 p; p.X = readS16(&data[2]); p.Y = readS16(&data[4]); p.Z = readS16(&data[6]); //TimeTaker t1("TOCLIENT_REMOVENODE"); // This will clear the cracking animation after digging ((ClientMap&)m_env.getMap()).clearTempMod(p); removeNode(p); } else if(command == TOCLIENT_ADDNODE) { if(datasize < 8 + MapNode::serializedLength(ser_version)) return; v3s16 p; p.X = readS16(&data[2]); p.Y = readS16(&data[4]); p.Z = readS16(&data[6]); //TimeTaker t1("TOCLIENT_ADDNODE"); MapNode n; n.deSerialize(&data[8], ser_version); addNode(p, n); } else if(command == TOCLIENT_BLOCKDATA) { // Ignore too small packet if(datasize < 8) return; v3s16 p; p.X = readS16(&data[2]); p.Y = readS16(&data[4]); p.Z = readS16(&data[6]); /*infostream<<"Client: Thread: BLOCKDATA for (" <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/ /*infostream<<"Client: Thread: BLOCKDATA for (" <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/ std::string datastring((char*)&data[8], datasize-8); std::istringstream istr(datastring, std::ios_base::binary); MapSector *sector; MapBlock *block; v2s16 p2d(p.X, p.Z); sector = m_env.getMap().emergeSector(p2d); assert(sector->getPos() == p2d); //TimeTaker timer("MapBlock deSerialize"); // 0ms block = sector->getBlockNoCreateNoEx(p.Y); if(block) { /* Update an existing block */ //infostream<<"Updating"<<std::endl; block->deSerialize(istr, ser_version); } else { /* Create a new block */ //infostream<<"Creating new"<<std::endl; block = new MapBlock(&m_env.getMap(), p); block->deSerialize(istr, ser_version); sector->insertBlock(block); //DEBUG /*NodeMod mod; mod.type = NODEMOD_CHANGECONTENT; mod.param = CONTENT_MESE; block->setTempMod(v3s16(8,10,8), mod); block->setTempMod(v3s16(8,9,8), mod); block->setTempMod(v3s16(8,8,8), mod); block->setTempMod(v3s16(8,7,8), mod); block->setTempMod(v3s16(8,6,8), mod);*/ } #if 0 /* Acknowledge block */ /* [0] u16 command [2] u8 count [3] v3s16 pos_0 [3+6] v3s16 pos_1 ... */ u32 replysize = 2+1+6; SharedBuffer<u8> reply(replysize); writeU16(&reply[0], TOSERVER_GOTBLOCKS); reply[2] = 1; writeV3S16(&reply[3], p); // Send as reliable m_con.Send(PEER_ID_SERVER, 1, reply, true); #endif /* Update Mesh of this block and blocks at x-, y- and z-. Environment should not be locked as it interlocks with the main thread, from which is will want to retrieve textures. */ //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio()); /* Add it to mesh update queue and set it to be acknowledged after update. */ //infostream<<"Adding mesh update task for received block"<<std::endl; addUpdateMeshTaskWithEdge(p, true); } else if(command == TOCLIENT_PLAYERPOS) { infostream<<"Received deprecated TOCLIENT_PLAYERPOS" <<std::endl; /*u16 our_peer_id; { //JMutexAutoLock lock(m_con_mutex); //bulk comment-out our_peer_id = m_con.GetPeerID(); } // Cancel if we don't have a peer id if(our_peer_id == PEER_ID_INEXISTENT){ infostream<<"TOCLIENT_PLAYERPOS cancelled: " "we have no peer id" <<std::endl; return; }*/ { //envlock //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out u32 player_size = 2+12+12+4+4; u32 player_count = (datasize-2) / player_size; u32 start = 2; for(u32 i=0; i<player_count; i++) { u16 peer_id = readU16(&data[start]); Player *player = m_env.getPlayer(peer_id); // Skip if player doesn't exist if(player == NULL) { start += player_size; continue; } // Skip if player is local player if(player->isLocal()) { start += player_size; continue; } v3s32 ps = readV3S32(&data[start+2]); v3s32 ss = readV3S32(&data[start+2+12]); s32 pitch_i = readS32(&data[start+2+12+12]); s32 yaw_i = readS32(&data[start+2+12+12+4]); /*infostream<<"Client: got " <<"pitch_i="<<pitch_i <<" yaw_i="<<yaw_i<<std::endl;*/ f32 pitch = (f32)pitch_i / 100.0; f32 yaw = (f32)yaw_i / 100.0; v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.); v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.); player->setPosition(position); player->setSpeed(speed); player->setPitch(pitch); player->setYaw(yaw); /*infostream<<"Client: player "<<peer_id <<" pitch="<<pitch <<" yaw="<<yaw<<std::endl;*/ start += player_size; } } //envlock } else if(command == TOCLIENT_PLAYERINFO) { u16 our_peer_id; { //JMutexAutoLock lock(m_con_mutex); //bulk comment-out our_peer_id = m_con.GetPeerID(); } // Cancel if we don't have a peer id if(our_peer_id == PEER_ID_INEXISTENT){ infostream<<"TOCLIENT_PLAYERINFO cancelled: " "we have no peer id" <<std::endl; return; } //infostream<<"Client: Server reports players:"<<std::endl; { //envlock //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out u32 item_size = 2+PLAYERNAME_SIZE; u32 player_count = (datasize-2) / item_size; u32 start = 2; // peer_ids core::list<u16> players_alive; for(u32 i=0; i<player_count; i++) { // Make sure the name ends in '\0' data[start+2+20-1] = 0; u16 peer_id = readU16(&data[start]); players_alive.push_back(peer_id); /*infostream<<"peer_id="<<peer_id <<" name="<<((char*)&data[start+2])<<std::endl;*/ // Don't update the info of the local player if(peer_id == our_peer_id) { start += item_size; continue; } Player *player = m_env.getPlayer(peer_id); // Create a player if it doesn't exist if(player == NULL) { player = new RemotePlayer( m_device->getSceneManager()->getRootSceneNode(), m_device, -1); player->peer_id = peer_id; m_env.addPlayer(player); infostream<<"Client: Adding new player " <<peer_id<<std::endl; } player->updateName((char*)&data[start+2]); start += item_size; } /* Remove those players from the environment that weren't listed by the server. */ //infostream<<"Removing dead players"<<std::endl; core::list<Player*> players = m_env.getPlayers(); core::list<Player*>::Iterator ip; for(ip=players.begin(); ip!=players.end(); ip++) { // Ingore local player if((*ip)->isLocal()) continue; // Warn about a special case if((*ip)->peer_id == 0) { infostream<<"Client: Removing " "dead player with id=0"<<std::endl; } bool is_alive = false; core::list<u16>::Iterator i; for(i=players_alive.begin(); i!=players_alive.end(); i++) { if((*ip)->peer_id == *i) { is_alive = true; break; } } /*infostream<<"peer_id="<<((*ip)->peer_id) <<" is_alive="<<is_alive<<std::endl;*/ if(is_alive) continue; infostream<<"Removing dead player "<<(*ip)->peer_id <<std::endl; m_env.removePlayer((*ip)->peer_id); } } //envlock } else if(command == TOCLIENT_SECTORMETA) { infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl; #if 0 /* [0] u16 command [2] u8 sector count [3...] v2s16 pos + sector metadata */ if(datasize < 3) return; //infostream<<"Client received TOCLIENT_SECTORMETA"<<std::endl; { //envlock //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); u8 buf[4]; is.read((char*)buf, 1); u16 sector_count = readU8(buf); //infostream<<"sector_count="<<sector_count<<std::endl; for(u16 i=0; i<sector_count; i++) { // Read position is.read((char*)buf, 4); v2s16 pos = readV2S16(buf); /*infostream<<"Client: deserializing sector at " <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/ // Create sector assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is); } } //envlock #endif } else if(command == TOCLIENT_INVENTORY) { if(datasize < 3) return; //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device); { //envlock //TimeTaker t2("mutex locking", m_device); //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out //t2.stop(); //TimeTaker t3("istringstream init", m_device); std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); //t3.stop(); //m_env.printPlayers(infostream); //TimeTaker t4("player get", m_device); Player *player = m_env.getLocalPlayer(); assert(player != NULL); //t4.stop(); //TimeTaker t1("inventory.deSerialize()", m_device); player->inventory.deSerialize(is); //t1.stop(); m_inventory_updated = true; //infostream<<"Client got player inventory:"<<std::endl; //player->inventory.print(infostream); } } //DEBUG else if(command == TOCLIENT_OBJECTDATA) { // Strip command word and create a stringstream std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); u8 buf[12]; /* Read players */ is.read((char*)buf, 2); u16 playercount = readU16(buf); for(u16 i=0; i<playercount; i++) { is.read((char*)buf, 2); u16 peer_id = readU16(buf); is.read((char*)buf, 12); v3s32 p_i = readV3S32(buf); is.read((char*)buf, 12); v3s32 s_i = readV3S32(buf); is.read((char*)buf, 4); s32 pitch_i = readS32(buf); is.read((char*)buf, 4); s32 yaw_i = readS32(buf); Player *player = m_env.getPlayer(peer_id); // Skip if player doesn't exist if(player == NULL) { continue; } // Skip if player is local player if(player->isLocal()) { continue; } f32 pitch = (f32)pitch_i / 100.0; f32 yaw = (f32)yaw_i / 100.0; v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.); v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.); player->setPosition(position); player->setSpeed(speed); player->setPitch(pitch); player->setYaw(yaw); } /* Read block objects NOTE: Deprecated stuff */ // Read active block count u16 blockcount = readU16(is); if(blockcount != 0){ infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 " "not supported"<<std::endl; return; } } else if(command == TOCLIENT_TIME_OF_DAY) { if(datasize < 4) return; u16 time_of_day = readU16(&data[2]); time_of_day = time_of_day % 24000; //infostream<<"Client: time_of_day="<<time_of_day<<std::endl; /* time_of_day: 0 = midnight 12000 = midday */ { m_env.setTimeOfDay(time_of_day); u32 dr = m_env.getDayNightRatio(); infostream<<"Client: time_of_day="<<time_of_day <<", dr="<<dr <<std::endl; } } else if(command == TOCLIENT_CHAT_MESSAGE) { /* u16 command u16 length wstring message */ u8 buf[6]; std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); // Read stuff is.read((char*)buf, 2); u16 len = readU16(buf); std::wstring message; for(u16 i=0; i<len; i++) { is.read((char*)buf, 2); message += (wchar_t)readU16(buf); } /*infostream<<"Client received chat message: " <<wide_to_narrow(message)<<std::endl;*/ m_chat_queue.push_back(message); } else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD) { //if(g_settings->getBool("enable_experimental")) { /* u16 command u16 count of removed objects for all removed objects { u16 id } u16 count of added objects for all added objects { u16 id u8 type u32 initialization data length string initialization data } */ char buf[6]; // Get all data except the command number std::string datastring((char*)&data[2], datasize-2); // Throw them in an istringstream std::istringstream is(datastring, std::ios_base::binary); // Read stuff // Read removed objects is.read(buf, 2); u16 removed_count = readU16((u8*)buf); for(u16 i=0; i<removed_count; i++) { is.read(buf, 2); u16 id = readU16((u8*)buf); // Remove it { //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out m_env.removeActiveObject(id); } } // Read added objects is.read(buf, 2); u16 added_count = readU16((u8*)buf); for(u16 i=0; i<added_count; i++) { is.read(buf, 2); u16 id = readU16((u8*)buf); is.read(buf, 1); u8 type = readU8((u8*)buf); std::string data = deSerializeLongString(is); // Add it { //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out m_env.addActiveObject(id, type, data); } } } } else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES) { //if(g_settings->getBool("enable_experimental")) { /* u16 command for all objects { u16 id u16 message length string message } */ char buf[6]; // Get all data except the command number std::string datastring((char*)&data[2], datasize-2); // Throw them in an istringstream std::istringstream is(datastring, std::ios_base::binary); while(is.eof() == false) { // Read stuff is.read(buf, 2); u16 id = readU16((u8*)buf); if(is.eof()) break; is.read(buf, 2); u16 message_size = readU16((u8*)buf); std::string message; message.reserve(message_size); for(u16 i=0; i<message_size; i++) { is.read(buf, 1); message.append(buf, 1); } // Pass on to the environment { //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out m_env.processActiveObjectMessage(id, message); } } } } else if(command == TOCLIENT_HP) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); Player *player = m_env.getLocalPlayer(); assert(player != NULL); u8 hp = readU8(is); player->hp = hp; } else if(command == TOCLIENT_MOVE_PLAYER) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); Player *player = m_env.getLocalPlayer(); assert(player != NULL); v3f pos = readV3F1000(is); f32 pitch = readF1000(is); f32 yaw = readF1000(is); player->setPosition(pos); /*player->setPitch(pitch); player->setYaw(yaw);*/ infostream<<"Client got TOCLIENT_MOVE_PLAYER" <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")" <<" pitch="<<pitch <<" yaw="<<yaw <<std::endl; /* Add to ClientEvent queue. This has to be sent to the main program because otherwise it would just force the pitch and yaw values to whatever the camera points to. */ ClientEvent event; event.type = CE_PLAYER_FORCE_MOVE; event.player_force_move.pitch = pitch; event.player_force_move.yaw = yaw; m_client_event_queue.push_back(event); // Ignore damage for a few seconds, so that the player doesn't // get damage from falling on ground m_ignore_damage_timer = 3.0; } else if(command == TOCLIENT_PLAYERITEM) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); u16 count = readU16(is); for (u16 i = 0; i < count; ++i) { u16 peer_id = readU16(is); Player *player = m_env.getPlayer(peer_id); if (player == NULL) { infostream<<"Client: ignoring player item " << deSerializeString(is) << " for non-existing peer id " << peer_id << std::endl; continue; } else if (player->isLocal()) { infostream<<"Client: ignoring player item " << deSerializeString(is) << " for local player" << std::endl; continue; } else { InventoryList *inv = player->inventory.getList("main"); std::string itemstring(deSerializeString(is)); if (itemstring.empty()) { inv->deleteItem(0); infostream <<"Client: empty player item for peer " << peer_id << std::endl; } else { std::istringstream iss(itemstring); delete inv->changeItem(0, InventoryItem::deSerialize(iss)); infostream<<"Client: player item for peer " << peer_id << ": "; player->getWieldItem()->serialize(infostream); infostream<<std::endl; } } } } else if(command == TOCLIENT_DEATHSCREEN) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); bool set_camera_point_target = readU8(is); v3f camera_point_target = readV3F1000(is); ClientEvent event; event.type = CE_DEATHSCREEN; event.deathscreen.set_camera_point_target = set_camera_point_target; event.deathscreen.camera_point_target_x = camera_point_target.X; event.deathscreen.camera_point_target_y = camera_point_target.Y; event.deathscreen.camera_point_target_z = camera_point_target.Z; m_client_event_queue.push_back(event); } else { infostream<<"Client: Ignoring unknown command " <<command<<std::endl; } }