omicron/src/client.c

266 lines
6.0 KiB
C

#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#define close closesocket
#define sleep Sleep
#else
#include <netdb.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "client.h"
#include "tinycthread.h"
#define QUEUE_SIZE 1048576
#define RECV_SIZE 4096
static int client_enabled = 0;
static int running = 0;
static int sd = 0;
static int bytes_sent = 0;
static int bytes_received = 0;
static char *queue = 0;
static int qsize = 0;
static thrd_t recv_thread;
static mtx_t mutex;
void client_enable() {
client_enabled = 1;
}
void client_disable() {
client_enabled = 0;
}
int get_client_enabled() {
return client_enabled;
}
int client_sendall(int sd, char *data, int length) {
if (!client_enabled) {
return 0;
}
int count = 0;
while (count < length) {
int n = send(sd, data + count, length, 0);
if (n == -1) {
return -1;
}
count += n;
length -= n;
bytes_sent += n;
}
return 0;
}
void client_send(char *data) {
if (!client_enabled) {
return;
}
if (client_sendall(sd, data, strlen(data)) == -1) {
perror("client_sendall");
exit(1);
}
}
void client_version(int version) {
if (!client_enabled) {
return;
}
char buffer[1024];
snprintf(buffer, 1024, "V,%d\n", version);
client_send(buffer);
}
void client_login(const char *username, const char *identity_token) {
if (!client_enabled) {
return;
}
char buffer[1024];
snprintf(buffer, 1024, "A,%s,%s\n", username, identity_token);
client_send(buffer);
}
void client_position(float x, float y, float z, float rx, float ry) {
if (!client_enabled) {
return;
}
static float px, py, pz, prx, pry = 0;
float distance =
(px - x) * (px - x) +
(py - y) * (py - y) +
(pz - z) * (pz - z) +
(prx - rx) * (prx - rx) +
(pry - ry) * (pry - ry);
if (distance < 0.0001) {
return;
}
px = x; py = y; pz = z; prx = rx; pry = ry;
char buffer[1024];
snprintf(buffer, 1024, "P,%.2f,%.2f,%.2f,%.2f,%.2f\n", x, y, z, rx, ry);
client_send(buffer);
}
void client_chunk(int p, int q, int key) {
if (!client_enabled) {
return;
}
char buffer[1024];
snprintf(buffer, 1024, "C,%d,%d,%d\n", p, q, key);
client_send(buffer);
}
void client_block(int x, int y, int z, int w) {
if (!client_enabled) {
return;
}
char buffer[1024];
snprintf(buffer, 1024, "B,%d,%d,%d,%d\n", x, y, z, w);
client_send(buffer);
}
void client_light(int x, int y, int z, int w) {
if (!client_enabled) {
return;
}
char buffer[1024];
snprintf(buffer, 1024, "L,%d,%d,%d,%d\n", x, y, z, w);
client_send(buffer);
}
void client_sign(int x, int y, int z, int face, const char *text) {
if (!client_enabled) {
return;
}
char buffer[1024];
snprintf(buffer, 1024, "S,%d,%d,%d,%d,%s\n", x, y, z, face, text);
client_send(buffer);
}
void client_talk(const char *text) {
if (!client_enabled) {
return;
}
if (strlen(text) == 0) {
return;
}
char buffer[1024];
snprintf(buffer, 1024, "T,%s\n", text);
client_send(buffer);
}
char *client_recv() {
if (!client_enabled) {
return 0;
}
char *result = 0;
mtx_lock(&mutex);
char *p = queue + qsize - 1;
while (p >= queue && *p != '\n') {
p--;
}
if (p >= queue) {
int length = p - queue + 1;
result = malloc(sizeof(char) * (length + 1));
memcpy(result, queue, sizeof(char) * length);
result[length] = '\0';
int remaining = qsize - length;
memmove(queue, p + 1, remaining);
qsize -= length;
bytes_received += length;
}
mtx_unlock(&mutex);
return result;
}
int recv_worker(void *arg) {
char *data = malloc(sizeof(char) * RECV_SIZE);
while (1) {
int length;
if ((length = recv(sd, data, RECV_SIZE - 1, 0)) <= 0) {
if (running) {
perror("recv");
exit(1);
}
else {
break;
}
}
data[length] = '\0';
while (1) {
int done = 0;
mtx_lock(&mutex);
if (qsize + length < QUEUE_SIZE) {
memcpy(queue + qsize, data, sizeof(char) * (length + 1));
qsize += length;
done = 1;
}
mtx_unlock(&mutex);
if (done) {
break;
}
sleep(0);
}
}
free(data);
return 0;
}
void client_connect(char *hostname, int port) {
if (!client_enabled) {
return;
}
struct hostent *host;
struct sockaddr_in address;
if ((host = gethostbyname(hostname)) == 0) {
perror("gethostbyname");
exit(1);
}
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = ((struct in_addr *)(host->h_addr_list[0]))->s_addr;
address.sin_port = htons(port);
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
if (connect(sd, (struct sockaddr *)&address, sizeof(address)) == -1) {
perror("connect");
exit(1);
}
}
void client_start() {
if (!client_enabled) {
return;
}
running = 1;
queue = (char *)calloc(QUEUE_SIZE, sizeof(char));
qsize = 0;
mtx_init(&mutex, mtx_plain);
if (thrd_create(&recv_thread, recv_worker, NULL) != thrd_success) {
perror("thrd_create");
exit(1);
}
}
void client_stop() {
if (!client_enabled) {
return;
}
running = 0;
close(sd);
// if (thrd_join(recv_thread, NULL) != thrd_success) {
// perror("thrd_join");
// exit(1);
// }
// mtx_destroy(&mutex);
qsize = 0;
free(queue);
// printf("Bytes Sent: %d, Bytes Received: %d\n",
// bytes_sent, bytes_received);
}