1 #define _GNU_SOURCE // don't worry, GNU extensions are only used when available
2 #include <dragonstd/flag.h>
8 #include "client/client.h"
9 #include "client/client_auth.h"
10 #include "client/client_inventory.h"
11 #include "client/client_player.h"
12 #include "client/client_terrain.h"
13 #include "client/debug_menu.h"
14 #include "client/game.h"
15 #include "client/input.h"
17 #include "interrupt.h"
21 DragonnetPeer *client;
26 static bool on_recv(__attribute__((unused)) DragonnetPeer *peer, DragonnetTypeId type, __attribute__((unused)) void *pkt)
29 pthread_mutex_lock(&client_auth.mtx);
31 // this code exists to stop malicious or malfunctioning packets
32 switch (client_auth.state) {
33 // the server shouldn't send anything during auth preparation, drop it
38 // only the auth packet is allowed before auth is finished
40 allowed = type == DRAGONNET_TYPE_ToClientAuth;
43 // don't process auth packets when auth is already finished
45 allowed = type != DRAGONNET_TYPE_ToClientAuth;
50 It is important that the auth state does not change to until the packet is
53 However, the only state change done by other threads is AUTH_INIT -> AUTH_WAIT,
54 which is not problematic since packets that are received during AUTH_INIT
55 are not processed, they are always dropped.
57 Therefore the mutex can be unlocked at this point.
59 pthread_mutex_unlock(&client_auth.mtx);
63 static void on_disconnect(__attribute__((unused)) DragonnetPeer *peer)
66 // don't free the connection before all other client components have shut down
70 static void on_ToClientAuth(__attribute__((unused)) DragonnetPeer *peer, ToClientAuth *pkt)
72 pthread_mutex_lock(&client_auth.mtx);
74 client_auth.state = AUTH_SUCCESS;
75 printf("[access] authenticated successfully\n");
77 client_auth.state = AUTH_INIT;
78 printf("[access] authentication failed, please try again\n");
80 pthread_cond_signal(&client_auth.cv);
81 pthread_mutex_unlock(&client_auth.mtx);
83 // yield the connection until the game is fully initialized
88 static void on_ToClientChunk(__attribute__((unused)) DragonnetPeer *peer, ToClientChunk *pkt)
90 TerrainChunk *chunk = terrain_get_chunk(client_terrain, pkt->pos, true);
92 terrain_deserialize_chunk(chunk, pkt->data);
93 ((TerrainChunkMeta *) chunk->extra)->empty = (pkt->data.siz == 0);
94 client_terrain_chunk_received(chunk);
97 static void on_ToClientInfo(__attribute__((unused)) DragonnetPeer *peer, ToClientInfo *pkt)
99 client_terrain_set_load_distance(pkt->load_distance);
103 static void on_ToClientTimeOfDay(__attribute__((unused)) DragonnetPeer *peer, ToClientTimeOfDay *pkt)
105 set_time_of_day(pkt->time_of_day);
108 static void on_ToClientMovement(__attribute__((unused)) DragonnetPeer *peer, ToClientMovement *pkt)
110 pthread_rwlock_wrlock(&client_player.lock_movement);
111 client_player.movement = *pkt;
112 pthread_rwlock_unlock(&client_player.lock_movement);
114 debug_menu_changed(ENTRY_FLIGHT);
115 debug_menu_changed(ENTRY_COLLISION);
118 int main(int argc, char **argv)
120 #ifdef __GLIBC__ // check whether bloat is enabled
121 pthread_setname_np(pthread_self(), "main");
125 fprintf(stderr, "[error] missing address\n");
129 if (!(client = dragonnet_connect(argv[1]))) {
130 fprintf(stderr, "[error] failed to connect to server\n");
134 printf("[access] connected to %s\n", client->address);
136 client->on_disconnect = &on_disconnect;
137 client->on_recv = (void *) &on_recv;
138 client->on_recv_type[DRAGONNET_TYPE_ToClientAuth ] = (void *) &on_ToClientAuth;
139 client->on_recv_type[DRAGONNET_TYPE_ToClientChunk ] = (void *) &on_ToClientChunk;
140 client->on_recv_type[DRAGONNET_TYPE_ToClientInfo ] = (void *) &on_ToClientInfo;
141 client->on_recv_type[DRAGONNET_TYPE_ToClientTimeOfDay ] = (void *) &on_ToClientTimeOfDay;
142 client->on_recv_type[DRAGONNET_TYPE_ToClientMovement ] = (void *) &on_ToClientMovement;
143 client->on_recv_type[DRAGONNET_TYPE_ToClientEntityAdd ] = (void *) &client_entity_add;
144 client->on_recv_type[DRAGONNET_TYPE_ToClientEntityRemove ] = (void *) &client_entity_remove;
145 client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdatePosRot ] = (void *) &client_entity_update_pos_rot;
146 client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdateNametag] = (void *) &client_entity_update_nametag;
147 client->on_recv_type[DRAGONNET_TYPE_ToClientPlayerInventory ] = (void *) &client_inventory_update_player;
153 client_terrain_init();
154 client_player_init();
155 client_entity_init();
156 dragonnet_peer_run(client);
158 if (!client_auth_init())
161 if (!game(&gfx_init))
164 dragonnet_peer_shutdown(client);
165 client_auth_deinit();
166 client_entity_deinit();
167 client_player_deinit();
168 client_terrain_deinit();
171 pthread_t recv_thread = client->recv_thread;
174 pthread_join(recv_thread, NULL);