X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fclient%2Fclient.cpp;h=8a3d1c89c98e36a17c645852172f3d92d9cfb0eb;hb=cf5ce8220483bb062740eeaedde6474928fd5e0e;hp=9c87549a3e27094c1ad8ffc8cc47b3143c550b53;hpb=c6ca9d21e45af5ea7caeec722a9b59fdf3aa3b24;p=blank.git diff --git a/src/client/client.cpp b/src/client/client.cpp index 9c87549..8a3d1c8 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -5,8 +5,12 @@ #include "../app/Environment.hpp" #include "../app/init.hpp" #include "../app/TextureIndex.hpp" +#include "../model/CompositeModel.hpp" #include +#include + +using namespace std; namespace blank { @@ -43,20 +47,24 @@ InteractiveState::InteractiveState(MasterState &master, uint32_t player_id) : master(master) , block_types() , save(master.GetEnv().config.GetWorldPath(master.GetWorldConf().name, master.GetClientConf().host)) -, world(block_types, master.GetWorldConf(), save) -, chunk_renderer(world, master.GetWorldConf().load.load_dist) +, world(block_types, master.GetWorldConf()) , interface( master.GetInterfaceConf(), master.GetEnv(), world, - *world.AddPlayer(master.GetInterfaceConf().player_name, player_id) -) { + world.AddPlayer(master.GetInterfaceConf().player_name, player_id) +) +, chunk_renderer(*interface.GetPlayer().chunks) +, skeletons() +, update_timer(16) { TextureIndex tex_index; master.GetEnv().loader.LoadBlockTypes("default", block_types, tex_index); chunk_renderer.LoadTextures(master.GetEnv().loader, tex_index); chunk_renderer.FogDensity(master.GetWorldConf().fog_density); + skeletons.Load(); // TODO: better solution for initializing HUD interface.SelectNext(); + update_timer.Start(); } void InteractiveState::OnEnter() { @@ -96,21 +104,27 @@ void InteractiveState::Update(int dt) { interface.Update(dt); world.Update(dt); - chunk_renderer.Rebase(interface.Player().ChunkCoords()); chunk_renderer.Update(dt); - master.GetClient().SendPlayerUpdate(interface.Player()); + update_timer.Update(dt); + + Entity &player = *interface.GetPlayer().entity; + + if (update_timer.Hit()) { + master.GetClient().SendPlayerUpdate(player); + } - glm::mat4 trans = interface.Player().Transform(interface.Player().ChunkCoords()); + glm::mat4 trans = player.Transform(player.ChunkCoords()); glm::vec3 dir(trans * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f)); glm::vec3 up(trans * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f)); - master.GetEnv().audio.Position(interface.Player().Position()); - master.GetEnv().audio.Velocity(interface.Player().Velocity()); + master.GetEnv().audio.Position(player.Position()); + master.GetEnv().audio.Velocity(player.Velocity()); master.GetEnv().audio.Orientation(dir, up); } void InteractiveState::Render(Viewport &viewport) { - viewport.WorldPosition(interface.Player().Transform(interface.Player().ChunkCoords())); + Entity &player = *interface.GetPlayer().entity; + viewport.WorldPosition(player.Transform(player.ChunkCoords())); chunk_renderer.Render(viewport); world.Render(viewport); interface.Render(viewport); @@ -129,11 +143,17 @@ MasterState::MasterState( , state() , client(cc) , init_state(*this) -, login_packet(-1) { +, login_packet(-1) +, update_status() +, update_timer(16) { client.GetConnection().SetHandler(this); + update_timer.Start(); } void MasterState::Quit() { + if (!client.GetConnection().Closed()) { + client.SendPart(); + } env.state.PopUntil(this); } @@ -150,6 +170,7 @@ void MasterState::Handle(const SDL_Event &event) { void MasterState::Update(int dt) { + update_timer.Update(dt); client.Handle(); client.Update(dt); } @@ -160,7 +181,7 @@ void MasterState::Render(Viewport &) { } -void MasterState::OnPacketLost(std::uint16_t id) { +void MasterState::OnPacketLost(uint16_t id) { if (id == login_packet) { login_packet = client.SendLogin(intf_conf.player_name); } @@ -168,8 +189,9 @@ void MasterState::OnPacketLost(std::uint16_t id) { void MasterState::OnTimeout() { if (client.GetConnection().Closed()) { - Quit(); // TODO: push disconnected message + cout << "connection timed out" << endl; + Quit(); } } @@ -178,17 +200,19 @@ void MasterState::On(const Packet::Join &pack) { if (state) { // changing worlds - std::cout << "server changing worlds" << std::endl; + cout << "server changing worlds to \"" << world_conf.name << '"' << endl; } else { // joining game - std::cout << "joined game" << std::endl; + cout << "joined game \"" << world_conf.name << '"' << endl; + // server received our login + login_packet = -1; } uint32_t player_id; pack.ReadPlayerID(player_id); state.reset(new InteractiveState(*this, player_id)); - pack.ReadPlayer(state->GetInterface().Player()); + pack.ReadPlayerState(state->GetInterface().GetPlayer().entity->GetState()); env.state.PopAfter(this); env.state.Push(state.get()); @@ -197,13 +221,106 @@ void MasterState::On(const Packet::Join &pack) { void MasterState::On(const Packet::Part &pack) { if (state) { // kicked - std::cout << "kicked by server" << std::endl; + cout << "kicked by server" << endl; } else { // join refused - std::cout << "login refused by server" << std::endl; + cout << "login refused by server" << endl; } Quit(); } +void MasterState::On(const Packet::SpawnEntity &pack) { + if (!state) { + cout << "got entity spawn before world was created" << endl; + Quit(); + return; + } + uint32_t entity_id; + pack.ReadEntityID(entity_id); + Entity &entity = state->GetWorld().ForceAddEntity(entity_id); + UpdateEntity(entity_id, pack.Seq()); + pack.ReadEntity(entity); + uint32_t skel_id; + pack.ReadSkeletonID(skel_id); + CompositeModel *skel = state->GetSkeletons().ByID(skel_id); + if (skel) { + skel->Instantiate(entity.GetModel()); + } + cout << "spawned entity " << entity.Name() << " at " << entity.AbsolutePosition() << endl; +} + +void MasterState::On(const Packet::DespawnEntity &pack) { + if (!state) { + cout << "got entity despawn before world was created" << endl; + Quit(); + return; + } + uint32_t entity_id; + pack.ReadEntityID(entity_id); + ClearEntity(entity_id); + for (Entity &entity : state->GetWorld().Entities()) { + if (entity.ID() == entity_id) { + entity.Kill(); + cout << "despawned entity " << entity.Name() << " at " << entity.AbsolutePosition() << endl; + return; + } + } +} + +void MasterState::On(const Packet::EntityUpdate &pack) { + if (!state) { + cout << "got entity update before world was created" << endl; + Quit(); + return; + } + + auto world_iter = state->GetWorld().Entities().begin(); + auto world_end = state->GetWorld().Entities().end(); + + uint32_t count = 0; + pack.ReadEntityCount(count); + + for (uint32_t i = 0; i < count; ++i) { + uint32_t entity_id = 0; + pack.ReadEntityID(entity_id, i); + + while (world_iter != world_end && world_iter->ID() < entity_id) { + ++world_iter; + } + if (world_iter == world_end) { + // nothing can be done from here + return; + } + if (world_iter->ID() == entity_id) { + if (UpdateEntity(entity_id, pack.Seq())) { + pack.ReadEntityState(world_iter->GetState(), i); + } + } + } +} + +bool MasterState::UpdateEntity(uint32_t entity_id, uint16_t seq) { + auto entry = update_status.find(entity_id); + if (entry == update_status.end()) { + update_status.emplace(entity_id, UpdateStatus{ seq, update_timer.Elapsed() }); + return true; + } + + int pack_diff = int16_t(seq) - int16_t(entry->second.last_packet); + int time_diff = update_timer.Elapsed() - entry->second.last_update; + entry->second.last_update = update_timer.Elapsed(); + + if (pack_diff > 0 || time_diff > 1500) { + entry->second.last_packet = seq; + return true; + } else { + return false; + } +} + +void MasterState::ClearEntity(uint32_t entity_id) { + update_status.erase(entity_id); +} + } }