Skip to content

Instantly share code, notes, and snippets.

@fwsGonzo
Created July 29, 2023 09:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fwsGonzo/d9116c46e5b7f8ed4743ab15f89c68c2 to your computer and use it in GitHub Desktop.
Save fwsGonzo/d9116c46e5b7f8ed4743ab15f89c68c2 to your computer and use it in GitHub Desktop.
3D fluid flow from unnamed game
#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