FluidBlock.cpp 8.5 KB

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