Skip to content

Instantly share code, notes, and snippets.

@MCJack123
Last active January 24, 2024 21:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MCJack123/e3a6b8dfc5cb0e1525252e8e5cd5fa8e to your computer and use it in GitHub Desktop.
Save MCJack123/e3a6b8dfc5cb0e1525252e8e5cd5fa8e to your computer and use it in GitHub Desktop.
Counter-Strike Source Discord RPC program (probably VAC safe, Linux only)
#include <discord.h>
#include <iostream>
#include <fstream>
#include <string>
#include <filesystem>
#include <thread>
#include <chrono>
namespace fs = std::filesystem;
static discord::Core* core{};
static discord::Activity activity;
static bool connected = true;
static int64_t client_id = // ID HERE
template<typename T>
T getMem_(std::ifstream& handle, uint32_t offset) {
T retval;
handle.seekg(offset, std::ios::cur);
handle.read((char*)&retval, sizeof(T));
//std::cout << "\n";
return retval;
}
template<>
std::string getMem_<std::string>(std::ifstream& handle, uint32_t offset) {
std::string retval;
handle.seekg(offset, std::ios::cur);
std::getline(handle, retval, '\0');
//std::cout << "\n";
return retval;
}
template<typename T, typename... Args>
T getMem_(std::ifstream& handle, uint32_t offset, Args... args) {
uint32_t addr = 0;
handle.seekg(offset, std::ios::cur);
handle.read((char*)&addr, 4);
//std::cout << addr << " ";
handle.seekg(addr, std::ios::beg);
return getMem_<T>(handle, args...);
}
template<typename T, typename... Args>
T getMem(std::ifstream& handle, uint32_t start, Args... args) {
handle.seekg(start, std::ios::beg);
//std::cout << start << " ";
return getMem_<T>(handle, args...);
}
int main() {
std::cout << "Looking for CS: Source...\n";
int pid = 0;
fs::path proc("/proc"), pdir;
while (!pid) {
for (const auto& dir : fs::directory_iterator(proc)) {
if (dir.is_directory()) {
std::ifstream in(dir.path() / "cmdline");
if (!in) continue;
std::string name;
std::getline(in, name);
in.close();
if (name.find("hl2_linux") != std::string::npos) {
pid = std::stoi(dir.path().filename());
pdir = dir;
std::cout << "Found PID: " << pid << "\n";
break;
}
}
}
if (!pid) std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Connecting to Discord...\n";
discord::Result result;
if ((result = discord::Core::Create(client_id, DiscordCreateFlags_Default, &core)) != discord::Result::Ok) {
connected = false;
std::cerr << "Could not connect to Discord: " << (int)result << "\n";
return (int)result;
}
std::cout << "Connected.\n";
activity.SetApplicationId(client_id);
activity.SetName("Counter-Strike Source");
activity.SetType(discord::ActivityType::Playing);
activity.SetState("Initializing");
activity.GetAssets().SetLargeImage("de_dust");
activity.GetAssets().SetSmallImage("game");
bool ready = false;
core->ActivityManager().UpdateActivity(activity, [&ready](discord::Result res){ready = true;});
while (!ready) core->RunCallbacks();
uint32_t GameUI = 0, ServerBrowser = 0, server = 0, client = 0, engine = 0;
std::ifstream maps(pdir / "maps");
if (!maps) {
std::cerr << "Could not open memory map\n";
return 3;
}
while (!maps.eof()) {
std::string line;
std::getline(maps, line);
if (line.find("/bin/GameUI.so") != std::string::npos && line.find("r-xp") != std::string::npos) {
GameUI = std::stoul(line.substr(0, 8), NULL, 16);
std::cout << "GameUI is at " << GameUI << "\n";
} else if (line.find("/bin/ServerBrowser.so") != std::string::npos && line.find("r-xp") != std::string::npos) {
ServerBrowser = std::stoul(line.substr(0, 8), NULL, 16);
std::cout << "ServerBrowser is at " << ServerBrowser << "\n";
} else if (line.find("/bin/client.so") != std::string::npos && line.find("r-xp") != std::string::npos) {
client = std::stoul(line.substr(0, 8), NULL, 16);
std::cout << "client is at " << client << "\n";
} else if (line.find("/bin/server.so") != std::string::npos && line.find("r-xp") != std::string::npos) {
server = std::stoul(line.substr(0, 8), NULL, 16);
std::cout << "server is at " << server << "\n";
} else if (line.find("/bin/engine.so") != std::string::npos && line.find("r-xp") != std::string::npos) {
engine = std::stoul(line.substr(0, 8), NULL, 16);
std::cout << "engine is at " << engine << "\n";
}
}
maps.close();
if (GameUI == 0 || ServerBrowser == 0 || server == 0 || client == 0 || engine == 0) {
std::cerr << "Could not find required pointers\n";
return 2;
}
std::ifstream mem(pdir / "mem");
if (!mem) {
std::cerr << "Could not open memory\n";
return 3;
}
while (fs::exists(pdir)) {
mem.clear();
std::string serverName = getMem<std::string>(mem, engine, 0x371312, 0x8, 0x0);
std::string mapName = getMem<std::string>(mem, engine, 0x2ad692, 0x24, 0x0);
std::cout << serverName << " - " << mapName << "\n";
float gameTime = getMem<float>(mem, server, 0x25896b, 0x0, 0x3c, 0x2ac);
float roundTime = getMem<float>(mem, server, 0x25934e, 0x2c);
uint16_t ctScore = getMem<uint16_t>(mem, server, 0x25896b, 0x0, 0x3c, 0x290);
uint16_t tScore = getMem<uint16_t>(mem, server, 0x25896b, 0x0, 0x3c, 0x292);
uint32_t health = getMem<uint32_t>(mem, client, 0xbea61c, 0x54, 0x1ac);
uint32_t money = getMem<uint32_t>(mem, server, 0xad5a5c, 0x14, 0x1190);
std::string team = getMem<std::string>(mem, server, 0x3b34ac, 0x0);
std::string state = "Playing as " + team + " (" + std::to_string(ctScore) + "-" + std::to_string(tScore) + ")";
std::string healthstr = std::to_string(health) + " HP - $" + std::to_string(money);
activity.GetAssets().SetLargeImage(mapName.c_str());
activity.GetAssets().SetLargeText(mapName.c_str());
activity.GetAssets().SetSmallText(healthstr.c_str());
activity.SetState(state.c_str());
activity.GetTimestamps().SetStart(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - (int64_t)(gameTime * 1000));
activity.GetTimestamps().SetEnd(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - (int64_t)(gameTime * 1000) + (int64_t)(roundTime * 60000));
bool ready = false;
core->ActivityManager().UpdateActivity(activity, [&ready](discord::Result res){
if (res == discord::Result::NotRunning) {
fprintf(stderr, "Discord disconnected. Restart CraftOS-PC to reconnect.\n");
connected = false;
}
ready = true;
});
while (!ready) core->RunCallbacks();
//std::cout << serverName << " " << mapName << "\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment