|
1 | 1 | #define NOMINMAX |
2 | | - |
| 2 | +extern int hCalc(char*); |
3 | 3 | #include <Windows.h> |
4 | 4 |
|
5 | 5 | #ifdef TEXT |
@@ -1895,6 +1895,101 @@ namespace RC |
1895 | 1895 | Output::send(STR("Dumping GUObjectArray took {} seconds\n"), dumper_duration); |
1896 | 1896 | // Object & Property Dumper -> END |
1897 | 1897 | } |
| 1898 | + auto UE4SSProgram::dump_all_funcs(const File::StringType& output_path_and_file_name) -> void |
| 1899 | + { |
| 1900 | + // Object & Property Dumper -> START |
| 1901 | + if (settings_manager.ObjectDumper.LoadAllAssetsBeforeDumpingObjects) |
| 1902 | + { |
| 1903 | + Output::send(STR("Loading all assets...\n")); |
| 1904 | + double asset_loading_duration{}; |
| 1905 | + { |
| 1906 | + ScopedTimer loading_timer{&asset_loading_duration}; |
| 1907 | + |
| 1908 | + UAssetRegistry::LoadAllAssets(); |
| 1909 | + } |
| 1910 | + Output::send(STR("Loading all assets took {} seconds\n"), asset_loading_duration); |
| 1911 | + } |
| 1912 | + |
| 1913 | + double dumper_duration{}; |
| 1914 | + { |
| 1915 | + ScopedTimer dumper_timer{&dumper_duration}; |
| 1916 | + |
| 1917 | + std::unordered_set<FField*> dumped_fields; |
| 1918 | + // There will be tons of dumped fields so lets just reserve tons in order to speed things up a bit |
| 1919 | + dumped_fields.reserve(100000); |
| 1920 | + |
| 1921 | + bool is_below_425 = Unreal::Version::IsBelow(4, 25); |
| 1922 | + |
| 1923 | + // The final outputted string shouldn't need be reformatted just to put a new line at the end |
| 1924 | + // Instead the object/property implementations should add a new line in the last format that they do |
| 1925 | + // |
| 1926 | + // Optimizations done: |
| 1927 | + // 1. The entire code-base has been changed to use 'wchar_t' instead of 'char'. |
| 1928 | + // The effect of this is that there is no need to ever convert between types. |
| 1929 | + // There's also no thinking about which type should be used since 'wchar_t' is now the standard for UE4SS. |
| 1930 | + // The downside with wchar_t is that all files that get output to will be doubled in size. |
| 1931 | + |
| 1932 | + using ObjectDumperOutputDevice = Output::NewFileDevice; |
| 1933 | + Output::Targets<ObjectDumperOutputDevice> scoped_dumper_out; |
| 1934 | + auto& file_device = scoped_dumper_out.get_device<ObjectDumperOutputDevice>(); |
| 1935 | + file_device.set_file_name_and_path(output_path_and_file_name); |
| 1936 | + file_device.set_formatter([](File::StringViewType string) -> File::StringType { |
| 1937 | + return File::StringType{string}; |
| 1938 | + }); |
| 1939 | + |
| 1940 | + // Make string & reserve massive amounts of space to hopefully not reach the end of the string and require more |
| 1941 | + // dynamic allocations |
| 1942 | + StringType out_line; |
| 1943 | + out_line.reserve(200000000); |
| 1944 | + |
| 1945 | + Output::send(STR("Dumping all objects & properties in GUObjectArray\n")); |
| 1946 | + |
| 1947 | + out_line.append(STR("{\"general\":{\"filename\":\"sample.exe\",\"architecture\":\"x86\",\"bitness\":64},\"segments\":[{\"name\":\".text\",\"start_rva\":4096,\"type\":\"CODE\",\"selector\":1}],\"exports\":[],\"functions\":[],\"names\":[\n")); |
| 1948 | + |
| 1949 | + UObjectGlobals::ForEachUObject([&](void* object, [[maybe_unused]] int32_t chunk_index, [[maybe_unused]] int32_t object_index) { |
| 1950 | + |
| 1951 | + if (static_cast<UObject*>(object)->IsA<UFunction>()) |
| 1952 | + { |
| 1953 | + int32_t ii; |
| 1954 | + UFunction* f = (UFunction*)object; |
| 1955 | + if ((f->GetFunctionFlags() & 0x00000400) != 0) // FUNC_Native |
| 1956 | + { |
| 1957 | + if ( (ii = hCalc((char*)f->GetFuncPtr())) ) |
| 1958 | + { |
| 1959 | + std::wstring a, ws = f->GetFullName(); |
| 1960 | + size_t pos = ws.rfind(L'.'); |
| 1961 | + if (pos != std::wstring::npos) |
| 1962 | + { |
| 1963 | + a = ws.substr(pos + 1); |
| 1964 | + pos = a.find(L":"); |
| 1965 | + if (pos != std::wstring::npos) |
| 1966 | + { |
| 1967 | + a.replace(pos, 1, L"__"); |
| 1968 | + } |
| 1969 | + } |
| 1970 | + out_line.append( // "path": "{}",, p_typed_this->GetFullName() |
| 1971 | + fmt::format(STR("{{\"rva\": {},\"name\": \"{}\",\"is_public\": false,\"is_func\": false}},\n"), ii, a)); |
| 1972 | + } |
| 1973 | + } |
| 1974 | + } |
| 1975 | + return LoopAction::Continue; |
| 1976 | + }); |
| 1977 | + |
| 1978 | + out_line[out_line.size() - 2] = ']'; |
| 1979 | + out_line[out_line.size() - 1] = '}'; |
| 1980 | + |
| 1981 | + // save to file |
| 1982 | + scoped_dumper_out.send(out_line); |
| 1983 | + |
| 1984 | + // Reset the dumped_fields set, otherwise no fields will be dumped in subsequent dumps |
| 1985 | + dumped_fields.clear(); |
| 1986 | + Output::send(STR("Done iterating GUObjectArray\n")); |
| 1987 | + } |
| 1988 | + |
| 1989 | + UAssetRegistry::FreeAllForcefullyLoadedAssets(); |
| 1990 | + Output::send(STR("Dumping GUObjectArray took {} seconds\n"), dumper_duration); |
| 1991 | + // Object & Property Dumper -> END |
| 1992 | + } |
1898 | 1993 |
|
1899 | 1994 | auto UE4SSProgram::static_cleanup() -> void |
1900 | 1995 | { |
|
0 commit comments