Various Refactors

This commit is contained in:
2025-01-03 00:22:43 -05:00
parent 2ee33d4575
commit 57ceb8adce
7 changed files with 133 additions and 91 deletions

View File

@@ -20,15 +20,11 @@ namespace CaveGame::Client
};
/// An extension of the world object that provides rendering for the game world.
class LocalWorld : public CaveGame::Core::World
{
public:
Camera2D camera;
std::thread chunk_thread;
std::atomic<bool> run_chunk_thread = true;
ConcurrentQueue<Vector2> RequestedChunks;
std::vector<Vector2> chunks_in_waiting;
ConcurrentQueue<Core::Chunk> ServedChunks;
Vector2 mouse_pos;
public:
JGL::Font font;
@@ -52,11 +48,6 @@ namespace CaveGame::Client
void LookForChunksNeedLoading();
void LookForChunksNeedUnloading();
void RequestChunk(const Vector2& cell);
void ChunkServerThread();
void RenderChunkTexture(const Vector2 &coords, JGL::RenderTarget* destination, const Core::Chunk& chunk);
/// Render chunk boundaries and relative coordinates, around the camera.
@@ -69,7 +60,5 @@ namespace CaveGame::Client
static Color4 GetSkyColorBaseForTimeOfDay(float time);
void DrawSky();
bool AwaitingChunkAtCell(const Vector2 &cell);
};
}

View File

@@ -285,21 +285,6 @@ namespace CaveGame::Client {
}
}
bool LocalWorld::AwaitingChunkAtCell(const Vector2& cell)
{
int cnt = std::count(chunks_in_waiting.begin(), chunks_in_waiting.end(), cell);
if (cnt > 1)
{
// Not good.
std::cerr << "Fuckiddy fuck" << std::endl;
return false;
}
if (cnt == 1)
return true;
return false;
}
void LocalWorld::LookForChunksNeedLoading()
{
@@ -357,40 +342,7 @@ namespace CaveGame::Client {
}
}
void LocalWorld::RequestChunk(const Vector2 &cell) {
// TODO: Ensure we cannot request the same chunk twice..
if (std::find(chunks_in_waiting.begin(), chunks_in_waiting.end(), cell) == chunks_in_waiting.end())
{
RequestedChunks.push(cell);
chunks_in_waiting.push_back(cell);
}
}
void LocalWorld::ChunkServerThread() {
while (run_chunk_thread)
{
while (!RequestedChunks.empty())
{
Vector2 cell;
RequestedChunks.front_pop(cell);
if (HasChunkOnFile(cell)) {
ServedChunks.emplace(Core::Chunk(cell, GetChunkFullPath(cell)));
} else {
Core::Chunk chunk(cell);
generator.FirstPass(chunk);
//SaveChunkToFile(cell, chunk);
ServedChunks.emplace(chunk);
}
//generator.FirstPass()
//std::this_thread::sleep_for(100ms);
}
//std::this_thread::sleep_for(250ns);
}
}
void LocalWorld::RefreshAll() {

View File

@@ -1,5 +1,7 @@
#include <Client/CreditsWindow.hpp>
#include "ClientApp/CaveGameWindow.hpp"
#include <bits/random.h>
#include <Core/Loggers.hpp>
#include <rewindow/inputservice.hpp>
@@ -193,9 +195,6 @@ namespace CaveGame::ClientApp
game_ctx->world->camera.ZoomIn(elapsed);
*/
if (IsKeyDown(Keys::R))
game_ctx->world->RefreshAll();
if (IsMouseButtonDown(MouseButtons::Left))
{
@@ -279,6 +278,7 @@ namespace CaveGame::ClientApp
debug_lines.push_back(std::format("tile: {} id: {}", data->MnemonicID(), (uint)data->NumericID()));
debug_lines.push_back(std::format("entities: {}", game_ctx->world->GetCurrentEntityCount()));
debug_lines.push_back(std::format("tile_simulation: {}", game_ctx->world->GetTileSimulationEnabled()));
}
draw_debug_info(debug_lines);
@@ -315,22 +315,31 @@ namespace CaveGame::ClientApp
void CaveGameWindow::OnKeyDown(const ReWindow::KeyDownEvent &ev) {
if (ev.key == Keys::Escape)
if (current_scene == game_ctx) {
if (current_scene == game_ctx) {
if (ev.key == Keys::F5)
game_ctx->world->RefreshAll();
if (ev.key == Keys::F7)
game_ctx->world->SetTileSimulationEnabled(!game_ctx->world->GetTileSimulationEnabled());
if (ev.key == Keys::F6) {
std::srand(std::time(nullptr));
game_ctx->world->SetSeed(std::rand());
}
if (ev.key == Keys::Escape) {
game_ctx->SaveAndExit();
ChangeScene(menu_ctx);
}
if (ev.key == Keys::P) {
if (current_scene == game_ctx) {
if (ev.key == Keys::P) {
auto coords = game_ctx->world->camera.ScreenToWorld(InputService::GetMousePosition());
auto* plr = new Core::Player(coords);
game_ctx->world->AddEntity(plr);
}
}
if (current_scene != nullptr)
current_scene->PassKeyInput(ev.key, true);

View File

@@ -132,9 +132,12 @@ namespace CaveGame::Core
#pragma endregion
public:
Generator() = default;
//Generator() = default;
explicit Generator(int seed);
int GetSeed() const { return seed;}
void SetSeed(int newSeed) { seed = newSeed; }
TileID HeightMap(float depth, int wx, int wy);
float Perlin(int wx, int wy, float hScale, float vScale, float offset, float outputScale);

View File

@@ -7,6 +7,7 @@ namespace CaveGame::Core
{
using TileState = uint16_t;
/// A b
class ITileMap
{
public:

View File

@@ -6,7 +6,7 @@
#include <unordered_map>
#include <filesystem>
#include <future>
#include "ConcurrentQueue.hpp"
#include "Entity.hpp"
@@ -32,6 +32,7 @@ namespace CaveGame::Core
};
/// The world class manages and coordinates terrain generation, chunk file IO, thread synchronization, and entity logic.
class World : public ITileMap {
public:
constexpr static uint RandomTileTickCoefficient = 100;
@@ -45,6 +46,18 @@ namespace CaveGame::Core
void SetTile(int x, int y, TileID t) override;
bool GetTileSimulationEnabled() const;
void SetTileSimulationEnabled(bool enabled);
int GetSeed() const {
return generator.GetSeed();
}
void SetSeed(int seed) {
generator.SetSeed(seed);
}
TileState GetTileState(int x, int y) const override { return 0; /* TODO: Implement tile state field */ }
void SetTileState(int x, int y, TileState state) override { /* TODO: Implement tile state field */ }
@@ -72,6 +85,7 @@ namespace CaveGame::Core
virtual void AutoSave();
/// Gracefully saves all game state and closes the play session.
virtual void SaveAndExit();
/// Returns whether or not the world currently has a chunk loaded at the specified chunk coordinates.
@@ -80,32 +94,26 @@ namespace CaveGame::Core
bool HasChunkOnFile(const Vector2 &cell) const;
bool AwaitingChunkAtCell(const Vector2 &cell);
void ChunkServerThread();
std::filesystem::path GetWorldRootPath() const;
std::filesystem::path GetChunkFullPath(const Vector2 &cell) const;
template <typename TEntity, class ... Args>
TEntity* AddNewEntity(Args&&... ctor_args)
{
// TODO: Does emplace_back construct the correct derived entity?
return entities.emplace_back(std::forward<Args>(ctor_args)...);
}
/// Adds the entity pointer to the world, via std::move, this may leave the original entity pointer empty.
///
void AddEntity(Entity* e)
{
entities.push_back(std::move(e));
}
void AddEntity(Entity* e);
void AddEntity(Entity& e)
{
entities.push_back(std::move(&e));
}
unsigned int GetCurrentEntityCount() const {
return entities.size();
}
/// Returns the number of extant entities in this world right now.
unsigned int GetCurrentEntityCount() const;
/// Marks that the chunk at the given cell coordinates is needed.
/// This will be picked up by the generator thread, and either generated, or loaded from disk.
void RequestChunk(const Vector2& cell);
void DropChunk(const Vector2& cell);
protected:
void SaveChunkToFile(const Vector2 &cell, const Chunk &chunk);
@@ -120,6 +128,12 @@ namespace CaveGame::Core
std::string world_name;
RNG rng;
float autosave_timer = 0.f;
bool simulate_tiles = true;
std::thread chunk_thread;
std::atomic<bool> run_chunk_thread = true;
ConcurrentQueue<Vector2> RequestedChunks;
std::vector<Vector2> chunks_in_waiting;
ConcurrentQueue<Core::Chunk> ServedChunks;
private:

View File

@@ -24,8 +24,10 @@ namespace CaveGame::Core
autosave_timer = 0;
}
DoRandomTileTicks();
DoForcedTileTicks();
if (simulate_tiles) {
DoRandomTileTicks();
DoForcedTileTicks();
}
for (auto* entity : entities) {
entity->Update(elapsed);
@@ -85,6 +87,12 @@ namespace CaveGame::Core
}
bool World::GetTileSimulationEnabled() const { return simulate_tiles; }
void World::SetTileSimulationEnabled(bool enabled) {
simulate_tiles = enabled;
}
Chunk World::GetChunkAtCell(const Vector2 &cell) {
if (ValidCoords(cell))
return loaded_chunks.at(cell);
@@ -231,6 +239,60 @@ namespace CaveGame::Core
}
}
void World::ChunkServerThread() {
while (run_chunk_thread)
{
while (!RequestedChunks.empty())
{
Vector2 cell;
RequestedChunks.front_pop(cell);
if (HasChunkOnFile(cell)) {
ServedChunks.emplace(Core::Chunk(cell, GetChunkFullPath(cell)));
} else {
Core::Chunk chunk(cell);
generator.FirstPass(chunk);
//SaveChunkToFile(cell, chunk);
ServedChunks.emplace(chunk);
}
//generator.FirstPass()
//std::this_thread::sleep_for(100ms);
}
//std::this_thread::sleep_for(250ns);
}
}
unsigned int World::GetCurrentEntityCount() const {
return entities.size();
}
void World::RequestChunk(const Vector2 &cell) {
// TODO: Ensure we cannot request the same chunk twice..
if (std::find(chunks_in_waiting.begin(), chunks_in_waiting.end(), cell) == chunks_in_waiting.end())
{
RequestedChunks.push(cell);
chunks_in_waiting.push_back(cell);
}
}
bool World::AwaitingChunkAtCell(const Vector2& cell)
{
int cnt = std::count(chunks_in_waiting.begin(), chunks_in_waiting.end(), cell);
if (cnt > 1)
{
// Not good.
std::cerr << "Fuckiddy fuck" << std::endl;
return false;
}
if (cnt == 1)
return true;
return false;
}
bool World::HasChunkOnFile(const Vector2 &cell) const {
return std::filesystem::exists(worlds/world_name/"chunks"/cell.ToString());
}
@@ -245,6 +307,10 @@ namespace CaveGame::Core
return GetWorldRootPath()/"chunks"/cell.ToString();
}
void World::AddEntity(Entity *e) {
entities.push_back(std::move(e));
}
void World::SaveChunkToFile(const Vector2& cell, const Chunk& chunk)
{
std::ofstream fout;
@@ -255,6 +321,14 @@ namespace CaveGame::Core
}
void World::RefreshAll() {
namespace fs = std::filesystem;
fs::path current_world_path = worlds/world_name;
if (fs::exists(current_world_path))
fs::remove_all(current_world_path);
loaded_chunks.clear();
}