mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-27 05:04:01 +08:00
* load the icons of a single achievement each overlay callback invokation, will slow things down during startup
but this avoids having to load the achievement icon during gameplay which causes micro-stutter * avoid loading and resizing the achievement icon each time it's unlocked * Local_Storage: avoid allocating buffers unless `stbi_load()` was successfull
This commit is contained in:
parent
37426bac82
commit
0b86464374
@ -1,9 +1,10 @@
|
||||
# 2024/3/11
|
||||
* manage overlay cursor input/clipping and internal frame processing in a better way,
|
||||
should prevent more games from pausing to display notifications
|
||||
* allow notifications of these types to steal/obscure input:
|
||||
- `notification_type_message`
|
||||
- `notification_type_invite`
|
||||
* load the icons of a single achievement each overlay callback invokation, will slow things down during startup
|
||||
but this avoids having to load the achievement icon during gameplay which causes micro-stutter
|
||||
* avoid loading and resizing the achievement icon each time it's unlocked
|
||||
* Local_Storage: avoid allocating buffers unless `stbi_load()` was successfull
|
||||
|
||||
---
|
||||
|
||||
|
@ -839,24 +839,23 @@ std::vector<image_pixel_t> Local_Storage::load_image(std::string const& image_pa
|
||||
std::string Local_Storage::load_image_resized(std::string const& image_path, std::string const& image_data, int resolution)
|
||||
{
|
||||
std::string resized_image{};
|
||||
char *resized_img = (char*)malloc(sizeof(char) * resolution * resolution * 4);
|
||||
PRINT_DEBUG("Local_Storage::load_image_resized: %s for resized image (%i)\n", (resized_img == nullptr ? "could not allocate memory" : "memory allocated"), (resolution * resolution * 4));
|
||||
const size_t resized_img_size = resolution * resolution * 4;
|
||||
|
||||
if (resized_img != nullptr) {
|
||||
if (image_path.length() > 0) {
|
||||
int width, height;
|
||||
unsigned char *img = stbi_load(image_path.c_str(), &width, &height, nullptr, 4);
|
||||
PRINT_DEBUG("Local_Storage::load_image_resized: \"%s\" %s\n", image_path.c_str(), (img == nullptr ? stbi_failure_reason() : "loaded"));
|
||||
if (img != nullptr) {
|
||||
stbir_resize_uint8(img, width, height, 0, (unsigned char*)resized_img, resolution, resolution, 0, 4);
|
||||
resized_image = std::string(resized_img, resolution * resolution * 4);
|
||||
stbi_image_free(img);
|
||||
}
|
||||
} else if (image_data.length() > 0) {
|
||||
stbir_resize_uint8((unsigned char*)image_data.c_str(), 184, 184, 0, (unsigned char*)resized_img, resolution, resolution, 0, 4);
|
||||
resized_image = std::string(resized_img, resolution * resolution * 4);
|
||||
if (image_path.length() > 0) {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
unsigned char *img = stbi_load(image_path.c_str(), &width, &height, nullptr, 4);
|
||||
PRINT_DEBUG("Local_Storage::load_image_resized: stbi_load %s '%s'\n", (img == nullptr ? stbi_failure_reason() : "loaded"), image_path.c_str());
|
||||
if (img != nullptr) {
|
||||
std::vector<char> out_resized(resized_img_size);
|
||||
stbir_resize_uint8(img, width, height, 0, (unsigned char*)&out_resized[0], resolution, resolution, 0, 4);
|
||||
resized_image = std::string((char*)&out_resized[0], out_resized.size());
|
||||
stbi_image_free(img);
|
||||
}
|
||||
free(resized_img);
|
||||
} else if (image_data.length() > 0) {
|
||||
std::vector<char> out_resized(resized_img_size);
|
||||
stbir_resize_uint8((unsigned char*)image_data.c_str(), 184, 184, 0, (unsigned char*)&out_resized[0], resolution, resolution, 0, 4);
|
||||
resized_image = std::string((char*)&out_resized[0], out_resized.size());
|
||||
}
|
||||
|
||||
reset_LastError();
|
||||
|
@ -5,6 +5,13 @@
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
#ifdef EMU_OVERLAY
|
||||
|
||||
#include <future>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include "InGameOverlay/RendererHook.h"
|
||||
|
||||
static constexpr size_t max_chat_len = 768;
|
||||
|
||||
enum window_state
|
||||
@ -81,17 +88,12 @@ struct Overlay_Achievement
|
||||
std::weak_ptr<uint64_t> icon;
|
||||
std::weak_ptr<uint64_t> icon_gray;
|
||||
|
||||
// avoids spam loading on failure
|
||||
constexpr const static int ICON_LOAD_MAX_TRIALS = 3;
|
||||
uint8_t icon_load_trials = ICON_LOAD_MAX_TRIALS;
|
||||
uint8_t icon_gray_load_trials = ICON_LOAD_MAX_TRIALS;
|
||||
};
|
||||
|
||||
#ifdef EMU_OVERLAY
|
||||
|
||||
#include <future>
|
||||
#include <atomic>
|
||||
#include "InGameOverlay/RendererHook.h"
|
||||
|
||||
struct NotificationsIndexes
|
||||
{
|
||||
int top_left = 0, top_center = 0, top_right = 0;
|
||||
@ -100,6 +102,8 @@ struct NotificationsIndexes
|
||||
|
||||
class Steam_Overlay
|
||||
{
|
||||
constexpr static const char ACH_FALLBACK_DIR[] = "achievement_images";
|
||||
|
||||
Settings* settings;
|
||||
SteamCallResults* callback_results;
|
||||
SteamCallBacks* callbacks;
|
||||
@ -110,13 +114,17 @@ class Steam_Overlay
|
||||
std::map<Friend, friend_window_state, Friend_Less> friends;
|
||||
|
||||
// avoids spam loading on failure
|
||||
std::atomic<int32_t> load_achievements_trials = 3;
|
||||
constexpr const static int LOAD_ACHIEVEMENTS_MAX_TRIALS = 3;
|
||||
std::atomic<int32_t> load_achievements_trials = LOAD_ACHIEVEMENTS_MAX_TRIALS;
|
||||
bool is_ready = false;
|
||||
bool show_overlay;
|
||||
ENotificationPosition notif_position;
|
||||
int h_inset, v_inset;
|
||||
std::string show_url;
|
||||
std::vector<Overlay_Achievement> achievements;
|
||||
// index of the next achievement whose icons will be loaded
|
||||
// used by the callback
|
||||
int next_ach_to_load = 0;
|
||||
bool show_achievements, show_settings;
|
||||
|
||||
// disable input when force_*.txt file is used
|
||||
@ -205,6 +213,9 @@ class Steam_Overlay
|
||||
|
||||
bool open_overlay_hook(bool toggle);
|
||||
|
||||
bool try_load_ach_icon(Overlay_Achievement &ach);
|
||||
bool try_load_ach_gray_icon(Overlay_Achievement &ach);
|
||||
|
||||
public:
|
||||
Steam_Overlay(Settings* settings, SteamCallResults* callback_results, SteamCallBacks* callbacks, RunEveryRunCB* run_every_runcb, Networking *network);
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
#include <utility>
|
||||
|
||||
#include "InGameOverlay/ImGui/imgui.h"
|
||||
|
||||
#include "dll/dll.h"
|
||||
@ -565,23 +567,24 @@ bool Steam_Overlay::submit_notification(notification_type type, const std::strin
|
||||
|
||||
notifications.emplace_back(notif);
|
||||
allow_renderer_frame_processing(true);
|
||||
switch (type) {
|
||||
// we want to steal focus for these ones
|
||||
case notification_type_message:
|
||||
case notification_type_invite:
|
||||
obscure_cursor_input(true);
|
||||
break;
|
||||
// uncomment this block to obscure cursor input and steal focus for these specific notifications
|
||||
// switch (type) {
|
||||
// // we want to steal focus for these ones
|
||||
// case notification_type_message:
|
||||
// case notification_type_invite:
|
||||
// obscure_cursor_input(true);
|
||||
// break;
|
||||
|
||||
// not effective
|
||||
case notification_type_achievement:
|
||||
case notification_type_auto_accept_invite:
|
||||
// nothing
|
||||
break;
|
||||
// // not effective
|
||||
// case notification_type_achievement:
|
||||
// case notification_type_auto_accept_invite:
|
||||
// // nothing
|
||||
// break;
|
||||
|
||||
default:
|
||||
PRINT_DEBUG("Steam_Overlay::submit_notification error unhandled type %i\n", (int)type);
|
||||
break;
|
||||
}
|
||||
// default:
|
||||
// PRINT_DEBUG("Steam_Overlay::submit_notification error unhandled type %i\n", (int)type);
|
||||
// break;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -869,16 +872,16 @@ void Steam_Overlay::build_notifications(int width, int height)
|
||||
}
|
||||
|
||||
// some extra window flags for each notification type
|
||||
ImGuiWindowFlags extra_flags = 0;
|
||||
ImGuiWindowFlags extra_flags = ImGuiWindowFlags_NoFocusOnAppearing;
|
||||
switch (it->type) {
|
||||
// games like "Mafia Definitive Edition" will pause the entire game/scene if focus was stolen
|
||||
// be less intrusive for notifications that do not require interaction
|
||||
case notification_type_achievement:
|
||||
case notification_type_auto_accept_invite:
|
||||
extra_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoInputs;
|
||||
case notification_type_message:
|
||||
extra_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoInputs;
|
||||
break;
|
||||
|
||||
case notification_type_message:
|
||||
case notification_type_invite:
|
||||
// nothing
|
||||
break;
|
||||
@ -947,23 +950,24 @@ void Steam_Overlay::build_notifications(int width, int height)
|
||||
if ((now - item.start_time) > Notification::show_time) {
|
||||
PRINT_DEBUG("Steam_Overlay::build_notifications removing a notification\n");
|
||||
allow_renderer_frame_processing(false);
|
||||
switch (item.type) {
|
||||
// we want to restore focus for these ones
|
||||
case notification_type_message:
|
||||
case notification_type_invite:
|
||||
obscure_cursor_input(false);
|
||||
break;
|
||||
// uncomment this block to restore app input focus
|
||||
// switch (item.type) {
|
||||
// // we want to restore focus for these ones
|
||||
// case notification_type_message:
|
||||
// case notification_type_invite:
|
||||
// obscure_cursor_input(false);
|
||||
// break;
|
||||
|
||||
// not effective
|
||||
case notification_type_achievement:
|
||||
case notification_type_auto_accept_invite:
|
||||
// nothing
|
||||
break;
|
||||
// // not effective
|
||||
// case notification_type_achievement:
|
||||
// case notification_type_auto_accept_invite:
|
||||
// // nothing
|
||||
// break;
|
||||
|
||||
default:
|
||||
PRINT_DEBUG("Steam_Overlay::build_notifications error unhandled remove for type %i\n", (int)item.type);
|
||||
break;
|
||||
}
|
||||
// default:
|
||||
// PRINT_DEBUG("Steam_Overlay::build_notifications error unhandled remove for type %i\n", (int)item.type);
|
||||
// break;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1019,6 +1023,62 @@ void Steam_Overlay::invite_friend(uint64 friend_id, class Steam_Friends* steamFr
|
||||
}
|
||||
}
|
||||
|
||||
bool Steam_Overlay::try_load_ach_icon(Overlay_Achievement &ach)
|
||||
{
|
||||
if (!_renderer) return false;
|
||||
if (!ach.icon.expired()) return true;
|
||||
|
||||
if (ach.icon_load_trials && ach.icon_name.size()) {
|
||||
--ach.icon_load_trials;
|
||||
std::string file_path = std::move(Local_Storage::get_game_settings_path() + ach.icon_name);
|
||||
unsigned long long file_size = file_size_(file_path);
|
||||
if (!file_size) {
|
||||
file_path = std::move(Local_Storage::get_game_settings_path() + Steam_Overlay::ACH_FALLBACK_DIR + "/" + ach.icon_name);
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
if (file_size) {
|
||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
||||
if (img.length() > 0) {
|
||||
ach.icon = _renderer->CreateImageResource(
|
||||
(void*)img.c_str(),
|
||||
settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
||||
if (!ach.icon.expired()) ach.icon_load_trials = Overlay_Achievement::ICON_LOAD_MAX_TRIALS;
|
||||
PRINT_DEBUG("Steam_Overlay::try_load_ach_icon '%s' (result=%i)\n", ach.name.c_str(), (int)!ach.icon.expired());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !ach.icon.expired();
|
||||
}
|
||||
|
||||
bool Steam_Overlay::try_load_ach_gray_icon(Overlay_Achievement &ach)
|
||||
{
|
||||
if (!_renderer) return false;
|
||||
if (!ach.icon_gray.expired()) return true;
|
||||
|
||||
if (ach.icon_gray_load_trials && ach.icon_gray_name.size()) {
|
||||
--ach.icon_gray_load_trials;
|
||||
std::string file_path = std::move(Local_Storage::get_game_settings_path() + ach.icon_gray_name);
|
||||
unsigned long long file_size = file_size_(file_path);
|
||||
if (!file_size) {
|
||||
file_path = std::move(Local_Storage::get_game_settings_path() + Steam_Overlay::ACH_FALLBACK_DIR + "/" + ach.icon_gray_name);
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
if (file_size) {
|
||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
||||
if (img.length() > 0) {
|
||||
ach.icon_gray = _renderer->CreateImageResource(
|
||||
(void*)img.c_str(),
|
||||
settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
||||
if (!ach.icon_gray.expired()) ach.icon_gray_load_trials = Overlay_Achievement::ICON_LOAD_MAX_TRIALS;
|
||||
PRINT_DEBUG("Steam_Overlay::try_load_ach_gray_icon '%s' (result=%i)\n", ach.name.c_str(), (int)!ach.icon_gray.expired());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !ach.icon_gray.expired();
|
||||
}
|
||||
|
||||
// Try to make this function as short as possible or it might affect game's fps.
|
||||
void Steam_Overlay::overlay_proc()
|
||||
{
|
||||
@ -1157,38 +1217,8 @@ void Steam_Overlay::overlay_proc()
|
||||
bool achieved = x.achieved;
|
||||
bool hidden = x.hidden && !achieved;
|
||||
|
||||
if (x.icon.expired() && x.icon_load_trials) {
|
||||
--x.icon_load_trials;
|
||||
std::string file_path = Local_Storage::get_game_settings_path() + x.icon_name;
|
||||
unsigned long long file_size = file_size_(file_path);
|
||||
if (!file_size) {
|
||||
file_path = Local_Storage::get_game_settings_path() + "achievement_images/" + x.icon_name;
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
if (file_size) {
|
||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
||||
if (img.length() > 0) {
|
||||
if (_renderer) x.icon = _renderer->CreateImageResource((void*)img.c_str(), settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
||||
if (!x.icon.expired()) x.icon_load_trials = Overlay_Achievement::ICON_LOAD_MAX_TRIALS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x.icon_gray.expired() && x.icon_gray_load_trials) {
|
||||
--x.icon_gray_load_trials;
|
||||
std::string file_path = Local_Storage::get_game_settings_path() + x.icon_gray_name;
|
||||
unsigned long long file_size = file_size_(file_path);
|
||||
if (!file_size) {
|
||||
file_path = Local_Storage::get_game_settings_path() + "achievement_images/" + x.icon_gray_name;
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
if (file_size) {
|
||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
||||
if (img.length() > 0) {
|
||||
if (_renderer) x.icon_gray = _renderer->CreateImageResource((void*)img.c_str(), settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
||||
if (!x.icon_gray.expired()) x.icon_gray_load_trials = Overlay_Achievement::ICON_LOAD_MAX_TRIALS;
|
||||
}
|
||||
}
|
||||
}
|
||||
try_load_ach_icon(x);
|
||||
try_load_ach_gray_icon(x);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
@ -1397,8 +1427,15 @@ void Steam_Overlay::UnSetupOverlay()
|
||||
if (_renderer) {
|
||||
PRINT_DEBUG("Steam_Overlay::UnSetupOverlay will free any images resources\n");
|
||||
for (auto &ach : achievements) {
|
||||
if (!ach.icon.expired()) _renderer->ReleaseImageResource(ach.icon);
|
||||
if (!ach.icon_gray.expired()) _renderer->ReleaseImageResource(ach.icon_gray);
|
||||
if (!ach.icon.expired()) {
|
||||
_renderer->ReleaseImageResource(ach.icon);
|
||||
ach.icon.reset();
|
||||
}
|
||||
|
||||
if (!ach.icon_gray.expired()) {
|
||||
_renderer->ReleaseImageResource(ach.icon_gray);
|
||||
ach.icon_gray.reset();
|
||||
}
|
||||
}
|
||||
|
||||
_renderer = nullptr;
|
||||
@ -1567,12 +1604,15 @@ void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||
if (!Ready()) return;
|
||||
|
||||
std::vector<Overlay_Achievement*> found_achs{};
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock2(global_mutex);
|
||||
|
||||
std::string ach_name = ach.value("name", std::string());
|
||||
for (auto &a : achievements) {
|
||||
if (a.name == ach_name) {
|
||||
found_achs.push_back(&a);
|
||||
|
||||
bool achieved = false;
|
||||
uint32 unlock_time = 0;
|
||||
get_steam_client()->steam_user_stats->GetAchievementAndUnlockTime(a.name.c_str(), &achieved, &unlock_time);
|
||||
@ -1583,32 +1623,16 @@ void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
||||
}
|
||||
|
||||
if (!settings->disable_overlay_achievement_notification) {
|
||||
// Load achievement image
|
||||
std::weak_ptr<uint64_t> icon_rsrc{};
|
||||
std::string icon_path = ach.value("icon", std::string());
|
||||
if (icon_path.size()) {
|
||||
std::string file_path{};
|
||||
unsigned long long file_size = 0;
|
||||
file_path = Local_Storage::get_game_settings_path() + icon_path;
|
||||
file_size = file_size_(file_path);
|
||||
if (!file_size) {
|
||||
file_path = Local_Storage::get_game_settings_path() + "achievement_images/" + icon_path;
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
if (file_size) {
|
||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
||||
if (img.length() > 0) {
|
||||
icon_rsrc = _renderer->CreateImageResource((void*)img.c_str(), settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
||||
}
|
||||
}
|
||||
for (auto found_ach : found_achs) {
|
||||
try_load_ach_icon(*found_ach);
|
||||
submit_notification(
|
||||
notification_type_achievement,
|
||||
ach.value("displayName", std::string()) + "\n" + ach.value("description", std::string()),
|
||||
{},
|
||||
found_ach->icon
|
||||
);
|
||||
}
|
||||
|
||||
submit_notification(
|
||||
notification_type_achievement,
|
||||
ach.value("displayName", std::string()) + "\n" + ach.value("description", std::string()),
|
||||
{},
|
||||
icon_rsrc
|
||||
);
|
||||
notify_sound_user_achievement();
|
||||
}
|
||||
}
|
||||
@ -1648,7 +1672,7 @@ void Steam_Overlay::RunCallbacks()
|
||||
if (achievements_num) {
|
||||
PRINT_DEBUG("Steam_Overlay POPULATE OVERLAY ACHIEVEMENTS\n");
|
||||
for (unsigned i = 0; i < achievements_num; ++i) {
|
||||
Overlay_Achievement ach;
|
||||
Overlay_Achievement ach{};
|
||||
ach.name = steamUserStats->GetAchievementName(i);
|
||||
ach.title = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "name");
|
||||
ach.description = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "desc");
|
||||
@ -1676,15 +1700,24 @@ void Steam_Overlay::RunCallbacks()
|
||||
}
|
||||
|
||||
// don't punish successfull attempts
|
||||
if (achievements.size()) {
|
||||
++load_achievements_trials;
|
||||
}
|
||||
PRINT_DEBUG("Steam_Overlay POPULATE OVERLAY ACHIEVEMENTS DONE\n");
|
||||
if (achievements.size()) load_achievements_trials = Steam_Overlay::LOAD_ACHIEVEMENTS_MAX_TRIALS;
|
||||
PRINT_DEBUG("Steam_Overlay POPULATE OVERLAY ACHIEVEMENTS DONE (count=%lu, loaded=%zu)\n", achievements_num, achievements.size());
|
||||
}
|
||||
}
|
||||
|
||||
if (!Ready()) return;
|
||||
|
||||
// load images/icons for the next ach
|
||||
if (next_ach_to_load < achievements.size()) {
|
||||
try_load_ach_icon(achievements[next_ach_to_load]);
|
||||
try_load_ach_gray_icon(achievements[next_ach_to_load]);
|
||||
|
||||
++next_ach_to_load;
|
||||
// this allows the callback to keep trying forever in case the image resource was reset
|
||||
// each icon has a limit though, so it won't slow things down forever
|
||||
if (next_ach_to_load >= achievements.size()) next_ach_to_load = 0;
|
||||
}
|
||||
|
||||
if (overlay_state_changed) {
|
||||
overlay_state_changed = false;
|
||||
|
||||
|
@ -1,9 +1,16 @@
|
||||
; global font size
|
||||
Font_Size 13.5
|
||||
; achievement icon size
|
||||
Icon_Size 64.0
|
||||
|
||||
; spacing between characters
|
||||
Font_Glyph_Extra_Spacing_x 1.0
|
||||
Font_Glyph_Extra_Spacing_y 0.0
|
||||
|
||||
; increase these values by 1 if the font is blurry
|
||||
Font_Oversample_H 1
|
||||
Font_Oversample_V 1
|
||||
|
||||
Notification_R 0.16
|
||||
Notification_G 0.29
|
||||
Notification_B 0.48
|
||||
|
@ -1,36 +0,0 @@
|
||||
# modified version of ColdClientLoader originally by Rat431
|
||||
[SteamClient]
|
||||
# path to game exe, absolute or relative to the loader
|
||||
Exe=my_app.exe
|
||||
# empty means the folder of the exe
|
||||
ExeRunDir=
|
||||
# any additional args to pass, ex: -dx11, also any args passed to the loader will be passed to the app
|
||||
ExeCommandLine=
|
||||
# IMPORTANT
|
||||
AppId=123
|
||||
|
||||
# path to the steamclient dlls, both must be set,
|
||||
# absolute paths or relative to the loader
|
||||
SteamClientDll=steamclient.dll
|
||||
SteamClient64Dll=steamclient64.dll
|
||||
|
||||
# force inject steamclient dll instead of waiting for the app to load it
|
||||
ForceInjectSteamClient=0
|
||||
|
||||
[Debug]
|
||||
# don't call `ResumeThread()` on the main thread after spawning the .exe
|
||||
ResumeByDebugger=0
|
||||
|
||||
[Extra]
|
||||
# path to a folder containing some dlls to inject into the app upon start
|
||||
# this folder will be traversed recursively
|
||||
# additionally, inside this folder you can create a file called `load_order.txt` and
|
||||
# inside it, specify line by line the order of the dlls that have to be injected
|
||||
# each line should be a relative path of the dll, relative to the injection folder
|
||||
DllsToInjectFolder=extra_dlls.EXAMPLE
|
||||
# don't display an error message when a dll injection fails
|
||||
IgnoreInjectionError=0
|
||||
# don't display an error message if the architecture of the loader is different from the app
|
||||
# this will result in a silent failure if a dll injection didn't succeed
|
||||
# both the loader and the app must have the same arch for the injection to work
|
||||
IgnoreLoaderArchDifference=0
|
Loading…
Reference in New Issue
Block a user