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