Block.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. #include "Block.h"
  2. #include "Dimension.h"
  3. #include "Game.h"
  4. #include "InteractionConfig.h"
  5. #include "Inventory.h"
  6. #include "ItemType.h"
  7. #include "MultiblockStructure.h"
  8. #include "PlaceableProof.h"
  9. #include "TickQueue.h"
  10. #include "WorldGenerator.h"
  11. Block::Block(
  12. int typeId, Framework::Vec3<int> pos, int dimensionId, bool hasInventory)
  13. : Inventory(pos, dimensionId, hasInventory)
  14. {
  15. transparent = false;
  16. passable = false;
  17. hp = 1;
  18. maxHP = 1;
  19. hardness = 1;
  20. this->typeId = typeId;
  21. speedModifier = 1;
  22. ticksLeftCounter = 0;
  23. wasTicked = 0;
  24. onTickCalled = 0;
  25. minTickTimeout = -1;
  26. maxTickTimeout = -1;
  27. currentTickTimeout = 0;
  28. interactable = 0;
  29. deadAndRemoved = 0;
  30. memset(lightEmisionColor, 0, 3);
  31. mapColor = 0;
  32. }
  33. Block::~Block() {}
  34. void Block::onDestroy(Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill)
  35. {
  36. if (!deadAndRemoved)
  37. {
  38. for (int i = 0; i < 6; i++)
  39. {
  40. Framework::Vec3<int> pos
  41. = getPos() + getDirection(getDirectionFromIndex(i));
  42. int type = Game::INSTANCE->getBlockType(pos, getDimensionId());
  43. if (type == BlockTypeEnum::NO_BLOCK)
  44. {
  45. Game::INSTANCE->zDimension(dimensionId)
  46. ->placeBlock(pos,
  47. Game::INSTANCE->zGenerator()->generateSingleBlock(
  48. pos, dimensionId));
  49. }
  50. else
  51. {
  52. Game::INSTANCE->zDimension(dimensionId)->sendBlockInfo(pos);
  53. }
  54. }
  55. getThis();
  56. if (zActor)
  57. {
  58. for (const DropConfig* config : zBlockType()->getDropConfigs())
  59. {
  60. config->onObjectDestroyed(zActor,
  61. zUsedItem,
  62. zUsedSkill,
  63. this); // a nother block might replace this block during the
  64. // drops
  65. }
  66. }
  67. Framework::Either<Block*, int> block
  68. = Game::INSTANCE->zBlockAt(getPos(), dimensionId, 0);
  69. deadAndRemoved = 1;
  70. if (block.isA()
  71. && block.getA() == this) // no other block has replaced this block
  72. {
  73. for (MultiblockStructure* structure : structures)
  74. structure->onBlockRemoved(zActor, zUsedItem, zUsedSkill, this);
  75. Game::INSTANCE->zDimension(dimensionId)
  76. ->placeBlock(getPos(), BlockTypeEnum::AIR);
  77. }
  78. else
  79. {
  80. if (structures.getEintragAnzahl() > 0)
  81. { // replace this block in the structures
  82. Block* zReplacement = block.isA()
  83. ? block.getA()
  84. : Game::INSTANCE->zRealBlockInstance(
  85. getPos(), dimensionId);
  86. for (MultiblockStructure* structure : structures)
  87. structure->onBlockReplaced(
  88. zActor, zUsedItem, zUsedSkill, this, zReplacement);
  89. }
  90. }
  91. release();
  92. }
  93. }
  94. void Block::onDialogClosed(Framework::Text dialogId) {}
  95. void Block::broadcastModelInfoChange()
  96. {
  97. NetworkMessage* message = new NetworkMessage();
  98. sendModelInfo(message);
  99. broadcastMessage(message);
  100. }
  101. void Block::broadcastMessage(NetworkMessage* message)
  102. {
  103. if (message->isEmpty())
  104. {
  105. message->release();
  106. }
  107. else
  108. {
  109. Dimension* dim = Game::INSTANCE->zDimension(getDimensionId());
  110. if (dim)
  111. {
  112. Chunk* zChunk
  113. = dim->zChunk(Game::getChunkCenter(getPos().x, getPos().y));
  114. if (zChunk)
  115. {
  116. zChunk->notifyObservers(message);
  117. }
  118. else
  119. {
  120. message->release();
  121. }
  122. }
  123. else
  124. {
  125. message->release();
  126. }
  127. }
  128. }
  129. void Block::broadcastPassableSpeedModifierChange()
  130. {
  131. NetworkMessage* message = new NetworkMessage();
  132. message->addressBlock(this);
  133. char* msg = new char[6];
  134. msg[0] = 3;
  135. msg[1] = passable;
  136. *(float*)(msg + 2) = speedModifier;
  137. message->setMessage(msg, 6);
  138. broadcastMessage(message);
  139. }
  140. void Block::onApiCall(char messageType,
  141. Framework::StreamReader* zRequest,
  142. NetworkMessage* zResponse,
  143. Entity* zSource)
  144. {}
  145. void Block::tick(TickQueue* zQueue)
  146. {
  147. if (wasTicked) return;
  148. wasTicked = 1;
  149. ticksLeftCounter++;
  150. if (minTickTimeout >= 0)
  151. {
  152. if (currentTickTimeout < ticksLeftCounter)
  153. {
  154. onTickCalled = 1;
  155. bool blocked = 0;
  156. bool result = onTick(zQueue, ticksLeftCounter, blocked);
  157. if (blocked)
  158. {
  159. wasTicked = 0;
  160. ticksLeftCounter--;
  161. onTickCalled = 0;
  162. zQueue->addToQueue(this);
  163. return;
  164. }
  165. if (result)
  166. currentTickTimeout
  167. = MAX(MIN(currentTickTimeout - 1, maxTickTimeout),
  168. MAX(minTickTimeout, 0));
  169. else
  170. currentTickTimeout
  171. = MAX(MIN(currentTickTimeout + 1, maxTickTimeout),
  172. MAX(minTickTimeout, 0));
  173. ticksLeftCounter = 0;
  174. }
  175. }
  176. else
  177. {
  178. onTickCalled = 1;
  179. bool blocked = 0;
  180. onTick(zQueue, 1, blocked);
  181. if (blocked)
  182. {
  183. wasTicked = 0;
  184. onTickCalled = 0;
  185. zQueue->addToQueue(this);
  186. return;
  187. }
  188. }
  189. }
  190. void Block::postTick()
  191. {
  192. wasTicked = 0;
  193. if (onTickCalled)
  194. {
  195. onPostTick();
  196. onTickCalled = 0;
  197. }
  198. }
  199. void Block::addToStructure(MultiblockStructure* structure)
  200. {
  201. if (structure->isBlockMember(this))
  202. structures.add(structure);
  203. else
  204. structure->release();
  205. }
  206. void Block::onLoaded()
  207. {
  208. for (MultiblockStructure* structure : structures)
  209. structure->onBlockLoaded(dynamic_cast<Block*>(getThis()));
  210. }
  211. void Block::onUnloaded()
  212. {
  213. for (MultiblockStructure* structure : structures)
  214. structure->onBlockUnloaded(this);
  215. }
  216. Framework::XML::Element* Block::getTargetUIML() const
  217. {
  218. return Game::INSTANCE->zBlockType(typeId)->getTargetUIML();
  219. }
  220. void Block::sendModelInfo(NetworkMessage* zMessage)
  221. {
  222. // overwritten by some blocks
  223. }
  224. bool Block::interact(Item* zItem, Entity* zActor, bool& itemChanged)
  225. {
  226. bool result = 0;
  227. for (InteractionConfig* config : zBlockType()->getInteractionConfigs())
  228. {
  229. result |= config->doInteraction(this, zItem, zActor, itemChanged);
  230. }
  231. return false;
  232. }
  233. void Block::api(Framework::StreamReader* zRequest,
  234. NetworkMessage* zResponse,
  235. Entity* zSource)
  236. {
  237. char id = 0;
  238. zRequest->lese(&id, 1);
  239. switch (id)
  240. {
  241. case 0:
  242. // request model state
  243. sendModelInfo(zResponse);
  244. break;
  245. case 1: // dialog closed
  246. {
  247. short nameLen;
  248. zRequest->lese((char*)&nameLen, 2);
  249. char* name = new char[nameLen + 1];
  250. zRequest->lese(name, nameLen);
  251. name[nameLen] = 0;
  252. onDialogClosed(name);
  253. delete[] name;
  254. break;
  255. }
  256. // 2 is handled in BasicBlock
  257. default: // component request handled in BasicBlock
  258. onApiCall(id, zRequest, zResponse, zSource);
  259. }
  260. }
  261. TickSourceType Block::isTickSource() const
  262. {
  263. return NONE;
  264. }
  265. bool Block::needsTick() const
  266. {
  267. return 1;
  268. }
  269. const BlockType* Block::zBlockType() const
  270. {
  271. return Game::INSTANCE->zBlockType(typeId);
  272. }
  273. bool Block::isTransparent() const
  274. {
  275. return transparent;
  276. }
  277. bool Block::isPassable() const
  278. {
  279. return passable;
  280. }
  281. bool Block::isInteractable(const Item* zItem) const
  282. {
  283. return interactable;
  284. }
  285. float Block::getHP() const
  286. {
  287. return hp;
  288. }
  289. float Block::getMaxHP() const
  290. {
  291. return maxHP;
  292. }
  293. float Block::getHardness() const
  294. {
  295. return hardness;
  296. }
  297. float Block::getSpeedModifier() const
  298. {
  299. return speedModifier;
  300. }
  301. const Framework::Vec3<int> Block::getPos() const
  302. {
  303. return (Framework::Vec3<int>)location;
  304. }
  305. void Block::setHP(
  306. Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, float hp)
  307. {
  308. bool isDead = this->hp == 0.f;
  309. this->hp = MAX(0.f, hp);
  310. if (!isDead && this->hp == 0.f)
  311. {
  312. onDestroy(zActor, zUsedItem, zUsedSkill); // this will be deleted
  313. }
  314. else
  315. {
  316. NetworkMessage* changeMsg = new NetworkMessage();
  317. changeMsg->addressBlock(this);
  318. char* msg = new char[5];
  319. msg[0] = 0; // hp changed
  320. *(float*)(msg + 1) = this->hp;
  321. changeMsg->setMessage(msg, 5);
  322. Game::INSTANCE->broadcastMessage(changeMsg);
  323. }
  324. }
  325. bool Block::isDeadAndRemoved() const
  326. {
  327. return deadAndRemoved;
  328. }
  329. void Block::getLightEmisionColor(unsigned char* result) const
  330. {
  331. result[0] = lightEmisionColor[0];
  332. result[1] = lightEmisionColor[0];
  333. result[2] = lightEmisionColor[0];
  334. }
  335. void Block::filterPassingLight(unsigned char rgb[3]) const
  336. {
  337. if (!transparent) // let no light pass intransparent blocks
  338. memset(rgb, 0, 3);
  339. }
  340. void Block::updateModel(ModelInfo* zInfo) const
  341. {
  342. Dimension* dim = Game::INSTANCE->zDimension(getDimensionId());
  343. if (dim)
  344. {
  345. Chunk* zChunk
  346. = dim->zChunk(Game::getChunkCenter(getPos().x, getPos().y));
  347. if (zChunk)
  348. {
  349. NetworkMessage* changeMsg = new NetworkMessage();
  350. changeMsg->addressBlock(this);
  351. Framework::InMemoryBuffer buffer;
  352. zInfo->writeTo(&buffer);
  353. char* msg = new char[(int)buffer.getSize() + 1];
  354. msg[0] = 1; // hmodel change
  355. buffer.lese(msg + 1, (int)buffer.getSize());
  356. changeMsg->setMessage(msg, (int)buffer.getSize() + 1);
  357. zChunk->notifyObservers(changeMsg);
  358. }
  359. }
  360. }
  361. int Block::getMapColor() const
  362. {
  363. return mapColor;
  364. }
  365. BasicBlockItem::BasicBlockItem(int itemTypeId,
  366. int blockTypeId,
  367. Framework::Text name,
  368. PlaceableProof* placeableProof)
  369. : Item(itemTypeId, name),
  370. transparent(0),
  371. passable(0),
  372. hardness(1.f),
  373. speedModifier(1.f),
  374. interactable(1),
  375. placeableProof(placeableProof)
  376. {
  377. this->blockTypeId = blockTypeId;
  378. placeable = 1;
  379. }
  380. BasicBlockItem::~BasicBlockItem()
  381. {
  382. if (placeableProof) placeableProof->release();
  383. }
  384. bool BasicBlockItem::canBeStackedWith(const Item* zItem) const
  385. {
  386. const BasicBlockItem* item = dynamic_cast<const BasicBlockItem*>(zItem);
  387. if (item)
  388. {
  389. return Item::canBeStackedWith(zItem) && transparent == item->transparent
  390. && passable == item->passable && hardness == item->hardness
  391. && speedModifier == item->speedModifier
  392. && interactable == item->interactable;
  393. }
  394. return 0;
  395. }
  396. bool BasicBlockItem::canBePlacedAt(
  397. int dimensionId, Framework::Vec3<int> worldPos) const
  398. {
  399. return Item::canBePlacedAt(dimensionId, worldPos)
  400. && (!placeableProof
  401. || placeableProof->isPlacable(this, worldPos, dimensionId));
  402. }
  403. BasicBlockItemType::BasicBlockItemType()
  404. : ItemType(),
  405. transparent(0),
  406. passable(0),
  407. hardness(1.f),
  408. speedModifier(1.f),
  409. blockTypeName(""),
  410. placeableProof(0)
  411. {}
  412. BasicBlockItemType::BasicBlockItemType(Framework::Text name,
  413. ModelInfo* model,
  414. bool transparent,
  415. bool passable,
  416. float hardness,
  417. float speedModifier,
  418. Framework::Text blockTypeName,
  419. PlaceableProof* placeableProof,
  420. int maxStackSize,
  421. Framework::RCArray<Framework::Text> groups)
  422. : ItemType(),
  423. transparent(transparent),
  424. passable(passable),
  425. hardness(hardness),
  426. speedModifier(speedModifier),
  427. blockTypeName(blockTypeName),
  428. placeableProof(placeableProof)
  429. {
  430. setName(name);
  431. setModel(model);
  432. setMaxStackSize(maxStackSize);
  433. for (Framework::Text* group : groups)
  434. addGroup(*group);
  435. }
  436. BasicBlockItemType::~BasicBlockItemType()
  437. {
  438. if (placeableProof) placeableProof->release();
  439. }
  440. bool BasicBlockItemType::initialize(Game* zGame)
  441. {
  442. blockTypeId = zGame->getBlockTypeId(blockTypeName);
  443. return blockTypeId >= 0 && ItemType::initialize(zGame);
  444. }
  445. int BasicBlockItemType::getBlockTypeId() const
  446. {
  447. return blockTypeId;
  448. }
  449. void BasicBlockItemType::setTransparent(bool transparent)
  450. {
  451. this->transparent = transparent;
  452. }
  453. bool BasicBlockItemType::isTransparent() const
  454. {
  455. return transparent;
  456. }
  457. void BasicBlockItemType::setPassable(bool passable)
  458. {
  459. this->passable = passable;
  460. }
  461. bool BasicBlockItemType::isPassable() const
  462. {
  463. return passable;
  464. }
  465. void BasicBlockItemType::setHardness(float hardness)
  466. {
  467. this->hardness = hardness;
  468. }
  469. float BasicBlockItemType::getHardness() const
  470. {
  471. return hardness;
  472. }
  473. void BasicBlockItemType::setSpeedModifier(float speedModifier)
  474. {
  475. this->speedModifier = speedModifier;
  476. }
  477. float BasicBlockItemType::getSpeedModifier() const
  478. {
  479. return speedModifier;
  480. }
  481. void BasicBlockItemType::setBlockTypeName(Framework::Text blockTypeName)
  482. {
  483. this->blockTypeName = blockTypeName;
  484. }
  485. Framework::Text BasicBlockItemType::getBlockTypeName() const
  486. {
  487. return blockTypeName;
  488. }
  489. void BasicBlockItemType::setPlaceableProof(PlaceableProof* placeableProof)
  490. {
  491. if (this->placeableProof) this->placeableProof->release();
  492. this->placeableProof = placeableProof;
  493. }
  494. PlaceableProof* BasicBlockItemType::zPlaceableProof() const
  495. {
  496. return placeableProof;
  497. }
  498. void BasicBlockItemType::loadSuperItem(
  499. Item* zItem, Framework::StreamReader* zReader) const
  500. {
  501. ItemType::loadSuperItem(zItem, zReader);
  502. BasicBlockItem* item = dynamic_cast<BasicBlockItem*>(zItem);
  503. if (!item)
  504. throw "BasicBlockItemType::loadSuperItem was called with an invalid "
  505. "item";
  506. zReader->lese((char*)&item->transparent, 1);
  507. zReader->lese((char*)&item->passable, 1);
  508. zReader->lese((char*)&item->hardness, 4);
  509. zReader->lese((char*)&item->speedModifier, 4);
  510. zReader->lese((char*)&item->interactable, 1);
  511. }
  512. void BasicBlockItemType::saveSuperItem(
  513. const Item* zItem, Framework::StreamWriter* zWriter) const
  514. {
  515. ItemType::saveSuperItem(zItem, zWriter);
  516. const BasicBlockItem* item = dynamic_cast<const BasicBlockItem*>(zItem);
  517. if (!item)
  518. throw "BasicBlockItemType::saveSuperItem was called with an invalid "
  519. "item";
  520. zWriter->schreibe((char*)&item->transparent, 1);
  521. zWriter->schreibe((char*)&item->passable, 1);
  522. zWriter->schreibe((char*)&item->hardness, 4);
  523. zWriter->schreibe((char*)&item->speedModifier, 4);
  524. zWriter->schreibe((char*)&item->interactable, 1);
  525. }
  526. Item* BasicBlockItemType::createItem() const
  527. {
  528. BasicBlockItem* item = new BasicBlockItem(id,
  529. blockTypeId,
  530. name,
  531. placeableProof
  532. ? dynamic_cast<PlaceableProof*>(placeableProof->getThis())
  533. : 0);
  534. item->transparent = transparent;
  535. item->passable = passable;
  536. item->hardness = hardness;
  537. item->speedModifier = speedModifier;
  538. item->interactable = 1;
  539. return item;
  540. }
  541. BasicBlockItemTypeFactory::BasicBlockItemTypeFactory()
  542. : ItemTypeFactoryBase()
  543. {}
  544. BasicBlockItemType* BasicBlockItemTypeFactory::createValue(
  545. Framework::JSON::JSONObject* zJson) const
  546. {
  547. return new BasicBlockItemType();
  548. }
  549. BasicBlockItemType* BasicBlockItemTypeFactory::fromJson(
  550. Framework::JSON::JSONObject* zJson) const
  551. {
  552. BasicBlockItemType* result = ItemTypeFactoryBase::fromJson(zJson);
  553. result->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
  554. result->setPassable(zJson->zValue("passable")->asBool()->getBool());
  555. result->setHardness(
  556. (float)zJson->zValue("hardness")->asNumber()->getNumber());
  557. result->setSpeedModifier(
  558. (float)zJson->zValue("speedModifier")->asNumber()->getNumber());
  559. result->setBlockTypeName(
  560. zJson->zValue("blockType")->asString()->getString());
  561. result->setPlaceableProof(
  562. zJson->zValue("placeableProof")->getType()
  563. == Framework::AbstractType::OBJECT
  564. ? Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(
  565. zJson->zValue("placeableProof"))
  566. : 0);
  567. return result;
  568. }
  569. Framework::JSON::JSONObject* BasicBlockItemTypeFactory::toJsonObject(
  570. BasicBlockItemType* zObject) const
  571. {
  572. Framework::JSON::JSONObject* result
  573. = ItemTypeFactoryBase::toJsonObject(zObject);
  574. result->addValue(
  575. "transparent", new Framework::JSON::JSONBool(zObject->isTransparent()));
  576. result->addValue(
  577. "passable", new Framework::JSON::JSONBool(zObject->isPassable()));
  578. result->addValue(
  579. "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
  580. result->addValue("speedModifier",
  581. new Framework::JSON::JSONNumber(zObject->getSpeedModifier()));
  582. result->addValue("blockType",
  583. new Framework::JSON::JSONString(zObject->getBlockTypeName()));
  584. result->addValue("placeableProof",
  585. zObject->zPlaceableProof() ? Game::INSTANCE->zTypeRegistry()->toJson(
  586. zObject->zPlaceableProof())
  587. : new Framework::JSON::JSONValue());
  588. return result;
  589. }
  590. JSONObjectValidationBuilder* BasicBlockItemTypeFactory::addToValidator(
  591. JSONObjectValidationBuilder* builder) const
  592. {
  593. return ItemTypeFactoryBase::addToValidator(
  594. builder->withRequiredBool("transparent")
  595. ->withDefault(false)
  596. ->finishBool()
  597. ->withRequiredBool("passable")
  598. ->withDefault(false)
  599. ->finishBool()
  600. ->withRequiredNumber("hardness")
  601. ->withDefault(1.f)
  602. ->finishNumber()
  603. ->withRequiredNumber("speedModifier")
  604. ->withDefault(1.f)
  605. ->finishNumber()
  606. ->withRequiredString("blockType")
  607. ->finishString()
  608. ->withRequiredAttribute("placeableProof",
  609. Game::INSTANCE->zTypeRegistry()->getValidator<PlaceableProof>())
  610. ->withRequiredObject("placeableProof")
  611. ->withDefaultNull()
  612. ->whichCanBeNull()
  613. ->finishObject());
  614. }
  615. const char* BasicBlockItemTypeFactory::getTypeToken() const
  616. {
  617. return "placeable";
  618. }