Entity.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. #include "Entity.h"
  2. #include "Dimension.h"
  3. #include "Game.h"
  4. #include "BlockType.h"
  5. #include "ItemSkill.h"
  6. #include "EntityRemovedUpdate.h"
  7. #include "NoBlock.h"
  8. ActionTarget::ActionTarget(Vec3<int> blockPos, Direction blockSide)
  9. : blockPos(blockPos),
  10. targetBlockSide(blockSide),
  11. entityId(-1)
  12. {}
  13. ActionTarget::ActionTarget(int entityId)
  14. : entityId(entityId)
  15. {}
  16. bool ActionTarget::isBlock(Framework::Vec3<int> blockPos, Direction blockSide) const
  17. {
  18. return this->entityId == -1 && this->blockPos == blockPos && this->targetBlockSide == targetBlockSide;
  19. }
  20. bool ActionTarget::isEntity(int entityId) const
  21. {
  22. return this->entityId == entityId;
  23. }
  24. void ActionTarget::applyItemSkillOnTarget(Entity* zActor, ItemSkill* zItemSkill, Item* zUsedItem)
  25. {
  26. if (entityId >= 0)
  27. {
  28. // TODO: get entity from game and apply skill
  29. }
  30. else
  31. {
  32. Block* block = Game::INSTANCE->zRealBlockInstance(blockPos, zActor->getCurrentDimensionId());
  33. if (block)
  34. zItemSkill->use(zActor, zUsedItem, block);
  35. }
  36. }
  37. void ActionTarget::placeBlock(Entity* zActor, Item* zItem)
  38. {
  39. // TODO: check stamina of actor
  40. auto zB = Game::INSTANCE->zBlockAt(blockPos + getDirection(targetBlockSide), zActor->getCurrentDimensionId());
  41. if ((zB.isA() && zB.getA()->zBlockType()->getId() == AirBlockBlockType::ID) || (zB.isB() && zB.isB() == AirBlockBlockType::ID))
  42. {
  43. Block* block = zItem->zPlacedBlockType()->createBlockAt(blockPos + getDirection(targetBlockSide), zItem);
  44. if (block)
  45. {
  46. Game::INSTANCE->zDimension(zActor->getCurrentDimensionId())->placeBlock(block->getPos(), block);
  47. zItem->onPlaced();
  48. // TODO: decrese stamina of actor
  49. }
  50. }
  51. }
  52. void ActionTarget::toMessage(const ActionTarget* zTarget, NetworkMessage* zMsg)
  53. {
  54. if (zTarget)
  55. {
  56. if (zTarget->entityId >= 0)
  57. {
  58. char* message = new char[6];
  59. message[0] = 3;
  60. message[1] = 1;
  61. *(int*)(message + 2) = zTarget->entityId;
  62. zMsg->setMessage(message, 6);
  63. }
  64. else
  65. {
  66. char* message = new char[18];
  67. message[0] = 3;
  68. message[1] = 2;
  69. *(int*)(message + 2) = zTarget->blockPos.x;
  70. *(int*)(message + 6) = zTarget->blockPos.y;
  71. *(int*)(message + 10) = zTarget->blockPos.z;
  72. *(int*)(message + 14) = zTarget->targetBlockSide;
  73. zMsg->setMessage(message, 18);
  74. }
  75. }
  76. else
  77. {
  78. char* message = new char[2];
  79. message[0] = 3;
  80. message[1] = 0;
  81. zMsg->setMessage(message, 2);
  82. }
  83. }
  84. void ActionTarget::save(ActionTarget* zTarget, Framework::StreamWriter* zWriter)
  85. {
  86. if (zTarget)
  87. {
  88. if (zTarget->entityId >= 0)
  89. {
  90. char b = 1;
  91. zWriter->schreibe(&b, 1);
  92. zWriter->schreibe((char*)&zTarget->entityId, 4);
  93. }
  94. else
  95. {
  96. char b = 2;
  97. zWriter->schreibe(&b, 1);
  98. zWriter->schreibe((char*)&zTarget->blockPos.x, 4);
  99. zWriter->schreibe((char*)&zTarget->blockPos.y, 4);
  100. zWriter->schreibe((char*)&zTarget->blockPos.z, 4);
  101. zWriter->schreibe((char*)&zTarget->targetBlockSide, 4);
  102. }
  103. }
  104. else
  105. {
  106. char b = 0;
  107. zWriter->schreibe(&b, 1);
  108. }
  109. }
  110. ActionTarget* ActionTarget::load(Framework::StreamReader* zReader)
  111. {
  112. char b;
  113. zReader->lese(&b, 1);
  114. if (b == 1)
  115. {
  116. int id;
  117. zReader->lese((char*)&id, 4);
  118. return new ActionTarget(id);
  119. }
  120. else if (b == 2)
  121. {
  122. Framework::Vec3<int> pos;
  123. Direction side;
  124. zReader->lese((char*)&pos.x, 4);
  125. zReader->lese((char*)&pos.y, 4);
  126. zReader->lese((char*)&pos.z, 4);
  127. zReader->lese((char*)&side, 4);
  128. return new ActionTarget(pos, side);
  129. }
  130. return 0;
  131. }
  132. Entity::Entity(const EntityType* zType, Framework::Vec3<float> location, int dimensionId, int entityId)
  133. : Inventory(location, true),
  134. speed(0, 0, 0),
  135. faceDir(1, 0, 0),
  136. target(0),
  137. zEntityType(zType),
  138. currentDimensionId(dimensionId),
  139. removed(0),
  140. gravityMultiplier(1.f),
  141. id(entityId)
  142. {}
  143. void Entity::onDeath()
  144. {
  145. removed = 1;
  146. Game::INSTANCE->requestWorldUpdate(new EntityRemovedUpdate(id, currentDimensionId, location));
  147. }
  148. void Entity::useItem(const ItemType* zType, Item* zItem)
  149. {
  150. if (zItem && zItem->isEatable())
  151. { // TODO: eat item
  152. zItem->applyFoodEffects(this);
  153. }
  154. else if (zItem && zItem->isPlaceable())
  155. { // TODO: place item
  156. cs.lock();
  157. if (target)
  158. target->placeBlock(this, zItem);
  159. cs.unlock();
  160. }
  161. else if (!zItem || zItem->isUsable())
  162. { // use item skill
  163. cs.lock();
  164. if (target)
  165. {
  166. ItemSkill* selected = 0;
  167. for (ItemSkill* skill : skills)
  168. {
  169. if (skill->zSkillType() == zType)
  170. {
  171. selected = skill;
  172. break;
  173. }
  174. }
  175. if (!selected)
  176. {
  177. selected = zType->createDefaultItemSkill();
  178. skills.add(selected);
  179. }
  180. target->applyItemSkillOnTarget(this, selected, zItem);
  181. }
  182. cs.unlock();
  183. }
  184. }
  185. void Entity::onTargetChange()
  186. {}
  187. void Entity::addMovementFrame(MovementFrame& frame)
  188. {
  189. cs.lock();
  190. movements.add(frame);
  191. cs.unlock();
  192. NetworkMessage* message = new NetworkMessage();
  193. message->addressEntity(this);
  194. char* msg = new char[37];
  195. msg[0] = 0;
  196. *(float*)(msg + 1) = frame.direction.x;
  197. *(float*)(msg + 5) = frame.direction.y;
  198. *(float*)(msg + 9) = frame.direction.z;
  199. *(float*)(msg + 13) = frame.targetPosition.x;
  200. *(float*)(msg + 17) = frame.targetPosition.y;
  201. *(float*)(msg + 21) = frame.targetPosition.z;
  202. *(int*)(msg + 25) = frame.movementFlags;
  203. *(double*)(msg + 29) = frame.duration;
  204. message->setMessage(msg, 37);
  205. Game::INSTANCE->broadcastMessage(message);
  206. faceDir = frame.direction;
  207. // TODO implement subscription system to notify only interested clients
  208. }
  209. void Entity::calculateTarget(Framework::Vec3<float> basePos, Framework::Vec3<float> direction)
  210. {
  211. Vec3<float> headPosition = basePos + faceOffset;
  212. int px = (int)floor(headPosition.x);
  213. int py = (int)floor(headPosition.y);
  214. int pz = (int)floor(headPosition.z);
  215. direction.normalize();
  216. Direction dir = BOTTOM;
  217. while (true)
  218. {
  219. if (getDefaultBlock(Game::INSTANCE->zBlockAt(Vec3<int>{ px, py, pz }, currentDimensionId))->isInteractable())
  220. {
  221. if (!target || !target->isBlock({ px, py, pz }, dir))
  222. {
  223. cs.lock();
  224. delete target;
  225. target = new ActionTarget({ px, py, pz }, dir);
  226. cs.unlock();
  227. onTargetChange();
  228. }
  229. break;
  230. }
  231. // collision to neighbor of current block
  232. if (direction.x > 0)
  233. {
  234. float xt = ((float)px + 1.f - headPosition.x) / direction.x;
  235. Vec3<float> tmp = headPosition + direction * xt;
  236. if (xt <= targetDistanceLimit && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f)
  237. {
  238. dir = WEST;
  239. px++;
  240. continue;
  241. }
  242. }
  243. if (direction.x < 0)
  244. {
  245. float xt = ((float)px - headPosition.x) / direction.x;
  246. Vec3<float> tmp = headPosition + direction * xt;
  247. if (xt <= targetDistanceLimit && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f)
  248. {
  249. dir = EAST;
  250. px--;
  251. continue;
  252. }
  253. }
  254. if (direction.y > 0)
  255. {
  256. float yt = ((float)py + 1.f - headPosition.y) / direction.y;
  257. Vec3<float> tmp = headPosition + direction * yt;
  258. if (yt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f)
  259. {
  260. dir = NORTH;
  261. py++;
  262. continue;
  263. }
  264. }
  265. if (direction.y < 0)
  266. {
  267. float yt = ((float)py - headPosition.y) / direction.y;
  268. Vec3<float> tmp = headPosition + direction * yt;
  269. if (yt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f)
  270. {
  271. dir = SOUTH;
  272. py--;
  273. continue;
  274. }
  275. }
  276. if (direction.z > 0)
  277. {
  278. float zt = ((float)pz + 1.f - headPosition.z) / direction.z;
  279. Vec3<float> tmp = headPosition + direction * zt;
  280. if (zt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f)
  281. {
  282. dir = BOTTOM;
  283. pz++;
  284. continue;
  285. }
  286. }
  287. if (direction.z < 0)
  288. {
  289. float zt = ((float)pz - headPosition.z) / direction.z;
  290. Vec3<float> tmp = headPosition + direction * zt;
  291. if (zt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1)
  292. {
  293. dir = TOP;
  294. pz--;
  295. continue;
  296. }
  297. }
  298. if (target)
  299. {
  300. cs.lock();
  301. delete target;
  302. target = 0;
  303. cs.unlock();
  304. onTargetChange();
  305. }
  306. break;
  307. }
  308. }
  309. void Entity::prepareTick(const Dimension* zDimension)
  310. {}
  311. void Entity::tick(const Dimension* zDimension)
  312. {
  313. if (time.isMeasuring())
  314. {
  315. time.messungEnde();
  316. if (movements.getEintragAnzahl() > 0)
  317. {
  318. MovementFrame currentFrame = movements.get(0);
  319. double seconds = time.getSekunden();
  320. while (seconds > 0)
  321. {
  322. if (currentFrame.duration <= 0)
  323. {
  324. cs.lock();
  325. movements.remove(0);
  326. cs.unlock();
  327. if (movements.getEintragAnzahl() > 0)
  328. currentFrame = movements.get(0);
  329. else
  330. break;
  331. }
  332. double t = MIN(currentFrame.duration, seconds);
  333. // TODO: add collisin detection to reduce cheating capability
  334. location += (currentFrame.targetPosition - location) * (float)(t / currentFrame.duration);
  335. currentFrame.duration -= t;
  336. seconds -= t;
  337. if (currentFrame.duration <= 0)
  338. {
  339. location = currentFrame.targetPosition;
  340. }
  341. }
  342. if (currentFrame.duration > 0)
  343. movements.set(currentFrame, 0);
  344. }
  345. }
  346. time.messungStart();
  347. }
  348. void Entity::api(Framework::StreamReader* zRequest, NetworkMessage* zResponse)
  349. {}
  350. void Entity::onFall(float collisionSpeed)
  351. {
  352. if (collisionSpeed > 5)
  353. {
  354. // TODO: take damage
  355. }
  356. }
  357. void Entity::setPosition(Framework::Vec3<float> pos)
  358. {
  359. location = pos;
  360. }
  361. float Entity::getMaxHP() const
  362. {
  363. return maxHP;
  364. }
  365. float Entity::getCurrentHP() const
  366. {
  367. return currentHP;
  368. }
  369. float Entity::getStamina() const
  370. {
  371. return stamina;
  372. }
  373. float Entity::getMaxStamina() const
  374. {
  375. return maxStamina;
  376. }
  377. float Entity::getHunger() const
  378. {
  379. return hunger;
  380. }
  381. float Entity::getMaxHunger() const
  382. {
  383. return maxHunger;
  384. }
  385. float Entity::getThirst() const
  386. {
  387. return thirst;
  388. }
  389. float Entity::getMaxThirst() const
  390. {
  391. return maxThirst;
  392. }
  393. Framework::Vec3<float> Entity::getSpeed() const
  394. {
  395. return speed;
  396. }
  397. Framework::Vec3<float> Entity::getFaceDir() const
  398. {
  399. return faceDir;
  400. }
  401. Framework::Vec3<float> Entity::getPosition() const
  402. {
  403. return location;
  404. }
  405. float Entity::getGravityMultiplier() const
  406. {
  407. return gravityMultiplier;
  408. }
  409. int Entity::getCurrentDimensionId() const
  410. {
  411. return currentDimensionId;
  412. }
  413. bool Entity::isRemoved() const
  414. {
  415. return removed;
  416. }
  417. const EntityType* Entity::zType() const
  418. {
  419. return zEntityType;
  420. }
  421. const ActionTarget* Entity::zTarget() const
  422. {
  423. return target;
  424. }
  425. int Entity::getId() const
  426. {
  427. return id;
  428. }
  429. bool Entity::hasDefaultModel() const
  430. {
  431. return 1;
  432. }
  433. ModelInfo Entity::getSpecialModel() const
  434. {
  435. return ModelInfo("", "", 0);
  436. }
  437. float Entity::getMaxSpeed() const
  438. {
  439. return maxMovementSpeed;
  440. }
  441. bool Entity::isMoving() const
  442. {
  443. return movements.getEintragAnzahl() > 0;
  444. }