diff --git a/.gitignore b/.gitignore
index afd4bf54..0ab04f5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,4 +56,9 @@ fallout4_test/resource.aps
Dependencies/libdeflate.vcxproj.user
Dependencies/libdeflate.vcxproj
Dependencies/tbb
+Dependencies/json
*.lnk
+
+# other
+*.cer
+*.bat
diff --git a/.gitmodules b/.gitmodules
index cc756f39..4b519f66 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -2,10 +2,6 @@
path = Dependencies/meshoptimizer
url = https://github.com/zeux/meshoptimizer.git
branch = master
-[submodule "Dependencies/tbb"]
- path = Dependencies/tbb
- url = https://github.com/01org/tbb.git
- branch = tbb_2019
[submodule "Dependencies/libdeflate"]
path = Dependencies/libdeflate
url = https://github.com/ebiggers/libdeflate.git
@@ -15,3 +11,13 @@
[submodule "Perchik71"]
path = Dependencies/mINI
url = https://github.com/Perchik71/mINI
+[submodule "Dependencies/json"]
+ path = Dependencies/json
+ url = https://github.com/nlohmann/json.git
+[submodule "Dependencies/tbb"]
+ path = Dependencies/tbb
+ url = https://github.com/oneapi-src/oneTBB.git
+ branch = tbb_2020
+[submodule "Dependencies/zipper"]
+ path = Dependencies/zipper
+ url = https://github.com/kuba--/zip.git
diff --git a/Dependencies/json b/Dependencies/json
new file mode 160000
index 00000000..e10a3fac
--- /dev/null
+++ b/Dependencies/json
@@ -0,0 +1 @@
+Subproject commit e10a3fac8a255433146e3f06a703dc110fc3c3da
diff --git a/Dependencies/tbb b/Dependencies/tbb
index a803f276..eca91f16 160000
--- a/Dependencies/tbb
+++ b/Dependencies/tbb
@@ -1 +1 @@
-Subproject commit a803f276186fa2c286a357207832112265b448e4
+Subproject commit eca91f16d7490a8abfdee652dadf457ec820cc37
diff --git a/Dependencies/zipper b/Dependencies/zipper
new file mode 160000
index 00000000..f02a47de
--- /dev/null
+++ b/Dependencies/zipper
@@ -0,0 +1 @@
+Subproject commit f02a47dee0858a7f34651d29616d462406f53a70
diff --git a/Resources/dialogs/1221-8.json b/Resources/dialogs/1221-8.json
new file mode 100644
index 00000000..10e5073d
--- /dev/null
+++ b/Resources/dialogs/1221-8.json
@@ -0,0 +1,12 @@
+{
+ "name": "Habrahabr",
+ "nothing": null,
+ "answer": {
+ "everything": 42
+ },
+ "companies": ["Infopulse", "TM"],
+ "user": {
+ "name": "tangro",
+ "active": true
+ }
+}
\ No newline at end of file
diff --git a/fallout4_test/fallout4_test.vcxproj b/fallout4_test/fallout4_test.vcxproj
index e37bd814..4aa8811b 100644
--- a/fallout4_test/fallout4_test.vcxproj
+++ b/fallout4_test/fallout4_test.vcxproj
@@ -164,6 +164,8 @@
+
+
@@ -173,6 +175,7 @@
+
@@ -258,12 +261,14 @@
+
+
diff --git a/fallout4_test/fallout4_test.vcxproj.filters b/fallout4_test/fallout4_test.vcxproj.filters
index 43eb8f6e..7fe52cd6 100644
--- a/fallout4_test/fallout4_test.vcxproj.filters
+++ b/fallout4_test/fallout4_test.vcxproj.filters
@@ -81,6 +81,12 @@
{15465807-fb72-43fe-a815-6fe39cdff7e4}
+
+ {81995caa-f5d0-49b7-965d-68c1333396e6}
+
+
+ {966ff70e-c235-430f-9b45-98e040be03f6}
+
@@ -359,6 +365,15 @@
Header Files\UI\Windows
+
+ Header Files\UI\Classes
+
+
+ __dependencies\zipper
+
+
+ __dependencies\zipper
+
@@ -589,6 +604,12 @@
Source Files\UI\Windows
+
+ Source Files\UI\Classes
+
+
+ __dependencies\zipper
+
diff --git a/fallout4_test/resource.rc b/fallout4_test/resource.rc
index 0406946a..3e7dcd91 100644
Binary files a/fallout4_test/resource.rc and b/fallout4_test/resource.rc differ
diff --git a/fallout4_test/src/patches/CKF4/Editor.cpp b/fallout4_test/src/patches/CKF4/Editor.cpp
index 0760ab8f..819104c3 100644
--- a/fallout4_test/src/patches/CKF4/Editor.cpp
+++ b/fallout4_test/src/patches/CKF4/Editor.cpp
@@ -258,8 +258,8 @@ uint32_t FIXAPI sub_1405B31C0_SSE41(BSTArray& Array, LPCVOID &Target)
for (uint32_t iter = 0; iter < vectorizedIterations; iter++)
{
- __m128i test1 = _mm_cmpeq_epi64(targets, _mm_loadu_si128((__m128i *)&data[index + 0]));
- __m128i test2 = _mm_cmpeq_epi64(targets, _mm_loadu_si128((__m128i *)&data[index + 2]));
+ __m128i test1 = _mm_cmpeq_epi64(targets, _mm_loadu_si128((__m128i*)&data[index + 0]));
+ __m128i test2 = _mm_cmpeq_epi64(targets, _mm_loadu_si128((__m128i*)&data[index + 2]));
INT32 mask = _mm_movemask_pd(_mm_castsi128_pd(_mm_or_si128(test1, test2)));
diff --git a/fallout4_test/src/patches/CKF4/JsonDialogGenerator.cpp b/fallout4_test/src/patches/CKF4/JsonDialogGenerator.cpp
new file mode 100644
index 00000000..682f9348
--- /dev/null
+++ b/fallout4_test/src/patches/CKF4/JsonDialogGenerator.cpp
@@ -0,0 +1,270 @@
+#include "JsonDialogGenerator.h"
+#include "LogWindow.h"
+#include "UIGraphics.h"
+
+#include "..\..\profiler_internal.h"
+
+#include "..\..\..\..\Dependencies\json\single_include\nlohmann\json.hpp"
+#include "..\..\..\..\Dependencies\zipper\src\zip.h"
+
+#include
+
+#define ARCHIVE_DIALOGS_FILENAME "data/f4ckfixes/dialogs.zip"
+#define FONTNAME "Microsoft Sans Serif"
+
+namespace Core
+{
+ namespace Classes
+ {
+ namespace UI
+ {
+ using json = nlohmann::json;
+ namespace fs = std::filesystem;
+
+ LPJsonDialogManager g_JsonDialogManager = NULL;
+
+ LPWORD lpwAlign(LPWORD lpIn)
+ {
+ ULONG ul;
+ ul = (ULONG)lpIn;
+ ul += 3;
+ ul >>= 2;
+ ul <<= 2;
+ return (LPWORD)ul;
+ }
+
+ BOOL CJsonDialogManager::AddDialog(const char* json_code, const LONG uid, const CJsonDialogType type)
+ {
+ if (type == CJsonDialogType::jdtUnknown)
+ return FALSE;
+
+ auto jDialog = json::parse(json_code);
+ if (jDialog.empty())
+ return FALSE;
+
+ WORD fsize = 8;
+ // Font point size.
+ switch (type)
+ {
+ case Core::Classes::UI::jdt10pt:
+ fsize = 10;
+ break;
+ case Core::Classes::UI::jdt12pt:
+ fsize = 12;
+ break;
+ }
+
+ CUICanvas* Canvas = new CUICanvas(GetDC(GetDesktopWindow()));
+
+ Canvas->Font.Name = FONTNAME;
+ Canvas->Font.Styles = {};
+ Canvas->Font.Size = fsize;
+
+ INT cxDlgUnit;
+ INT cyDlgUnit;
+ Canvas->TextSize("X", cxDlgUnit, cyDlgUnit);
+ cxDlgUnit = cxDlgUnit >> 1;
+ cyDlgUnit = cyDlgUnit >> 1;
+
+ ReleaseDC(GetDesktopWindow(), Canvas->Handle);
+ delete Canvas;
+
+ std::string sTitle = jDialog["title"].get();
+ std::string sFace = FONTNAME;
+
+ const size_t titleSize = sTitle.length() + 1;
+ const size_t fontSize = sFace.length() + 1;
+ const size_t dataSize = sizeof(DLGTEMPLATE) +
+ sizeof(CHAR) + // Menu array
+ sizeof(CHAR) + // Class array
+ titleSize + // Title array
+ sizeof(WORD) + // Font point size
+ fontSize; // Font array
+
+ LPDLGITEMTEMPLATE lpdit;
+ LPDLGTEMPLATE hgbl = (LPDLGTEMPLATE)GlobalAlloc(GMEM_ZEROINIT, dataSize + (512 * jDialog["items"].size()));
+ if (!hgbl)
+ return FALSE;
+
+ LPDLGTEMPLATE dt = (LPDLGTEMPLATE)GlobalLock(hgbl);
+ dt->style = jDialog["style"].get() | DS_SETFONT | WS_VISIBLE;
+ dt->dwExtendedStyle = jDialog["styleex"].get();
+ dt->cdit = jDialog["items"].size();
+ dt->x = (jDialog["x"].get() * 4) / cxDlgUnit;
+ dt->y = (jDialog["y"].get() * 8) / cyDlgUnit;
+ dt->cx = (jDialog["width"].get() * 4) / cxDlgUnit;
+ dt->cy = (jDialog["height"].get() * 8) / cyDlgUnit;
+
+ BYTE* dtExtra = (BYTE*)dt + sizeof(DLGTEMPLATE);
+
+ // Menu array.
+ *(CHAR*)dtExtra = '\0';
+ dtExtra += sizeof(CHAR);
+ // Class array.
+ *(CHAR*)dtExtra = '\0';
+ dtExtra += sizeof(CHAR);
+ // Title array.
+ memcpy(dtExtra, sTitle.data(), titleSize);
+ dtExtra += titleSize;
+ // Font point size.
+ *(WORD*)dtExtra = fsize;
+ dtExtra += sizeof(WORD);
+ // Font array.
+ memcpy(dtExtra, sFace.data(), fontSize);
+
+ LPWORD lpw = (LPWORD)dtExtra;
+ auto items = jDialog["items"];
+ for (json::iterator it = items.begin(); it != items.end(); ++it)
+ {
+ lpdit = (LPDLGITEMTEMPLATE)lpwAlign(lpw);
+ lpdit->x = (it.value()["x"].get() * 4) / cxDlgUnit;
+ lpdit->y = (it.value()["y"].get() * 8) / cyDlgUnit;
+ lpdit->cx = (it.value()["width"].get() * 4) / cxDlgUnit;
+ lpdit->cy = (it.value()["height"].get() * 8) / cyDlgUnit;
+ lpdit->id = it.value()["id"].get();
+ lpdit->style = WS_CHILD | it.value()["style"].get();
+
+ lpw = (LPWORD)(lpdit + 1);
+ *lpw++ = 0xFFFF;
+
+ auto item_type = it.value()["type"].get();
+ if (!stricmp(item_type.data(), "PUSHBUTTON"))
+ *lpw++ = 0x0080;
+ else if (!stricmp(item_type.data(), "EDITTEXT"))
+ *lpw++ = 0x0081;
+ else if (!stricmp(item_type.data(), "LTEXT"))
+ *lpw++ = 0x0082;
+ else if (!stricmp(item_type.data(), "PUSHBUTTON"))
+ *lpw++ = 0x0083;
+ else if (!stricmp(item_type.data(), "PUSHBUTTON"))
+ *lpw++ = 0x0084;
+ else if (!stricmp(item_type.data(), "COMBOBOX"))
+ *lpw++ = 0x0085;
+ else
+ *lpw++ = 0x0086;
+
+
+ /* static class */
+
+ auto caption = it.value()["id"].get();
+ memcpy((LPWSTR)lpw, caption.data(), caption.length());
+ lpw += 1 + caption.length();
+ }
+
+ /*
+ 0x0080 Button
+ Edit
+ Static
+ List box
+ Scroll bar
+0x0085
+
+ 2581,29,16,61,12,ES_AUTOHSCROLL
+ CONTROL "",2093,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,0,42,104,191,WS_EX_CLIENTEDGE
+ CONTROL "List2",1041,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_EDITLABELS | WS_TABSTOP,119,0,245,233,WS_EX_CLIENTEDGE
+ "",2157,105,0,10,233,NOT WS_GROUP
+ LTEXT "Filter",-1,3,18,19,10
+ 6024,29,2,61,98,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Layout",-1,3,4,23,11
+ PUSHBUTTON "...",6025,93,1,11,14
+ PUSHBUTTON "-",6027,93,15,11,14
+ CONTROL "Show only active (*) forms",2579,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,30,101,9
+ */
+
+
+ GlobalUnlock(hgbl);
+
+ return TRUE;
+ }
+
+ VOID CJsonDialogManager::Init(VOID)
+ {
+ // If there is no archive, this will cause an error and can't run the CK.
+ AssertMsgVa(fs::exists(fs::absolute(ARCHIVE_DIALOGS_FILENAME)), "File \"%s\" no found", ARCHIVE_DIALOGS_FILENAME);
+
+ LogWindow::Log("Initialize JSON dialog manager");
+ // open archive
+ struct zip_t* zip = zip_open(ARCHIVE_DIALOGS_FILENAME, 0, 'r');
+ AssertMsgVa(zip, "File \"%s\" corrupted or not an archive", ARCHIVE_DIALOGS_FILENAME);
+ LogWindow::Log("Initialize JSON dialog manager");
+ // reading the archive and retrieving data
+ CJsonDialogType jdtType = CJsonDialogType::jdtUnknown;
+ std::string sJson, sName;
+ INT nCount = zip_entries_total(zip);
+ for (INT i = 0; i < nCount; ++i)
+ {
+ zip_entry_openbyindex(zip, i);
+ // skip dirs
+ if (zip_entry_isdir(zip) != 0)
+ continue;
+
+ sName = zip_entry_name(zip);
+ if (sName.find_first_of('-') == std::string::npos)
+ LogWindow::Log("JSON: Incorrect filename \"%s\"", sName.c_str());
+ else
+ {
+ size_t nSize = zip_entry_size(zip);
+ if (!nSize)
+ continue;
+ // read
+ char* buf = NULL;
+ size_t bufsize = 0;
+ if (zip_entry_read(zip, (void**)&buf, &bufsize) != nSize)
+ LogWindow::Log("JSON: Error read file \"%s\"", sName.c_str());
+ //else if (zip_entry_crc32(zip) != CRC32(buf))
+ // LogWindow::Log("JSON: Incorrect CRC32 \"%s\"", sName.c_str());
+ else
+ {
+ auto AtuID = sName.find_first_of('-');
+ std::string sID = sName.substr(0, AtuID);
+ auto AtExt = sName.find_first_of('.');
+ std::string sType = sName.substr(AtuID + 1, AtExt);
+ std::string sExt = sName.substr(AtExt + 1);
+
+ switch (strtol(sType.data(), NULL, 10))
+ {
+ case 8:
+ jdtType = CJsonDialogType::jdt8pt;
+ break;
+ case 10:
+ jdtType = CJsonDialogType::jdt10pt;
+ break;
+ case 12:
+ jdtType = CJsonDialogType::jdt12pt;
+ break;
+ default:
+ jdtType = CJsonDialogType::jdtUnknown;
+ break;
+ }
+
+ if (jdtType == CJsonDialogType::jdtUnknown)
+ LogWindow::Log("JSON: Unknown dialog type %s \"%s\"", sType.c_str(), sName.c_str());
+ else if (strnicmp(sExt.c_str(), "json", 8))
+ LogWindow::Log("JSON: file \"%s\" not JSON", sName.c_str());
+ else if (!AddDialog(buf, strtol(sID.data(), NULL, 10), jdtType))
+ LogWindow::Log("JSON: Incorrect JSON data in file \"%s\"", sName.c_str());
+ }
+
+ if (buf)
+ free(buf);
+ }
+ }
+ }
+
+ VOID CJsonDialogManager::Release(VOID)
+ {
+ LogWindow::Log("Shutdown JSON dialog manager");
+ }
+
+ CJsonDialogManager::CJsonDialogManager(VOID)
+ {
+ Init();
+ }
+
+ CJsonDialogManager::~CJsonDialogManager(VOID)
+ {
+ Release();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/fallout4_test/src/patches/CKF4/JsonDialogGenerator.h b/fallout4_test/src/patches/CKF4/JsonDialogGenerator.h
new file mode 100644
index 00000000..b96a3a6b
--- /dev/null
+++ b/fallout4_test/src/patches/CKF4/JsonDialogGenerator.h
@@ -0,0 +1,52 @@
+#pragma once
+
+/*
+An apple fell on my head :D
+I came up with the idea of using simple languages to generate dialogs.
+This should solve the problem of bad dialogs in the future and support 10pt and 12pt text in dialogs.
+*/
+
+#include "..\..\common.h"
+
+#include
+
+namespace Core
+{
+ namespace Classes
+ {
+ namespace UI
+ {
+ enum CJsonDialogType
+ {
+ jdtUnknown,
+ jdt8pt,
+ jdt10pt,
+ jdt12pt
+ };
+
+ //
+ typedef class CJsonDialog
+ {
+
+ } *PJsonDialog, *LPJsonDialog;
+
+
+ //
+ typedef class CJsonDialogManager
+ {
+ private:
+ tbb::concurrent_vector m_items;
+ public:
+ BOOL AddDialog(const char* json_code, const LONG uid, const CJsonDialogType type);
+ protected:
+ virtual VOID Init(VOID);
+ VOID Release(VOID);
+ public:
+ CJsonDialogManager(VOID);
+ virtual ~CJsonDialogManager(VOID);
+ } *PJsonDialogManager, *LPJsonDialogManager;
+
+ extern LPJsonDialogManager g_JsonDialogManager;
+ }
+ }
+}
\ No newline at end of file
diff --git a/fallout4_test/src/patches/CKF4/UIThemeMode.cpp b/fallout4_test/src/patches/CKF4/UIThemeMode.cpp
index 1aab0710..0b226898 100644
--- a/fallout4_test/src/patches/CKF4/UIThemeMode.cpp
+++ b/fallout4_test/src/patches/CKF4/UIThemeMode.cpp
@@ -252,7 +252,7 @@ namespace UITheme
{
if (nCode == HC_ACTION)
{
- if (auto messageData = reinterpret_cast(lParam); (messageData->message == WM_CREATE)/* || messageData->message == WM_INITDIALOG*/)
+ if (auto messageData = reinterpret_cast(lParam); messageData->message == WM_CREATE)
{
LPCREATESTRUCTA lpCreateStruct = (LPCREATESTRUCTA)messageData->lParam;
if (lpCreateStruct)
@@ -557,8 +557,8 @@ namespace UITheme
if ((Theme::GetTheme() == Theme::Theme_Dark) || (Theme::GetTheme() == Theme::Theme_DarkGray))
{
// detected standart OS theme (comdlg32)
- COLORREF clTest = GetPixel(hdc, pRect->left + 2, pRect->top + 2);
- if (((GetRValue(clTest) + GetGValue(clTest) + GetBValue(clTest)) / 3) > 128)
+ COLORREF clTest = GetPixel(hdc, pRect->left + ((pRect->right - pRect->left) >> 1), pRect->top + 2);
+ if (CLR_INVALID != clTest && ((GetRValue(clTest) + GetGValue(clTest) + GetBValue(clTest)) / 3) > 128)
return DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, dwTextFlags2, pRect);
}
diff --git a/fallout4_test/src/patches/patches_f4ck.cpp b/fallout4_test/src/patches/patches_f4ck.cpp
index 5d3559ec..bc6bdb28 100644
--- a/fallout4_test/src/patches/patches_f4ck.cpp
+++ b/fallout4_test/src/patches/patches_f4ck.cpp
@@ -24,7 +24,10 @@
#include "CKF4/ResponseWindow.h"
#include "CKF4/DataWindow.h"
#include "CKF4/PreferencesWindow.h"
-//#include "CKF4/ActorWindow.h"
+
+// include json generator dialogs
+#include "CKF4/JsonDialogGenerator.h"
+
#include
@@ -383,6 +386,10 @@ VOID FIXAPI F_UIPatches(VOID)
XUtil::DetourClassJump(OFFSET(0xE1D2C7, 0), &Classes::CUIProgressDialog::ProcessMessagesOnlyLoadCellWorld);
}
}
+
+ // Initializing the dialog manager.
+ // Loading all supported dialogs.
+ //Classes::g_JsonDialogManager = new Classes::CJsonDialogManager();
}
diff --git a/fallout4_test/src/profiler_internal.h b/fallout4_test/src/profiler_internal.h
index c938bec6..f50f858a 100644
--- a/fallout4_test/src/profiler_internal.h
+++ b/fallout4_test/src/profiler_internal.h
@@ -1,3 +1,5 @@
+#include "common.h"
+
static constexpr uint32_t crc_table[256] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
diff --git a/fallout4_test/src/xutil.cpp b/fallout4_test/src/xutil.cpp
index 51dc3b51..40a8bd74 100644
--- a/fallout4_test/src/xutil.cpp
+++ b/fallout4_test/src/xutil.cpp
@@ -159,6 +159,18 @@ size_t XUtil::Str::findCaseInsensitive(std::string data, std::string toSearch, s
return data.find(toSearch, pos);
}
+std::string XUtil::Str::format(const char* fmt, ...)
+{
+ va_list va;
+ char message[2048];
+
+ va_start(va, fmt);
+ _vsnprintf(&message[0], _TRUNCATE, fmt, va);
+ va_end(va);
+
+ return message;
+}
+
void XUtil::Trim(char *Buffer, char C)
{
size_t len = strlen(Buffer);
diff --git a/fallout4_test/src/xutil.h b/fallout4_test/src/xutil.h
index 0472c2dc..9221e57f 100644
--- a/fallout4_test/src/xutil.h
+++ b/fallout4_test/src/xutil.h
@@ -215,6 +215,9 @@ namespace XUtil
// https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-the-last-error-code
std::string __stdcall GetLastErrorToStr(DWORD err, const std::string& namefunc);
std::string __stdcall GetLastErrorToStr(const std::string& namefunc);
+
+ // formating string
+ std::string format(const char* fmt, ...);
}
void SetThreadName(uint32_t ThreadID, const char *ThreadName);