Skip to content

Commit

Permalink
🎮 New mod type: '.dashboard'
Browse files Browse the repository at this point in the history
Usual modcache treatment: recorded in cache file 'mods.cache', viewable/searchable in SelectorUI, can have preview image.

For an example, see file 'default.dashboard' added to 'dashboards.zip'.

A new cvar was added: 'ui_default_dashboard' (string) - stores the name of default dashboard, you can change it via Settings (tab UI).
  • Loading branch information
ohlidalp committed Feb 12, 2025
1 parent 6428a1d commit 2dd9565
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 84 deletions.
Binary file added resources/dashboards/default-mini.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions resources/dashboards/default.dashboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// A dashboard mod MUST contain a '.dashboard' file, even if just empty.
// All layout files must start the same as the .dashboard file.
// For example: foo.dashboard -> foo_dashboard3500.layout.
// Supported names:
// foo_dashboard_boat.layout
// foo_dashboard3500.layout <---- fallback
// foo_dashboard3500_analog.layout
// foo_dashboard3500_analog_mph.layout
// foo_dashboard3500_mph.layout
// foo_dashboard7000.layout
// foo_dashboard7000_analog.layout
// foo_dashboard7000_analog_mph.layout
// foo_dashboard7000_mph.layout
// ------------------------------------------------------------

dashboard_name "Default"
dashboard_description "Default Dashboard"
dashboard_supports_7000rpm true
dashboard_supports_mph true
dashboard_supports_analog true
dashboard_supports_boat true
1 change: 1 addition & 0 deletions source/main/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ CVar* ui_show_live_repair_controls;
CVar* ui_show_vehicle_buttons;
CVar* ui_preset;
CVar* ui_hide_gui;
CVar* ui_default_dashboard;

// Instance access
AppContext* GetAppContext () { return &g_app_context; };
Expand Down
2 changes: 2 additions & 0 deletions source/main/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ enum LoaderType //!< Search mode for `ModCache::Query()` & Operation mode for `G
LT_AddonPart, // No script alias, invoked manually, ext: addonpart
LT_Tuneup, // No script alias, invoked manually, ext: tuneup
LT_AssetPack, // No script alias, invoked manually, ext: assetpack
LT_DashBoard, // No script alias, invoked manually, ext: dashboard
};

enum class TObjSpecialObject
Expand Down Expand Up @@ -540,6 +541,7 @@ extern CVar* ui_show_live_repair_controls; //!< bool
extern CVar* ui_show_vehicle_buttons;
extern CVar* ui_preset; //!< enum `RoR::UiPreset`
extern CVar* ui_hide_gui; //!< bool; The 'hide GUI' hotkey state
extern CVar* ui_default_dashboard; //!< string; name of the '.dashboard' file in modcache.

// ------------------------------------------------------------------------------------------------
// Global objects
Expand Down
161 changes: 155 additions & 6 deletions source/main/gui/DashBoardManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@

#include "DashBoardManager.h"

#include "Actor.h"
#include "Application.h"
#include "CacheSystem.h"
#include "Console.h"
#include "GenericFileFormat.h"
#include "Utils.h"

using namespace Ogre;
using namespace RoR;

#define INITDATA(key, type, name) data[key] = dashData_t(type, name)

DashBoardManager::DashBoardManager(void) : visible(true)
DashBoardManager::DashBoardManager(ActorPtr actor) : visible(true), m_actor(actor)
{

// init data
Expand Down Expand Up @@ -170,15 +174,160 @@ std::string DashBoardManager::getLinkNameForID(DashData id)
}
}

int DashBoardManager::loadDashBoard(Ogre::String filename, bool textureLayer)
std::string DashBoardManager::determineLayoutFromDashboardMod(CacheEntryPtr& entry, std::string const& basename)
{
// Determine what the dashboard supports - read the '.dashboard' file using GenericDocument
bool supports_7000rpm = false;
bool supports_analog = false;
bool supports_mph = false;
bool supports_boat = false;
try
{
Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().openResource(entry->fname, entry->resource_group);

DashBoard* d = new DashBoard(this, filename, textureLayer);
d->setVisible(true);
GenericDocumentPtr doc = new GenericDocument();
BitMask_t options = GenericDocument::OPTION_ALLOW_SLASH_COMMENTS;
doc->loadFromDataStream(datastream, options);

m_dashboards.push_back(d);
GenericDocContextPtr context = new GenericDocContext(doc);

return 0;
while (!context->endOfFile())
{
if (context->isTokKeyword(0) && context->isTokBool(1))
{
supports_7000rpm |= (context->getTokKeyword() == "dashboard_supports_7000rpm") && context->getTokBool(1);
supports_analog |= (context->getTokKeyword() == "dashboard_supports_analog") && context->getTokBool(1);
supports_mph |= (context->getTokKeyword() == "dashboard_supports_mph") && context->getTokBool(1);
supports_boat |= (context->getTokKeyword() == "dashboard_supports_boat") && context->getTokBool(1);
}

context->seekNextLine();
}
}
catch (Ogre::Exception& e)
{
App::GetConsole()->putMessage(
Console::CONSOLE_MSGTYPE_ACTOR, Console::CONSOLE_SYSTEM_WARNING,
fmt::format("Could not load dashboard: Error parsing file '{}', message: {}",
entry->fname, e.getDescription()));
return "";
}

if (m_actor->ar_driveable == TRUCK) // load default for a truck
{
if (!supports_analog || App::gfx_speedo_digital->getBool())
{
if (App::gfx_speedo_imperial->getBool() && supports_mph)
{
if (m_actor->ar_engine->getShiftUpRPM() > 3500 && supports_7000rpm)
{
return fmt::format("{}_dashboard7000_mph.layout", basename); //7000 rpm tachometer thanks to Klink
}
else
{
return fmt::format("{}_dashboard3500_mph.layout", basename);
}
}
else
{
if (m_actor->ar_engine->getShiftUpRPM() > 3500 && supports_7000rpm)
{
return fmt::format("{}_dashboard7000.layout", basename); //7000 rpm tachometer thanks to Klink
}
else
{
return fmt::format("{}_dashboard3500.layout", basename);
}
}
}
else // Analog speedometer
{
if (!supports_mph || App::gfx_speedo_imperial->getBool())
{
if (m_actor->ar_engine->getShiftUpRPM() > 3500 && supports_7000rpm)
{
return fmt::format("{}_dashboard7000_analog_mph.layout", basename); //7000 rpm tachometer thanks to Klink
}
else
{
return fmt::format("{}_dashboard3500_analog_mph.layout", basename);
}
}
else
{
if (m_actor->ar_engine->getShiftUpRPM() > 3500 && supports_7000rpm)
{
return fmt::format("{}_dashboard7000_analog.layout", basename); //7000 rpm tachometer thanks to Klink
}
else
{
return fmt::format("{}_dashboard3500_analog.layout", basename);
}
}
}
}
else if (m_actor->ar_driveable == BOAT)
{
return fmt::format("{}_dashboard_boat.layout", basename);
}
return "";
}

void DashBoardManager::loadDashBoard(std::string const& filename, BitMask_t flags)
{
// filename may be either '.layout' file (classic approach) or a new '.dashboard' mod.
// ----------------------------------------------------------------------------------

if (BITMASK_IS_0(flags, LOADDASHBOARD_SCREEN_HUD | LOADDASHBOARD_RTT_TEXTURE))
return; // Nothing to do.

std::string basename, ext, layoutfname;
Ogre::StringUtil::splitBaseFilename(filename, basename, ext);
if (ext == "dashboard")
{
CacheEntryPtr entry = App::GetCacheSystem()->FindEntryByFilename(LT_DashBoard, /*partial=*/false, filename);
if (!entry)
{
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_WARNING,
fmt::format("DashboardManager: Could not find dashboard file '{}'", filename));
return;
}
App::GetCacheSystem()->LoadResource(entry);
layoutfname = this->determineLayoutFromDashboardMod(entry, basename);
}
else
{
layoutfname = filename;
}

if (layoutfname == "")
{
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_ACTOR, Console::CONSOLE_SYSTEM_WARNING,
fmt::format("{}: Cannot load dashboard '{}' - no applicable layout file found", m_actor->ar_design_name, filename));
return;
}

if (BITMASK_IS_1(flags, LOADDASHBOARD_RTT_TEXTURE))
{
DashBoard* d = new DashBoard(this, layoutfname, /* textureLayer: */true);
d->setVisible(true);
m_dashboards.push_back(d);
if (BITMASK_IS_0(flags, LOADDASHBOARD_STACKABLE))
{
m_rtt_loaded = true;
}
}

if (BITMASK_IS_1(flags, LOADDASHBOARD_SCREEN_HUD))
{
DashBoard* d = new DashBoard(this, layoutfname, /* textureLayer: */false);
d->setVisible(true);
m_dashboards.push_back(d);
if (BITMASK_IS_0(flags, LOADDASHBOARD_STACKABLE))
{
m_hud_loaded = true;
}
}
}

void DashBoardManager::update(float dt)
Expand Down
18 changes: 15 additions & 3 deletions source/main/gui/DashBoardManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,18 @@ enum DashData
DD_MAX
};

enum LoadDashBoardFlags
{
LOADDASHBOARD_SCREEN_HUD = BITMASK(1), //!< Will be drawn to screen. Unless STACKABLE, it prevents the default dashboard from loading.
LOADDASHBOARD_RTT_TEXTURE = BITMASK(2), //!< Will be drawn to texture. Unless STACKABLE, it prevents the default dashboard from loading.
LOADDASHBOARD_STACKABLE = BITMASK(3) //!< Allows loading multiple dashboards at once (by default there's only one for screen and one for RTT).
};

// this class is NOT intended to be thread safe - performance is required
class DashBoardManager
{
public:
DashBoardManager(void);
DashBoardManager(ActorPtr actor);
~DashBoardManager(void);

// Getter / Setter
Expand All @@ -228,21 +235,26 @@ class DashBoardManager
int getLinkIDForName(Ogre::String& str);
std::string getLinkNameForID(DashData id);

int loadDashBoard(Ogre::String filename, bool textureLayer);
void loadDashBoard(const std::string& filename, BitMask_t flags);

void update(float dt);
void updateFeatures();

bool WasDashboardLoaded() const { return (m_dashboards.size() > 0); };
bool wasDashboardHudLoaded() const { return m_hud_loaded; };
bool wasDashboardRttLoaded() const { return m_rtt_loaded; };

void setVisible(bool visibility);
void setVisible3d(bool visibility);
bool getVisible() { return visible; };
void windowResized();
protected:
std::string determineLayoutFromDashboardMod(CacheEntryPtr& entry, std::string const& basename);
bool visible = false;
dashData_t data[DD_MAX];
std::vector<DashBoard*> m_dashboards;
bool m_hud_loaded = false;
bool m_rtt_loaded = false;
ActorPtr m_actor;
};

class DashBoard
Expand Down
2 changes: 1 addition & 1 deletion source/main/gui/OverlayWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ void OverlayWrapper::showDashboardOverlays(bool show, ActorPtr actor)
m_dashboard_visible = show;

// check if we use the new style dashboards
if (actor && actor->ar_dashboard && actor->ar_dashboard->WasDashboardLoaded())
if (actor && actor->ar_dashboard && actor->ar_dashboard->wasDashboardHudLoaded())
{
actor->ar_dashboard->setVisible(show);
return;
Expand Down
17 changes: 16 additions & 1 deletion source/main/gui/panels/GUI_GameSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ void GameSettings::DrawUiSettings()

ImGui::Separator();

DrawDefaultDashboardEdit();

DrawGCheckbox(App::gfx_speedo_digital, _LC("GameSettings", "Digital speedometer"));
DrawGCheckbox(App::gfx_speedo_imperial, _LC("GameSettings", "Imperial units"));

Expand Down Expand Up @@ -667,4 +669,17 @@ void GameSettings::DrawUiPresetCombo()
}

ImGui::PopID(); //"uiPreset"
}
}

void GameSettings::DrawDefaultDashboardEdit()
{
ImGui::TextDisabled("%s:", _LC("GameSettings", "Default dashboard"));
ImGui::SameLine();
ImGui::Text("%s", App::ui_default_dashboard->getStr().c_str());
ImGui::SameLine();
if (ImGui::SmallButton(_LC("GameSettings", "Change")))
{
LoaderType* payload = new LoaderType(LoaderType::LT_DashBoard);
App::GetGameContext()->PushMessage(Message(MSG_GUI_OPEN_SELECTOR_REQUESTED, (void*)payload));
}
}
1 change: 1 addition & 0 deletions source/main/gui/panels/GUI_GameSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class GameSettings

// Helpers
void DrawUiPresetCombo();
void DrawDefaultDashboardEdit();

// GUI state
bool m_is_visible = false;
Expand Down
6 changes: 6 additions & 0 deletions source/main/gui/panels/GUI_MainSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,12 @@ void MainSelector::Apply()
App::GetGameContext()->PushMessage(Message(MSG_SIM_LOAD_TERRN_REQUESTED, sd_entry.sde_entry->fname));
this->Close();
}
else if (m_loader_type == LT_DashBoard &&
App::app_state->getEnum<AppState>() == AppState::MAIN_MENU)
{
App::ui_default_dashboard->setStr(sd_entry.sde_entry->fname);
this->Close();
}
else if (App::app_state->getEnum<AppState>() == AppState::SIMULATION)
{
LoaderType type = m_loader_type;
Expand Down
Loading

0 comments on commit 2dd9565

Please sign in to comment.