FluidBlock.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #include "FluidBlock.h"
  2. #include "Game.h"
  3. FluidBlock::FluidBlock(int typeId,
  4. Framework::Vec3<int> pos,
  5. int dimensionId,
  6. Vec3<float> lightWeights)
  7. : Block(typeId, 0, pos, dimensionId, 0),
  8. lightWeights(lightWeights)
  9. {
  10. transparent = 1;
  11. passable = 1;
  12. hp = 1;
  13. maxHP = 1;
  14. hardness = -1.f;
  15. speedModifier = 0.5f;
  16. tickSource = 1;
  17. interactable = 0;
  18. fluidAmount = 0;
  19. lastBroadcastedAmount = fluidAmount;
  20. }
  21. FluidBlock::~FluidBlock() {}
  22. bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
  23. {
  24. nextFlow = 0;
  25. int bottom = neighbourTypes[getDirectionIndex(Direction::BOTTOM)];
  26. if (bottom == BlockTypeEnum::AIR)
  27. {
  28. nextFlow |= 1 << getDirectionIndex(Direction::BOTTOM);
  29. }
  30. else
  31. {
  32. if (zNeighbours[getDirectionIndex(Direction::BOTTOM)]
  33. && bottom == zBlockType()->getId())
  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. short transferAmount = (short)MIN(
  43. this->fluidAmount, (short)1000 - below->fluidAmount);
  44. below->fluidAmount
  45. = (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 = 0; i < 6; i++)
  52. {
  53. if (getDirectionFromIndex(i) != Direction::BOTTOM
  54. && getDirectionFromIndex(i) != Direction::TOP)
  55. {
  56. if (neighbourTypes[i] == typeId && zNeighbours[i])
  57. {
  58. others[neighborCount] = zNeighbours[i];
  59. neighborCount++;
  60. }
  61. }
  62. }
  63. if (neighborCount > 0)
  64. {
  65. Inventory* array[5]
  66. = {this, others[0], others[1], others[2], others[3]};
  67. MultipleInventoryLock lock(array, neighborCount + 1);
  68. // all neighbot fluid blocks are locked now
  69. FluidBlock* otherFluids[4];
  70. for (int i = 0; i < neighborCount; i++)
  71. {
  72. otherFluids[i] = dynamic_cast<FluidBlock*>(others[i]);
  73. }
  74. // order other fluids increasing by fluid amount
  75. sortByAmound(otherFluids, neighborCount);
  76. short distCount = 0;
  77. short targetAmount = 0;
  78. for (int i = 1; i <= neighborCount; i++)
  79. {
  80. int fluidAmount = this->fluidAmount;
  81. for (int j = 0; j < i; j++)
  82. {
  83. fluidAmount += otherFluids[j]->fluidAmount;
  84. }
  85. if (fluidAmount / (i + 1) < this->fluidAmount)
  86. {
  87. targetAmount = (short)(fluidAmount / (i + 1));
  88. distCount = (short)i;
  89. }
  90. else
  91. {
  92. break;
  93. }
  94. }
  95. for (int i = 0; i < distCount; i++)
  96. {
  97. short transferAmount
  98. = (short)(targetAmount - otherFluids[i]->fluidAmount);
  99. otherFluids[i]->fluidAmount
  100. = (short)(otherFluids[i]->fluidAmount + transferAmount);
  101. this->fluidAmount = (short)(this->fluidAmount - transferAmount);
  102. }
  103. } // unlock
  104. neighborCount = 0;
  105. for (int i = 0; i < 6; i++)
  106. {
  107. if (getDirectionFromIndex(i) != Direction::BOTTOM
  108. && getDirectionFromIndex(i) != Direction::TOP)
  109. {
  110. int neighbor = neighbourTypes[i];
  111. if (neighbor == BlockTypeEnum::AIR
  112. && fluidAmount > neighborCount + 1)
  113. {
  114. nextFlow |= 1 << i;
  115. neighborCount++;
  116. }
  117. }
  118. }
  119. }
  120. return 1;
  121. }
  122. void FluidBlock::sendModelInfo(NetworkMessage* zMessage)
  123. {
  124. zMessage->addressBlock(this);
  125. char* msg = new char[3];
  126. msg[0] = 2; // fluid amount change
  127. *(short*)(msg + 1) = fluidAmount;
  128. zMessage->setMessage(msg, 3);
  129. }
  130. void FluidBlock::broadcastAmount()
  131. {
  132. if (lastBroadcastedAmount != fluidAmount)
  133. {
  134. lastBroadcastedAmount = fluidAmount;
  135. NetworkMessage* changeMsg = new NetworkMessage();
  136. sendModelInfo(changeMsg);
  137. Game::INSTANCE->broadcastMessage(changeMsg);
  138. }
  139. }
  140. void FluidBlock::onPostTick()
  141. {
  142. if (nextFlow != 0)
  143. {
  144. Game::INSTANCE->doLater([this]() {
  145. for (int i = 0; i < 6; i++)
  146. {
  147. if ((nextFlow | (1 << i)) == nextFlow)
  148. {
  149. Vec3<int> pos
  150. = getPos() + getDirection(getDirectionFromIndex(i));
  151. if (neighbourTypes[i] == BlockTypeEnum::AIR)
  152. {
  153. FluidBlock* spawn = new FluidBlock(
  154. typeId, pos, dimensionId, lightWeights);
  155. spawn->fluidAmount = 1;
  156. Game::INSTANCE->zDimension(getDimensionId())
  157. ->placeBlock(pos, spawn);
  158. fluidAmount--;
  159. }
  160. }
  161. }
  162. if (fluidAmount == 0)
  163. {
  164. Game::INSTANCE->zDimension(getDimensionId())
  165. ->placeBlock(getPos(),
  166. StaticRegistry<BlockType>::INSTANCE
  167. .zElement(BlockTypeEnum::AIR)
  168. ->createBlockAt(getPos(), dimensionId, 0));
  169. }
  170. else
  171. {
  172. broadcastAmount();
  173. }
  174. });
  175. }
  176. }
  177. void FluidBlock::sortByAmound(FluidBlock** array, int count)
  178. {
  179. if (count == 2)
  180. {
  181. if (array[0]->fluidAmount > array[1]->fluidAmount)
  182. {
  183. FluidBlock* tmp = array[0];
  184. array[0] = array[1];
  185. array[1] = tmp;
  186. }
  187. }
  188. else if (count == 3)
  189. {
  190. if (array[0]->fluidAmount > array[1]->fluidAmount)
  191. {
  192. FluidBlock* tmp = array[0];
  193. array[0] = array[1];
  194. array[1] = tmp;
  195. }
  196. if (array[1]->fluidAmount > array[2]->fluidAmount)
  197. {
  198. FluidBlock* tmp = array[1];
  199. array[1] = array[2];
  200. array[2] = tmp;
  201. }
  202. if (array[0]->fluidAmount > array[1]->fluidAmount)
  203. {
  204. FluidBlock* tmp = array[0];
  205. array[0] = array[1];
  206. array[1] = tmp;
  207. }
  208. }
  209. else if (count == 4)
  210. {
  211. if (array[0]->fluidAmount > array[1]->fluidAmount)
  212. {
  213. FluidBlock* tmp = array[0];
  214. array[0] = array[1];
  215. array[1] = tmp;
  216. }
  217. if (array[2]->fluidAmount > array[3]->fluidAmount)
  218. {
  219. FluidBlock* tmp = array[2];
  220. array[2] = array[3];
  221. array[3] = tmp;
  222. }
  223. if (array[0]->fluidAmount > array[2]->fluidAmount)
  224. {
  225. FluidBlock* tmp = array[0];
  226. array[0] = array[2];
  227. array[2] = tmp;
  228. }
  229. if (array[1]->fluidAmount > array[3]->fluidAmount)
  230. {
  231. FluidBlock* tmp = array[1];
  232. array[1] = array[3];
  233. array[3] = tmp;
  234. }
  235. if (array[1]->fluidAmount > array[2]->fluidAmount)
  236. {
  237. FluidBlock* tmp = array[1];
  238. array[1] = array[2];
  239. array[2] = tmp;
  240. }
  241. }
  242. }
  243. void FluidBlock::filterPassingLight(unsigned char rgb[3]) const
  244. {
  245. rgb[0] = (unsigned char)(rgb[0] * lightWeights.x);
  246. rgb[1] = (unsigned char)(rgb[1] * lightWeights.y);
  247. rgb[2] = (unsigned char)(rgb[2] * lightWeights.z);
  248. }
  249. short FluidBlock::getFluidAmount() const
  250. {
  251. return fluidAmount;
  252. }
  253. FluidBlockType::FluidBlockType(int id,
  254. ModelInfo model,
  255. const char* name,
  256. int mapColor,
  257. Vec3<float> lightWeights)
  258. : BlockType(id, 0, model, 1, 10, 0, name, true, mapColor),
  259. lightWeights(lightWeights)
  260. {}
  261. void FluidBlockType::loadSuperBlock(
  262. Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
  263. {
  264. FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
  265. zReader->lese((char*)&block->fluidAmount, 2);
  266. BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
  267. }
  268. void FluidBlockType::saveSuperBlock(
  269. Block* zBlock, Framework::StreamWriter* zWriter) const
  270. {
  271. FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
  272. zWriter->schreibe((char*)&block->fluidAmount, 2);
  273. BlockType::saveSuperBlock(zBlock, zWriter);
  274. }
  275. Item* FluidBlockType::createItem() const
  276. {
  277. return 0;
  278. }
  279. Block* FluidBlockType::createBlock(
  280. Framework::Vec3<int> position, int dimensionId) const
  281. {
  282. FluidBlock* result
  283. = new FluidBlock(getId(), position, dimensionId, lightWeights);
  284. result->fluidAmount = 1000;
  285. return result;
  286. }
  287. bool FluidBlockType::isFluid() const
  288. {
  289. return true;
  290. }