Block.cpp 19 KB

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