Block.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. #include "Block.h"
  2. #include "Dimension.h"
  3. #include "Game.h"
  4. #include "Inventory.h"
  5. #include "ItemEntity.h"
  6. #include "MultiblockStructure.h"
  7. #include "NoBlock.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(zNeighbours, 0, sizeof(Block*) * 6);
  31. memset(lightEmisionColor, 0, 3);
  32. mapColor = 0;
  33. }
  34. Block::~Block() {}
  35. void Block::onDestroy(Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill)
  36. {
  37. if (!deadAndRemoved)
  38. {
  39. for (int i = 0; i < 6; i++)
  40. {
  41. Framework::Vec3<int> pos
  42. = getPos() + getDirection(getDirectionFromIndex(i));
  43. if (neighbourTypes[i] == 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::tick(TickQueue* zQueue)
  141. {
  142. if (wasTicked) return;
  143. wasTicked = 1;
  144. ticksLeftCounter++;
  145. if (minTickTimeout >= 0)
  146. {
  147. if (currentTickTimeout < ticksLeftCounter)
  148. {
  149. onTickCalled = 1;
  150. bool blocked = 0;
  151. bool result = onTick(zQueue, ticksLeftCounter, blocked);
  152. if (blocked)
  153. {
  154. wasTicked = 0;
  155. ticksLeftCounter--;
  156. onTickCalled = 0;
  157. zQueue->addToQueue(this);
  158. return;
  159. }
  160. if (result)
  161. currentTickTimeout
  162. = MAX(MIN(currentTickTimeout - 1, maxTickTimeout),
  163. MAX(minTickTimeout, 0));
  164. else
  165. currentTickTimeout
  166. = MAX(MIN(currentTickTimeout + 1, maxTickTimeout),
  167. MAX(minTickTimeout, 0));
  168. ticksLeftCounter = 0;
  169. }
  170. }
  171. else
  172. {
  173. onTickCalled = 1;
  174. bool blocked = 0;
  175. onTick(zQueue, 1, blocked);
  176. if (blocked)
  177. {
  178. wasTicked = 0;
  179. onTickCalled = 0;
  180. zQueue->addToQueue(this);
  181. return;
  182. }
  183. }
  184. }
  185. void Block::postTick()
  186. {
  187. wasTicked = 0;
  188. if (onTickCalled)
  189. {
  190. onPostTick();
  191. onTickCalled = 0;
  192. }
  193. }
  194. void Block::setNeighbour(
  195. Direction dir, Framework::Either<Block*, int> neighbour)
  196. {
  197. if (neighbour.isA())
  198. setNeighbourBlock(dir, neighbour);
  199. else
  200. {
  201. setNeighbourBlock(dir, 0);
  202. setNeighbourType(dir, neighbour);
  203. }
  204. }
  205. void Block::setNeighbourBlock(Direction dir, Block* zN)
  206. {
  207. if (zN) setNeighbourType(dir, zN->zBlockType()->getId());
  208. zNeighbours[getDirectionIndex(dir)] = zN;
  209. }
  210. void Block::setNeighbourType(Direction dir, int type)
  211. {
  212. neighbourTypes[getDirectionIndex(dir)] = type;
  213. }
  214. void Block::addToStructure(MultiblockStructure* structure)
  215. {
  216. if (structure->isBlockMember(this))
  217. structures.add(structure);
  218. else
  219. structure->release();
  220. }
  221. void Block::onLoaded()
  222. {
  223. for (MultiblockStructure* structure : structures)
  224. structure->onBlockLoaded(dynamic_cast<Block*>(getThis()));
  225. }
  226. void Block::onUnloaded()
  227. {
  228. for (MultiblockStructure* structure : structures)
  229. structure->onBlockUnloaded(this);
  230. }
  231. Framework::Text Block::getTargetUIML()
  232. {
  233. return Game::INSTANCE->zBlockType(typeId)->getTargetUIML();
  234. }
  235. void Block::sendModelInfo(NetworkMessage* zMessage)
  236. {
  237. // overwritten by some blocks
  238. }
  239. bool Block::interact(Item* zItem, Entity* zActor)
  240. {
  241. return false;
  242. }
  243. void Block::api(Framework::StreamReader* zRequest, NetworkMessage* zResponse)
  244. {
  245. char id = 0;
  246. zRequest->lese(&id, 1);
  247. switch (id)
  248. {
  249. case 0:
  250. // request model state
  251. sendModelInfo(zResponse);
  252. break;
  253. case 1: // dialog closed
  254. short nameLen;
  255. zRequest->lese((char*)&nameLen, 2);
  256. char* name = new char[nameLen + 1];
  257. zRequest->lese(name, nameLen);
  258. name[nameLen] = 0;
  259. onDialogClosed(name);
  260. delete[] name;
  261. break;
  262. }
  263. }
  264. TickSourceType Block::isTickSource() const
  265. {
  266. return NONE;
  267. }
  268. bool Block::needsTick() const
  269. {
  270. return 1;
  271. }
  272. const BlockType* Block::zBlockType() const
  273. {
  274. return Game::INSTANCE->zBlockType(typeId);
  275. }
  276. bool Block::isTransparent() const
  277. {
  278. return transparent;
  279. }
  280. bool Block::isPassable() const
  281. {
  282. return passable;
  283. }
  284. bool Block::isInteractable(const Item* zItem) const
  285. {
  286. return interactable;
  287. }
  288. float Block::getHP() const
  289. {
  290. return hp;
  291. }
  292. float Block::getMaxHP() const
  293. {
  294. return maxHP;
  295. }
  296. float Block::getHardness() const
  297. {
  298. return hardness;
  299. }
  300. float Block::getSpeedModifier() const
  301. {
  302. return speedModifier;
  303. }
  304. const Framework::Vec3<int> Block::getPos() const
  305. {
  306. return (Framework::Vec3<int>)location;
  307. }
  308. bool Block::isVisible() const
  309. {
  310. if (passable || transparent) return 1;
  311. for (int i = 0; i < 6; i++)
  312. {
  313. const Block* neighbour = CONST_BLOCK(zNeighbours[i], neighbourTypes[i]);
  314. if (neighbour->isPassable() || neighbour->isTransparent()) return 1;
  315. }
  316. return 0;
  317. }
  318. void Block::setHP(
  319. Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, float hp)
  320. {
  321. bool isDead = this->hp == 0.f;
  322. this->hp = MAX(0.f, hp);
  323. if (!isDead && this->hp == 0.f)
  324. {
  325. onDestroy(zActor, zUsedItem, zUsedSkill); // this will be deleted
  326. }
  327. else
  328. {
  329. NetworkMessage* changeMsg = new NetworkMessage();
  330. changeMsg->addressBlock(this);
  331. char* msg = new char[5];
  332. msg[0] = 0; // hp changed
  333. *(float*)(msg + 1) = this->hp;
  334. changeMsg->setMessage(msg, 5);
  335. Game::INSTANCE->broadcastMessage(changeMsg);
  336. }
  337. }
  338. bool Block::isDeadAndRemoved() const
  339. {
  340. return deadAndRemoved;
  341. }
  342. const unsigned char* Block::getLightEmisionColor() const
  343. {
  344. return lightEmisionColor;
  345. }
  346. void Block::filterPassingLight(unsigned char rgb[3]) const
  347. {
  348. if (!transparent) // let no light pass intransparent blocks
  349. memset(rgb, 0, 3);
  350. }
  351. Block* Block::zNeighbor(Direction dir) const
  352. {
  353. return zNeighbours[getDirectionIndex(dir)];
  354. }
  355. void Block::updateModel(ModelInfo* zInfo) const
  356. {
  357. Dimension* dim = Game::INSTANCE->zDimension(getDimensionId());
  358. if (dim)
  359. {
  360. Chunk* zChunk
  361. = dim->zChunk(Game::getChunkCenter(getPos().x, getPos().y));
  362. if (zChunk)
  363. {
  364. NetworkMessage* changeMsg = new NetworkMessage();
  365. changeMsg->addressBlock(this);
  366. Framework::InMemoryBuffer buffer;
  367. zInfo->writeTo(&buffer);
  368. char* msg = new char[(int)buffer.getSize() + 1];
  369. msg[0] = 1; // hmodel change
  370. buffer.lese(msg + 1, (int)buffer.getSize());
  371. changeMsg->setMessage(msg, (int)buffer.getSize() + 1);
  372. zChunk->notifyObservers(changeMsg);
  373. }
  374. }
  375. }
  376. int Block::getMapColor() const
  377. {
  378. return mapColor;
  379. }
  380. BasicBlockItem::BasicBlockItem(int itemTypeId,
  381. int blockTypeId,
  382. Framework::Text name,
  383. PlaceableProof* placeableProof)
  384. : Item(itemTypeId, name),
  385. transparent(0),
  386. passable(0),
  387. hardness(1.f),
  388. speedModifier(1.f),
  389. interactable(1),
  390. placeableProof(placeableProof)
  391. {
  392. this->blockTypeId = blockTypeId;
  393. placeable = 1;
  394. }
  395. BasicBlockItem::~BasicBlockItem()
  396. {
  397. if (placeableProof) placeableProof->release();
  398. }
  399. bool BasicBlockItem::canBeStackedWith(const Item* zItem) const
  400. {
  401. const BasicBlockItem* item = dynamic_cast<const BasicBlockItem*>(zItem);
  402. if (item)
  403. {
  404. return Item::canBeStackedWith(zItem) && transparent == item->transparent
  405. && passable == item->passable && hardness == item->hardness
  406. && speedModifier == item->speedModifier
  407. && interactable == item->interactable;
  408. }
  409. return 0;
  410. }
  411. bool BasicBlockItem::canBePlacedAt(
  412. int dimensionId, Framework::Vec3<int> worldPos) const
  413. {
  414. return Item::canBePlacedAt(dimensionId, worldPos)
  415. && (!placeableProof
  416. || placeableProof->isPlacable(this, worldPos, dimensionId));
  417. }
  418. BasicBlockItemType::BasicBlockItemType()
  419. : ItemType(),
  420. transparent(0),
  421. passable(0),
  422. hardness(1.f),
  423. speedModifier(1.f),
  424. blockTypeName(""),
  425. placeableProof(0)
  426. {}
  427. BasicBlockItemType::BasicBlockItemType(Framework::Text name,
  428. ModelInfo* model,
  429. bool transparent,
  430. bool passable,
  431. float hardness,
  432. float speedModifier,
  433. Framework::Text blockTypeName,
  434. PlaceableProof* placeableProof,
  435. int maxStackSize,
  436. Framework::RCArray<Framework::Text> groups)
  437. : ItemType(),
  438. transparent(transparent),
  439. passable(passable),
  440. hardness(hardness),
  441. speedModifier(speedModifier),
  442. blockTypeName(blockTypeName),
  443. placeableProof(placeableProof)
  444. {
  445. setName(name);
  446. setModel(model);
  447. setMaxStackSize(maxStackSize);
  448. for (Framework::Text* group : groups)
  449. addGroup(*group);
  450. }
  451. BasicBlockItemType::~BasicBlockItemType()
  452. {
  453. if (placeableProof) placeableProof->release();
  454. }
  455. bool BasicBlockItemType::initialize(Game* zGame)
  456. {
  457. blockTypeId = zGame->getBlockTypeId(blockTypeName);
  458. return blockTypeId >= 0 && ItemType::initialize(zGame);
  459. }
  460. int BasicBlockItemType::getBlockTypeId() const
  461. {
  462. return blockTypeId;
  463. }
  464. void BasicBlockItemType::setTransparent(bool transparent)
  465. {
  466. this->transparent = transparent;
  467. }
  468. bool BasicBlockItemType::isTransparent() const
  469. {
  470. return transparent;
  471. }
  472. void BasicBlockItemType::setPassable(bool passable)
  473. {
  474. this->passable = passable;
  475. }
  476. bool BasicBlockItemType::isPassable() const
  477. {
  478. return passable;
  479. }
  480. void BasicBlockItemType::setHardness(float hardness)
  481. {
  482. this->hardness = hardness;
  483. }
  484. float BasicBlockItemType::getHardness() const
  485. {
  486. return hardness;
  487. }
  488. void BasicBlockItemType::setSpeedModifier(float speedModifier)
  489. {
  490. this->speedModifier = speedModifier;
  491. }
  492. float BasicBlockItemType::getSpeedModifier() const
  493. {
  494. return speedModifier;
  495. }
  496. void BasicBlockItemType::setBlockTypeName(Framework::Text blockTypeName)
  497. {
  498. this->blockTypeName = blockTypeName;
  499. }
  500. Framework::Text BasicBlockItemType::getBlockTypeName() const
  501. {
  502. return blockTypeName;
  503. }
  504. void BasicBlockItemType::setPlaceableProof(PlaceableProof* placeableProof)
  505. {
  506. if (this->placeableProof) this->placeableProof->release();
  507. this->placeableProof = placeableProof;
  508. }
  509. PlaceableProof* BasicBlockItemType::zPlaceableProof() const
  510. {
  511. return placeableProof;
  512. }
  513. void BasicBlockItemType::loadSuperItem(
  514. Item* zItem, Framework::StreamReader* zReader) const
  515. {
  516. ItemType::loadSuperItem(zItem, zReader);
  517. BasicBlockItem* item = dynamic_cast<BasicBlockItem*>(zItem);
  518. if (!item)
  519. throw "BasicBlockItemType::loadSuperItem was called with an invalid "
  520. "item";
  521. zReader->lese((char*)&item->transparent, 1);
  522. zReader->lese((char*)&item->passable, 1);
  523. zReader->lese((char*)&item->hardness, 4);
  524. zReader->lese((char*)&item->speedModifier, 4);
  525. zReader->lese((char*)&item->interactable, 1);
  526. }
  527. void BasicBlockItemType::saveSuperItem(
  528. const Item* zItem, Framework::StreamWriter* zWriter) const
  529. {
  530. ItemType::saveSuperItem(zItem, zWriter);
  531. const BasicBlockItem* item = dynamic_cast<const BasicBlockItem*>(zItem);
  532. if (!item)
  533. throw "BasicBlockItemType::saveSuperItem was called with an invalid "
  534. "item";
  535. zWriter->schreibe((char*)&item->transparent, 1);
  536. zWriter->schreibe((char*)&item->passable, 1);
  537. zWriter->schreibe((char*)&item->hardness, 4);
  538. zWriter->schreibe((char*)&item->speedModifier, 4);
  539. zWriter->schreibe((char*)&item->interactable, 1);
  540. }
  541. Item* BasicBlockItemType::createItem() const
  542. {
  543. BasicBlockItem* item = new BasicBlockItem(id,
  544. blockTypeId,
  545. name,
  546. placeableProof
  547. ? dynamic_cast<PlaceableProof*>(placeableProof->getThis())
  548. : 0);
  549. item->transparent = transparent;
  550. item->passable = passable;
  551. item->hardness = hardness;
  552. item->speedModifier = speedModifier;
  553. item->interactable = 1;
  554. return item;
  555. }
  556. BasicBlockItemTypeFactory::BasicBlockItemTypeFactory()
  557. : ItemTypeFactoryBase()
  558. {}
  559. BasicBlockItemType* BasicBlockItemTypeFactory::createValue(
  560. Framework::JSON::JSONObject* zJson) const
  561. {
  562. return new BasicBlockItemType();
  563. }
  564. BasicBlockItemType* BasicBlockItemTypeFactory::fromJson(
  565. Framework::JSON::JSONObject* zJson) const
  566. {
  567. BasicBlockItemType* result = ItemTypeFactoryBase::fromJson(zJson);
  568. result->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
  569. result->setPassable(zJson->zValue("passable")->asBool()->getBool());
  570. result->setHardness(
  571. (float)zJson->zValue("hardness")->asNumber()->getNumber());
  572. result->setSpeedModifier(
  573. (float)zJson->zValue("speedModifier")->asNumber()->getNumber());
  574. result->setBlockTypeName(
  575. zJson->zValue("blockType")->asString()->getString());
  576. result->setPlaceableProof(
  577. zJson->zValue("placeableProof")->getType()
  578. == Framework::AbstractType::OBJECT
  579. ? Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(
  580. zJson->zValue("placeableProof"))
  581. : 0);
  582. return result;
  583. }
  584. Framework::JSON::JSONObject* BasicBlockItemTypeFactory::toJsonObject(
  585. BasicBlockItemType* zObject) const
  586. {
  587. Framework::JSON::JSONObject* result
  588. = ItemTypeFactoryBase::toJsonObject(zObject);
  589. result->addValue(
  590. "transparent", new Framework::JSON::JSONBool(zObject->isTransparent()));
  591. result->addValue(
  592. "passable", new Framework::JSON::JSONBool(zObject->isPassable()));
  593. result->addValue(
  594. "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
  595. result->addValue("speedModifier",
  596. new Framework::JSON::JSONNumber(zObject->getSpeedModifier()));
  597. result->addValue("blockType",
  598. new Framework::JSON::JSONString(zObject->getBlockTypeName()));
  599. result->addValue("placeableProof",
  600. zObject->zPlaceableProof() ? Game::INSTANCE->zTypeRegistry()->toJson(
  601. zObject->zPlaceableProof())
  602. : new Framework::JSON::JSONValue());
  603. return result;
  604. }
  605. JSONObjectValidationBuilder* BasicBlockItemTypeFactory::addToValidator(
  606. JSONObjectValidationBuilder* builder) const
  607. {
  608. return ItemTypeFactoryBase::addToValidator(
  609. builder->withRequiredBool("transparent")
  610. ->withDefault(false)
  611. ->finishBool()
  612. ->withRequiredBool("passable")
  613. ->withDefault(false)
  614. ->finishBool()
  615. ->withRequiredNumber("hardness")
  616. ->withDefault(1.f)
  617. ->finishNumber()
  618. ->withRequiredNumber("speedModifier")
  619. ->withDefault(1.f)
  620. ->finishNumber()
  621. ->withRequiredString("blockType")
  622. ->finishString()
  623. ->withRequiredAttribute("placeableProof",
  624. Game::INSTANCE->zTypeRegistry()->getValidator<PlaceableProof>())
  625. ->withRequiredObject("placeableProof")
  626. ->withDefaultNull()
  627. ->whichCanBeNull()
  628. ->finishObject());
  629. }
  630. const char* BasicBlockItemTypeFactory::getTypeToken() const
  631. {
  632. return "placeable";
  633. }