FluidBlock.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. #include "FluidBlock.h"
  2. #include <Logging.h>
  3. #include "BlockType.h"
  4. #include "Dimension.h"
  5. #include "FluidContainer.h"
  6. #include "Game.h"
  7. FluidBlock::FluidBlock(int typeId,
  8. Framework::Vec3<int> pos,
  9. int dimensionId,
  10. Framework::Vec3<float> lightWeights)
  11. : Block(typeId, pos, dimensionId, 0),
  12. lightWeights(lightWeights),
  13. nextFlow(0),
  14. maxFlowDistance(8)
  15. {
  16. transparent = 1;
  17. passable = 1;
  18. hp = 1;
  19. maxHP = 1;
  20. hardness = -1.f;
  21. speedModifier = 0.5f;
  22. interactable = 0;
  23. flowOptions = 0;
  24. distanceToSource = 0;
  25. }
  26. FluidBlock::~FluidBlock() {}
  27. bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
  28. {
  29. nextFlow -= numTicks;
  30. if (nextFlow <= 0)
  31. {
  32. const FluidBlockType* zType
  33. = dynamic_cast<const FluidBlockType*>(zBlockType());
  34. if (zType)
  35. {
  36. nextFlow = zType->getTicktsToFlow();
  37. }
  38. else
  39. {
  40. nextFlow = 0;
  41. }
  42. doFlow();
  43. }
  44. return true;
  45. }
  46. void FluidBlock::onPostTick() {}
  47. void FluidBlock::sendModelInfo(NetworkMessage* zMessage)
  48. {
  49. zMessage->addressBlock(this);
  50. char* msg = new char[3];
  51. msg[0] = 2; // fluid amount change
  52. *(msg + 1) = flowOptions;
  53. *(msg + 2) = distanceToSource;
  54. zMessage->setMessage(msg, 3);
  55. }
  56. void FluidBlock::doFlow()
  57. {
  58. bool doesFlowSidewards = 1;
  59. Framework::Either<Block*, int> below = Game::INSTANCE->zBlockAt(
  60. getPos() + getDirection(Direction::BOTTOM), getDimensionId(), 0);
  61. if (((below.isA() && below.getA()->zBlockType() == zBlockType()
  62. || below.getB() == BlockTypeEnum::AIR)
  63. && distanceToSource)
  64. || distanceToSource >= maxFlowDistance)
  65. {
  66. doesFlowSidewards = 0;
  67. }
  68. bool changed = false;
  69. int minNeighborDistance = maxFlowDistance;
  70. char nextFlowOptions = 0;
  71. for (int i = 0; i < 6; i++)
  72. {
  73. Direction dir = getDirectionFromIndex(i);
  74. Framework::Either<Block*, int> neighbor = Game::INSTANCE->zBlockAt(
  75. getPos() + getDirection(dir), getDimensionId(), 0);
  76. if (dir & Direction::TOP)
  77. {
  78. if (neighbor.isA() && neighbor.getA()->zBlockType() == zBlockType())
  79. {
  80. FluidBlock* neighbour
  81. = dynamic_cast<FluidBlock*>(neighbor.getA());
  82. minNeighborDistance = 0;
  83. nextFlowOptions = (char)getOppositeDirection(dir);
  84. }
  85. continue;
  86. }
  87. if (neighbor.isB() && neighbor.getB() == BlockTypeEnum::AIR)
  88. {
  89. if (dir & Direction::BOTTOM || doesFlowSidewards)
  90. {
  91. Game::INSTANCE->doLater([this, dir, i]() {
  92. Framework::Either<Block*, int> neighbor
  93. = Game::INSTANCE->zBlockAt(
  94. getPos() + getDirection(dir), getDimensionId(), 0);
  95. if (neighbor.isB() && neighbor.getB() == BlockTypeEnum::AIR)
  96. {
  97. Block* belowBlock = zBlockType()->createBlockAt(
  98. getPos() + getDirection(dir), getDimensionId(), 0);
  99. FluidBlock* fluidBlock
  100. = dynamic_cast<FluidBlock*>(belowBlock);
  101. if (fluidBlock)
  102. {
  103. fluidBlock->distanceToSource
  104. = dir & Direction::BOTTOM
  105. ? 1
  106. : distanceToSource + 1;
  107. fluidBlock->flowOptions = (char)dir;
  108. Game::INSTANCE->zDimension(getDimensionId())
  109. ->placeBlock(
  110. getPos() + getDirection(dir), belowBlock);
  111. }
  112. else
  113. {
  114. Framework::Logging::error()
  115. << "created flow fuild block is not an "
  116. "instance of FluidBlock";
  117. belowBlock->release();
  118. }
  119. }
  120. });
  121. }
  122. }
  123. else if (neighbor.isA()
  124. && neighbor.getA()->zBlockType() == zBlockType())
  125. {
  126. if (dir & Direction::BOTTOM) continue;
  127. FluidBlock* neighbour = dynamic_cast<FluidBlock*>(neighbor.getA());
  128. if (neighbour)
  129. {
  130. if (neighbour->distanceToSource < minNeighborDistance)
  131. {
  132. minNeighborDistance = neighbour->distanceToSource;
  133. nextFlowOptions = (char)getOppositeDirection(dir);
  134. }
  135. else if (neighbour->distanceToSource == minNeighborDistance)
  136. {
  137. nextFlowOptions = (char)getOppositeDirection(dir);
  138. }
  139. }
  140. }
  141. }
  142. if (distanceToSource)
  143. {
  144. if (minNeighborDistance + 1 > distanceToSource)
  145. {
  146. distanceToSource = minNeighborDistance + 1;
  147. flowOptions = 0; // reavaluated next tick
  148. changed = true;
  149. }
  150. }
  151. if (distanceToSource > maxFlowDistance)
  152. {
  153. distanceToSource = maxFlowDistance;
  154. Game::INSTANCE->doLater([this]() { setHP(0, 0, 0, 0.f); });
  155. }
  156. if (changed)
  157. {
  158. broadcastModelInfoChange();
  159. }
  160. }
  161. bool FluidBlock::isInteractable(const Item* zItem) const
  162. {
  163. return distanceToSource == 0
  164. && dynamic_cast<const FluidContainerItem*>(zItem);
  165. }
  166. void FluidBlock::filterPassingLight(unsigned char rgb[3]) const
  167. {
  168. rgb[0] = (unsigned char)(rgb[0] * lightWeights.x);
  169. rgb[1] = (unsigned char)(rgb[1] * lightWeights.y);
  170. rgb[2] = (unsigned char)(rgb[2] * lightWeights.z);
  171. }
  172. TickSourceType FluidBlock::isTickSource() const
  173. {
  174. return TickSourceType::AFTER_WORLD_UPDATE;
  175. }
  176. bool FluidBlock::needsTick() const
  177. {
  178. return true;
  179. }
  180. char FluidBlock::getDistanceToSource() const
  181. {
  182. return distanceToSource;
  183. }
  184. char FluidBlock::getFlowOptions() const
  185. {
  186. return flowOptions;
  187. }
  188. FluidBlockType::FluidBlockType()
  189. : BlockType(),
  190. lightWeights(1.f, 1.f, 1.f),
  191. ticktsToFlow(20),
  192. flowDistance(8),
  193. hungerRecoveryPerL(0.f),
  194. thirstRecoveryPerL(0.f),
  195. heat(10.f)
  196. {}
  197. void FluidBlockType::loadSuperBlock(
  198. Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
  199. {
  200. FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
  201. zReader->lese(&block->flowOptions, 1);
  202. zReader->lese(&block->distanceToSource, 1);
  203. block->nextFlow = ticktsToFlow;
  204. block->maxFlowDistance = flowDistance;
  205. BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
  206. }
  207. void FluidBlockType::saveSuperBlock(
  208. Block* zBlock, Framework::StreamWriter* zWriter) const
  209. {
  210. FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
  211. zWriter->schreibe(&block->flowOptions, 1);
  212. zWriter->schreibe(&block->distanceToSource, 1);
  213. BlockType::saveSuperBlock(zBlock, zWriter);
  214. }
  215. Item* FluidBlockType::createItem() const
  216. {
  217. return 0;
  218. }
  219. Block* FluidBlockType::createBlock(
  220. Framework::Vec3<int> position, int dimensionId) const
  221. {
  222. FluidBlock* result
  223. = new FluidBlock(getId(), position, dimensionId, lightWeights);
  224. result->nextFlow = ticktsToFlow;
  225. result->maxFlowDistance = flowDistance;
  226. return result;
  227. }
  228. bool FluidBlockType::isFluid() const
  229. {
  230. return true;
  231. }
  232. ItemType* FluidBlockType::createItemType() const
  233. {
  234. return 0;
  235. }
  236. void FluidBlockType::setTicktsToFlow(int ticksToFlow)
  237. {
  238. this->ticktsToFlow = ticksToFlow;
  239. }
  240. int FluidBlockType::getTicktsToFlow() const
  241. {
  242. return ticktsToFlow;
  243. }
  244. void FluidBlockType::setFlowDistance(unsigned char flowDistance)
  245. {
  246. this->flowDistance = flowDistance;
  247. }
  248. unsigned char FluidBlockType::getFlowDistance() const
  249. {
  250. return flowDistance;
  251. }
  252. void FluidBlockType::setLightWeights(Framework::Vec3<float> lightWeights)
  253. {
  254. this->lightWeights = lightWeights;
  255. }
  256. Framework::Vec3<float> FluidBlockType::getLightWeights() const
  257. {
  258. return lightWeights;
  259. }
  260. void FluidBlockType::setHungerRecoveryPerL(float hungerRecoveryPerL)
  261. {
  262. this->hungerRecoveryPerL = hungerRecoveryPerL;
  263. }
  264. float FluidBlockType::getHungerRecoveryPerL() const
  265. {
  266. return hungerRecoveryPerL;
  267. }
  268. void FluidBlockType::setThirstRecoveryPerL(float thirstRecoveryPerL)
  269. {
  270. this->thirstRecoveryPerL = thirstRecoveryPerL;
  271. }
  272. float FluidBlockType::getThirstRecoveryPerL() const
  273. {
  274. return thirstRecoveryPerL;
  275. }
  276. void FluidBlockType::setHeat(float heat)
  277. {
  278. this->heat = heat;
  279. }
  280. float FluidBlockType::getHeat() const
  281. {
  282. return heat;
  283. }
  284. FluidBlockTypeFactory::FluidBlockTypeFactory()
  285. : BlockTypeFactoryBase()
  286. {}
  287. FluidBlockType* FluidBlockTypeFactory::createValue(
  288. Framework::JSON::JSONObject* zJson) const
  289. {
  290. return new FluidBlockType();
  291. }
  292. FluidBlockType* FluidBlockTypeFactory::fromJson(
  293. Framework::JSON::JSONObject* zJson) const
  294. {
  295. FluidBlockType* result = BlockTypeFactoryBase::fromJson(zJson);
  296. result->setLightWeights(
  297. Framework::Vec3<float>((float)zJson->zValue("lightWeight")
  298. ->asObject()
  299. ->zValue("red")
  300. ->asNumber()
  301. ->getNumber(),
  302. (float)zJson->zValue("lightWeight")
  303. ->asObject()
  304. ->zValue("green")
  305. ->asNumber()
  306. ->getNumber(),
  307. (float)zJson->zValue("lightWeight")
  308. ->asObject()
  309. ->zValue("blue")
  310. ->asNumber()
  311. ->getNumber()));
  312. result->setTicktsToFlow(
  313. (int)zJson->zValue("ticksToFlow")->asNumber()->getNumber());
  314. result->setFlowDistance(
  315. (char)zJson->zValue("flowDistance")->asNumber()->getNumber());
  316. result->setHungerRecoveryPerL(
  317. (float)zJson->zValue("hungerRecoveryPerL")->asNumber()->getNumber());
  318. result->setThirstRecoveryPerL(
  319. (float)zJson->zValue("thirstRecoveryPerL")->asNumber()->getNumber());
  320. result->setHeat((float)zJson->zValue("heat")->asNumber()->getNumber());
  321. return result;
  322. }
  323. Framework::JSON::JSONObject* FluidBlockTypeFactory::toJsonObject(
  324. FluidBlockType* zObject) const
  325. {
  326. Framework::JSON::JSONObject* result
  327. = BlockTypeFactoryBase::toJsonObject(zObject);
  328. Framework::JSON::JSONObject* lightWeight
  329. = new Framework::JSON::JSONObject();
  330. lightWeight->addValue(
  331. "red", new Framework::JSON::JSONNumber(zObject->getLightWeights().x));
  332. lightWeight->addValue(
  333. "green", new Framework::JSON::JSONNumber(zObject->getLightWeights().y));
  334. lightWeight->addValue(
  335. "blue", new Framework::JSON::JSONNumber(zObject->getLightWeights().z));
  336. result->addValue("lightWeight", lightWeight);
  337. result->addValue("ticksToFlow",
  338. new Framework::JSON::JSONNumber((double)zObject->getTicktsToFlow()));
  339. result->addValue("flowDistance",
  340. new Framework::JSON::JSONNumber((double)zObject->getFlowDistance()));
  341. result->addValue("hungerRecoveryPerL",
  342. new Framework::JSON::JSONNumber(
  343. (double)zObject->getHungerRecoveryPerL()));
  344. result->addValue("thirstRecoveryPerL",
  345. new Framework::JSON::JSONNumber(
  346. (double)zObject->getThirstRecoveryPerL()));
  347. result->addValue(
  348. "heat", new Framework::JSON::JSONNumber((double)zObject->getHeat()));
  349. return result;
  350. }
  351. JSONObjectValidationBuilder* FluidBlockTypeFactory::addToValidator(
  352. JSONObjectValidationBuilder* builder) const
  353. {
  354. return BlockTypeFactoryBase::addToValidator(
  355. builder->withRequiredObject("lightWeight")
  356. ->withRequiredNumber("red")
  357. ->whichIsGreaterOrEqual(0.0)
  358. ->whichIsLessOrEqual(1.0)
  359. ->finishNumber()
  360. ->withRequiredNumber("green")
  361. ->whichIsGreaterOrEqual(0.0)
  362. ->whichIsLessOrEqual(1.0)
  363. ->finishNumber()
  364. ->withRequiredNumber("blue")
  365. ->whichIsGreaterOrEqual(0.0)
  366. ->whichIsLessOrEqual(1.0)
  367. ->finishNumber()
  368. ->finishObject()
  369. ->withRequiredNumber("ticksToFlow")
  370. ->whichIsGreaterOrEqual(1.0)
  371. ->finishNumber()
  372. ->withRequiredNumber("flowDistance")
  373. ->whichIsGreaterOrEqual(0.0)
  374. ->finishNumber()
  375. ->withRequiredNumber("hungerRecoveryPerL")
  376. ->whichIsGreaterOrEqual(0.0)
  377. ->withDefault(0.0)
  378. ->finishNumber()
  379. ->withRequiredNumber("thirstRecoveryPerL")
  380. ->whichIsGreaterOrEqual(0.0)
  381. ->withDefault(0.0)
  382. ->finishNumber()
  383. ->withRequiredNumber("heat")
  384. ->withDefault(10.0)
  385. ->finishNumber());
  386. }
  387. const char* FluidBlockTypeFactory::getTypeToken() const
  388. {
  389. return "fluid";
  390. }