Skip to content

Commit 0d11108

Browse files
authored
Merge pull request godotengine#79126 from bruvzg/SteamTime
Enable optional minimal SteamAPI integration for usage time tracking (editor only).
2 parents 762c1fd + c34d646 commit 0d11108

File tree

5 files changed

+214
-0
lines changed

5 files changed

+214
-0
lines changed

SConstruct

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise e
254254
opts.Add(BoolVariable("scu_build", "Use single compilation unit build", False))
255255
opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determines RAM use)", "0")
256256
opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the Project Manager", True))
257+
opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False))
257258

258259
# Thirdparty libraries
259260
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))

main/SCsub

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ env_main = env.Clone()
1010

1111
env_main.add_source_files(env.main_sources, "*.cpp")
1212

13+
if env["steamapi"] and env.editor_build:
14+
env_main.Append(CPPDEFINES=["STEAMAPI_ENABLED"])
15+
1316
if env["tests"]:
1417
env_main.Append(CPPDEFINES=["TESTS_ENABLED"])
1518

main/main.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@
113113
#endif // DISABLE_DEPRECATED
114114
#endif // TOOLS_ENABLED
115115

116+
#if defined(STEAMAPI_ENABLED)
117+
#include "main/steam_tracker.h"
118+
#endif
119+
116120
#include "modules/modules_enabled.gen.h" // For mono.
117121

118122
#if defined(MODULE_MONO_ENABLED) && defined(TOOLS_ENABLED)
@@ -143,6 +147,10 @@ static ZipArchive *zip_packed_data = nullptr;
143147
#endif
144148
static MessageQueue *message_queue = nullptr;
145149

150+
#if defined(STEAMAPI_ENABLED)
151+
static SteamTracker *steam_tracker = nullptr;
152+
#endif
153+
146154
// Initialized in setup2()
147155
static AudioServer *audio_server = nullptr;
148156
static CameraServer *camera_server = nullptr;
@@ -2445,6 +2453,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
24452453

24462454
OS::get_singleton()->benchmark_end_measure("Startup", "Core");
24472455

2456+
#if defined(STEAMAPI_ENABLED)
2457+
if (editor || project_manager) {
2458+
steam_tracker = memnew(SteamTracker);
2459+
}
2460+
#endif
2461+
24482462
if (p_second_phase) {
24492463
return setup2();
24502464
}
@@ -2503,6 +2517,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
25032517
OS::get_singleton()->benchmark_end_measure("Startup", "Core");
25042518
OS::get_singleton()->benchmark_end_measure("Startup", "Setup");
25052519

2520+
#if defined(STEAMAPI_ENABLED)
2521+
if (steam_tracker) {
2522+
memdelete(steam_tracker);
2523+
}
2524+
#endif
2525+
25062526
OS::get_singleton()->finalize_core();
25072527
locale = String();
25082528

@@ -4336,6 +4356,12 @@ void Main::cleanup(bool p_force) {
43364356
message_queue->flush();
43374357
memdelete(message_queue);
43384358

4359+
#if defined(STEAMAPI_ENABLED)
4360+
if (steam_tracker) {
4361+
memdelete(steam_tracker);
4362+
}
4363+
#endif
4364+
43394365
unregister_core_driver_types();
43404366
unregister_core_extensions();
43414367
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);

main/steam_tracker.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**************************************************************************/
2+
/* steam_tracker.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#if defined(STEAMAPI_ENABLED)
32+
33+
#include "steam_tracker.h"
34+
35+
// https://partner.steamgames.com/doc/sdk/api#initialization_and_shutdown
36+
37+
SteamTracker::SteamTracker() {
38+
String path;
39+
if (OS::get_singleton()->has_feature("linuxbsd")) {
40+
path = OS::get_singleton()->get_executable_path().get_base_dir().path_join("libsteam_api.so");
41+
if (!FileAccess::exists(path)) {
42+
path = OS::get_singleton()->get_executable_path().get_base_dir().path_join("../lib").path_join("libsteam_api.so");
43+
if (!FileAccess::exists(path)) {
44+
return;
45+
}
46+
}
47+
} else if (OS::get_singleton()->has_feature("windows")) {
48+
if (OS::get_singleton()->has_feature("64")) {
49+
path = OS::get_singleton()->get_executable_path().get_base_dir().path_join("steam_api64.dll");
50+
} else {
51+
path = OS::get_singleton()->get_executable_path().get_base_dir().path_join("steam_api.dll");
52+
}
53+
if (!FileAccess::exists(path)) {
54+
return;
55+
}
56+
} else if (OS::get_singleton()->has_feature("macos")) {
57+
path = OS::get_singleton()->get_executable_path().get_base_dir().path_join("libsteam_api.dylib");
58+
if (!FileAccess::exists(path)) {
59+
path = OS::get_singleton()->get_executable_path().get_base_dir().path_join("../Frameworks").path_join("libsteam_api.dylib");
60+
if (!FileAccess::exists(path)) {
61+
return;
62+
}
63+
}
64+
} else {
65+
return;
66+
}
67+
68+
Error err = OS::get_singleton()->open_dynamic_library(path, steam_library_handle);
69+
if (err != OK) {
70+
steam_library_handle = nullptr;
71+
return;
72+
}
73+
print_verbose("Loaded SteamAPI library");
74+
75+
void *symbol_handle = nullptr;
76+
err = OS::get_singleton()->get_dynamic_library_symbol_handle(steam_library_handle, "SteamAPI_InitFlat", symbol_handle, true); // Try new API, 1.59+.
77+
if (err != OK) {
78+
err = OS::get_singleton()->get_dynamic_library_symbol_handle(steam_library_handle, "SteamAPI_Init", symbol_handle); // Try old API.
79+
if (err != OK) {
80+
return;
81+
}
82+
steam_init_function = (SteamAPI_InitFunction)symbol_handle;
83+
} else {
84+
steam_init_flat_function = (SteamAPI_InitFlatFunction)symbol_handle;
85+
}
86+
87+
err = OS::get_singleton()->get_dynamic_library_symbol_handle(steam_library_handle, "SteamAPI_Shutdown", symbol_handle);
88+
if (err != OK) {
89+
return;
90+
}
91+
steam_shutdown_function = (SteamAPI_ShutdownFunction)symbol_handle;
92+
93+
if (steam_init_flat_function) {
94+
char err_msg[1024] = {};
95+
steam_initalized = (steam_init_flat_function(&err_msg[0]) == SteamAPIInitResult_OK);
96+
} else if (steam_init_function) {
97+
steam_initalized = steam_init_function();
98+
}
99+
}
100+
101+
SteamTracker::~SteamTracker() {
102+
if (steam_shutdown_function && steam_initalized) {
103+
steam_shutdown_function();
104+
}
105+
if (steam_library_handle) {
106+
OS::get_singleton()->close_dynamic_library(steam_library_handle);
107+
}
108+
}
109+
110+
#endif // STEAMAPI_ENABLED

main/steam_tracker.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**************************************************************************/
2+
/* steam_tracker.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#ifndef STEAM_TRACKER_H
32+
#define STEAM_TRACKER_H
33+
34+
#if defined(STEAMAPI_ENABLED)
35+
36+
#include "core/os/os.h"
37+
38+
// SteamTracker is used to load SteamAPI dynamic library and initialize
39+
// the interface, this notifies Steam that Godot editor is running and
40+
// allow tracking of the usage time of child instances of the engine
41+
// (e.g., opened projects).
42+
//
43+
// Currently, SteamAPI is not used by the engine in any way, and is not
44+
// exposed to the scripting APIs.
45+
46+
enum SteamAPIInitResult {
47+
SteamAPIInitResult_OK = 0,
48+
SteamAPIInitResult_FailedGeneric = 1,
49+
SteamAPIInitResult_NoSteamClient = 2,
50+
SteamAPIInitResult_VersionMismatch = 3,
51+
};
52+
53+
// https://partner.steamgames.com/doc/api/steam_api#SteamAPI_Init
54+
typedef bool (*SteamAPI_InitFunction)();
55+
typedef SteamAPIInitResult (*SteamAPI_InitFlatFunction)(char *r_err_msg);
56+
57+
// https://partner.steamgames.com/doc/api/steam_api#SteamAPI_Shutdown
58+
typedef void (*SteamAPI_ShutdownFunction)();
59+
60+
class SteamTracker {
61+
void *steam_library_handle = nullptr;
62+
SteamAPI_InitFunction steam_init_function = nullptr;
63+
SteamAPI_InitFlatFunction steam_init_flat_function = nullptr;
64+
SteamAPI_ShutdownFunction steam_shutdown_function = nullptr;
65+
bool steam_initalized = false;
66+
67+
public:
68+
SteamTracker();
69+
~SteamTracker();
70+
};
71+
72+
#endif // STEAMAPI_ENABLED
73+
74+
#endif // STEAM_TRACKER_H

0 commit comments

Comments
 (0)