プラグインフレームワークを自分で書く(13)

4396 ワード

では、前の章で欠けている部分を補いましょう.この部分の最後に、完全なコードが得られます.
モンスターカード
前に説明したプラグインフレームワークに基づいて、わざと4つの異なるタイプのプラグインを作成しました.
  • 純C++プラグイン
  • 純Cカード
  • 動的/共有ライブラリとして配備されたハイブリッドプラグイン
  • は、実行可能ファイルのC++スタティックプラグイン
  • に直接リンクすべきである.
    これらのプラグインはすべて、そのモンスターオブジェクトをactorとしてPluginManagerに登録します.また,ゲーム自体にはHero類が提供されており,IActorインタフェースを実現した対象としている.ゲームによって制御されるHero類と他のモンスターオブジェクトのほとんどのIActorインタフェースのコードは一致している.ゲームには内蔵のモンスターも提供されます.
    動的C++プラグイン
    ダイナミックC++カードにはKillerBunnyとStationarySatanの2種類のモンスターが登録されています.次のコードはKillerBunnyです.hヘッダファイル.KillerBunnyはC++IActorインタフェースを直接実現した(これにより純粋なC++プラグインになった).PluginManagerのオブジェクトの作成と破棄に使用するcreate()とdestroy()static関数を実現します.StationarySatanおよび他の純粋なC++プラグインオブジェクトは基本的に類似しています(privateデータを除く).
    #ifndef KILLER_BUNNY_H
    #define KILLER_BUNNY_H
     
    #include <object_model/object_model.h>
     
    struct PF_ObjectParams;
     
    class KillerBunny : public IActor
    {
    public:
        // static plugin interface
        static void * create(PF_ObjectParams *);
        static apr_int32_t destroy(void *);
        ~KillerBunny();
     
        // IActor methods
        virtual void getInitialInfo(ActorInfo * info);
        virtual void play(ITurn * turnInfo);
     
    private:
        KillerBunny();
    };
     
    #endif

    次のコードにはcreate()とdestroy()の実装が含まれています.これらはすべて簡単です.create()関数は、新しいKillerBunnyオブジェクトを作成し、それを返します(voidポインタの形式).destroy()関数には、create()関数が返すvoidポインタをパラメータとして必要とします.voidポインタをKillerBunnyポインタに変換しdeleteが落ちます.ここで最も重要な部分は、PluginManagerがKillerBunnyクラスに関する情報を「知る」必要がなく、KillerBunnyオブジェクトを作成できるようにすることです.返されるインスタンスは、voidポインタが返されている場合でもIActorインタフェースで使用できます.
    void * KillerBunny::create(PF_ObjectParams *)
    {
        return new KillerBunny();
    }
     
    apr_int32_t KillerBunny::destroy(void * p)
    {
        if (!p)
            return -1;
        delete (KillerBunny *)p;
        return 0;
    }

    次のコードにはIActorインタフェースの実装が含まれています.これらの関数も簡単です.getInitialInfo()関数は、いくつかのデータを使用してActorInfo構造を組み立てるために使用されます.Play()関数こそ、KillerBunnyが実際に提供する機能です.移動、攻撃、回避などです.ここではITurnインタフェースから友軍のリストを取得するだけです.これは私たちが完全な実現を提供する必要がないからです.実際には、私たちの怪物は何もできません.Heroだけが本当の攻撃をすることができる.モンスターが攻撃を受けると、自分を守り反撃する必要があります.
    void KillerBunny::getInitialInfo(ActorInfo * info)
    {
        ::strcpy((char *)info->name, "KillerBunny");
        info->attack = 10;
        info->damage = 3;
        info->defense = 8;
        info->health = 20;
        info->movement = 2;
     
        // Irrelevant. Will be assigned by system later
        info->id = 0;
        info->location_x = 0;
        info->location_y = 0;
    }
     
    void KillerBunny::play(ITurn * turnInfo)
    {
        IActorInfoIterator * friends = turnInfo->getFriends();
    }

    これらのコードを書く目的は、純粋なC++プラグインを書くのがどんなに簡単かを実証することです.公式化されたcreate()とdestroy()static関数を除いて、標準的なC++クラスを実現するだけで、神秘的なコードを追加する必要はありません.
    次はプラグイン初期化コードです.これらのコードは複雑ではありませんが、煩雑でエラーが発生しやすいです.PF_InitPlugin関数では、終了関数とPF_を定義します.RegisterParams構造体を組み立て、すべてのプラグインオブジェクトを登録します.初期化に失敗したときにNULLが返されることを確認します.それ以外に何もありません.これが純粋なC++モンスタープラグインを作成するために必要です(以下のコードでは、2つのモンスターを登録しています).
    #include "cpp_plugin.h"
    #include "plugin_framework/plugin.h"
    #include "KillerBunny.h"
    #include "StationarySatan.h"
     
    extern "C" PLUGIN_API apr_int32_t ExitFunc()
    {
        return 0;
    }
     
    extern "C" PLUGIN_API PF_ExitFunc PF_initPlugin(const PF_PlatformServices * params)
    {
        int res = 0;
     
        PF_RegisterParams rp;
        rp.version.major = 1;
        rp.version.minor = 0;
        rp.programmingLanguage = PF_ProgrammingLanguage_CPP;
     
        // Register KillerBunny
        rp.createFunc = KillerBunny::create;
        rp.destroyFunc = KillerBunny::destroy;
        res = params->registerObject((const apr_byte_t *)"KillerBunny", &rp);
        if (res < 0)
            return NULL;
     
        // Regiater StationarySatan
        rp.createFunc = StationarySatan::create;
        rp.destroyFunc = StationarySatan::destroy;
        res = params->registerObject((const apr_byte_t *)"StationarySatan", &rp);
        if (res < 0)
            return NULL;
     
        return ExitFunc;
    }