void Client::sendChangePassword(const std::string &oldpassword, const std::string &newpassword) { LocalPlayer *player = m_env.getLocalPlayer(); if (player == NULL) return; std::string playername = player->getName(); if (m_proto_ver >= 25) { // get into sudo mode and then send new password to server m_password = oldpassword; m_new_password = newpassword; startAuth(choseAuthMech(m_sudo_auth_methods)); } else { std::string oldpwd = translate_password(playername, oldpassword); std::string newpwd = translate_password(playername, newpassword); NetworkPacket pkt(TOSERVER_PASSWORD_LEGACY, 2 * PASSWORD_SIZE); for (u8 i = 0; i < PASSWORD_SIZE; i++) { pkt << (u8) (i < oldpwd.length() ? oldpwd[i] : 0); } for (u8 i = 0; i < PASSWORD_SIZE; i++) { pkt << (u8) (i < newpwd.length() ? newpwd[i] : 0); } Send(&pkt); } }
int LuaLocalPlayer::l_get_breath(lua_State *L) { LocalPlayer *player = getobject(L, 1); lua_pushinteger(L, player->getBreath()); return 1; }
void Client::typeChatMessage(const std::string &message) { // Discard empty line if(message.empty()) return; // Send to others sendChatMessage(message); // Show locally if (message[0] == '/') { m_chat_queue.push("issued command: " + message); } //freeminer display self message after recieving from server #if MINETEST_PROTO else { LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); std::string name = (player->getName()); m_chat_queue.push(std::string() + "<" + name + "> " + message); } #endif }
int LuaLocalPlayer::l_get_velocity(lua_State *L) { LocalPlayer *player = getobject(L, 1); push_v3f(L, player->getSpeed() / BS); return 1; }
int LuaLocalPlayer::l_get_pos(lua_State *L) { LocalPlayer *player = getobject(L, 1); push_v3f(L, player->getPosition() / BS); return 1; }
int LuaLocalPlayer::l_get_name(lua_State *L) { LocalPlayer *player = getobject(L, 1); lua_pushstring(L, player->getName()); return 1; }
void CharSelectDialog::updatePlayerInfo() { LocalPlayer *pi = mCharInfo->getEntry(); if (pi) { mNameLabel->setCaption(strprintf(_("Name: %s"), pi->getName().c_str())); mLevelLabel->setCaption(strprintf(_("Level: %d"), pi->mLevel)); mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), pi->mJobLevel)); mMoneyLabel->setCaption(strprintf(_("Gold: %d"), pi->mGp)); if (!mCharSelected) { mNewDelCharButton->setCaption(_("Delete")); mSelectButton->setEnabled(true); } } else { mNameLabel->setCaption(strprintf(_("Name: %s"), "")); mLevelLabel->setCaption(strprintf(_("Level: %d"), 0)); mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), 0)); mMoneyLabel->setCaption(strprintf(_("Money: %s"), "")); mNewDelCharButton->setCaption(_("New")); mSelectButton->setEnabled(false); } mBeingBox->setBeing(pi); }
void Client::typeChatMessage(const std::wstring &message) { // Discard empty line if (message.empty()) return; // If message was ate by script API, don't send it to server if (m_script->on_sending_message(wide_to_utf8(message))) { return; } // Send to others sendChatMessage(message); // Show locally if (message[0] != L'/') { // compatibility code if (m_proto_ver < 29) { LocalPlayer *player = m_env.getLocalPlayer(); assert(player); std::wstring name = narrow_to_wide(player->getName()); pushToChatQueue(new ChatMessage(CHATMESSAGE_TYPE_NORMAL, message, name)); } } }
void Client::handleCommand_AuthAccept(NetworkPacket* pkt) { deleteAuthData(); v3f playerpos; *pkt >> playerpos >> m_map_seed >> m_recommended_send_interval >> m_sudo_auth_methods; playerpos -= v3f(0, BS / 2, 0); // Set player position LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); player->setPosition(playerpos); infostream << "Client: received map seed: " << m_map_seed << std::endl; infostream << "Client: received recommended send interval " << m_recommended_send_interval<<std::endl; // Reply to server std::string lang = gettext("LANG_CODE"); if (lang == "LANG_CODE") lang = ""; NetworkPacket resp_pkt(TOSERVER_INIT2, sizeof(u16) + lang.size()); resp_pkt << lang; Send(&resp_pkt); m_state = LC_Init; }
void InputMenu::callback(HUDuiControl* w, void* data) { HUDuiList* list = (HUDuiList*)w; std::vector<std::string> *options = &list->getList(); std::string selectedOption = (*options)[list->getIndex()]; switch (((const char*)data)[0]) { case 'J': BZDB.set("joystickname", selectedOption); getMainWindow()->initJoystick(selectedOption); break; case 'F': { LocalPlayer* myTank = LocalPlayer::getMyTank(); // Do we force or not? if (selectedOption == "Do not force") { BZDB.set("allowInputChange", "1"); } else { BZDB.set("allowInputChange", "0"); BZDB.set("forceInputDevice", selectedOption); // Set the current input device to whatever we're forced to if (myTank) { myTank->setInputMethod(BZDB.get("forceInputDevice")); } } } break; case 'G': bool grabbing = (selectedOption == "yes"); if (grabbing) BZDB.set("mousegrab", "true"); else BZDB.set("mousegrab", "false"); getMainWindow()->enableGrabMouse(grabbing); break; } }
void Client::selectPlayerItem(u16 item) { LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); player->wieldItem(item); sendPlayerItem(item); }
bool CheckCollision(Tile tile) { if (localPlayer.left() <= tile.right() && localPlayer.right() >= tile.left() && localPlayer.top() <= tile.bottom() && localPlayer.bottom() >= tile.top()) { return true; } return false; }
void Client::sendPlayerPos() { LocalPlayer *myplayer = m_env.getLocalPlayer(); if (!myplayer) return; ClientMap &map = m_env.getClientMap(); u8 camera_fov = map.getCameraFov(); u8 wanted_range = map.getControl().wanted_range; // Save bandwidth by only updating position when something changed if(myplayer->last_position == myplayer->getPosition() && myplayer->last_speed == myplayer->getSpeed() && myplayer->last_pitch == myplayer->getPitch() && myplayer->last_yaw == myplayer->getYaw() && myplayer->last_keyPressed == myplayer->keyPressed && myplayer->last_camera_fov == camera_fov && myplayer->last_wanted_range == wanted_range) return; myplayer->last_position = myplayer->getPosition(); myplayer->last_speed = myplayer->getSpeed(); myplayer->last_pitch = myplayer->getPitch(); myplayer->last_yaw = myplayer->getYaw(); myplayer->last_keyPressed = myplayer->keyPressed; myplayer->last_camera_fov = camera_fov; myplayer->last_wanted_range = wanted_range; NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4 + 1 + 1); writePlayerPos(myplayer, &map, &pkt); Send(&pkt); }
BaseLocalPlayer* getLocalPlayer(PlayerId id) { LocalPlayer *myTank = LocalPlayer::getMyTank(); if (myTank->getId() == id) return myTank; #ifdef ROBOT for (int i = 0; i < numRobots; i++) if (robots[i]->getId() == id) return robots[i]; #endif return NULL; }
Player* lookupPlayer(PlayerId id) { // check my tank first LocalPlayer *myTank = LocalPlayer::getMyTank(); if (myTank->getId() == id) return myTank; if (id == ServerPlayer) return World::getWorld()->getWorldWeapons(); if (id < curMaxPlayers && player[id] && player[id]->getId() == id) return player[id]; // it's nobody we know about return NULL; }
void Client::sendPlayerPos() { LocalPlayer *myplayer = m_env.getLocalPlayer(); if(myplayer == NULL) return; ClientMap &map = m_env.getClientMap(); u8 camera_fov = map.getCameraFov(); u8 wanted_range = map.getControl().wanted_range; // Save bandwidth by only updating position when something changed if(myplayer->last_position == myplayer->getPosition() && myplayer->last_speed == myplayer->getSpeed() && myplayer->last_pitch == myplayer->getPitch() && myplayer->last_yaw == myplayer->getYaw() && myplayer->last_keyPressed == myplayer->keyPressed && myplayer->last_camera_fov == camera_fov && myplayer->last_wanted_range == wanted_range) return; myplayer->last_position = myplayer->getPosition(); myplayer->last_speed = myplayer->getSpeed(); myplayer->last_pitch = myplayer->getPitch(); myplayer->last_yaw = myplayer->getYaw(); myplayer->last_keyPressed = myplayer->keyPressed; myplayer->last_camera_fov = camera_fov; myplayer->last_wanted_range = wanted_range; //infostream << "Sending Player Position information" << std::endl; u16 our_peer_id; { //MutexAutoLock lock(m_con_mutex); //bulk comment-out our_peer_id = m_con.GetPeerID(); } // Set peer id if not set already if(myplayer->peer_id == PEER_ID_INEXISTENT) myplayer->peer_id = our_peer_id; assert(myplayer->peer_id == our_peer_id); NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4 + 1 + 1); writePlayerPos(myplayer, &map, &pkt); Send(&pkt); }
Inventory* Client::getInventory(const InventoryLocation &loc) { switch(loc.type){ case InventoryLocation::UNDEFINED: {} break; case InventoryLocation::CURRENT_PLAYER: { LocalPlayer *player = m_env.getLocalPlayer(); assert(player); return &player->inventory; } break; case InventoryLocation::PLAYER: { // Check if we are working with local player inventory LocalPlayer *player = m_env.getLocalPlayer(); if (!player || strcmp(player->getName(), loc.name.c_str()) != 0) return NULL; return &player->inventory; } break; case InventoryLocation::NODEMETA: { NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p); if(!meta) return NULL; return meta->getInventory(); } break; case InventoryLocation::DETACHED: { if (m_detached_inventories.count(loc.name) == 0) return NULL; return m_detached_inventories[loc.name]; } break; default: FATAL_ERROR("Invalid inventory location type."); break; } return NULL; }
void HandleCollision(Tile tile) { double overlapX, overlapY; if (localPlayer.midpoint().x > tile.midpoint().x) overlapX = tile.right() - localPlayer.left(); else overlapX = -(localPlayer.right() - tile.left()); if (localPlayer.midpoint().y > tile.midpoint().y) overlapY = tile.bottom() - localPlayer.top(); else overlapY = -(localPlayer.bottom() - tile.top()); if (overlapX != 0 && overlapY != 0) { if (abs(overlapY) < abs(overlapX)) { if (overlapY < 0) { if (localPlayer.velocityY > 0) { localPlayer.onGround = true; localPlayer.position.y += overlapY; localPlayer.velocityY = 0; if (std::find(groundTileList.begin(), groundTileList.end(), tile) == groundTileList.end()) groundTileList.push_back(tile); } } else { if (localPlayer.velocityY < 0) { if (CheckCollisionBottom(tile)) { localPlayer.position.y += overlapY; localPlayer.velocityY = 0; } } } } else { localPlayer.position.x += overlapX; localPlayer.velocityX = 0; } } }
void Client::typeChatMessage(const std::wstring &message) { // Discard empty line if(message == L"") return; // Send to others sendChatMessage(message); // Show locally if (message[0] == L'/') { m_chat_queue.push((std::wstring)L"issued command: " + message); } else { LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); std::wstring name = narrow_to_wide(player->getName()); m_chat_queue.push((std::wstring)L"<" + name + L"> " + message); } }
bool CharSelectDialog::selectByName(const std::string &name) { if (mCharInfo->isLocked()) return false; unsigned int oldPos = mCharInfo->getPos(); mCharInfo->select(0); do { LocalPlayer *player = mCharInfo->getEntry(); if (player && player->getName() == name) return true; mCharInfo->next(); } while (mCharInfo->getPos()); mCharInfo->select(oldPos); return false; }
LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot) { LocalPlayer *tempPlayer = new LocalPlayer; slot = msg.readInt8(); // character slot tempPlayer->setName(msg.readString()); tempPlayer->setGender(msg.readInt8() == GENDER_MALE ? GENDER_MALE : GENDER_FEMALE); int hs = msg.readInt8(), hc = msg.readInt8(); tempPlayer->setHairStyle(hs, hc); tempPlayer->setLevel(msg.readInt16()); tempPlayer->setCharacterPoints(msg.readInt16()); tempPlayer->setCorrectionPoints(msg.readInt16()); tempPlayer->setMoney(msg.readInt32()); for (int i = 0; i < 7; i++) { tempPlayer->setAttributeBase(i, msg.readInt8()); } return tempPlayer; }
void ClientEnvironment::step(float dtime) { DSTACK(__FUNCTION_NAME); // Get some settings bool free_move = g_settings.getBool("free_move"); bool footprints = g_settings.getBool("footprints"); // Get local player LocalPlayer *lplayer = getLocalPlayer(); assert(lplayer); // collision info queue core::list<CollisionInfo> player_collisions; /* Get the speed the player is going */ bool is_climbing = lplayer->is_climbing; f32 player_speed = 0.001; // just some small value player_speed = lplayer->getSpeed().getLength(); /* Maximum position increment */ //f32 position_max_increment = 0.05*BS; f32 position_max_increment = 0.1*BS; // Maximum time increment (for collision detection etc) // time = distance / speed f32 dtime_max_increment = position_max_increment / player_speed; // Maximum time increment is 10ms or lower if(dtime_max_increment > 0.01) dtime_max_increment = 0.01; // Don't allow overly huge dtime if(dtime > 0.5) dtime = 0.5; f32 dtime_downcount = dtime; /* Stuff that has a maximum time increment */ u32 loopcount = 0; do { loopcount++; f32 dtime_part; if(dtime_downcount > dtime_max_increment) { dtime_part = dtime_max_increment; dtime_downcount -= dtime_part; } else { dtime_part = dtime_downcount; /* Setting this to 0 (no -=dtime_part) disables an infinite loop when dtime_part is so small that dtime_downcount -= dtime_part does nothing */ dtime_downcount = 0; } /* Handle local player */ { v3f lplayerpos = lplayer->getPosition(); // Apply physics if(free_move == false && is_climbing == false) { // Gravity v3f speed = lplayer->getSpeed(); if(lplayer->swimming_up == false) speed.Y -= 9.81 * BS * dtime_part * 2; // Water resistance if(lplayer->in_water_stable || lplayer->in_water) { f32 max_down = 2.0*BS; if(speed.Y < -max_down) speed.Y = -max_down; f32 max = 2.5*BS; if(speed.getLength() > max) { speed = speed / speed.getLength() * max; } } lplayer->setSpeed(speed); } /* Move the lplayer. This also does collision detection. */ lplayer->move(dtime_part, *m_map, position_max_increment, &player_collisions); } } while(dtime_downcount > 0.001); //std::cout<<"Looped "<<loopcount<<" times."<<std::endl; for(core::list<CollisionInfo>::Iterator i = player_collisions.begin(); i != player_collisions.end(); i++) { CollisionInfo &info = *i; if(info.t == COLLISION_FALL) { //f32 tolerance = BS*10; // 2 without damage f32 tolerance = BS*12; // 3 without damage f32 factor = 1; if(info.speed > tolerance) { f32 damage_f = (info.speed - tolerance)/BS*factor; u16 damage = (u16)(damage_f+0.5); if(lplayer->hp > damage) lplayer->hp -= damage; else lplayer->hp = 0; ClientEnvEvent event; event.type = CEE_PLAYER_DAMAGE; event.player_damage.amount = damage; m_client_event_queue.push_back(event); } } } /* Stuff that can be done in an arbitarily large dtime */ for(core::list<Player*>::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; v3f playerpos = player->getPosition(); /* Handle non-local players */ if(player->isLocal() == false) { // Move player->move(dtime, *m_map, 100*BS); // Update lighting on remote players on client u8 light = LIGHT_MAX; try{ // Get node at head v3s16 p = floatToInt(playerpos + v3f(0,BS+BS/2,0), BS); MapNode n = m_map->getNode(p); light = n.getLightBlend(getDayNightRatio()); } catch(InvalidPositionException &e) {} player->updateLight(light); } /* Add footsteps to grass */ if(footprints) { // Get node that is at BS/4 under player v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS); try{ MapNode n = m_map->getNode(bottompos); if(n.getContent() == CONTENT_GRASS) { n.setContent(CONTENT_GRASS_FOOTSTEPS); m_map->setNode(bottompos, n); // Update mesh on client if(m_map->mapType() == MAPTYPE_CLIENT) { v3s16 p_blocks = getNodeBlockPos(bottompos); MapBlock *b = m_map->getBlockNoCreate(p_blocks); //b->updateMesh(getDayNightRatio()); b->setMeshExpired(true); } } } catch(InvalidPositionException &e) { } } } /* Step active objects and update lighting of them */ for(core::map<u16, ClientActiveObject*>::Iterator i = m_active_objects.getIterator(); i.atEnd()==false; i++) { ClientActiveObject* obj = i.getNode()->getValue(); // Step object obj->step(dtime, this); if(m_active_object_light_update_interval.step(dtime, 0.21)) { // Update lighting //u8 light = LIGHT_MAX; u8 light = 0; try{ // Get node at head v3s16 p = obj->getLightPosition(); MapNode n = m_map->getNode(p); light = n.getLightBlend(getDayNightRatio()); } catch(InvalidPositionException &e) {} obj->updateLight(light); } } }
void CharServerHandler::readPlayerData(Net::MessageIn &msg, Net::Character *character, bool withColors) { if (!character) return; const Token &token = static_cast<LoginHandler*>(Net::getLoginHandler())->getToken(); LocalPlayer *tempPlayer = new LocalPlayer(msg.readInt32(), 0); tempPlayer->setGender(token.sex); PlayerInfoBackend &data = character->data; data.mAttributes[EXP] = msg.readInt32(); data.mAttributes[MONEY] = msg.readInt32(); data.mStats[JOB].exp = msg.readInt32(); int temp = msg.readInt32(); data.mStats[JOB].base = temp; data.mStats[JOB].mod = temp; int shoes = msg.readInt16(); int gloves = msg.readInt16(); int cape = msg.readInt16(); int misc1 = msg.readInt16(); msg.readInt32(); // option msg.readInt32(); // karma msg.readInt32(); // manner msg.readInt16(); // character points left data.mAttributes[HP] = msg.readInt16(); data.mAttributes[MAX_HP] = msg.readInt16(); data.mAttributes[MP] = msg.readInt16(); data.mAttributes[MAX_MP] = msg.readInt16(); msg.readInt16(); // speed tempPlayer->setSubtype(msg.readInt16()); // class (used for race) int hairStyle = msg.readInt16(); uint16_t weapon = msg.readInt16(); // server not used it. may be need use? tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", 1, true); data.mAttributes[LEVEL] = msg.readInt16(); msg.readInt16(); // skill point int bottomClothes = msg.readInt16(); int shield = msg.readInt16(); int hat = msg.readInt16(); // head option top int topClothes = msg.readInt16(); tempPlayer->setSprite(SPRITE_HAIR, hairStyle * -1, ItemDB::get(-hairStyle).getDyeColorsString(msg.readInt16())); int misc2 = msg.readInt16(); tempPlayer->setName(msg.readString(24)); character->dummy = tempPlayer; for (int i = 0; i < 6; i++) character->data.mStats[i + STR].base = msg.readInt8(); if (withColors) { tempPlayer->setSprite(SPRITE_SHOE, shoes, "", msg.readInt8()); tempPlayer->setSprite(SPRITE_GLOVES, gloves, "", msg.readInt8()); tempPlayer->setSprite(SPRITE_CAPE, cape, "", msg.readInt8()); tempPlayer->setSprite(SPRITE_MISC1, misc1, "", msg.readInt8()); tempPlayer->setSprite(SPRITE_BOTTOMCLOTHES, bottomClothes, "", msg.readInt8()); //to avoid show error (error.xml) need remove this sprite if (!config.getBoolValue("hideShield")) tempPlayer->setSprite(SPRITE_SHIELD, shield, "", msg.readInt8()); else msg.readInt8(); tempPlayer->setSprite(SPRITE_HAT, hat, "", msg.readInt8()); // head option top tempPlayer->setSprite(SPRITE_TOPCLOTHES, topClothes, "", msg.readInt8()); tempPlayer->setSprite(SPRITE_MISC2, misc2, "", msg.readInt8()); msg.skip(5); character->slot = msg.readInt8(); // character slot } else { tempPlayer->setSprite(SPRITE_SHOE, shoes); tempPlayer->setSprite(SPRITE_GLOVES, gloves); tempPlayer->setSprite(SPRITE_CAPE, cape); tempPlayer->setSprite(SPRITE_MISC1, misc1); tempPlayer->setSprite(SPRITE_BOTTOMCLOTHES, bottomClothes); //to avoid show error (error.xml) need remove this sprite if (!config.getBoolValue("hideShield")) tempPlayer->setSprite(SPRITE_SHIELD, shield); tempPlayer->setSprite(SPRITE_HAT, hat); // head option top tempPlayer->setSprite(SPRITE_TOPCLOTHES, topClothes); tempPlayer->setSprite(SPRITE_MISC2, misc2); character->slot = msg.readInt8(); // character slot } msg.readInt8(); // unknown }
void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_control, const CameraOrientation &cam, const PointedThing &pointed_old, float dtime) { v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); if (m_flags.show_debug) { static float drawtime_avg = 0; drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05; u16 fps = 1.0 / stats.dtime_jitter.avg; std::ostringstream os(std::ios_base::binary); os << std::fixed << PROJECT_NAME_C " " << g_version_hash << ", FPS: " << fps << std::setprecision(0) << ", drawtime: " << drawtime_avg << "ms" << std::setprecision(1) << ", dtime jitter: " << (stats.dtime_jitter.max_fraction * 100.0) << "%" << std::setprecision(1) << ", view range: " << (draw_control->range_all ? "All" : itos(draw_control->wanted_range)) << std::setprecision(3) << ", RTT: " << client->getRTT() << "s"; setStaticText(m_guitext, utf8_to_wide(os.str()).c_str()); m_guitext->setRelativePosition(core::rect<s32>(5, 5, screensize.X, 5 + g_fontengine->getTextHeight())); } // Finally set the guitext visible depending on the flag m_guitext->setVisible(m_flags.show_debug); if (m_flags.show_debug) { LocalPlayer *player = client->getEnv().getLocalPlayer(); v3f player_position = player->getPosition(); std::ostringstream os(std::ios_base::binary); os << std::setprecision(1) << std::fixed << "pos: (" << (player_position.X / BS) << ", " << (player_position.Y / BS) << ", " << (player_position.Z / BS) << "), yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° " << yawToDirectionString(cam.camera_yaw) << ", seed: " << ((u64)client->getMapSeed()); if (pointed_old.type == POINTEDTHING_NODE) { ClientMap &map = client->getEnv().getClientMap(); const NodeDefManager *nodedef = client->getNodeDefManager(); MapNode n = map.getNodeNoEx(pointed_old.node_undersurface); if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") { os << ", pointed: " << nodedef->get(n).name << ", param2: " << (u64) n.getParam2(); } } setStaticText(m_guitext2, utf8_to_wide(os.str()).c_str()); m_guitext2->setRelativePosition(core::rect<s32>(5, 5 + g_fontengine->getTextHeight(), screensize.X, 5 + g_fontengine->getTextHeight() * 2 )); } m_guitext2->setVisible(m_flags.show_debug); setStaticText(m_guitext_info, translate_string(m_infotext).c_str()); m_guitext_info->setVisible(m_flags.show_hud && g_menumgr.menuCount() == 0); static const float statustext_time_max = 1.5f; if (!m_statustext.empty()) { m_statustext_time += dtime; if (m_statustext_time >= statustext_time_max) { clearStatusText(); m_statustext_time = 0.0f; } } setStaticText(m_guitext_status, translate_string(m_statustext).c_str()); m_guitext_status->setVisible(!m_statustext.empty()); if (!m_statustext.empty()) { s32 status_width = m_guitext_status->getTextWidth(); s32 status_height = m_guitext_status->getTextHeight(); s32 status_y = screensize.Y - 150; s32 status_x = (screensize.X - status_width) / 2; m_guitext_status->setRelativePosition(core::rect<s32>(status_x , status_y - status_height, status_x + status_width, status_y)); // Fade out video::SColor final_color = m_statustext_initial_color; final_color.setAlpha(0); video::SColor fade_color = m_statustext_initial_color.getInterpolated_quadratic( m_statustext_initial_color, final_color, m_statustext_time / statustext_time_max); m_guitext_status->setOverrideColor(fade_color); m_guitext_status->enableOverrideColor(true); } }
void CharServerHandler::readPlayerData(Net::MessageIn &msg, Net::Character *character) { const Token &token = static_cast<LoginHandler*>(Net::getLoginHandler())->getToken(); LocalPlayer *tempPlayer = new LocalPlayer(msg.readInt32(), 0); tempPlayer->setGender(token.sex); character->data.mAttributes[EXP] = msg.readInt32(); character->data.mAttributes[MONEY] = msg.readInt32(); character->data.mStats[JOB].exp = msg.readInt32(); int temp = msg.readInt32(); character->data.mStats[JOB].base = temp; character->data.mStats[JOB].mod = temp; tempPlayer->setSprite(SPRITE_SHOE, msg.readInt16()); tempPlayer->setSprite(SPRITE_GLOVES, msg.readInt16()); tempPlayer->setSprite(SPRITE_CAPE, msg.readInt16()); tempPlayer->setSprite(SPRITE_MISC1, msg.readInt16()); msg.readInt32(); // option msg.readInt32(); // karma msg.readInt32(); // manner msg.skip(2); // unknown character->data.mAttributes[HP] = msg.readInt16(); character->data.mAttributes[MAX_HP] = msg.readInt16(); character->data.mAttributes[MP] = msg.readInt16(); character->data.mAttributes[MAX_MP] = msg.readInt16(); msg.readInt16(); // speed tempPlayer->setSubtype(msg.readInt16()); // class (used for race) int hairStyle = msg.readInt16(); Uint16 weapon = msg.readInt16(); tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true); character->data.mAttributes[LEVEL] = msg.readInt16(); msg.readInt16(); // skill point tempPlayer->setSprite(SPRITE_BOTTOMCLOTHES, msg.readInt16()); // head bottom tempPlayer->setSprite(SPRITE_SHIELD, msg.readInt16()); tempPlayer->setSprite(SPRITE_HAT, msg.readInt16()); // head option top tempPlayer->setSprite(SPRITE_TOPCLOTHES, msg.readInt16()); // head option mid tempPlayer->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(msg.readInt16())); tempPlayer->setSprite(SPRITE_MISC2, msg.readInt16()); tempPlayer->setName(msg.readString(24)); character->dummy = tempPlayer; for (int i = 0; i < 6; i++) character->data.mStats[i + STR].base = msg.readInt8(); character->slot = msg.readInt8(); // character slot msg.readInt8(); // unknown }
void Client::step(float dtime) { // Limit a bit if(dtime > 2.0) dtime = 2.0; if(m_ignore_damage_timer > dtime) m_ignore_damage_timer -= dtime; else m_ignore_damage_timer = 0.0; m_animation_time += dtime; if(m_animation_time > 60.0) m_animation_time -= 60.0; m_time_of_day_update_timer += dtime; ReceiveAll(); /* Packet counter */ { float &counter = m_packetcounter_timer; counter -= dtime; if(counter <= 0.0) { counter = 20.0; infostream << "Client packetcounter (" << m_packetcounter_timer << "):"<<std::endl; m_packetcounter.print(infostream); m_packetcounter.clear(); } } // UGLY hack to fix 2 second startup delay caused by non existent // server client startup synchronization in local server or singleplayer mode static bool initial_step = true; if (initial_step) { initial_step = false; } else if(m_state == LC_Created) { float &counter = m_connection_reinit_timer; counter -= dtime; if(counter <= 0.0) { counter = 2.0; LocalPlayer *myplayer = m_env.getLocalPlayer(); FATAL_ERROR_IF(myplayer == NULL, "Local player not found in environment."); sendInit(myplayer->getName()); } // Not connected, return return; } /* Do stuff if connected */ /* Run Map's timers and unload unused data */ const float map_timer_and_unload_dtime = 5.25; if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) { ScopeProfiler sp(g_profiler, "Client: map timer and unload"); std::vector<v3s16> deleted_blocks; m_env.getMap().timerUpdate(map_timer_and_unload_dtime, g_settings->getFloat("client_unload_unused_data_timeout"), g_settings->getS32("client_mapblock_limit"), &deleted_blocks); /* Send info to server NOTE: This loop is intentionally iterated the way it is. */ std::vector<v3s16>::iterator i = deleted_blocks.begin(); std::vector<v3s16> sendlist; for(;;) { if(sendlist.size() == 255 || i == deleted_blocks.end()) { if(sendlist.empty()) break; /* [0] u16 command [2] u8 count [3] v3s16 pos_0 [3+6] v3s16 pos_1 ... */ sendDeletedBlocks(sendlist); if(i == deleted_blocks.end()) break; sendlist.clear(); } sendlist.push_back(*i); ++i; } } /* Send pending messages on out chat queue */ if (!m_out_chat_queue.empty() && canSendChatMessage()) { sendChatMessage(m_out_chat_queue.front()); m_out_chat_queue.pop(); } /* Handle environment */ // Control local player (0ms) LocalPlayer *player = m_env.getLocalPlayer(); assert(player); player->applyControl(dtime, &m_env); // Step environment m_env.step(dtime); m_sound->step(dtime); /* Get events */ while (m_env.hasClientEnvEvents()) { ClientEnvEvent envEvent = m_env.getClientEnvEvent(); if (envEvent.type == CEE_PLAYER_DAMAGE) { if (m_ignore_damage_timer <= 0) { u8 damage = envEvent.player_damage.amount; if (envEvent.player_damage.send_to_server) sendDamage(damage); // Add to ClientEvent queue ClientEvent *event = new ClientEvent(); event->type = CE_PLAYER_DAMAGE; event->player_damage.amount = damage; m_client_event_queue.push(event); } } } /* Print some info */ float &counter = m_avg_rtt_timer; counter += dtime; if(counter >= 10) { counter = 0.0; // connectedAndInitialized() is true, peer exists. float avg_rtt = getRTT(); infostream << "Client: avg_rtt=" << avg_rtt << std::endl; } /* Send player position to server */ { float &counter = m_playerpos_send_timer; counter += dtime; if((m_state == LC_Ready) && (counter >= m_recommended_send_interval)) { counter = 0.0; sendPlayerPos(); } } /* Replace updated meshes */ { int num_processed_meshes = 0; while (!m_mesh_update_thread.m_queue_out.empty()) { num_processed_meshes++; MinimapMapblock *minimap_mapblock = NULL; bool do_mapper_update = true; MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx(); MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p); if (block) { // Delete the old mesh delete block->mesh; block->mesh = nullptr; if (r.mesh) { minimap_mapblock = r.mesh->moveMinimapMapblock(); if (minimap_mapblock == NULL) do_mapper_update = false; bool is_empty = true; for (int l = 0; l < MAX_TILE_LAYERS; l++) if (r.mesh->getMesh(l)->getMeshBufferCount() != 0) is_empty = false; if (is_empty) delete r.mesh; else // Replace with the new mesh block->mesh = r.mesh; } } else { delete r.mesh; } if (m_minimap && do_mapper_update) m_minimap->addBlock(r.p, minimap_mapblock); if (r.ack_block_to_server) { /* Acknowledge block [0] u8 count [1] v3s16 pos_0 */ sendGotBlocks(r.p); } } if (num_processed_meshes > 0) g_profiler->graphAdd("num_processed_meshes", num_processed_meshes); } /* Load fetched media */ if (m_media_downloader && m_media_downloader->isStarted()) { m_media_downloader->step(this); if (m_media_downloader->isDone()) { delete m_media_downloader; m_media_downloader = NULL; } } /* If the server didn't update the inventory in a while, revert the local inventory (so the player notices the lag problem and knows something is wrong). */ if(m_inventory_from_server) { float interval = 10.0; float count_before = floor(m_inventory_from_server_age / interval); m_inventory_from_server_age += dtime; float count_after = floor(m_inventory_from_server_age / interval); if(count_after != count_before) { // Do this every <interval> seconds after TOCLIENT_INVENTORY // Reset the locally changed inventory to the authoritative inventory LocalPlayer *player = m_env.getLocalPlayer(); player->inventory = *m_inventory_from_server; m_inventory_updated = true; } } /* Update positions of sounds attached to objects */ { for (auto &m_sounds_to_object : m_sounds_to_objects) { int client_id = m_sounds_to_object.first; u16 object_id = m_sounds_to_object.second; ClientActiveObject *cao = m_env.getActiveObject(object_id); if (!cao) continue; m_sound->updateSoundPosition(client_id, cao->getPosition()); } } /* Handle removed remotely initiated sounds */ m_removed_sounds_check_timer += dtime; if(m_removed_sounds_check_timer >= 2.32) { m_removed_sounds_check_timer = 0; // Find removed sounds and clear references to them std::vector<s32> removed_server_ids; for (std::unordered_map<s32, int>::iterator i = m_sounds_server_to_client.begin(); i != m_sounds_server_to_client.end();) { s32 server_id = i->first; int client_id = i->second; ++i; if(!m_sound->soundExists(client_id)) { m_sounds_server_to_client.erase(server_id); m_sounds_client_to_server.erase(client_id); m_sounds_to_objects.erase(client_id); removed_server_ids.push_back(server_id); } } // Sync to server if(!removed_server_ids.empty()) { sendRemovedSounds(removed_server_ids); } } m_mod_storage_save_timer -= dtime; if (m_mod_storage_save_timer <= 0.0f) { verbosestream << "Saving registered mod storages." << std::endl; m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval"); for (std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) { if (it->second->isModified()) { it->second->save(getModStoragePath()); } } } // Write server map if (m_localdb && m_localdb_save_interval.step(dtime, m_cache_save_interval)) { m_localdb->endSave(); m_localdb->beginSave(); } }
void Client::sendPlayerPos() { LocalPlayer *myplayer = m_env.getLocalPlayer(); if(myplayer == NULL) return; // Save bandwidth by only updating position when something changed if(myplayer->last_position == myplayer->getPosition() && myplayer->last_speed == myplayer->getSpeed() && myplayer->last_pitch == myplayer->getPitch() && myplayer->last_yaw == myplayer->getYaw() && myplayer->last_keyPressed == myplayer->keyPressed) return; myplayer->last_position = myplayer->getPosition(); myplayer->last_speed = myplayer->getSpeed(); myplayer->last_pitch = myplayer->getPitch(); myplayer->last_yaw = myplayer->getYaw(); myplayer->last_keyPressed = myplayer->keyPressed; u16 our_peer_id; { //MutexAutoLock lock(m_con_mutex); //bulk comment-out our_peer_id = m_con.GetPeerID(); } // Set peer id if not set already if(myplayer->peer_id == PEER_ID_INEXISTENT) myplayer->peer_id = our_peer_id; assert(myplayer->peer_id == our_peer_id); v3f pf = myplayer->getPosition(); v3f sf = myplayer->getSpeed(); s32 pitch = myplayer->getPitch() * 100; s32 yaw = myplayer->getYaw() * 100; u32 keyPressed = myplayer->keyPressed; v3s32 position(pf.X*100, pf.Y*100, pf.Z*100); v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100); /* Format: [0] v3s32 position*100 [12] v3s32 speed*100 [12+12] s32 pitch*100 [12+12+4] s32 yaw*100 [12+12+4+4] u32 keyPressed */ NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4); pkt << position << speed << pitch << yaw << keyPressed; Send(&pkt); }
void Game::dummyInit() { LocalPlayer *player = new LocalPlayer(this, "Kali", Data::wizard(WizardID::KALI), GREEN, Data::race("barbarians"), 60, 40); LocalPlayer *player2 = new LocalPlayer(this, "Antani", Data::wizard(WizardID::MERLIN), BLUE, Data::race("barbarians"), 60, 40); Army* army2 = new Army(player2, { new Hero(Data::unit("hero_dwarf")->as<HeroSpec>()), new RaceUnit(Data::unit("barbarian_spearmen")->as<RaceUnitSpec>()), new FantasticUnit(Data::unit("funit_magic_spirit")->as<SummonSpec>()), }); player2->add(army2); placeArmy(army2, Position(2, 2, ARCANUS)); players.push_back(player); players.push_back(player2); current = players.begin(); world->fill(TILE_WATER, ARCANUS); world->fill(TILE_WATER, MYRRAN); world->rect(TILE_GRASS, 3, 3, 10, 10, ARCANUS); world->rect(TILE_MOUNTAIN, 4, 4, 2, 2, ARCANUS); world->line(TILE_HILL, 4, 8, 11, true, ARCANUS); world->rect(TILE_GRASS, 1, 1, 6, 6, MYRRAN); world->line(TILE_MOUNTAIN, 6, 8, 5, false, MYRRAN); world->line(TILE_HILL, 5, 8, 6, true, MYRRAN); world->line(TILE_WATER, 2, 6, 6, true, ARCANUS); world->set(TILE_WATER, 4, 7, ARCANUS); world->set(TILE_HILL, 4,4, ARCANUS); world->set(TILE_DESERT, 8,8, ARCANUS); world->set(TILE_DESERT, 7,8, ARCANUS); world->set(TILE_DESERT, 9,8, ARCANUS); world->set(TILE_DESERT, 8,7, ARCANUS); world->set(TILE_DESERT, 8,9, ARCANUS); world->set(TILE_DESERT, 7,9, ARCANUS); world->set(TILE_DESERT, 9,9, ARCANUS); world->set(TILE_DESERT, 10,9, ARCANUS); world->get(7, 8, ARCANUS)->placeManaNode(new ManaNode(School::SORCERY, 0)); //WorldGenerator.generate(world, ARCANUS); //WorldGenerator.generate(world, MYRRAN); Army* a = new Army(player, { new FantasticUnit(Data::unit("funit_great_drake")->as<SummonSpec>()), new RaceUnit(Data::unit("barbarian_spearmen")->as<RaceUnitSpec>()), new RaceUnit(Data::unit("barbarian_swordsmen")->as<RaceUnitSpec>()), new RaceUnit(Data::unit("barbarian_bowmen")->as<RaceUnitSpec>()), new RaceUnit(Data::unit("barbarian_cavalry")->as<RaceUnitSpec>()), new FantasticUnit(Data::unit("funit_great_drake")->as<SummonSpec>()), new RaceUnit(Data::unit("barbarian_berserkers")->as<RaceUnitSpec>()), }); SpellCast cast = SpellCast(player, Spells::BLESS); a->get(0)->skills()->add(cast); //map.get(5, 5, ARCANUS).placeManaNode(mapMechanics.generateManaNode(world, 5, 5, ARCANUS)); //this.meldNode(a, 5, 5, ARCANUS); //map.get(5, 6, ARCANUS).placeManaNode(new ManaNode()); //map.get(6, 5, ARCANUS).placeManaNode(new ManaNode()); //map.get(6, 6, ARCANUS).placeManaNode(new ManaNode()); world->get(4, 3, ARCANUS)->placeResource(Resource::COAL); world->get(3, 4, ARCANUS)->placeResource(Resource::WILD_GAME); //map.rect(TILE_GRASS, 2, 2, 6, 3); //map.rect(TILE_GRASS, 8, 4, 1, 1); world->get(3,4,ARCANUS)->placeRoad(true); world->get(3,5,ARCANUS)->placeRoad(true); world->get(4,5,ARCANUS)->placeRoad(true); world->get(5,5,ARCANUS)->placeRoad(true); world->set(TILE_VOLCANO, 0, 0, ARCANUS); world->set(TILE_VOLCANO, 59, 0, ARCANUS); world->set(TILE_VOLCANO, 0, 39, ARCANUS); world->set(TILE_VOLCANO, 59, 39, ARCANUS); world->set(TILE_HILL, 1, 2, MYRRAN); player->fog()->setRect(0, 0, 60, 40, ARCANUS); player->fog()->setRect(0, 0, 60, 40, MYRRAN); player->setViewport(5, 5); player->book()->discoverSpell(Spells::BLESS); player->book()->discoverSpell(Spells::CORRUPTION); player->book()->discoverSpell(Spells::CHANGE_TERRAIN); player->book()->discoverSpell(Spells::RAISE_VOLCANO); player->book()->discoverSpell(Spells::GUARDIAN_SPIRIT); new LocalGame(this); placeArmy(a, Position(5, 6, ARCANUS)); placeArmy(new Army(player, {new FantasticUnit(Data::unit("funit_magic_spirit")->as<SummonSpec>()),new FantasticUnit(Data::unit("funit_great_drake")->as<SummonSpec>())}), Position(4, 3, ARCANUS)); placeArmy(new Army(player, {new FantasticUnit(Data::unit("funit_great_drake")->as<SummonSpec>()), new Hero(Data::unit("hero_dwarf")->as<HeroSpec>())}), Position(4, 8, ARCANUS)); City* florence = new City(player, "Florence", 4000, Position(3, 3, ARCANUS)); florence->addBuilding(Building::MAGE_FORTRESS); florence->addBuilding(Building::SMITHY); florence->addBuilding(Building::BUILDERS_HALL); florence->addBuilding(Building::BARRACKS); florence->addBuilding(Building::FIGHTERS_GUILD); florence->addBuilding(Building::SUMMONING_CIRCLE); florence->addBuilding(Building::ALCHEMISTS_GUILD); settleCity(florence); world->get(7,6,ARCANUS)->placePlace(new Place(PLACE_TOWER_OF_WIZARDRY, false)); world->get(8,6,ARCANUS)->placePlace(new Place(PLACE_CAVE, false)); world->calcSubTiles(); world->updateRoads(); init(); }
void Client::step(float dtime) { DSTACK(FUNCTION_NAME); // Limit a bit if(dtime > 2.0) dtime = 2.0; if(m_ignore_damage_timer > dtime) m_ignore_damage_timer -= dtime; else m_ignore_damage_timer = 0.0; m_animation_time += dtime; if(m_animation_time > 60.0) m_animation_time -= 60.0; m_time_of_day_update_timer += dtime; ReceiveAll(); /* Packet counter */ { float &counter = m_packetcounter_timer; counter -= dtime; if(counter <= 0.0) { counter = 20.0; infostream << "Client packetcounter (" << m_packetcounter_timer << "):"<<std::endl; m_packetcounter.print(infostream); m_packetcounter.clear(); } } // UGLY hack to fix 2 second startup delay caused by non existent // server client startup synchronization in local server or singleplayer mode static bool initial_step = true; if (initial_step) { initial_step = false; } else if(m_state == LC_Created) { float &counter = m_connection_reinit_timer; counter -= dtime; if(counter <= 0.0) { counter = 2.0; Player *myplayer = m_env.getLocalPlayer(); FATAL_ERROR_IF(myplayer == NULL, "Local player not found in environment."); // Send TOSERVER_INIT_LEGACY // [0] u16 TOSERVER_INIT_LEGACY // [2] u8 SER_FMT_VER_HIGHEST_READ // [3] u8[20] player_name // [23] u8[28] password (new in some version) // [51] u16 minimum supported network protocol version (added sometime) // [53] u16 maximum supported network protocol version (added later than the previous one) char pName[PLAYERNAME_SIZE]; char pPassword[PASSWORD_SIZE]; memset(pName, 0, PLAYERNAME_SIZE * sizeof(char)); memset(pPassword, 0, PASSWORD_SIZE * sizeof(char)); std::string hashed_password = translatePassword(myplayer->getName(), m_password); snprintf(pName, PLAYERNAME_SIZE, "%s", myplayer->getName()); snprintf(pPassword, PASSWORD_SIZE, "%s", hashed_password.c_str()); sendLegacyInit(pName, pPassword); if (LATEST_PROTOCOL_VERSION >= 25) sendInit(myplayer->getName()); } // Not connected, return return; } /* Do stuff if connected */ /* Run Map's timers and unload unused data */ const float map_timer_and_unload_dtime = 5.25; if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) { ScopeProfiler sp(g_profiler, "Client: map timer and unload"); std::vector<v3s16> deleted_blocks; m_env.getMap().timerUpdate(map_timer_and_unload_dtime, g_settings->getFloat("client_unload_unused_data_timeout"), g_settings->getS32("client_mapblock_limit"), &deleted_blocks); /* Send info to server NOTE: This loop is intentionally iterated the way it is. */ std::vector<v3s16>::iterator i = deleted_blocks.begin(); std::vector<v3s16> sendlist; for(;;) { if(sendlist.size() == 255 || i == deleted_blocks.end()) { if(sendlist.empty()) break; /* [0] u16 command [2] u8 count [3] v3s16 pos_0 [3+6] v3s16 pos_1 ... */ sendDeletedBlocks(sendlist); if(i == deleted_blocks.end()) break; sendlist.clear(); } sendlist.push_back(*i); ++i; } } /* Handle environment */ // Control local player (0ms) LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); player->applyControl(dtime); // Step environment m_env.step(dtime); /* Get events */ for(;;) { ClientEnvEvent event = m_env.getClientEvent(); if(event.type == CEE_NONE) { break; } else if(event.type == CEE_PLAYER_DAMAGE) { if(m_ignore_damage_timer <= 0) { u8 damage = event.player_damage.amount; if(event.player_damage.send_to_server) sendDamage(damage); // Add to ClientEvent queue ClientEvent event; event.type = CE_PLAYER_DAMAGE; event.player_damage.amount = damage; m_client_event_queue.push(event); } } else if(event.type == CEE_PLAYER_BREATH) { u16 breath = event.player_breath.amount; sendBreath(breath); } } /* Print some info */ float &counter = m_avg_rtt_timer; counter += dtime; if(counter >= 10) { counter = 0.0; // connectedAndInitialized() is true, peer exists. float avg_rtt = getRTT(); infostream << "Client: avg_rtt=" << avg_rtt << std::endl; } /* Send player position to server */ { float &counter = m_playerpos_send_timer; counter += dtime; if((m_state == LC_Ready) && (counter >= m_recommended_send_interval)) { counter = 0.0; sendPlayerPos(); } } /* Replace updated meshes */ { int num_processed_meshes = 0; while (!m_mesh_update_thread.m_queue_out.empty()) { num_processed_meshes++; MinimapMapblock *minimap_mapblock = NULL; bool do_mapper_update = true; MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx(); MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p); if (block) { // Delete the old mesh if (block->mesh != NULL) { delete block->mesh; block->mesh = NULL; } if (r.mesh) { minimap_mapblock = r.mesh->moveMinimapMapblock(); if (minimap_mapblock == NULL) do_mapper_update = false; } if (r.mesh && r.mesh->getMesh()->getMeshBufferCount() == 0) { delete r.mesh; } else { // Replace with the new mesh block->mesh = r.mesh; } } else { delete r.mesh; } if (do_mapper_update) m_mapper->addBlock(r.p, minimap_mapblock); if (r.ack_block_to_server) { /* Acknowledge block [0] u8 count [1] v3s16 pos_0 */ sendGotBlocks(r.p); } } if (num_processed_meshes > 0) g_profiler->graphAdd("num_processed_meshes", num_processed_meshes); } /* Load fetched media */ if (m_media_downloader && m_media_downloader->isStarted()) { m_media_downloader->step(this); if (m_media_downloader->isDone()) { received_media(); delete m_media_downloader; m_media_downloader = NULL; } } /* If the server didn't update the inventory in a while, revert the local inventory (so the player notices the lag problem and knows something is wrong). */ if(m_inventory_from_server) { float interval = 10.0; float count_before = floor(m_inventory_from_server_age / interval); m_inventory_from_server_age += dtime; float count_after = floor(m_inventory_from_server_age / interval); if(count_after != count_before) { // Do this every <interval> seconds after TOCLIENT_INVENTORY // Reset the locally changed inventory to the authoritative inventory Player *player = m_env.getLocalPlayer(); player->inventory = *m_inventory_from_server; m_inventory_updated = true; } } /* Update positions of sounds attached to objects */ { for(std::map<int, u16>::iterator i = m_sounds_to_objects.begin(); i != m_sounds_to_objects.end(); ++i) { int client_id = i->first; u16 object_id = i->second; ClientActiveObject *cao = m_env.getActiveObject(object_id); if(!cao) continue; v3f pos = cao->getPosition(); m_sound->updateSoundPosition(client_id, pos); } } /* Handle removed remotely initiated sounds */ m_removed_sounds_check_timer += dtime; if(m_removed_sounds_check_timer >= 2.32) { m_removed_sounds_check_timer = 0; // Find removed sounds and clear references to them std::vector<s32> removed_server_ids; for(std::map<s32, int>::iterator i = m_sounds_server_to_client.begin(); i != m_sounds_server_to_client.end();) { s32 server_id = i->first; int client_id = i->second; ++i; if(!m_sound->soundExists(client_id)) { m_sounds_server_to_client.erase(server_id); m_sounds_client_to_server.erase(client_id); m_sounds_to_objects.erase(client_id); removed_server_ids.push_back(server_id); } } // Sync to server if(!removed_server_ids.empty()) { sendRemovedSounds(removed_server_ids); } } // Write server map if (m_localdb && m_localdb_save_interval.step(dtime, m_cache_save_interval)) { m_localdb->endSave(); m_localdb->beginSave(); } }
void RadarRenderer::render(SceneRenderer& renderer, bool blank) { const int ox = renderer.getWindow().getOriginX(); const int oy = renderer.getWindow().getOriginY(); float opacity = renderer.getPanelOpacity(); if ((opacity < 1.0f) && (opacity > 0.0f)) { glScissor(ox + x - 2, oy + y - 2, w + 4, h + 4); glColor4f(0.0f, 0.0f, 0.0f, opacity); glRectf((float) x, (float) y, (float)(x + w), (float)(y + h)); } glScissor(ox + x, oy + y, w, h); LocalPlayer *myTank = LocalPlayer::getMyTank(); if (opacity == 1.0f) { // glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // glClear(GL_COLOR_BUFFER_BIT); } if (blank) return; // prepare transforms float worldSize = BZDB.eval(StateDatabase::BZDB_WORLDSIZE); float range = BZDB.eval("displayRadarRange") * worldSize; // when burrowed, limit radar range if (myTank && (myTank->getFlag() == Flags::Burrow) && (myTank->getPosition()[2] < 0.0f)) { #ifdef _MSC_VER range = min(range, worldSize / 4.0f); #else range = std::min(range, worldSize / 4.0f); #endif } glMatrixMode(GL_PROJECTION); glLoadIdentity(); const int xSize = renderer.getWindow().getWidth(); const int ySize = renderer.getWindow().getHeight(); const double xCenter = double(x) + 0.5 * double(w); const double yCenter = double(y) + 0.5 * double(h); const double xUnit = 2.0 * range / double(w); const double yUnit = 2.0 * range / double(h); glOrtho(-xCenter * xUnit, (xSize - xCenter) * xUnit, -yCenter * yUnit, (ySize - yCenter) * yUnit, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); OpenGLGState::resetState(); TextureManager &tm = TextureManager::instance(); int noiseTexture = tm.getTextureID( "noise" ); // if jammed then draw white noise. occasionally draw a good frame. if (jammed && bzfrand() > decay) { glColor3f(1.0,1.0,1.0); if (noiseTexture >= 0 && renderer.useQuality() > 0) { const int sequences = 10; static float np[] = { 0, 0, 1, 1, 1, 1, 0, 0, 0.5f, 0.5f, 1.5f, 1.5f, 1.5f, 1.5f, 0.5f, 0.5f, 0.25f, 0.25f, 1.25f, 1.25f, 1.25f, 1.25f, 0.25f, 0.25f, 0, 0.5f, 1, 1.5f, 1, 1.5f, 0, 0.5f, 0.5f, 0, 1.5f, 1, 1.4f, 1, 0.5f, 0, 0.75f, 0.75f, 1.75f, 1.75f, 1.75f, 1.75f, 0.75f, 0.75f, }; int noisePattern = 4 * int(floor(sequences * bzfrand())); glEnable(GL_TEXTURE_2D); tm.bind(noiseTexture); glBegin(GL_QUADS); glTexCoord2f(np[noisePattern+0],np[noisePattern+1]); glVertex2f(-range,-range); glTexCoord2f(np[noisePattern+2],np[noisePattern+1]); glVertex2f( range,-range); glTexCoord2f(np[noisePattern+2],np[noisePattern+3]); glVertex2f( range, range); glTexCoord2f(np[noisePattern+0],np[noisePattern+3]); glVertex2f(-range, range); glEnd(); glDisable(GL_TEXTURE_2D); } else if (noiseTexture >= 0 && BZDBCache::texture && renderer.useQuality() == 0) { glEnable(GL_TEXTURE_2D); tm.bind(noiseTexture); glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex2f(-range,-range); glTexCoord2f(1,0); glVertex2f( range,-range); glTexCoord2f(1,1); glVertex2f( range, range); glTexCoord2f(0,1); glVertex2f(-range, range); glEnd(); glDisable(GL_TEXTURE_2D); } if (decay > 0.015f) decay *= 0.5f; } else if (myTank) // only draw if there's a local player { // if decay is sufficiently small then boost it so it's more // likely a jammed radar will get a few good frames closely // spaced in time. value of 1 guarantees at least two good // frames in a row. if (decay <= 0.015f) decay = 1.0f; else decay *= 0.5f; // get size of pixel in model space (assumes radar is square) ps = 2.0f * range / GLfloat(w); // relative to my tank const LocalPlayer* myTank = LocalPlayer::getMyTank(); const float* pos = myTank->getPosition(); float angle = myTank->getAngle(); // draw the view angle blewow stuff // view frustum edges glColor3f(1.0f, 0.625f, 0.125f); const float fovx = renderer.getViewFrustum().getFOVx(); const float viewWidth = range * tanf(0.5f * fovx); glBegin(GL_LINE_STRIP); glVertex2f(-viewWidth, range); glVertex2f(0.0f, 0.0f); glVertex2f(viewWidth, range); glEnd(); glPushMatrix(); glRotatef(90.0f - angle * 180.0f / M_PI, 0.0f, 0.0f, 1.0f); glPushMatrix(); glTranslatef(-pos[0], -pos[1], 0.0f); // Redraw buildings makeList( renderer); // draw my shots int maxShots = world.getMaxShots(); int i; float muzzleHeight = BZDB.eval(StateDatabase::BZDB_MUZZLEHEIGHT); for (i = 0; i < maxShots; i++) { const ShotPath* shot = myTank->getShot(i); if (shot) { const float cs = colorScale(shot->getPosition()[2], muzzleHeight, BZDBCache::enhancedRadar); glColor3f(1.0f * cs, 1.0f * cs, 1.0f * cs); shot->radarRender(); } } //draw world weapon shots WorldPlayer *worldWeapons = World::getWorld()->getWorldWeapons(); maxShots = worldWeapons->getMaxShots(); for (i = 0; i < maxShots; i++) { const ShotPath* shot = worldWeapons->getShot(i); if (shot) { const float cs = colorScale(shot->getPosition()[2], muzzleHeight, BZDBCache::enhancedRadar); glColor3f(1.0f * cs, 1.0f * cs, 1.0f * cs); shot->radarRender(); } } // draw other tanks (and any flags on them) // note about flag drawing. each line segment is drawn twice // (once in each direction); this degrades the antialiasing // but on systems that don't do correct filtering of endpoints // not doing it makes (half) the endpoints jump wildly. const int curMaxPlayers = world.getCurMaxPlayers(); for (i = 0; i < curMaxPlayers; i++) { RemotePlayer* player = world.getPlayer(i); if (!player || !player->isAlive() || ((player->getFlag() == Flags::Stealth) && (myTank->getFlag() != Flags::Seer))) continue; GLfloat x = player->getPosition()[0]; GLfloat y = player->getPosition()[1]; GLfloat z = player->getPosition()[2]; if (player->getFlag() != Flags::Null) { glColor3fv(player->getFlag()->getColor()); drawFlagOnTank(x, y, z); } if (player->isPaused() || player->isNotResponding()) { const float dimfactor = 0.4f; const float *color = Team::getRadarColor(myTank->getFlag() == Flags::Colorblindness ? RogueTeam : player->getTeam()); float dimmedcolor[3]; dimmedcolor[0] = color[0] * dimfactor; dimmedcolor[1] = color[1] * dimfactor; dimmedcolor[2] = color[2] * dimfactor; glColor3fv(dimmedcolor); } else { glColor3fv(Team::getRadarColor(myTank->getFlag() == Flags::Colorblindness ? RogueTeam : player->getTeam())); } // If this tank is hunted flash it on the radar if (player->isHunted() && myTank->getFlag() != Flags::Colorblindness) { if (flashTank.isOn()) { if (!toggleTank) { float flashcolor[3]; flashcolor[0] = 0.0f; flashcolor[1] = 0.8f; flashcolor[2] = 0.9f; glColor3fv(flashcolor); } } else { toggleTank = !toggleTank; flashTank.setClock(0.2f); } } drawTank(x, y, z); } bool coloredShot = BZDB.isTrue("coloredradarshots"); // draw other tanks' shells maxShots = World::getWorld()->getMaxShots(); for (i = 0; i < curMaxPlayers; i++) { RemotePlayer* player = world.getPlayer(i); if (!player) continue; for (int j = 0; j < maxShots; j++) { const ShotPath* shot = player->getShot(j); if (shot && shot->getFlag() != Flags::InvisibleBullet) { const float *shotcolor; if (coloredShot) { if (myTank->getFlag() == Flags::Colorblindness) shotcolor = Team::getRadarColor(RogueTeam); else shotcolor = Team::getRadarColor(player->getTeam()); const float cs = colorScale(shot->getPosition()[2], muzzleHeight, BZDBCache::enhancedRadar); glColor3f(shotcolor[0] * cs, shotcolor[1] * cs, shotcolor[2] * cs); } else { glColor3f(1.0f, 1.0f, 1.0f); } shot->radarRender(); } } } // draw flags not on tanks. const int maxFlags = world.getMaxFlags(); const bool drawNormalFlags = BZDB.isTrue("displayRadarFlags"); for (i = 0; i < maxFlags; i++) { const Flag& flag = world.getFlag(i); // don't draw flags that don't exist or are on a tank if (flag.status == FlagNoExist || flag.status == FlagOnTank) continue; // don't draw normal flags if we aren't supposed to if (flag.type->flagTeam == NoTeam && !drawNormalFlags) continue; // Flags change color by height const float cs = colorScale(flag.position[2], muzzleHeight, BZDBCache::enhancedRadar); const float *flagcolor = flag.type->getColor(); glColor3f(flagcolor[0] * cs, flagcolor[1] * cs, flagcolor[2] * cs); drawFlag(flag.position[0], flag.position[1], flag.position[2]); } // draw antidote flag const float* antidotePos = LocalPlayer::getMyTank()->getAntidoteLocation(); if (antidotePos) { glColor3f(1.0f, 1.0f, 0.0f); drawFlag(antidotePos[0], antidotePos[1], antidotePos[2]); } // draw these markers above all others always centered glPopMatrix(); // north marker GLfloat ns = 0.05f * range, ny = 0.9f * range; glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_LINE_STRIP); glVertex2f(-ns, ny - ns); glVertex2f(-ns, ny + ns); glVertex2f(ns, ny - ns); glVertex2f(ns, ny + ns); glEnd(); // always up glPopMatrix(); // get size of pixel in model space (assumes radar is square) GLfloat ps = 2.0f * range / GLfloat(w); // forward tick glBegin(GL_LINES); glVertex2f(0.0f, range - ps); glVertex2f(0.0f, range - 4.0f * ps); glEnd(); // my tank glColor3f(1.0f, 1.0f, 1.0f); drawTank(0.0f, 0.0f, myTank->getPosition()[2]); // my flag if (myTank->getFlag() != Flags::Null) { glColor3fv(myTank->getFlag()->getColor()); drawFlagOnTank(0.0f, 0.0f, myTank->getPosition()[2]); } } // restore GL state glPopMatrix(); }