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); }
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 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); }
int LuaLocalPlayer::l_get_pos(lua_State *L) { LocalPlayer *player = getobject(L, 1); push_v3f(L, player->getPosition() / BS); return 1; }
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; // Check that an existing peer_id is the same as the connection's if (myplayer->peer_id != our_peer_id) return; MSGPACK_PACKET_INIT(TOSERVER_PLAYERPOS, 5); PACK(TOSERVER_PLAYERPOS_POSITION, myplayer->getPosition()); PACK(TOSERVER_PLAYERPOS_SPEED, myplayer->getSpeed()); PACK(TOSERVER_PLAYERPOS_PITCH, myplayer->getPitch()); PACK(TOSERVER_PLAYERPOS_YAW, myplayer->getYaw()); PACK(TOSERVER_PLAYERPOS_KEY_PRESSED, myplayer->keyPressed); // Send as unreliable Send(0, buffer, false); }
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 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(); }
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 ClientEnvironment::step(float dtime) { DSTACK(FUNCTION_NAME); /* Step time of day */ stepTimeOfDay(dtime); // Get some settings bool fly_allowed = m_client->checkLocalPrivilege("fly"); bool free_move = fly_allowed && g_settings->getBool("free_move"); // Get local player LocalPlayer *lplayer = getLocalPlayer(); assert(lplayer); // collision info queue std::vector<CollisionInfo> player_collisions; /* Get the speed the player is going */ bool is_climbing = lplayer->is_climbing; f32 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 = 1; if(player_speed > 0.001) 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 */ { // Apply physics if(!free_move && !is_climbing) { // Gravity v3f speed = lplayer->getSpeed(); if(!lplayer->in_liquid) speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2; // Liquid floating / sinking if(lplayer->in_liquid && !lplayer->swimming_vertical) speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2; // Liquid resistance if(lplayer->in_liquid_stable || lplayer->in_liquid) { // How much the node's viscosity blocks movement, ranges between 0 and 1 // Should match the scale at which viscosity increase affects other liquid attributes const f32 viscosity_factor = 0.3; v3f d_wanted = -speed / lplayer->movement_liquid_fluidity; f32 dl = d_wanted.getLength(); if(dl > lplayer->movement_liquid_fluidity_smooth) dl = lplayer->movement_liquid_fluidity_smooth; dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor); v3f d = d_wanted.normalize() * dl; speed += d; } lplayer->setSpeed(speed); } /* Move the lplayer. This also does collision detection. */ lplayer->move(dtime_part, this, position_max_increment, &player_collisions); } } while(dtime_downcount > 0.001); //std::cout<<"Looped "<<loopcount<<" times."<<std::endl; for(std::vector<CollisionInfo>::iterator i = player_collisions.begin(); i != player_collisions.end(); ++i) { CollisionInfo &info = *i; v3f speed_diff = info.new_speed - info.old_speed;; // Handle only fall damage // (because otherwise walking against something in fast_move kills you) if(speed_diff.Y < 0 || info.old_speed.Y >= 0) continue; // Get rid of other components speed_diff.X = 0; speed_diff.Z = 0; f32 pre_factor = 1; // 1 hp per node/s f32 tolerance = BS*14; // 5 without damage f32 post_factor = 1; // 1 hp per node/s if(info.type == COLLISION_NODE) { const ContentFeatures &f = m_client->ndef()-> get(m_map->getNodeNoEx(info.node_p)); // Determine fall damage multiplier int addp = itemgroup_get(f.groups, "fall_damage_add_percent"); pre_factor = 1.0 + (float)addp/100.0; } float speed = pre_factor * speed_diff.getLength(); if(speed > tolerance) { f32 damage_f = (speed - tolerance)/BS * post_factor; u16 damage = (u16)(damage_f+0.5); if(damage != 0){ damageLocalPlayer(damage, true); MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage"); m_client->event()->put(e); } } } /* A quick draft of lava damage */ if(m_lava_hurt_interval.step(dtime, 1.0)) { v3f pf = lplayer->getPosition(); // Feet, middle and head v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS); MapNode n1 = m_map->getNodeNoEx(p1); v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS); MapNode n2 = m_map->getNodeNoEx(p2); v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS); MapNode n3 = m_map->getNodeNoEx(p3); u32 damage_per_second = 0; damage_per_second = MYMAX(damage_per_second, m_client->ndef()->get(n1).damage_per_second); damage_per_second = MYMAX(damage_per_second, m_client->ndef()->get(n2).damage_per_second); damage_per_second = MYMAX(damage_per_second, m_client->ndef()->get(n3).damage_per_second); if(damage_per_second != 0) { damageLocalPlayer(damage_per_second, true); } } // Protocol v29 make this behaviour obsolete if (getGameDef()->getProtoVersion() < 29) { /* Drowning */ if (m_drowning_interval.step(dtime, 2.0)) { v3f pf = lplayer->getPosition(); // head v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS); MapNode n = m_map->getNodeNoEx(p); ContentFeatures c = m_client->ndef()->get(n); u8 drowning_damage = c.drowning; if (drowning_damage > 0 && lplayer->hp > 0) { u16 breath = lplayer->getBreath(); if (breath > 10) { breath = 11; } if (breath > 0) { breath -= 1; } lplayer->setBreath(breath); updateLocalPlayerBreath(breath); } if (lplayer->getBreath() == 0 && drowning_damage > 0) { damageLocalPlayer(drowning_damage, true); } } if (m_breathing_interval.step(dtime, 0.5)) { v3f pf = lplayer->getPosition(); // head v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS); MapNode n = m_map->getNodeNoEx(p); ContentFeatures c = m_client->ndef()->get(n); if (!lplayer->hp) { lplayer->setBreath(11); } else if (c.drowning == 0) { u16 breath = lplayer->getBreath(); if (breath <= 10) { breath += 1; lplayer->setBreath(breath); updateLocalPlayerBreath(breath); } } } } // Update lighting on local player (used for wield item) u32 day_night_ratio = getDayNightRatio(); { // Get node at head // On InvalidPositionException, use this as default // (day: LIGHT_SUN, night: 0) MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0); v3s16 p = lplayer->getLightPosition(); node_at_lplayer = m_map->getNodeNoEx(p); u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef()); final_color_blend(&lplayer->light_color, light, day_night_ratio); } /* Step active objects and update lighting of them */ g_profiler->avg("CEnv: num of objects", m_active_objects.size()); bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21); for (UNORDERED_MAP<u16, ClientActiveObject*>::iterator i = m_active_objects.begin(); i != m_active_objects.end(); ++i) { ClientActiveObject* obj = i->second; // Step object obj->step(dtime, this); if(update_lighting) { // Update lighting u8 light = 0; bool pos_ok; // Get node at head v3s16 p = obj->getLightPosition(); MapNode n = m_map->getNodeNoEx(p, &pos_ok); if (pos_ok) light = n.getLightBlend(day_night_ratio, m_client->ndef()); else light = blend_light(day_night_ratio, LIGHT_SUN, 0); obj->updateLight(light); } } /* Step and handle simple objects */ g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size()); for(std::vector<ClientSimpleObject*>::iterator i = m_simple_objects.begin(); i != m_simple_objects.end();) { std::vector<ClientSimpleObject*>::iterator cur = i; ClientSimpleObject *simple = *cur; simple->step(dtime); if(simple->m_to_be_removed) { delete simple; i = m_simple_objects.erase(cur); } else { ++i; } } }