]> git.localhorst.tv Git - blank.git/blob - src/client/client.cpp
sync entities with clients
[blank.git] / src / client / client.cpp
1 #include "InitialState.hpp"
2 #include "InteractiveState.hpp"
3 #include "MasterState.hpp"
4
5 #include "../app/Environment.hpp"
6 #include "../app/init.hpp"
7 #include "../app/TextureIndex.hpp"
8
9 #include <iostream>
10 #include <glm/gtx/io.hpp>
11
12 using namespace std;
13
14
15 namespace blank {
16 namespace client {
17
18 InitialState::InitialState(MasterState &master)
19 : master(master)
20 , message() {
21         message.Position(glm::vec3(0.0f), Gravity::CENTER);
22         message.Set(master.GetEnv().assets.large_ui_font, "logging in");
23 }
24
25 void InitialState::OnEnter() {
26
27 }
28
29 void InitialState::Handle(const SDL_Event &evt) {
30         if (evt.type == SDL_QUIT) {
31                 master.Quit();
32         }
33 }
34
35 void InitialState::Update(int dt) {
36         master.Update(dt);
37 }
38
39 void InitialState::Render(Viewport &viewport) {
40         message.Render(viewport);
41 }
42
43
44 // TODO: this clutter is a giant mess
45 InteractiveState::InteractiveState(MasterState &master, uint32_t player_id)
46 : master(master)
47 , block_types()
48 , save(master.GetEnv().config.GetWorldPath(master.GetWorldConf().name, master.GetClientConf().host))
49 , world(block_types, master.GetWorldConf(), save)
50 , chunk_renderer(world, master.GetWorldConf().load.load_dist)
51 , interface(
52         master.GetInterfaceConf(),
53         master.GetEnv(),
54         world,
55         *world.AddPlayer(master.GetInterfaceConf().player_name, player_id)
56 ) {
57         TextureIndex tex_index;
58         master.GetEnv().loader.LoadBlockTypes("default", block_types, tex_index);
59         chunk_renderer.LoadTextures(master.GetEnv().loader, tex_index);
60         chunk_renderer.FogDensity(master.GetWorldConf().fog_density);
61         // TODO: better solution for initializing HUD
62         interface.SelectNext();
63 }
64
65 void InteractiveState::OnEnter() {
66         master.GetEnv().window.GrabMouse();
67 }
68
69 void InteractiveState::Handle(const SDL_Event &event) {
70         switch (event.type) {
71                 case SDL_KEYDOWN:
72                         interface.HandlePress(event.key);
73                         break;
74                 case SDL_KEYUP:
75                         interface.HandleRelease(event.key);
76                         break;
77                 case SDL_MOUSEBUTTONDOWN:
78                         interface.HandlePress(event.button);
79                         break;
80                 case SDL_MOUSEBUTTONUP:
81                         interface.HandleRelease(event.button);
82                         break;
83                 case SDL_MOUSEMOTION:
84                         interface.Handle(event.motion);
85                         break;
86                 case SDL_MOUSEWHEEL:
87                         interface.Handle(event.wheel);
88                         break;
89                 case SDL_QUIT:
90                         master.Quit();
91                         break;
92                 default:
93                         break;
94         }
95 }
96
97 void InteractiveState::Update(int dt) {
98         master.Update(dt);
99
100         interface.Update(dt);
101         world.Update(dt);
102         chunk_renderer.Rebase(interface.Player().ChunkCoords());
103         chunk_renderer.Update(dt);
104
105         master.GetClient().SendPlayerUpdate(interface.Player());
106
107         glm::mat4 trans = interface.Player().Transform(interface.Player().ChunkCoords());
108         glm::vec3 dir(trans * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));
109         glm::vec3 up(trans * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f));
110         master.GetEnv().audio.Position(interface.Player().Position());
111         master.GetEnv().audio.Velocity(interface.Player().Velocity());
112         master.GetEnv().audio.Orientation(dir, up);
113 }
114
115 void InteractiveState::Render(Viewport &viewport) {
116         viewport.WorldPosition(interface.Player().Transform(interface.Player().ChunkCoords()));
117         chunk_renderer.Render(viewport);
118         world.Render(viewport);
119         interface.Render(viewport);
120 }
121
122
123 MasterState::MasterState(
124         Environment &env,
125         const World::Config &wc,
126         const Interface::Config &ic,
127         const Client::Config &cc)
128 : env(env)
129 , world_conf(wc)
130 , intf_conf(ic)
131 , client_conf(cc)
132 , state()
133 , client(cc)
134 , init_state(*this)
135 , login_packet(-1) {
136         client.GetConnection().SetHandler(this);
137 }
138
139 void MasterState::Quit() {
140         if (!client.GetConnection().Closed()) {
141                 client.SendPart();
142         }
143         env.state.PopUntil(this);
144 }
145
146
147 void MasterState::OnEnter() {
148         login_packet = client.SendLogin(intf_conf.player_name);
149         env.state.Push(&init_state);
150 }
151
152
153 void MasterState::Handle(const SDL_Event &event) {
154
155 }
156
157
158 void MasterState::Update(int dt) {
159         client.Handle();
160         client.Update(dt);
161 }
162
163
164 void MasterState::Render(Viewport &) {
165
166 }
167
168
169 void MasterState::OnPacketLost(uint16_t id) {
170         if (id == login_packet) {
171                 login_packet = client.SendLogin(intf_conf.player_name);
172         }
173 }
174
175 void MasterState::OnTimeout() {
176         if (client.GetConnection().Closed()) {
177                 // TODO: push disconnected message
178                 cout << "connection timed out" << endl;
179                 Quit();
180         }
181 }
182
183 void MasterState::On(const Packet::Join &pack) {
184         pack.ReadWorldName(world_conf.name);
185
186         if (state) {
187                 // changing worlds
188                 cout << "server changing worlds to \"" << world_conf.name << '"' << endl;
189         } else {
190                 // joining game
191                 cout << "joined game \"" << world_conf.name << '"' << endl;
192         }
193
194         uint32_t player_id;
195         pack.ReadPlayerID(player_id);
196         state.reset(new InteractiveState(*this, player_id));
197
198         pack.ReadPlayer(state->GetInterface().Player());
199
200         env.state.PopAfter(this);
201         env.state.Push(state.get());
202 }
203
204 void MasterState::On(const Packet::Part &pack) {
205         if (state) {
206                 // kicked
207                 cout << "kicked by server" << endl;
208         } else {
209                 // join refused
210                 cout << "login refused by server" << endl;
211         }
212         Quit();
213 }
214
215 void MasterState::On(const Packet::SpawnEntity &pack) {
216         if (!state) {
217                 cout << "got entity spawn before world was created" << endl;
218                 Quit();
219                 return;
220         }
221         uint32_t entity_id;
222         pack.ReadEntityID(entity_id);
223         Entity *entity = state->GetWorld().AddEntity(entity_id);
224         if (!entity) {
225                 cout << "entity ID inconsistency" << endl;
226                 Quit();
227                 return;
228         }
229         pack.ReadEntity(*entity);
230         cout << "spawned entity " << entity->Name() << " at " << entity->AbsolutePosition() << endl;
231 }
232
233 void MasterState::On(const Packet::DespawnEntity &pack) {
234         if (!state) {
235                 cout << "got entity despawn before world was created" << endl;
236                 Quit();
237                 return;
238         }
239         uint32_t entity_id;
240         pack.ReadEntityID(entity_id);
241         for (Entity &entity : state->GetWorld().Entities()) {
242                 if (entity.ID() == entity_id) {
243                         entity.Kill();
244                         cout << "despawned entity " << entity.Name() << " at " << entity.AbsolutePosition() << endl;
245                         return;
246                 }
247         }
248 }
249
250 void MasterState::On(const Packet::EntityUpdate &pack) {
251         if (!state) {
252                 cout << "got entity update before world was created" << endl;
253                 Quit();
254                 return;
255         }
256
257         auto world_iter = state->GetWorld().Entities().begin();
258         auto world_end = state->GetWorld().Entities().end();
259
260         uint32_t count = 0;
261         pack.ReadEntityCount(count);
262
263         for (uint32_t i = 0; i < count; ++i) {
264                 uint32_t entity_id = 0;
265                 pack.ReadEntityID(entity_id, i);
266
267                 while (world_iter != world_end && world_iter->ID() < entity_id) {
268                         ++world_iter;
269                 }
270                 if (world_iter == world_end) {
271                         // nothing can be done from here
272                         return;
273                 }
274                 if (world_iter->ID() == entity_id) {
275                         pack.ReadEntity(*world_iter, i);
276                 }
277         }
278 }
279
280 }
281 }