Wire engine services into game skeleton
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#include "game_services.h"
|
||||
|
||||
#include <frostbite2D/audio/audio_system.h>
|
||||
#include <frostbite2D/resource/asset.h>
|
||||
#include <frostbite2D/resource/audio_database.h>
|
||||
#include <frostbite2D/resource/npk_archive.h>
|
||||
#include <frostbite2D/resource/pvf_archive.h>
|
||||
#include <frostbite2D/resource/save_system.h>
|
||||
#include <frostbite2D/resource/sound_pack_archive.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace ns_game {
|
||||
|
||||
namespace {
|
||||
|
||||
bool assetExists(const char* path) {
|
||||
return frostbite2D::Asset::get().exists(path);
|
||||
}
|
||||
|
||||
const char* firstExistingPath(const char* primary, const char* fallback) {
|
||||
if (assetExists(primary)) {
|
||||
return primary;
|
||||
}
|
||||
if (fallback && assetExists(fallback)) {
|
||||
return fallback;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
GameServices& GameServices::Get() {
|
||||
static GameServices services;
|
||||
return services;
|
||||
}
|
||||
|
||||
void GameServices::Initialize() {
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
status_.saveInitialized = frostbite2D::SaveSystem::get().listSlots().size() > 0;
|
||||
initializeAudio();
|
||||
initializePvfArchive();
|
||||
initializeNpkArchive();
|
||||
initializeSoundPackArchive();
|
||||
initializeAudioDatabase();
|
||||
|
||||
SDL_Log("GameServices: audio=%d save=%d pvf=%d npk=%d soundpack=%d audiodb=%d",
|
||||
status_.audioInitialized ? 1 : 0,
|
||||
status_.saveInitialized ? 1 : 0,
|
||||
status_.pvfArchiveOpen ? 1 : 0,
|
||||
status_.npkArchiveOpen ? 1 : 0,
|
||||
status_.soundPackOpen ? 1 : 0,
|
||||
status_.audioDatabaseLoaded ? 1 : 0);
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
void GameServices::initializeAudio() {
|
||||
frostbite2D::AudioConfig config;
|
||||
status_.audioInitialized = frostbite2D::AudioSystem::get().init(config);
|
||||
}
|
||||
|
||||
void GameServices::initializePvfArchive() {
|
||||
const char* pvfPath = firstExistingPath("Script.pvf", "assets/Script.pvf");
|
||||
if (!pvfPath) {
|
||||
SDL_Log("GameServices: optional Script.pvf not found");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& pvf = frostbite2D::PvfArchive::get();
|
||||
if (pvf.open(pvfPath)) {
|
||||
pvf.init();
|
||||
status_.pvfArchiveOpen = pvf.isOpen();
|
||||
}
|
||||
}
|
||||
|
||||
void GameServices::initializeNpkArchive() {
|
||||
auto& asset = frostbite2D::Asset::get();
|
||||
auto& npk = frostbite2D::NpkArchive::get();
|
||||
if (asset.isDirectory("assets/ImagePacks2")) {
|
||||
npk.setImagePackDirectory("assets/ImagePacks2");
|
||||
}
|
||||
npk.init();
|
||||
status_.npkArchiveOpen = npk.isOpen();
|
||||
}
|
||||
|
||||
void GameServices::initializeSoundPackArchive() {
|
||||
auto& asset = frostbite2D::Asset::get();
|
||||
auto& soundPack = frostbite2D::SoundPackArchive::get();
|
||||
if (asset.isDirectory("assets/SoundPacks")) {
|
||||
soundPack.setSoundPackDirectory("assets/SoundPacks");
|
||||
}
|
||||
soundPack.init();
|
||||
status_.soundPackOpen = soundPack.isOpen();
|
||||
}
|
||||
|
||||
void GameServices::initializeAudioDatabase() {
|
||||
const char* audioDbPath =
|
||||
firstExistingPath("assets/audio/audio.xml", "assets/audio.xml");
|
||||
if (!audioDbPath) {
|
||||
SDL_Log("GameServices: optional audio database not found");
|
||||
return;
|
||||
}
|
||||
|
||||
status_.audioDatabaseLoaded =
|
||||
frostbite2D::AudioDatabase::get().loadFromFile(audioDbPath);
|
||||
}
|
||||
|
||||
} // namespace ns_game
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
namespace ns_game {
|
||||
|
||||
struct GameServiceStatus {
|
||||
bool audioInitialized = false;
|
||||
bool saveInitialized = false;
|
||||
bool pvfArchiveOpen = false;
|
||||
bool npkArchiveOpen = false;
|
||||
bool soundPackOpen = false;
|
||||
bool audioDatabaseLoaded = false;
|
||||
};
|
||||
|
||||
class GameServices {
|
||||
public:
|
||||
static GameServices& Get();
|
||||
|
||||
GameServices(const GameServices&) = delete;
|
||||
GameServices& operator=(const GameServices&) = delete;
|
||||
|
||||
void Initialize();
|
||||
const GameServiceStatus& Status() const { return status_; }
|
||||
|
||||
private:
|
||||
GameServices() = default;
|
||||
|
||||
void initializeAudio();
|
||||
void initializePvfArchive();
|
||||
void initializeNpkArchive();
|
||||
void initializeSoundPackArchive();
|
||||
void initializeAudioDatabase();
|
||||
|
||||
GameServiceStatus status_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace ns_game
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "stage_map_resource.h"
|
||||
|
||||
#include <frostbite2D/resource/asset.h>
|
||||
#include <frostbite2D/resource/pvf_archive.h>
|
||||
#include <frostbite2D/resource/script_parser.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace ns_game {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string assetFallbackPath(const std::string& path) {
|
||||
if (path.rfind("assets/", 0) == 0) {
|
||||
return path;
|
||||
}
|
||||
return "assets/" + path;
|
||||
}
|
||||
|
||||
bool isLikelyPvfScript(const frostbite2D::RawData& rawData) {
|
||||
if (!rawData.data || rawData.size < 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto opcode = static_cast<unsigned char>(rawData.data[2]);
|
||||
switch (static_cast<frostbite2D::ScriptOpcode>(opcode)) {
|
||||
case frostbite2D::ScriptOpcode::Integer:
|
||||
case frostbite2D::ScriptOpcode::Float:
|
||||
case frostbite2D::ScriptOpcode::StringRef5:
|
||||
case frostbite2D::ScriptOpcode::StringRef6:
|
||||
case frostbite2D::ScriptOpcode::StringRef7:
|
||||
case frostbite2D::ScriptOpcode::StringRef8:
|
||||
case frostbite2D::ScriptOpcode::ExtendedString9:
|
||||
case frostbite2D::ScriptOpcode::ExtendedString10:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::optional<StageMapResource> LoadStageMapResource(const std::string& path) {
|
||||
frostbite2D::Asset& asset = frostbite2D::Asset::get();
|
||||
if (auto content = asset.readFileToString(path)) {
|
||||
StageMapResource resource;
|
||||
resource.source = StageMapResourceSource::AssetText;
|
||||
resource.path = path;
|
||||
resource.text = *content;
|
||||
return resource;
|
||||
}
|
||||
|
||||
const std::string fallbackPath = assetFallbackPath(path);
|
||||
if (fallbackPath != path) {
|
||||
if (auto content = asset.readFileToString(fallbackPath)) {
|
||||
StageMapResource resource;
|
||||
resource.source = StageMapResourceSource::AssetText;
|
||||
resource.path = fallbackPath;
|
||||
resource.text = *content;
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
frostbite2D::PvfArchive& pvf = frostbite2D::PvfArchive::get();
|
||||
if (pvf.isOpen()) {
|
||||
if (auto rawData = pvf.getFileRawData(path);
|
||||
rawData && isLikelyPvfScript(*rawData)) {
|
||||
frostbite2D::ScriptParser parser(*rawData, path);
|
||||
if (parser.isValid()) {
|
||||
StageMapResource resource;
|
||||
resource.source = StageMapResourceSource::PvfBinaryScript;
|
||||
resource.path = path;
|
||||
for (const frostbite2D::ScriptValue& value : parser.parseAll()) {
|
||||
resource.scriptValues.push_back(value.toString());
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto content = pvf.getFileContent(path)) {
|
||||
StageMapResource resource;
|
||||
resource.source = StageMapResourceSource::PvfText;
|
||||
resource.path = path;
|
||||
resource.text = *content;
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Log("StageMapResource: map not found: %s", path.c_str());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace ns_game
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ns_game {
|
||||
|
||||
enum class StageMapResourceSource {
|
||||
None,
|
||||
AssetText,
|
||||
PvfText,
|
||||
PvfBinaryScript
|
||||
};
|
||||
|
||||
struct StageMapResource {
|
||||
StageMapResourceSource source = StageMapResourceSource::None;
|
||||
std::string path;
|
||||
std::string text;
|
||||
std::vector<std::string> scriptValues;
|
||||
|
||||
bool hasContent() const {
|
||||
return !text.empty() || !scriptValues.empty();
|
||||
}
|
||||
};
|
||||
|
||||
std::optional<StageMapResource> LoadStageMapResource(const std::string& path);
|
||||
|
||||
} // namespace ns_game
|
||||
@@ -1,8 +1,21 @@
|
||||
#include "level_definition.h"
|
||||
#include "stage_map_resource.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace ns_game {
|
||||
|
||||
LevelDefinition CreateWhiteboxLevel() {
|
||||
if (auto mapResource = LoadStageMapResource("map/stage_01.map")) {
|
||||
SDL_Log("CreateWhiteboxLevel: loaded %s map resource: %s",
|
||||
mapResource->source == StageMapResourceSource::AssetText ? "asset"
|
||||
: mapResource->source == StageMapResourceSource::PvfText ? "pvf-text"
|
||||
: mapResource->source == StageMapResourceSource::PvfBinaryScript
|
||||
? "pvf-script"
|
||||
: "unknown",
|
||||
mapResource->path.c_str());
|
||||
}
|
||||
|
||||
LevelDefinition level;
|
||||
level.worldWidth = 3200.0f;
|
||||
level.worldHeight = 720.0f;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "scene/whitebox_scene.h"
|
||||
#include "core/game_config.h"
|
||||
#include "core/game_services.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
@@ -80,6 +81,8 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ns_game::GameServices::Get().Initialize();
|
||||
|
||||
app.run([]() {
|
||||
frostbite2D::SceneManager::get().ReplaceScene(
|
||||
frostbite2D::MakePtr<ns_game::WhiteboxScene>());
|
||||
|
||||
Reference in New Issue
Block a user