123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788 |
- #include "Entity.h"
- #include <Text.h>
- #include "BlockType.h"
- #include "Dimension.h"
- #include "EntityRemovedUpdate.h"
- #include "Game.h"
- #include "ItemSkill.h"
- #include "NoBlock.h"
- ActionTarget::ActionTarget(Vec3<int> blockPos, Direction blockSide)
- : blockPos(blockPos),
- targetBlockSide(blockSide),
- entityId(-1)
- {}
- ActionTarget::ActionTarget(int entityId)
- : entityId(entityId)
- {}
- bool ActionTarget::isBlock(
- Framework::Vec3<int> blockPos, Direction blockSide) const
- {
- return this->entityId == -1 && this->blockPos == blockPos
- && (this->targetBlockSide == targetBlockSide
- || blockSide == NO_DIRECTION);
- }
- bool ActionTarget::isEntity(int entityId) const
- {
- return this->entityId == entityId;
- }
- void ActionTarget::useItemSkillOnTarget(
- Entity* zActor, ItemSkill* zItemSkill, Item* zUsedItem)
- {
- if (entityId >= 0)
- {
- Entity* target = Game::INSTANCE->zEntity(entityId);
- if (target) zItemSkill->use(zActor, zUsedItem, target);
- }
- else
- {
- Block* block = Game::INSTANCE->zRealBlockInstance(
- blockPos, zActor->getDimensionId());
- if (block) zItemSkill->use(zActor, zUsedItem, block);
- }
- }
- void ActionTarget::interactItemSkillOnTarget(
- Entity* zActor, ItemSkill* zItemSkill, Item* zUsedItem)
- {
- if (zItemSkill)
- {
- if (entityId >= 0)
- {
- Entity* target = Game::INSTANCE->zEntity(entityId);
- if (target) zItemSkill->interact(zActor, zUsedItem, target);
- }
- else
- {
- Block* block = Game::INSTANCE->zRealBlockInstance(
- blockPos, zActor->getDimensionId());
- if (block) zItemSkill->interact(zActor, zUsedItem, block);
- }
- }
- else
- {
- if (entityId >= 0)
- {
- Block* block = Game::INSTANCE->zRealBlockInstance(
- blockPos, zActor->getDimensionId());
- if (block) block->interact(zUsedItem, zActor);
- }
- else
- {
- Block* block = Game::INSTANCE->zRealBlockInstance(
- blockPos, zActor->getDimensionId());
- if (block) block->interact(zUsedItem, zActor);
- }
- }
- }
- void ActionTarget::placeBlock(Entity* zActor, Item* zItem)
- {
- if (zActor->getStamina() > 0.2f)
- {
- if (zItem->canBePlacedAt(zActor->getDimensionId(),
- blockPos + getDirection(targetBlockSide)))
- {
- Block* block = zItem->zPlacedBlockType()->createBlockAt(
- blockPos + getDirection(targetBlockSide),
- zActor->getDimensionId(),
- zItem);
- if (block)
- {
- Game::INSTANCE->zDimension(zActor->getDimensionId())
- ->placeBlock(block->getPos(), block);
- zItem->onPlaced();
- zActor->setStamina(zActor->getStamina() - 0.2f);
- }
- }
- }
- }
- void ActionTarget::toMessage(
- const ActionTarget* zTarget, int dimensionId, NetworkMessage* zMsg)
- {
- if (zTarget)
- {
- if (zTarget->entityId >= 0)
- {
- char* message = new char[6];
- message[0] = 3;
- message[1] = 1;
- *(int*)(message + 2) = zTarget->entityId;
- zMsg->setMessage(message, 6);
- }
- else
- {
- Framework::Text targetUIML = "";
- auto block
- = Game::INSTANCE->zBlockAt(zTarget->blockPos, dimensionId);
- if (block.isA())
- {
- targetUIML = block.getA()->getTargetUIML();
- }
- else if (block.isB())
- {
- targetUIML = StaticRegistry<BlockType>::INSTANCE
- .zElement(block.getB())
- ->getTargetUIML();
- }
- char* message = new char[18 + targetUIML.getLength() + 2];
- message[0] = 3;
- message[1] = 2;
- *(int*)(message + 2) = zTarget->blockPos.x;
- *(int*)(message + 6) = zTarget->blockPos.y;
- *(int*)(message + 10) = zTarget->blockPos.z;
- *(int*)(message + 14) = zTarget->targetBlockSide;
- short len = (short)targetUIML.getLength();
- *(short*)(message + 18) = len;
- memcpy(message + 20, targetUIML.getText(), len);
- zMsg->setMessage(message, 18 + len + 2);
- }
- }
- else
- {
- char* message = new char[2];
- message[0] = 3;
- message[1] = 0;
- zMsg->setMessage(message, 2);
- }
- }
- void ActionTarget::save(ActionTarget* zTarget, Framework::StreamWriter* zWriter)
- {
- if (zTarget)
- {
- if (zTarget->entityId >= 0)
- {
- char b = 1;
- zWriter->schreibe(&b, 1);
- zWriter->schreibe((char*)&zTarget->entityId, 4);
- }
- else
- {
- char b = 2;
- zWriter->schreibe(&b, 1);
- zWriter->schreibe((char*)&zTarget->blockPos.x, 4);
- zWriter->schreibe((char*)&zTarget->blockPos.y, 4);
- zWriter->schreibe((char*)&zTarget->blockPos.z, 4);
- zWriter->schreibe((char*)&zTarget->targetBlockSide, 4);
- }
- }
- else
- {
- char b = 0;
- zWriter->schreibe(&b, 1);
- }
- }
- ActionTarget* ActionTarget::load(Framework::StreamReader* zReader)
- {
- char b;
- zReader->lese(&b, 1);
- if (b == 1)
- {
- int id;
- zReader->lese((char*)&id, 4);
- return new ActionTarget(id);
- }
- else if (b == 2)
- {
- Framework::Vec3<int> pos;
- Direction side;
- zReader->lese((char*)&pos.x, 4);
- zReader->lese((char*)&pos.y, 4);
- zReader->lese((char*)&pos.z, 4);
- zReader->lese((char*)&side, 4);
- return new ActionTarget(pos, side);
- }
- return 0;
- }
- Entity::Entity(
- int typeId, Framework::Vec3<float> location, int dimensionId, int entityId)
- : Inventory(location, dimensionId, true),
- chatSecurityLevel(0),
- speed(0, 0, 0),
- faceDir(1, 0, 0),
- target(0),
- typeId(typeId),
- removed(0),
- gravityMultiplier(1.f),
- id(entityId),
- placeBlockCooldown(0)
- {}
- void Entity::onDeath()
- {
- removed = 1;
- Game::INSTANCE->requestWorldUpdate(
- new EntityRemovedUpdate(id, dimensionId, location));
- }
- void Entity::useItem(int typeId, Item* zItem, bool left)
- {
- if (left)
- {
- if (!zItem || zItem->isUsable())
- {
- cs.lock();
- if (target)
- {
- ItemSkill* selected = zSkill(typeId);
- if (!selected)
- {
- selected
- = StaticRegistry<ItemType>::INSTANCE.zElement(typeId)
- ->createDefaultItemSkill();
- if (selected) skills.add(selected);
- }
- if (!selected)
- {
- selected = zSkill(ItemTypeEnum::PLAYER_HAND);
- }
- target->useItemSkillOnTarget(this, selected, zItem);
- }
- cs.unlock();
- }
- else if (left)
- {
- useItem(ItemTypeEnum::PLAYER_HAND, 0, left);
- }
- }
- else
- {
- if (zItem && zItem->isEatable())
- { // eat item
- zItem->applyFoodEffects(this);
- }
- else if (zItem && zItem->isPlaceable())
- { // place item
- if (placeBlockCooldown <= 0)
- {
- cs.lock();
- if (target)
- {
- target->placeBlock(this, zItem);
- placeBlockCooldown = 15;
- }
- cs.unlock();
- }
- }
- else if (!zItem || zItem->isUsable())
- { // use item skill
- cs.lock();
- if (target)
- {
- ItemSkill* selected = zSkill(typeId);
- if (!selected)
- {
- selected
- = StaticRegistry<ItemType>::INSTANCE.zElement(typeId)
- ->createDefaultItemSkill();
- if (selected) skills.add(selected);
- }
- target->interactItemSkillOnTarget(this, selected, zItem);
- }
- cs.unlock();
- }
- }
- }
- void Entity::onTargetChange() {}
- void Entity::interact(Item* zItem, Entity* zActor) {}
- void Entity::addMovementFrame(MovementFrame& frame)
- {
- cs.lock();
- movements.add(frame);
- cs.unlock();
- NetworkMessage* message = new NetworkMessage();
- message->addressEntity(this);
- char* msg = new char[37];
- msg[0] = 0;
- *(float*)(msg + 1) = frame.direction.x;
- *(float*)(msg + 5) = frame.direction.y;
- *(float*)(msg + 9) = frame.direction.z;
- *(float*)(msg + 13) = frame.targetPosition.x;
- *(float*)(msg + 17) = frame.targetPosition.y;
- *(float*)(msg + 21) = frame.targetPosition.z;
- *(int*)(msg + 25) = frame.movementFlags;
- *(double*)(msg + 29) = frame.duration;
- message->setMessage(msg, 37);
- Game::INSTANCE->broadcastMessage(message);
- faceDir = frame.direction;
- // TODO implement subscription system to notify only interested clients
- }
- void Entity::calculateTarget(Framework::Vec3<float> basePos,
- Framework::Vec3<float> direction,
- const Item* zItem)
- {
- Vec3<float> headPosition = basePos + faceOffset;
- int px = (int)floor(headPosition.x);
- int py = (int)floor(headPosition.y);
- int pz = (int)floor(headPosition.z);
- direction.normalize();
- Direction dir = BOTTOM;
- while (true)
- {
- if (getDefaultBlock(Game::INSTANCE->zBlockAt(Vec3<int>{px, py, pz}, dimensionId))
- ->isInteractable(zItem))
- {
- if (!target || !target->isBlock({px, py, pz}, dir))
- {
- cs.lock();
- delete target;
- target = new ActionTarget({px, py, pz}, dir);
- cs.unlock();
- onTargetChange();
- }
- break;
- }
- // collision to neighbor of current block
- if (direction.x > 0)
- {
- float xt = ((float)px + 1.f - headPosition.x) / direction.x;
- Vec3<float> tmp = headPosition + direction * xt;
- if (xt <= targetDistanceLimit && tmp.y >= (float)py
- && tmp.y < (float)py + 1.f && tmp.z >= (float)pz
- && tmp.z < (float)pz + 1.f)
- {
- dir = WEST;
- px++;
- continue;
- }
- }
- if (direction.x < 0)
- {
- float xt = ((float)px - headPosition.x) / direction.x;
- Vec3<float> tmp = headPosition + direction * xt;
- if (xt <= targetDistanceLimit && tmp.y >= (float)py
- && tmp.y < (float)py + 1.f && tmp.z >= (float)pz
- && tmp.z < (float)pz + 1.f)
- {
- dir = EAST;
- px--;
- continue;
- }
- }
- if (direction.y > 0)
- {
- float yt = ((float)py + 1.f - headPosition.y) / direction.y;
- Vec3<float> tmp = headPosition + direction * yt;
- if (yt <= targetDistanceLimit && tmp.x >= (float)px
- && tmp.x < (float)px + 1.f && tmp.z >= (float)pz
- && tmp.z < (float)pz + 1.f)
- {
- dir = NORTH;
- py++;
- continue;
- }
- }
- if (direction.y < 0)
- {
- float yt = ((float)py - headPosition.y) / direction.y;
- Vec3<float> tmp = headPosition + direction * yt;
- if (yt <= targetDistanceLimit && tmp.x >= (float)px
- && tmp.x < (float)px + 1.f && tmp.z >= (float)pz
- && tmp.z < (float)pz + 1.f)
- {
- dir = SOUTH;
- py--;
- continue;
- }
- }
- if (direction.z > 0)
- {
- float zt = ((float)pz + 1.f - headPosition.z) / direction.z;
- Vec3<float> tmp = headPosition + direction * zt;
- if (zt <= targetDistanceLimit && tmp.x >= (float)px
- && tmp.x < (float)px + 1.f && tmp.y >= (float)py
- && tmp.y < (float)py + 1.f)
- {
- dir = BOTTOM;
- pz++;
- continue;
- }
- }
- if (direction.z < 0)
- {
- float zt = ((float)pz - headPosition.z) / direction.z;
- Vec3<float> tmp = headPosition + direction * zt;
- if (zt <= targetDistanceLimit && tmp.x >= (float)px
- && tmp.x < (float)px + 1.f && tmp.y >= (float)py
- && tmp.y < (float)py + 1)
- {
- dir = TOP;
- pz--;
- continue;
- }
- }
- if (target)
- {
- cs.lock();
- delete target;
- target = 0;
- cs.unlock();
- onTargetChange();
- }
- break;
- }
- }
- void Entity::removeStatusBarObserver(Entity* zSource, Framework::Text id)
- {
- cs.lock();
- int index = 0;
- for (auto observer : statusBarObservers)
- {
- if (observer.getFirst() == zSource->getId()
- && observer.getSecond().istGleich(id))
- {
- statusBarObservers.remove(index);
- break;
- }
- index++;
- }
- cs.unlock();
- }
- void Entity::addStatusBarObserver(Entity* zSource, Framework::Text id)
- {
- cs.lock();
- for (auto observer : statusBarObservers)
- {
- if (observer.getFirst() == zSource->getId()
- && observer.getSecond().istGleich(id))
- {
- cs.unlock();
- return;
- }
- }
- statusBarObservers.add(ImmutablePair<int, Text>(zSource->getId(), id));
- cs.unlock();
- }
- void Entity::notifyStatusBarObservers(NetworkMessage* msg)
- {
- cs.lock();
- int index = 0;
- Array<int> toDelete;
- for (auto observer : statusBarObservers)
- {
- Entity* e = Game::INSTANCE->zEntity(observer.getFirst());
- if (e)
- {
- msg->addressUIElement(observer.getSecond());
- Game::INSTANCE->sendMessage(msg->clone(), e);
- }
- else
- toDelete.add(index, 0);
- index++;
- }
- for (int i : toDelete)
- statusBarObservers.remove(i);
- cs.unlock();
- msg->release();
- }
- ItemSkill* Entity::zSkill(int itemType)
- {
- for (ItemSkill* skill : skills)
- {
- if (skill->getTypeId() == typeId)
- {
- return skill;
- }
- }
- return 0;
- }
- void Entity::prepareTick(const Dimension* zDimension) {}
- void Entity::tick(const Dimension* zDimension)
- {
- if (placeBlockCooldown > 0)
- {
- placeBlockCooldown--;
- }
- placeBlockCooldown--;
- if (time.isMeasuring())
- {
- time.messungEnde();
- if (movements.getEintragAnzahl() > 0)
- {
- MovementFrame currentFrame = movements.get(0);
- double seconds = time.getSekunden();
- while (seconds > 0)
- {
- if (currentFrame.duration <= 0)
- {
- cs.lock();
- movements.remove(0);
- cs.unlock();
- if (movements.getEintragAnzahl() > 0)
- currentFrame = movements.get(0);
- else
- break;
- }
- double t = MIN(currentFrame.duration, seconds);
- // TODO: add collision detection to reduce cheating capability
- location += (currentFrame.targetPosition - location)
- * (float)(t / currentFrame.duration);
- currentFrame.duration -= t;
- seconds -= t;
- if (currentFrame.duration <= 0)
- {
- location = currentFrame.targetPosition;
- }
- }
- if (currentFrame.duration > 0) movements.set(currentFrame, 0);
- if (getStamina() <= getMaxStamina() - 0.0025f)
- {
- if (getThirst() > 0 && getHunger() > 0)
- {
- setStamina(getStamina() + 0.0025f);
- setHunger(getHunger() - 0.0005f);
- setThirst(getThirst() - 0.0015f);
- }
- }
- }
- else
- {
- if (getStamina() <= getMaxStamina() - 0.005f)
- {
- if (getThirst() > 0 && getHunger() > 0)
- {
- setStamina(getStamina() + 0.005f);
- setHunger(getHunger() - 0.001f);
- setThirst(getThirst() - 0.003f);
- }
- }
- }
- }
- time.messungStart();
- }
- void Entity::api(Framework::StreamReader* zRequest,
- NetworkMessage* zResponse,
- Entity* zSource)
- {
- char type;
- zRequest->lese(&type, 1);
- switch (type)
- {
- case 0: // request status bar state
- {
- char len;
- zRequest->lese(&len, 1);
- char* guiId = new char[(int)len + 1];
- zRequest->lese(guiId, len);
- guiId[(int)len] = 0;
- zResponse->addressUIElement(guiId);
- addStatusBarObserver(zSource, guiId);
- char* msg = new char[33];
- msg[0] = 0;
- *(float*)(msg + 1) = getMaxHP();
- *(float*)(msg + 5) = getCurrentHP();
- *(float*)(msg + 9) = getMaxStamina();
- *(float*)(msg + 13) = getStamina();
- *(float*)(msg + 17) = getMaxHunger();
- *(float*)(msg + 21) = getHunger();
- *(float*)(msg + 25) = getMaxThirst();
- *(float*)(msg + 29) = getThirst();
- zResponse->setMessage(msg, 33);
- delete[] guiId;
- break;
- }
- case 1: // remove status bar observer
- {
- char len;
- zRequest->lese(&len, 1);
- char* guiId = new char[(int)len + 1];
- zRequest->lese(guiId, len);
- guiId[(int)len] = 0;
- removeStatusBarObserver(zSource, guiId);
- delete[] guiId;
- break;
- }
- }
- }
- void Entity::onFall(float collisionSpeed)
- {
- if (collisionSpeed > 5)
- {
- // TODO: take damage
- }
- }
- void Entity::setChatSecurityLevel(int level)
- {
- chatSecurityLevel = level;
- }
- void Entity::setPosition(Framework::Vec3<float> pos)
- {
- location = pos;
- }
- void Entity::setHP(float hp)
- {
- currentHP = MIN(MAX(hp, 0), maxHP);
- NetworkMessage* msg = new NetworkMessage();
- char* message = new char[9];
- message[0] = 1;
- *(float*)(message + 1) = getMaxHP();
- *(float*)(message + 5) = getCurrentHP();
- msg->setMessage(message, 9);
- notifyStatusBarObservers(msg);
- }
- void Entity::setStamina(float stamina)
- {
- this->stamina = MIN(MAX(stamina, 0), maxStamina);
- NetworkMessage* msg = new NetworkMessage();
- char* message = new char[9];
- message[0] = 2;
- *(float*)(message + 1) = getMaxStamina();
- *(float*)(message + 5) = getStamina();
- msg->setMessage(message, 9);
- notifyStatusBarObservers(msg);
- }
- void Entity::setHunger(float hunger)
- {
- this->hunger = MIN(MAX(hunger, 0), maxHunger);
- NetworkMessage* msg = new NetworkMessage();
- char* message = new char[9];
- message[0] = 3;
- *(float*)(message + 1) = getMaxHunger();
- *(float*)(message + 5) = getHunger();
- msg->setMessage(message, 9);
- notifyStatusBarObservers(msg);
- }
- void Entity::setThirst(float thirst)
- {
- this->thirst = MIN(MAX(thirst, 0), maxThirst);
- NetworkMessage* msg = new NetworkMessage();
- char* message = new char[9];
- message[0] = 4;
- *(float*)(message + 1) = getMaxThirst();
- *(float*)(message + 5) = getThirst();
- msg->setMessage(message, 9);
- notifyStatusBarObservers(msg);
- }
- float Entity::getMaxHP() const
- {
- return maxHP;
- }
- float Entity::getCurrentHP() const
- {
- return currentHP;
- }
- float Entity::getStamina() const
- {
- return stamina;
- }
- float Entity::getMaxStamina() const
- {
- return maxStamina;
- }
- float Entity::getHunger() const
- {
- return hunger;
- }
- float Entity::getMaxHunger() const
- {
- return maxHunger;
- }
- float Entity::getThirst() const
- {
- return thirst;
- }
- float Entity::getMaxThirst() const
- {
- return maxThirst;
- }
- Framework::Vec3<float> Entity::getSpeed() const
- {
- return speed;
- }
- Framework::Vec3<float> Entity::getFaceDir() const
- {
- return faceDir;
- }
- Framework::Vec3<float> Entity::getPosition() const
- {
- return location;
- }
- float Entity::getGravityMultiplier() const
- {
- return gravityMultiplier;
- }
- bool Entity::isRemoved() const
- {
- return removed;
- }
- const EntityType* Entity::zType() const
- {
- return StaticRegistry<EntityType>::INSTANCE.zElement(typeId);
- }
- const ActionTarget* Entity::zTarget() const
- {
- return target;
- }
- int Entity::getId() const
- {
- return id;
- }
- bool Entity::hasDefaultModel() const
- {
- return 1;
- }
- ModelInfo Entity::getSpecialModel() const
- {
- return ModelInfo("", "", 0);
- }
- float Entity::getMaxSpeed() const
- {
- return maxMovementSpeed;
- }
- bool Entity::isMoving() const
- {
- return movements.getEintragAnzahl() > 0;
- }
- int Entity::getChatSecurityLevel() const
- {
- return chatSecurityLevel;
- }
|