FluidBlock.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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. lastBroadcastedAmount = fluidAmount;
  16. }
  17. FluidBlock::~FluidBlock() {}
  18. bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
  19. {
  20. nextFlow = 0;
  21. int bottom = neighbourTypes[getDirectionIndex(Direction::BOTTOM)];
  22. if (bottom != zBlockType()->getId())
  23. {
  24. if (bottom == BlockTypeEnum::AIR)
  25. {
  26. nextFlow |= 1 << getDirectionIndex(Direction::BOTTOM);
  27. }
  28. else
  29. {
  30. if (zNeighbours[getDirectionIndex(Direction::BOTTOM)]
  31. && zNeighbours[getDirectionIndex(Direction::BOTTOM)]
  32. ->zBlockType()
  33. ->getId()
  34. == typeId)
  35. {
  36. Inventory* array[2]
  37. = {zNeighbours[getDirectionIndex(Direction::BOTTOM)], this};
  38. MultipleInventoryLock lock(array, 2);
  39. FluidBlock* below = dynamic_cast<FluidBlock*>(
  40. zNeighbours[getDirectionIndex(Direction::BOTTOM)]);
  41. if (below->fluidAmount < 1000)
  42. {
  43. short transferAmount
  44. = (short)MIN(this->fluidAmount, (short)1000 - below->fluidAmount);
  45. below->fluidAmount = (short)(below->fluidAmount + transferAmount);
  46. this->fluidAmount = (short)(this->fluidAmount - transferAmount);
  47. }
  48. }
  49. short neighborCount = 0;
  50. Inventory* others[4];
  51. for (int i = 1; i < 5; i++)
  52. {
  53. if (neighbourTypes[i] == typeId && zNeighbours[i])
  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. short distCount = 0;
  73. short 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 = (short)(fluidAmount / (i + 1));
  84. distCount = (short)i;
  85. }
  86. else
  87. {
  88. break;
  89. }
  90. }
  91. for (int i = 0; i < distCount; i++)
  92. {
  93. short transferAmount
  94. = (short)(targetAmount - otherFluids[i]->fluidAmount);
  95. otherFluids[i]->fluidAmount
  96. = (short)(otherFluids[i]->fluidAmount + transferAmount);
  97. this->fluidAmount = (short)(this->fluidAmount - transferAmount);
  98. }
  99. } // unlock
  100. neighborCount = 0;
  101. for (int i = 0; i < 6; i++)
  102. {
  103. if (getDirectionFromIndex(i) != Direction::BOTTOM
  104. && getDirectionFromIndex(i) != Direction::TOP)
  105. {
  106. int neighbor = neighbourTypes[i];
  107. if (neighbor == BlockTypeEnum::AIR
  108. && fluidAmount > neighborCount + 1)
  109. {
  110. nextFlow |= 1 << i;
  111. neighborCount++;
  112. }
  113. }
  114. }
  115. }
  116. }
  117. return 1;
  118. }
  119. void FluidBlock::broadcastAmount()
  120. {
  121. if (lastBroadcastedAmount != fluidAmount)
  122. {
  123. lastBroadcastedAmount = fluidAmount;
  124. NetworkMessage* changeMsg = new NetworkMessage();
  125. changeMsg->addressBlock(this);
  126. char* msg = new char[3];
  127. msg[0] = 2; // fluid amount change
  128. *(short*)(msg + 1) = fluidAmount;
  129. changeMsg->setMessage(msg, 3);
  130. Game::INSTANCE->broadcastMessage(changeMsg);
  131. }
  132. }
  133. void FluidBlock::onPostTick()
  134. {
  135. if (nextFlow != 0)
  136. {
  137. Game::INSTANCE->doLater([this]() {
  138. for (int i = 0; i < 6; i++)
  139. {
  140. if ((nextFlow | (1 << i)) == nextFlow)
  141. {
  142. Vec3<int> pos
  143. = getPos() + getDirection(getDirectionFromIndex(i));
  144. if (neighbourTypes[i] == BlockTypeEnum::AIR)
  145. {
  146. FluidBlock* spawn = new FluidBlock(typeId, pos);
  147. spawn->fluidAmount = 1;
  148. Game::INSTANCE->zDimension(getDimensionId())
  149. ->placeBlock(pos, spawn);
  150. fluidAmount--;
  151. }
  152. }
  153. }
  154. if (fluidAmount == 0)
  155. {
  156. Game::INSTANCE->zDimension(getDimensionId())
  157. ->placeBlock(getPos(),
  158. StaticRegistry<BlockType>::INSTANCE
  159. .zElement(BlockTypeEnum::AIR)
  160. ->createBlockAt(getPos(), 0));
  161. }
  162. else
  163. {
  164. broadcastAmount();
  165. }
  166. });
  167. }
  168. }
  169. void FluidBlock::sortByAmound(FluidBlock** array, int count)
  170. {
  171. if (count == 2)
  172. {
  173. if (array[0]->fluidAmount > array[1]->fluidAmount)
  174. {
  175. FluidBlock* tmp = array[0];
  176. array[0] = array[1];
  177. array[1] = tmp;
  178. }
  179. }
  180. else if (count == 3)
  181. {
  182. if (array[0]->fluidAmount > array[1]->fluidAmount)
  183. {
  184. FluidBlock* tmp = array[0];
  185. array[0] = array[1];
  186. array[1] = tmp;
  187. }
  188. if (array[1]->fluidAmount > array[2]->fluidAmount)
  189. {
  190. FluidBlock* tmp = array[1];
  191. array[1] = array[2];
  192. array[2] = tmp;
  193. }
  194. if (array[0]->fluidAmount > array[1]->fluidAmount)
  195. {
  196. FluidBlock* tmp = array[0];
  197. array[0] = array[1];
  198. array[1] = tmp;
  199. }
  200. }
  201. else if (count == 4)
  202. {
  203. if (array[0]->fluidAmount > array[1]->fluidAmount)
  204. {
  205. FluidBlock* tmp = array[0];
  206. array[0] = array[1];
  207. array[1] = tmp;
  208. }
  209. if (array[2]->fluidAmount > array[3]->fluidAmount)
  210. {
  211. FluidBlock* tmp = array[2];
  212. array[2] = array[3];
  213. array[3] = tmp;
  214. }
  215. if (array[0]->fluidAmount > array[2]->fluidAmount)
  216. {
  217. FluidBlock* tmp = array[0];
  218. array[0] = array[2];
  219. array[2] = tmp;
  220. }
  221. if (array[1]->fluidAmount > array[3]->fluidAmount)
  222. {
  223. FluidBlock* tmp = array[1];
  224. array[1] = array[3];
  225. array[3] = tmp;
  226. }
  227. if (array[1]->fluidAmount > array[2]->fluidAmount)
  228. {
  229. FluidBlock* tmp = array[1];
  230. array[1] = array[2];
  231. array[2] = tmp;
  232. }
  233. }
  234. }
  235. FluidBlockType::FluidBlockType(int id, ModelInfo model, const char* name)
  236. : BlockType(id, 0, model, 1, 10, 0, name, true)
  237. {}
  238. void FluidBlockType::loadSuperBlock(
  239. Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
  240. {
  241. FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
  242. zReader->lese((char*)&block->fluidAmount, 2);
  243. BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
  244. }
  245. void FluidBlockType::saveSuperBlock(
  246. Block* zBlock, Framework::StreamWriter* zWriter) const
  247. {
  248. FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
  249. zWriter->schreibe((char*)&block->fluidAmount, 2);
  250. BlockType::saveSuperBlock(zBlock, zWriter);
  251. }
  252. Item* FluidBlockType::createItem() const
  253. {
  254. return 0;
  255. }
  256. Block* FluidBlockType::createBlock(Framework::Vec3<int> position) const
  257. {
  258. FluidBlock* result = new FluidBlock(getId(), position);
  259. result->fluidAmount = 1000;
  260. return result;
  261. }