1 #ifdef _WIN32
2     #include <winsock2.h>
3     #include <windows.h>
4     #define close closesocket
5     #define sleep Sleep
6 #else
7     #include <netdb.h>
8     #include <unistd.h>
9     #include <sys/socket.h>
10     #include <netinet/in.h>
11 #endif
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include "client.h"
17 #include "tinycthread.h"
18 
19 #define QUEUE_SIZE 1048576
20 #define RECV_SIZE 4096
21 
22 static int client_enabled = 0;
23 static int running = 0;
24 static int sd = 0;
25 static int bytes_sent = 0;
26 static int bytes_received = 0;
27 static char *queue = 0;
28 static int qsize = 0;
29 static thrd_t recv_thread;
30 static mtx_t mutex;
31 
client_enable()32 void client_enable() {
33     client_enabled = 1;
34 }
35 
client_disable()36 void client_disable() {
37     client_enabled = 0;
38 }
39 
get_client_enabled()40 int get_client_enabled() {
41     return client_enabled;
42 }
43 
client_sendall(int sd,char * data,int length)44 int client_sendall(int sd, char *data, int length) {
45     if (!client_enabled) {
46         return 0;
47     }
48     int count = 0;
49     while (count < length) {
50         int n = send(sd, data + count, length, 0);
51         if (n == -1) {
52             return -1;
53         }
54         count += n;
55         length -= n;
56         bytes_sent += n;
57     }
58     return 0;
59 }
60 
client_send(char * data)61 void client_send(char *data) {
62     if (!client_enabled) {
63         return;
64     }
65     if (client_sendall(sd, data, strlen(data)) == -1) {
66         perror("client_sendall");
67         exit(1);
68     }
69 }
70 
client_version(int version)71 void client_version(int version) {
72     if (!client_enabled) {
73         return;
74     }
75     char buffer[1024];
76     snprintf(buffer, 1024, "V,%d\n", version);
77     client_send(buffer);
78 }
79 
client_login(const char * username,const char * identity_token)80 void client_login(const char *username, const char *identity_token) {
81     if (!client_enabled) {
82         return;
83     }
84     char buffer[1024];
85     snprintf(buffer, 1024, "A,%s,%s\n", username, identity_token);
86     client_send(buffer);
87 }
88 
client_position(float x,float y,float z,float rx,float ry)89 void client_position(float x, float y, float z, float rx, float ry) {
90     if (!client_enabled) {
91         return;
92     }
93     static float px, py, pz, prx, pry = 0;
94     float distance =
95         (px - x) * (px - x) +
96         (py - y) * (py - y) +
97         (pz - z) * (pz - z) +
98         (prx - rx) * (prx - rx) +
99         (pry - ry) * (pry - ry);
100     if (distance < 0.0001) {
101         return;
102     }
103     px = x; py = y; pz = z; prx = rx; pry = ry;
104     char buffer[1024];
105     snprintf(buffer, 1024, "P,%.2f,%.2f,%.2f,%.2f,%.2f\n", x, y, z, rx, ry);
106     client_send(buffer);
107 }
108 
client_chunk(int p,int q,int key)109 void client_chunk(int p, int q, int key) {
110     if (!client_enabled) {
111         return;
112     }
113     char buffer[1024];
114     snprintf(buffer, 1024, "C,%d,%d,%d\n", p, q, key);
115     client_send(buffer);
116 }
117 
client_block(int x,int y,int z,int w)118 void client_block(int x, int y, int z, int w) {
119     if (!client_enabled) {
120         return;
121     }
122     char buffer[1024];
123     snprintf(buffer, 1024, "B,%d,%d,%d,%d\n", x, y, z, w);
124     client_send(buffer);
125 }
126 
client_light(int x,int y,int z,int w)127 void client_light(int x, int y, int z, int w) {
128     if (!client_enabled) {
129         return;
130     }
131     char buffer[1024];
132     snprintf(buffer, 1024, "L,%d,%d,%d,%d\n", x, y, z, w);
133     client_send(buffer);
134 }
135 
client_sign(int x,int y,int z,int face,const char * text)136 void client_sign(int x, int y, int z, int face, const char *text) {
137     if (!client_enabled) {
138         return;
139     }
140     char buffer[1024];
141     snprintf(buffer, 1024, "S,%d,%d,%d,%d,%s\n", x, y, z, face, text);
142     client_send(buffer);
143 }
144 
client_talk(const char * text)145 void client_talk(const char *text) {
146     if (!client_enabled) {
147         return;
148     }
149     if (strlen(text) == 0) {
150         return;
151     }
152     char buffer[1024];
153     snprintf(buffer, 1024, "T,%s\n", text);
154     client_send(buffer);
155 }
156 
client_recv()157 char *client_recv() {
158     if (!client_enabled) {
159         return 0;
160     }
161     char *result = 0;
162     mtx_lock(&mutex);
163     char *p = queue + qsize - 1;
164     while (p >= queue && *p != '\n') {
165         p--;
166     }
167     if (p >= queue) {
168         int length = p - queue + 1;
169         result = malloc(sizeof(char) * (length + 1));
170         memcpy(result, queue, sizeof(char) * length);
171         result[length] = '\0';
172         int remaining = qsize - length;
173         memmove(queue, p + 1, remaining);
174         qsize -= length;
175         bytes_received += length;
176     }
177     mtx_unlock(&mutex);
178     return result;
179 }
180 
recv_worker(void * arg)181 int recv_worker(void *arg) {
182     char *data = malloc(sizeof(char) * RECV_SIZE);
183     while (1) {
184         int length;
185         if ((length = recv(sd, data, RECV_SIZE - 1, 0)) <= 0) {
186             if (running) {
187                 perror("recv");
188                 exit(1);
189             }
190             else {
191                 break;
192             }
193         }
194         data[length] = '\0';
195         while (1) {
196             int done = 0;
197             mtx_lock(&mutex);
198             if (qsize + length < QUEUE_SIZE) {
199                 memcpy(queue + qsize, data, sizeof(char) * (length + 1));
200                 qsize += length;
201                 done = 1;
202             }
203             mtx_unlock(&mutex);
204             if (done) {
205                 break;
206             }
207             sleep(0);
208         }
209     }
210     free(data);
211     return 0;
212 }
213 
client_connect(char * hostname,int port)214 void client_connect(char *hostname, int port) {
215     if (!client_enabled) {
216         return;
217     }
218     struct hostent *host;
219     struct sockaddr_in address;
220     if ((host = gethostbyname(hostname)) == 0) {
221         perror("gethostbyname");
222         exit(1);
223     }
224     memset(&address, 0, sizeof(address));
225     address.sin_family = AF_INET;
226     address.sin_addr.s_addr = ((struct in_addr *)(host->h_addr_list[0]))->s_addr;
227     address.sin_port = htons(port);
228     if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
229         perror("socket");
230         exit(1);
231     }
232     if (connect(sd, (struct sockaddr *)&address, sizeof(address)) == -1) {
233         perror("connect");
234         exit(1);
235     }
236 }
237 
client_start()238 void client_start() {
239     if (!client_enabled) {
240         return;
241     }
242     running = 1;
243     queue = (char *)calloc(QUEUE_SIZE, sizeof(char));
244     qsize = 0;
245     mtx_init(&mutex, mtx_plain);
246     if (thrd_create(&recv_thread, recv_worker, NULL) != thrd_success) {
247         perror("thrd_create");
248         exit(1);
249     }
250 }
251 
client_stop()252 void client_stop() {
253     if (!client_enabled) {
254         return;
255     }
256     running = 0;
257     close(sd);
258     // if (thrd_join(recv_thread, NULL) != thrd_success) {
259     //     perror("thrd_join");
260     //     exit(1);
261     // }
262     // mtx_destroy(&mutex);
263     qsize = 0;
264     free(queue);
265     // printf("Bytes Sent: %d, Bytes Received: %d\n",
266     //     bytes_sent, bytes_received);
267 }
268