Console without 100 if Statements

Posts 1–10 of 10 · Page 1 of 1
Console without 100 if Statements
I saw a bunch of people who released a "Console" that just used 100 ifs to check if the Command exist. I didn't want to do that so I thought of something else.


First of all we need a ArrayList with the commands and the offset for that command (Seperated by an '=').
[C#]!!

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace Vorlage
{
    class Program
    {
        static void Main(string[] args)
        {
            //------------------------------------------
            ArrayList commands = new ArrayList();
            commands.Add("title=0x10055BD0");
            commands.Add("support=0x10055CAC");
            Console.WriteLine("Waiting for Command to execute...\n");
        }
Now we have to add something to the code above so we can use our ArrayList in the Method.
Code:
Check(commands);
Now the actual Method:
Code:
static void Check(ArrayList commands)
        {
            while (true)
            {
What do we need?
-A string (query) that reads the entered command.
-Byte(_byte) to zero out the value before writing to it
-Another string(offset) to grab the offset from the ArrayList(commands)
-A Memory Class (Credits to Jorndel)
So:
Code:
Trainer_Class Proc = new Trainer_Class();
                Proc.Process_Handle("iw5mp");
                byte[] _byte = new byte[0xFF];
                string query = Console.ReadLine();
                string offset = null;
How should the user even enter a command?
We expect that the user enters something like:
set <command> <value>
So we need to grab the value from the query to write it to the address later. To do that we first remove the "set ".
set = 3 space = 1. 3+1=4. Obviously. Start Index is 0 ofcourse.
Code:
 string value = query.Remove(0, 4);               //removes "set " from query
Now it looks like this:
<command> <value>
We have to remove everything before the first Space(' ') now.
Code:
value = value.Substring(value.IndexOf(' ') + 1); //removes <command> from query
So we got the blank value now. Now we have to compare if the entered command(the query) even exist in the ArrayList(commands).
We already know that the query looks like:
set <command> <value>. So something like:
set title drizzle
We also know that the ArrayList entry look like:
title=0x10055BD0
So we can compare the red marked things. We have to remove the "set ", <value> from the query and the =0x10055BD0 from the ArrayList.
First the query:
Code:
string bridge = query.Remove(0, 4);              //removes "set " from query
                bridge = bridge.Remove(bridge.IndexOf(' '));     //removes <value> from query
Since we got an ArrayList we need an foreach loop.
Code:
 bool exist = false;
                foreach (string str in commands)
                {
                    if (str.Remove(str.IndexOf('=')) == bridge)
                    {
                        offset = str.Substring(str.IndexOf('=') + 1);
                        exist = true;
                        break;
                    }
                }
So foreach entry in the ArrayList(commands) it removes the = and the offset from the string(str) to compare it to the bridge(query - "set ", <value>). If they're equal we set the bool exist to true and break the loop. Otherwise it just stays on false.
Now we're almost done. We just need to check now if our bool exist is == true or == false. If it's true it prints out "Command found and Successfully executed." and uses the value we just defined above and the offset to write to the process. If not it prints out "Command not found.". But currently the offset is an string. We need an int for the address. So we need to convert a string hex to an int hex(thanks bio).
Code:
  if (exist == true)
                {
                    int i = Convert.ToInt32(offset, 16);  //string hex -> int hex
                    Proc.WriteBytes(i, _byte); //Zero value out first
                    Proc.WriteString(i, value);
                    Console.WriteLine("Command found and Successfully executed.");
                    
                }
                else
                {
                    Console.WriteLine("Command not found.");
                }
            }
I hope I was able to help you. That kinda was the only thought I had to prevent people from using 1000 if's. The benefit of my method now is that you dont have to add a if statement everytime you add a command. Just add it to the ArrayList e.g:
mycommandname=myoffset

Full Code:
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace Vorlage
{
    class Program
    {
        static void Main(string[] args)
        {
            //------------------------------------------
            ArrayList commands = new ArrayList();
            commands.Add("title=0x10055BD0");
            commands.Add("support=0x10055CAC");
            Console.WriteLine("Waiting for Command to execute...\n");
            Check(commands);
        }
        /*
            * Expected:
            * set <command> <value>
        */
        static void Check(ArrayList commands)
        {
            while (true)
            {
                Trainer_Class Proc = new Trainer_Class();
                Proc.Process_Handle("iw5mp");
                byte[] _byte = new byte[0xFF];
                string query = Console.ReadLine();
                string offset = null;

                string value = query.Remove(0, 4);               //removes "set " from query
                value = value.Substring(value.IndexOf(' ') + 1); //removes <command> from query
                string bridge = query.Remove(0, 4);              //removes "set " from query
                bridge = bridge.Remove(bridge.IndexOf(' '));     //removes <value> from query
                bool exist = false;
                foreach (string str in commands)
                {
                    if (str.Remove(str.IndexOf('=')) == bridge)
                    {
                        offset = str.Substring(str.IndexOf('=') + 1);
                        exist = true;
                        break;
                    }
                }
                if (exist == true)
                {
                    int i = Convert.ToInt32(offset, 16);  //string hex -> int hex
                    Proc.WriteBytes(i, _byte);
                    Proc.WriteString(i, value);
                    Console.WriteLine("Command found and Successfully executed.");
                    
                }
                else
                {
                    Console.WriteLine("Command not found.");
                }
            }
        }
    }
}
EDIT:
Move please. Wrong section by accident.
Or just do it like mw3 and all quake games.

Code:
typedef void(*xfunction)();


typedef struct cmd_s
{
    char* name;
    xfunction callback;
    cmd_s* next;
} cmd_t;
static cmd_t *cmds = nullptr;


auto* Cmd_AddCommand(char* name, xfunction cb){
    auto c = cmds;
    if(!c){
        c = new cmd_s();
        c->name = name;
        c->function = cb;
        return c;
   }
   
   while(c->next){
       if(!strcmp(c->name, name))
           return c;
       c = c->next;
   }
   
   c = new cmd_s();
   c->name = name;
   c->function = cb;
   
   return c;
}




auto* Cmd_FindCommand(char* name){
    auto c = cmds;
    
    while(c && c->next){
        if(!strcmp(c->name, name))
            return c;
    }
    return nullptr;
}


void Cmd_RemoveCommand(char* name){
    auto c = cmds;
    auto c2 = c;
    
    while(c && c2 && c->next){
        if(!strcmp(c->name, name)){
            c2->next = c->next;
Code:
            delete c;
            break;
        }
        c2 = c;
        c = c->next;
    }
}


void Cmd_ExecuteSingle(char* str)
{
    Cmd_TokenizeString( str );
    
    auto c = cmds;
    while(c){
        if(!stricmp(c->name, Cmd_Argv(0))){
            c->function();
            break;
        }
        c = c->next;
    }
    
    Cmd_EndTokenizeString(  );
}

^


With some C++ help that could look way better. Some operator overloading and you can just pass through a structure containing the name of the command and a callback function.

Or make it look something like this:

Code:
Console c;

c.AddCommand("help", HelpCallback);
c.RemoveCommand("help");
c.EditCommand("help", NewCallback);
I may optimize it later. This was like just to give people an idea how they could make it.
Made it a bit easier:

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Trainer__Class;
namespace Vorlage2
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
              * Expected:
              * set <command> <value>
            */
            string[] commands = { "title=0x10055BD0", "support=0x10055CAC" };
            Console.WriteLine("Waiting for Command to execute...\n");
            Check(commands);
        }
        static void Check(string[] commands)
        {
            while (true)
            {
                Trainer_Class Proc = new Trainer_Class();
                Proc.Process_Handle("iw5mp");
                string query = Console.ReadLine();
                string[] query_split = null;
                string[] commands_split = null;
                string value = null;
                int offset = 0;
                byte[] _byte = new byte[0xFF];
                bool exist = false;
                foreach (string command in commands)
                {
                    query_split = query.Split(' ');
                    commands_split = command.Split('=');
                    if (query_split[1] == commands_split[0])
                    {
                        exist = true;
                        break;
                    }
                }
                if (exist == true)
                {
                    value = query_split[2];
                    offset = Convert.ToInt32(commands_split[1], 16);
                    Proc.WriteBytes(offset, _byte);
                    Proc.WriteString(offset, value);
                    Console.WriteLine("Command found and Successfully executed.");
                }
                else Console.WriteLine("Command not found.");
            }
        }
    }
}
Here's a quick C++ version that I just coded up:

Code:
//! Command-line Manager - Simple
//! code to show how to manage
//! command parsing and issuing

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <functional>

using std::string;
using std::vector;
using std::map;
using std::function;

using Callback = function<void()>;

map<string, Callback> g_Callbacks;

const char DELIMETER = ' ';

//! the lexer to break the command
//! into the different elements
void break_string(const string& str,
                  vector<string>& elements)
{
    string temp; // used to store each element

    for(auto it = str.cbegin(); it != str.cend(); ++it)
    {
        if(it == str.cend() - 1)
        {
            temp += *it;
            elements.push_back(temp);
            return;
        }

        if(*it == DELIMETER)
        {
            elements.push_back(temp);
            temp.clear();
        } else
        {
            temp += *it;
        }
    }
}

//! lex then parse the string in order
//! to call the corresponding callback
void execute_cmd(const string& cmd)
{
    if(cmd.length() < 1)
    {
        throw std::invalid_argument("[!] <execute_cmd> Bad command issued (length)");
    }

    vector<string> elements;
    break_string(cmd, elements);

    for(auto it = g_Callbacks.cbegin(); it != g_Callbacks.cend(); ++it)
    {
        if(it->first == elements.at(0))
        {
            it->second();
            return;
        }
    }

    throw std::runtime_error("[!] <execute_cmd> Could not identify command");
}

void test_exit()
{
    std::printf("exiting..\r\n");
}

int main(int, char**)
{
    try
    {

        g_Callbacks["exit"] = test_exit;

        string cmd = std::string();

        std::cout << "> " << std::endl;
        std::cin >> cmd;

        execute_cmd(cmd);

    } catch(const std::exception& error)
    {
        std::cout << error.what() << std::endl;
    }

    return EXIT_SUCCESS;
}

Of course you can make some improvements such as wrapping it in a single class for one instance of a ConsoleCommandHandler (bad name). Plus there isn't any support for passing in any arguments into the callback functions (you might need that).
Quote Originally Posted by maktm View Post
Here's a quick C++ version that I just coded up:

Code:
//! Command-line Manager - Simple
//! code to show how to manage
//! command parsing and issuing

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <functional>

using std::string;
using std::vector;
using std::map;
using std::function;

using Callback = function<void()>;

map<string, Callback> g_Callbacks;

const char DELIMETER = ' ';

//! the lexer to break the command
//! into the different elements
void break_string(const string& str,
                  vector<string>& elements)
{
    string temp; // used to store each element

    for(auto it = str.cbegin(); it != str.cend(); ++it) {
        if(it == str.cend() - 1) {
            temp += *it;
            elements.push_back(temp);
            return;
        }

        if(*it == DELIMETER) {
            elements.push_back(temp);
            temp.clear();
        } else {
            temp += *it;
        }
    }
}

//! lex then parse the string in order
//! to call the corresponding callback
void execute_cmd(const string& cmd)
{
    if(cmd.length() < 1)
    {
        throw std::invalid_argument("[!] <execute_cmd> Bad command issued (length)");
    }

    vector<string> elements;
    break_string(cmd, elements);

    for(auto it = g_Callbacks.cbegin(); it != g_Callbacks.cend(); ++it) {
        if(it->first == cmd) {
            it->second();
            return;
        }
    }

    throw std::runtime_error("[!] <execute_cmd> Could not identify command");
}

void test_exit()
{
    std::printf("exiting..\r\n");
}

int main(int, char**)
{
    try
    {

        g_Callbacks["exit"] = test_exit;

        string cmd = std::string();

        std::cout << "> " << std::endl;
        std::cin >> cmd;

        execute_cmd(cmd);

    }
    catch(const std::exception& error)
    {
        std::cout << error.what() << std::endl;
    }

    return EXIT_SUCCESS;
}

Of course you can make some improvements such as wrapping it in a single class for one instance of a ConsoleCommandHandler (bad name). Plus there isn't any support for passing in any arguments into the callback functions (you might need that).
That'll be a rather heavy payload including all that stuff.

The C version I posted ( Well it uses C++11 keywords ) is smaller and faster.
Quote Originally Posted by Hitokiri~ View Post

That'll be a rather heavy payload including all that stuff.

The C version I posted ( Well it uses C++11 keywords ) is smaller and faster.
I wrote mine with ease of use in mind, not performance/size. You can always combine the two, create your own containers (which you shouldn't do since you're reinventing the wheel but if you want you can), then overload some useful operators (assignment for callback addition) to get a compromise between the two.
Quote Originally Posted by maktm View Post
I wrote mine with ease of use in mind, not performance/size. You can always combine the two, create your own containers (which you shouldn't do since you're reinventing the wheel but if you want you can), then overload some useful operators (assignment for callback addition) to get a compromise between the two.
What's so hard about doing:

Code:
Cmd_AddCommand( "screenshot", screenshot_f );
Quote Originally Posted by Hitokiri~ View Post


What's so hard about doing:

Code:
Cmd_AddCommand( "screenshot", screenshot_f );
Didn't read the whole thing and assumed your use of C (mostly) would affect ease of use.
But wrapping this in a class can make everything convenient. f.e. you can easily add another
handler with code like this:

Code:
instance["cmd"] += handler;
You'd simply overload 2 operators and it could all look cleaner.
Posts 1–10 of 10 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Talk with us