FluidBlock.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #include "FluidBlock.h"
  2. #include "Game.h"
  3. FluidBlock::FluidBlock(int typeId, Framework::Vec3<int> pos)
  4. : Block(typeId, 0, pos, 0)
  5. {
  6. transparent = 1;
  7. passable = 1;
  8. hp = 1;
  9. maxHP = 1;
  10. hardness = -1.f;
  11. speedModifier = 0.5f;
  12. tickSource = 1;
  13. interactable = 0;
  14. fluidAmount = 0;
  15. }
  16. FluidBlock::~FluidBlock() {}
  17. bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
  18. {
  19. nextFlow = 0;
  20. int bottom = neighbourTypes[getDirectionIndex(Direction::BOTTOM)];
  21. if (bottom != zBlockType()->getId())
  22. {
  23. if (bottom == BlockTypeEnum::AIR)
  24. {
  25. nextFlow |= 1 << getDirectionIndex(Direction::BOTTOM);
  26. }
  27. else
  28. {
  29. if (zNeighbours[getDirectionIndex(Direction::BOTTOM)]
  30. && zNeighbours[getDirectionIndex(Direction::BOTTOM)]
  31. ->zBlockType()
  32. ->getId()
  33. == typeId)
  34. {
  35. Inventory* array[2]
  36. = {zNeighbours[getDirectionIndex(Direction::BOTTOM)], this};
  37. MultipleInventoryLock lock(array, 2);
  38. FluidBlock* below = dynamic_cast<FluidBlock*>(
  39. zNeighbours[getDirectionIndex(Direction::BOTTOM)]);
  40. if (below->fluidAmount < 1000)
  41. {
  42. int transferAmount
  43. = MIN(this->fluidAmount, 1000 - below->fluidAmount);
  44. below->fluidAmount += transferAmount;
  45. this->fluidAmount -= transferAmount;
  46. }
  47. }
  48. int neighborCount = 0;
  49. Inventory* others[4];
  50. for (int i = 1; i < 5; i++)
  51. {
  52. if (neighbourTypes[i] == BlockTypeEnum::FLUID && zNeighbours[i]
  53. && zNeighbours[i]->zBlockType()->getId() == typeId)
  54. {
  55. others[neighborCount] = zNeighbours[i];
  56. neighborCount++;
  57. }
  58. }
  59. if (neighborCount > 0)
  60. {
  61. Inventory* array[5]
  62. = {this, others[0], others[1], others[2], others[3]};
  63. MultipleInventoryLock lock(array, neighborCount + 1);
  64. // all neighbot fluid blocks are locked now
  65. FluidBlock* otherFluids[4];
  66. for (int i = 0; i < neighborCount; i++)
  67. {
  68. otherFluids[i] = dynamic_cast<FluidBlock*>(others[i]);
  69. }
  70. // order other fluids increasing by fluid amount
  71. sortByAmound(otherFluids, neighborCount);
  72. int distCount = 0;
  73. int targetAmount = 0;
  74. for (int i = 1; i <= neighborCount; i++)
  75. {
  76. int fluidAmount = this->fluidAmount;
  77. for (int j = 0; j < i; j++)
  78. {
  79. fluidAmount += otherFluids[j]->fluidAmount;
  80. }
  81. if (fluidAmount / (i + 1) > this->fluidAmount)
  82. {
  83. targetAmount = fluidAmount / (i + 1);
  84. distCount = i;
  85. }
  86. else
  87. {
  88. break;
  89. }
  90. }
  91. for (int i = 0; i < distCount; i++)
  92. {
  93. int transferAmount
  94. = targetAmount - otherFluids[i]->fluidAmount;
  95. otherFluids[i]->fluidAmount += transferAmount;
  96. this->fluidAmount -= transferAmount;
  97. }
  98. // TODO: distribute fluids
  99. } // unlock
  100. neighborCount = 0;
  101. for (int i = 1; i < 5; i++)
  102. {
  103. int neighbor = neighbourTypes[i];
  104. if (neighbor == BlockTypeEnum::AIR
  105. && fluidAmount > neighborCount + 1)
  106. {
  107. nextFlow |= 1 << i;
  108. neighborCount++;
  109. }
  110. }
  111. }
  112. }
  113. }
  114. void FluidBlock::onPostTick()
  115. {
  116. if (nextFlow != 0)
  117. {
  118. Game::INSTANCE->doLater([this]() {
  119. for (int i = 0; i < 6; i++)
  120. {
  121. if ((nextFlow | (1 << i)) == nextFlow)
  122. {
  123. Vec3<int> pos
  124. = getPos() + getDirection(getDirectionFromIndex(i));
  125. if (neighbourTypes[i] == BlockTypeEnum::AIR)
  126. {
  127. FluidBlock* spawn = new FluidBlock(typeId, pos);
  128. spawn->fluidAmount = 1;
  129. Game::INSTANCE->zDimension(getDimensionId())
  130. ->placeBlock(pos, spawn);
  131. fluidAmount--;
  132. }
  133. }
  134. }
  135. if (fluidAmount == 0)
  136. {
  137. Game::INSTANCE->zDimension(getDimensionId())
  138. ->placeBlock(getPos(),
  139. StaticRegistry<BlockType>::INSTANCE
  140. .zElement(BlockTypeEnum::AIR)
  141. ->createBlockAt(getPos(), 0));
  142. }
  143. });
  144. }
  145. }
  146. void FluidBlock::sortByAmound(FluidBlock** array, int count)
  147. {
  148. if (count == 2)
  149. {
  150. if (array[0]->fluidAmount > array[1]->fluidAmount)
  151. {
  152. FluidBlock* tmp = array[0];
  153. array[0] = array[1];
  154. array[1] = tmp;
  155. }
  156. }
  157. else if (count == 3)
  158. {
  159. if (array[0]->fluidAmount > array[1]->fluidAmount)
  160. {
  161. FluidBlock* tmp = array[0];
  162. array[0] = array[1];
  163. array[1] = tmp;
  164. }
  165. if (array[1]->fluidAmount > array[2]->fluidAmount)
  166. {
  167. FluidBlock* tmp = array[1];
  168. array[1] = array[2];
  169. array[2] = tmp;
  170. }
  171. if (array[0]->fluidAmount > array[1]->fluidAmount)
  172. {
  173. FluidBlock* tmp = array[0];
  174. array[0] = array[1];
  175. array[1] = tmp;
  176. }
  177. }
  178. else if (count == 4)
  179. {
  180. if (array[0]->fluidAmount > array[1]->fluidAmount)
  181. {
  182. FluidBlock* tmp = array[0];
  183. array[0] = array[1];
  184. array[1] = tmp;
  185. }
  186. if (array[2]->fluidAmount > array[3]->fluidAmount)
  187. {
  188. FluidBlock* tmp = array[2];
  189. array[2] = array[3];
  190. array[3] = tmp;
  191. }
  192. if (array[0]->fluidAmount > array[2]->fluidAmount)
  193. {
  194. FluidBlock* tmp = array[0];
  195. array[0] = array[2];
  196. array[2] = tmp;
  197. }
  198. if (array[1]->fluidAmount > array[3]->fluidAmount)
  199. {
  200. FluidBlock* tmp = array[1];
  201. array[1] = array[3];
  202. array[3] = tmp;
  203. }
  204. if (array[1]->fluidAmount > array[2]->fluidAmount)
  205. {
  206. FluidBlock* tmp = array[1];
  207. array[1] = array[2];
  208. array[2] = tmp;
  209. }
  210. }
  211. }
  212. FluidBlockType::FluidBlockType(int id, ModelInfo model, const char* name)
  213. : BlockType(id, 0, model, 1, 10, 0, name)
  214. {}
  215. void FluidBlockType::loadSuperBlock(
  216. Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
  217. {
  218. FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
  219. zReader->lese((char*)&block->fluidAmount, 2);
  220. BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
  221. }
  222. void FluidBlockType::saveSuperBlock(
  223. Block* zBlock, Framework::StreamWriter* zWriter) const
  224. {
  225. FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
  226. zWriter->schreibe((char*)&block->fluidAmount, 2);
  227. BlockType::saveSuperBlock(zBlock, zWriter);
  228. }
  229. Item* FluidBlockType::createItem() const
  230. {
  231. return 0;
  232. }
  233. Block* FluidBlockType::createBlock(Framework::Vec3<int> position) const
  234. {
  235. FluidBlock* result = new FluidBlock(getId(), position);
  236. result->fluidAmount = 1000;
  237. return result;
  238. }