summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Generating/CMakeLists.txt2
-rw-r--r--src/Generating/ComposableGenerator.cpp16
-rw-r--r--src/Generating/EnderDragonFightStructuresGen.cpp285
-rw-r--r--src/Generating/EnderDragonFightStructuresGen.h38
4 files changed, 340 insertions, 1 deletions
diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt
index bf539d6c2..e299c97d7 100644
--- a/src/Generating/CMakeLists.txt
+++ b/src/Generating/CMakeLists.txt
@@ -11,6 +11,7 @@ target_sources(
DistortedHeightmap.cpp
DungeonRoomsFinisher.cpp
EndGen.cpp
+ EnderDragonFightStructuresGen.cpp
FinishGen.cpp
GridStructGen.cpp
HeiGen.cpp
@@ -43,6 +44,7 @@ target_sources(
DistortedHeightmap.h
DungeonRoomsFinisher.h
EndGen.h
+ EnderDragonFightStructuresGen.h
FinishGen.h
GridStructGen.h
HeiGen.h
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index d5c64e4c4..9b170ecc8 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -23,6 +23,7 @@
#include "DistortedHeightmap.h"
#include "DungeonRoomsFinisher.h"
#include "EndGen.h"
+#include "EnderDragonFightStructuresGen.h"
#include "MineShafts.h"
#include "Noise3DGenerator.h"
#include "Ravines.h"
@@ -262,7 +263,7 @@ void cComposableGenerator::InitializeGeneratorDefaults(cIniFile & a_IniFile, eDi
a_IniFile.GetValueSet("Generator", "ConstantBiome", "End");
a_IniFile.GetValueSet("Generator", "ShapeGen", "End");
a_IniFile.GetValueSet("Generator", "CompositionGen", "End");
- a_IniFile.GetValueSet("Generator", "Finishers", "");
+ a_IniFile.GetValueSet("Generator", "Finishers", "EnderDragonFightStructures");
break;
} // dimEnd
@@ -450,6 +451,19 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
m_FinishGens.push_back(std::make_unique<cDungeonRoomsFinisher>(*m_ShapeGen, m_Seed, GridSize, MaxSize, MinSize, HeightDistrib));
}
+ else if (NoCaseCompare(finisher, "EnderDragonFightStructures") == 0)
+ {
+ AString Pillars = a_IniFile.GetValueSet("Generator", "ObsidianPillars",
+ "76|3|false; 79|3|true; 82|3|true; "
+ "85|4|false; 88|4|false; 91|4|false; "
+ "94|5|false; 97|5|false; 100|5|false; "
+ "103|6|false");
+ int Radius = a_IniFile.GetValueSetI("Generator", "ObsidianPillarsRadius", 43);
+ // The init method is called manually because the linker can't access the cChunkDef::Width in the constructor
+ auto Gen = new cEnderDragonFightStructuresGen(m_Seed);
+ Gen->Init(Pillars, Radius);
+ m_FinishGens.push_back(cFinishGenPtr(Gen));
+ }
else if (NoCaseCompare(finisher, "GlowStone") == 0)
{
m_FinishGens.push_back(std::make_unique<cFinishGenGlowStone>(m_Seed));
diff --git a/src/Generating/EnderDragonFightStructuresGen.cpp b/src/Generating/EnderDragonFightStructuresGen.cpp
new file mode 100644
index 000000000..8e6bf30ce
--- /dev/null
+++ b/src/Generating/EnderDragonFightStructuresGen.cpp
@@ -0,0 +1,285 @@
+
+#include "Globals.h"
+
+#include "EnderDragonFightStructuresGen.h"
+#include "../Chunk.h"
+#include "../Entities/EnderCrystal.h"
+#include "../WorldStorage/SchematicFileSerializer.h"
+
+const std::array<Vector3i, 48> cEnderDragonFightStructuresGen::m_CagePos =
+{
+ {
+ // First layer
+ {-2, -1, -2}, {-2, -1, -1}, {-2, -1, 0}, {-2, -1, 1}, {-2, -1, 2},
+ {2, -1, -2}, {2, -1, -1}, {2, -1, 0}, {2, -1, 1}, {2, -1, 2},
+ {-1, -1, -2}, {0, -1, -2}, {1, -1, -2},
+ {-1, -1, 2}, {0, -1, 2}, {1, -1, 2},
+
+ // Second layer
+ {-2, 0, -2}, {-2, 0, -1}, {-2, 0, 0}, {-2, 0, 1}, {-2, 0, 2},
+ {2, 0, -2}, {2, 0, -1}, {2, 0, 0}, {2, 0, 1}, {2, 0, 2},
+ {-1, 0, -2}, {0, 0, -2}, {1, 0, -2},
+ {-1, 0, 2}, {0, 0, 2}, {1, 0, 2},
+
+ // Third layer
+ {-2, 1, -2}, {-2, 1, -1}, {-2, 1, 0}, {-2, 1, 1}, {-2, 1, 2},
+ {2, 1, -2}, {2, 1, -1}, {2, 1, 0}, {2, 1, 1}, {2, 1, 2},
+ {-1, 1, -2}, {0, 1, -2}, {1, 1, -2},
+ {-1, 1, 2}, {0, 1, 2}, {1, 1, 2},
+ }
+};
+
+
+
+
+
+const std::array<Vector3i, 26> cEnderDragonFightStructuresGen::m_CageAir =
+{
+ {
+ // First layer
+ {-1, -1, -1}, {0, -1, -1}, {1, -1, -1},
+ {-1, -1, 1}, {0, -1, 1}, {1, -1, 1},
+ {-1, -1, 0}, {1, -1, 0},
+
+ // Second layer
+ {-1, 0, -1}, {0, 0, -1}, {1, 0, -1},
+ {-1, 0, 1}, {0, 0, 1}, {1, 0, 1},
+ {-1, 0, 0}, {1, 0, 0}, {0, 0, 0},
+
+ // Third layer
+ {-1, 1, -1}, {0, 1, -1}, {1, 1, -1},
+ {-1, 1, 1}, {0, 1, 1}, {1, 1, 1},
+ {-1, 1, 0}, {1, 1, 0}, {0, 1, 0},
+ }
+};
+
+
+
+
+
+cEnderDragonFightStructuresGen::cEnderDragonFightStructuresGen(int a_Seed) :
+ m_Noise(a_Seed)
+{
+}
+
+
+
+
+
+void cEnderDragonFightStructuresGen::Init(const AString & a_TowerProperties, int a_Radius)
+{
+ const auto ChunkWidth = cChunkDef::Width;
+ // Loads the fountain schematic
+ if (!cFile::IsFile(AString("Prefabs") + cFile::GetPathSeparator() + "SinglePieceStructures" + cFile::GetPathSeparator() + "EndFountain.schematic"))
+ {
+ LOGWARNING("EnderDragonFightStructuresGen is missing its end fountain prefab, please update your Cuberite server files! There will be no end fountain!");
+ }
+ else
+ {
+ cSchematicFileSerializer::LoadFromSchematicFile(m_Fountain, AString("Prefabs") + cFile::GetPathSeparator() + "SinglePieceStructures" + cFile::GetPathSeparator() + "EndFountain.schematic");
+ }
+
+ // Reads the given tower properties
+ const auto TowerPropertiesVector = StringSplitAndTrim(a_TowerProperties, ";");
+ std::vector<sTowerProperties> TowerProperties;
+ for (const auto & TowerProperty : TowerPropertiesVector)
+ {
+ const auto TowerPropertyVector = StringSplitAndTrim(TowerProperty, "|");
+ if (TowerPropertyVector.size() != 3)
+ {
+ LOGWARNING("Got unknown parameters on generating obsidian pillars: %s, Please use \"Height|Radius|HasCage\"; ...", TowerProperty);
+ continue;
+ }
+ int Height = std::min(std::stoi(TowerPropertyVector[0]), cChunkDef::Height - 2); // The highest block placed is two blocks above the given height (the cage above some towers)
+ int Radius = std::stoi(TowerPropertyVector[1]);
+ bool HasCage;
+ if (NoCaseCompare(TowerPropertyVector[2], "true") == 0)
+ {
+ HasCage = true;
+ }
+ else if (NoCaseCompare(TowerPropertyVector[2], "false") == 0)
+ {
+ HasCage = false;
+ }
+ else
+ {
+ LOGWARNING("Got unknown value for boolean of the tower: %s should have a cage! %s. Tower will not be generated!", TowerProperty, TowerPropertyVector[2]);
+ continue;
+ }
+ TowerProperties.push_back({Vector3d(), Height, Radius, HasCage});
+ }
+ // A random angle in radian
+ double Angle = m_Noise.IntNoise1D(m_Noise.GetSeed()) * M_PI + M_PI;
+ // Shuffles the order of the towers
+ std::shuffle(TowerProperties.begin(), TowerProperties.end(), std::default_random_engine(static_cast<size_t>(m_Noise.GetSeed())));
+ // Generate Positions in a circle
+ for (size_t I = 0; I < TowerProperties.size(); I++)
+ {
+ auto TowerPos = Vector3i(FloorC(a_Radius * cos(Angle)), 0, FloorC(a_Radius * sin(Angle)));
+ TowerProperties[I].m_Pos = TowerPos;
+
+ // Check all crossed chunks
+ for (int X = -TowerProperties[I].m_Radius - ChunkWidth; X <= TowerProperties[I].m_Radius + ChunkWidth; X+=std::min(TowerProperties[I].m_Radius, ChunkWidth))
+ {
+ for (int Z = -TowerProperties[I].m_Radius - ChunkWidth; Z <= TowerProperties[I].m_Radius + ChunkWidth; Z+=std::min(TowerProperties[I].m_Radius, ChunkWidth))
+ {
+ auto Chunk = cChunkDef::BlockToChunk({TowerPos.x + X, 0, TowerPos.z + Z});
+ // Update limits
+ m_MinX = std::min(Chunk.m_ChunkX, m_MinX);
+ m_MinZ = std::min(Chunk.m_ChunkZ, m_MinZ);
+
+ m_MaxX = std::max(Chunk.m_ChunkX, m_MaxX);
+ m_MaxZ = std::max(Chunk.m_ChunkZ, m_MaxZ);
+ // If the tower is not in chunk put it in
+ bool ShouldPlace = true;
+ for (const auto & Property : m_TowerPos[Chunk])
+ {
+ ShouldPlace &= !(TowerPos == Property.m_Pos);
+ }
+ if (ShouldPlace)
+ {
+ m_TowerPos[Chunk].emplace_back(TowerProperties[I]);
+ }
+ }
+ }
+ // Generate angle of next tower
+ Angle = fmod(Angle + (2.0 * M_PI / static_cast<double>(TowerProperties.size())), 2.0 * M_PI);
+ }
+}
+
+
+
+
+
+void cEnderDragonFightStructuresGen::GenFinish(cChunkDesc &a_ChunkDesc)
+{
+ auto Coords = a_ChunkDesc.GetChunkCoords();
+ // If not in the chunks to write
+ if ((Coords.m_ChunkX > m_MaxX) ||
+ (Coords.m_ChunkX < m_MinX) ||
+ (Coords.m_ChunkZ > m_MaxZ) ||
+ (Coords.m_ChunkZ < m_MinZ))
+ {
+ return;
+ }
+ // Places the exit portal
+ if (Coords == cChunkCoords({0, 0}))
+ {
+ /*
+ auto EnderDragon = std::make_unique<cEnderDragon>();
+ EnderDragon->SetPosition({0.0, static_cast<double>(a_ChunkDesc.GetHeight(0, 0) + 20), 0.0}); // Spawns the dragon 20 blocks above the terrain at (0, 0)
+ a_ChunkDesc.GetEntities().emplace_back(std::move(EnderDragon));
+ */ // Todo: 25.10.20 - Add the ender dragon spawning when the dragon behaves properly - 12xx12
+ a_ChunkDesc.WriteBlockArea(m_Fountain,
+ static_cast<int>(FloorC(-m_Fountain.GetSizeX() / 2)),
+ 62,
+ static_cast<int>(FloorC(-m_Fountain.GetSizeX() / 2)),
+ cBlockArea::msSpongePrint
+ );
+ }
+ else if (Coords == cChunkCoords({-1, 0}))
+ {
+ a_ChunkDesc.WriteBlockArea(m_Fountain,
+ cChunkDef::Width - static_cast<int>(FloorC(m_Fountain.GetSizeX() / 2)),
+ 62,
+ static_cast<int>(FloorC(-m_Fountain.GetSizeZ() / 2)),
+ cBlockArea::msSpongePrint
+ );
+ }
+ else if (Coords == cChunkCoords({0, -1}))
+ {
+ a_ChunkDesc.WriteBlockArea(m_Fountain,
+ static_cast<int>(FloorC(-m_Fountain.GetSizeX() / 2)),
+ 62,
+ cChunkDef::Width - static_cast<int>(FloorC(m_Fountain.GetSizeZ() / 2)),
+ cBlockArea::msSpongePrint);
+ }
+ else if (Coords == cChunkCoords({-1, -1}))
+ {
+ a_ChunkDesc.WriteBlockArea(m_Fountain,
+ cChunkDef::Width - static_cast<int>(FloorC(m_Fountain.GetSizeX() / 2)),
+ 62,
+ cChunkDef::Width - static_cast<int>(FloorC(m_Fountain.GetSizeZ() / 2)),
+ cBlockArea::msSpongePrint);
+ }
+ auto It = m_TowerPos.find(Coords);
+ if (It == m_TowerPos.end())
+ {
+ return;
+ }
+ for (const auto & Property : It->second)
+ {
+ PlaceTower(a_ChunkDesc, Property);
+ }
+}
+
+
+
+
+
+void cEnderDragonFightStructuresGen::PlaceTower(cChunkDesc &a_ChunkDesc, const sTowerProperties & a_Properties)
+{
+ auto Pos = cChunkDef::AbsoluteToRelative(a_Properties.m_Pos, a_ChunkDesc.GetChunkCoords());
+ // Place obsidian pillar
+ for (int X = -a_Properties.m_Radius; X < a_Properties.m_Radius; X++)
+ {
+ for (int Z = -a_Properties.m_Radius; Z < a_Properties.m_Radius; Z++)
+ {
+ Vector3i NewPos = {Pos.x + X, 1, Pos.z + Z};
+ if (cChunkDef::IsValidRelPos(NewPos))
+ {
+ // The 3 was achieved by trial and error till the shape matched the notchian implementation
+ if ((NewPos - Vector3i(Pos.x, 1, Pos.z)).SqrLength() < a_Properties.m_Radius * a_Properties.m_Radius - 3)
+ {
+ for (int Y = 0; Y <= a_Properties.m_Height - 2; Y++)
+ {
+ a_ChunkDesc.SetBlockType(NewPos.x, Y, NewPos.z, E_BLOCK_OBSIDIAN);
+ }
+ }
+ }
+ }
+ }
+
+ // Spawn the iron bars if there are some
+ if (a_Properties.m_HasCage)
+ {
+ // Place walls
+ for (const auto & Offset : m_CagePos)
+ {
+ if (cChunkDef::IsValidRelPos(Vector3d(Pos.x, a_Properties.m_Height, Pos.z) + Offset))
+ {
+ a_ChunkDesc.SetBlockType(Pos.x + Offset.x, a_Properties.m_Height + Offset.y, Pos.z + Offset.z, E_BLOCK_IRON_BARS);
+ }
+ }
+ // Remove any block that may generate inside the cage
+ for (const auto & Offset : m_CageAir)
+ {
+ if (cChunkDef::IsValidRelPos(Pos + Offset))
+ {
+ a_ChunkDesc.SetBlockType(Pos.x + Offset.x, a_Properties.m_Height + Offset.y, Pos.z + Offset.z, E_BLOCK_AIR);
+ }
+ }
+ // Place roof
+ for (int X = -2; X <= 2; ++X)
+ {
+ for (int Z = -2; Z <= 2; ++Z)
+ {
+ if (cChunkDef::IsValidRelPos({Pos.x + X, 1, Pos.z + Z}))
+ {
+ a_ChunkDesc.SetBlockType(Pos.x + X, a_Properties.m_Height + 2, Pos.z + Z, E_BLOCK_IRON_BARS);
+ }
+ }
+ }
+ }
+ // Place the top decoration if the origin is in this chunk
+ if (cChunkDef::IsValidRelPos(Pos))
+ {
+ // Spawn the bedrock
+ a_ChunkDesc.SetBlockType(Pos.x, a_Properties.m_Height - 1, Pos.z, E_BLOCK_BEDROCK);
+ // Spawn the fire
+ a_ChunkDesc.SetBlockType(Pos.x, a_Properties.m_Height, Pos.z, E_BLOCK_FIRE);
+ // Spawn the ender crystal of the origin position is in this chunk
+ auto EnderCrystal = std::make_unique<cEnderCrystal>(Vector3d(0.5, a_Properties.m_Height, 0.5) + a_Properties.m_Pos, true);
+ a_ChunkDesc.GetEntities().emplace_back(std::move(EnderCrystal));
+ }
+}
diff --git a/src/Generating/EnderDragonFightStructuresGen.h b/src/Generating/EnderDragonFightStructuresGen.h
new file mode 100644
index 000000000..be6b2506e
--- /dev/null
+++ b/src/Generating/EnderDragonFightStructuresGen.h
@@ -0,0 +1,38 @@
+
+#pragma once
+
+/*
+https://minecraft.gamepedia.com/End_spike
+https://minecraft.gamepedia.com/End_Crystal
+https://minecraft.gamepedia.com/Ender_Dragon
+*/
+
+#include "FinishGen.h"
+
+class cEnderDragonFightStructuresGen :
+ public cFinishGen
+{
+public:
+ cEnderDragonFightStructuresGen(int a_Seed);
+ void Init(const AString & a_TowerProperties, int a_Radius);
+
+protected:
+ struct sTowerProperties
+ {
+ Vector3i m_Pos;
+ int m_Height;
+ int m_Radius;
+ bool m_HasCage;
+ };
+
+ cNoise m_Noise;
+ std::map<cChunkCoords, std::vector<sTowerProperties>> m_TowerPos;
+ static const std::array<Vector3i, 48> m_CagePos;
+ static const std::array<Vector3i, 26> m_CageAir;
+ cBlockArea m_Fountain;
+
+ int m_MinX = -1, m_MaxX = 1, m_MinZ = -1, m_MaxZ = 1;
+
+ void GenFinish(cChunkDesc &a_ChunkDesc) override;
+ void PlaceTower(cChunkDesc & a_ChunkDesc, const sTowerProperties & a_TowerProperties);
+};