⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pythonscript.cpp

📁 这也是 Premier.Press.MUD.GAME.PROGRAMMING.rar 一书的源码
💻 CPP
字号:
// MUD Programming
// Ron Penton
// (C)2003
// PythonScript.h - This file contains python related helpers for implementing
//                  BetterMUD scripts
// 
// 


#include "PythonScript.h"

namespace BetterMUD
{



// ============================================================================
//  PythonCallable Functions
// ============================================================================
// This is a helper macro that will make the following Call functions easier to 
// use. It wraps around a call to something that returns a PyObject, and handles
// exceptions thrown within.
#define PYTHONCALL( CALL )                                                  \
    PythonObject r;                                                         \
    try{ r = CALL }                                                         \
    catch( ... ) {                                                          \
        PyErr_Print();                                                      \
        throw Exception( "Python Function Call Failed" );                   \
    }                                                                       \
    if( r.get() == 0 ) {                                                    \
        PyErr_Print();                                                      \
        throw Exception( "Python Function Call Failed" );                   \
    }                                                                       \
    return r;


PythonObject PythonCallable::Call( std::string p_name )
{
    PYTHONCALL( PyObject_CallMethodObjArgs( m_module.get(), StringToPy( p_name ).get(), NULL ); )
}

PythonObject PythonCallable::Call( std::string p_name, const PythonObject& p_arg1 )
{
    PYTHONCALL( PyObject_CallMethodObjArgs( m_module.get(), StringToPy( p_name ).get(), p_arg1.get(), NULL ); )
}

PythonObject PythonCallable::Call( std::string p_name, const PythonObject& p_arg1, const PythonObject& p_arg2 )
{
    PYTHONCALL( PyObject_CallMethodObjArgs( m_module.get(), StringToPy( p_name ).get(), p_arg1.get(), p_arg2.get(), NULL ); )
}

PythonObject PythonCallable::Call( std::string p_name, const PythonObject& p_arg1, const PythonObject& p_arg2, const PythonObject& p_arg3 )
{
    PYTHONCALL( PyObject_CallMethodObjArgs( m_module.get(), StringToPy( p_name ).get(), p_arg1.get(), p_arg2.get(), p_arg3.get(), NULL ); )
}

PythonObject PythonCallable::Call( std::string p_name, const PythonObject& p_arg1, const PythonObject& p_arg2, const PythonObject& p_arg3, const PythonObject& p_arg4 )
{
    PYTHONCALL( PyObject_CallMethodObjArgs( m_module.get(), StringToPy( p_name ).get(), p_arg1.get(), p_arg2.get(), p_arg3.get(), p_arg4.get(), NULL ); )
}

PythonObject PythonCallable::Call( std::string p_name, const PythonObject& p_arg1, const PythonObject& p_arg2, const PythonObject& p_arg3, const PythonObject& p_arg4, const PythonObject& p_arg5 )
{
    PYTHONCALL( PyObject_CallMethodObjArgs( m_module.get(), StringToPy( p_name ).get(), p_arg1.get(), p_arg2.get(), p_arg3.get(), p_arg4.get(), p_arg5.get(), NULL ); )
}

PythonObject PythonCallable::Call( std::string p_name, const PythonObject& p_arg1, const PythonObject& p_arg2, const PythonObject& p_arg3, const PythonObject& p_arg4, const PythonObject& p_arg5, const PythonObject& p_arg6 )
{
    PYTHONCALL( PyObject_CallMethodObjArgs( m_module.get(), StringToPy( p_name ).get(), p_arg1.get(), p_arg2.get(), p_arg3.get(), p_arg4.get(), p_arg5.get(), p_arg6.get(), NULL ); )
}




// ============================================================================
//  PythonModule Functions
// ============================================================================

void PythonModule::Load( const std::string& p_module )
{
    // load the module
    PythonObject p = PyImport_ImportModule( const_cast<char*>( p_module.c_str() ) );
    if( p.get() == 0 )
        throw Exception( "Couldn't load python module: " + p_module );

    m_module = p;
}

void PythonModule::Reload( SCRIPTRELOADMODE p_mode )
{
    // reload the module
    m_module = PyImport_ReloadModule( m_module.get() );

    // simply return if you want to leave the existing scripts as they are,
    // without actually updating them
    if( p_mode == LEAVEEXISTING )
        return;

    spawnlist::iterator itr = m_spawns.begin();
    while( itr != m_spawns.end() )
    {
        (*itr)->Reload();
        ++itr;
    }
}





PythonInstance* PythonModule::SpawnNew( const std::string p_str )
{
    try
    {
    // Get the class from the module:
    PythonObject c = PyObject_GetAttrString( m_module.get(), const_cast<char*>(p_str.c_str()) );
    
    // no good, throw an exception
    if( c.get() == 0 )
        throw Exception( "Could not find python class: " + p_str );

    // grab an instance of that class now:
    PythonObject i = PyInstance_New( c.get(), NULL, NULL );

    if( i.get() == 0 )
        throw Exception( "Could not create python class instance: " + p_str );

    PythonInstance* mod = new PythonInstance( i, this );

    if( !mod )  throw Exception( "Error allocating memory for python module" );

    // set the modules instance and parent pointer, and add it to my list.
    m_spawns.push_back( mod );

    return mod;
    }
    catch( Exception& e ) { throw; }
    catch( ... )        // catch any extra errors we didn't grab before
    {
        PyErr_Print();
        throw Exception( "Unknown error attempting to create class instance: " + p_str );
    }
}


void PythonModule::DeleteChild( PythonInstance* p_instance )
{
    m_spawns.erase( std::find( m_spawns.begin(), m_spawns.end(), p_instance ) );
}



// ============================================================================
//  PythonInstance Functions
// ============================================================================
PythonInstance::~PythonInstance()
{
    if( m_parent )
        m_parent->DeleteChild( this );
}

void PythonInstance::Reload()
{
    // get the name of the class you want to reload
    std::string clsname = m_module.GetNameOfClass();

    // get a new class object from the parent module
    PythonObject cls = PyObject_GetAttrString( 
        m_parent->get(), 
        const_cast<char*>(clsname.c_str()) );

    if( cls.get() == 0 )
        throw Exception( "Could not find python class: " + clsname );

    // set my class attribute to point to the new class functions (but not data)
    PyObject_SetAttrString( m_module.get(), "__class__", cls.get() );
}


void PythonInstance::Load( std::istream& p_stream )
{
    std::string str;
    std::string temp;
    bool done = false;

    // read in the "[DATA] tag:
    std::getline( p_stream, temp );

    // loop until you hit "[/DATA]"
    while( !done )
    {
        std::getline( p_stream, temp );
        if( temp == "[/DATA]" )
            done = true;
        else
            str += temp + "\n";
    }

    // send everything inbetween to the script
    Call( "LoadScript", StringToPy( str ) );
}

void PythonInstance::Save( std::ostream& p_stream )
{
    p_stream << "[DATA]\n";
    p_stream << StringFromPy( Call( "SaveScript" ) );
    p_stream << "[/DATA]\n";
}



// ============================================================================
//  PythonDatabase Functions
// ============================================================================
PythonDatabase::~PythonDatabase()
{
    modules::iterator itr = m_modules.begin();
    while( itr != m_modules.end() )
    {
        delete *itr;
        ++itr;
    }
}


void PythonDatabase::Load()
{
    std::string filename = m_directory + "manifest";
    std::ifstream manifest( filename.c_str(), std::ios::binary );
    manifest >> std::ws;

    while( manifest.good() )
    {
        std::string modulename;
        manifest >> modulename >> std::ws;
        Load( modulename );
    }
}


void PythonDatabase::AddModule( const std::string& p_module )
{
    Load( p_module );

    // write the new module name out to the manifest
    std::string filename = m_directory + "manifest";
    std::ofstream manifest( filename.c_str(), std::ios::binary | std::ios::app );
    manifest << "\n" << p_module << "\n";
}



void PythonDatabase::Load( const std::string& p_module )
{
    std::string modname = m_directory + p_module;

    // convert "/" or "\" to "." for proper module loading
    modname = BasicLib::SearchAndReplace( modname, "/", "." );
    modname = BasicLib::SearchAndReplace( modname, "\\", "." );

    PythonModule* mod = new PythonModule();
    if( !mod )  throw Exception( "Not enough memory to load python module" );

    try
    {
        mod->Load( modname );
        m_modules.push_back( mod );
    }
    catch( ... )
    {
        delete mod;
        throw;
    }
}

void PythonDatabase::Reload( const std::string& p_module, SCRIPTRELOADMODE p_mode )
{
    modules::iterator itr = m_modules.begin();
    while( itr != m_modules.end() )
    {
        if( (*itr)->Name() == p_module )
        {
            (*itr)->Reload( p_mode );
            return;
        }
        ++itr;
    }   

    // if we got this far, then the module doesn't exist, so load it
    Load( p_module );
}

PythonInstance* PythonDatabase::SpawnNew( const std::string p_str )
{
    modules::iterator itr = m_modules.begin();
    while( itr != m_modules.end() )
    {
        if( (*itr)->Has( p_str ) )
            return (*itr)->SpawnNew( p_str );
        ++itr;
    }   

    throw Exception( "Error: Cannot load module: " + p_str );
}


}   // end namespace BetterMUD

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -