2016-06-25 08:34:36 +00:00
|
|
|
/*
|
|
|
|
* player.c
|
|
|
|
*
|
|
|
|
* Created on: Jun 24, 2016
|
|
|
|
* Author: root
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "accept.h"
|
2019-04-15 16:50:10 +00:00
|
|
|
#include "basin/packet.h"
|
2019-04-14 20:45:32 +00:00
|
|
|
#include <basin/network.h>
|
|
|
|
#include <basin/inventory.h>
|
|
|
|
#include <basin/queue.h>
|
|
|
|
#include <basin/tileentity.h>
|
|
|
|
#include <basin/server.h>
|
|
|
|
#include <basin/profile.h>
|
|
|
|
#include <basin/basin.h>
|
|
|
|
#include <basin/anticheat.h>
|
|
|
|
#include <basin/command.h>
|
|
|
|
#include <basin/smelting.h>
|
|
|
|
#include <basin/crafting.h>
|
|
|
|
#include <basin/plugin.h>
|
|
|
|
#include <avuna/string.h>
|
2016-12-30 08:12:04 +00:00
|
|
|
#include <math.h>
|
2016-06-25 08:34:36 +00:00
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
struct player* player_new(struct entity* entity, char* name, struct uuid uuid, struct conn* conn, uint8_t gamemode) {
|
2016-06-25 08:34:36 +00:00
|
|
|
struct player* player = xmalloc(sizeof(struct player));
|
2016-12-24 23:09:16 +00:00
|
|
|
entity->data.player.player = player;
|
2016-06-25 08:34:36 +00:00
|
|
|
player->entity = entity;
|
|
|
|
player->conn = conn;
|
|
|
|
player->name = name;
|
|
|
|
player->uuid = uuid;
|
|
|
|
player->gamemode = gamemode;
|
|
|
|
player->currentItem = 0;
|
|
|
|
player->ping = 0;
|
|
|
|
player->stage = 0;
|
2016-08-16 07:18:30 +00:00
|
|
|
player->invulnerable = 0;
|
|
|
|
player->walkSpeed = 0;
|
|
|
|
player->flySpeed = 0;
|
|
|
|
player->flying = 0;
|
|
|
|
player->xpseed = 0;
|
|
|
|
player->xptotal = 0;
|
|
|
|
player->xplevel = 0;
|
|
|
|
player->score = 0;
|
|
|
|
player->saturation = 0.;
|
|
|
|
player->sleeping = 0;
|
|
|
|
player->fire = 0;
|
2017-01-03 19:18:52 +00:00
|
|
|
//TODO: enderitems
|
2016-12-29 08:00:22 +00:00
|
|
|
player->food = 20;
|
2016-08-16 07:18:30 +00:00
|
|
|
player->foodTick = 0;
|
2016-12-24 23:09:16 +00:00
|
|
|
player->nextKeepAlive = 0;
|
2016-12-28 10:18:41 +00:00
|
|
|
player->inHand = NULL;
|
2016-12-24 23:09:16 +00:00
|
|
|
memset(&player->digging_position, 0, sizeof(struct encpos));
|
|
|
|
player->digging = -1.;
|
|
|
|
player->digspeed = 0.;
|
2016-12-28 10:18:41 +00:00
|
|
|
player->inventory = xmalloc(sizeof(struct inventory));
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_new(player->inventory, INVTYPE_PLAYERINVENTORY, 0, 46);
|
2016-12-26 08:31:26 +00:00
|
|
|
player->openInv = NULL;
|
2019-04-14 20:45:32 +00:00
|
|
|
hashmap_put(player->inventory->players, player->entity->id, player);
|
2017-01-01 09:39:37 +00:00
|
|
|
player->loadedChunks = new_hashmap(1, 1);
|
2017-09-10 03:00:32 +00:00
|
|
|
player->loadedEntities = new_hashmap(1, 0);
|
2016-12-26 08:31:26 +00:00
|
|
|
player->incomingPacket = new_queue(0, 1);
|
|
|
|
player->outgoingPacket = new_queue(0, 1);
|
2016-12-28 10:18:41 +00:00
|
|
|
player->defunct = 0;
|
2016-12-29 08:00:22 +00:00
|
|
|
player->lastSwing = tick_counter;
|
2016-12-30 03:18:53 +00:00
|
|
|
player->foodTimer = 0;
|
2016-12-30 10:03:03 +00:00
|
|
|
struct timespec ts;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
2017-01-03 19:51:34 +00:00
|
|
|
player->reachDistance = 6.f;
|
2016-12-30 08:12:04 +00:00
|
|
|
player->spawnedIn = 0;
|
|
|
|
player->llTick = 0;
|
2016-12-30 08:48:35 +00:00
|
|
|
player->triggerRechunk = 0;
|
2017-01-02 07:33:14 +00:00
|
|
|
player->chunksSent = 0;
|
2017-01-03 19:18:52 +00:00
|
|
|
player->world = NULL;
|
2017-03-05 00:11:19 +00:00
|
|
|
player->itemUseDuration = 0;
|
|
|
|
player->itemUseHand = 0;
|
|
|
|
player->chunkRequests = new_queue(0, 1);
|
2017-03-05 18:22:00 +00:00
|
|
|
player->foodExhaustion = 0.;
|
2017-03-11 20:02:53 +00:00
|
|
|
player->lastTeleportID = 0;
|
2016-06-25 08:34:36 +00:00
|
|
|
return player;
|
|
|
|
}
|
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
void player_send_entity_move(struct player* player, struct entity* ent) {
|
2017-01-03 19:18:52 +00:00
|
|
|
double md = entity_distsq_block(ent, ent->lx, ent->ly, ent->lz);
|
|
|
|
double mp = (ent->yaw - ent->lyaw) * (ent->yaw - ent->lyaw) + (ent->pitch - ent->lpitch) * (ent->pitch - ent->lpitch);
|
2017-03-05 00:11:19 +00:00
|
|
|
|
2017-01-03 19:18:52 +00:00
|
|
|
//printf("mp = %f, md = %f\n", mp, md);
|
|
|
|
if ((md > .001 || mp > .01 || ent->type == ENT_PLAYER)) {
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
2017-03-11 20:02:53 +00:00
|
|
|
int ft = tick_counter % 200 == 0 || (ent->type == ENT_PLAYER && ent->data.player.player->lastTeleportID != 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (!ft && md <= .001 && mp <= .01) {
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITY;
|
|
|
|
pkt->data.play_client.entity.entity_id = ent->id;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
} else if (!ft && mp > .01 && md <= .001) {
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITYLOOK;
|
|
|
|
pkt->data.play_client.entitylook.entity_id = ent->id;
|
|
|
|
pkt->data.play_client.entitylook.yaw = (uint8_t)((ent->yaw / 360.) * 256.);
|
|
|
|
pkt->data.play_client.entitylook.pitch = (uint8_t)((ent->pitch / 360.) * 256.);
|
|
|
|
pkt->data.play_client.entitylook.on_ground = ent->onGround;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITYHEADLOOK;
|
|
|
|
pkt->data.play_client.entityheadlook.entity_id = ent->id;
|
|
|
|
pkt->data.play_client.entityheadlook.head_yaw = (uint8_t)((ent->yaw / 360.) * 256.);
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
} else if (!ft && mp <= .01 && md > .001 && md < 64.) {
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITYRELATIVEMOVE;
|
|
|
|
pkt->data.play_client.entityrelativemove.entity_id = ent->id;
|
|
|
|
pkt->data.play_client.entityrelativemove.delta_x = (int16_t)((ent->x * 32. - ent->lx * 32.) * 128.);
|
|
|
|
pkt->data.play_client.entityrelativemove.delta_y = (int16_t)((ent->y * 32. - ent->ly * 32.) * 128.);
|
|
|
|
pkt->data.play_client.entityrelativemove.delta_z = (int16_t)((ent->z * 32. - ent->lz * 32.) * 128.);
|
|
|
|
pkt->data.play_client.entityrelativemove.on_ground = ent->onGround;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
} else if (!ft && mp > .01 && md > .001 && md < 64.) {
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITYLOOKANDRELATIVEMOVE;
|
|
|
|
pkt->data.play_client.entitylookandrelativemove.entity_id = ent->id;
|
|
|
|
pkt->data.play_client.entitylookandrelativemove.delta_x = (int16_t)((ent->x * 32. - ent->lx * 32.) * 128.);
|
|
|
|
pkt->data.play_client.entitylookandrelativemove.delta_y = (int16_t)((ent->y * 32. - ent->ly * 32.) * 128.);
|
|
|
|
pkt->data.play_client.entitylookandrelativemove.delta_z = (int16_t)((ent->z * 32. - ent->lz * 32.) * 128.);
|
|
|
|
pkt->data.play_client.entitylookandrelativemove.yaw = (uint8_t)((ent->yaw / 360.) * 256.);
|
|
|
|
pkt->data.play_client.entitylookandrelativemove.pitch = (uint8_t)((ent->pitch / 360.) * 256.);
|
|
|
|
pkt->data.play_client.entitylookandrelativemove.on_ground = ent->onGround;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITYHEADLOOK;
|
|
|
|
pkt->data.play_client.entityheadlook.entity_id = ent->id;
|
|
|
|
pkt->data.play_client.entityheadlook.head_yaw = (uint8_t)((ent->yaw / 360.) * 256.);
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
} else {
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITYTELEPORT;
|
|
|
|
pkt->data.play_client.entityteleport.entity_id = ent->id;
|
|
|
|
pkt->data.play_client.entityteleport.x = ent->x;
|
|
|
|
pkt->data.play_client.entityteleport.y = ent->y;
|
|
|
|
pkt->data.play_client.entityteleport.z = ent->z;
|
|
|
|
pkt->data.play_client.entityteleport.yaw = (uint8_t)((ent->yaw / 360.) * 256.);
|
|
|
|
pkt->data.play_client.entityteleport.pitch = (uint8_t)((ent->pitch / 360.) * 256.);
|
|
|
|
pkt->data.play_client.entityteleport.on_ground = ent->onGround;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITYHEADLOOK;
|
|
|
|
pkt->data.play_client.entityheadlook.entity_id = ent->id;
|
|
|
|
pkt->data.play_client.entityheadlook.head_yaw = (uint8_t)((ent->yaw / 360.) * 256.);
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void player_receive_packet(struct player* player, struct packet* inp) {
|
|
|
|
if (player->entity->health <= 0. && inp->id != PKT_PLAY_SERVER_KEEPALIVE && inp->id != PKT_PLAY_SERVER_CLIENTSTATUS) goto cont;
|
|
|
|
if (inp->id == PKT_PLAY_SERVER_KEEPALIVE) {
|
|
|
|
if (inp->data.play_server.keepalive.keep_alive_id == player->nextKeepAlive) {
|
|
|
|
player->nextKeepAlive = 0;
|
|
|
|
}
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_CHATMESSAGE) {
|
|
|
|
char* msg = inp->data.play_server.chatmessage.message;
|
2017-01-04 06:24:16 +00:00
|
|
|
if (ac_chat(player, msg)) goto cont;
|
2017-01-03 19:18:52 +00:00
|
|
|
if (startsWith(msg, "/")) {
|
|
|
|
callCommand(player, msg + 1);
|
|
|
|
} else {
|
|
|
|
size_t s = strlen(msg) + 512;
|
|
|
|
char* rs = xmalloc(s);
|
|
|
|
snprintf(rs, s, "{\"text\": \"<%s>: %s\"}", player->name, replace(replace(msg, "\\", "\\\\"), "\"", "\\\""));
|
|
|
|
printf("<CHAT> <%s>: %s\n", player->name, msg);
|
|
|
|
BEGIN_BROADCAST (players)
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_CHATMESSAGE;
|
|
|
|
pkt->data.play_client.chatmessage.position = 0;
|
|
|
|
pkt->data.play_client.chatmessage.json_data = xstrdup(rs, 0);
|
|
|
|
add_queue(bc_player->outgoingPacket, pkt);
|
|
|
|
END_BROADCAST (players)
|
|
|
|
xfree(rs);
|
|
|
|
}
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_PLAYER) {
|
2017-03-11 20:02:53 +00:00
|
|
|
if (player->lastTeleportID != 0) goto cont;
|
2017-01-03 20:31:57 +00:00
|
|
|
struct pkt_play_server_player pkt = inp->data.play_server.player;
|
2017-01-03 23:28:42 +00:00
|
|
|
if (ac_tick(player, pkt.on_ground)) goto cont;
|
2017-01-03 19:18:52 +00:00
|
|
|
player->entity->lx = player->entity->x;
|
|
|
|
player->entity->ly = player->entity->y;
|
|
|
|
player->entity->lz = player->entity->z;
|
|
|
|
player->entity->lyaw = player->entity->yaw;
|
|
|
|
player->entity->lpitch = player->entity->pitch;
|
2017-01-03 20:31:57 +00:00
|
|
|
player->entity->onGround = pkt.on_ground;
|
2017-01-03 19:18:52 +00:00
|
|
|
BEGIN_BROADCAST(player->entity->loadingPlayers)
|
2019-04-17 13:38:46 +00:00
|
|
|
player_send_entity_move(bc_player, player->entity);
|
2017-01-03 19:18:52 +00:00
|
|
|
END_BROADCAST(player->entity->loadingPlayers)
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_PLAYERPOSITION) {
|
2017-03-11 20:02:53 +00:00
|
|
|
if (player->lastTeleportID != 0) goto cont;
|
2017-01-03 20:31:57 +00:00
|
|
|
struct pkt_play_server_playerposition pkt = inp->data.play_server.playerposition;
|
2017-01-03 23:28:42 +00:00
|
|
|
if (ac_tick(player, pkt.on_ground)) goto cont;
|
|
|
|
if (ac_tickpos(player, pkt.x, pkt.feet_y, pkt.z)) goto cont;
|
2017-01-03 20:31:57 +00:00
|
|
|
|
2017-01-03 19:18:52 +00:00
|
|
|
double lx = player->entity->x;
|
|
|
|
double ly = player->entity->y;
|
|
|
|
double lz = player->entity->z;
|
|
|
|
player->entity->lyaw = player->entity->yaw;
|
|
|
|
player->entity->lpitch = player->entity->pitch;
|
2017-02-05 20:51:29 +00:00
|
|
|
double mx = pkt.x - lx;
|
|
|
|
double my = pkt.feet_y - ly;
|
|
|
|
double mz = pkt.z - lz;
|
|
|
|
if (moveEntity(player->entity, &mx, &my, &mz, .05)) {
|
2019-04-17 13:38:46 +00:00
|
|
|
player_teleport(player, lx, ly, lz);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else {
|
|
|
|
player->entity->lx = lx;
|
|
|
|
player->entity->ly = ly;
|
|
|
|
player->entity->lz = lz;
|
|
|
|
}
|
2017-01-03 20:31:57 +00:00
|
|
|
player->entity->onGround = pkt.on_ground;
|
2017-01-03 19:18:52 +00:00
|
|
|
float dx = player->entity->x - player->entity->lx;
|
|
|
|
float dy = player->entity->y - player->entity->ly;
|
|
|
|
float dz = player->entity->z - player->entity->lz;
|
|
|
|
float d3 = dx * dx + dy * dy + dz * dz;
|
|
|
|
if (!player->spawnedIn && d3 > 0.00000001) player->spawnedIn = 1;
|
|
|
|
if (d3 > 5. * 5. * 5.) {
|
2019-04-17 13:38:46 +00:00
|
|
|
player_teleport(player, player->entity->lx, player->entity->ly, player->entity->lz);
|
|
|
|
player_kick(player, "You attempted to move too fast!");
|
2017-01-03 19:18:52 +00:00
|
|
|
} else {
|
|
|
|
BEGIN_BROADCAST(player->entity->loadingPlayers)
|
2019-04-17 13:38:46 +00:00
|
|
|
player_send_entity_move(bc_player, player->entity);
|
2017-01-03 19:18:52 +00:00
|
|
|
END_BROADCAST(player->entity->loadingPlayers)
|
|
|
|
}
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_PLAYERLOOK) {
|
2017-03-11 20:02:53 +00:00
|
|
|
if (player->lastTeleportID != 0) goto cont;
|
2017-01-03 20:31:57 +00:00
|
|
|
struct pkt_play_server_playerlook pkt = inp->data.play_server.playerlook;
|
2017-01-03 23:28:42 +00:00
|
|
|
if (ac_tick(player, pkt.on_ground)) goto cont;
|
|
|
|
if (ac_ticklook(player, pkt.yaw, pkt.pitch)) goto cont;
|
2017-01-03 20:31:57 +00:00
|
|
|
|
2017-01-03 19:18:52 +00:00
|
|
|
player->entity->lx = player->entity->x;
|
|
|
|
player->entity->ly = player->entity->y;
|
|
|
|
player->entity->lz = player->entity->z;
|
|
|
|
player->entity->lyaw = player->entity->yaw;
|
|
|
|
player->entity->lpitch = player->entity->pitch;
|
2017-01-03 20:31:57 +00:00
|
|
|
player->entity->onGround = pkt.on_ground;
|
|
|
|
player->entity->yaw = pkt.yaw;
|
|
|
|
player->entity->pitch = pkt.pitch;
|
2017-01-03 19:18:52 +00:00
|
|
|
BEGIN_BROADCAST(player->entity->loadingPlayers)
|
2019-04-17 13:38:46 +00:00
|
|
|
player_send_entity_move(bc_player, player->entity);
|
2017-01-03 19:18:52 +00:00
|
|
|
END_BROADCAST(player->entity->loadingPlayers)
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_PLAYERPOSITIONANDLOOK) {
|
2017-03-11 20:02:53 +00:00
|
|
|
if (player->lastTeleportID != 0) goto cont;
|
2017-01-03 20:31:57 +00:00
|
|
|
struct pkt_play_server_playerpositionandlook pkt = inp->data.play_server.playerpositionandlook;
|
2017-01-03 23:28:42 +00:00
|
|
|
if (ac_tick(player, pkt.on_ground)) goto cont;
|
|
|
|
if (ac_tickpos(player, pkt.x, pkt.feet_y, pkt.z)) goto cont;
|
|
|
|
if (ac_ticklook(player, pkt.yaw, pkt.pitch)) goto cont;
|
2017-01-03 19:18:52 +00:00
|
|
|
double lx = player->entity->x;
|
|
|
|
double ly = player->entity->y;
|
|
|
|
double lz = player->entity->z;
|
|
|
|
player->entity->lyaw = player->entity->yaw;
|
|
|
|
player->entity->lpitch = player->entity->pitch;
|
2017-02-05 20:51:29 +00:00
|
|
|
double mx = pkt.x - lx;
|
|
|
|
double my = pkt.feet_y - ly;
|
|
|
|
double mz = pkt.z - lz;
|
|
|
|
if (moveEntity(player->entity, &mx, &my, &mz, .05)) {
|
2019-04-17 13:38:46 +00:00
|
|
|
player_teleport(player, lx, ly, lz);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else {
|
|
|
|
player->entity->lx = lx;
|
|
|
|
player->entity->ly = ly;
|
|
|
|
player->entity->lz = lz;
|
|
|
|
}
|
2017-01-03 20:31:57 +00:00
|
|
|
player->entity->onGround = pkt.on_ground;
|
|
|
|
player->entity->yaw = pkt.yaw;
|
|
|
|
player->entity->pitch = pkt.pitch;
|
2017-01-03 19:18:52 +00:00
|
|
|
float dx = player->entity->x - player->entity->lx;
|
|
|
|
float dy = player->entity->y - player->entity->ly;
|
|
|
|
float dz = player->entity->z - player->entity->lz;
|
|
|
|
float d3 = dx * dx + dy * dy + dz * dz;
|
|
|
|
if (!player->spawnedIn && d3 > 0.00000001) player->spawnedIn = 1;
|
|
|
|
if (d3 > 5. * 5. * 5.) {
|
2019-04-17 13:38:46 +00:00
|
|
|
player_teleport(player, player->entity->lx, player->entity->ly, player->entity->lz);
|
2017-01-03 19:18:52 +00:00
|
|
|
printf("Player '%s' attempted to move too fast!\n", player->name);
|
|
|
|
} else {
|
|
|
|
BEGIN_BROADCAST(player->entity->loadingPlayers)
|
2019-04-17 13:38:46 +00:00
|
|
|
player_send_entity_move(bc_player, player->entity);
|
2017-01-03 19:18:52 +00:00
|
|
|
END_BROADCAST(player->entity->loadingPlayers)
|
|
|
|
}
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_ANIMATION) {
|
|
|
|
player->lastSwing = tick_counter;
|
|
|
|
BEGIN_BROADCAST_EXCEPT_DIST(player, player->entity, CHUNK_VIEW_DISTANCE * 16.)
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_ANIMATION;
|
|
|
|
pkt->data.play_client.animation.entity_id = player->entity->id;
|
|
|
|
pkt->data.play_client.animation.animation = inp->data.play_server.animation.hand == 0 ? 0 : 3;
|
|
|
|
add_queue(bc_player->outgoingPacket, pkt);
|
|
|
|
END_BROADCAST(player->world->players)
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_PLAYERDIGGING) {
|
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ci = inventory_get(player, player->inventory, player->currentItem + 36);
|
2017-01-03 19:18:52 +00:00
|
|
|
struct item_info* ii = ci == NULL ? NULL : getItemInfo(ci->item);
|
|
|
|
if (inp->data.play_server.playerdigging.status == 0) {
|
|
|
|
if (entity_dist_block(player->entity, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z) > player->reachDistance) {
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
goto cont;
|
|
|
|
}
|
2019-04-17 14:45:14 +00:00
|
|
|
struct block_info* bi = getBlockInfo(world_get_block(player->world, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z));
|
2017-01-03 19:18:52 +00:00
|
|
|
if (bi == NULL) {
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
float hard = bi->hardness;
|
|
|
|
if (hard > 0. && player->gamemode == 0) {
|
|
|
|
player->digging = 0.;
|
|
|
|
memcpy(&player->digging_position, &inp->data.play_server.playerdigging.location, sizeof(struct encpos));
|
|
|
|
BEGIN_BROADCAST_EXCEPT_DIST(player, player->entity, CHUNK_VIEW_DISTANCE * 16.)
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_BLOCKBREAKANIMATION;
|
|
|
|
pkt->data.play_client.blockbreakanimation.entity_id = player->entity->id;
|
|
|
|
memcpy(&pkt->data.play_server.playerdigging.location, &player->digging_position, sizeof(struct encpos));
|
|
|
|
pkt->data.play_client.blockbreakanimation.destroy_stage = 0;
|
|
|
|
add_queue(bc_player->outgoingPacket, pkt);
|
|
|
|
END_BROADCAST(player->world->players)
|
|
|
|
} else if (hard == 0. || player->gamemode == 1) {
|
|
|
|
if (player->gamemode == 1) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* slot = inventory_get(player, player->inventory, 36 + player->currentItem);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (slot != NULL && (slot->item == ITM_SWORDWOOD || slot->item == ITM_SWORDGOLD || slot->item == ITM_SWORDSTONE || slot->item == ITM_SWORDIRON || slot->item == ITM_SWORDDIAMOND)) {
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 14:45:14 +00:00
|
|
|
block blk = world_get_block(player->world, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z);
|
2017-01-03 19:18:52 +00:00
|
|
|
int nb = 0;
|
|
|
|
if (ii != NULL && ii->onItemBreakBlock != NULL) {
|
|
|
|
if ((*ii->onItemBreakBlock)(player->world, player, player->currentItem + 36, ci, player->digging_position.x, player->digging_position.y, player->digging_position.z)) {
|
2019-04-17 14:45:14 +00:00
|
|
|
world_set_block(player->world, blk, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
2017-01-03 19:18:52 +00:00
|
|
|
nb = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!nb) {
|
2019-04-17 14:45:14 +00:00
|
|
|
if (world_set_block(player->world, 0, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z)) {
|
|
|
|
world_set_block(player->world, blk, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z);
|
2017-03-11 20:02:53 +00:00
|
|
|
} else {
|
|
|
|
player->foodExhaustion += 0.005;
|
|
|
|
if (player->gamemode != 1) dropBlockDrops(player->world, blk, player, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z);
|
|
|
|
}
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
player->digging = -1.;
|
|
|
|
memset(&player->digging_position, 0, sizeof(struct encpos));
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
} else if (inp->data.play_server.playerdigging.status == 1 || inp->data.play_server.playerdigging.status == 2) {
|
|
|
|
if (entity_dist_block(player->entity, inp->data.play_server.playerdigging.location.x, inp->data.play_server.playerdigging.location.y, inp->data.play_server.playerdigging.location.z) > player->reachDistance || player->digging <= 0.) {
|
2019-04-17 14:45:14 +00:00
|
|
|
block blk = world_get_block(player->world, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
|
|
|
world_set_block(player->world, blk, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
2017-01-03 19:18:52 +00:00
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
if (inp->data.play_server.playerdigging.status == 2) {
|
2019-04-17 14:45:14 +00:00
|
|
|
block blk = world_get_block(player->world, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
2017-01-03 19:18:52 +00:00
|
|
|
if ((player->digging + player->digspeed) >= 1.) {
|
|
|
|
int nb = 0;
|
|
|
|
if (ii != NULL && ii->onItemBreakBlock != NULL) {
|
|
|
|
if ((*ii->onItemBreakBlock)(player->world, player, player->currentItem + 36, ci, player->digging_position.x, player->digging_position.y, player->digging_position.z)) {
|
2019-04-17 14:45:14 +00:00
|
|
|
world_set_block(player->world, blk, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
2017-01-03 19:18:52 +00:00
|
|
|
nb = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!nb) {
|
2019-04-17 14:45:14 +00:00
|
|
|
if (world_set_block(player->world, 0, player->digging_position.x, player->digging_position.y, player->digging_position.z)) {
|
|
|
|
world_set_block(player->world, blk, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
2017-03-11 20:02:53 +00:00
|
|
|
} else {
|
|
|
|
player->foodExhaustion += 0.005;
|
|
|
|
if (player->gamemode != 1) dropBlockDrops(player->world, blk, player, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
|
|
|
}
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-04-17 14:45:14 +00:00
|
|
|
world_set_block(player->world, blk, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
player->digging = -1.;
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
BEGIN_BROADCAST_EXCEPT_DIST(player, player->entity, 128.)
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_BLOCKBREAKANIMATION;
|
|
|
|
pkt->data.play_client.blockbreakanimation.entity_id = player->entity->id;
|
|
|
|
memcpy(&pkt->data.play_server.playerdigging.location, &player->digging_position, sizeof(struct encpos));
|
|
|
|
memset(&player->digging_position, 0, sizeof(struct encpos));
|
|
|
|
pkt->data.play_client.blockbreakanimation.destroy_stage = -1;
|
|
|
|
add_queue(bc_player->outgoingPacket, pkt);
|
|
|
|
END_BROADCAST(player->world->players)
|
|
|
|
} else if (inp->data.play_server.playerdigging.status == 3) {
|
|
|
|
if (player->openInv != NULL) {
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
goto cont;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ci = inventory_get(player, player->inventory, 36 + player->currentItem);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (ci != NULL) {
|
|
|
|
dropPlayerItem(player, ci);
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, player->inventory, 36 + player->currentItem, NULL, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
} else if (inp->data.play_server.playerdigging.status == 4) {
|
|
|
|
if (player->openInv != NULL) {
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
goto cont;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ci = inventory_get(player, player->inventory, 36 + player->currentItem);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (ci != NULL) {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t ss = ci->count;
|
|
|
|
ci->count = 1;
|
2017-01-03 19:18:52 +00:00
|
|
|
dropPlayerItem(player, ci);
|
2019-04-18 15:59:54 +00:00
|
|
|
ci->count = ss;
|
|
|
|
if (--ci->count == 0) {
|
2017-01-03 19:18:52 +00:00
|
|
|
ci = NULL;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, player->inventory, 36 + player->currentItem, ci, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
2017-01-03 23:46:58 +00:00
|
|
|
} else if (inp->data.play_server.playerdigging.status == 5) {
|
2017-03-05 00:11:19 +00:00
|
|
|
if (player->itemUseDuration > 0) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ihs = inventory_get(player, player->inventory, player->itemUseHand ? 45 : (36 + player->currentItem));
|
2017-03-05 00:11:19 +00:00
|
|
|
struct item_info* ihi = ihs == NULL ? NULL : getItemInfo(ihs->item);
|
|
|
|
if (ihs == NULL || ihi == NULL) {
|
|
|
|
player->itemUseDuration = 0;
|
|
|
|
player->entity->usingItemMain = 0;
|
|
|
|
player->entity->usingItemOff = 0;
|
|
|
|
updateMetadata(player->entity);
|
|
|
|
}
|
|
|
|
if (ihi->onItemUse != NULL) (*ihi->onItemUse)(player->world, player, player->itemUseHand ? 45 : (36 + player->currentItem), ihs, player->itemUseDuration);
|
|
|
|
player->entity->usingItemMain = 0;
|
|
|
|
player->entity->usingItemOff = 0;
|
|
|
|
player->itemUseDuration = 0;
|
|
|
|
updateMetadata(player->entity);
|
|
|
|
}
|
2017-01-03 23:46:58 +00:00
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
} else if (inp->data.play_server.playerdigging.status == 6) {
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_swap(player, player->inventory, 45, 36 + player->currentItem, 1);
|
2017-01-03 23:46:58 +00:00
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
} else pthread_mutex_unlock(&player->inventory->mut);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_CREATIVEINVENTORYACTION) {
|
|
|
|
if (player->gamemode == 1) {
|
|
|
|
struct inventory* inv = NULL;
|
|
|
|
if (player->openInv == NULL) inv = player->inventory;
|
|
|
|
else if (player->openInv != NULL) inv = player->openInv;
|
|
|
|
if (inv == NULL) goto cont;
|
|
|
|
pthread_mutex_lock(&inv->mut);
|
|
|
|
if (inp->data.play_server.creativeinventoryaction.clicked_item.item >= 0 && inp->data.play_server.creativeinventoryaction.slot == -1) {
|
|
|
|
dropPlayerItem(player, &inp->data.play_server.creativeinventoryaction.clicked_item);
|
|
|
|
} else {
|
|
|
|
int16_t sl = inp->data.play_server.creativeinventoryaction.slot;
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, sl, &inp->data.play_server.creativeinventoryaction.clicked_item, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&inv->mut);
|
|
|
|
}
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_HELDITEMCHANGE) {
|
|
|
|
if (inp->data.play_server.helditemchange.slot >= 0 && inp->data.play_server.helditemchange.slot < 9) {
|
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
|
|
|
player->currentItem = inp->data.play_server.helditemchange.slot;
|
|
|
|
onInventoryUpdate(player, player->inventory, player->currentItem + 36);
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
}
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_ENTITYACTION) {
|
|
|
|
if (inp->data.play_server.entityaction.action_id == 0) player->entity->sneaking = 1;
|
|
|
|
else if (inp->data.play_server.entityaction.action_id == 1) player->entity->sneaking = 0;
|
|
|
|
else if (inp->data.play_server.entityaction.action_id == 3) player->entity->sprinting = 1;
|
|
|
|
else if (inp->data.play_server.entityaction.action_id == 4) player->entity->sprinting = 0;
|
2017-03-05 00:11:19 +00:00
|
|
|
updateMetadata(player->entity);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_PLAYERBLOCKPLACEMENT) {
|
|
|
|
if (player->openInv != NULL) goto cont;
|
|
|
|
if (entity_dist_block(player->entity, inp->data.play_server.playerblockplacement.location.x, inp->data.play_server.playerblockplacement.location.y, inp->data.play_server.playerblockplacement.location.z) > player->reachDistance) goto cont;
|
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ci = inventory_get(player, player->inventory, 36 + player->currentItem);
|
2017-01-03 19:18:52 +00:00
|
|
|
int32_t x = inp->data.play_server.playerblockplacement.location.x;
|
|
|
|
int32_t y = inp->data.play_server.playerblockplacement.location.y;
|
|
|
|
int32_t z = inp->data.play_server.playerblockplacement.location.z;
|
|
|
|
uint8_t face = inp->data.play_server.playerblockplacement.face;
|
2019-04-17 14:45:14 +00:00
|
|
|
block b = world_get_block(player->world, x, y, z);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (ci != NULL) {
|
|
|
|
struct item_info* ii = getItemInfo(ci->item);
|
|
|
|
if (ii != NULL && ii->onItemInteract != NULL) {
|
2017-09-05 02:29:12 +00:00
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
2018-01-19 04:06:47 +00:00
|
|
|
if ((*ii->onItemInteract)(player->world, player, player->currentItem + 36, ci, x, y, z, face, inp->data.play_server.playerblockplacement.cursor_position_x, inp->data.play_server.playerblockplacement.cursor_position_y, inp->data.play_server.playerblockplacement.cursor_position_z)) goto pbp_cont;
|
2017-09-05 02:29:12 +00:00
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
2019-04-18 15:59:54 +00:00
|
|
|
ci = inventory_get(player, player->inventory, 36 + player->currentItem);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
struct block_info* bi = getBlockInfo(b);
|
|
|
|
if (!player->entity->sneaking && bi != NULL && bi->onBlockInteract != NULL) {
|
2017-09-05 02:29:12 +00:00
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
2017-01-03 19:18:52 +00:00
|
|
|
(*bi->onBlockInteract)(player->world, b, x, y, z, player, face, inp->data.play_server.playerblockplacement.cursor_position_x, inp->data.play_server.playerblockplacement.cursor_position_y, inp->data.play_server.playerblockplacement.cursor_position_z);
|
2017-09-05 02:29:12 +00:00
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
2019-04-18 15:59:54 +00:00
|
|
|
ci = inventory_get(player, player->inventory, 36 + player->currentItem);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (ci != NULL && ci->item < 256) {
|
|
|
|
if (bi == NULL || !bi->material->replacable) {
|
|
|
|
if (face == 0) y--;
|
|
|
|
else if (face == 1) y++;
|
|
|
|
else if (face == 2) z--;
|
|
|
|
else if (face == 3) z++;
|
|
|
|
else if (face == 4) x--;
|
|
|
|
else if (face == 5) x++;
|
|
|
|
}
|
2019-04-17 14:45:14 +00:00
|
|
|
block b2 = world_get_block(player->world, x, y, z);
|
2017-01-03 19:18:52 +00:00
|
|
|
struct block_info* bi2 = getBlockInfo(b2);
|
|
|
|
if (b2 == 0 || bi2 == NULL || bi2->material->replacable) {
|
|
|
|
block tbb = (ci->item << 4) | (ci->damage & 0x0f);
|
|
|
|
struct block_info* tbi = getBlockInfo(tbb);
|
|
|
|
if (tbi == NULL) goto pbp_cont;
|
|
|
|
struct boundingbox pbb;
|
|
|
|
int bad = 0;
|
2019-04-18 15:59:54 +00:00
|
|
|
//int32_t chunk_x = x >> 4;
|
|
|
|
//int32_t chunk_z = z >> 4;
|
|
|
|
//for (int32_t icx = chunk_x - 1; icx <= chunk_x + 1; icx++)
|
|
|
|
//for (int32_t icz = chunk_z - 1; icz <= chunk_z + 1; icz++) {
|
2019-04-17 14:45:14 +00:00
|
|
|
//struct chunk* ch = world_get_chunk(player->world, icx, icz);
|
2017-01-03 19:18:52 +00:00
|
|
|
//if (ch != NULL) {
|
|
|
|
BEGIN_HASHMAP_ITERATION(player->world->entities)
|
|
|
|
struct entity* ent = (struct entity*) value;
|
2017-02-05 19:53:32 +00:00
|
|
|
if (ent == NULL || entity_distsq_block(ent, x, y, z) > 8. * 8. || !hasFlag(getEntityInfo(ent->type), "livingbase")) continue;
|
2017-01-03 19:18:52 +00:00
|
|
|
getEntityCollision(ent, &pbb);
|
|
|
|
pbb.minX += .01;
|
|
|
|
pbb.minY += .01;
|
|
|
|
pbb.minZ += .01;
|
|
|
|
pbb.maxX -= .001;
|
|
|
|
pbb.maxY -= .001;
|
|
|
|
pbb.maxZ -= .001;
|
|
|
|
for (size_t i = 0; i < tbi->boundingBox_count; i++) {
|
|
|
|
struct boundingbox* bb = &tbi->boundingBoxes[i];
|
|
|
|
if (bb == NULL) continue;
|
|
|
|
struct boundingbox abb;
|
|
|
|
abb.minX = bb->minX + x;
|
|
|
|
abb.maxX = bb->maxX + x;
|
|
|
|
abb.minY = bb->minY + y;
|
|
|
|
abb.maxY = bb->maxY + y;
|
|
|
|
abb.minZ = bb->minZ + z;
|
|
|
|
abb.maxZ = bb->maxZ + z;
|
|
|
|
if (boundingbox_intersects(&abb, &pbb)) {
|
|
|
|
bad = 1;
|
|
|
|
BREAK_HASHMAP_ITERATION(player->world->entities);
|
|
|
|
goto phi;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
END_HASHMAP_ITERATION(player->world->entities)
|
|
|
|
phi: ;
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
if (!bad) {
|
2019-04-17 13:38:46 +00:00
|
|
|
if ((tbb = player_can_place_block(player, tbb, x, y, z, face))) {
|
2019-04-17 14:45:14 +00:00
|
|
|
if (world_set_block(player->world, tbb, x, y, z)) {
|
|
|
|
world_set_block(player->world, b2, x, y, z);
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, player->inventory, 36 + player->currentItem, ci, 1, 1);
|
2017-09-10 03:00:32 +00:00
|
|
|
} else if (player->gamemode != 1) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (--ci->count <= 0) {
|
2017-09-10 03:00:32 +00:00
|
|
|
ci = NULL;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, player->inventory, 36 + player->currentItem, ci, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
2018-01-19 04:33:51 +00:00
|
|
|
} else {
|
2019-04-17 14:45:14 +00:00
|
|
|
world_set_block(player->world, b2, x, y, z);
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, player->inventory, 36 + player->currentItem, ci, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-04-17 14:45:14 +00:00
|
|
|
world_set_block(player->world, b2, x, y, z);
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, player->inventory, 36 + player->currentItem, ci, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-04-17 14:45:14 +00:00
|
|
|
world_set_block(player->world, b2, x, y, z);
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, player->inventory, 36 + player->currentItem, ci, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pbp_cont: ;
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_CLICKWINDOW) {
|
|
|
|
struct inventory* inv = NULL;
|
|
|
|
if (inp->data.play_server.clickwindow.window_id == 0 && player->openInv == NULL) inv = player->inventory;
|
|
|
|
else if (player->openInv != NULL && inp->data.play_server.clickwindow.window_id == player->openInv->windowID) inv = player->openInv;
|
|
|
|
if (inv == NULL) goto cont;
|
|
|
|
int8_t b = inp->data.play_server.clickwindow.button;
|
|
|
|
int16_t act = inp->data.play_server.clickwindow.action_number;
|
|
|
|
int32_t mode = inp->data.play_server.clickwindow.mode;
|
|
|
|
int16_t slot = inp->data.play_server.clickwindow.slot;
|
|
|
|
pthread_mutex_lock(&inv->mut);
|
|
|
|
int s0ic = inv->type == INVTYPE_PLAYERINVENTORY || inv->type == INVTYPE_WORKBENCH;
|
|
|
|
//printf("click mode=%i, b=%i, slot=%i\n", mode, b, slot);
|
|
|
|
int force_desync = 0;
|
|
|
|
if (mode == 5 && b == 10 && player->gamemode != 1) force_desync = 1;
|
|
|
|
if (slot >= 0 || force_desync) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* invs = force_desync ? NULL : inventory_get(player, inv, slot);
|
|
|
|
if ((mode != 4 && mode != 2 && mode != 5 && mode != 3 && ((inp->data.play_server.clickwindow.clicked_item.item < 0) != (invs == NULL))) || (invs != NULL && inp->data.play_server.clickwindow.clicked_item.item >= 0 && !(slot_stackable(invs, &inp->data.play_server.clickwindow.clicked_item) && invs->count == inp->data.play_server.clickwindow.clicked_item.count)) || force_desync) {
|
2017-01-03 19:18:52 +00:00
|
|
|
//printf("desync\n");
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_CONFIRMTRANSACTION;
|
|
|
|
pkt->data.play_client.confirmtransaction.window_id = inv->windowID;
|
|
|
|
pkt->data.play_client.confirmtransaction.action_number = act;
|
|
|
|
pkt->data.play_client.confirmtransaction.accepted = 0;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
if (inv != player->inventory) {
|
|
|
|
pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_WINDOWITEMS;
|
|
|
|
pkt->data.play_client.windowitems.window_id = inv->windowID;
|
|
|
|
pkt->data.play_client.windowitems.count = inv->slot_count;
|
|
|
|
pkt->data.play_client.windowitems.slot_data = xmalloc(sizeof(struct slot) * inv->slot_count);
|
|
|
|
for (size_t i = 0; i < inv->slot_count; i++) {
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(inv->slots[i], &pkt->data.play_client.windowitems.slot_data[i]);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
}
|
|
|
|
pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_WINDOWITEMS;
|
|
|
|
pkt->data.play_client.windowitems.window_id = player->inventory->windowID;
|
|
|
|
pkt->data.play_client.windowitems.count = player->inventory->slot_count;
|
|
|
|
pkt->data.play_client.windowitems.slot_data = xmalloc(sizeof(struct slot) * player->inventory->slot_count);
|
|
|
|
for (size_t i = 0; i < player->inventory->slot_count; i++) {
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(player->inventory->slots[i], &pkt->data.play_client.windowitems.slot_data[i]);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_SETSLOT;
|
|
|
|
pkt->data.play_client.setslot.window_id = -1;
|
|
|
|
pkt->data.play_client.setslot.slot = -1;
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(player->inHand, &pkt->data.play_client.setslot.slot_data);
|
2017-01-03 19:18:52 +00:00
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
} else {
|
|
|
|
if (mode != 5 && inv->dragSlot_count > 0) {
|
|
|
|
inv->dragSlot_count = 0;
|
|
|
|
}
|
|
|
|
int sto = 0;
|
|
|
|
if (inv->type == INVTYPE_FURNACE) sto = slot == 2;
|
|
|
|
if (mode == 0) {
|
|
|
|
if (s0ic && slot == 0 && invs != NULL) {
|
|
|
|
if (player->inHand == NULL) {
|
|
|
|
player->inHand = invs;
|
|
|
|
invs = NULL;
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, 0, invs, 0, 0);
|
|
|
|
crafting_once(player, inv);
|
|
|
|
} else if (slot_stackable(player->inHand, invs) && (player->inHand->count + invs->count) < slot_max_size(player->inHand)) {
|
|
|
|
player->inHand->count += invs->count;
|
2017-01-03 19:18:52 +00:00
|
|
|
invs = NULL;
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, 0, invs, 0, 1);
|
|
|
|
crafting_once(player, inv);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else if (b == 0) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (slot_stackable(player->inHand, invs)) {
|
2017-01-03 19:18:52 +00:00
|
|
|
if (sto) {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t os = player->inHand->count;
|
|
|
|
int mss = slot_max_size(player->inHand);
|
|
|
|
player->inHand->count += invs->count;
|
|
|
|
if (player->inHand->count > mss) player->inHand->count = mss;
|
|
|
|
int dr = player->inHand->count - os;
|
|
|
|
if (dr >= invs->count) {
|
2017-01-03 19:18:52 +00:00
|
|
|
invs = NULL;
|
2019-04-18 15:59:54 +00:00
|
|
|
} else invs->count -= dr;
|
|
|
|
inventory_set_slot(player, inv, slot, invs, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t os = invs->count;
|
|
|
|
int mss = slot_max_size(player->inHand);
|
|
|
|
invs->count += player->inHand->count;
|
|
|
|
if (invs->count > mss) invs->count = mss;
|
|
|
|
inventory_set_slot(player, inv, slot, invs, 0, 1);
|
|
|
|
int dr = invs->count - os;
|
|
|
|
if (dr >= player->inHand->count) {
|
2017-01-03 19:18:52 +00:00
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
} else {
|
2019-04-18 15:59:54 +00:00
|
|
|
player->inHand->count -= dr;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
} else if (player->inHand == NULL || inventory_validate(inv->type, slot, player->inHand)) {
|
2017-01-03 19:18:52 +00:00
|
|
|
struct slot* t = invs;
|
|
|
|
invs = player->inHand;
|
|
|
|
player->inHand = t;
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, slot, invs, 0, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else if (b == 1) {
|
|
|
|
if (player->inHand == NULL && invs != NULL) {
|
|
|
|
player->inHand = xmalloc(sizeof(struct slot));
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(invs, player->inHand);
|
|
|
|
uint8_t os = invs->count;
|
|
|
|
invs->count /= 2;
|
|
|
|
player->inHand->count = os - invs->count;
|
|
|
|
inventory_set_slot(player, inv, slot, invs, 0, 1);
|
|
|
|
} else if (player->inHand != NULL && !sto && inventory_validate(inv->type, slot, player->inHand) && (invs == NULL || (slot_stackable(player->inHand, invs) && player->inHand->count + invs->count < slot_max_size(player->inHand)))) {
|
2017-01-03 19:18:52 +00:00
|
|
|
if (invs == NULL) {
|
|
|
|
invs = xmalloc(sizeof(struct slot));
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(player->inHand, invs);
|
|
|
|
invs->count = 1;
|
2017-01-03 19:18:52 +00:00
|
|
|
} else {
|
2019-04-18 15:59:54 +00:00
|
|
|
invs->count++;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
if (--player->inHand->count <= 0) {
|
2017-01-03 19:18:52 +00:00
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, slot, invs, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (mode == 1 && invs != NULL) {
|
|
|
|
if (inv->type == INVTYPE_PLAYERINVENTORY) {
|
|
|
|
int16_t it = invs->item;
|
|
|
|
if (slot == 0) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int amt = crafting_all(player, inv);
|
2017-01-03 19:18:52 +00:00
|
|
|
for (int i = 0; i < amt; i++)
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_add(player, inv, invs, 44, 8, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
onInventoryUpdate(player, inv, 1); // 2-4 would just repeat the calculation
|
|
|
|
} else if (slot != 45 && it == ITM_SHIELD && inv->slots[45] == NULL) {
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_swap(player, inv, 45, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot != 5 && inv->slots[5] == NULL && (it == BLK_PUMPKIN || it == ITM_HELMETCLOTH || it == ITM_HELMETCHAIN || it == ITM_HELMETIRON || it == ITM_HELMETDIAMOND || it == ITM_HELMETGOLD)) {
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_swap(player, inv, 5, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot != 6 && inv->slots[6] == NULL && (it == ITM_CHESTPLATECLOTH || it == ITM_CHESTPLATECHAIN || it == ITM_CHESTPLATEIRON || it == ITM_CHESTPLATEDIAMOND || it == ITM_CHESTPLATEGOLD)) {
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_swap(player, inv, 6, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot != 7 && inv->slots[7] == NULL && (it == ITM_LEGGINGSCLOTH || it == ITM_LEGGINGSCHAIN || it == ITM_LEGGINGSIRON || it == ITM_LEGGINGSDIAMOND || it == ITM_LEGGINGSGOLD)) {
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_swap(player, inv, 7, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot != 8 && inv->slots[8] == NULL && (it == ITM_BOOTSCLOTH || it == ITM_BOOTSCHAIN || it == ITM_BOOTSIRON || it == ITM_BOOTSDIAMOND || it == ITM_BOOTSGOLD)) {
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_swap(player, inv, 8, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot > 35 && slot < 45 && invs != NULL) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 9, 36, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot > 8 && slot < 36 && invs != NULL) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 36, 45, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if ((slot == 45 || slot < 9) && invs != NULL) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 9, 36, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
else {
|
2019-04-18 15:59:54 +00:00
|
|
|
r = inventory_add(player, inv, invs, 36, 45, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (inv->type == INVTYPE_WORKBENCH) {
|
|
|
|
if (slot == 0) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int amt = crafting_all(player, inv);
|
2017-01-03 19:18:52 +00:00
|
|
|
for (int i = 0; i < amt; i++)
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_add(player, inv, inv->slots[0], 45, 9, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
onInventoryUpdate(player, inv, 1); // 2-4 would just repeat the calculation
|
|
|
|
} else if (slot <= 9) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 10, 46, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot > 9 && slot < 37) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 37, 46, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot > 36 && slot < 46) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 10, 37, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else if (inv->type == INVTYPE_CHEST) {
|
|
|
|
if (slot < 27) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 62, 26, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot >= 27) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 0, 27, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else if (inv->type == INVTYPE_FURNACE) {
|
|
|
|
if (slot > 2) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (smelting_output(invs) != NULL) inventory_swap(player, inv, 0, slot, 0);
|
|
|
|
else if (smelting_burnTime(invs) > 0) inventory_swap(player, inv, 1, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
else if (slot > 29) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 3, 30, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (slot < 30) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 30, 39, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-04-18 15:59:54 +00:00
|
|
|
int r = inventory_add(player, inv, invs, 38, 2, 0);
|
|
|
|
if (r <= 0) inventory_set_slot(player, inv, slot, NULL, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (mode == 2) {
|
|
|
|
if (inv->type == INVTYPE_PLAYERINVENTORY) {
|
|
|
|
if (slot == 0) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* invb = inventory_get(player, inv, 36 + b);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (invb == NULL) {
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, 36 + b, inv->slots[0], 0, 1);
|
|
|
|
inventory_set_slot(player, inv, 0, NULL, 0, 1);
|
|
|
|
crafting_once(player, inv);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
} else if (b >= 0 && b <= 8) inventory_swap(player, inv, 36 + b, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (inv->type == INVTYPE_WORKBENCH) {
|
|
|
|
if (slot == 0) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* invb = inventory_get(player, inv, 37 + b);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (invb == NULL) {
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, 37 + b, inv->slots[0], 0, 1);
|
|
|
|
inventory_set_slot(player, inv, 0, NULL, 0, 1);
|
|
|
|
crafting_once(player, inv);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
} else if (b >= 0 && b <= 8) inventory_swap(player, inv, 37 + b, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (inv->type == INVTYPE_CHEST) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (b >= 0 && b <= 8) inventory_swap(player, inv, 54 + b, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (inv->type == INVTYPE_FURNACE) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (b >= 0 && b <= 8) inventory_swap(player, inv, 30 + b, slot, 0);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else if (mode == 3) {
|
|
|
|
if (player->gamemode == 1) {
|
|
|
|
if (invs != NULL && player->inHand == NULL) {
|
|
|
|
player->inHand = xmalloc(sizeof(struct slot));
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(invs, player->inHand);
|
|
|
|
player->inHand->count = slot_max_size(player->inHand);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
//middle click, NOP in survival?
|
|
|
|
} else if (mode == 4 && invs != NULL) {
|
|
|
|
if (b == 0) {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t p = invs->count;
|
|
|
|
invs->count = 1;
|
2017-01-03 19:18:52 +00:00
|
|
|
dropPlayerItem(player, invs);
|
2019-04-18 15:59:54 +00:00
|
|
|
invs->count = p - 1;
|
|
|
|
if (invs->count == 0) invs = NULL;
|
|
|
|
inventory_set_slot(player, inv, slot, invs, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (b == 1) {
|
|
|
|
dropPlayerItem(player, invs);
|
|
|
|
invs = NULL;
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, slot, invs, 1, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
if (s0ic && slot == 0) crafting_once(player, inv);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else if (mode == 5) {
|
|
|
|
if (b == 1 || b == 5 || b == 9) {
|
|
|
|
int ba = 0;
|
|
|
|
if (inv->type == INVTYPE_PLAYERINVENTORY) {
|
|
|
|
if (slot == 0 || (slot >= 5 && slot <= 8)) ba = 1;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
if (!ba && inv->dragSlot_count < inv->slot_count && inventory_validate(inv->type, slot, player->inHand) && (invs == NULL || slot_stackable(invs, player->inHand))) {
|
2017-01-03 19:18:52 +00:00
|
|
|
inv->dragSlot[inv->dragSlot_count++] = slot;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (mode == 6 && player->inHand != NULL) {
|
2019-04-18 15:59:54 +00:00
|
|
|
int mss = slot_max_size(player->inHand);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (inv->type == INVTYPE_PLAYERINVENTORY) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (player->inHand->count < mss) {
|
2017-01-03 19:18:52 +00:00
|
|
|
for (size_t i = 9; i < 36; i++) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* invi = inventory_get(player, inv, i);
|
|
|
|
if (slot_stackable(player->inHand, invi)) {
|
|
|
|
uint8_t oc = player->inHand->count;
|
|
|
|
player->inHand->count += invi->count;
|
|
|
|
if (player->inHand->count > mss) player->inHand->count = mss;
|
|
|
|
invi->count -= player->inHand->count - oc;
|
|
|
|
if (invi->count <= 0) invi = NULL;
|
|
|
|
inventory_set_slot(player, inv, i, invi, 0, 1);
|
|
|
|
if (player->inHand->count >= mss) break;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
if (player->inHand->count < mss) {
|
2017-01-03 19:18:52 +00:00
|
|
|
for (size_t i = 36; i < 45; i++) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* invi = inventory_get(player, inv, i);
|
|
|
|
if (slot_stackable(player->inHand, invi)) {
|
|
|
|
uint8_t oc = player->inHand->count;
|
|
|
|
player->inHand->count += invi->count;
|
|
|
|
if (player->inHand->count > mss) player->inHand->count = mss;
|
|
|
|
invi->count -= player->inHand->count - oc;
|
|
|
|
if (invi->count <= 0) invi = NULL;
|
|
|
|
inventory_set_slot(player, inv, i, invi, 0, 1);
|
|
|
|
if (player->inHand->count >= mss) break;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (inv->type == INVTYPE_WORKBENCH) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (player->inHand->count < mss) {
|
2017-01-03 19:18:52 +00:00
|
|
|
for (size_t i = 1; i < 46; i++) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* invi = inventory_get(player, inv, i);
|
|
|
|
if (slot_stackable(player->inHand, invi)) {
|
|
|
|
uint8_t oc = player->inHand->count;
|
|
|
|
player->inHand->count += invi->count;
|
|
|
|
if (player->inHand->count > mss) player->inHand->count = mss;
|
|
|
|
invi->count -= player->inHand->count - oc;
|
|
|
|
if (invi->count <= 0) invi = NULL;
|
|
|
|
inventory_set_slot(player, inv, i, invi, 0, 1);
|
|
|
|
if (player->inHand->count >= mss) break;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (inv->type == INVTYPE_CHEST) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (player->inHand->count < mss) {
|
2017-01-03 19:18:52 +00:00
|
|
|
for (size_t i = 0; i < 63; i++) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* invi = inventory_get(player, inv, i);
|
|
|
|
if (slot_stackable(player->inHand, invi)) {
|
|
|
|
uint8_t oc = player->inHand->count;
|
|
|
|
player->inHand->count += invi->count;
|
|
|
|
if (player->inHand->count > mss) player->inHand->count = mss;
|
|
|
|
invi->count -= player->inHand->count - oc;
|
|
|
|
if (invi->count <= 0) invi = NULL;
|
|
|
|
inventory_set_slot(player, inv, i, invi, 0, 1);
|
|
|
|
if (player->inHand->count >= mss) break;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (inv->type == INVTYPE_FURNACE) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (player->inHand->count < mss) {
|
2017-03-11 20:02:53 +00:00
|
|
|
for (size_t i = 3; i < 39; i++) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* invi = inventory_get(player, inv, i);
|
|
|
|
if (slot_stackable(player->inHand, invi)) {
|
|
|
|
uint8_t oc = player->inHand->count;
|
|
|
|
player->inHand->count += invi->count;
|
|
|
|
if (player->inHand->count > mss) player->inHand->count = mss;
|
|
|
|
invi->count -= player->inHand->count - oc;
|
|
|
|
if (invi->count <= 0) invi = NULL;
|
|
|
|
inventory_set_slot(player, inv, i, invi, 0, 1);
|
|
|
|
if (player->inHand->count >= mss) break;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_CONFIRMTRANSACTION;
|
|
|
|
pkt->data.play_client.confirmtransaction.window_id = inv->windowID;
|
|
|
|
pkt->data.play_client.confirmtransaction.action_number = act;
|
|
|
|
pkt->data.play_client.confirmtransaction.accepted = 1;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
}
|
|
|
|
} else if (slot == -999) {
|
|
|
|
if (mode != 5 && inv->dragSlot_count > 0) {
|
|
|
|
inv->dragSlot_count = 0;
|
|
|
|
}
|
|
|
|
if (mode == 0 && player->inHand != NULL) {
|
|
|
|
if (b == 1) {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t p = player->inHand->count;
|
|
|
|
player->inHand->count = 1;
|
2017-01-03 19:18:52 +00:00
|
|
|
dropPlayerItem(player, player->inHand);
|
2019-04-18 15:59:54 +00:00
|
|
|
player->inHand->count = p - 1;
|
|
|
|
if (player->inHand->count == 0) {
|
2017-01-03 19:18:52 +00:00
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
}
|
|
|
|
} else if (b == 0) {
|
|
|
|
dropPlayerItem(player, player->inHand);
|
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
}
|
|
|
|
} else if (mode == 5 && player->inHand != NULL) {
|
|
|
|
if (b == 0 || b == 4 || b == 8) {
|
|
|
|
memset(inv->dragSlot, 0, inv->slot_count * 2);
|
|
|
|
inv->dragSlot_count = 0;
|
|
|
|
} else if (inv->dragSlot_count > 0) {
|
|
|
|
if (b == 2) {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t total = player->inHand->count;
|
2017-01-03 19:18:52 +00:00
|
|
|
uint8_t per = total / inv->dragSlot_count;
|
|
|
|
if (per == 0) per = 1;
|
|
|
|
for (int i = 0; i < inv->dragSlot_count; i++) {
|
|
|
|
int sl = inv->dragSlot[i];
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ssl = inventory_get(player, inv, sl);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (ssl == NULL) {
|
|
|
|
ssl = xmalloc(sizeof(struct slot));
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(player->inHand, ssl);
|
|
|
|
ssl->count = per;
|
|
|
|
inventory_set_slot(player, inv, sl, ssl, 0, 1);
|
|
|
|
if (per >= player->inHand->count) {
|
2017-01-03 19:18:52 +00:00
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
player->inHand->count -= per;
|
2017-01-03 19:18:52 +00:00
|
|
|
} else {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t os = ssl->count;
|
|
|
|
ssl->count += per;
|
|
|
|
int mss = slot_max_size(player->inHand);
|
|
|
|
if (ssl->count > mss) ssl->count = mss;
|
|
|
|
inventory_set_slot(player, inv, sl, ssl, 0, 1);
|
|
|
|
if (per >= player->inHand->count) {
|
2017-01-03 19:18:52 +00:00
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
player->inHand->count -= ssl->count - os;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (b == 6) {
|
|
|
|
uint8_t per = 1;
|
|
|
|
for (int i = 0; i < inv->dragSlot_count; i++) {
|
|
|
|
int sl = inv->dragSlot[i];
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ssl = inventory_get(player, inv, sl);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (ssl == NULL) {
|
|
|
|
ssl = xmalloc(sizeof(struct slot));
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(player->inHand, ssl);
|
|
|
|
ssl->count = per;
|
|
|
|
inventory_set_slot(player, inv, sl, ssl, 0, 1);
|
|
|
|
if (per >= player->inHand->count) {
|
2017-01-03 19:18:52 +00:00
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
player->inHand->count -= per;
|
2017-01-03 19:18:52 +00:00
|
|
|
} else {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t os = ssl->count;
|
|
|
|
ssl->count += per;
|
|
|
|
int mss = slot_max_size(player->inHand);
|
|
|
|
if (ssl->count > mss) ssl->count = mss;
|
|
|
|
inventory_set_slot(player, inv, sl, ssl, 0, 1);
|
|
|
|
if (per >= player->inHand->count) {
|
2017-01-03 19:18:52 +00:00
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-18 15:59:54 +00:00
|
|
|
player->inHand->count -= ssl->count - os;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (b == 10 && player->gamemode == 1) {
|
2019-04-18 15:59:54 +00:00
|
|
|
uint8_t per = slot_max_size(player->inHand);
|
2017-01-03 19:18:52 +00:00
|
|
|
for (int i = 0; i < inv->dragSlot_count; i++) {
|
|
|
|
int sl = inv->dragSlot[i];
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ssl = inventory_get(player, inv, sl);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (ssl == NULL) {
|
|
|
|
ssl = xmalloc(sizeof(struct slot));
|
2019-04-18 15:59:54 +00:00
|
|
|
slot_duplicate(player->inHand, ssl);
|
|
|
|
ssl->count = per;
|
|
|
|
inventory_set_slot(player, inv, sl, ssl, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
} else {
|
2019-04-18 15:59:54 +00:00
|
|
|
ssl->count = per;
|
|
|
|
inventory_set_slot(player, inv, sl, ssl, 0, 1);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&inv->mut);
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_CLOSEWINDOW) {
|
|
|
|
player_closeWindow(player, inp->data.play_server.closewindow.window_id);
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_USEENTITY) {
|
2017-09-10 03:00:32 +00:00
|
|
|
if (inp->data.play_server.useentity.type == 0) {
|
2019-04-17 14:45:14 +00:00
|
|
|
struct entity* ent = world_get_entity(player->world, inp->data.play_server.useentity.target);
|
2017-09-10 03:00:32 +00:00
|
|
|
if (ent != NULL && ent != player->entity && ent->health > 0. && ent->world == player->world && entity_dist(ent, player->entity) < 4.) {
|
|
|
|
struct entity_info* ei = getEntityInfo(ent->type);
|
|
|
|
if (ei != NULL && ei->onInteract != NULL) {
|
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
2019-04-18 15:59:54 +00:00
|
|
|
(*ei->onInteract)(player->world, ent, player, inventory_get(player, player->inventory, 36 + player->currentItem), 36 + player->currentItem);
|
2017-09-10 03:00:32 +00:00
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (inp->data.play_server.useentity.type == 1) {
|
2019-04-17 14:45:14 +00:00
|
|
|
struct entity* ent = world_get_entity(player->world, inp->data.play_server.useentity.target);
|
2017-01-03 19:18:52 +00:00
|
|
|
if (ent != NULL && ent != player->entity && ent->health > 0. && ent->world == player->world && entity_dist(ent, player->entity) < 4. && (tick_counter - player->lastSwing) >= 3) {
|
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
2019-04-18 15:59:54 +00:00
|
|
|
damageEntityWithItem(ent, player->entity, 36 + player->currentItem, inventory_get(player, player->inventory, 36 + player->currentItem));
|
2017-01-03 19:18:52 +00:00
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
}
|
|
|
|
player->lastSwing = tick_counter;
|
|
|
|
}
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_CLIENTSTATUS) {
|
|
|
|
if (inp->data.play_server.clientstatus.action_id == 0 && player->entity->health <= 0.) {
|
2019-04-17 14:45:14 +00:00
|
|
|
world_despawn_entity(player->world, player->entity);
|
|
|
|
world_spawn_entity(player->world, player->entity);
|
2017-01-03 19:18:52 +00:00
|
|
|
player->entity->health = 20.;
|
|
|
|
player->food = 20;
|
2017-03-11 20:02:53 +00:00
|
|
|
player->entity->fallDistance = 0.;
|
2017-01-03 19:18:52 +00:00
|
|
|
player->saturation = 0.; // TODO
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_UPDATEHEALTH;
|
|
|
|
pkt->data.play_client.updatehealth.health = player->entity->health;
|
|
|
|
pkt->data.play_client.updatehealth.food = player->food;
|
|
|
|
pkt->data.play_client.updatehealth.food_saturation = player->saturation;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_RESPAWN;
|
|
|
|
pkt->data.play_client.respawn.dimension = player->world->dimension;
|
|
|
|
pkt->data.play_client.respawn.difficulty = difficulty;
|
|
|
|
pkt->data.play_client.respawn.gamemode = player->gamemode;
|
|
|
|
pkt->data.play_client.respawn.level_type = xstrdup(player->world->levelType, 0);
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
2019-04-17 13:38:46 +00:00
|
|
|
player_teleport(player, (double) player->world->spawnpos.x + .5, (double) player->world->spawnpos.y,
|
|
|
|
(double) player->world->spawnpos.z + .5); // TODO: make overworld
|
|
|
|
player_set_gamemode(player, -1);
|
2017-03-11 20:02:53 +00:00
|
|
|
BEGIN_HASHMAP_ITERATION (plugins)
|
|
|
|
struct plugin* plugin = value;
|
|
|
|
if (plugin->onPlayerSpawn != NULL) (*plugin->onPlayerSpawn)(player->world, player);
|
|
|
|
END_HASHMAP_ITERATION (plugins)
|
|
|
|
player->entity->invincibilityTicks = 5;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_USEITEM) {
|
|
|
|
int32_t hand = inp->data.play_server.useitem.hand;
|
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* cs = inventory_get(player, player->inventory, hand ? 45 : (36 + player->currentItem));
|
2017-01-03 19:18:52 +00:00
|
|
|
if (cs != NULL) {
|
|
|
|
struct item_info* ii = getItemInfo(cs->item);
|
2017-03-05 00:11:19 +00:00
|
|
|
if (ii != NULL && (ii->canUseItem == NULL || (*ii->canUseItem)(player->world, player, hand ? 45 : (36 + player->currentItem), cs))) {
|
|
|
|
if (ii->maxUseDuration == 0 && ii->onItemUse != NULL) (*ii->onItemUse)(player->world, player, hand ? 45 : (36 + player->currentItem), cs, 0);
|
|
|
|
else if (ii->maxUseDuration > 0) {
|
|
|
|
player->itemUseDuration = 1;
|
|
|
|
player->itemUseHand = hand ? 1 : 0;
|
|
|
|
player->entity->usingItemMain = !player->itemUseHand;
|
|
|
|
player->entity->usingItemOff = player->itemUseHand;
|
|
|
|
updateMetadata(player->entity);
|
|
|
|
}
|
|
|
|
}
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
2017-03-11 20:02:53 +00:00
|
|
|
} else if (inp->id == PKT_PLAY_SERVER_TELEPORTCONFIRM) {
|
|
|
|
if (inp->data.play_server.teleportconfirm.teleport_id == player->lastTeleportID) player->lastTeleportID = 0;
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
cont: ;
|
|
|
|
}
|
|
|
|
|
2017-03-05 18:22:00 +00:00
|
|
|
void player_hungerUpdate(struct player* player) {
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_UPDATEHEALTH;
|
|
|
|
pkt->data.play_client.updatehealth.health = player->entity->health;
|
|
|
|
pkt->data.play_client.updatehealth.food = player->food;
|
|
|
|
pkt->data.play_client.updatehealth.food_saturation = player->saturation;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
}
|
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
void player_tick(struct world* world, struct player* player) {
|
2017-01-03 19:18:52 +00:00
|
|
|
if (player->defunct) {
|
|
|
|
put_hashmap(players, player->entity->id, NULL);
|
|
|
|
BEGIN_BROADCAST (players)
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_PLAYERLISTITEM;
|
|
|
|
pkt->data.play_client.playerlistitem.action_id = 4;
|
|
|
|
pkt->data.play_client.playerlistitem.number_of_players = 1;
|
|
|
|
pkt->data.play_client.playerlistitem.players = xmalloc(sizeof(struct listitem_player));
|
|
|
|
memcpy(&pkt->data.play_client.playerlistitem.players->uuid, &player->uuid, sizeof(struct uuid));
|
|
|
|
add_queue(bc_player->outgoingPacket, pkt);
|
|
|
|
END_BROADCAST (players)
|
2019-04-17 14:45:14 +00:00
|
|
|
world_despawn_player(player->world, player);
|
2017-01-03 19:18:52 +00:00
|
|
|
add_collection(defunctPlayers, player);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
player->chunksSent = 0;
|
|
|
|
if (tick_counter % 200 == 0) {
|
|
|
|
if (player->nextKeepAlive != 0) {
|
|
|
|
player->conn->disconnect = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_KEEPALIVE;
|
|
|
|
pkt->data.play_client.keepalive.keep_alive_id = rand();
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
} else if (tick_counter % 200 == 100) {
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_TIMEUPDATE;
|
|
|
|
pkt->data.play_client.timeupdate.time_of_day = player->world->time;
|
|
|
|
pkt->data.play_client.timeupdate.world_age = player->world->age;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
}
|
2017-03-05 18:22:00 +00:00
|
|
|
if (player->gamemode != 1 && player->gamemode != 3) {
|
|
|
|
float dt = entity_dist_block(player->entity, player->entity->lx, player->entity->ly, player->entity->lz);
|
|
|
|
if (dt > 0.) {
|
|
|
|
if (player->entity->inWater) player->foodExhaustion += .01 * dt;
|
|
|
|
else if (player->entity->onGround) {
|
|
|
|
if (player->entity->sprinting) player->foodExhaustion += .1 * dt;
|
|
|
|
}
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
2017-03-05 18:22:00 +00:00
|
|
|
if (player->foodExhaustion > 4.) {
|
|
|
|
player->foodExhaustion -= 4.;
|
|
|
|
if (player->saturation > 0.) {
|
|
|
|
player->saturation -= 1.;
|
|
|
|
if (player->saturation < 0.) player->saturation = 0.;
|
|
|
|
} else if (difficulty > 0) {
|
|
|
|
player->food -= 1;
|
|
|
|
if (player->food < 0) player->food = 0.;
|
|
|
|
}
|
|
|
|
player_hungerUpdate(player);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
2017-03-11 20:02:53 +00:00
|
|
|
if (player->saturation > 0. && player->food >= 20 && difficulty == 0) {
|
2017-03-05 18:22:00 +00:00
|
|
|
if (++player->foodTimer >= 10) {
|
2017-03-11 20:02:53 +00:00
|
|
|
if (player->entity->health < player->entity->maxHealth) {
|
|
|
|
healEntity(player->entity, player->saturation < 6. ? player->saturation / 6. : 1.);
|
|
|
|
player->foodExhaustion += (player->saturation < 6. ? player->saturation : 6.) / 6.;
|
|
|
|
}
|
2017-03-05 18:22:00 +00:00
|
|
|
player->foodTimer = 0;
|
|
|
|
}
|
|
|
|
} else if (player->food >= 18) {
|
|
|
|
if (++player->foodTimer >= 80) {
|
2017-03-11 20:02:53 +00:00
|
|
|
if (player->entity->health < player->entity->maxHealth) {
|
|
|
|
healEntity(player->entity, 1.);
|
|
|
|
player->foodExhaustion += 1.;
|
|
|
|
}
|
2017-03-05 18:22:00 +00:00
|
|
|
player->foodTimer = 0;
|
|
|
|
}
|
|
|
|
} else if (player->food <= 0) {
|
|
|
|
if (++player->foodTimer >= 80) {
|
|
|
|
if (player->entity->health > 10. || difficulty == 3 || (player->entity->health > 1. && difficulty == 2)) damageEntity(player->entity, 1., 0);
|
|
|
|
player->foodTimer = 0;
|
|
|
|
}
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
beginProfilerSection("chunks");
|
|
|
|
int32_t pcx = ((int32_t) player->entity->x >> 4);
|
|
|
|
int32_t pcz = ((int32_t) player->entity->z >> 4);
|
|
|
|
int32_t lpcx = ((int32_t) player->entity->lx >> 4);
|
|
|
|
int32_t lpcz = ((int32_t) player->entity->lz >> 4);
|
2017-03-11 20:02:53 +00:00
|
|
|
if (player->loadedChunks->entry_count == 0 || player->triggerRechunk) { // || tick_counter % 200 == 0
|
2017-01-03 19:18:52 +00:00
|
|
|
beginProfilerSection("chunkLoading_tick");
|
2017-03-05 00:11:19 +00:00
|
|
|
pthread_mutex_lock(&player->chunkRequests->data_mutex);
|
2017-03-11 20:02:53 +00:00
|
|
|
int we0 = player->loadedChunks->entry_count == 0 || player->triggerRechunk;
|
2017-01-03 19:18:52 +00:00
|
|
|
if (player->triggerRechunk) {
|
|
|
|
BEGIN_HASHMAP_ITERATION(player->loadedChunks)
|
|
|
|
struct chunk* ch = (struct chunk*) value;
|
|
|
|
if (ch->x < pcx - CHUNK_VIEW_DISTANCE || ch->x > pcx + CHUNK_VIEW_DISTANCE || ch->z < pcz - CHUNK_VIEW_DISTANCE || ch->z > pcz + CHUNK_VIEW_DISTANCE) {
|
2019-04-17 14:45:14 +00:00
|
|
|
struct chunk_request* cr = xmalloc(sizeof(struct chunk_request));
|
2019-04-18 15:59:54 +00:00
|
|
|
cr->chunk_x = ch->x;
|
|
|
|
cr->chunk_z = ch->z;
|
2017-03-11 20:02:53 +00:00
|
|
|
cr->world = world;
|
2017-01-03 19:18:52 +00:00
|
|
|
cr->load = 0;
|
2017-03-05 00:11:19 +00:00
|
|
|
add_queue(player->chunkRequests, cr);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
END_HASHMAP_ITERATION(player->loadedChunks)
|
|
|
|
}
|
|
|
|
for (int r = 0; r <= CHUNK_VIEW_DISTANCE; r++) {
|
|
|
|
int32_t x = pcx - r;
|
|
|
|
int32_t z = pcz - r;
|
|
|
|
for (int i = 0; i < ((r == 0) ? 1 : (r * 8)); i++) {
|
2019-04-17 14:45:14 +00:00
|
|
|
if (we0 || !contains_hashmap(player->loadedChunks, chunk_get_key_direct(x, z))) {
|
|
|
|
struct chunk_request* cr = xmalloc(sizeof(struct chunk_request));
|
2019-04-18 15:59:54 +00:00
|
|
|
cr->chunk_x = x;
|
|
|
|
cr->chunk_z = z;
|
2017-03-11 20:02:53 +00:00
|
|
|
cr->world = world;
|
2017-01-03 19:18:52 +00:00
|
|
|
cr->load = 1;
|
2017-03-05 00:11:19 +00:00
|
|
|
add_queue(player->chunkRequests, cr);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
if (i < 2 * r) x++;
|
|
|
|
else if (i < 4 * r) z++;
|
|
|
|
else if (i < 6 * r) x--;
|
|
|
|
else if (i < 8 * r) z--;
|
|
|
|
}
|
|
|
|
}
|
2017-03-05 00:11:19 +00:00
|
|
|
pthread_mutex_unlock(&player->chunkRequests->data_mutex);
|
2017-01-03 19:18:52 +00:00
|
|
|
player->triggerRechunk = 0;
|
2017-03-05 00:11:19 +00:00
|
|
|
pthread_cond_signal (&chunk_wake);
|
2017-01-03 19:18:52 +00:00
|
|
|
endProfilerSection("chunkLoading_tick");
|
|
|
|
}
|
|
|
|
if (lpcx != pcx || lpcz != pcz) {
|
2017-03-05 00:11:19 +00:00
|
|
|
pthread_mutex_lock(&player->chunkRequests->data_mutex);
|
2017-01-03 19:18:52 +00:00
|
|
|
for (int32_t fx = lpcx; lpcx < pcx ? (fx < pcx) : (fx > pcx); lpcx < pcx ? fx++ : fx--) {
|
|
|
|
for (int32_t fz = lpcz - CHUNK_VIEW_DISTANCE; fz <= lpcz + CHUNK_VIEW_DISTANCE; fz++) {
|
|
|
|
beginProfilerSection("chunkUnloading_live");
|
2019-04-17 14:45:14 +00:00
|
|
|
struct chunk_request* cr = xmalloc(sizeof(struct chunk_request));
|
2019-04-18 15:59:54 +00:00
|
|
|
cr->chunk_x = lpcx < pcx ? (fx - CHUNK_VIEW_DISTANCE) : (fx + CHUNK_VIEW_DISTANCE);
|
|
|
|
cr->chunk_z = fz;
|
2017-01-03 19:18:52 +00:00
|
|
|
cr->load = 0;
|
2017-03-05 00:11:19 +00:00
|
|
|
add_queue(player->chunkRequests, cr);
|
2017-01-03 19:18:52 +00:00
|
|
|
endProfilerSection("chunkUnloading_live");
|
|
|
|
beginProfilerSection("chunkLoading_live");
|
2019-04-17 14:45:14 +00:00
|
|
|
cr = xmalloc(sizeof(struct chunk_request));
|
2019-04-18 15:59:54 +00:00
|
|
|
cr->chunk_x = lpcx < pcx ? (fx + CHUNK_VIEW_DISTANCE) : (fx - CHUNK_VIEW_DISTANCE);
|
|
|
|
cr->chunk_z = fz;
|
2017-03-11 20:02:53 +00:00
|
|
|
cr->world = world;
|
2017-01-03 19:18:52 +00:00
|
|
|
cr->load = 1;
|
2017-03-05 00:11:19 +00:00
|
|
|
add_queue(player->chunkRequests, cr);
|
2017-01-03 19:18:52 +00:00
|
|
|
endProfilerSection("chunkLoading_live");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int32_t fz = lpcz; lpcz < pcz ? (fz < pcz) : (fz > pcz); lpcz < pcz ? fz++ : fz--) {
|
|
|
|
for (int32_t fx = lpcx - CHUNK_VIEW_DISTANCE; fx <= lpcx + CHUNK_VIEW_DISTANCE; fx++) {
|
|
|
|
beginProfilerSection("chunkUnloading_live");
|
2019-04-17 14:45:14 +00:00
|
|
|
struct chunk_request* cr = xmalloc(sizeof(struct chunk_request));
|
2019-04-18 15:59:54 +00:00
|
|
|
cr->chunk_x = fx;
|
|
|
|
cr->chunk_z = lpcz < pcz ? (fz - CHUNK_VIEW_DISTANCE) : (fz + CHUNK_VIEW_DISTANCE);
|
2017-01-03 19:18:52 +00:00
|
|
|
cr->load = 0;
|
2017-03-05 00:11:19 +00:00
|
|
|
add_queue(player->chunkRequests, cr);
|
2017-01-03 19:18:52 +00:00
|
|
|
endProfilerSection("chunkUnloading_live");
|
|
|
|
beginProfilerSection("chunkLoading_live");
|
2019-04-17 14:45:14 +00:00
|
|
|
cr = xmalloc(sizeof(struct chunk_request));
|
2019-04-18 15:59:54 +00:00
|
|
|
cr->chunk_x = fx;
|
|
|
|
cr->chunk_z = lpcz < pcz ? (fz + CHUNK_VIEW_DISTANCE) : (fz - CHUNK_VIEW_DISTANCE);
|
2017-01-03 19:18:52 +00:00
|
|
|
cr->load = 1;
|
2017-03-11 20:02:53 +00:00
|
|
|
cr->world = world;
|
2017-03-05 00:11:19 +00:00
|
|
|
add_queue(player->chunkRequests, cr);
|
2017-01-03 19:18:52 +00:00
|
|
|
endProfilerSection("chunkLoading_live");
|
|
|
|
}
|
|
|
|
}
|
2017-03-05 00:11:19 +00:00
|
|
|
pthread_mutex_unlock(&player->chunkRequests->data_mutex);
|
|
|
|
pthread_cond_signal (&chunk_wake);
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
endProfilerSection("chunks");
|
2017-03-05 00:11:19 +00:00
|
|
|
if (player->itemUseDuration > 0) {
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ihs = inventory_get(player, player->inventory, player->itemUseHand ? 45 : (36 + player->currentItem));
|
2017-03-05 00:11:19 +00:00
|
|
|
struct item_info* ihi = ihs == NULL ? NULL : getItemInfo(ihs->item);
|
|
|
|
if (ihs == NULL || ihi == NULL) {
|
|
|
|
player->itemUseDuration = 0;
|
|
|
|
player->entity->usingItemMain = 0;
|
|
|
|
player->entity->usingItemOff = 0;
|
|
|
|
updateMetadata(player->entity);
|
|
|
|
} else if (ihi->maxUseDuration <= player->itemUseDuration) {
|
|
|
|
if (ihi->onItemUse != NULL) (*ihi->onItemUse)(world, player, player->itemUseHand ? 45 : (36 + player->currentItem), ihs, player->itemUseDuration);
|
|
|
|
player->itemUseDuration = 0;
|
|
|
|
player->entity->usingItemMain = 0;
|
|
|
|
player->entity->usingItemOff = 0;
|
|
|
|
updateMetadata(player->entity);
|
|
|
|
} else {
|
|
|
|
if (ihi->onItemUseTick != NULL) (*ihi->onItemUseTick)(world, player, player->itemUseHand ? 45 : (36 + player->currentItem), ihs, player->itemUseDuration);
|
|
|
|
player->itemUseDuration++;
|
|
|
|
}
|
|
|
|
}
|
2017-01-03 19:18:52 +00:00
|
|
|
//if (((int32_t) player->entity->lx >> 4) != pcx || ((int32_t) player->entity->lz >> 4) != pcz || player->loadedChunks->count < CHUNK_VIEW_DISTANCE * CHUNK_VIEW_DISTANCE * 4 || player->triggerRechunk) {
|
|
|
|
//}
|
|
|
|
if (player->digging >= 0.) {
|
2019-04-17 14:45:14 +00:00
|
|
|
block bw = world_get_block(world, player->digging_position.x, player->digging_position.y, player->digging_position.z);
|
2017-01-03 19:18:52 +00:00
|
|
|
struct block_info* bi = getBlockInfo(bw);
|
|
|
|
float digspeed = 0.;
|
|
|
|
if (bi->hardness > 0.) {
|
|
|
|
pthread_mutex_lock(&player->inventory->mut);
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* ci = inventory_get(player, player->inventory, 36 + player->currentItem);
|
2017-01-03 19:18:52 +00:00
|
|
|
struct item_info* cii = ci == NULL ? NULL : getItemInfo(ci->item);
|
2019-04-14 20:45:32 +00:00
|
|
|
int hasProperTool = (cii == NULL ? 0 : tools_proficient(cii->toolType, cii->harvestLevel, bw));
|
|
|
|
int hasProperTool2 = (cii == NULL ? 0 : tools_proficient(cii->toolType, 0xFF, bw));
|
2017-01-03 19:18:52 +00:00
|
|
|
pthread_mutex_unlock(&player->inventory->mut);
|
|
|
|
int rnt = bi->material->requiresnotool;
|
|
|
|
float ds = hasProperTool2 ? cii->toolProficiency : 1.;
|
|
|
|
//efficiency enchantment
|
|
|
|
for (size_t i = 0; i < player->entity->effect_count; i++) {
|
|
|
|
if (player->entity->effects[i].effectID == POT_HASTE) {
|
|
|
|
ds *= 1. + (float) (player->entity->effects[i].amplifier + 1) * .2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (size_t i = 0; i < player->entity->effect_count; i++) {
|
|
|
|
if (player->entity->effects[i].effectID == POT_MINING_FATIGUE) {
|
|
|
|
if (player->entity->effects[i].amplifier == 0) ds *= .3;
|
|
|
|
else if (player->entity->effects[i].amplifier == 1) ds *= .09;
|
|
|
|
else if (player->entity->effects[i].amplifier == 2) ds *= .0027;
|
|
|
|
else ds *= .00081;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//if in water and not in aqua affintity enchant ds /= 5.;
|
|
|
|
if (!player->entity->onGround) ds /= 5.;
|
|
|
|
digspeed = ds / (bi->hardness * ((hasProperTool || rnt) ? 30. : 100.));
|
|
|
|
}
|
|
|
|
player->digging += (player->digging == 0. ? 2. : 1.) * digspeed;
|
|
|
|
BEGIN_BROADCAST_EXCEPT_DIST(player, player->entity, 128.)
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_BLOCKBREAKANIMATION;
|
|
|
|
pkt->data.play_client.blockbreakanimation.entity_id = player->entity->id;
|
|
|
|
memcpy(&pkt->data.play_server.playerdigging.location, &player->digging_position, sizeof(struct encpos));
|
|
|
|
pkt->data.play_client.blockbreakanimation.destroy_stage = (int8_t)(player->digging * 9);
|
|
|
|
add_queue(bc_player->outgoingPacket, pkt);
|
|
|
|
END_BROADCAST(player->world->players)
|
|
|
|
}
|
|
|
|
beginProfilerSection("entity_transmission");
|
2017-02-06 02:35:21 +00:00
|
|
|
if (tick_counter % 20 == 0) {
|
|
|
|
BEGIN_HASHMAP_ITERATION(player->loadedEntities)
|
|
|
|
struct entity* ent = (struct entity*) value;
|
|
|
|
if (entity_distsq(ent, player->entity) > (CHUNK_VIEW_DISTANCE * 16.) * (CHUNK_VIEW_DISTANCE * 16.)) {
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_DESTROYENTITIES;
|
|
|
|
pkt->data.play_client.destroyentities.count = 1;
|
|
|
|
pkt->data.play_client.destroyentities.entity_ids = xmalloc(sizeof(int32_t));
|
|
|
|
pkt->data.play_client.destroyentities.entity_ids[0] = ent->id;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
put_hashmap(player->loadedEntities, ent->id, NULL);
|
|
|
|
put_hashmap(ent->loadingPlayers, player->entity->id, NULL);
|
|
|
|
}
|
|
|
|
END_HASHMAP_ITERATION(player->loadedEntities)
|
2017-01-03 19:18:52 +00:00
|
|
|
}
|
|
|
|
endProfilerSection("entity_transmission");
|
|
|
|
beginProfilerSection("player_transmission");
|
2019-04-18 15:59:54 +00:00
|
|
|
//int32_t chunk_x = ((int32_t) player->entity->x) >> 4;
|
|
|
|
//int32_t chunk_z = ((int32_t) player->entity->z) >> 4;
|
|
|
|
//for (int32_t icx = chunk_x - CHUNK_VIEW_DISTANCE; icx <= chunk_x + CHUNK_VIEW_DISTANCE; icx++)
|
|
|
|
//for (int32_t icz = chunk_z - CHUNK_VIEW_DISTANCE; icz <= chunk_z + CHUNK_VIEW_DISTANCE; icz++) {
|
2019-04-17 14:45:14 +00:00
|
|
|
//struct chunk* ch = world_get_chunk(player->world, icx, icz);
|
2017-01-03 19:18:52 +00:00
|
|
|
//if (ch != NULL) {
|
|
|
|
BEGIN_HASHMAP_ITERATION(player->world->entities)
|
|
|
|
struct entity* ent = (struct entity*) value;
|
|
|
|
if (ent == player->entity || contains_hashmap(player->loadedEntities, ent->id) || entity_distsq(player->entity, ent) > (CHUNK_VIEW_DISTANCE * 16.) * (CHUNK_VIEW_DISTANCE * 16.)) continue;
|
|
|
|
if (ent->type == ENT_PLAYER) loadPlayer(player, ent->data.player.player);
|
|
|
|
else loadEntity(player, ent);
|
|
|
|
END_HASHMAP_ITERATION(player->world->entities)
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
endProfilerSection("player_transmission");
|
2017-03-11 20:02:53 +00:00
|
|
|
BEGIN_HASHMAP_ITERATION (plugins)
|
|
|
|
struct plugin* plugin = value;
|
|
|
|
if (plugin->tick_player != NULL) (*plugin->tick_player)(player->world, player);
|
|
|
|
END_HASHMAP_ITERATION (plugins)
|
2017-01-03 19:18:52 +00:00
|
|
|
//printf("%i\n", player->loadedChunks->size);
|
|
|
|
}
|
|
|
|
|
2016-12-30 08:12:04 +00:00
|
|
|
int player_onGround(struct player* player) {
|
|
|
|
struct entity* entity = player->entity;
|
|
|
|
struct boundingbox obb;
|
|
|
|
getEntityCollision(entity, &obb);
|
|
|
|
if (obb.minX == obb.maxX || obb.minZ == obb.maxZ || obb.minY == obb.maxY) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
obb.minY += -.08;
|
|
|
|
struct boundingbox pbb;
|
|
|
|
getEntityCollision(entity, &pbb);
|
|
|
|
double ny = -.08;
|
|
|
|
for (int32_t x = floor(obb.minX); x < floor(obb.maxX + 1.); x++) {
|
|
|
|
for (int32_t z = floor(obb.minZ); z < floor(obb.maxZ + 1.); z++) {
|
|
|
|
for (int32_t y = floor(obb.minY); y < floor(obb.maxY + 1.); y++) {
|
2019-04-17 14:45:14 +00:00
|
|
|
block b = world_get_block(entity->world, x, y, z);
|
2016-12-30 08:12:04 +00:00
|
|
|
if (b == 0) continue;
|
|
|
|
struct block_info* bi = getBlockInfo(b);
|
|
|
|
if (bi == NULL) continue;
|
|
|
|
for (size_t i = 0; i < bi->boundingBox_count; i++) {
|
|
|
|
struct boundingbox* bb = &bi->boundingBoxes[i];
|
|
|
|
if (b > 0 && bb->minX != bb->maxX && bb->minY != bb->maxY && bb->minZ != bb->maxZ) {
|
|
|
|
if (bb->maxX + x > obb.minX && bb->minX + x < obb.maxX ? (bb->maxY + y > obb.minY && bb->minY + y < obb.maxY ? bb->maxZ + z > obb.minZ && bb->minZ + z < obb.maxZ : 0) : 0) {
|
|
|
|
if (pbb.maxX > bb->minX + x && pbb.minX < bb->maxX + x && pbb.maxZ > bb->minZ + z && pbb.minZ < bb->maxZ + z) {
|
|
|
|
double t;
|
|
|
|
if (ny > 0. && pbb.maxY <= bb->minY + y) {
|
|
|
|
t = bb->minY + y - pbb.maxY;
|
|
|
|
if (t < ny) {
|
|
|
|
ny = t;
|
|
|
|
}
|
|
|
|
} else if (ny < 0. && pbb.minY >= bb->maxY + y) {
|
|
|
|
t = bb->maxY + y - pbb.minY;
|
|
|
|
if (t > ny) {
|
|
|
|
ny = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fabs(-.08 - ny) > .001;
|
|
|
|
}
|
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
void player_kick(struct player* player, char* message) {
|
2016-12-30 08:12:04 +00:00
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_DISCONNECT;
|
|
|
|
size_t sl = strlen(message);
|
|
|
|
pkt->data.play_client.disconnect.reason = xmalloc(sl + 512);
|
2016-12-30 20:04:55 +00:00
|
|
|
snprintf(pkt->data.play_client.disconnect.reason, sl + 512, "{\"text\": \"%s\", \"color\": \"red\"}", message);
|
2016-12-30 08:12:04 +00:00
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
if (player->conn != NULL) player->conn->disconnect = 1;
|
2016-12-30 20:04:55 +00:00
|
|
|
broadcastf("red", "Kicked Player %s for reason: %s", player->name, message);
|
2016-12-30 08:12:04 +00:00
|
|
|
}
|
|
|
|
|
2016-12-29 08:00:22 +00:00
|
|
|
float player_getAttackStrength(struct player* player, float adjust) {
|
|
|
|
float cooldownPeriod = 4.;
|
2019-04-18 15:59:54 +00:00
|
|
|
struct slot* sl = inventory_get(player, player->inventory, 36 + player->currentItem);
|
2016-12-29 08:00:22 +00:00
|
|
|
if (sl != NULL) {
|
|
|
|
struct item_info* ii = getItemInfo(sl->item);
|
|
|
|
if (ii != NULL) {
|
|
|
|
cooldownPeriod = ii->attackSpeed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
float str = ((float) (tick_counter - player->lastSwing) + adjust) * cooldownPeriod / 20.;
|
|
|
|
if (str > 1.) str = 1.;
|
|
|
|
if (str < 0.) str = 0.;
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
void player_teleport(struct player* player, double x, double y, double z) {
|
2016-12-29 08:00:22 +00:00
|
|
|
player->entity->x = x;
|
|
|
|
player->entity->y = y;
|
|
|
|
player->entity->z = z;
|
2016-12-30 03:18:53 +00:00
|
|
|
player->entity->lx = x;
|
|
|
|
player->entity->ly = y;
|
|
|
|
player->entity->lz = z;
|
2016-12-30 08:48:35 +00:00
|
|
|
player->triggerRechunk = 1;
|
2017-01-01 09:39:37 +00:00
|
|
|
player->spawnedIn = 0;
|
2016-12-29 08:00:22 +00:00
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
2016-12-30 03:18:53 +00:00
|
|
|
pkt->id = PKT_PLAY_CLIENT_ENTITYVELOCITY;
|
|
|
|
pkt->data.play_client.entityvelocity.entity_id = player->entity->id;
|
|
|
|
pkt->data.play_client.entityvelocity.velocity_x = 0;
|
|
|
|
pkt->data.play_client.entityvelocity.velocity_y = 0;
|
|
|
|
pkt->data.play_client.entityvelocity.velocity_z = 0;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
pkt = xmalloc(sizeof(struct packet));
|
2016-12-29 08:00:22 +00:00
|
|
|
pkt->id = PKT_PLAY_CLIENT_PLAYERPOSITIONANDLOOK;
|
|
|
|
pkt->data.play_client.playerpositionandlook.x = player->entity->x;
|
|
|
|
pkt->data.play_client.playerpositionandlook.y = player->entity->y;
|
|
|
|
pkt->data.play_client.playerpositionandlook.z = player->entity->z;
|
|
|
|
pkt->data.play_client.playerpositionandlook.yaw = player->entity->yaw;
|
|
|
|
pkt->data.play_client.playerpositionandlook.pitch = player->entity->pitch;
|
|
|
|
pkt->data.play_client.playerpositionandlook.flags = 0x0;
|
2017-03-11 20:02:53 +00:00
|
|
|
pkt->data.play_client.playerpositionandlook.teleport_id = tick_counter;
|
|
|
|
player->lastTeleportID = pkt->data.play_client.playerpositionandlook.teleport_id;
|
2016-12-29 08:00:22 +00:00
|
|
|
add_queue(player->outgoingPacket, pkt);
|
2017-03-11 20:02:53 +00:00
|
|
|
/*BEGIN_HASHMAP_ITERATION(player->entity->loadingPlayers)
|
|
|
|
struct player* bp = value;
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_DESTROYENTITIES;
|
|
|
|
pkt->data.play_client.destroyentities.count = 1;
|
|
|
|
pkt->data.play_client.destroyentities.entity_ids = xmalloc(sizeof(int32_t));
|
|
|
|
pkt->data.play_client.destroyentities.entity_ids[0] = player->entity->id;
|
|
|
|
add_queue(bp->outgoingPacket, pkt);
|
|
|
|
put_hashmap(bp->loadedEntities, player->entity->id, NULL);
|
|
|
|
pthread_rwlock_unlock(&player->entity->loadingPlayers->data_mutex);
|
|
|
|
put_hashmap(player->entity->loadingPlayers, bp->entity->id, NULL);
|
|
|
|
pthread_rwlock_rdlock(&player->entity->loadingPlayers->data_mutex);
|
|
|
|
END_HASHMAP_ITERATION(player->entity->loadingPlayers)
|
|
|
|
BEGIN_HASHMAP_ITERATION(player->loadedEntities)
|
|
|
|
struct entity* be = value;
|
|
|
|
if (be->type != ENT_PLAYER) continue;
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_DESTROYENTITIES;
|
|
|
|
pkt->data.play_client.destroyentities.count = 1;
|
|
|
|
pkt->data.play_client.destroyentities.entity_ids = xmalloc(sizeof(int32_t));
|
|
|
|
pkt->data.play_client.destroyentities.entity_ids[0] = be->id;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
put_hashmap(player->loadedEntities, be->id, NULL);
|
|
|
|
put_hashmap(be->loadingPlayers, player->entity->id, NULL);
|
|
|
|
END_HASHMAP_ITERATION(player->loadedEntities)*/
|
2017-01-03 19:51:34 +00:00
|
|
|
// if (player->tps > 0) player->tps--;
|
2016-12-29 08:00:22 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
struct player* player_get_by_name(char* name) {
|
2017-01-01 09:39:37 +00:00
|
|
|
BEGIN_HASHMAP_ITERATION (players)
|
|
|
|
struct player* player = (struct player*) value;
|
|
|
|
if (player != NULL && streq_nocase(name, player->name)) {
|
|
|
|
BREAK_HASHMAP_ITERATION(players);
|
|
|
|
return player;
|
2016-12-30 03:18:53 +00:00
|
|
|
}
|
2017-01-01 09:39:37 +00:00
|
|
|
END_HASHMAP_ITERATION (players)
|
2016-12-30 03:18:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void player_closeWindow(struct player* player, uint16_t windowID) {
|
|
|
|
struct inventory* inv = NULL;
|
|
|
|
if (windowID == 0 && player->openInv == NULL) inv = player->inventory;
|
|
|
|
else if (player->openInv != NULL && windowID == player->openInv->windowID) inv = player->openInv;
|
|
|
|
if (inv != NULL) {
|
2017-01-03 19:18:52 +00:00
|
|
|
pthread_mutex_lock(&inv->mut);
|
2016-12-30 03:18:53 +00:00
|
|
|
if (player->inHand != NULL) {
|
|
|
|
dropPlayerItem(player, player->inHand);
|
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
player->inHand = NULL;
|
|
|
|
}
|
|
|
|
if (inv->type == INVTYPE_PLAYERINVENTORY) {
|
|
|
|
for (int i = 1; i < 5; i++) {
|
|
|
|
if (inv->slots[i] != NULL) {
|
|
|
|
dropPlayerItem(player, inv->slots[i]);
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, i, NULL, 0, 1);
|
2016-12-30 03:18:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (inv->type == INVTYPE_WORKBENCH) {
|
|
|
|
for (int i = 1; i < 10; i++) {
|
|
|
|
if (inv->slots[i] != NULL) {
|
|
|
|
dropPlayerItem(player, inv->slots[i]);
|
2019-04-18 15:59:54 +00:00
|
|
|
inventory_set_slot(player, inv, i, NULL, 0, 1);
|
2016-12-30 03:18:53 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-03 19:18:52 +00:00
|
|
|
pthread_mutex_unlock(&inv->mut);
|
2017-01-03 23:28:42 +00:00
|
|
|
freeInventory(inv);
|
2016-12-30 03:18:53 +00:00
|
|
|
inv = NULL;
|
|
|
|
} else if (inv->type == INVTYPE_CHEST) {
|
2019-04-18 15:59:54 +00:00
|
|
|
if (inv->tile != NULL) {
|
2016-12-30 03:18:53 +00:00
|
|
|
BEGIN_BROADCAST_DIST(player->entity, 128.)
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_BLOCKACTION;
|
2019-04-18 15:59:54 +00:00
|
|
|
pkt->data.play_client.blockaction.location.x = inv->tile->x;
|
|
|
|
pkt->data.play_client.blockaction.location.y = inv->tile->y;
|
|
|
|
pkt->data.play_client.blockaction.location.z = inv->tile->z;
|
2016-12-30 03:18:53 +00:00
|
|
|
pkt->data.play_client.blockaction.action_id = 1;
|
2017-01-01 09:39:37 +00:00
|
|
|
pkt->data.play_client.blockaction.action_param = inv->players->entry_count - 1;
|
2019-04-18 15:59:54 +00:00
|
|
|
pkt->data.play_client.blockaction.block_type = world_get_block(player->world, inv->tile->x, inv->tile->y, inv->tile->z) >> 4;
|
2016-12-30 03:18:53 +00:00
|
|
|
add_queue(bc_player->outgoingPacket, pkt);
|
2017-01-01 09:39:37 +00:00
|
|
|
END_BROADCAST(player->world->players)
|
2016-12-30 03:18:53 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-03 19:18:52 +00:00
|
|
|
if (inv != NULL) {
|
|
|
|
if (inv->type != INVTYPE_PLAYERINVENTORY) put_hashmap(inv->players, player->entity->id, NULL);
|
|
|
|
pthread_mutex_unlock(&inv->mut);
|
|
|
|
}
|
2016-12-30 03:18:53 +00:00
|
|
|
}
|
|
|
|
player->openInv = NULL; // TODO: free sometimes?
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
void player_set_gamemode(struct player* player, int gamemode) {
|
2016-12-30 03:18:53 +00:00
|
|
|
if (gamemode != -1) {
|
|
|
|
player->gamemode = gamemode;
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_CHANGEGAMESTATE;
|
|
|
|
pkt->data.play_client.changegamestate.reason = 3;
|
|
|
|
pkt->data.play_client.changegamestate.value = gamemode;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
}
|
|
|
|
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
|
|
pkt->id = PKT_PLAY_CLIENT_PLAYERABILITIES;
|
|
|
|
pkt->data.play_client.playerabilities.flags = player->gamemode == 1 ? (0x04 | 0x08) : 0x0;
|
|
|
|
pkt->data.play_client.playerabilities.flying_speed = .05;
|
|
|
|
pkt->data.play_client.playerabilities.field_of_view_modifier = .1;
|
|
|
|
add_queue(player->outgoingPacket, pkt);
|
|
|
|
}
|
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
void player_free(struct player* player) {
|
2016-12-28 10:18:41 +00:00
|
|
|
struct packet* pkt = NULL;
|
|
|
|
while ((pkt = pop_nowait_queue(player->incomingPacket)) != NULL) {
|
|
|
|
freePacket(STATE_PLAY, 0, pkt);
|
2017-01-01 09:39:37 +00:00
|
|
|
xfree(pkt);
|
2016-12-28 10:18:41 +00:00
|
|
|
}
|
2016-12-26 08:31:26 +00:00
|
|
|
del_queue(player->incomingPacket);
|
2016-12-28 10:18:41 +00:00
|
|
|
while ((pkt = pop_nowait_queue(player->outgoingPacket)) != NULL) {
|
|
|
|
freePacket(STATE_PLAY, 1, pkt);
|
2017-01-01 09:39:37 +00:00
|
|
|
xfree(pkt);
|
2016-12-28 10:18:41 +00:00
|
|
|
}
|
2017-01-01 09:39:37 +00:00
|
|
|
del_queue(player->outgoingPacket);
|
2019-04-17 14:45:14 +00:00
|
|
|
struct chunk_request* cr;
|
2017-03-05 00:11:19 +00:00
|
|
|
while ((cr = pop_nowait_queue(player->chunkRequests)) != NULL) {
|
|
|
|
xfree(cr);
|
|
|
|
}
|
|
|
|
del_queue(player->chunkRequests);
|
2016-12-28 10:18:41 +00:00
|
|
|
if (player->inHand != NULL) {
|
|
|
|
freeSlot(player->inHand);
|
|
|
|
xfree(player->inHand);
|
|
|
|
}
|
2017-01-01 09:39:37 +00:00
|
|
|
del_hashmap(player->loadedChunks);
|
|
|
|
del_hashmap(player->loadedEntities);
|
2016-12-28 10:18:41 +00:00
|
|
|
freeInventory(player->inventory);
|
|
|
|
xfree(player->inventory);
|
2016-06-25 08:34:36 +00:00
|
|
|
xfree(player->name);
|
|
|
|
xfree(player);
|
|
|
|
}
|
2017-09-10 03:00:32 +00:00
|
|
|
|
2019-04-17 13:38:46 +00:00
|
|
|
block player_can_place_block(struct player* player, block blk, int32_t x, int32_t y, int32_t z, uint8_t face) {
|
2017-09-10 03:00:32 +00:00
|
|
|
struct block_info* bi = getBlockInfo(blk);
|
|
|
|
block tbb = blk;
|
|
|
|
if (bi != NULL && bi->onBlockPlacedPlayer != NULL) tbb = (*bi->onBlockPlacedPlayer)(player, player->world, tbb, x, y, z, face);
|
|
|
|
BEGIN_HASHMAP_ITERATION (plugins)
|
|
|
|
struct plugin* plugin = value;
|
|
|
|
if (plugin->onBlockPlacedPlayer != NULL) tbb = (*plugin->onBlockPlacedPlayer)(player, player->world, tbb, x, y, z, face);
|
|
|
|
END_HASHMAP_ITERATION (plugins)
|
|
|
|
bi = getBlockInfo(blk);
|
|
|
|
if (bi != NULL && bi->canBePlaced != NULL && !(*bi->canBePlaced)(player->world, tbb, x, y, z)) {
|
|
|
|
return 0;
|
|
|
|
}
|
2019-04-17 14:45:14 +00:00
|
|
|
block b = world_get_block(player->world, x, y, z);
|
2018-01-16 21:26:15 +00:00
|
|
|
return (b == 0 || getBlockInfo(b)->material->replacable) ? tbb : 0;
|
2017-09-10 03:00:32 +00:00
|
|
|
}
|