Hacked in AssetService to the splash screen, still needs some polish.

This commit is contained in:
2025-03-02 04:26:50 -05:00
parent 4a11961c0f
commit 0b9c5eb449
10 changed files with 269 additions and 57 deletions

View File

@@ -20,8 +20,8 @@ set(CMAKE_CXX_STANDARD 20)
if (UNIX)
# TODO: Enable ALL optimization flags for RELEASE builds.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -floop-nest-optimize -funroll-loops")
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -floop-nest-optimize -funroll-loops")
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

View File

@@ -20,18 +20,20 @@
#include <iostream>
#include <JGL/types/Texture.h>
#include <JGL/types/Font.h>
#include <queue>
namespace CaveGame::Client
{
using namespace JGL;
enum AssetType { DATA, TEXT, AUDIO, MODEL, TEXTURE, FONT, SHADER };
enum AssetLifestyle { STATIC, STREAMED};
struct Asset {
std::string name;
std::string metadata;
std::string type;
struct AssetRequest {
std::filesystem::path path;
AssetType type;
};
class AssetService {
@@ -41,9 +43,9 @@ namespace CaveGame::Client
static AssetService* Get();
JGL::Texture* player_sprite;
JGL::Texture* explosion_sprite;
JGL::Texture* title_img;
JGL::Texture *player_sprite;
JGL::Texture *explosion_sprite;
JGL::Texture *title_img;
AssetService();
@@ -51,36 +53,50 @@ namespace CaveGame::Client
void TempLoadSimple();
/// Performs one "Load Cycle" on the current thread. This means we will attempt to load a number of queued items until we've spent at least maxTTL seconds.
void LoadCycle(float maxTTL = 1e-3f);
unsigned int TotalAssetsQueued() const;
unsigned int TotalAssetsLoaded() const;
unsigned int AssetsToBeLoaded() const;
JGL::Texture* GetTexture(const std::string& textureName) {
std::shared_ptr<Texture> GetTexture(const std::string &textureName) {
return textures[textureName];
}
JGL::Font* GetFont(const std::string& fontName) {
return fonts[fontName];
std::shared_ptr<JGL::Font> GetFont(const std::string &fontName) {
//return fonts[fontName];
}
void EnqueueTexture(const std::string& texName);
void EnqueueFont(const std::string& fontName);
void EnqueueTexture(const std::filesystem::path &path);
void EnqueueFont(const std::filesystem::path& path);
void EnqueueSound(const std::filesystem::path& path);
void LoadAllFromQueue();
/// Performs one "Load Cycle" on the current thread. This means we will attempt to load a number of queued items until we've spent at least maxTTL seconds.
bool LoadFromQueue(float maxTimeExpenditure = 1e-3f);
bool LoadAsset(const AssetRequest& request);
bool IsLoadComplete() const { return queue.empty(); }
void EnqueueDefaultAssetsFolder();
std::string LastAsset() const { return last_asset_processed; }
void EnqueueContents(const std::filesystem::path& folder) {
for (const auto& entry : std::filesystem::recursive_directory_iterator(folder)) {
if (entry.is_regular_file()) {
std::cout << entry << std::endl;
}
}
}
unsigned int TotalQueued() const { return total_queued; }
unsigned int TotalLoaded() const { return total_loaded; }
protected:
std::unordered_map<std::string, JGL::Font*> fonts;
std::unordered_map<std::string, JGL::Texture*> textures;
/// @returns only the filename of the given path.
static std::string FilenameFromPath(const std::filesystem::path& path);
/// @returns only the filename, without a file extension, of the given path.
static std::string FilenameFromPathWithoutExtension(const std::filesystem::path& path);
protected:
std::unordered_map<std::string, std::shared_ptr<Font>> fonts;
std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
std::queue<AssetRequest> queue;
std::string last_asset_processed;
unsigned int total_queued = 0;
unsigned int total_loaded = 0;
};
}

View File

@@ -120,5 +120,7 @@ namespace CaveGame::Client {
void WorldEditToolDrawTiles(int x, int y, int radius, int density, TileID tile);
void WorldEditToolDrawOverlay();
Vector2 MouseWorldPos();
};
}

View File

@@ -1,6 +1,7 @@
#include <Client/AssetService.hpp>
#include <thread>
#include <JGL/types/Texture.h>
using namespace std::chrono_literals;
static CaveGame::Client::AssetService* singleton;
@@ -22,3 +23,89 @@ void CaveGame::Client::AssetService::EnqueueDefaultAssetsFolder() {
textures.emplace("player", new JGL::Texture("assets/textures/player.png"));
}
std::string CaveGame::Client::AssetService::FilenameFromPath(const std::filesystem::path &path) {
return path.string().substr(path.string().find_last_of("/\\") + 1);
}
std::string CaveGame::Client::AssetService::FilenameFromPathWithoutExtension(const std::filesystem::path &path) {
auto base = path.string().substr(path.string().find_last_of("/\\") + 1);
std::string::size_type const p(base.find_last_of('.'));
return base.substr(0, p);
}
void CaveGame::Client::AssetService::EnqueueTexture(const std::filesystem::path &path) {
queue.push({path, AssetType::TEXTURE});
total_queued++;
}
void CaveGame::Client::AssetService::EnqueueFont(const std::filesystem::path &path) {
queue.push({path, AssetType::FONT});
total_queued++;
}
void CaveGame::Client::AssetService::EnqueueSound(const std::filesystem::path &path) {
queue.push({path, AssetType::AUDIO});
total_queued++;
}
bool CaveGame::Client::AssetService::LoadAsset(const CaveGame::Client::AssetRequest &request) {
last_asset_processed = request.path;
switch(request.type) {
case AssetType::TEXTURE: {
auto texture =std::make_shared<Texture>(request.path);
textures[request.path] = texture;
}
default: {
// TODO: We don't support this asset type yet!!!
}
}
last_asset_processed = request.path; //FilenameFromPath(request.path);
total_loaded++;
return true;
}
bool CaveGame::Client::AssetService::LoadFromQueue(float maxTimeExpenditure) {
using fsec = std::chrono::duration<float>;
using clock = std::chrono::high_resolution_clock;
if (queue.empty())
return true;
auto start = clock::now();
//while (!queue.empty() && maxTimeExpenditure > 0.f)
//{
AssetRequest request = queue.front();
queue.pop();
if (!LoadAsset(request))
{
std::cerr << "bruh" << std::endl;
// Failed to load!!!
}
auto cur_time = clock::now();
fsec fs = cur_time - start;
maxTimeExpenditure -= fs.count();
//std::this_thread::sleep_for(250ms);
//}
return queue.empty();
}
void CaveGame::Client::AssetService::LoadAllFromQueue() {
while (!queue.empty())
{
AssetRequest request = queue.front();
queue.pop();
if (!LoadAsset(request))
{
std::cerr << "bruh" << std::endl;
// Failed to load!!!
}
}
}

View File

@@ -50,11 +50,14 @@ void CaveGame::Client::GameSession::SaveAndExit() {
world->SaveAndExit();
}
void CaveGame::Client::GameSession::WorldEditToolDrawTiles(int x, int y, int radius, int density, TileID tile)
{
tool_rng = RNG(x + y);
World()->SetTile(x, y, tile);
for (int dx = -radius; dx <= radius; ++dx)
for (int dy = -radius; dy <= radius; ++dy)
if (density >= 100 || density > tool_rng.Float(0, 99))
@@ -62,26 +65,85 @@ void CaveGame::Client::GameSession::WorldEditToolDrawTiles(int x, int y, int rad
World()->SetTile(x+dx, y+dy, tile);
}
bool following = false;
Vector2 last = {0,0};
Vector2 CaveGame::Client::GameSession::MouseWorldPos()
{
return World()->camera.ScreenToWorld(mouse_pos);
}
void CaveGame::Client::GameSession::WorldEditToolDrawTiles(TileID tile) {
Vector2 tile_radius = {0.5f, 0.5f};
Vector2 world_coords = World()->camera.ScreenToWorld(mouse_pos) - tile_radius;
Vector2 world_coords = MouseWorldPos() - tile_radius;
//Vector2i rounded_coords = {Math::FloorInt(world_coords.x), Math::FloorInt(world_coords.y)};
int radius = Math::FloorInt(tile_tool->BrushRadius());
int density = Math::FloorInt(tile_tool->BrushDensity());
int x = Math::FloorInt(world_coords.x);
int y = Math::FloorInt(world_coords.y);
WorldEditToolDrawTiles(x, y, radius, density, tile);
Vector2 floor_wc = Vector2(x, y);
float dist = world_coords.Distance(last);
//if (dist > 1)
//{
for (int i = 0; i < dist; i++)
{
Vector2 step = last.Lerp(world_coords, i / dist);
x = Math::FloorInt(step.x);
y = Math::FloorInt(step.y);
WorldEditToolDrawTiles(x, y, radius, density, tile);
}
last = floor_wc;
//}
}
void CaveGame::Client::GameSession::WorldEditToolControlsUpdate(float elapsed){
if (InputService::IsMouseButtonDown(MouseButtons::Left))
WorldEditToolDrawTiles(TileID::AIR);
if (InputService::IsMouseButtonDown(MouseButtons::Left)) {
if (!following)
{
last = MouseWorldPos();
following = true;
}
WorldEditToolDrawTiles(TileID::AIR);
} else {
if (following)
following = false;
}
if (InputService::IsMouseButtonDown(MouseButtons::Right)) {
if (!following)
{
last = MouseWorldPos();
following = true;
}
if (InputService::IsMouseButtonDown(MouseButtons::Right))
WorldEditToolDrawTiles(hotbar.GetCurrentSlotTileID());
} else
if (following)
following = false;
}
void CaveGame::Client::GameSession::Update(float elapsed) {

View File

@@ -1,6 +1,6 @@
#include <Client/Splash.hpp>
#include <JGL/JGL.h>
#include "Client/AssetService.hpp"
CaveGame::Client::Splash::Splash() : Scene()
{
@@ -72,6 +72,8 @@ void CaveGame::Client::Splash::DrawProgressBar()
float progress_bar_length = bar_length * load_percent;
JGL::J2D::FillRect(Colors::White, bar_pos, {progress_bar_length, bar_height});
JGL::J2D::DrawString(Colors::Black, AssetService::Get()->LastAsset(), bar_pos.x, bar_pos.y, 1, 16);
}
@@ -116,12 +118,16 @@ void CaveGame::Client::Splash::Draw()
void CaveGame::Client::Splash::Update(float elapsed)
{
if (load_percent < 1)
load_percent += elapsed/2.f;
else
load_percent = 1;
AssetService::Get()->LoadFromQueue();
splash_timer -= elapsed;
load_percent = (float)AssetService::Get()->TotalLoaded() / (float)AssetService::Get()->TotalQueued();
//if (load_percent < 1)
//load_percent += elapsed/2.f;
//else
//load_percent = 1;
//splash_timer -= elapsed;
}
@@ -144,7 +150,8 @@ void CaveGame::Client::Splash::Unload() {
}
bool CaveGame::Client::Splash::SplashComplete() const {
return splash_timer < 0;
return AssetService::Get()->IsLoadComplete();
//return splash_timer < 0;
}
CaveGame::Client::Splash::~Splash() {

View File

@@ -209,6 +209,10 @@ namespace CaveGame::ClientApp {
} else
Log("Must be in-game to use this command!");
}},
{"save-world", {}, [this](const auto& args) {
if (InGame())
GameSession()->World()->Save();
}},
};

View File

@@ -105,7 +105,20 @@ namespace CaveGame::ClientApp
this->assets.TempLoadSimple();
this->assets.EnqueueDefaultAssetsFolder();
OpenWorld({.NewWorld = false});
for (int i = 0; i < 10; i++)
{
assets.EnqueueTexture("assets/textures/redacted.png");
assets.EnqueueTexture("assets/textures/bg.png");
assets.EnqueueTexture("assets/textures/player.png");
assets.EnqueueTexture("assets/textures/explosion.png");
assets.EnqueueTexture("assets/textures/title_1.png");
assets.EnqueueTexture("assets/textures/ash_wip_potions.png");
}
ChangeScene(splash_ctx);
//OpenWorld({.NewWorld = false});
//this->ChangeScene(this->game_ctx);
// TODO: Implement Resource/Asset manager rather than passing asset references around like this.

View File

@@ -125,9 +125,12 @@ namespace CaveGame::Core {
virtual void RefreshAll();
virtual void AutoSaveAsync() { }
virtual void AutoSave();
void Save();
void SaveAsync()
{
}
/// Gracefully saves all game state and closes the play session.
virtual void SaveAndExit();
@@ -160,10 +163,19 @@ namespace CaveGame::Core {
void DropChunk(const Vector2i& cell);
void SetTileTiccRate(float ticcrate);
float GetTileTiccRate() const { return TileTiccRate; }
float GetTileTiccRate() const { return tile_ticc_frequency; }
protected:
void SaveChunkToFile(const Vector2i &cell, Chunk* chunk);
virtual void AutoSaveAsync() {
OnAutosave.Invoke();
Logs::Info("Autosaving...");
Save();
Logs::Info("Autosave successful!");
}
virtual void AutoSave();
bool ValidCoords(const Vector2i &cell) const;
protected:
std::vector<Entity*> entities;
@@ -182,11 +194,15 @@ namespace CaveGame::Core {
ConcurrentQueue<Core::Chunk*> ServedChunks;
float tile_ticc_counter;
float TileTiccRate = 48.f; // Ticcs per second.
// Ticcs per second.
float tile_ticc_frequency = 48.f;
bool save_in_progress = false;
private:
void Save();
void SimulateTiles(float elapsed);
};
}

View File

@@ -21,12 +21,23 @@ namespace CaveGame::Core
}
}
void CaveGame::Core::World::SimulateTiles(float elapsed)
{
tile_ticc_counter+=elapsed;
if (tile_ticc_counter > 1.f / tile_ticc_frequency) {
tile_ticc_counter -= 1.f / tile_ticc_frequency;
DoTileTiccs(elapsed);
}
}
void CaveGame::Core::World::Update(float elapsed) {
#ifdef DEBUGGING
for (const auto& [coords, chunk] : loaded_chunks) {
chunk->Update(elapsed);
}
#endif
time_of_day += elapsed;
@@ -44,14 +55,8 @@ namespace CaveGame::Core
autosave_timer = 0;
}
if (simulate_tiles) {
tile_ticc_counter+=elapsed;
if (tile_ticc_counter > 1.f / TileTiccRate) {
tile_ticc_counter -= 1.f / TileTiccRate;
DoTileTiccs(elapsed);
}
}
if (simulate_tiles)
SimulateTiles(elapsed);
for (auto* entity : entities) {
entity->Update(elapsed);