#include "Player.hpp" #include "../content/ContentLUT.hpp" #include "../physics/Hitbox.hpp" #include "../physics/PhysicsSolver.hpp" #include "../voxels/Chunks.hpp" #include "../world/Level.hpp" #include "../window/Events.hpp" #include "../window/Camera.hpp" #include "../items/Inventory.hpp" #include "../objects/Entities.hpp" #include "../objects/rigging.hpp" #include #include #include const float CROUCH_SPEED_MUL = 0.35f; const float RUN_SPEED_MUL = 1.5f; const float PLAYER_GROUND_DAMPING = 10.0f; const float PLAYER_AIR_DAMPING = 7.0f; const float FLIGHT_SPEED_MUL = 4.0f; const float CHEAT_SPEED_MUL = 5.0f; const float JUMP_FORCE = 8.0f; Player::Player(Level* level, glm::vec3 position, float speed, std::shared_ptr inv, entityid_t eid) : level(level), speed(speed), chosenSlot(0), position(position), inventory(std::move(inv)), eid(eid), camera(level->getCamera("base:first-person")), spCamera(level->getCamera("base:third-person-front")), tpCamera(level->getCamera("base:third-person-back")), currentCamera(camera) { camera->setFov(glm::radians(90.0f)); spCamera->setFov(glm::radians(90.0f)); tpCamera->setFov(glm::radians(90.0f)); } Player::~Player() { } void Player::updateEntity() { if (eid == 0) { auto& def = level->content->entities.require("base:player"); eid = level->entities->spawn(def, getPosition()); } else if (auto entity = level->entities->get(eid)) { position = entity->getTransform().pos; } else { // TODO: check if chunk loaded } } Hitbox* Player::getHitbox() { if (auto entity = level->entities->get(eid)) { return &entity->getRigidbody().hitbox; } return nullptr; } void Player::updateInput(PlayerInput& input, float delta) { auto hitbox = getHitbox(); if (hitbox == nullptr) { return; } bool crouch = input.shift && hitbox->grounded && !input.sprint; float speed = this->speed; if (flight){ speed *= FLIGHT_SPEED_MUL; } if (input.cheat){ speed *= CHEAT_SPEED_MUL; } hitbox->crouching = crouch; if (crouch) { speed *= CROUCH_SPEED_MUL; } else if (input.sprint) { speed *= RUN_SPEED_MUL; } glm::vec3 dir(0,0,0); if (input.moveForward){ dir += camera->dir; } if (input.moveBack){ dir -= camera->dir; } if (input.moveRight){ dir += camera->right; } if (input.moveLeft){ dir -= camera->right; } if (glm::length(dir) > 0.0f){ dir = glm::normalize(dir); hitbox->velocity += dir * speed * delta * 9.0f; } hitbox->linearDamping = PLAYER_GROUND_DAMPING; hitbox->verticalDamping = flight; hitbox->gravityScale = flight ? 0.0f : 1.0f; if (flight){ hitbox->linearDamping = PLAYER_AIR_DAMPING; if (input.jump){ hitbox->velocity.y += speed * delta * 9; } if (input.shift){ hitbox->velocity.y -= speed * delta * 9; } } if (!hitbox->grounded) { hitbox->linearDamping = PLAYER_AIR_DAMPING; } if (input.jump && hitbox->grounded){ hitbox->velocity.y = JUMP_FORCE; } if ((input.flight && !noclip) || (input.noclip && flight == noclip)){ flight = !flight; if (flight){ hitbox->velocity.y += 1.0f; } } hitbox->type = noclip ? BodyType::KINEMATIC : BodyType::DYNAMIC; if (input.noclip) { noclip = !noclip; } input.noclip = false; input.flight = false; } void Player::updateSelectedEntity() { selectedEid = selection.entity; } #include "../window/Window.hpp" void Player::postUpdate() { auto entity = level->entities->get(eid); if (!entity.has_value()) { return; } auto& hitbox = entity->getRigidbody().hitbox; position = hitbox.position; if (flight && hitbox.grounded) { flight = false; } if (spawnpoint.y <= 0.1) { attemptToFindSpawnpoint(); } auto& skeleton = entity->getSkeleton(); skeleton.visible = currentCamera != camera; size_t bodyIndex = skeleton.config->find("body")->getIndex(); size_t headIndex = skeleton.config->find("head")->getIndex(); skeleton.pose.matrices[bodyIndex] = glm::rotate(glm::mat4(1.0f), glm::radians(cam.x), glm::vec3(0, 1, 0)); skeleton.pose.matrices[headIndex] = glm::rotate( glm::mat4(1.0f), glm::radians(cam.y), glm::vec3(1, 0, 0)); } void Player::teleport(glm::vec3 position) { this->position = position; if (auto hitbox = getHitbox()) { hitbox->position = position; } } void Player::attemptToFindSpawnpoint() { glm::vec3 newpos ( position.x + (rand() % 200 - 100), rand() % 80 + 100, position.z + (rand() % 200 - 100) ); while (newpos.y > 0 && !level->chunks->isObstacleBlock(newpos.x, newpos.y-2, newpos.z)) { newpos.y--; } voxel* headvox = level->chunks->get(newpos.x, newpos.y+1, newpos.z); if (level->chunks->isObstacleBlock(newpos.x, newpos.y, newpos.z) || headvox == nullptr || headvox->id != 0) { return; } spawnpoint = newpos + glm::vec3(0.5f, 0.0f, 0.5f); teleport(spawnpoint); } void Player::setChosenSlot(int index) { chosenSlot = index; } int Player::getChosenSlot() const { return chosenSlot; } float Player::getSpeed() const { return speed; } bool Player::isFlight() const { return flight; } void Player::setFlight(bool flag) { this->flight = flag; } bool Player::isNoclip() const { return noclip; } void Player::setNoclip(bool flag) { this->noclip = flag; } entityid_t Player::getEntity() const { return eid; } void Player::setEntity(entityid_t eid) { this->eid = eid; } entityid_t Player::getSelectedEntity() const { return selectedEid; } std::shared_ptr Player::getInventory() const { return inventory; } void Player::setSpawnPoint(glm::vec3 spawnpoint) { this->spawnpoint = spawnpoint; } glm::vec3 Player::getSpawnPoint() const { return spawnpoint; } std::unique_ptr Player::serialize() const { auto root = std::make_unique(); auto& posarr = root->putList("position"); posarr.put(position.x); posarr.put(position.y); posarr.put(position.z); auto& rotarr = root->putList("rotation"); rotarr.put(cam.x); rotarr.put(cam.y); rotarr.put(cam.z); auto& sparr = root->putList("spawnpoint"); sparr.put(spawnpoint.x); sparr.put(spawnpoint.y); sparr.put(spawnpoint.z); root->put("flight", flight); root->put("noclip", noclip); root->put("chosen-slot", chosenSlot); root->put("entity", eid); root->put("inventory", inventory->serialize()); auto found = std::find( level->cameras.begin(), level->cameras.end(), currentCamera); if (found != level->cameras.end()) { root->put("camera", level->content->getIndices( ResourceType::CAMERA).getName(found - level->cameras.begin())); } return root; } void Player::deserialize(dynamic::Map *src) { auto posarr = src->list("position"); position.x = posarr->num(0); position.y = posarr->num(1); position.z = posarr->num(2); camera->position = position; auto rotarr = src->list("rotation"); cam.x = rotarr->num(0); cam.y = rotarr->num(1); if (rotarr->size() > 2) { cam.z = rotarr->num(2); } if (src->has("spawnpoint")) { auto sparr = src->list("spawnpoint"); setSpawnPoint(glm::vec3( sparr->num(0), sparr->num(1), sparr->num(2) )); } else { setSpawnPoint(position); } src->flag("flight", flight); src->flag("noclip", noclip); setChosenSlot(src->get("chosen-slot", getChosenSlot())); src->num("entity", eid); if (auto invmap = src->map("inventory")) { getInventory()->deserialize(invmap.get()); } if (src->has("camera")) { std::string name; src->str("camera", name); if (auto camera = level->getCamera(name)) { currentCamera = camera; } } } void Player::convert(dynamic::Map* data, const ContentLUT* lut) { auto players = data->list("players"); if (players) { for (uint i = 0; i < players->size(); i++) { auto playerData = players->map(i); if (auto inventory = playerData->map("inventory")) { Inventory::convert(inventory.get(), lut); } } } else { if (auto inventory = data->map("inventory")) { Inventory::convert(inventory.get(), lut); } } }