1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-18 11:19:10 +00:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
jwplatt
2011-03-12 12:34:52 -05:00
commit b970ae4bad
3976 changed files with 1301355 additions and 0 deletions

View File

@ -0,0 +1,281 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "PythonInterface.h"
#include "compile.h"
#include "eval.h"
#include "marshal.h"
#include "cStringIO.h"
static PyObject* stdFile; // python object of the stdout and err file
void PythonInterface::initPython(std::string rootDir)
{
// if haven't been initialized then do it
if ( Py_IsInitialized() == 0 )
{
// initialize the Python stuff
// let Python do some intialization...
Py_SetProgramName("plasma");
Py_Initialize();
// intialize any of our special plasma python modules
// initP2PInterface();
// save object to the Plasma module
// plasmaMod = PyImport_ImportModule("Plasma");
// create the StringIO for the stdout and stderr file
PycStringIO = (struct PycStringIO_CAPI*)PyCObject_Import("cStringIO", "cStringIO_CAPI");
stdFile = (*PycStringIO->NewOutput)(20000);
// if we need the builtins then find the builtin module
PyObject* sysmod = PyImport_ImportModule("sys");
// then add the builtin dicitionary to our module's dictionary
if (sysmod != NULL )
{
// get the sys's dictionary to find the stdout and stderr
PyObject* sys_dict = PyModule_GetDict(sysmod);
if (stdFile != nil)
{
PyDict_SetItemString(sys_dict,"stdout", stdFile);
PyDict_SetItemString(sys_dict,"stderr", stdFile);
}
// NOTE: we will reset the path to not include paths
// ...that Python may have found in the registery
PyObject* path_list = PyList_New(0);
printf("Setting up include dirs:\n");
printf("%s\n",rootDir.c_str());
PyObject* more_path = PyString_FromString(rootDir.c_str());
PyList_Append(path_list, more_path);
// make sure that our plasma libraries are gotten before the system ones
std::string temp = rootDir + "plasma";
printf("%s\n",temp.c_str());
PyObject* more_path3 = PyString_FromString(temp.c_str());
PyList_Append(path_list, more_path3);
temp = rootDir + "system";
printf("%s\n\n",temp.c_str());
PyObject* more_path2 = PyString_FromString("system");
PyList_Append(path_list, more_path2);
// set the path to be this one
PyDict_SetItemString(sys_dict,"path",path_list);
Py_DECREF(sysmod);
}
}
// initialized++;
}
void PythonInterface::addPythonPath(std::string path)
{
PyObject* sysmod = PyImport_ImportModule("sys");
if (sysmod != NULL)
{
PyObject* sys_dict = PyModule_GetDict(sysmod);
PyObject* path_list = PyDict_GetItemString(sys_dict, "path");
printf("Adding path %s\n", path.c_str());
PyObject* more_path = PyString_FromString(path.c_str());
PyList_Append(path_list, more_path);
Py_DECREF(sysmod);
}
}
void PythonInterface::finiPython()
{
if (Py_IsInitialized() != 0)
{
Py_Finalize();
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : CompileString
// PARAMETERS : command - string of commands to execute in the...
// : filename - filename to say where to code came from
//
// PURPOSE : run a python string in a specific module name
//
PyObject* PythonInterface::CompileString(char *command, char* filename)
{
PyObject* pycode = Py_CompileString(command, filename, Py_file_input);
return pycode;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : DumpObject
// PARAMETERS : pyobject - string of commands to execute in the...
//
// PURPOSE : marshals an object into a char string
//
hsBool PythonInterface::DumpObject(PyObject* pyobj, char** pickle, Int32* size)
{
PyObject *s; // the python string object where the marsalled object wil go
// convert object to a marshalled string python object
s = PyMarshal_WriteObjectToString(pyobj);
// did it actually do it?
if ( s != NULL )
{
// yes, then get the size and the string address
*size = PyString_Size(s);
*pickle = PyString_AsString(s);
return true;
}
else // otherwise, there was an error
{
// Yikes! errors!
PyErr_Print(); // FUTURE: we may have to get the string to display in max...later
return false;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : getOutputAndReset
// PARAMETERS : none
//
// PURPOSE : get the Output to the error file to be displayed
//
int PythonInterface::getOutputAndReset(char** line)
{
PyObject* pyStr = (*PycStringIO->cgetvalue)(stdFile);
char *str = PyString_AsString( pyStr );
int size = PyString_Size( pyStr );
// reset the file back to zero
PyObject_CallMethod(stdFile,"reset","");
/*
// check to see if the debug python module is loaded
if ( dbgOut != nil )
{
// then send it the new text
if ( PyObject_CallFunction(dbgOut,"s",str) == nil )
{
// for some reason this function didn't, remember that and not call it again
dbgOut = nil;
// if there was an error make sure that the stderr gets flushed so it can be seen
PyErr_Print(); // make sure the error is printed
PyErr_Clear(); // clear the error
}
}
*/
if (line)
*line = str;
return size;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : CreateModule
// PARAMETERS : module - module name to create
//
// PURPOSE : create a new module with built-ins
//
PyObject* PythonInterface::CreateModule(char* module)
{
PyObject *m, *d;
// first we must get rid of any old modules of the same name, we'll replace it
PyObject *modules = PyImport_GetModuleDict();
if ((m = PyDict_GetItemString(modules, module)) != NULL && PyModule_Check(m))
// clear it
_PyModule_Clear(m);
// create the module
m = PyImport_AddModule(module);
if (m == NULL)
return nil;
d = PyModule_GetDict(m);
// add in the built-ins
// first make sure that we don't already have the builtins
if (PyDict_GetItemString(d, "__builtins__") == NULL)
{
// if we need the builtins then find the builtin module
PyObject *bimod = PyImport_ImportModule("__builtin__");
// then add the builtin dicitionary to our module's dictionary
if (bimod == NULL || PyDict_SetItemString(d, "__builtins__", bimod) != 0)
return nil;
Py_DECREF(bimod);
}
return m;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : RunPYC
// PARAMETERS : code - compiled code
// : module - module name to run the code in
//
// PURPOSE : run a compiled python code in a specific module name
//
hsBool PythonInterface::RunPYC(PyObject* code, PyObject* module)
{
PyObject *d, *v;
// make sure that we're given a good module... or at least one with an address
if ( !module )
{
// if no module was given then use just use the main module
module = PyImport_AddModule("__main__");
if (module == NULL)
return false;
}
// get the dictionaries for this module
d = PyModule_GetDict(module);
// run the string
v = PyEval_EvalCode((PyCodeObject*)code, d, d);
// check for errors and print them
if (v == NULL)
{
// Yikes! errors!
PyErr_Print();
return false;
}
Py_DECREF(v);
if (Py_FlushLine())
PyErr_Clear();
return true;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetModuleItem
// PARAMETERS : item - what item in the plasma module to get
//
// PURPOSE : get an item (probably a function) from a specific module
//
PyObject* PythonInterface::GetModuleItem(char* item, PyObject* module)
{
if ( module )
{
PyObject* d = PyModule_GetDict(module);
return PyDict_GetItemString(d, item);
}
return nil;
}

View File

@ -0,0 +1,43 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "Python.h"
#include <string>
namespace PythonInterface
{
void initPython(std::string rootDir);
void finiPython();
// So the Python packer can add extra paths
void addPythonPath(std::string dir);
PyObject* CompileString(char *command, char* filename);
hsBool DumpObject(PyObject* pyobj, char** pickle, Int32* size);
int getOutputAndReset(char** line=nil);
PyObject* CreateModule(char* module);
hsBool RunPYC(PyObject* code, PyObject* module);
PyObject* GetModuleItem(char* item, PyObject* module);
}

View File

@ -0,0 +1,451 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsStream.h"
#include "../plFile/hsFiles.h"
#include "PythonInterface.h"
#include <vector>
#include <string>
#include <direct.h>
static const char* kPackFileName = "python.pak";
static const char* kGlueFile = ".\\plasma\\glue.py";
static char* glueFile = (char*)kGlueFile;
void WritePythonFile(const char *fileName, const char* path, hsStream *s)
{
hsUNIXStream pyStream, glueStream;
char* pathAndFile = new char[strlen(fileName)+strlen(path)+2];
strcpy(pathAndFile,path);
char lastchar = pathAndFile[strlen(pathAndFile)-1];
if (lastchar != '\\' && lastchar != '/')
strcat(pathAndFile, "\\");
strcat(pathAndFile,fileName);
if (!pyStream.Open(pathAndFile) || !glueStream.Open(glueFile))
{
printf("Unable to open path %s, ",pathAndFile);
return;
}
printf("==Packing %s, ",fileName);
pyStream.FastFwd();
UInt32 pyFileSize = pyStream.GetPosition();
pyStream.Rewind();
glueStream.FastFwd();
UInt32 glueFileSize = glueStream.GetPosition();
glueStream.Rewind();
UInt32 totalSize = pyFileSize + glueFileSize + 2;
char *code = new char[totalSize];
UInt32 amountRead = pyStream.Read(pyFileSize, code);
hsAssert(amountRead == pyFileSize, "Bad read");
code[pyFileSize] = '\n';
amountRead = glueStream.Read(glueFileSize, code+pyFileSize+1);
hsAssert(amountRead == glueFileSize, "Bad read");
code[totalSize-1] = '\0';
// remove the CRs, they seem to give Python heartburn
int k = 0;
for (int i = 0; i < totalSize; i++)
{
if (code[i] != '\r') // is it not a CR?
code[k++] = code[i];
// else
// skip the CRs
}
PyObject* pythonCode = PythonInterface::CompileString(code, (char*)fileName);
if (pythonCode)
{
// we need to find out if this is PythonFile module
// create a module name... with the '.' as an X
// and create a python file name that is without the ".py"
char* modulename = new char[strlen(fileName)+1];
char* pythonfilename = new char[strlen(fileName)+1];
int j;
for (j=0; j<strlen(fileName); j++)
{
if (fileName[j] == '.')
{
modulename[j] = 'X';
pythonfilename[j] = '\0';
}
else
{
modulename[j] = fileName[j];
pythonfilename[j] = fileName[j];
}
}
modulename[j] = '\0';
PyObject* fModule = PythonInterface::CreateModule(modulename);
delete [] modulename;
// run the code
if (PythonInterface::RunPYC(pythonCode, fModule) )
{
// set the name of the file (in the global dictionary of the module)
PyObject* dict = PyModule_GetDict(fModule);
PyObject* pfilename = PyString_FromString(pythonfilename);
PyDict_SetItemString(dict, "glue_name", pfilename);
// next we need to:
// - create instance of class
PyObject* getID = PythonInterface::GetModuleItem("glue_getBlockID",fModule);
hsBool foundID = false;
if ( getID!=nil && PyCallable_Check(getID) )
{
PyObject* id = PyObject_CallFunction(getID,nil);
if ( id && PyInt_Check(id) )
foundID = true;
}
if ( foundID == false ) // then there was an error or no ID or somethin'
{
// oops, this is not a PythonFile modifier
// re-read the source and compile it without the glue code this time
memset(code,0,totalSize);
pyStream.Rewind();
amountRead = pyStream.Read(pyFileSize, code);
hsAssert(amountRead == pyFileSize, "Bad read");
strcat(code,"\n");
k = 0;
for (int i = 0; i < strlen(code)+1; i++)
{
if (code[i] != '\r') // is it not a CR?
code[k++] = code[i];
// else
// skip the CRs
}
pythonCode = PythonInterface::CompileString(code, (char*)fileName);
hsAssert(pythonCode,"Not sure why this didn't compile the second time???");
printf("an import file ");
}
else
printf("a PythonFile modifier(tm) ");
}
else
{
printf("......blast! Error during run-code!\n");
s->WriteSwap32(0);
char* errmsg;
int chars_read = PythonInterface::getOutputAndReset(&errmsg);
if (chars_read > 0)
{
printf(errmsg);
printf("\n");
}
}
delete [] pythonfilename;
}
// make sure that we have code to save
if (pythonCode)
{
Int32 size;
char* pycode;
PythonInterface::DumpObject(pythonCode,&pycode,&size);
printf("\n");
// print any message after each module
char* errmsg;
int chars_read = PythonInterface::getOutputAndReset(&errmsg);
if (chars_read > 0)
{
printf(errmsg);
printf("\n");
}
s->WriteSwap32(size);
s->Write(size, pycode);
}
else
{
printf("......blast! Compile error!\n");
s->WriteSwap32(0);
PyErr_Print();
PyErr_Clear();
char* errmsg;
int chars_read = PythonInterface::getOutputAndReset(&errmsg);
if (chars_read > 0)
{
printf(errmsg);
printf("\n");
}
}
delete [] code;
delete [] pathAndFile; // all done with the path and filename as one
pyStream.Close();
glueStream.Close();
}
void FindFiles(std::vector<std::string> &filenames, std::vector<std::string> &pathnames, const char* path)
{
// Get the names of all the python files
hsFolderIterator folder;
// if there is a path... set it
if ( path )
folder.SetPath(path);
while (folder.NextFileSuffix(".py"))
{
const char *fileName = folder.GetFileName();
filenames.push_back(fileName);
if ( path )
pathnames.push_back(path);
else
pathnames.push_back("");
}
}
std::string ToLowerCase(std::string str)
{
std::string retVal = "";
for (int i=0; i<str.length(); i++)
{
if ((str[i]>='A')&&(str[i]<='Z'))
retVal += (char)tolower(str[i]);
else
retVal += str[i];
}
return retVal;
}
void FindSubDirs(std::vector<std::string> &dirnames, std::vector<std::string> &pakNames, char *path)
{
hsFolderIterator folder;
if (path)
folder.SetPath(path);
while (folder.NextFile())
{
if (folder.IsDirectory())
{
std::string dirName = folder.GetFileName();
if ((dirName != ".")&&(dirName != "..")&&(ToLowerCase(dirName) != "system") && (ToLowerCase(dirName) != "plasma"))
{
dirnames.push_back(dirName);
pakNames.push_back(dirName+".pak");
}
}
}
}
// adds or removes the ending slash in a path as necessary
std::string AdjustEndingSlash(std::string path, bool endingSlash = false)
{
std::string retVal = path;
bool endSlashExists = false;
char temp = path[path.length()-1];
if (temp == '\\')
endSlashExists = true;
if (endingSlash)
{
if (!endSlashExists)
retVal += "\\";
}
else
{
if (endSlashExists)
{
std::string temp = "";
for (int i=0; i<retVal.length()-1; i++)
temp += retVal[i];
retVal = temp;
}
}
return retVal;
}
// appends partialPath onto the end of fullPath, inserting or removing slashes as necesssary
std::string ConcatDirs(std::string fullPath, std::string partialPath)
{
bool fullSlash = false, partialSlash = false;
char temp = fullPath[fullPath.length()-1];
if (temp == '\\')
fullSlash = true;
temp = partialPath[0];
if (temp == '\\')
partialSlash = true;
std::string retVal = "";
if (!fullSlash)
retVal = fullPath + "\\";
if (partialSlash)
{
std::string temp = "";
for (int i=1; i<partialPath.length(); i++)
temp += partialPath[i];
partialPath = temp;
}
retVal += partialPath;
return retVal;
}
void PackDirectory(std::string dir, std::string rootPath, std::string pakName, std::vector<std::string>& extraDirs, bool packSysAndPlasma = false)
{
// make sure the dir ends in a slash
dir = AdjustEndingSlash(dir,true);
printf("\nCreating %s using the contents of %s\n",pakName.c_str(),dir.c_str());
printf("Changing working directory to %s\n",rootPath.c_str());
if (_chdir(rootPath.c_str()))
{
printf("ERROR: Directory change to %s failed for some reason\n",rootPath.c_str());
printf("Unable to continue with the packing of this directory, aborting...\n");
return;
}
else
printf("Directory changed to %s\n",rootPath.c_str());
std::vector<std::string> fileNames;
std::vector<std::string> pathNames;
FindFiles(fileNames,pathNames,dir.c_str());
if (packSysAndPlasma)
{
printf("Adding the system and plasma directories to this pack file\n");
std::string tempPath;
tempPath = dir + "system";
FindFiles(fileNames,pathNames,tempPath.c_str());
tempPath = dir + "plasma";
FindFiles(fileNames,pathNames,tempPath.c_str());
}
// ok, we know how many files we're gonna pack, so make a fake index (we'll fill in later)
hsUNIXStream s;
if (!s.Open(pakName.c_str(), "wb"))
return;
s.WriteSwap32(fileNames.size());
int i;
for (i = 0; i < fileNames.size(); i++)
{
s.WriteSafeString(fileNames[i].c_str());
s.WriteSwap32(0);
}
PythonInterface::initPython(rootPath);
for (i = 0; i < extraDirs.size(); i++)
PythonInterface::addPythonPath(rootPath + extraDirs[i]);
// set to maximum optimization (includes removing __doc__ strings)
Py_OptimizeFlag = 2;
std::vector<UInt32> filePositions;
filePositions.resize(fileNames.size());
for (i = 0; i < fileNames.size(); i++)
{
UInt32 initialPos = s.GetPosition();
WritePythonFile(fileNames[i].c_str(), pathNames[i].c_str(), &s);
UInt32 endPos = s.GetPosition();
filePositions[i] = initialPos;
}
s.SetPosition(sizeof(UInt32));
for (i = 0; i < fileNames.size(); i++)
{
s.WriteSafeString(fileNames[i].c_str());
s.WriteSwap32(filePositions[i]);
}
s.Close();
PythonInterface::finiPython();
}
void PrintUsage()
{
printf("Usage:\n");
printf("plPythonPack [directory to pack...]\n");
printf("NOTE: the directory to pack must have full system and plasma dirs and\n");
printf(" must be a relative path to the current working directory\n");
}
void main(int argc, char *argv[])
{
printf("The Python Pack Utility\n");
char buffer[_MAX_PATH];
_getcwd(buffer,_MAX_PATH);
std::string baseWorkingDir = buffer;
// are they asking for usage?
if (argc == 2)
{
std::string temp = argv[1];
temp = ToLowerCase(temp);
if ((temp == "?") || (temp == "-?") || (temp == "/?") || (temp == "-help") || (temp == "/help")
|| (temp == "-h") || (temp == "/h"))
{
PrintUsage();
return;
}
}
// wrong number of args, print usage
if (argc > 2)
{
PrintUsage();
return;
}
std::vector<std::string> dirNames;
std::vector<std::string> pakNames;
std::string rootPath;
if (argc == 1)
{
FindSubDirs(dirNames,pakNames,nil);
rootPath = AdjustEndingSlash(baseWorkingDir,true);
}
else
{
std::string path = argv[1];
FindSubDirs(dirNames,pakNames,argv[1]);
rootPath = ConcatDirs(baseWorkingDir,path);
rootPath = AdjustEndingSlash(rootPath,true);
}
PackDirectory(rootPath,rootPath,rootPath+kPackFileName,dirNames,true);
for (int i=0; i<dirNames.size(); i++)
{
PackDirectory(dirNames[i],rootPath,rootPath+pakNames[i],dirNames);
}
}