mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-27 15:29:36 -04:00
152 lines
4.5 KiB
C#
152 lines
4.5 KiB
C#
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
|
|
using System;
|
|
using ClassicalSharp.Map;
|
|
|
|
namespace ClassicalSharp.Singleplayer {
|
|
|
|
public class FoilagePhysics {
|
|
Game game;
|
|
PhysicsBase physics;
|
|
World map;
|
|
Random rnd = new Random();
|
|
|
|
public FoilagePhysics(Game game, PhysicsBase physics) {
|
|
this.game = game;
|
|
this.physics = physics;
|
|
map = game.World;
|
|
|
|
physics.OnPlace[Block.Sapling] = HandleSapling;
|
|
physics.OnRandomTick[Block.Sapling] = HandleSapling;
|
|
physics.OnRandomTick[Block.Dirt] = HandleDirt;
|
|
physics.OnRandomTick[Block.Grass] = HandleGrass;
|
|
|
|
physics.OnRandomTick[Block.Dandelion] = HandleFlower;
|
|
physics.OnRandomTick[Block.Rose] = HandleFlower;
|
|
physics.OnRandomTick[Block.RedMushroom] = HandleMushroom;
|
|
physics.OnRandomTick[Block.BrownMushroom] = HandleMushroom;
|
|
}
|
|
|
|
void HandleSapling(int index, byte block) {
|
|
int x = index % map.Width;
|
|
int y = (index / map.Width) / map.Length;
|
|
int z = (index / map.Width) % map.Length;
|
|
GrowTree(x, y, z);
|
|
}
|
|
|
|
void HandleDirt(int index, byte block) {
|
|
int x = index % map.Width;
|
|
int y = (index / map.Width) / map.Length;
|
|
int z = (index / map.Width) % map.Length;
|
|
|
|
if (game.Lighting.IsLit(x, y, z))
|
|
game.UpdateBlock(x, y, z, Block.Grass);
|
|
}
|
|
|
|
void HandleGrass(int index, byte block) {
|
|
int x = index % map.Width;
|
|
int y = (index / map.Width) / map.Length;
|
|
int z = (index / map.Width) % map.Length;
|
|
|
|
if (!game.Lighting.IsLit(x, y, z))
|
|
game.UpdateBlock(x, y, z, Block.Dirt);
|
|
}
|
|
|
|
void HandleFlower(int index, byte block) {
|
|
int x = index % map.Width;
|
|
int y = (index / map.Width) / map.Length;
|
|
int z = (index / map.Width) % map.Length;
|
|
|
|
if (!game.Lighting.IsLit(x, y, z)) {
|
|
game.UpdateBlock(x, y, z, Block.Air);
|
|
physics.ActivateNeighbours(x, y, z, index);
|
|
return;
|
|
}
|
|
|
|
byte below = Block.Dirt;
|
|
if (y > 0) below = map.blocks[index - map.Width * map.Length];
|
|
if (!(below == Block.Dirt || below == Block.Grass)) {
|
|
game.UpdateBlock(x, y, z, Block.Air);
|
|
physics.ActivateNeighbours(x, y, z, index);
|
|
}
|
|
}
|
|
|
|
void HandleMushroom(int index, byte block) {
|
|
int x = index % map.Width;
|
|
int y = (index / map.Width) / map.Length;
|
|
int z = (index / map.Width) % map.Length;
|
|
|
|
if (game.Lighting.IsLit(x, y, z)) {
|
|
game.UpdateBlock(x, y, z, Block.Air);
|
|
physics.ActivateNeighbours(x, y, z, index);
|
|
return;
|
|
}
|
|
|
|
byte below = Block.Stone;
|
|
if (y > 0) below = map.blocks[index - map.Width * map.Length];
|
|
if (!(below == Block.Stone || below == Block.Cobblestone)) {
|
|
game.UpdateBlock(x, y, z, Block.Air);
|
|
physics.ActivateNeighbours(x, y, z, index);
|
|
}
|
|
}
|
|
|
|
// Algorithm source: Looking at the trees generated by the default classic server.
|
|
// Hence, the random thresholds may be slightly off.
|
|
public void GrowTree(int x, int y, int z) {
|
|
int trunkH = rnd.Next(1, 4);
|
|
game.UpdateBlock(x, y, z, 0);
|
|
|
|
// Can the new tree grow?
|
|
if (!CheckBounds(x, x, y, y + trunkH - 1, z, z) ||
|
|
!CheckBounds(x - 2, x + 2, y + trunkH, y + trunkH + 1, z - 2, z + 2) ||
|
|
!CheckBounds(x - 1, x + 1, y + trunkH + 2, y + trunkH + 3, z - 1, z + 1)) {
|
|
game.UpdateBlock(x, y, z, 0);
|
|
return;
|
|
}
|
|
|
|
// Leaves bottom layer
|
|
y += trunkH;
|
|
for (int zz = -2; zz <= 2; zz++) {
|
|
for (int xx = -2; xx <= 2; xx++) {
|
|
if (Math.Abs(xx) == 2 && Math.Abs(zz) == 2) {
|
|
if (rnd.Next(0, 5) < 4) game.UpdateBlock(x + xx, y, z + zz, Block.Leaves);
|
|
if (rnd.Next(0, 5) < 2) game.UpdateBlock(x + xx, y + 1, z + zz, Block.Leaves);
|
|
} else {
|
|
game.UpdateBlock(x + xx, y, z + zz, Block.Leaves);
|
|
game.UpdateBlock(x + xx, y + 1, z + zz, Block.Leaves);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Leaves top layer
|
|
y += 2;
|
|
for (int zz = -1; zz <= 1; zz++) {
|
|
for (int xx = -1; xx <= 1; xx++) {
|
|
if (xx == 0 || zz == 0) {
|
|
game.UpdateBlock(x + xx, y, z + zz, Block.Leaves);
|
|
game.UpdateBlock(x + xx, y + 1, z + zz, Block.Leaves);
|
|
} else if (rnd.Next(0, 5) == 0) {
|
|
game.UpdateBlock(x + xx, y, z + zz, Block.Leaves);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Base trunk
|
|
y -= 2 + trunkH;
|
|
for (int yy = 0; yy < trunkH + 3; yy++)
|
|
game.UpdateBlock(x, y + yy, z, Block.Log);
|
|
}
|
|
|
|
bool CheckBounds(int x1, int x2, int y1, int y2, int z1, int z2) {
|
|
for (int y = y1; y <= y2; y++)
|
|
for (int z = z1; z <= z2; z++)
|
|
for (int x = x1; x <= x2; x++)
|
|
{
|
|
if (!map.IsValidPos(x, y, z)) return false;
|
|
|
|
byte block = map.GetBlock(x, y, z);
|
|
if (!(block == 0 || block == Block.Leaves)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
} |