FluidBlock.cpp 12 KB

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