Hey there,
Things were a little boring lately, exams, life... This brings us back to developing hard days.
If you're still interested into developing SRO, yo dude, this thread is for you.
The goal of the thread won't be that useful for servers as a gameplay, I mean, it will be useful as for staff members only, since they should be the only people who use the console.
What Can I Use This For: Basically, you can do more stuff controlling the server if you have got your own filter or emulator, and you know how to do the communication between the client and the server. But remember to check user's primary & content group before doing the command job, or normal players will play around with media, open console and cheat.
Background Work: Well, searching this could be one of the easiest things you may try to find, the first & correct idea should be in your mind is looking for an existing command name in sro_client strings, and yeah, that's it.
Basically, the client has a list of existing commands, it's loaded on sro_client loading. So, we can hook the function that loads commands and load our custom commands with it, pretty simple. Here's a final output of my code,
Note: I used florian's hooking lib to hook, if you wanna use it, you'll find it in the attachments.
IFConsole.h:
IFConsole.cpp:
Note: Any addresses given above were found on VSRO 1.88 sro_client, so they are most likely different on any other version.
Note: Structures above are for VC80 libs, back when string/wstring was 28 bytes.
Note: Always compile on Release!
Special thanks to: florian0 :rolleyes:
Things were a little boring lately, exams, life... This brings us back to developing hard days.
If you're still interested into developing SRO, yo dude, this thread is for you.
| Introduction Video | |
|
|
|
The goal of the thread won't be that useful for servers as a gameplay, I mean, it will be useful as for staff members only, since they should be the only people who use the console.
What Can I Use This For: Basically, you can do more stuff controlling the server if you have got your own filter or emulator, and you know how to do the communication between the client and the server. But remember to check user's primary & content group before doing the command job, or normal players will play around with media, open console and cheat.
Background Work: Well, searching this could be one of the easiest things you may try to find, the first & correct idea should be in your mind is looking for an existing command name in sro_client strings, and yeah, that's it.
Basically, the client has a list of existing commands, it's loaded on sro_client loading. So, we can hook the function that loads commands and load our custom commands with it, pretty simple. Here's a final output of my code,
Note: I used florian's hooking lib to hook, if you wanna use it, you'll find it in the attachments.
IFConsole.h:
Code:
#pragma once
#include <Windows.h>
#include <iostream>
#include <vector>
typedef bool (CALLBACK ConsoleCommandFunc)(class ConsoleCommandData*);
static std::vector<std::pair<const wchar_t*, ConsoleCommandFunc*>> CustomConsoleCommands;
class ConsoleCommandData
{
public:
char pad_0000[68]; //0x0000
const wchar_t* FullCommand; //0x0044
};
class CIFConsole
{
public:
static void InitializeCustomCommands();
void OnCommandsLoading();
void AddCommand(std::wstring commandmaintext, ConsoleCommandFunc* func, int a3);
};
Code:
#include "IFConsole.h"
#include "hook.h"
#include "Global.h"
static bool CALLBACK MyCuteTestingFunc(ConsoleCommandData* cmddata)
{
wchar_t buffer[255];
swprintf_s(buffer, L"Custom Command Debuggging, Command Entered Text: (%s).", cmddata->FullCommand);
IngameDebug(buffer);
return true; // return key success
}
void CIFConsole::InitializeCustomCommands(void)
{
replaceOffset(0x0055A027, addr_from_this(&CIFConsole::OnCommandsLoading));
CustomConsoleCommands.push_back(std::pair<const wchar_t*, ConsoleCommandFunc*>(L"HelloWorld", MyCuteTestingFunc));
}
void CIFConsole::OnCommandsLoading(void)
{
for (auto i = CustomConsoleCommands.begin(); i != CustomConsoleCommands.end(); i++)
{
this->AddCommand(i->first, i->second, 0);
}
reinterpret_cast<void(__thiscall*)(CIFConsole*)>(0x00558910)(this);
}
void CIFConsole::AddCommand(std::wstring commandmaintext, ConsoleCommandFunc* func, int a3)
{
reinterpret_cast<void(__thiscall*)(CIFConsole*, std::wstring, ConsoleCommandFunc*, int)>(0x00555DB0)(this, commandmaintext, func, a3);
}
Note: Structures above are for VC80 libs, back when string/wstring was 28 bytes.
Note: Always compile on Release!
Special thanks to: florian0 :rolleyes: