Block.cpp 17 KB

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