FluidBlock.cpp 8.9 KB

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