-COMMON = array.o binsearch.o linkedlist.o map.o
+COMMON = array.o binsearch.o linkedlist.o map.o util.o
SERVER = $(COMMON) server.o
+CLIENT = $(COMMON) client.o
-all: DragonblocksServer
+all: Dragonblocks DragonblocksServer
+
+Dragonblocks: $(CLIENT)
+ gcc -g -o Dragonblocks $(CLIENT)
DragonblocksServer: $(SERVER)
gcc -g -o DragonblocksServer $(SERVER)
%.o: %.c
- gcc -c -g -o $@ -Wall -Wextra -Wpedantic $<
+ gcc -c -g -o $@ -Wall -Wextra -Wpedantic -Werror $<
clean:
rm *.o
--- /dev/null
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include "map.h"
+#include "util.h"
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+
+ int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sockfd == -1)
+ syscall_error("socket");
+
+ if (argc <= 1)
+ internal_error("missing address");
+
+ struct in_addr addr_buf;
+
+ if (inet_aton(argv[1], &addr_buf) == 0)
+ internal_error("invalid address");
+
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = get_port_from_args(argc, argv, 2),
+ .sin_addr = addr_buf,
+ };
+
+ if (connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+ syscall_error("connect");
+
+ Map *map = map_create(NULL);
+
+ MapBlock *block = map_deserialize_block(sockfd);
+ map_create_block(map, (v3s32) {0, 0, 0}, block);
+
+ MapNode node = map_get_node(map, (v3s32) {0, 0, 0});
+ printf("%d\n", node.type);
+
+ close(sockfd);
+
+ map_delete(map);
+}
#include <stdlib.h>
#include <stdbool.h>
+#include <endian.h>
+#include <unistd.h>
#include "map.h"
#include "binsearch.h"
return block;
}
+void map_create_block(Map *map, v3s32 pos, MapBlock *block)
+{
+ block->pos = pos;
+
+ MapSector *sector = map_get_sector(map, (v2s32) {pos.x, pos.z}, true);
+ BinsearchResult res = binsearch(&pos.y, sector->blocks.ptr, sector->blocks.siz, &block_compare);
+ if (res.success) {
+ map_raw_delete_block(sector->blocks.ptr[res.index]);
+ sector->blocks.ptr[res.index] = block;
+ } else {
+ array_insert(§or->blocks, block, res.index);
+ }
+}
+
+void map_serialize_block(int fd, MapBlock *block)
+{
+ ITERATE_MAPBLOCK {
+ u32 encoded_type = htobe32((u32) block->data[x][y][z].type);
+ write(fd, &encoded_type, 4);
+ }
+}
+
+MapBlock *map_deserialize_block(int fd)
+{
+ MapBlock *block = malloc(sizeof(MapBlock));
+ ITERATE_MAPBLOCK {
+ u32 encoded_type;
+ read(fd, &encoded_type, 4);
+ Node type = be32toh(encoded_type);
+ if (type >= MAX_NODES)
+ type = NODE_INVALID;
+ block->data[x][y][z] = map_node_create(type);
+ }
+ return block;
+}
+
MapNode map_get_node(Map *map, v3s32 pos)
{
MapBlock *block = map_get_block(map, (v3s32) {pos.x / 16, pos.y / 16, pos.z / 16}, false);
MapBlock *map_get_block(Map *map, v3s32 pos, bool create);
void map_create_block(Map *map, v3s32 pos, MapBlock *block);
-void map_serialize_block(int fd, MapBlock *); // ToDo
-MapBlock *map_deserialize_block(int fd); // ToDo
+void map_serialize_block(int fd, MapBlock *);
+MapBlock *map_deserialize_block(int fd);
void map_delete_block(MapBlock *); // ToDo
void map_unload_block(MapBlock *); // ToDo
typedef enum
{
NODE_UNLOADED, // Used for nodes in unloaded blocks
+ NODE_INVALID, // Used for invalid nodes sent by server
NODE_AIR,
NODE_GRASS,
NODE_DIRT,
NODE_STONE,
+ MAX_NODES,
} Node;
#endif
#include <assert.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
#include "map.h"
+#include "util.h"
-int main()
+int main(int argc, char **argv)
{
+ program_name = argv[0];
+
+ int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sockfd == -1)
+ syscall_error("socket");
+
+ struct sockaddr_in srv_addr = {
+ .sin_family = AF_INET,
+ .sin_port = get_port_from_args(argc, argv, 1),
+ .sin_addr = {.s_addr = INADDR_ANY},
+ };
+
+ int flag = 1;
+
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, 4) == -1)
+ syscall_error("setsockopt");
+
+ if (bind(sockfd, (struct sockaddr *) &srv_addr, sizeof(srv_addr)) == -1)
+ syscall_error("bind");
+
+ if (listen(sockfd, 3) == -1)
+ syscall_error("listen");
+
Map *map = map_create(NULL);
map_set_node(map, (v3s32) {0, 0, 0}, map_node_create(NODE_STONE));
- printf("test 1 passed\n");
- map_set_node(map, (v3s32) {0, 5, 89}, map_node_create(NODE_DIRT));
- printf("test 2 passed\n");
- map_set_node(map, (v3s32) {321, 0, 89}, map_node_create(NODE_GRASS));
- printf("test 3 passed\n");
- map_set_node(map, (v3s32) {3124, 99, 2}, map_node_create(NODE_GRASS));
- printf("test 4 passed\n");
+
+ struct sockaddr_in cli_addr_buf;
+ socklen_t cli_addrlen_buf;
+
+ int fd = accept(sockfd, (struct sockaddr *) &cli_addr_buf, &cli_addrlen_buf);
+
+ if (fd == -1)
+ syscall_error("accept");
+
MapBlock *block = map_get_block(map, (v3s32) {0, 0, 0}, false);
assert(block);
- printf("(0 | 0 | 0) Block dump:\n");
- ITERATE_MAPBLOCK printf("%d", block->data[x][y][z].type);
+ map_serialize_block(fd, block);
+ close(fd);
+
+ shutdown(sockfd, SHUT_RDWR);
+ close(sockfd);
map_delete(map);
}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <arpa/inet.h>
+#include "util.h"
+
+const char *program_name;
+
+void syscall_error(const char *err)
+{
+ perror(err);
+ exit(EXIT_FAILURE);
+}
+
+void internal_error(const char *err)
+{
+ fprintf(stderr, "%s: %s\n", program_name, err);
+ exit(EXIT_FAILURE);
+}
+
+unsigned short get_port_from_args(int argc, char **argv, int index)
+{
+ if (argc <= index)
+ internal_error("missing port");
+
+ unsigned int port = atoi(argv[index]);
+
+ if (port == 0 || port > USHRT_MAX)
+ internal_error("invalid port");
+
+ return htons(port);
+}
--- /dev/null
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include "types.h"
+
+extern const char *program_name;
+
+void syscall_error(const char *err);
+void internal_error(const char *err);
+u16 get_port_from_args(int argc, char **argv, int index);
+
+#endif