Hacked in AssetService to the splash screen, still needs some polish.
This commit is contained in:
@@ -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")
|
||||
|
@@ -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;
|
||||
|
||||
};
|
||||
}
|
||||
|
@@ -120,5 +120,7 @@ namespace CaveGame::Client {
|
||||
void WorldEditToolDrawTiles(int x, int y, int radius, int density, TileID tile);
|
||||
|
||||
void WorldEditToolDrawOverlay();
|
||||
|
||||
Vector2 MouseWorldPos();
|
||||
};
|
||||
}
|
||||
|
@@ -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!!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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() {
|
||||
|
@@ -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();
|
||||
}},
|
||||
|
||||
};
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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);
|
||||
};
|
||||
}
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user