1
0
Fork 0

Initial nether composition generator

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1266 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2013-03-11 17:15:34 +00:00
parent 9931b5634b
commit d2573b84dd
7 changed files with 164 additions and 8 deletions

View File

@ -425,3 +425,101 @@ void cCompoGenBiomal::FillColumnPattern(int a_RelX, int a_RelZ, int a_Height, cC
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompoGenNether:
cCompoGenNether::cCompoGenNether(int a_Seed) :
m_Noise1(a_Seed + 10),
m_Noise2(a_Seed * a_Seed * 10 + a_Seed * 1000 + 6000),
m_Threshold(0)
{
}
void cCompoGenNether::ComposeTerrain(
int a_ChunkX, int a_ChunkZ,
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
cEntityList & a_Entities, // Entitites may be generated along with the terrain
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
)
{
HEIGHTTYPE MaxHeight = 0;
for (int i = 0; i < ARRAYCOUNT(a_HeightMap); i++)
{
if (a_HeightMap[i] > MaxHeight)
{
MaxHeight = a_HeightMap[i];
}
}
const int SEGMENT_HEIGHT = 8;
const int INTERPOL_X = 16; // Must be a divisor of 16
const int INTERPOL_Z = 16; // Must be a divisor of 16
// Interpolate the chunk in 16 * SEGMENT_HEIGHT * 16 "segments", each 8 blocks high and each linearly interpolated separately.
// Have two buffers, one for the lowest floor and one for the highest floor, so that Y-interpolation can be done between them
// Then swap the buffers and use the previously-top one as the current-bottom, without recalculating it.
int FloorBuf1[17 * 17];
int FloorBuf2[17 * 17];
int * FloorHi = FloorBuf1;
int * FloorLo = FloorBuf2;
int BaseX = a_ChunkX * cChunkDef::Width;
int BaseZ = a_ChunkZ * cChunkDef::Width;
// Interpolate the lowest floor:
for (int z = 0; z <= 16 / INTERPOL_Z; z++) for (int x = 0; x <= 16 / INTERPOL_X; x++)
{
FloorLo[INTERPOL_X * x + 17 * INTERPOL_Z * z] =
m_Noise1.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) *
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
IntArrayLinearInterpolate2D(FloorLo, 17, 17, INTERPOL_X, INTERPOL_Z);
// Interpolate segments:
for (int Segment = 0; Segment < MaxHeight; Segment += SEGMENT_HEIGHT)
{
// First update the high floor:
for (int z = 0; z <= 16 / INTERPOL_Z; z++) for (int x = 0; x <= 16 / INTERPOL_X; x++)
{
FloorHi[INTERPOL_X * x + 17 * INTERPOL_Z * z] =
m_Noise1.IntNoise3DInt(BaseX + INTERPOL_X * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) *
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
IntArrayLinearInterpolate2D(FloorHi, 17, 17, INTERPOL_X, INTERPOL_Z);
// Interpolate between FloorLo and FloorHi:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
{
int Lo = FloorLo[x + 17 * z] / 256;
int Hi = FloorHi[x + 17 * z] / 256;
for (int y = 0; y < SEGMENT_HEIGHT; y++)
{
int Val = Lo + (Hi - Lo) * y / SEGMENT_HEIGHT;
cChunkDef::SetBlock(a_BlockTypes, x, y + Segment, z, (Val < m_Threshold) ? E_BLOCK_NETHERRACK : E_BLOCK_AIR);
}
}
// Swap the floors:
std::swap(FloorLo, FloorHi);
}
// Bedrock at the bottom and at the top:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
{
cChunkDef::SetBlock(a_BlockTypes, x, 0, z, E_BLOCK_BEDROCK);
cChunkDef::SetBlock(a_BlockTypes, x, cChunkDef::GetHeight(a_HeightMap, x, z), z, E_BLOCK_BEDROCK);
}
}

View File

@ -152,3 +152,31 @@ protected:
class cCompoGenNether :
public cTerrainCompositionGen
{
public:
cCompoGenNether(int a_Seed);
protected:
cNoise m_Noise1;
cNoise m_Noise2;
int m_Threshold;
// cTerrainCompositionGen overrides:
virtual void ComposeTerrain(
int a_ChunkX, int a_ChunkZ,
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
cEntityList & a_Entities, // Entitites may be generated along with the terrain
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
) override;
} ;

View File

@ -283,6 +283,10 @@ void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
BlockBeachBottom, BlockSea
);
}
else if (NoCaseCompare(CompoGenName, "nether") == 0)
{
m_CompositionGen = new cCompoGenNether(m_ChunkGenerator.GetSeed());
}
else
{
if (NoCaseCompare(CompoGenName, "biomal") != 0)

View File

@ -461,7 +461,7 @@ void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
WriteString(""); // Username, not used
WriteString("default"); // Level type
WriteInt ((int)a_Player.GetGameMode());
WriteInt (0); // TODO: Dimension (Nether / Overworld / End)
WriteInt ((int)(a_World.GetDimension()));
WriteByte (2); // TODO: Difficulty
WriteByte (0); // Unused
WriteByte (60); // Client list width or something
@ -600,7 +600,7 @@ void cProtocol125::SendRespawn(void)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_RESPAWN);
WriteInt (0); // TODO: Dimension; 0 = Overworld
WriteInt ((int)(m_Client->GetPlayer()->GetWorld()->GetDimension()));
WriteByte (2); // TODO: Difficulty; 2 = Normal
WriteByte ((char)m_Client->GetPlayer()->GetGameMode());
WriteShort (256); // Current world height

View File

@ -326,7 +326,7 @@ void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
WriteInt (a_Player.GetUniqueID()); // EntityID of the player
WriteString("default"); // Level type
WriteByte ((int)a_Player.GetGameMode());
WriteByte (0); // TODO: Dimension (Nether / Overworld / End)
WriteByte ((Byte)(a_World.GetDimension()));
WriteByte (2); // TODO: Difficulty
WriteByte (0); // Unused, used to be world height
WriteByte (8); // Client list width or something

View File

@ -201,6 +201,22 @@ cWorld::cWorld(const AString & a_WorldName) :
cIniFile IniFile(m_IniFileName);
IniFile.ReadFile();
m_Dimension = (eDimension)(IniFile.GetValueSetI("General", "Dimension", 0));
switch (m_Dimension)
{
case dimNether:
case dimOverworld:
case dimEnd:
{
break;
}
default:
{
LOGWARNING("Unknown dimension: %d. Setting to Overworld (0)", m_Dimension);
m_Dimension = dimOverworld;
break;
}
} // switch (m_Dimension)
m_SpawnX = IniFile.GetValueSetF("SpawnPosition", "X", m_SpawnX);
m_SpawnY = IniFile.GetValueSetF("SpawnPosition", "Y", m_SpawnY);
m_SpawnZ = IniFile.GetValueSetF("SpawnPosition", "Z", m_SpawnZ);

View File

@ -54,12 +54,17 @@ typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
class cWorld // tolua_export
{ // tolua_export
// tolua_begin
class cWorld
{
public:
// tolua_begin
enum eDimension
{
dimNether = -1,
dimOverworld = 0,
dimEnd = 1,
} ;
static const char * GetClassStatic(void)
{
@ -92,6 +97,8 @@ public:
eGameMode GetGameMode(void) const { return m_GameMode; }
bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }
eDimension GetDimension(void) const { return m_Dimension; }
int GetHeight(int a_BlockX, int a_BlockZ);
@ -459,7 +466,10 @@ private:
friend class cRoot;
// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
/// The dimension of the world, used by the client to provide correct lighting scheme
eDimension m_Dimension;
/// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
MTRand m_TickRand;
double m_SpawnX;