From d2573b84dd52c06c723953ef66da4af8937a5a53 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Mon, 11 Mar 2013 17:15:34 +0000 Subject: [PATCH] Initial nether composition generator git-svn-id: http://mc-server.googlecode.com/svn/trunk@1266 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Generating/CompoGen.cpp | 98 +++++++++++++++++++++++ source/Generating/CompoGen.h | 28 +++++++ source/Generating/ComposableGenerator.cpp | 4 + source/Protocol/Protocol125.cpp | 4 +- source/Protocol/Protocol132.cpp | 2 +- source/World.cpp | 16 ++++ source/World.h | 20 +++-- 7 files changed, 164 insertions(+), 8 deletions(-) diff --git a/source/Generating/CompoGen.cpp b/source/Generating/CompoGen.cpp index 53d10c674..e1d620ab3 100644 --- a/source/Generating/CompoGen.cpp +++ b/source/Generating/CompoGen.cpp @@ -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); + } +} + + + + diff --git a/source/Generating/CompoGen.h b/source/Generating/CompoGen.h index 39f57735f..e92ba505c 100644 --- a/source/Generating/CompoGen.h +++ b/source/Generating/CompoGen.h @@ -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; +} ; + + + + diff --git a/source/Generating/ComposableGenerator.cpp b/source/Generating/ComposableGenerator.cpp index 793d6a449..0cd6bfb4f 100644 --- a/source/Generating/ComposableGenerator.cpp +++ b/source/Generating/ComposableGenerator.cpp @@ -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) diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index 0b4b0f942..9514fb278 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -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 diff --git a/source/Protocol/Protocol132.cpp b/source/Protocol/Protocol132.cpp index 0c928bde1..e051bcfa1 100644 --- a/source/Protocol/Protocol132.cpp +++ b/source/Protocol/Protocol132.cpp @@ -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 diff --git a/source/World.cpp b/source/World.cpp index 6ff9395c1..70b70d1f1 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -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); diff --git a/source/World.h b/source/World.h index 781dc3e8c..2e8572b00 100644 --- a/source/World.h +++ b/source/World.h @@ -54,12 +54,17 @@ typedef cItemCallback 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;