Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d5ada3e
add DWORD field type support to metadata system
Mosch0512 Jan 11, 2026
2700955
create SkillData directory with single source of truth for SKILL_ATTR…
Mosch0512 Jan 11, 2026
39c6524
add skill field definitions using X-macros
Mosch0512 Jan 11, 2026
5f52ba1
extract shared field metadata infrastructure to FieldMetadataHelper
Mosch0512 Jan 11, 2026
13793c7
add skill editor translations to metadata and UI files
Mosch0512 Jan 11, 2026
578ce38
implement skill data loader
Mosch0512 Jan 11, 2026
c0edbcf
implement skill data saver with backup support
Mosch0512 Jan 11, 2026
88adecb
implement skill CSV exporter
Mosch0512 Jan 11, 2026
888a8c3
create skill data handler facade
Mosch0512 Jan 11, 2026
9ad4f6e
migrate skill loading to use SkillDataHandler in all builds
Mosch0512 Jan 24, 2026
75335b6
implement skill editor column renderer
Mosch0512 Jan 11, 2026
71f9af7
implement skill editor table renderer
Mosch0512 Jan 11, 2026
7efeaf0
implement skill editor action buttons and popups
Mosch0512 Jan 11, 2026
bdd3749
implement skill editor UI orchestrator
Mosch0512 Jan 11, 2026
c25fa12
extend MuEditorConfig for skill editor support
Mosch0512 Jan 11, 2026
fe299c8
integrate skill editor into MuEditorCore
Mosch0512 Jan 24, 2026
14a7ff8
add "Skill Editor" button to toolbar
Mosch0512 Jan 11, 2026
34c5c36
Included German, Indonesian, Polish, Russian, Ukrainian, and Filipino…
Mosch0512 Jan 11, 2026
14829be
Load extended Unicode font support for multilingual character renderi…
Mosch0512 Jan 11, 2026
1b91850
Make skill export to csv button green
Mosch0512 Jan 13, 2026
d354764
Move change saves info into editor console
Mosch0512 Jan 13, 2026
237cb2c
Match the item save change editor logs
Mosch0512 Jan 13, 2026
8362b0b
Add legacy skill format support and export functionality
Mosch0512 Jan 13, 2026
8189f32
Improve naming of Export S6E3 functions
Mosch0512 Jan 13, 2026
c1c8882
Remove unused OpenSkillScript function
Mosch0512 Jan 24, 2026
c2865d0
Remove extra argument
Mosch0512 Jan 14, 2026
093b5dc
Dynamically load platform-specific system fonts for extended Unicode …
Mosch0512 Jan 14, 2026
135c676
Extract `WideToNarrow` helper to `StringUtils` for reusability and re…
Mosch0512 Jan 15, 2026
e692421
Replace `WideCharToMultiByte` with `StringUtils::WideToNarrow` in `It…
Mosch0512 Jan 15, 2026
ab4eaa8
Fix after rebase
Mosch0512 Jan 24, 2026
be1bbcd
Fix wrong naming of Windows.h to windows.h
Mosch0512 Jan 25, 2026
169555c
Replace `WideCharToMultiByte` with `StringUtils::WideToNarrow` in `Mu…
Mosch0512 Jan 25, 2026
f66ea55
Refactor default field visibility logic in `MuSkillEditorUI` using `s…
Mosch0512 Jan 25, 2026
262c7dc
Replace `WideCharToMultiByte` with `StringUtils::WideToNarrow` in `Sk…
Mosch0512 Jan 25, 2026
41e20c6
Replace `swprintf` with safer `swprintf_s` across ItemEditor and Skil…
Mosch0512 Jan 25, 2026
3d978e7
Introduce `CommonDataSaver` utility for standardized file backup crea…
Mosch0512 Jan 25, 2026
2e34362
Improve item change logging to work for bool also
Mosch0512 Jan 25, 2026
5e015b0
Improve editor logging to display counts of loaded skills and items c…
Mosch0512 Jan 25, 2026
3d8564b
remove misleading comment
Mosch0512 Jan 25, 2026
5331da6
Refactor skill change logging using `LogSkillFieldChange` helper for …
Mosch0512 Jan 25, 2026
75913f5
Fix missing fields `SKILL_FIELDS_AFTER_ARRAYS` for csv header and dat…
Mosch0512 Jan 25, 2026
6647d92
Add `SKILL_FIELDS_AFTER_ARRAYS` for CSV data export to include missin…
Mosch0512 Jan 25, 2026
e07cbf9
Add `SKILL_FIELDS_AFTER_ARRAYS` to `SkillFieldMetadata` for descripto…
Mosch0512 Jan 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/MuEditor/Config/MuEditorConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ void CMuEditorConfig::Load()
{
m_columnVisibility[key] = (value == "1" || value == "true");
}
else if (currentSection == "SkillEditorColumnVisibility")
{
m_skillEditorColumnVisibility[key] = (value == "1" || value == "true");
}
}
}

Expand Down Expand Up @@ -100,6 +104,14 @@ void CMuEditorConfig::Save()
{
file << col.first << "=" << (col.second ? "1" : "0") << "\n";
}
file << "\n";

// Write [SkillEditorColumnVisibility] section
file << "[SkillEditorColumnVisibility]\n";
for (const auto& col : m_skillEditorColumnVisibility)
{
file << col.first << "=" << (col.second ? "1" : "0") << "\n";
}

file.close();
}
Expand Down
11 changes: 8 additions & 3 deletions src/MuEditor/Config/MuEditorConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ class CMuEditorConfig
std::string GetLanguage() const;
void SetLanguage(const std::string& language);

// Column visibility settings
// Item Editor column visibility settings
bool GetColumnVisibility(const std::string& columnName, bool defaultValue = false) const;
void SetColumnVisibility(const std::string& columnName, bool visible);

// Get all column visibility settings
// Get all item editor column visibility settings
const std::map<std::string, bool>& GetAllColumnVisibility() const { return m_columnVisibility; }
void SetAllColumnVisibility(const std::map<std::string, bool>& visibility) { m_columnVisibility = visibility; }

// Skill Editor column visibility settings
const std::map<std::string, bool>& GetSkillEditorColumnVisibility() const { return m_skillEditorColumnVisibility; }
void SetSkillEditorColumnVisibility(const std::map<std::string, bool>& visibility) { m_skillEditorColumnVisibility = visibility; }

private:
CMuEditorConfig();

Expand All @@ -36,7 +40,8 @@ class CMuEditorConfig

// Settings storage
std::string m_language;
std::map<std::string, bool> m_columnVisibility;
std::map<std::string, bool> m_columnVisibility; // Item Editor columns
std::map<std::string, bool> m_skillEditorColumnVisibility; // Skill Editor columns

// Helper functions for INI parsing
std::string Trim(const std::string& str);
Expand Down
106 changes: 102 additions & 4 deletions src/MuEditor/Core/MuEditorCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
#ifdef _EDITOR

#include "MuEditorCore.h"
#include "../MuEditor/UI/Common/MuEditorUI.h"
#include "../MuEditor/UI/Console/MuEditorConsoleUI.h"
#include "imgui.h"
#include "imgui_impl_win32.h"
#include "imgui_impl_opengl2.h"
#include "MuInputBlockerCore.h"
#include "../Config/MuEditorConfig.h"
#include "../MuEditor/UI/Common/MuEditorCenterPaneUI.h"
#include "../MuEditor/UI/ItemEditor/MuItemEditorUI.h"
#include "../MuEditor/UI/SkillEditor/MuSkillEditorUI.h"
#include "../UI/Common/MuEditorUI.h"
#include "../UI/Console/MuEditorConsoleUI.h"
#include "Translation/i18n.h"
#include "Utilities/StringUtils.h"

// Windows cursor display counter thresholds
// The cursor is visible when the counter is >= CURSOR_VISIBLE_THRESHOLD
Expand All @@ -30,6 +32,7 @@ CMuEditorCore::CMuEditorCore()
, m_bInitialized(false)
, m_bFrameStarted(false)
, m_bShowItemEditor(false)
, m_bShowSkillEditor(false)
, m_bHoveringUI(false)
, m_bPreviousFrameHoveringUI(false)
{
Expand Down Expand Up @@ -65,6 +68,98 @@ void CMuEditorCore::Initialize(HWND hwnd, HDC hdc)
fwprintf(stderr, L"[MuEditor] ImGui context created\n");
fflush(stderr);

// Load font with extended Unicode support for multiple languages
// This includes Latin, Cyrillic, Greek, and other common character sets
ImFontConfig fontConfig;
fontConfig.OversampleH = 2;
fontConfig.OversampleV = 2;
fontConfig.PixelSnapH = true;

// Build font atlas with multiple Unicode ranges
ImFontGlyphRangesBuilder builder;
builder.AddRanges(io.Fonts->GetGlyphRangesDefault()); // Basic Latin + Latin Supplement
builder.AddRanges(io.Fonts->GetGlyphRangesCyrillic()); // Cyrillic (Russian, Ukrainian, etc.)
builder.AddRanges(io.Fonts->GetGlyphRangesGreek()); // Greek
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Includes common Asian characters

// Add additional specific characters if needed
static const ImWchar additionalRanges[] = {
0x0100, 0x017F, // Latin Extended-A (Polish, etc.)
0x0180, 0x024F, // Latin Extended-B
0x1E00, 0x1EFF, // Latin Extended Additional (Vietnamese)
0,
};
builder.AddRanges(additionalRanges);

ImVector<ImWchar> ranges;
builder.BuildRanges(&ranges);

// Load default font with extended ranges
// Try platform-specific fonts that support extended Unicode
bool fontLoaded = false;

#ifdef _WIN32
// Windows: Get fonts directory dynamically
wchar_t windowsDir[MAX_PATH];
if (GetWindowsDirectoryW(windowsDir, MAX_PATH) > 0)
{
std::wstring fontPathW = std::wstring(windowsDir) + L"\\Fonts\\segoeui.ttf";

// Convert to UTF-8 using StringUtils helper
std::string fontPath = StringUtils::WideToNarrow(fontPathW.c_str());
if (!fontPath.empty())
{
if (io.Fonts->AddFontFromFileTTF(fontPath.c_str(), 16.0f, &fontConfig, ranges.Data) != nullptr)
{
fontLoaded = true;
}
}
}
#elif __APPLE__
// macOS: Try system fonts
const char* macFonts[] = {
"/System/Library/Fonts/Supplemental/Arial Unicode.ttf",
"/System/Library/Fonts/Helvetica.ttc",
"/Library/Fonts/Arial Unicode.ttf"
};
for (const char* fontPath : macFonts)
{
if (io.Fonts->AddFontFromFileTTF(fontPath, 16.0f, &fontConfig, ranges.Data) != nullptr)
{
fontLoaded = true;
break;
}
}
#else
// Linux: Try common fonts with Unicode support
const char* linuxFonts[] = {
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/TTF/DejaVuSans.ttf",
"/usr/share/fonts/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf"
};
for (const char* fontPath : linuxFonts)
{
if (io.Fonts->AddFontFromFileTTF(fontPath, 16.0f, &fontConfig, ranges.Data) != nullptr)
{
fontLoaded = true;
break;
}
}
#endif

// Fallback to ImGui's default font if no system font loaded
// Note: Default font only supports basic ASCII, not extended ranges
if (!fontLoaded)
{
io.Fonts->AddFontDefault(&fontConfig);
}

// Note: Don't call io.Fonts->Build() - the backend will build it automatically

fwprintf(stderr, L"[MuEditor] Font loaded with Unicode support\n");
fflush(stderr);

// Dark theme
ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
Expand Down Expand Up @@ -148,6 +243,9 @@ void CMuEditorCore::Shutdown()
// Save item editor preferences before shutting down
g_MuItemEditorUI.SaveColumnPreferences();

// Save skill editor preferences before shutting down
g_MuSkillEditorUI.SaveColumnPreferences();

ImGui_ImplOpenGL2_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
Expand Down Expand Up @@ -305,12 +403,12 @@ void CMuEditorCore::Render()
m_bHoveringUI = false;

// Render toolbar (handles both open and closed states)
g_MuEditorUI.RenderToolbar(m_bEditorMode, m_bShowItemEditor);
g_MuEditorUI.RenderToolbar(m_bEditorMode, m_bShowItemEditor, m_bShowSkillEditor);

if (m_bEditorMode)
{
// Render center pane (handles all editor windows and input blocking)
g_MuEditorCenterPaneUI.Render(m_bShowItemEditor);
g_MuEditorCenterPaneUI.Render(m_bShowItemEditor, m_bShowSkillEditor);

// Render console
g_MuEditorConsoleUI.Render();
Expand Down
2 changes: 2 additions & 0 deletions src/MuEditor/Core/MuEditorCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class CMuEditorCore
void ToggleEditor() { m_bEditorMode = !m_bEditorMode; }

bool IsShowingItemEditor() const { return m_bShowItemEditor; }
bool IsShowingSkillEditor() const { return m_bShowSkillEditor; }
bool IsHoveringUI() const { return m_bHoveringUI; }
void SetHoveringUI(bool hovering) { m_bHoveringUI = hovering; }

Expand All @@ -30,6 +31,7 @@ class CMuEditorCore
bool m_bInitialized;
bool m_bFrameStarted;
bool m_bShowItemEditor;
bool m_bShowSkillEditor;
bool m_bHoveringUI;
bool m_bPreviousFrameHoveringUI; // Store previous frame's hover state for input blocking
};
Expand Down
10 changes: 6 additions & 4 deletions src/MuEditor/UI/Common/MuEditorCenterPaneUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
#ifdef _EDITOR

#include "MuEditorCenterPaneUI.h"

#include "../MuEditor/UI/ItemEditor/MuItemEditorUI.h"
#include "../MuEditor/UI/SkillEditor/MuSkillEditorUI.h"

CMuEditorCenterPaneUI& CMuEditorCenterPaneUI::GetInstance()
{
static CMuEditorCenterPaneUI instance;
return instance;
}

void CMuEditorCenterPaneUI::Render(bool& showItemEditor)
void CMuEditorCenterPaneUI::Render(bool& showItemEditor, bool& showSkillEditor)
{
// Simply render editor windows directly without a container
// The container was causing an extra debug window to appear
Expand All @@ -22,8 +22,10 @@ void CMuEditorCenterPaneUI::Render(bool& showItemEditor)
g_MuItemEditorUI.Render(showItemEditor);
}

// Future editor windows can be added here
// if (showOtherEditor) { g_MuOtherEditor.Render(showOtherEditor); }
if (showSkillEditor)
{
g_MuSkillEditorUI.Render(showSkillEditor);
}
}

#endif // _EDITOR
2 changes: 1 addition & 1 deletion src/MuEditor/UI/Common/MuEditorCenterPaneUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class CMuEditorCenterPaneUI
public:
static CMuEditorCenterPaneUI& GetInstance();

void Render(bool& showItemEditor);
void Render(bool& showItemEditor, bool& showSkillEditor);

private:
CMuEditorCenterPaneUI() = default;
Expand Down
12 changes: 9 additions & 3 deletions src/MuEditor/UI/Common/MuEditorUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ CMuEditorUI& CMuEditorUI::GetInstance()
return instance;
}

void CMuEditorUI::RenderToolbar(bool& editorEnabled, bool& showItemEditor)
void CMuEditorUI::RenderToolbar(bool& editorEnabled, bool& showItemEditor, bool& showSkillEditor)
{
if (editorEnabled)
{
RenderToolbarFull(editorEnabled, showItemEditor);
RenderToolbarFull(editorEnabled, showItemEditor, showSkillEditor);
}
else
{
Expand Down Expand Up @@ -109,7 +109,7 @@ void CMuEditorUI::RenderToolbarOpen(bool& editorEnabled)
ImGui::PopStyleColor(2);
}

void CMuEditorUI::RenderToolbarFull(bool& editorEnabled, bool& showItemEditor)
void CMuEditorUI::RenderToolbarFull(bool& editorEnabled, bool& showItemEditor, bool& showSkillEditor)
{
ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, TOOLBAR_HEIGHT), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
Expand Down Expand Up @@ -138,6 +138,12 @@ void CMuEditorUI::RenderToolbarFull(bool& editorEnabled, bool& showItemEditor)
showItemEditor = !showItemEditor;
}

ImGui::SameLine();
if (ImGui::Button("Skill Editor"))
{
showSkillEditor = !showSkillEditor;
}

// Language selector
ImGui::SameLine();
ImGui::SetNextItemWidth(100.0f);
Expand Down
4 changes: 2 additions & 2 deletions src/MuEditor/UI/Common/MuEditorUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ class CMuEditorUI
public:
static CMuEditorUI& GetInstance();

void RenderToolbar(bool& editorEnabled, bool& showItemEditor);
void RenderToolbar(bool& editorEnabled, bool& showItemEditor, bool& showSkillEditor);
void RenderCenterViewport();

private:
CMuEditorUI() = default;
~CMuEditorUI() = default;

void RenderToolbarOpen(bool& editorEnabled);
void RenderToolbarFull(bool& editorEnabled, bool& showItemEditor);
void RenderToolbarFull(bool& editorEnabled, bool& showItemEditor, bool& showSkillEditor);
};

#define g_MuEditorUI CMuEditorUI::GetInstance()
Expand Down
14 changes: 7 additions & 7 deletions src/MuEditor/UI/ItemEditor/ItemEditorActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ void CItemEditorActions::ConvertItemName(char* outBuffer, size_t bufferSize, con
WideCharToMultiByte(CP_UTF8, 0, name, -1, outBuffer, (int)bufferSize, NULL, NULL);
}

std::string CItemEditorActions::GetFieldValueAsString(const ITEM_ATTRIBUTE& item, const FieldDescriptor& desc)
std::string CItemEditorActions::GetFieldValueAsString(const ITEM_ATTRIBUTE& item, const ItemFieldDescriptor& desc)
{
std::stringstream ss;

Expand Down Expand Up @@ -64,7 +64,7 @@ std::string CItemEditorActions::GetFieldValueAsString(const ITEM_ATTRIBUTE& item
std::string CItemEditorActions::GetCSVHeader()
{
std::stringstream ss;
const FieldDescriptor* fields = GetFieldDescriptors(); const int fieldCount = GetFieldCount();
const ItemFieldDescriptor* fields = GetFieldDescriptors(); const int fieldCount = GetFieldCount();

ss << "Index";
for (int i = 0; i < fieldCount; ++i)
Expand All @@ -78,7 +78,7 @@ std::string CItemEditorActions::GetCSVHeader()
std::string CItemEditorActions::ExportItemToReadable(int itemIndex, ITEM_ATTRIBUTE& item)
{
std::stringstream ss;
const FieldDescriptor* fields = GetFieldDescriptors(); const int fieldCount = GetFieldCount();
const ItemFieldDescriptor* fields = GetFieldDescriptors(); const int fieldCount = GetFieldCount();

ss << "Row " << itemIndex << "\n";
ss << "Index = " << itemIndex;
Expand All @@ -95,7 +95,7 @@ std::string CItemEditorActions::ExportItemToReadable(int itemIndex, ITEM_ATTRIBU
std::string CItemEditorActions::ExportItemToCSV(int itemIndex, ITEM_ATTRIBUTE& item)
{
std::stringstream ss;
const FieldDescriptor* fields = GetFieldDescriptors(); const int fieldCount = GetFieldCount();
const ItemFieldDescriptor* fields = GetFieldDescriptors(); const int fieldCount = GetFieldCount();

ss << itemIndex;

Expand Down Expand Up @@ -168,9 +168,9 @@ void CItemEditorActions::RenderExportS6E3Button()
if (ImGui::Button(EDITOR_TEXT("btn_export_s6e3")))
{
wchar_t fileName[256];
swprintf_s(fileName, _countof(fileName), L"Data\\Local\\%ls\\Item_%ls_S6E3.bmd", g_strSelectedML.c_str(), g_strSelectedML.c_str());
swprintf_s(fileName, _countof(fileName), L"Data\\Local\\%ls\\Item_S6E3.bmd", g_strSelectedML.c_str());

if (g_ItemDataHandler.SaveLegacy(fileName))
if (g_ItemDataHandler.ExportAsS6E3(fileName))
{
std::string filename_str = "Item_" + std::string(g_strSelectedML.begin(), g_strSelectedML.end()) + "_S6E3.bmd";
g_MuEditorConsoleUI.LogEditor("Exported items as S6E3 legacy format: " + filename_str);
Expand All @@ -194,7 +194,7 @@ void CItemEditorActions::RenderExportCSVButton()
if (ImGui::Button(EDITOR_TEXT("btn_export_csv")))
{
wchar_t csvFileName[256];
swprintf_s(csvFileName, _countof(csvFileName), L"Data\\Local\\%ls\\Item_%ls_export.csv", g_strSelectedML.c_str(), g_strSelectedML.c_str());
swprintf_s(csvFileName, _countof(csvFileName), L"Data\\Local\\%ls\\Item.csv", g_strSelectedML.c_str());

if (g_ItemDataHandler.ExportToCsv(csvFileName))
{
Expand Down
3 changes: 2 additions & 1 deletion src/MuEditor/UI/ItemEditor/ItemEditorActions.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "GameData/ItemData/ItemFieldMetadata.h"

#ifdef _EDITOR

Expand Down Expand Up @@ -34,7 +35,7 @@ class CItemEditorActions
static void ConvertItemName(char* outBuffer, size_t bufferSize, const wchar_t* name);

// Get field value as string (descriptor-driven)
static std::string GetFieldValueAsString(const ITEM_ATTRIBUTE& item, const struct FieldDescriptor& desc);
static std::string GetFieldValueAsString(const ITEM_ATTRIBUTE &item, const ItemFieldDescriptor &desc);
};

#endif // _EDITOR
Loading