mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-05-07 23:20:26 +09:00
gsr-game-tracker: track native games and emulators (from ananicy-rules)
This commit is contained in:
@@ -144,6 +144,7 @@ executable(
|
||||
executable(
|
||||
'gsr-game-tracker',
|
||||
[
|
||||
'tools/gsr-game-tracker/native_games.c',
|
||||
'tools/gsr-game-tracker/main.c'
|
||||
],
|
||||
install : true
|
||||
|
||||
98
tools/gsr-game-tracker/create-native-games-list.py
Executable file
98
tools/gsr-game-tracker/create-native-games-list.py
Executable file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# Skips steam games and games that end with .x86_64, .x86 or .x64
|
||||
def extract_non_tracked_games(filepath):
|
||||
game_names = []
|
||||
with open(filepath, "r") as file:
|
||||
is_steam_game = False
|
||||
for line in file.readlines():
|
||||
if line.startswith("#"):
|
||||
is_steam_game = "steam" in line
|
||||
elif line.startswith("{") and not is_steam_game:
|
||||
game_name = json.loads(line)["name"]
|
||||
if not game_name.endswith(".x86_64") and not game_name.endswith(".x86") and not game_name.endswith(".x64"):
|
||||
game_names.append(json.loads(line)["name"])
|
||||
return game_names
|
||||
|
||||
def write_process_name_matcher_code_file(filepath, all_games):
|
||||
games_by_len = {}
|
||||
for game in all_games:
|
||||
l = games_by_len.get(len(game), [])
|
||||
l.append(game)
|
||||
games_by_len[len(game)] = l
|
||||
|
||||
with open(filepath, "w") as file:
|
||||
file.write(
|
||||
'#include "native_games.h"\n'
|
||||
'\n'
|
||||
'#include <string.h>\n'
|
||||
'\n'
|
||||
'/* This file was auto-generated with create-native-games-list.py, do not edit manually! */\n'
|
||||
'\n')
|
||||
|
||||
for game_len in games_by_len:
|
||||
games_quoted = ", ".join('"%s"' % game for game in games_by_len[game_len])
|
||||
file.write("static const char *process_names_len_%d[] = { %s, NULL };\n" % (game_len, games_quoted))
|
||||
|
||||
file.write("\n")
|
||||
file.write(
|
||||
"bool is_process_name_native_game(const char *process_name, size_t size) {\n"
|
||||
" switch(size) {\n")
|
||||
|
||||
for game_len in games_by_len:
|
||||
file.write(
|
||||
" case %d: {\n"
|
||||
" for(size_t i = 0; process_names_len_%d[i] != NULL; ++i) {\n"
|
||||
" if(memcmp(process_name, process_names_len_%d[i], size) == 0)\n"
|
||||
" return true;\n"
|
||||
" }\n"
|
||||
" return false;\n"
|
||||
" }\n" % (game_len, game_len, game_len))
|
||||
|
||||
file.write(
|
||||
" default: {\n"
|
||||
" return false;\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
)
|
||||
|
||||
def add_games_from_rules_filepath(filepath):
|
||||
games = extract_non_tracked_games(filepath)
|
||||
print("Scanning file: %s, num games found: %d" % (filepath, len(games)))
|
||||
return games
|
||||
|
||||
def add_games_from_rules_recursive(dir):
|
||||
games_added = []
|
||||
for folder, subfolders, files in os.walk(dir):
|
||||
for file in files:
|
||||
filepath = os.path.abspath(os.path.join(folder, file))
|
||||
games_added.extend(add_games_from_rules_filepath(filepath))
|
||||
return games_added
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("usage: create-native-games-list.py <path-to-ananicy-rules>")
|
||||
exit(1)
|
||||
|
||||
ananicy_root_path = sys.argv[1]
|
||||
ananicy_conf_path = os.path.join(ananicy_root_path, "ananicy.conf")
|
||||
if not os.path.exists(ananicy_conf_path):
|
||||
print("error: the path this script was launched with is not the ananicy-rules root directory (file %s doesn't exist)" % ananicy_conf_path)
|
||||
exit(1)
|
||||
|
||||
ananicy_native_games_path = os.path.join(ananicy_root_path, "00-default", "Games", "linux-native")
|
||||
ananicy_emulators_path = os.path.join(ananicy_root_path, "00-default", "Games", "emulators.rules")
|
||||
|
||||
all_games = []
|
||||
all_games.extend(add_games_from_rules_recursive(ananicy_native_games_path))
|
||||
all_games.extend(add_games_from_rules_filepath(ananicy_emulators_path))
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
write_process_name_matcher_code_file(os.path.join(script_dir, "native_games.c"), all_games)
|
||||
|
||||
main()
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "native_games.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
@@ -107,28 +109,30 @@ static bool memeql(const char *haystack, size_t haystack_size, const char *needl
|
||||
return haystack_size == needle_size && memcmp(haystack, needle, needle_size) == 0;
|
||||
}
|
||||
|
||||
static bool is_wine_binary(const char *argv0, size_t size) {
|
||||
const char *base = memchr_reverse(argv0, '/', size);
|
||||
static const char* process_get_basename(const char *argv0, size_t argv0_len, size_t *basename_len) {
|
||||
*basename_len = 0;
|
||||
const char *base = memchr_reverse(argv0, '/', argv0_len);
|
||||
base = base ? base + 1 : argv0;
|
||||
const size_t base_len = argv0 + size - base;
|
||||
return memeql(base, base_len, "wine") ||
|
||||
memeql(base, base_len, "wine64") ||
|
||||
memeql(base, base_len, "wine-preloader") ||
|
||||
memeql(base, base_len, "wine64-preloader");
|
||||
*basename_len = argv0 + argv0_len - base;
|
||||
return base;
|
||||
}
|
||||
|
||||
static bool is_wine_server(const char *argv0, size_t size) {
|
||||
const char *base = memchr_reverse(argv0, '/', size);
|
||||
base = base ? base + 1 : argv0;
|
||||
const size_t base_len = argv0 + size - base;
|
||||
return memeql(base, base_len, "wineserver");
|
||||
static bool is_wine_binary(const char *process_basename, size_t process_basename_len) {
|
||||
return memeql(process_basename, process_basename_len, "wine") ||
|
||||
memeql(process_basename, process_basename_len, "wine64") ||
|
||||
memeql(process_basename, process_basename_len, "wine-preloader") ||
|
||||
memeql(process_basename, process_basename_len, "wine64-preloader");
|
||||
}
|
||||
|
||||
static bool has_game_arch_suffix(const char *argv0, size_t size) {
|
||||
static bool is_wine_server(const char *process_basename, size_t process_basename_len) {
|
||||
return memeql(process_basename, process_basename_len, "wineserver");
|
||||
}
|
||||
|
||||
static bool has_game_arch_suffix(const char *process_basename, size_t process_basename_len) {
|
||||
static const char *suffixes[] = { ".x86_64", ".x64", ".x86" };
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const size_t slen = strlen(suffixes[i]);
|
||||
if (size >= slen && memcmp(argv0 + size - slen, suffixes[i], slen) == 0)
|
||||
if (process_basename_len >= slen && memcmp(process_basename + process_basename_len - slen, suffixes[i], slen) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -173,8 +177,15 @@ static void check_process(pid_t pid) {
|
||||
const char *argv1 = cmdline_buf + argv0_len + 1;
|
||||
const size_t argv1_len = (size_t)cmd_n > argv0_len + 1 ? get_argv_len(argv1, cmd_n - (argv0_len + 1)) : 0;
|
||||
|
||||
if (cmd_n > 0 && (is_wine_binary(argv0, argv0_len) || has_game_arch_suffix(argv0, argv0_len) || has_wine_env)
|
||||
&& !is_wine_server(argv0, argv0_len)
|
||||
size_t process_basename_len = 0;
|
||||
const char *process_basename = process_get_basename(argv0, argv0_len, &process_basename_len);
|
||||
|
||||
if (cmd_n > 0
|
||||
&& (is_wine_binary(process_basename, process_basename_len)
|
||||
|| has_game_arch_suffix(process_basename, process_basename_len)
|
||||
|| has_wine_env
|
||||
|| is_process_name_native_game(process_basename, process_basename_len))
|
||||
&& !is_wine_server(process_basename, process_basename_len)
|
||||
&& !memeql(argv1, argv1_len, "--version")
|
||||
&& (!is_steam_app || steam_overlay_game_id != NULL))
|
||||
{
|
||||
|
||||
174
tools/gsr-game-tracker/native_games.c
Normal file
174
tools/gsr-game-tracker/native_games.c
Normal file
@@ -0,0 +1,174 @@
|
||||
#include "native_games.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* This file was auto-generated with create-native-games-list.py, do not edit manually! */
|
||||
|
||||
static const char *process_names_len_12[] = { "soh.appimage", "supertuxkart", "HytaleClient", "DDNet-Server", "Vintagestory", "ut-bin-amd64", "fs-uae-devel", "xenia_canary", "shadPS4:Main", NULL };
|
||||
static const char *process_names_len_5[] = { "sober", "DDNet", "zdoom", "cen64", "mesen", "higan", "rpcs3", NULL };
|
||||
static const char *process_names_len_14[] = { "sober_services", "chocolate-doom", "CodenameEngine", "quakespasm-svn", "2ship.appimage", "rott-shareware", "unreal-bin-x86", "PPSSPPHeadless", NULL };
|
||||
static const char *process_names_len_15[] = { "UnleashedRecomp", "CoherentUI_Host", "linux_64_client", "rott-registered", "UnrealLinux.bin", "Quake3-UrT.i386", "DuckStation-x64", NULL };
|
||||
static const char *process_names_len_10[] = { "sm64coopdx", "luanti.bin", "quakespasm", "srcds_i486", "rbdoom3bfg", "tyr-glqwcl", "ut-bin-x86", NULL };
|
||||
static const char *process_names_len_6[] = { "luanti", "Mobbos", "glhwcl", "hexen2", "dhewm3", "Funkin", "quake2", "gzdoom", "quake3", "ecwolf", "ut-bin", "fs-uae", "dosbox", NULL };
|
||||
static const char *process_names_len_11[] = { "PsychEngine", "devilutionx", "d1x-rebirth", "d2x-rebirth", "Kade Engine", "tyr-glquake", "xonotic-glx", "xonotic-sdl", "dolphin-emu", NULL };
|
||||
static const char *process_names_len_8[] = { "glhexen2", "alephone", "openrct2", "freesynd", "riot-web", "rottexpr", "tyr-qwcl", "ioquake3", "ironwail", "vkquake2", "cen64-qt", "mednafen", "PPSSPPQt", "pcsx2-qt", NULL };
|
||||
static const char *process_names_len_4[] = { "hwcl", "osu!", "rott", "xemu", "cemu", "suyu", "yuzu", "eden", "mame", NULL };
|
||||
static const char *process_names_len_9[] = { "openmohaa", "omohaaded", "berkelium", "cefsimple", "srcds_run", "tyr-quake", "iortcw-mp", "iortcw-sp", "xenia.exe", "retroarch", "mesen-git", "PPSSPPSDL", NULL };
|
||||
static const char *process_names_len_21[] = { "launch_openmohaa_base", NULL };
|
||||
static const char *process_names_len_29[] = { "launch_openmohaa_breakthrough", NULL };
|
||||
static const char *process_names_len_26[] = { "launch_openmohaa_spearhead", NULL };
|
||||
static const char *process_names_len_13[] = { "yamagi-quake2", NULL };
|
||||
static const char *process_names_len_17[] = { "yamagi-quake2-git", "Zelda64Recompiled", "xonotic-local-sdl", NULL };
|
||||
static const char *process_names_len_3[] = { "0ad", "etl", "RMG", NULL };
|
||||
static const char *process_names_len_2[] = { "fm", "et", NULL };
|
||||
static const char *process_names_len_7[] = { "Etterna", "etterna", "vkquake", "melonDS", "ryujinx", "sdlmame", "scummvm", "blastem", "redream", "shadps4", NULL };
|
||||
static const char *process_names_len_18[] = { "VintagestoryServer", NULL };
|
||||
static const char *process_names_len_16[] = { "unreal-bin-amd64", "xenia_canary.exe", NULL };
|
||||
|
||||
bool is_process_name_native_game(const char *process_name, size_t size) {
|
||||
switch(size) {
|
||||
case 12: {
|
||||
for(size_t i = 0; process_names_len_12[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_12[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 5: {
|
||||
for(size_t i = 0; process_names_len_5[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_5[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 14: {
|
||||
for(size_t i = 0; process_names_len_14[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_14[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 15: {
|
||||
for(size_t i = 0; process_names_len_15[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_15[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 10: {
|
||||
for(size_t i = 0; process_names_len_10[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_10[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 6: {
|
||||
for(size_t i = 0; process_names_len_6[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_6[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 11: {
|
||||
for(size_t i = 0; process_names_len_11[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_11[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 8: {
|
||||
for(size_t i = 0; process_names_len_8[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_8[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 4: {
|
||||
for(size_t i = 0; process_names_len_4[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_4[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 9: {
|
||||
for(size_t i = 0; process_names_len_9[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_9[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 21: {
|
||||
for(size_t i = 0; process_names_len_21[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_21[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 29: {
|
||||
for(size_t i = 0; process_names_len_29[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_29[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 26: {
|
||||
for(size_t i = 0; process_names_len_26[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_26[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 13: {
|
||||
for(size_t i = 0; process_names_len_13[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_13[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 17: {
|
||||
for(size_t i = 0; process_names_len_17[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_17[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 3: {
|
||||
for(size_t i = 0; process_names_len_3[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_3[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 2: {
|
||||
for(size_t i = 0; process_names_len_2[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_2[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 7: {
|
||||
for(size_t i = 0; process_names_len_7[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_7[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 18: {
|
||||
for(size_t i = 0; process_names_len_18[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_18[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 16: {
|
||||
for(size_t i = 0; process_names_len_16[i] != NULL; ++i) {
|
||||
if(memcmp(process_name, process_names_len_16[i], size) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
tools/gsr-game-tracker/native_games.h
Normal file
10
tools/gsr-game-tracker/native_games.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef NATIVE_GAMES_H
|
||||
#define NATIVE_GAMES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Checks for native games (or emulators) that are not steam games and neither ends with .x86_64, .x86 or .x64 */
|
||||
bool is_process_name_native_game(const char *process_name, size_t size);
|
||||
|
||||
#endif /* NATIVE_GAMES_H */
|
||||
Reference in New Issue
Block a user