]> git.localhorst.tv Git - blank.git/blob - src/client/client.cpp
ba9fcc9bdfb3c9b9e742deb60d1c7d0dd51f46a5
[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())
50 , interface(
51         master.GetInterfaceConf(),
52         master.GetEnv(),
53         world,
54         world.AddPlayer(master.GetInterfaceConf().player_name, player_id)
55 )
56 , chunk_renderer(*interface.GetPlayer().chunks) {
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.Update(dt);
103
104         Entity &player = *interface.GetPlayer().entity;
105
106         master.GetClient().SendPlayerUpdate(player);
107
108         glm::mat4 trans = player.Transform(player.ChunkCoords());
109         glm::vec3 dir(trans * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));
110         glm::vec3 up(trans * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f));
111         master.GetEnv().audio.Position(player.Position());
112         master.GetEnv().audio.Velocity(player.Velocity());
113         master.GetEnv().audio.Orientation(dir, up);
114 }
115
116 void InteractiveState::Render(Viewport &viewport) {
117         Entity &player = *interface.GetPlayer().entity;
118         viewport.WorldPosition(player.Transform(player.ChunkCoords()));
119         chunk_renderer.Render(viewport);
120         world.Render(viewport);
121         interface.Render(viewport);
122 }
123
124
125 MasterState::MasterState(
126         Environment &env,
127         const World::Config &wc,
128         const Interface::Config &ic,
129         const Client::Config &cc)
130 : env(env)
131 , world_conf(wc)
132 , intf_conf(ic)
133 , client_conf(cc)
134 , state()
135 , client(cc)
136 , init_state(*this)
137 , login_packet(-1) {
138         client.GetConnection().SetHandler(this);
139 }
140
141 void MasterState::Quit() {
142         if (!client.GetConnection().Closed()) {
143                 client.SendPart();
144         }
145         env.state.PopUntil(this);
146 }
147
148
149 void MasterState::OnEnter() {
150         login_packet = client.SendLogin(intf_conf.player_name);
151         env.state.Push(&init_state);
152 }
153
154
155 void MasterState::Handle(const SDL_Event &event) {
156
157 }
158
159
160 void MasterState::Update(int dt) {
161         client.Handle();
162         client.Update(dt);
163 }
164
165
166 void MasterState::Render(Viewport &) {
167
168 }
169
170
171 void MasterState::OnPacketLost(uint16_t id) {
172         if (id == login_packet) {
173                 login_packet = client.SendLogin(intf_conf.player_name);
174         }
175 }
176
177 void MasterState::OnTimeout() {
178         if (client.GetConnection().Closed()) {
179                 // TODO: push disconnected message
180                 cout << "connection timed out" << endl;
181                 Quit();
182         }
183 }
184
185 void MasterState::On(const Packet::Join &pack) {
186         pack.ReadWorldName(world_conf.name);
187
188         if (state) {
189                 // changing worlds
190                 cout << "server changing worlds to \"" << world_conf.name << '"' << endl;
191         } else {
192                 // joining game
193                 cout << "joined game \"" << world_conf.name << '"' << endl;
194         }
195
196         uint32_t player_id;
197         pack.ReadPlayerID(player_id);
198         state.reset(new InteractiveState(*this, player_id));
199
200         pack.ReadPlayer(*state->GetInterface().GetPlayer().entity);
201
202         env.state.PopAfter(this);
203         env.state.Push(state.get());
204 }
205
206 void MasterState::On(const Packet::Part &pack) {
207         if (state) {
208                 // kicked
209                 cout << "kicked by server" << endl;
210         } else {
211                 // join refused
212                 cout << "login refused by server" << endl;
213         }
214         Quit();
215 }
216
217 void MasterState::On(const Packet::SpawnEntity &pack) {
218         if (!state) {
219                 cout << "got entity spawn before world was created" << endl;
220                 Quit();
221                 return;
222         }
223         uint32_t entity_id;
224         pack.ReadEntityID(entity_id);
225         Entity *entity = state->GetWorld().AddEntity(entity_id);
226         if (!entity) {
227                 cout << "entity ID inconsistency" << endl;
228                 Quit();
229                 return;
230         }
231         pack.ReadEntity(*entity);
232         cout << "spawned entity " << entity->Name() << " at " << entity->AbsolutePosition() << endl;
233 }
234
235 void MasterState::On(const Packet::DespawnEntity &pack) {
236         if (!state) {
237                 cout << "got entity despawn before world was created" << endl;
238                 Quit();
239                 return;
240         }
241         uint32_t entity_id;
242         pack.ReadEntityID(entity_id);
243         for (Entity &entity : state->GetWorld().Entities()) {
244                 if (entity.ID() == entity_id) {
245                         entity.Kill();
246                         cout << "despawned entity " << entity.Name() << " at " << entity.AbsolutePosition() << endl;
247                         return;
248                 }
249         }
250 }
251
252 void MasterState::On(const Packet::EntityUpdate &pack) {
253         if (!state) {
254                 cout << "got entity update before world was created" << endl;
255                 Quit();
256                 return;
257         }
258
259         auto world_iter = state->GetWorld().Entities().begin();
260         auto world_end = state->GetWorld().Entities().end();
261
262         uint32_t count = 0;
263         pack.ReadEntityCount(count);
264
265         for (uint32_t i = 0; i < count; ++i) {
266                 uint32_t entity_id = 0;
267                 pack.ReadEntityID(entity_id, i);
268
269                 while (world_iter != world_end && world_iter->ID() < entity_id) {
270                         ++world_iter;
271                 }
272                 if (world_iter == world_end) {
273                         // nothing can be done from here
274                         return;
275                 }
276                 if (world_iter->ID() == entity_id) {
277                         pack.ReadEntity(*world_iter, i);
278                 }
279         }
280 }
281
282 }
283 }