Browse Source

Make Python.Cheat command more usable by not parsing its argument

The argument is now always treated as a plain string and passed directly
to the cheat. This is the behavior expected by all the functions in
xCheat.py, which parse the string argument manually where needed.

The previous implementation evaluated the argument value as a Python
expression. This theoretically allowed passing non-string arguments, but
none of the cheats use this (and it's also a potential code execution
issue). If no argument was passed, the function was called with no
arguments, which is also not supported by any of the cheats.

In practice, this required unintuitive syntax for calling the cheats
correctly, for example:

    Python.Cheat GetPlayerID None
    Python.Cheat GetSDL "'FirstWeekClothing'"

With the new argument handling, these have been simplified to:

    Python.Cheat GetPlayerID
    Python.Cheat GetSDL FirstWeekClothing
ticket/54
dgelessus 5 months ago
parent
commit
96facaa7bb
  1. 11
      Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp
  2. 42
      Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.cpp
  3. 4
      Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.h

11
Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp

@ -7061,17 +7061,12 @@ PF_CONSOLE_CMD( Python,
"string functions, ...", // Params
"Run a cheat command" )
{
std::string extraParms;
const char* extraParms = "";
if (numParams > 1)
{
extraParms = "(";
extraParms.append(params[1]);
extraParms.append(",)");
extraParms = params[1];
}
else
extraParms = "()";
PythonInterface::RunFunctionSafe("xCheat", params[0], extraParms.c_str());
PythonInterface::RunFunctionStringArg("xCheat", params[0], extraParms);
std::string output;
// get the messages

42
Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.cpp

@ -2102,38 +2102,32 @@ PyObject* PythonInterface::RunFunction(PyObject* module, const char* name, PyObj
return result;
}
PyObject* PythonInterface::ParseArgs(const char* args)
{
PyObject* result = NULL;
PyObject* scope = PyDict_New();
if (scope)
{
//- Py_eval_input makes this function accept only single expresion (not statement)
//- When using empty scope, functions and classes like 'file' or '__import__' are not visible
result = PyRun_String(args, Py_eval_input, scope, NULL);
Py_DECREF(scope);
}
return result;
}
bool PythonInterface::RunFunctionSafe(const char* module, const char* function, const char* args)
bool PythonInterface::RunFunctionStringArg(const char* module, const char* name, const char* arg)
{
PyObject* moduleObj = ImportModule(module);
bool result = false;
if (moduleObj)
{
PyObject* argsObj = ParseArgs(args);
if (argsObj)
PyObject* argObj = PyString_FromString(arg);
if (argObj)
{
PyObject* callResult = RunFunction(moduleObj, function, argsObj);
if (callResult)
PyObject* argsObj = PyTuple_New(1);
if (argsObj)
{
result = true;
Py_DECREF(callResult);
// PyTuple_SET_ITEM steals the reference to argObj.
PyTuple_SET_ITEM(argsObj, 0, argObj);
PyObject* callResult = RunFunction(moduleObj, name, argsObj);
if (callResult)
{
result = true;
Py_DECREF(callResult);
}
Py_DECREF(argsObj);
}
else
{
Py_DECREF(argObj);
}
Py_DECREF(argsObj);
}
Py_DECREF(moduleObj);
}

4
Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.h

@ -223,9 +223,7 @@ public:
static PyObject* RunFunction(PyObject* module, const char* name, PyObject* args);
static PyObject* ParseArgs(const char* args);
static bool RunFunctionSafe(const char* module, const char* function, const char* args);
static bool RunFunctionStringArg(const char* module, const char* name, const char* arg);
/////////////////////////////////////////////////////////////////////////////
//

Loading…
Cancel
Save