Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement fluid physics changes #1062

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;

import net.glowstone.inventory.ToolType;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
Expand Down
118 changes: 88 additions & 30 deletions src/main/java/net/glowstone/block/blocktype/BlockLiquid.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import net.glowstone.block.GlowBlock;
import net.glowstone.block.GlowBlockState;
import net.glowstone.block.ItemTable;
import net.glowstone.block.data.Waterlogged;
import net.glowstone.entity.GlowPlayer;
import org.bukkit.Material;
import org.bukkit.block.Biome;
Expand Down Expand Up @@ -60,6 +61,25 @@ private static boolean isWater(Material material) {
return material == Material.WATER;
}

private static boolean isWaterlogged(GlowBlock block) {
return block.getBlockData() instanceof Waterlogged
&& ((Waterlogged) block.getBlockData()).isWaterlogged();
}

// These account for waterlogged blocks:

private static boolean isLiquid(GlowBlock block) {
return isWaterlogged(block) || block.isLiquid();
}

private static Material getType(GlowBlock block) {
return isWaterlogged(block) ? Material.WATER : block.getType();
}

private static byte getStrength(GlowBlock block) {
return isWaterlogged(block) ? STRENGTH_SOURCE : block.getState().getRawData();
}

/**
* Check if the BlockState block is collectible by a bucket.
*
Expand Down Expand Up @@ -103,8 +123,8 @@ private void calculateFlow(GlowBlock block) {
}
GlowBlockState state = block.getState();
if (calculateTarget(block.getRelative(DOWN), DOWN, true)) {
if (!block.getRelative(UP).isLiquid()
&& state.getRawData() == STRENGTH_SOURCE) {
if (!isLiquid(block.getRelative(UP))
&& getStrength(block) == STRENGTH_SOURCE) {
for (BlockFace face : SIDES) {
calculateTarget(block.getRelative(face), face, true);
}
Expand Down Expand Up @@ -145,11 +165,19 @@ private boolean calculateTarget(GlowBlock target, BlockFace direction, boolean f
}
return true;
}
if (target.isLiquid()) {
if (getType(target.getRelative(direction.getOppositeFace())) == Material.WATER
&& target.getBlockData() instanceof Waterlogged) {
// Fill the block with water, if waterloggable
if (flow) {
soak(target, direction);
}
return true;
}
if (isLiquid(target)) {
// let's mix
if (flow) {
mix(target, direction, target.getRelative(direction.getOppositeFace()).getType(),
target.getType());
mix(target, direction, getType(target.getRelative(direction.getOppositeFace())),
getType(target));
}
return true;
}
Expand All @@ -163,9 +191,10 @@ private void flow(GlowBlock source, BlockFace direction) {
if (fromToEvent.isCancelled()) {
return;
}
byte strength = fromToEvent.getBlock().getState().getRawData();
GlowBlock block = (GlowBlock) fromToEvent.getBlock();
byte strength = getStrength(block);
if (DOWN != fromToEvent.getFace()) {
if (strength < (isWater(fromToEvent.getBlock().getType())
if (strength < (isWater(getType(block))
|| fromToEvent.getBlock().getBiome() == Biome.NETHER ? STRENGTH_MIN_WATER
: STRENGTH_MIN_LAVA)) {
// decrease the strength
Expand All @@ -179,11 +208,40 @@ private void flow(GlowBlock source, BlockFace direction) {
strength = STRENGTH_MAX;
}
// flow to the target
// doesn't need to take waterlogging into account, because it will never flow into a waterloggable block
// (because waterlogged blocks always "have" water source blocks in them)
GlowBlock toBlock = (GlowBlock) fromToEvent.getToBlock();
toBlock.setType(fromToEvent.getBlock().getType(), strength, false);
toBlock.getWorld().requestPulse(toBlock);
}

private void soak(GlowBlock target, BlockFace direction) {
if (getStrength(target.getRelative(direction.getOppositeFace())) == STRENGTH_MIN_WATER) {
// no strength, can't waterlog
return;
}
boolean source = false; // is a water source block
BlockFace[] faces = {UP, NORTH, EAST, SOUTH, WEST};
int count = 0;
for (BlockFace face : faces) {
if (isWater(getType(target.getRelative(face)))) {
if (count < 2 && face != UP
&& getStrength(target.getRelative(face)) == STRENGTH_SOURCE) {
count++;
}
if (target.getWorld().getServer().getClassicWater()
&& (face == UP || getStrength(target.getRelative(face)) < getStrength(target))) {
source = true;
break;
}
}
}
source = source || count == 2; // found 2 adjacent source blocks
if (source) { // only waterlog with source strength
((Waterlogged) target.getBlockData()).setWaterlogged(true);
}
}

private void mix(GlowBlock target, BlockFace direction, Material flowingMaterial,
Material targetMaterial) {
if (flowingMaterial == Material.WATER && targetMaterial == Material.LAVA) {
Expand All @@ -207,34 +265,34 @@ private void mix(GlowBlock target, BlockFace direction, Material flowingMaterial
@Override
public void updatePhysicsAfterEvent(GlowBlock me) {
super.updatePhysicsAfterEvent(me);
if (isStationary(me.getType())) {
if (isStationary(getType(me))) {
// TODO: set flowing
//me.setType(getOpposite(me.getType()), me.getData(), false);
}
boolean isWater = isWater(me.getType());
if (me.getState().getRawData() != STRENGTH_SOURCE) {
boolean isWater = isWater(getType(me));
byte strength = getStrength(me);
if (strength != STRENGTH_SOURCE) {
BlockFace[] faces = {UP, NORTH, EAST, SOUTH, WEST};
boolean connected = false;
int count = 0;
for (BlockFace face : faces) {
if (me.getRelative(face).getType() == me.getType()) {
if (isWater && count < 2 && face != UP
&& me.getRelative(face).getState().getRawData() == STRENGTH_SOURCE) {
count++;
}
if (!connected && face == UP
|| me.getRelative(face).getState().getRawData()
< me.getState().getRawData()) {
connected = true;
if (me.getWorld().getServer().getClassicWater()) {
me.getState().setRawData(STRENGTH_SOURCE);
}
}
if (me.getWorld().getServer().getClassicWater()
&& me.getRelative(face).getState().getRawData() == STRENGTH_SOURCE) {
me.getRelative(face).setType(Material.AIR);
if (getType(me.getRelative(face)) != getType(me)) {
continue;
}
byte neighborStrength = getStrength(me.getRelative(face));
if (count < 2 && face != UP
&& (isWater && neighborStrength == STRENGTH_SOURCE)) {
count++;
}
if (!connected && face == UP || neighborStrength < strength) {
connected = true;
if (me.getWorld().getServer().getClassicWater()) {
me.getState().setRawData(STRENGTH_SOURCE);
}
}
if (me.getWorld().getServer().getClassicWater() && neighborStrength == STRENGTH_SOURCE) {
me.getRelative(face).setType(Material.AIR);
}
}
if (!connected) {
me.setType(Material.AIR);
Expand All @@ -245,9 +303,9 @@ public void updatePhysicsAfterEvent(GlowBlock me) {
return;
}
}
if (!(me.getState().getRawData()
== (isWater || me.getBiome() == Biome.NETHER ? STRENGTH_MIN_WATER
: STRENGTH_MIN_LAVA)) || me.getRelative(DOWN).getType() == Material.AIR) {
if (getStrength(me)
!= (isWater || me.getBiome() == Biome.NETHER ? STRENGTH_MIN_WATER
: STRENGTH_MIN_LAVA) || me.getRelative(DOWN).getType() == Material.AIR) {
calculateFlow(me);
}
}
Expand All @@ -259,7 +317,7 @@ public boolean isPulseOnce(GlowBlock block) {

@Override
public int getPulseTickSpeed(GlowBlock block) {
return isWater(block.getType()) || block.getBiome() == Biome.NETHER ? TICK_RATE_WATER
return isWater(getType(block)) || block.getBiome() == Biome.NETHER ? TICK_RATE_WATER
: TICK_RATE_LAVA;
}
}
25 changes: 24 additions & 1 deletion src/main/java/net/glowstone/block/blocktype/BlockMagma.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
package net.glowstone.block.blocktype;

import net.glowstone.block.GlowBlock;
import net.glowstone.block.GlowBlockState;
import net.glowstone.entity.GlowPlayer;
import net.glowstone.inventory.ToolType;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;

public class BlockMagma extends BlockDirectDrops {

public BlockMagma() {
super(Material.MAGMA_BLOCK, ToolType.PICKAXE);
}

@Override
public void placeBlock(GlowPlayer player, GlowBlockState blockState, BlockFace face,
ItemStack holding, Vector clickedLoc) {
super.placeBlock(player, blockState, face, holding, clickedLoc);
bubbleUp(blockState.getBlock().getRelative(BlockFace.UP));
}

private void bubbleUp(GlowBlock target) {
// trigger bubble chain
if (target.getType() == Material.WATER) {
target.setType(Material.BUBBLE_COLUMN);
}
if (target.getType() == Material.BUBBLE_COLUMN) {
Bukkit.getLogger().info("create whirlpool at " + target.getLocation());
// todo: set 'drag' blockdata to true
}
}

@Override
public void onEntityStep(GlowBlock block, LivingEntity entity) {
entity.damage(1.0, EntityDamageEvent.DamageCause.FIRE);
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/net/glowstone/block/blocktype/BlockSoulSand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package net.glowstone.block.blocktype;

import net.glowstone.block.GlowBlock;
import net.glowstone.block.GlowBlockState;
import net.glowstone.entity.GlowPlayer;
import net.glowstone.inventory.ToolType;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;

public class BlockSoulSand extends BlockDirectDrops {
public BlockSoulSand() {
super(Material.SOUL_SAND, ToolType.SHOVEL);
}

@Override
public void placeBlock(GlowPlayer player, GlowBlockState blockState, BlockFace face,
ItemStack holding, Vector clickedLoc) {
super.placeBlock(player, blockState, face, holding, clickedLoc);
bubbleUp(blockState.getBlock().getRelative(BlockFace.UP));
}

private void bubbleUp(GlowBlock target) {
if (target.getType() == Material.WATER) {
target.setType(Material.BUBBLE_COLUMN);
}
if (target.getType() == Material.BUBBLE_COLUMN) {
Bukkit.getLogger().info("create upwards bubble column at " + target.getLocation());
// todo: set 'drag' blockdata to false
}
}
}
23 changes: 23 additions & 0 deletions src/main/java/net/glowstone/block/blocktype/BlockWater.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import net.glowstone.block.GlowBlock;
import net.glowstone.block.GlowBlockState;
import net.glowstone.constants.GlowBiomeClimate;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.event.block.BlockSpreadEvent;
Expand Down Expand Up @@ -40,6 +41,28 @@ public void updateBlock(GlowBlock block) {
}
}

@Override
public void onNearBlockChanged(GlowBlock block, BlockFace face, GlowBlock changedBlock,
Material oldType, byte oldData, Material newType, byte newData) {
// spread bubble column up or let it die out
if (face != BlockFace.DOWN) {
return;
}
switch (newType) {
case BUBBLE_COLUMN: {
block.setType(Material.BUBBLE_COLUMN);
Bukkit.getLogger().info("spread bubble column at " + block.getLocation());
// todo: set 'drag' blockdata to that of the block below
break;
}
case WATER: {
block.setType(Material.WATER);
Bukkit.getLogger().info("destroy bubble column at " + block.getLocation());
break;
}
}
}

private boolean hasNearSolidBlock(GlowBlock block) {
// check there's at least a solid block around
for (BlockFace face : SIDES) {
Expand Down