Added dynamic world loading

This commit is contained in:
JavaProphet 2016-12-24 20:59:02 -08:00
parent be2f415ac5
commit 9d7191cd59
17 changed files with 369 additions and 112 deletions

View File

@ -74,3 +74,15 @@ int rem_collection(struct collection* coll, void* data) {
return -1;
}
int contains_collection(struct collection* coll, void* data) {
pthread_rwlock_rdlock(&coll->data_mutex);
for (int i = 0; i < coll->size; i++) {
if (coll->data[i] == data) {
pthread_rwlock_unlock(&coll->data_mutex);
return 1;
}
}
pthread_rwlock_unlock(&coll->data_mutex);
return 0;
}

View File

@ -27,4 +27,6 @@ int add_collection(struct collection* coll, void* data);
int rem_collection(struct collection* coll, void* data);
int contains_collection(struct collection* coll, void* data);
#endif /* COLLECTION_H_ */

View File

@ -26,6 +26,96 @@ void flush_outgoing(struct player* player) {
}
}
void loadPlayer(struct player* to, struct player* from) {
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_SPAWNPLAYER;
pkt->data.play_client.spawnplayer.entity_id = from->entity->id;
memcpy(&pkt->data.play_client.spawnplayer.player_uuid, &from->entity->data.player.player->uuid, sizeof(struct uuid));
pkt->data.play_client.spawnplayer.x = from->entity->x;
pkt->data.play_client.spawnplayer.y = from->entity->y;
pkt->data.play_client.spawnplayer.z = from->entity->z;
pkt->data.play_client.spawnplayer.yaw = (from->entity->yaw / 360.) * 256.;
pkt->data.play_client.spawnplayer.pitch = (from->entity->pitch / 360.) * 256.;
writeMetadata(from->entity, &pkt->data.play_client.spawnplayer.metadata.metadata, &pkt->data.play_client.spawnplayer.metadata.metadata_size);
add_queue(to->conn->outgoingPacket, pkt);
pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = from->entity->id;
pkt->data.play_client.entityequipment.slot = 0;
duplicateSlot(from->inventory.slots == NULL ? NULL : from->inventory.slots[from->currentItem + 36], &pkt->data.play_client.entityequipment.item);
add_queue(to->conn->outgoingPacket, pkt);
pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = from->entity->id;
pkt->data.play_client.entityequipment.slot = 5;
duplicateSlot(from->inventory.slots == NULL ? NULL : from->inventory.slots[5], &pkt->data.play_client.entityequipment.item);
add_queue(to->conn->outgoingPacket, pkt);
pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = from->entity->id;
pkt->data.play_client.entityequipment.slot = 4;
duplicateSlot(from->inventory.slots == NULL ? NULL : from->inventory.slots[6], &pkt->data.play_client.entityequipment.item);
add_queue(to->conn->outgoingPacket, pkt);
pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = from->entity->id;
pkt->data.play_client.entityequipment.slot = 3;
duplicateSlot(from->inventory.slots == NULL ? NULL : from->inventory.slots[7], &pkt->data.play_client.entityequipment.item);
add_queue(to->conn->outgoingPacket, pkt);
pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = from->entity->id;
pkt->data.play_client.entityequipment.slot = 2;
duplicateSlot(from->inventory.slots == NULL ? NULL : from->inventory.slots[8], &pkt->data.play_client.entityequipment.item);
add_queue(to->conn->outgoingPacket, pkt);
pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = from->entity->id;
pkt->data.play_client.entityequipment.slot = 1;
duplicateSlot(from->inventory.slots == NULL ? NULL : from->inventory.slots[45], &pkt->data.play_client.entityequipment.item);
add_queue(to->conn->outgoingPacket, pkt);
flush_outgoing(to);
}
void onInventoryUpdate(struct inventory* inventory, int slot) {
if (inventory->type == INVTYPE_PLAYERINVENTORY) {
if (slot == inventory->player->currentItem + 36) {
BEGIN_BROADCAST_EXCEPT_DIST(inventory->player, inventory->player->entity, 128.)
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = inventory->player->entity->id;
pkt->data.play_client.entityequipment.slot = 0;
duplicateSlot(inventory->slots == NULL ? NULL : inventory->slots[inventory->player->currentItem + 36], &pkt->data.play_client.entityequipment.item);
add_queue(bc_player->conn->outgoingPacket, pkt);
flush_outgoing (bc_player);
END_BROADCAST
} else if (slot >= 5 && slot <= 8) {
BEGIN_BROADCAST_EXCEPT_DIST(inventory->player, inventory->player->entity, 128.)
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = inventory->player->entity->id;
if (slot == 5) pkt->data.play_client.entityequipment.slot = 5;
else if (slot == 6) pkt->data.play_client.entityequipment.slot = 4;
else if (slot == 7) pkt->data.play_client.entityequipment.slot = 3;
else if (slot == 8) pkt->data.play_client.entityequipment.slot = 2;
duplicateSlot(inventory->slots == NULL ? NULL : inventory->slots[slot], &pkt->data.play_client.entityequipment.item);
add_queue(bc_player->conn->outgoingPacket, pkt);
flush_outgoing (bc_player);
END_BROADCAST
} else if (slot == 45) {
BEGIN_BROADCAST_EXCEPT_DIST(inventory->player, inventory->player->entity, 128.)
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYEQUIPMENT;
pkt->data.play_client.entityequipment.entity_id = inventory->player->entity->id;
pkt->data.play_client.entityequipment.slot = 1;
duplicateSlot(inventory->slots == NULL ? NULL : inventory->slots[45], &pkt->data.play_client.entityequipment.item);
add_queue(bc_player->conn->outgoingPacket, pkt);
flush_outgoing (bc_player);
END_BROADCAST
}
}
}
void tick_player(struct world* world, struct player* player) {
if (tick_counter % 200 == 0) {
if (player->nextKeepAlive != 0) {
@ -39,6 +129,53 @@ void tick_player(struct world* world, struct player* player) {
add_queue(player->conn->outgoingPacket, pkt);
flush_outgoing(player);
}
int32_t pcx = ((int32_t) player->entity->x >> 4);
int32_t pcz = ((int32_t) player->entity->z >> 4);
if (((int32_t) player->entity->lx >> 4) != pcx || ((int32_t) player->entity->lz >> 4) != pcz || player->loadedChunks->count == 0) {
for (int x = -CHUNK_VIEW_DISTANCE + pcx; x <= CHUNK_VIEW_DISTANCE + pcx; x++) {
for (int z = -CHUNK_VIEW_DISTANCE + pcz; z <= CHUNK_VIEW_DISTANCE + pcz; z++) {
struct chunk* ch = getChunk(player->world, x, z);
if (ch != NULL && !contains_collection(player->loadedChunks, ch)) {
ch->playersLoaded++;
add_collection(player->loadedChunks, ch);
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_CHUNKDATA;
pkt->data.play_client.chunkdata.data = ch;
pkt->data.play_client.chunkdata.ground_up_continuous = 1;
pkt->data.play_client.chunkdata.number_of_block_entities = 0;
pkt->data.play_client.chunkdata.block_entities = NULL;
add_queue(player->conn->outgoingPacket, pkt);
flush_outgoing(player);
//printf("client load %i, %i\n", ch->x, ch->z);
}
}
}
pthread_rwlock_wrlock(&player->loadedChunks->data_mutex);
for (int i = 0; i < player->loadedChunks->size; i++) {
struct chunk* ch = player->loadedChunks->data[i];
if (ch == NULL) continue;
int dx = (ch->x - pcx);
if (dx < 0) dx = -dx;
int dz = (ch->z - pcz);
if (dz < 0) dz = -dz;
if (dx > CHUNK_VIEW_DISTANCE || dz > CHUNK_VIEW_DISTANCE) {
//printf("client unload %i, %i\n", ch->x, ch->z);
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_UNLOADCHUNK;
pkt->data.play_client.unloadchunk.chunk_x = ch->x;
pkt->data.play_client.unloadchunk.chunk_z = ch->z;
add_queue(player->conn->outgoingPacket, pkt);
flush_outgoing(player);
player->loadedChunks->data[i] = NULL;
player->loadedChunks->count--;
if (--ch->playersLoaded <= 0) {
//printf("server unload %i, %i\n", ch->x, ch->z);
unloadChunk(player->world, ch);
}
}
}
pthread_rwlock_unlock(&player->loadedChunks->data_mutex);
}
if (player->digging >= 0.) {
struct block_info* bi = &block_infos[getBlockWorld(world, player->digging_position.x, player->digging_position.y, player->digging_position.z)];
float digspeed = 0.;

View File

@ -13,6 +13,10 @@
void flush_outgoing(struct player* player);
void loadPlayer(struct player* to, struct player* from);
void onInventoryUpdate(struct inventory* inventory, int slot);
void tick_world(struct world* world);
void broadcast(char* text);

View File

@ -9,6 +9,7 @@
#define GLOBALS_H_
#define MC_PROTOCOL_VERSION 315
#define CHUNK_VIEW_DISTANCE 10
#include <stdlib.h>

View File

@ -7,20 +7,21 @@
#include "inventory.h"
#include "globals.h"
#include <GL/gl.h>
#include "item.h"
#include "network.h"
#include <string.h>
#include <math.h>
#include "util.h"
void newInventory(struct inventory* inv, int type, int id) {
void newInventory(struct inventory* inv, int type, int id, int slots) {
inv->title = NULL;
inv->slots = NULL;
inv->slot_count = 0;
inv->slot_count = slots;
inv->props = NULL;
inv->prop_count = 0;
inv->type = type;
inv->windowID = id;
inv->player = NULL;
}
void _freeInventorySlots(struct inventory* inv) {
@ -29,22 +30,22 @@ void _freeInventorySlots(struct inventory* inv) {
if (inv->slots[i] == NULL) continue;
if (inv->slots[i]->nbt != NULL) {
freeNBT(inv->slots[i]->nbt);
free(inv->slots[i]->nbt);
xfree(inv->slots[i]->nbt);
}
free(inv->slots[i]);
xfree(inv->slots[i]);
}
free(inv->slots);
xfree(inv->slots);
inv->slots = NULL;
}
}
void freeInventory(struct inventory* inv) {
if (inv->title != NULL) free(inv->title);
if (inv->title != NULL) xfree(inv->title);
if (inv->props != NULL) {
for (size_t i = 0; i < inv->prop_count; i++) {
free(inv->props[i]);
xfree(inv->props[i]);
}
free(inv->props);
xfree(inv->props);
}
_freeInventorySlots(inv);
}
@ -73,7 +74,8 @@ void setInventoryItems(struct inventory* inv, struct slot** slots, size_t slot_c
for (size_t i = 0; i < slot_count; i++) {
if (slots[i]->item < 0) {
if (slots[i]->nbt != NULL) freeNBT(slots[i]->nbt);
free(slots[i]);
xfree(slots[i]->nbt);
xfree(slots[i]);
slots[i] = NULL;
}
}
@ -85,27 +87,21 @@ void setInventorySlot(struct inventory* inv, struct slot* slot, int index) {
if (index < 0 || index >= inv->slot_count) return;
if (inv->slots == NULL) {
if (inv->slot_count < 1) return;
inv->slots = malloc(sizeof(struct slot*) * inv->slot_count);
inv->slots = xmalloc(sizeof(struct slot*) * inv->slot_count);
for (int i = 0; i < inv->slot_count; i++) {
inv->slots[i] = NULL;
}
}
if (slot != NULL && slot->item < 0) {
if (slot->nbt != NULL) {
freeNBT(slot->nbt);
free(slot->nbt);
}
free(slot);
slot = NULL;
}
if (inv->slots[index] != NULL) {
if (inv->slots[index]->nbt != NULL) {
freeNBT(inv->slots[index]->nbt);
free(inv->slots[index]->nbt);
xfree(inv->slots[index]->nbt);
}
free(inv->slots[index]);
xfree(inv->slots[index]);
}
inv->slots[index] = slot;
if (slot != NULL && slot->item == -1) slot = NULL;
inv->slots[index] = xmalloc(sizeof(struct slot));
duplicateSlot(slot, inv->slots[index]);
}
void setInventoryProperty(struct inventory* inv, int16_t name, int16_t value) {
@ -116,12 +112,12 @@ void setInventoryProperty(struct inventory* inv, int16_t name, int16_t value) {
return;
}
}
inv->props = realloc(inv->props, sizeof(int16_t*) * (inv->prop_count + 1));
inv->props = xrealloc(inv->props, sizeof(int16_t*) * (inv->prop_count + 1));
} else {
inv->props = malloc(sizeof(int16_t*));
inv->props = xmalloc(sizeof(int16_t*));
inv->prop_count = 0;
}
int16_t* dm = malloc(sizeof(int16_t) * 2);
int16_t* dm = xmalloc(sizeof(int16_t) * 2);
dm[0] = name;
dm[1] = value;
inv->props[inv->prop_count++] = dm;

View File

@ -47,9 +47,10 @@ struct inventory {
int16_t** props;
size_t prop_count;
int windowID;
struct player* player; // only for player inventories
};
void newInventory(struct inventory* inv, int type, int id);
void newInventory(struct inventory* inv, int type, int id, int slots);
void freeInventory(struct inventory* inv);

View File

@ -7,24 +7,27 @@
#include "nbt.h"
#include <stdlib.h>
#include <string.h>
#include "xstring.h"
#include "util.h"
#include <zlib.h>
#include <stdio.h>
#include "network.h"
void freeNBT(struct nbt_tag* nbt) {
if (nbt->name != NULL) free(nbt->name);
if (nbt->name != NULL) xfree(nbt->name);
if (nbt->children != NULL) {
for (size_t i = 0; i < nbt->children_count; i++) {
freeNBT(nbt->children[i]);
free(nbt->children[i]);
xfree(nbt->children[i]);
}
free(nbt->children);
xfree(nbt->children);
}
if (nbt->id == NBT_TAG_BYTEARRAY) {
free(nbt->data.nbt_bytearray.data);
xfree(nbt->data.nbt_bytearray.data);
} else if (nbt->id == NBT_TAG_STRING) {
free(nbt->data.nbt_string);
xfree(nbt->data.nbt_string);
} else if (nbt->id == NBT_TAG_INTARRAY) {
free(nbt->data.nbt_intarray.ints);
xfree(nbt->data.nbt_intarray.ints);
}
}
@ -36,19 +39,19 @@ struct nbt_tag* getNBTChild(struct nbt_tag* nbt, char* name) {
}
struct nbt_tag* cloneNBT(struct nbt_tag* nbt) {
struct nbt_tag* nt = malloc(sizeof(struct nbt_tag));
nt->name = nbt->name == NULL ? NULL : strdup(nbt->name);
struct nbt_tag* nt = xmalloc(sizeof(struct nbt_tag));
nt->name = nbt->name == NULL ? NULL : xstrdup(nbt->name, 0);
nt->id = nbt->id;
nt->children_count = nbt->children_count;
nt->children = nt->children_count == 0 ? NULL : malloc(sizeof(struct nbt_tag*) * nt->children_count);
nt->children = nt->children_count == 0 ? NULL : xmalloc(sizeof(struct nbt_tag*) * nt->children_count);
memcpy(&nt->data, &nbt->data, sizeof(union nbt_data));
if (nbt->id == NBT_TAG_BYTEARRAY) {
nt->data.nbt_bytearray.data = malloc(nt->data.nbt_bytearray.len);
nt->data.nbt_bytearray.data = xmalloc(nt->data.nbt_bytearray.len);
memcpy(nt->data.nbt_bytearray.data, nbt->data.nbt_bytearray.data, nt->data.nbt_bytearray.len);
} else if (nbt->id == NBT_TAG_STRING) {
nt->data.nbt_string = strdup(nbt->data.nbt_string);
nt->data.nbt_string = xstrdup(nbt->data.nbt_string, 0);
} else if (nbt->id == NBT_TAG_INTARRAY) {
nt->data.nbt_intarray.ints = malloc(nt->data.nbt_intarray.count * 4);
nt->data.nbt_intarray.ints = xmalloc(nt->data.nbt_intarray.count * 4);
memcpy(nt->data.nbt_intarray.ints, nbt->data.nbt_intarray.ints, nt->data.nbt_intarray.count * 4);
}
for (size_t i = 0; i < nt->children_count; i++) {
@ -58,7 +61,7 @@ struct nbt_tag* cloneNBT(struct nbt_tag* nbt) {
}
int __recurReadNBT(struct nbt_tag** root, unsigned char* buffer, size_t buflen, int list) {
struct nbt_tag* cur = malloc(sizeof(struct nbt_tag));
struct nbt_tag* cur = xmalloc(sizeof(struct nbt_tag));
cur->name = NULL;
cur->children = NULL;
cur->children_count = 0;
@ -247,17 +250,17 @@ int __recurReadNBT(struct nbt_tag** root, unsigned char* buffer, size_t buflen,
r += nr;
if (!(st != NULL && st->id != NBT_TAG_END && buflen > 0)) continue;
if (cur->children == NULL) {
cur->children = malloc(sizeof(struct nbt_tag*));
cur->children = xmalloc(sizeof(struct nbt_tag*));
cur->children_count = 0;
} else {
cur->children = realloc(cur->children, sizeof(struct nbt_tag*) * (cur->children_count + 1));
cur->children = xrealloc(cur->children, sizeof(struct nbt_tag*) * (cur->children_count + 1));
}
cur->children[cur->children_count++] = st;
} while (st != NULL && st->id != NBT_TAG_END && buflen > 0);
} else if (cur->id == NBT_TAG_INTARRAY) {
if (buflen < 4) {
free(cur->name);
free(cur);
xfree(cur->name);
xfree(cur);
return 0;
}
memcpy(&cur->data.nbt_intarray.count, buffer, 4);
@ -266,11 +269,11 @@ int __recurReadNBT(struct nbt_tag** root, unsigned char* buffer, size_t buflen,
buflen -= 4;
r += 4;
if (buflen < (cur->data.nbt_intarray.count * 4) || cur->data.nbt_intarray.count <= 0) {
free(cur->name);
free(cur);
xfree(cur->name);
xfree(cur);
return 0;
}
cur->data.nbt_intarray.ints = malloc(cur->data.nbt_intarray.count * 4);
cur->data.nbt_intarray.ints = xmalloc(cur->data.nbt_intarray.count * 4);
memcpy(cur->data.nbt_intarray.ints, buffer, cur->data.nbt_intarray.count * 4);
buffer += cur->data.nbt_intarray.count * 4;
buflen -= cur->data.nbt_intarray.count * 4;
@ -319,7 +322,8 @@ ssize_t decompressNBT(void* data, size_t size, void** dest) {
int readNBT(struct nbt_tag** root, unsigned char* buffer, size_t buflen) {
if (buflen == 0) return 0;
return __recurReadNBT(root, buffer, buflen, 0);
int x = __recurReadNBT(root, buffer, buflen, 0);
return x;
}
int __recurWriteNBT(struct nbt_tag* root, unsigned char* buffer, size_t buflen, int list) {
@ -335,6 +339,7 @@ int __recurWriteNBT(struct nbt_tag* root, unsigned char* buffer, size_t buflen,
if (root->id > 0) {
int16_t sl = strlen(root->name);
memcpy(buffer, &sl, 2);
swapEndian(buffer, 2);
r += 2;
buffer += 2;
buflen -= 2;
@ -354,30 +359,35 @@ int __recurWriteNBT(struct nbt_tag* root, unsigned char* buffer, size_t buflen,
} else if (root->id == NBT_TAG_SHORT) {
if (buflen < 2) return 0;
memcpy(buffer, &root->data.nbt_short, 2);
swapEndian(buffer, 2);
r += 2;
buffer += 2;
buflen -= 2;
} else if (root->id == NBT_TAG_INT) {
if (buflen < 4) return 0;
memcpy(buffer, &root->data.nbt_int, 4);
swapEndian(buffer, 4);
r += 4;
buffer += 4;
buflen -= 4;
} else if (root->id == NBT_TAG_LONG) {
if (buflen < 8) return 0;
memcpy(buffer, &root->data.nbt_short, 8);
swapEndian(buffer, 8);
r += 8;
buffer += 8;
buflen -= 8;
} else if (root->id == NBT_TAG_FLOAT) {
if (buflen < 4) return 0;
memcpy(buffer, &root->data.nbt_float, 4);
swapEndian(buffer, 4);
r += 4;
buffer += 4;
buflen -= 4;
} else if (root->id == NBT_TAG_DOUBLE) {
if (buflen < 8) return 0;
memcpy(buffer, &root->data.nbt_double, 8);
swapEndian(buffer, 8);
r += 8;
buffer += 8;
buflen -= 8;
@ -396,6 +406,7 @@ int __recurWriteNBT(struct nbt_tag* root, unsigned char* buffer, size_t buflen,
if (buflen < 2) return 0;
uint16_t sl = strlen(root->data.nbt_string);
memcpy(buffer, &sl, 2);
swapEndian(buffer, 2);
r += 2;
buffer += 2;
buflen -= 2;
@ -408,6 +419,7 @@ int __recurWriteNBT(struct nbt_tag* root, unsigned char* buffer, size_t buflen,
if (buflen < 5) return 0;
buffer[0] = root->data.nbt_list.type;
memcpy(buffer, &root->data.nbt_list.count, 4);
swapEndian(buffer, 4);
r += 5;
buffer += 5;
buflen -= 5;
@ -420,15 +432,21 @@ int __recurWriteNBT(struct nbt_tag* root, unsigned char* buffer, size_t buflen,
}
} else if (root->id == NBT_TAG_COMPOUND) {
for (size_t i = 0; i < root->children_count; i++) {
int x = __recurWriteNBT(root->children[i], buffer, buflen, 1);
int x = __recurWriteNBT(root->children[i], buffer, buflen, 0);
r += x;
buffer += x;
buflen -= x;
if (buflen <= 0 || root->children[i]->id == NBT_TAG_END) break;
if (buflen <= 0) break;
}
if (buflen <= 1) return 0;
buffer[0] = 0;
buffer++;
buflen--;
r++;
} else if (root->id == NBT_TAG_INTARRAY) {
if (buflen < 4) return 0;
memcpy(buffer, &root->data.nbt_intarray.count, 4);
swapEndian(buffer, 4);
r += 4;
buffer += 4;
buflen -= 4;

View File

@ -20,6 +20,7 @@
#include <time.h>
#include "accept.h"
#include "packet.h"
#include "util.h"
void swapEndian(void* dou, size_t ss) {
uint8_t* pxs = (uint8_t*) dou;
@ -212,6 +213,50 @@ int readSlot(struct slot* slot, unsigned char* buffer, size_t buflen) {
return 5 + readNBT(&slot->nbt, buffer, buflen);
}
void duplicateSlot(struct slot* slot, struct slot* dup) {
if (slot == NULL) {
memset(dup, 0, sizeof(struct slot));
dup->item = -1;
return;
}
dup->item = slot->item;
dup->damage = slot->damage;
dup->itemCount = slot->itemCount;
dup->nbt = xmalloc(sizeof(struct nbt_tag));
duplicateNBT(slot->nbt, dup->nbt);
}
void duplicateNBT(struct nbt_tag* nbt, struct nbt_tag* dup) {
if (nbt == NULL) {
memset(dup, 0, sizeof(struct nbt_tag));
return;
}
dup->name = nbt->name == NULL ? NULL : xstrdup(nbt->name, 0);
dup->id = nbt->id;
dup->children_count = nbt->children_count;
if (dup->id == NBT_TAG_BYTE || dup->id == NBT_TAG_SHORT || dup->id == NBT_TAG_INT || dup->id == NBT_TAG_LONG || dup->id == NBT_TAG_FLOAT || dup->id == NBT_TAG_DOUBLE) {
memcpy(&dup->data, &nbt->data, sizeof(union nbt_data));
} else if (dup->id == NBT_TAG_BYTEARRAY) {
dup->data.nbt_bytearray.len = nbt->data.nbt_bytearray.len;
dup->data.nbt_bytearray.data = xmalloc(dup->data.nbt_bytearray.len);
memcpy(dup->data.nbt_bytearray.data, nbt->data.nbt_bytearray.data, dup->data.nbt_bytearray.len);
} else if (dup->id == NBT_TAG_STRING) {
dup->data.nbt_string = xstrdup(nbt->data.nbt_string, 0);
} else if (dup->id == NBT_TAG_LIST) {
dup->data.nbt_list.type = nbt->data.nbt_list.type;
dup->data.nbt_list.count = nbt->data.nbt_list.count;
} else if (dup->id == NBT_TAG_INTARRAY) {
dup->data.nbt_intarray.count = nbt->data.nbt_intarray.count;
dup->data.nbt_intarray.ints = xmalloc(4 * dup->data.nbt_intarray.count);
memcpy(dup->data.nbt_intarray.ints, nbt->data.nbt_intarray.ints, dup->data.nbt_bytearray.len);
}
dup->children = xmalloc(sizeof(struct nbt_tag*) * dup->children_count);
for (size_t i = 0; i < dup->children_count; i++) {
dup->children[i] = xmalloc(sizeof(struct nbt_tag));
duplicateNBT(nbt->children[i], dup->children[i]);
}
}
int writeSlot(struct slot* slot, unsigned char* buffer, size_t buflen) {
if (buflen < 2) return -1;
memcpy(buffer, &slot->item, 2);

View File

@ -40,11 +40,6 @@ struct entity_metadata {
#include "packet.h"
#define STATE_HANDSHAKE 0
#define STATE_STATUS 1
#define STATE_LOGIN 2
#define STATE_PLAY 3
void swapEndian(void* dou, size_t ss);
int getVarIntSize(int32_t input);
@ -65,6 +60,12 @@ int readString(char** output, unsigned char* buffer, size_t buflen);
int readSlot(struct slot* slot, unsigned char* buffer, size_t buflen);
int writeSlot(struct slot* slot, unsigned char* buffer, size_t buflen);
void duplicateSlot(struct slot* slot, struct slot* dup);
void duplicateNBT(struct nbt_tag* nbt, struct nbt_tag* dup);
ssize_t readPacket(struct conn* conn, unsigned char* buf, size_t buflen, struct packet* packet);
ssize_t writePacket(struct conn* conn, struct packet* packet);

View File

@ -8,9 +8,9 @@
#include "nbt.h"
#define STATE_HANDSHAKE 0
#define STATE_PLAY 1
#define STATE_STATUS 2
#define STATE_LOGIN 3
#define STATE_PLAY 3
#define STATE_STATUS 1
#define STATE_LOGIN 2
#define PKT_HANDSHAKE_SERVER_HANDSHAKE 0

View File

@ -10,6 +10,8 @@
#include "accept.h"
#include "util.h"
#include "network.h"
#include "inventory.h"
#include "xstring.h"
struct player* newPlayer(struct entity* entity, char* name, struct uuid uuid, struct conn* conn, uint8_t gamemode) {
struct player* player = xmalloc(sizeof(struct player));
@ -44,10 +46,15 @@ struct player* newPlayer(struct entity* entity, char* name, struct uuid uuid, st
memset(&player->digging_position, 0, sizeof(struct encpos));
player->digging = -1.;
player->digspeed = 0.;
newInventory(&player->inventory, INVTYPE_PLAYERINVENTORY, 0, 46);
player->inventory.player = player;
player->loadedChunks = new_collection(0);
return player;
}
void freePlayer(struct player* player) {
del_collection(player->loadedChunks);
freeInventory(&player->inventory);
xfree(player->name);
xfree(player);
}

View File

@ -43,6 +43,8 @@ struct player {
struct encpos digging_position;
float digging;
float digspeed;
struct inventory inventory;
struct collection* loadedChunks;
};
struct player* newPlayer(struct entity* entity, char* name, struct uuid, struct conn* conn, uint8_t gamemode);

View File

@ -71,10 +71,12 @@ int add_queue(struct queue* queue, void* data) {
memcpy(ndata, queue->data + queue->start, (queue->end - queue->start) * sizeof(void*));
} else {
memcpy(ndata, queue->data + queue->start, (orc - queue->start) * sizeof(void*));
memcpy(ndata + (orc - queue->start), queue->data + queue->end, (queue->start - queue->end) * sizeof(void*));
memcpy(ndata + (orc - queue->start), queue->data, (queue->end) * sizeof(void*));
}
xfree(queue->data);
queue->data = ndata;
queue->start = 0;
queue->end = orc;
} else if (queue->capacity == 0) {
} else {
while (queue->size == queue->capacity) {
@ -93,10 +95,12 @@ int add_queue(struct queue* queue, void* data) {
memcpy(ndata, queue->data + queue->start, (queue->end - queue->start) * sizeof(void*));
} else {
memcpy(ndata, queue->data + queue->start, (orc - queue->start) * sizeof(void*));
memcpy(ndata + (orc - queue->start), queue->data + queue->end, (queue->start - queue->end) * sizeof(void*));
memcpy(ndata + (orc - queue->start), queue->data, (queue->end) * sizeof(void*));
}
xfree(queue->data);
queue->data = ndata;
queue->start = 0;
queue->end = orc;
} else queue->end -= rp;
}
queue->size++;
@ -133,8 +137,8 @@ void* pop_nowait_queue(struct queue* queue) {
if (queue->mt) {
pthread_mutex_lock(&queue->data_mutex);
}
if (queue->size == 0) {
pthread_mutex_unlock(&queue->data_mutex);
if (queue->size <= 0) {
if (queue->mt) pthread_mutex_unlock(&queue->data_mutex);
return NULL;
}
void* data = queue->data[queue->start++];

View File

@ -54,12 +54,12 @@ void closeConn(struct work_param* param, struct conn* conn) {
}
despawnPlayer(conn->player->world, conn->player);
freeEntity(conn->player->entity);
freePlayer(conn->player);
}
if (conn->host_ip != NULL) xfree(conn->host_ip);
if (conn->readBuffer != NULL) xfree(conn->readBuffer);
if (conn->writeBuffer != NULL) xfree(conn->writeBuffer);
xfree(conn);
}
int handleRead(struct conn* conn, struct work_param* param, int fd) {
@ -91,7 +91,7 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
rep.id = PKT_STATUS_CLIENT_RESPONSE;
rep.data.status_client.response.json_response = xmalloc(1000);
rep.data.status_client.response.json_response[999] = 0;
snprintf(rep.data.status_client.response.json_response, 999, "{\"version\":{\"name\":\"1.11.2\",\"protocol\":%i},\"players\":{\"max\":%i,\"online\":%i},\"description\":{\"text\":\"%s\"}}", MC_PROTOCOL_VERSION, max_players, 0, motd);
snprintf(rep.data.status_client.response.json_response, 999, "{\"version\":{\"name\":\"1.11\",\"protocol\":%i},\"players\":{\"max\":%i,\"online\":%i},\"description\":{\"text\":\"%s\"}}", MC_PROTOCOL_VERSION, max_players, 0, motd);
if (writePacket(conn, &rep) < 0) goto rete;
xfree(rep.data.status_client.response.json_response);
} else if (inp->id == PKT_STATUS_SERVER_PING) {
@ -124,7 +124,7 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
xfree(rep.data.login_client.loginsuccess.uuid);
conn->state = STATE_PLAY;
struct entity* ep = newEntity(nextEntityID++, (float) overworld->spawnpos.x + .5, (float) overworld->spawnpos.y, (float) overworld->spawnpos.z + .5, ENT_PLAYER, 0., 0.);
struct player* player = newPlayer(ep, xstrdup(inp->data.login_client.loginsuccess.username, 0), uuid, conn, 0); // TODO default gamemode
struct player* player = newPlayer(ep, xstrdup(rep.data.login_client.loginsuccess.username, 0), uuid, conn, 1); // TODO default gamemode
conn->player = player;
add_collection(players, player);
rep.id = PKT_PLAY_CLIENT_JOINGAME;
@ -151,7 +151,7 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
memcpy(&rep.data.play_client.spawnposition.location, &overworld->spawnpos, sizeof(struct encpos));
if (writePacket(conn, &rep) < 0) goto rete;
rep.id = PKT_PLAY_CLIENT_PLAYERABILITIES;
rep.data.play_client.playerabilities.flags = 0x4; // TODO: allows flying, remove
rep.data.play_client.playerabilities.flags = 0x4 | 0x8; // TODO: allows flying, remove
rep.data.play_client.playerabilities.flying_speed = 0.05;
rep.data.play_client.playerabilities.field_of_view_modifier = .1;
if (writePacket(conn, &rep) < 0) goto rete;
@ -208,57 +208,35 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
if (ent == NULL || entity_distsq(ent, player->entity) > 16384.) continue;
if (ent->type == ENT_PLAYER) {
if (ent->data.player.player != player) {
rep.id = PKT_PLAY_CLIENT_SPAWNPLAYER;
rep.data.play_client.spawnplayer.entity_id = ent->id;
memcpy(&rep.data.play_client.spawnplayer.player_uuid, &ent->data.player.player->uuid, sizeof(struct uuid));
rep.data.play_client.spawnplayer.x = ent->x;
rep.data.play_client.spawnplayer.y = ent->y;
rep.data.play_client.spawnplayer.z = ent->z;
rep.data.play_client.spawnplayer.yaw = (ent->yaw / 360.) * 256.;
rep.data.play_client.spawnplayer.pitch = (ent->pitch / 360.) * 256.;
rep.data.play_client.spawnplayer.metadata.metadata = NULL;
rep.data.play_client.spawnplayer.metadata.metadata_size = 0;
writeMetadata(ent, &rep.data.play_client.spawnplayer.metadata.metadata, &rep.data.play_client.spawnplayer.metadata.metadata_size);
if (writePacket(conn, &rep) < 0) goto rete;
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_SPAWNPLAYER;
pkt->data.play_client.spawnplayer.entity_id = player->entity->id;
memcpy(&pkt->data.play_client.spawnplayer.player_uuid, &player->entity->data.player.player->uuid, sizeof(struct uuid));
pkt->data.play_client.spawnplayer.x = player->entity->x;
pkt->data.play_client.spawnplayer.y = player->entity->y;
pkt->data.play_client.spawnplayer.z = player->entity->z;
pkt->data.play_client.spawnplayer.yaw = (player->entity->yaw / 360.) * 256.;
pkt->data.play_client.spawnplayer.pitch = (player->entity->pitch / 360.) * 256.;
writeMetadata(player->entity, &pkt->data.play_client.spawnplayer.metadata.metadata, &pkt->data.play_client.spawnplayer.metadata.metadata_size);
add_queue(ent->data.player.player->conn->outgoingPacket, pkt);
flush_outgoing(ent->data.player.player);
loadPlayer(player, ent->data.player.player);
loadPlayer(ent->data.player.player, player);
}
}
}
char bct[256];
snprintf(bct, 256, "%s has joined the server!", player->name);
broadcast(bct);
for (int x = -9; x < 10; x++) {
for (int z = -9; z < 10; z++) {
struct chunk* ch = getChunk(overworld, x + (int32_t) ep->x / 16, z + (int32_t) ep->z / 16);
if (ch != NULL) {
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_CHUNKDATA;
pkt->data.play_client.chunkdata.data = ch;
pkt->data.play_client.chunkdata.ground_up_continuous = 1;
pkt->data.play_client.chunkdata.number_of_block_entities = 0;
pkt->data.play_client.chunkdata.block_entities = NULL;
add_queue(player->conn->outgoingPacket, pkt);
flush_outgoing(player);
}
}
}
/*for (int x = -9; x < 10; x++) {
for (int z = -9; z < 10; z++) {
struct chunk* ch = getChunk(overworld, x + (int32_t) ep->x / 16, z + (int32_t) ep->z / 16);
if (ch != NULL) {
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_CHUNKDATA;
pkt->data.play_client.chunkdata.data = ch;
pkt->data.play_client.chunkdata.ground_up_continuous = 1;
pkt->data.play_client.chunkdata.number_of_block_entities = 0;
pkt->data.play_client.chunkdata.block_entities = NULL;
add_queue(player->conn->outgoingPacket, pkt);
flush_outgoing(player);
}
}
}*/
}
}
} else if (conn->state == STATE_PLAY) {
if (inp->id == PKT_PLAY_SERVER_KEEPALIVE) {
if (rep.data.play_client.keepalive.keep_alive_id == conn->player->nextKeepAlive) {
if (inp->data.play_server.keepalive.keep_alive_id == conn->player->nextKeepAlive) {
conn->player->nextKeepAlive = 0;
}
} else if (inp->id == PKT_PLAY_SERVER_CHATMESSAGE) {
@ -305,7 +283,7 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
} else if (inp->id == PKT_PLAY_SERVER_PLAYERDIGGING) {
if (inp->data.play_server.playerdigging.status == 0) {
float hard = block_infos[getBlockWorld(conn->player->world, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z)].hardness;
if (hard > 0.) {
if (hard > 0. && conn->player->gamemode == 0) {
conn->player->digging = 0.;
memcpy(&conn->player->digging_position, &inp->data.play_server.playerdigging.location, sizeof(struct encpos));
BEGIN_BROADCAST_EXCEPT_DIST(conn->player, conn->player->entity, 128.)
@ -317,7 +295,7 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
add_queue(bc_player->conn->outgoingPacket, pkt);
flush_outgoing (bc_player);
END_BROADCAST
} else if (hard == 0.) {
} else if (hard == 0. || conn->player->gamemode == 1) {
setBlockWorld(conn->player->world, 0, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z);
conn->player->digging = -1.;
memset(&conn->player->digging_position, 0, sizeof(struct encpos));
@ -338,6 +316,32 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
flush_outgoing (bc_player);
END_BROADCAST
}
} else if (inp->id == PKT_PLAY_SERVER_CREATIVEINVENTORYACTION) {
if (inp->data.play_server.creativeinventoryaction.clicked_item.item >= 0 && inp->data.play_server.creativeinventoryaction.slot == -1) {
//drop item
} else {
int16_t sl = inp->data.play_server.creativeinventoryaction.slot;
setInventorySlot(&conn->player->inventory, &inp->data.play_server.creativeinventoryaction.clicked_item, sl);
onInventoryUpdate(&conn->player->inventory, sl);
}
} else if (inp->id == PKT_PLAY_SERVER_HELDITEMCHANGE) {
if (inp->data.play_server.helditemchange.slot >= 0 && inp->data.play_server.helditemchange.slot < 9) {
conn->player->currentItem = inp->data.play_server.helditemchange.slot;
onInventoryUpdate(&conn->player->inventory, conn->player->currentItem + 36);
}
} else if (inp->id == PKT_PLAY_SERVER_ENTITYACTION) {
if (inp->data.play_server.entityaction.action_id == 0) conn->player->entity->sneaking = 1;
else if (inp->data.play_server.entityaction.action_id == 1) conn->player->entity->sneaking = 0;
else if (inp->data.play_server.entityaction.action_id == 3) conn->player->entity->sprinting = 1;
else if (inp->data.play_server.entityaction.action_id == 4) conn->player->entity->sprinting = 0;
BEGIN_BROADCAST_EXCEPT_DIST(conn->player, conn->player->entity, 128.)
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_ENTITYMETADATA;
pkt->data.play_client.entitymetadata.entity_id = conn->player->entity->id;
writeMetadata(conn->player->entity, &pkt->data.play_client.entitymetadata.metadata.metadata, &pkt->data.play_client.entitymetadata.metadata.metadata_size);
add_queue(bc_player->conn->outgoingPacket, pkt);
flush_outgoing (bc_player);
END_BROADCAST
}
//printf("recv: %i\n", inp->id);
}

View File

@ -213,7 +213,22 @@ struct chunk* getChunk(struct world* world, int16_t x, int16_t z) {
}
void unloadChunk(struct world* world, struct chunk* chunk) {
chunk->unload = 1;
//TODO: save chunk
int16_t rx = chunk->x >> 5;
int16_t rz = chunk->z >> 5;
pthread_rwlock_rdlock(&world->regions->data_mutex);
for (size_t i = 0; i < world->regions->size; i++) {
if (world->regions->data[i] != NULL && ((struct region*) world->regions->data[i])->x == rx && ((struct region*) world->regions->data[i])->z == rz) {
struct region* r = ((struct region*) world->regions->data[i]);
r->loaded[chunk->z & 0x1F][chunk->x & 0x1F] = 0;
r->chunks[chunk->z & 0x1F][chunk->x & 0x1F] = 0;
freeChunk(chunk);
pthread_rwlock_unlock(&world->regions->data_mutex);
return;
}
}
pthread_rwlock_unlock(&world->regions->data_mutex);
}
int getBiome(struct world* world, int32_t x, int32_t z) {
@ -240,12 +255,19 @@ struct chunk* newChunk(int16_t x, int16_t z) {
chunk->z = z;
for (int i = 0; i < 16; i++)
chunk->empty[i] = 1;
chunk->unload = 0;
chunk->playersLoaded = 0;
return chunk;
}
void freeChunk(struct chunk* chunk) {
if (chunk->skyLight != NULL) xfree(chunk->skyLight);
if (chunk->tileEntities != NULL) {
for (size_t i = 0; i < chunk->tileEntity_count; i++) {
freeNBT(chunk->tileEntities[i]);
xfree(chunk->tileEntities[i]);
}
xfree(chunk->tileEntities);
}
xfree(chunk);
}
struct region* newRegion(char* path, int16_t x, int16_t z) {

View File

@ -35,12 +35,13 @@ struct chunk {
unsigned char blockLight[256][16][8]; // y, z, x(4-bit)
unsigned char* skyLight; // if non-NULL, points to a 2048-byte nibble-array.
int empty[16];
int unload;
int lightpopulated;
int terrainpopulated;
uint64_t inhabitedticks;
uint16_t heightMap[16][16]; // z, x
struct nbt** tileEntities;
size_t tileEntity_count;
struct nbt_tag** tileEntities;
uint32_t playersLoaded;
//TODO: tileTicks
};