最終更新日 2024-09-25

ScenarioModからIronPythonModを使う場合

概要

前節では、C++/CLIのミニマムサンプルでIronPythonを呼び出しました。
ここまで知っておけばScenarioModでIronPythonを利用する方法を理解するのは簡単です。

ScenaroMod側

ScnearioModのソースには、「On_起動時」あたりで、Python関連のエンジンやスコープを構築します。

それらはメソッドを跨いで利用しますので、下のソース例の「GREF」クラスのように、
グローバル変数的な形で参照を持っておく必要があることに注意しましょう。

On_相場変更直前()で前節の例と全く同じことを再現したものとなります。
On_起動時にGREFに控えた「PythonEngineへの参照(GREF::pe)」や「スコープへの参照(GREF::scope)」を使う点だけ変更点です。

#include "カスタム駆動関数.h"

using namespace System;


using namespace System::Collections;

using namespace IronPython::Hosting;
using namespace Microsoft::Scripting::Hosting;


ref class GREF {
public:
  static ScriptEngine^ pe;
  static ScriptScope^ scope;
};



void カスタム::On_起動時() {
  // スクリプトエラー等をキャッチできるようにしよう。
  try {
    GREF::pe = Python::CreateEngine();

    // ファイルを実行。
    GREF::scope = GREF::pe->ExecuteFile("script.py");
  }
  catch (Exception^ e) {
    デバッグ出力 << e->Message << endl;
  }
}


void カスタム::On_相場変更直前() {

  // スクリプトエラー等をキャッチできるようにしよう。
  try {
    // 変数 abc を intとして取得
    int val = GREF::scope->GetVariable<int>("abc");

    // 変数 name を String^ として取得
    String^ str = GREF::scope->GetVariable<String^>("name");
    デバッグ出力 << str << endl;

    // 変数 ret_valを「ArrayList^」型として取得
    ArrayList^ arr1 = GREF::scope->GetVariable<ArrayList^>("ret_val");
    for each (int l in arr1) {
      デバッグ出力 << l << endl;
    }

    // 関数を呼び出し
    GREF::pe->Execute("hello('world')", GREF::scope);

    // 関数を呼び出すが、返り値は、String^型とみなす
    String^ ret1 = GREF::pe->Execute<String^>("get_hello('world')", GREF::scope);
    デバッグ出力 << ret1 << endl;

    // 日本語名の関数を呼び出すが、返り値は、String^型とみなす
    String^ retstr = GREF::pe->Execute<String^>("ハロー('world')", GREF::scope);
    string native_str = string←String(retstr);
    デバッグ出力 << retstr << endl;

    // 関数を呼び出す。返り値はArrayList^型
    ArrayList^ arr2 = GREF::pe->Execute<ArrayList^>("get_ret_val()", GREF::scope);
    for each (int l in arr2) {
      デバッグ出力 << l << endl;
    }

    // intを引数に取って、boolを返す関数
    auto funcIsOdd = GREF::pe->Operations->GetMember<Func<int, bool>^>(GREF::scope, "is_odd");
    bool b1 = funcIsOdd(3);
    デバッグ出力 << b1 << endl;
    bool b2 = funcIsOdd(4);
    デバッグ出力 << b2 << endl;


  }
  catch (Exception^ e) {
    デバッグ出力 << e->Message << endl;
  }

}


Python側

スクリプト側は前節と全く同じものです。

C++/CLIの「マルチバイト」から呼ばれますので、「script.pyのソースコードの文字コードをShitJIS(=cp932)」で保存してください。
(テキストエディタなどで実際に確認してください。間違っているとSyntax Errorが出ます)

IronPythonのソース:script.py

# coding: cp932


from System.Collections import *

abc = 3

name = "武田信玄"

def hello( x ) :
  print "hello, " + x

def ハロー( x ) :
  print "ハロー, " + x
  return "ハロー" + x


def get_hello( x ) :
  return "hello, " + x


a = [10,20,30]
ret_val = ArrayList(a)

def get_ret_val() :
  return ret_val


def is_odd(num):
  if num % 2 == 1:
    return True
  else:
    return False

以上となります。

ScenarioModに組み込まれているLuaは専用にカスタムしたものでしたが、
今回のIronPythonModの仕組みは、汎用的なIronPythonのdllの使い方と同一です。

ですので、C#から呼び出し、C++/CLIからの呼び出し、いずれでもよいので使い方を知っておけば、
自作プロジェクトや他のゲームのMod制作などにおいて、幅広く役立つことでしょう。