-
-
Save fwsGonzo/d9116c46e5b7f8ed4743ab15f89c68c2 to your computer and use it in GitHub Desktop.
3D fluid flow from unnamed game
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <api.h> | |
using namespace api; | |
void simulate_fluid_flow(int x, int y, int z, Block origin); | |
/// @brief Max flow distance of fluid | |
static constexpr uint16_t FLOW_MAX = 15; | |
/// @brief Time between flow changes | |
static constexpr float FLOW_TIME = 0.15; | |
static inline bool isOverwritable(Block blk, Block fluid) | |
{ | |
if (blk.isAir()) | |
return true; | |
if (blk.getID() == fluid.getID()) | |
return fluid.getExtra() < blk.getExtra(); | |
return !blk.isLiquid() && blk.isOverwritable() && !blk.isInGroup("seaweed"); | |
} | |
static int fluid_flow_down(GridWalker walker, Block blk) | |
{ | |
// Check destination | |
walker.move(0, -1, 0); | |
if (!walker.good()) | |
return 0; | |
auto newblock = walker.get(); | |
if (isOverwritable(newblock, blk)) | |
{ | |
walker.set(blk); | |
simulate_fluid_flow(walker.getX(), walker.getY(), walker.getZ(), blk); | |
return 1; | |
} | |
// Also return the level of the other block when the IDs match | |
if(newblock.getID() == blk.getID()) | |
return newblock.getExtra(); | |
return 15; | |
} | |
template <int dx, int dy, int dz> | |
static int fluid_check_side(GridWalker walker, Block blk) | |
{ | |
walker.move(dx, dy, dz); | |
auto newblock = walker.get(); | |
if (isOverwritable(newblock, blk)) | |
{ | |
auto under = walker.below().get(); | |
if (isOverwritable(under, blk)) | |
return 2; | |
return 1; | |
} | |
return 0; | |
} | |
template <int dx, int dy, int dz> | |
static void fluid_flow(GridWalker walker, Block blk) | |
{ | |
walker.move(dx, dy, dz); | |
walker.set(blk); | |
simulate_fluid_flow(walker.getX(), walker.getY(), walker.getZ(), blk); | |
} | |
void simulate_fluid_flow(int x, int y, int z, Block origin) | |
{ | |
auto level = origin.getExtra(); | |
if (level < FLOW_MAX) | |
{ | |
block_t fluid_id = origin.getID(); | |
// Start flowing | |
Timer::oneshot(FLOW_TIME, | |
[x, y, z, fluid_id] (auto) | |
{ | |
GridWalker walker{x, y, z}; | |
auto origin = walker.get(); | |
// Check source and flow level | |
if (origin.getID() == fluid_id && origin.getExtra() < FLOW_MAX) | |
{ | |
Block blk = origin; | |
// Raise flow level when going down | |
int flow = | |
fluid_flow_down(walker, Block{fluid_id, 1}); | |
if (flow <= 2) | |
return; | |
// Increase flow level on the sides | |
blk.setExtra(origin.getExtra() + 1); | |
int px = fluid_check_side< 1, 0, 0>(walker, blk); | |
int nx = fluid_check_side<-1, 0, 0>(walker, blk); | |
int pz = fluid_check_side< 0, 0, 1>(walker, blk); | |
int nz = fluid_check_side< 0, 0, -1>(walker, blk); | |
int flow_target = 1; | |
if (px == 2 || nx == 2 || pz == 2 || nz == 2) | |
flow_target = 2; | |
if (px == flow_target) | |
fluid_flow< 1, 0, 0>(walker, blk); | |
if (nx == flow_target) | |
fluid_flow<-1, 0, 0>(walker, blk); | |
if (pz == flow_target) | |
fluid_flow< 0, 0, 1>(walker, blk); | |
if (nz == flow_target) | |
fluid_flow< 0, 0, -1>(walker, blk); | |
} | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment