Created
September 10, 2024 10:28
-
-
Save Densamisten/60cb7487b10043c53a85907598c3af31 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
package exonihility.block; | |
import com.mojang.serialization.MapCodec; | |
import exonihility.effect.AllyshiptStatusEffects; | |
import it.unimi.dsi.fastutil.objects.Object2IntMap; | |
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; | |
import net.minecraft.block.*; | |
import net.minecraft.entity.Entity; | |
import net.minecraft.entity.effect.StatusEffectInstance; | |
import net.minecraft.entity.player.PlayerEntity; | |
import net.minecraft.fluid.FluidState; | |
import net.minecraft.fluid.Fluids; | |
import net.minecraft.item.ItemPlacementContext; | |
import net.minecraft.particle.ParticleTypes; | |
import net.minecraft.registry.Registries; | |
import net.minecraft.registry.tag.BiomeTags; | |
import net.minecraft.server.world.ServerWorld; | |
import net.minecraft.sound.SoundCategory; | |
import net.minecraft.sound.SoundEvents; | |
import net.minecraft.state.StateManager; | |
import net.minecraft.state.property.BooleanProperty; | |
import net.minecraft.state.property.IntProperty; | |
import net.minecraft.state.property.Properties; | |
import net.minecraft.util.Util; | |
import net.minecraft.util.math.BlockPos; | |
import net.minecraft.util.math.Direction; | |
import net.minecraft.util.math.random.Random; | |
import net.minecraft.util.shape.VoxelShape; | |
import net.minecraft.util.shape.VoxelShapes; | |
import net.minecraft.world.*; | |
import net.minecraft.world.dimension.NetherPortal; | |
import java.util.Map; | |
import java.util.function.Function; | |
import java.util.stream.Collectors; | |
public class AmaterasuBlock extends AbstractFireBlock implements Waterloggable { | |
public static final MapCodec<AmaterasuBlock> CODEC = createCodec(AmaterasuBlock::new); | |
public static final IntProperty AGE; | |
public static final BooleanProperty NORTH; | |
public static final BooleanProperty EAST; | |
public static final BooleanProperty SOUTH; | |
public static final BooleanProperty WEST; | |
public static final BooleanProperty UP; | |
private static final Map<Direction, BooleanProperty> DIRECTION_PROPERTIES; | |
private static final VoxelShape UP_SHAPE; | |
private static final VoxelShape WEST_SHAPE; | |
private static final VoxelShape EAST_SHAPE; | |
private static final VoxelShape NORTH_SHAPE; | |
private static final VoxelShape SOUTH_SHAPE; | |
public static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED; | |
protected static final VoxelShape BASE_SHAPE = Block.createCuboidShape(0.0, 0.0, 0.0, 16.0, 1.0, 16.0); | |
private final Map<BlockState, VoxelShape> shapesByState; | |
private final Object2IntMap<Block> burnChances = new Object2IntOpenHashMap<>(); | |
private final Object2IntMap<Block> spreadChances = new Object2IntOpenHashMap<>(); | |
public MapCodec<AmaterasuBlock> getCodec() { | |
return CODEC; | |
} | |
public AmaterasuBlock(AbstractBlock.Settings settings) { | |
super(settings, 1.0F); | |
this.setDefaultState(this.stateManager.getDefaultState().with(AGE, 0).with(NORTH, false).with(EAST, false).with(SOUTH, false).with(WEST, false).with(UP, false).with(WATERLOGGED, false)); | |
this.shapesByState = this.stateManager.getStates().stream() | |
.filter((state) -> state.get(AGE) == 0) | |
.collect(Collectors.toMap(Function.identity(), AmaterasuBlock::getShapeForState)); | |
} | |
private static VoxelShape getShapeForState(BlockState state) { | |
VoxelShape voxelShape = VoxelShapes.empty(); | |
if (state.get(UP)) { | |
voxelShape = UP_SHAPE; | |
} | |
if (state.get(NORTH)) { | |
voxelShape = VoxelShapes.union(voxelShape, NORTH_SHAPE); | |
} | |
if (state.get(SOUTH)) { | |
voxelShape = VoxelShapes.union(voxelShape, SOUTH_SHAPE); | |
} | |
if (state.get(EAST)) { | |
voxelShape = VoxelShapes.union(voxelShape, EAST_SHAPE); | |
} | |
if (state.get(WEST)) { | |
voxelShape = VoxelShapes.union(voxelShape, WEST_SHAPE); | |
} | |
return voxelShape.isEmpty() ? BASE_SHAPE : voxelShape; | |
} | |
@Override | |
protected BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) { | |
if (state.get(WATERLOGGED)) { | |
world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); | |
} | |
return this.canPlaceAt(state, world, pos) ? this.getStateWithAge(world, pos, state.get(AGE)) : Blocks.AIR.getDefaultState(); | |
} | |
@Override | |
protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { | |
return this.shapesByState.get(state.with(AGE, 0)); | |
} | |
@Override | |
public BlockState getPlacementState(ItemPlacementContext ctx) { | |
return this.getStateForPosition(ctx.getWorld(), ctx.getBlockPos()) | |
.with(WATERLOGGED, ctx.getWorld().getFluidState(ctx.getBlockPos()).isOf(Fluids.WATER)); | |
} | |
protected BlockState getStateForPosition(BlockView world, BlockPos pos) { | |
BlockPos blockPos = pos.down(); | |
BlockState blockState = world.getBlockState(blockPos); | |
if (!this.isFlammable(blockState) && !blockState.isSideSolidFullSquare(world, blockPos, Direction.UP)) { | |
BlockState blockState2 = this.getDefaultState(); | |
Direction[] var6 = Direction.values(); | |
for (Direction direction : var6) { | |
BooleanProperty booleanProperty = DIRECTION_PROPERTIES.get(direction); | |
if (booleanProperty != null) { | |
blockState2 = blockState2.with(booleanProperty, this.isFlammable(world.getBlockState(pos.offset(direction)))); | |
} | |
} | |
return blockState2; | |
} else { | |
return this.getDefaultState(); | |
} | |
} | |
@Override | |
protected boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) { | |
BlockPos blockPos = pos.down(); | |
BlockPos blockBelowPos = pos.down(); | |
BlockState blockBelowState = world.getBlockState(blockBelowPos); | |
FluidState fluidState = world.getFluidState(blockBelowPos); | |
return world.getBlockState(blockPos).isSideSolidFullSquare(world, blockPos, Direction.UP) || this.areBlocksAroundFlammable(world, pos) || blockBelowState.getBlock() instanceof Waterloggable || fluidState.getFluid() == Fluids.WATER; | |
} | |
@Override | |
protected void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) { | |
world.scheduleBlockTick(pos, this, getFireTickDelay(world.random)); | |
int i = state.get(AGE); | |
int j = Math.min(15, i + random.nextInt(3) / 2); | |
if (i != j) { | |
state = state.with(AGE, j); | |
world.setBlockState(pos, state, 4); | |
} | |
boolean bl2 = world.getBiome(pos).isIn(BiomeTags.INCREASED_FIRE_BURNOUT); | |
int k = bl2 ? -50 : 0; | |
this.trySpreadingFire(world, pos.east(), 1000 + k, random, i); | |
this.trySpreadingFire(world, pos.west(), 1000 + k, random, i); | |
this.trySpreadingFire(world, pos.down(), 1000 + k, random, i); | |
this.trySpreadingFire(world, pos.up(), 1000 + k, random, i); | |
this.trySpreadingFire(world, pos.north(), 1000 + k, random, i); | |
this.trySpreadingFire(world, pos.south(), 1000 + k, random, i); | |
BlockPos.Mutable mutable = new BlockPos.Mutable(); | |
for (int l = -1; l <= 1; ++l) { | |
for (int m = -1; m <= 1; ++m) { | |
for (int n = -1; n <= 4; ++n) { | |
if (l != 0 || n != 0 || m != 0) { | |
int o = 100; | |
if (n > 1) { | |
o += (n - 1) * 100; | |
} | |
mutable.set(pos, l, n, m); | |
int p = this.getBurnChance(world, mutable); | |
if (p > 0) { | |
int q = (p + 40 + world.getDifficulty().getId() * 7) / (i + 30); | |
if (bl2) { | |
q /= 2; | |
} | |
if (q > 0 && random.nextInt(o) <= q) { | |
int r = Math.min(15, i + random.nextInt(5) / 4); | |
world.setBlockState(mutable, this.getStateWithAge(world, mutable, r), 3); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
private int getSpreadChance(BlockState state) { | |
return this.spreadChances.getInt(state.getBlock()); | |
} | |
private int getBurnChance(BlockState state) { | |
return this.burnChances.getInt(state.getBlock()); | |
} | |
private void trySpreadingFire(World world, BlockPos pos, int spreadFactor, Random random, int currentAge) { | |
int i = this.getSpreadChance(world.getBlockState(pos)); | |
if (random.nextInt(spreadFactor) < i) { | |
BlockState blockState = world.getBlockState(pos); | |
if (random.nextInt(currentAge + 10) < 5) { | |
int j = Math.min(currentAge + random.nextInt(5) / 4, 15); | |
world.setBlockState(pos, this.getStateWithAge(world, pos, j), 3); | |
} | |
Block block = blockState.getBlock(); | |
if (block instanceof TntBlock) { | |
TntBlock.primeTnt(world, pos); | |
} | |
} | |
} | |
public static BlockState getState(BlockView world, BlockPos pos) { | |
BlockPos blockPos = pos.down(); | |
BlockState blockState = world.getBlockState(blockPos); | |
return SoulFireBlock.isSoulBase(blockState) ? AllyshipBlocks.AMATERASU_BLOCK.getDefaultState() : ((AmaterasuBlock) AllyshipBlocks.AMATERASU_BLOCK).getStateForPosition(world, pos); | |
} | |
private BlockState getStateWithAge(WorldAccess world, BlockPos pos, int age) { | |
BlockState blockState = getState(world, pos); | |
return blockState.isOf(AllyshipBlocks.AMATERASU_BLOCK) ? blockState.with(AGE, age) : blockState; | |
} | |
private boolean areBlocksAroundFlammable(BlockView world, BlockPos pos) { | |
Direction[] var3 = Direction.values(); | |
for (Direction direction : var3) { | |
if (this.isFlammable(world.getBlockState(pos.offset(direction)))) { | |
return true; | |
} | |
} | |
return false; | |
} | |
private int getBurnChance(WorldView world, BlockPos pos) { | |
if (!world.isAir(pos)) { | |
return 0; | |
} else { | |
int i = 0; | |
Direction[] var4 = Direction.values(); | |
for (Direction direction : var4) { | |
BlockState blockState = world.getBlockState(pos.offset(direction)); | |
i = Math.max(this.getBurnChance(blockState), i); | |
} | |
return i; | |
} | |
} | |
@Override | |
public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { | |
if (random.nextInt(24) == 0) { | |
world.playSound((double)pos.getX() + 0.5, (double)pos.getY() + 0.5, (double)pos.getZ() + 0.5, SoundEvents.BLOCK_FIRE_AMBIENT, SoundCategory.BLOCKS, 1.0F + random.nextFloat(), random.nextFloat() * 0.7F + 0.3F, false); | |
} | |
BlockPos blockPos = pos.down(); | |
BlockState blockState = world.getBlockState(blockPos); | |
int i; | |
double d; | |
double e; | |
double f; | |
if (!this.isFlammable(blockState) && !blockState.isSideSolidFullSquare(world, blockPos, Direction.UP)) { | |
if (this.isFlammable(world.getBlockState(pos.west()))) { | |
// Custom black flame effect | |
for ( i = 0; i < 3; ++i) { | |
double x = pos.getX() + random.nextDouble(); | |
double y = pos.getY() + random.nextDouble() * 0.5 + 0.5; | |
double z = pos.getZ() + random.nextDouble(); | |
world.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0, 0.0, 0.0); // SMOKE instead of LARGE_SMOKE for a black appearance | |
} | |
} | |
if (this.isFlammable(world.getBlockState(pos.east()))) { | |
// Custom black flame effect | |
for (i = 0; i < 3; ++i) { | |
double x = pos.getX() + random.nextDouble(); | |
double y = pos.getY() + random.nextDouble() * 0.5 + 0.5; | |
double z = pos.getZ() + random.nextDouble(); | |
world.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0, 0.0, 0.0); // SMOKE instead of LARGE_SMOKE for a black appearance | |
} | |
} | |
if (this.isFlammable(world.getBlockState(pos.north()))) { | |
for (i = 0; i < 3; ++i) { | |
double x = pos.getX() + random.nextDouble(); | |
double y = pos.getY() + random.nextDouble() * 0.5 + 0.5; | |
double z = pos.getZ() + random.nextDouble(); | |
world.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0, 0.0, 0.0); // SMOKE instead of LARGE_SMOKE for a black appearance | |
} | |
} | |
if (this.isFlammable(world.getBlockState(pos.south()))) { | |
for (i = 0; i < 3; ++i) { | |
double x = pos.getX() + random.nextDouble(); | |
double y = pos.getY() + random.nextDouble() * 0.5 + 0.5; | |
double z = pos.getZ() + random.nextDouble(); | |
world.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0, 0.0, 0.0); // SMOKE instead of LARGE_SMOKE for a black appearance | |
} | |
} | |
if (this.isFlammable(world.getBlockState(pos.up()))) { | |
for (i = 0; i < 3; ++i) { | |
double x = pos.getX() + random.nextDouble(); | |
double y = pos.getY() + random.nextDouble() * 0.5 + 0.5; | |
double z = pos.getZ() + random.nextDouble(); | |
world.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0, 0.0, 0.0); // SMOKE instead of LARGE_SMOKE for a black appearance | |
} | |
} | |
} else { | |
for (i = 0; i < 3; ++i) { | |
double x = pos.getX() + random.nextDouble(); | |
double y = pos.getY() + random.nextDouble() * 0.5 + 0.5; | |
double z = pos.getZ() + random.nextDouble(); | |
world.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0, 0.0, 0.0); // SMOKE instead of LARGE_SMOKE for a black appearance | |
} | |
} | |
} | |
@Override | |
public void onSteppedOn(World world, BlockPos pos, BlockState state, Entity entity) { | |
if (entity instanceof PlayerEntity) { | |
((PlayerEntity) entity).addStatusEffect(new StatusEffectInstance(AllyshiptStatusEffects.AMATERASU, 20, 0)); | |
} | |
super.onSteppedOn(world, pos, state, entity); | |
} | |
@Override | |
protected boolean isFlammable(BlockState state) { | |
return false; | |
} | |
@Override | |
protected void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean notify) { | |
super.onBlockAdded(state, world, pos, oldState, notify); | |
world.scheduleBlockTick(pos, this, getFireTickDelay(world.random)); | |
} | |
private static int getFireTickDelay(Random random) { | |
return 30 + random.nextInt(10); | |
} | |
@Override | |
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) { | |
builder.add(AGE, NORTH, EAST, SOUTH, WEST, UP, WATERLOGGED); | |
} | |
public void registerFlammableBlock(Block block, int burnChance, int spreadChance) { | |
this.burnChances.put(block, burnChance); | |
this.spreadChances.put(block, spreadChance); | |
} | |
public static void registerDefaultFlammables() { | |
AmaterasuBlock amaterasuBlock = (AmaterasuBlock) AllyshipBlocks.AMATERASU_BLOCK; | |
Registries.BLOCK.forEach(block -> amaterasuBlock.registerFlammableBlock(block, 100, 10)); | |
} | |
public static boolean canPlaceAt(World world, BlockPos pos, Direction direction) { | |
BlockState blockState = world.getBlockState(pos); | |
if (!blockState.isAir()) { | |
return false; | |
} else { | |
return getState(world, pos).canPlaceAt(world, pos) || shouldLightPortalAt(world, pos, direction); | |
} | |
} | |
private static boolean isOverworldOrNether(World world) { | |
return world.getRegistryKey() == World.OVERWORLD || world.getRegistryKey() == World.NETHER; | |
} | |
private static boolean shouldLightPortalAt(World world, BlockPos pos, Direction direction) { | |
if (!isOverworldOrNether(world)) { | |
return false; | |
} else { | |
BlockPos.Mutable mutable = pos.mutableCopy(); | |
boolean bl = false; | |
Direction[] var5 = Direction.values(); | |
int var6 = var5.length; | |
for(int var7 = 0; var7 < var6; ++var7) { | |
Direction direction2 = var5[var7]; | |
if (world.getBlockState(mutable.set(pos).move(direction2)).isOf(Blocks.OBSIDIAN)) { | |
bl = true; | |
break; | |
} | |
} | |
if (!bl) { | |
return false; | |
} else { | |
Direction.Axis axis = direction.getAxis().isHorizontal() ? direction.rotateYCounterclockwise().getAxis() : Direction.Type.HORIZONTAL.randomAxis(world.random); | |
return NetherPortal.getNewPortal(world, pos, axis).isPresent(); | |
} | |
} | |
} | |
static { | |
AGE = Properties.AGE_15; | |
NORTH = ConnectingBlock.NORTH; | |
EAST = ConnectingBlock.EAST; | |
SOUTH = ConnectingBlock.SOUTH; | |
WEST = ConnectingBlock.WEST; | |
UP = ConnectingBlock.UP; | |
DIRECTION_PROPERTIES = ConnectingBlock.FACING_PROPERTIES.entrySet().stream() | |
.filter(entry -> entry.getKey() != Direction.DOWN) | |
.collect(Util.toMap()); | |
UP_SHAPE = Block.createCuboidShape(0.0, 15.0, 0.0, 16.0, 16.0, 16.0); | |
WEST_SHAPE = Block.createCuboidShape(0.0, 0.0, 0.0, 1.0, 16.0, 16.0); | |
EAST_SHAPE = Block.createCuboidShape(15.0, 0.0, 0.0, 16.0, 16.0, 16.0); | |
NORTH_SHAPE = Block.createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 1.0); | |
SOUTH_SHAPE = Block.createCuboidShape(0.0, 0.0, 15.0, 16.0, 16.0, 16.0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment