Various Refactors
This commit is contained in:
@@ -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);
|
||||
};
|
||||
}
|
@@ -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() {
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -7,6 +7,7 @@ namespace CaveGame::Core
|
||||
{
|
||||
using TileState = uint16_t;
|
||||
|
||||
/// A b
|
||||
class ITileMap
|
||||
{
|
||||
public:
|
||||
|
@@ -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:
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user