GoogleAppScriptからFacebookに投稿
この記事は2017年07月23日にqiitaに投稿した内容です。
環境
V2.10
概要
GoogleAppScriptを使用して一定時間ごとにFacebookにメッセージを投稿します
Facebookアプリの作成
https://developers.facebook.com/apps/
・「新しいアプリの追加」を押す ・「表示名」を入力する(例:TestGAS) ・「アプリIDを作成したください」を押す ・セキュリティチェックで文字を入力する
アクセストークンの取得
https://developers.facebook.com/tools/explorer/
・「グラフAPIエクスプローラ」の右側の「アプリ」と表示されているドロップボックスを作成したアプリに変更する(例:TestGAS) 最初は「GraphApiExplorer」と表示されているかもしれない ・「トークンを取得」を押す ・「ユーザーアクセストークンを取得」を押す ・「publish_actions」にチェックする ・「アクセストークンを取得」を押す 「アクセストークン」に表示される このアクセストークンは短期で1時間くらいしか有効じゃない
長期アクセストークンの取得
https://developers.facebook.com/tools/explorer/
・「GET/V2.10/」の横に「oauth/access_token?grant_type=fb_exchange_token&client_id=AAA&client_secret=BBB&fb_exchange_token=XXX」と入力して、「送信」 AAAはアプリID(ダッシュボードで確認) BBBはappsecret(ダッシュボードで確認) XXXは取得したアクセストークン ・返ってきた長期アクセストークンをメモる
ユーザーIDの確認
https://developers.facebook.com/tools/explorer/
・「GET/V2.10/」の横に「me?fields=id,name」と入力して、「送信」
投稿のテスト
https://developers.facebook.com/tools/explorer/
・「GET/V2.10/」の「GET」を「POST」に変更 ・「me/feed?message=TestMessage」と入力して「送信」 TestMessageが投稿される
ブラウザからUrlで投稿
・ブラウザのURL入力欄で「https://graph.facebook.com/me/feed?method=POST&version=v2.10&message=TestMessage&access_token=XXX」と入力してリターン meの部分はユーザーIDでも可能 XXXは取得した長期アクセストークン
アクセストークンデバッガ
https://developers.facebook.com/tools/debug/accesstoken/
アクセストークンを入力すると有効期限等の情報が得られる
GoogleAppScriptの作成
https://script.google.com/macros/d/
・下記のスクリプトをコピペして置き換える
アクセストークン用スクリプトプロパティの作成
https://script.google.com/macros/d/
・「ファイル」>「プロジェクトのプロパティ」を押す ・「スプリプトのプロパティ」タブに変更する ・「行の追加」を押す ・「名前」にプロパティ名を入れる(例:accessToken) ・「名前」欄の右側を押すと「値」入力欄が出るので取得した長期アクセストークンを入力する PropertiesService.getScriptProperties().getProperty('accessToken')でアクセスできる
一定時間毎に処理を行う
GoogleAppScriptを使用して一定時間毎にFirebaseにレコードを追加するを参照する
スクリプト
function setTrigger()
{
//十分毎に処理を実行
var executeFuncName = "httpRequestFacebookPost";
deleteTriggers( executeFuncName );
ScriptApp.newTrigger( executeFuncName ).timeBased().everyMinutes( 10 ).create();
}
function deleteTriggers( executeFuncName )
{
//登録されているトリガーを削除
var triggers = ScriptApp.getProjectTriggers();
for( var i = 0; i < triggers.length; i++ )
{
if ( triggers[ i ].getHandlerFunction() == executeFuncName )
ScriptApp.deleteTrigger( triggers[ i ] );
}
}
function httpRequestFacebookPost()
{
var uri = "https://graph.facebook.com/me/feed?method=POST&version=v2.10";
var message = "TestMessage4";
var accessToken = PropertiesService.getScriptProperties().getProperty('accessToken');
UrlFetchApp.fetch( uri + "&message=" + message + "&access_token=" + accessToken );
}
GoogleComputeEngineのVMインスタンスにWinScpでログイン
※この記事は2017年07月20日にqiitaに投稿した内容です。
環境
Windows10 Home
概要
コマンドラインでの操作がつらい。GUIでファイル転送したい為にWinScpで接続します
GoogleComputeEngineの設定
以下を参照して設定する GoogleComputeEngine上にサーバを立ててUNETを動かす
WinScpのインストール
https://winscp.net/eng/download.php
・「Installation package」をダウンロードしてインストール エクスプローラ風にした
WinScp接続設定
・「転送プロトコル」は「SCP」に設定 ・「ホスト名」はVMインスタンスの「外部IP」を設定(例:104.198.168.72) ・「ユーザー名」は「gcloud compute ssh」コマンドの時のユーザー名(例:fukaken5050) ・「ポート番号」は22 ・「パスワード」は設定しない ・「設定」ボタンを押す ・「SSH」>「認証」>「認証条件」>「秘密鍵」>「...」を押す ・「C:\Users(ユーザー)\ユーザー名\.ssh」にある「google_compute_engine.ppk」を選択 ・「OK」を押す ・「保存」を押す ・「ログイン」でログインする
隠しファイルの表示
「.bash_profile」等の表示の為 ・メニューの「表示」>「環境設定」 ・「パネル」>「隠しファイルを表示する」にチェック
Taskを使用した非同期処理のテスト
この記事は2017年07月15日にqiitaに投稿した内容です。
環境
Unity2017.1.0f3
概要
.NET4.6が使用できるようになったのでTask・Async/Awaitのテスト
.NET4.6の設定
「PlayerSettings」>「OtherSettings」>「ScriptRuntimeVertion」を「Experimental(.NET4.6Equivalent)」に変更する
プログラム
順次実行と並列実行をしています
Assets/TestTask.cs
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
public class TestTask : MonoBehaviour
{
[SerializeField] private Text _text = null;
private IEnumerator Start()
{
yield return new WaitForSeconds( 3.0f );
//順次実行
yield return StartCoroutine( TestTaskSequentialProcess() );
//並列実行
yield return StartCoroutine( TestTaskParallelProcess() );
}
private IEnumerator TestTaskSequentialProcess()
{
Debug.Log( "StartTestTaskSequential:" + Thread.CurrentThread.ManagedThreadId + "--------------------" );
var prevTime = Time.realtimeSinceStartup;
// var task = Task.Run( () => TaskSequential() );
var task = TaskSequential();
//task.Wait();//awaitのせいでデッドロックする
while( true )
{
if( task.IsCanceled == true || task.IsCompleted == true || task.IsFaulted == true )
break;
var time = Time.realtimeSinceStartup;
Debug.Log( "DeltaTime:" + ( time - prevTime ).ToString() );
prevTime = time;
yield return null;
}
Debug.Log( "CompleteTestTaskSequential" );
yield break;
}
private IEnumerator TestTaskParallelProcess()
{
Debug.Log( "StartTestTaskParallel:" + Thread.CurrentThread.ManagedThreadId + "--------------------" );
var prevTime = Time.realtimeSinceStartup;
//var task = Task.Run( () => TaskParallel() );
var task = TaskParallel();
//task.Wait(); //動作するが中身がわからないと使えないので使わない
while( true )
{
if( task.IsCanceled == true || task.IsCompleted == true || task.IsFaulted == true )
break;
var time = Time.realtimeSinceStartup;
Debug.Log( "DeltaTime:" + ( time - prevTime ).ToString() );
prevTime = time;
yield return null;
}
Debug.Log( "CompleteTestTaskParallel" );
yield break;
}
//Task.Run()で呼び出されなければ、呼び出し元と同じスレッドで実行される
//メインスレッドで実行されているならUnityの関数が使える
//awaitで待っている間、Taskは中断され、他に処理がうつる
private async Task TaskSequential()
{
Debug.Log( "StartTaskSequential:" + Thread.CurrentThread.ManagedThreadId );
if( _text != null )
_text.text = "StartTaskSequential";
for ( var i = 0; i < 5; i++ )
{
var index = i;
//awaitでTaskが終わるまで中断
await Task.Run(() => Sleep( index ) );
}
Debug.Log( "CompleteTaskSequential" );
}
private Task TaskParallel()
{
Debug.Log( "StartTaskParallel:" + Thread.CurrentThread.ManagedThreadId );
if( _text != null )
_text.text = "StartTaskParallel";
var tasks = new List<Task>();
for ( var i = 0; i < 5; i++ )
{
var index = i;
var task = Task.Run(() => Sleep( index ) );
tasks.Add( task );
}
//すべてのタスクが完了した時に完了するタスクを生成
var taskAll = Task.WhenAll( tasks );
//この時点では終わっていない
//ここで終わらせたければ asyncにしてawait Task.WhenAll()にする
Debug.Log( "CompleteTaskParallel" );
return taskAll;
}
private void Sleep( int index )
{
Debug.Log( "Sleep:" + Thread.CurrentThread.ManagedThreadId );
Thread.Sleep( 1000 );
Debug.Log( index );
}
}
Threadを用いた並列処理
Task・Async/Awaitを使用したくない場合 http://qiita.com/fukaken5050/items/c6ea9233b708082ae1e9
参考
http://qiita.com/acple@github/items/8f63aacb13de9954c5da http://qiita.com/takutoy/items/6f3a20f7f48f36d918dd
AssetBundleManagerのwwwをUnityWebRequestに変えて、さらにキャッシュの古いバージョンを削除してみる
この記事は2017年07月11日にqiitaに投稿した内容です。
環境
Unity2017.1.0f3
概要
wwwは使用しないでUnityWebRequestを使用したほうがいいらしいのでテスト また、Caching.ClearOtherCachedVersionsを使用して、キャッシュの古いバージョンを削除します
変更箇所
// Where we actuall call WWW to download the assetBundle.
static protected bool LoadAssetBundleInternal (string assetBundleName, bool isLoadingAssetBundleManifest)
{
// Already loaded.
LoadedAssetBundle bundle = null;
m_LoadedAssetBundles.TryGetValue(assetBundleName, out bundle);
if (bundle != null)
{
bundle.m_ReferencedCount++;
return true;
}
// @TODO: Do we need to consider the referenced count of WWWs?
// In the demo, we never have duplicate WWWs as we wait LoadAssetAsync()/LoadLevelAsync() to be finished before calling another LoadAssetAsync()/LoadLevelAsync().
// But in the real case, users can call LoadAssetAsync()/LoadLevelAsync() several times then wait them to be finished which might have duplicate WWWs.
if (m_DownloadingWWWs.ContainsKey(assetBundleName) )
return true;
// WWW download = null;
UnityWebRequest download = null;
string url = m_BaseDownloadingURL + assetBundleName;
// For manifest assetbundle, always download it as we don't have hash for it.
if (isLoadingAssetBundleManifest)
// download = new WWW(url);
download = UnityWebRequest.GetAssetBundle( url );
else
{
download = UnityWebRequest.GetAssetBundle( url, m_AssetBundleManifest.GetAssetBundleHash(assetBundleName), 0 );
//Unity2017 バージョン違いを消す
if( Caching.ClearOtherCachedVersions( assetBundleName, m_AssetBundleManifest.GetAssetBundleHash(assetBundleName ) ) == false )
Debug.LogWarning( "ClearOtherCachedVersions" );
}
// download = WWW.LoadFromCacheOrDownload(url, m_AssetBundleManifest.GetAssetBundleHash(assetBundleName), 0);
download.Send();
m_DownloadingWWWs.Add(assetBundleName, download);
return false;
}
void Update()
{
// Collect all the finished WWWs.
var keysToRemove = new List<string>();
foreach (var keyValue in m_DownloadingWWWs)
{
// WWW download = keyValue.Value;
var download = keyValue.Value;
// If downloading fails.
if (download.error != null)
{
m_DownloadingErrors.Add(keyValue.Key, string.Format("Failed downloading bundle {0} from {1}: {2}", keyValue.Key, download.url, download.error));
keysToRemove.Add(keyValue.Key);
continue;
}
// If downloading succeeds.
if(download.isDone)
{
// AssetBundle bundle = download.assetBundle;
AssetBundle bundle = ((DownloadHandlerAssetBundle)download.downloadHandler).assetBundle;
if (bundle == null)
{
m_DownloadingErrors.Add(keyValue.Key, string.Format("{0} is not a valid asset bundle.", keyValue.Key));
keysToRemove.Add(keyValue.Key);
continue;
}
//Debug.Log("Downloading " + keyValue.Key + " is done at frame " + Time.frameCount);
// m_LoadedAssetBundles.Add(keyValue.Key, new LoadedAssetBundle( download.assetBundle ) );
m_LoadedAssetBundles.Add(keyValue.Key, new LoadedAssetBundle( bundle ) );
keysToRemove.Add(keyValue.Key);
//Unity2017キャッシュの確認
var currentCache = Caching.currentCacheForWriting;
var versions = new List<Hash128>();
var assetbundleName = Path.GetFileName( download.url );
Caching.GetCachedVersions( assetbundleName, versions );
Debug.Log( "CacheVersionCount:" + bundle.name + ":" + versions.Count );
Debug.Log( "CachePath:" + currentCache.path );
Debug.Log( "CacheSize:" + currentCache.spaceOccupied + "/" + currentCache.maximumAvailableStorageSpace );
}
}
// Remove the finished WWWs.
foreach( var key in keysToRemove)
{
// WWW download = m_DownloadingWWWs[key];
var download = m_DownloadingWWWs[key];
m_DownloadingWWWs.Remove(key);
download.Dispose();
}
// Update all in progress operations
for (int i=0;i<m_InProgressOperations.Count;)
{
if (!m_InProgressOperations[i].Update())
{
m_InProgressOperations.RemoveAt(i);
}
else
i++;
}
}
c++プラグインでSquirrelスクリプトとやり取りをする(Android)
この記事は2017年07月11日にqiitaに投稿した内容です。
環境
Unity5.6.2f1 Squirrel 3.1
概要
c++Likeなスクリプト言語のSquirrelとやり取りをするテストです
Squirrelのダウンロード
以下のページで「Download」を押す https://sourceforge.net/projects/squirrel/
AndroidStudioとUnityの事前設定
以下を参照してプロジェクトを作成する プラグインでc++と連携する(Android) libunisquirrel.soとしてエクスポートする
Squirrel関連のファイル追加
・AndroidのNativePluginを作成した時の「cpp」フォルダ内に「squirrel3」というフォルダを作成 ・ダウンロードしたtar.gzを展開する ・「squirrel」「sqstdlib」「include」フォルダを作成した「squirrel3」の中にフォルダ毎コピーする ・コピーしたフォルダ内の「.cpp」と「.h」以外を削除する
CMakeLists.txt
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
UniSquirrel.cpp
#squirrel3
squirrel3/squirrel/sqapi.cpp
squirrel3/squirrel/sqbaselib.cpp
squirrel3/squirrel/sqclass.cpp
squirrel3/squirrel/sqcompiler.cpp
squirrel3/squirrel/sqdebug.cpp
squirrel3/squirrel/sqfuncstate.cpp
squirrel3/squirrel/sqlexer.cpp
squirrel3/squirrel/sqmem.cpp
squirrel3/squirrel/sqobject.cpp
squirrel3/squirrel/sqstate.cpp
squirrel3/squirrel/sqtable.cpp
squirrel3/squirrel/sqvm.cpp
squirrel3/sqstdlib/sqstdaux.cpp
squirrel3/sqstdlib/sqstdblob.cpp
squirrel3/sqstdlib/sqstdio.cpp
squirrel3/sqstdlib/sqstdmath.cpp
squirrel3/sqstdlib/sqstdrex.cpp
squirrel3/sqstdlib/sqstdstream.cpp
squirrel3/sqstdlib/sqstdstring.cpp
squirrel3/sqstdlib/sqstdsystem.cpp
)
# Specifies a path to native header files.
include_directories( Unity/ )
include_directories( squirrel3/include/ )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log
)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
)
プログラム
Squirrelの「.nut」ファイルはUTF8(bom無し)CR+LFでテストしました
UniSquirrel.cpp
#include "IUnityInterface.h"
#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
//#define SQUNICODE
#include "squirrel.h"
#include "sqstdio.h"
#include "sqstdaux.h"
static void printfunc( HSQUIRRELVM v, const SQChar* pFormat, ... );
static SQInteger print_args( HSQUIRRELVM v );
static SQInteger register_global_func( HSQUIRRELVM v, SQFUNCTION f, const char *fname );
static void CallSquirrelFunc( HSQUIRRELVM v );
extern "C"
{
using CallbackOutputString = void(*)( const SQChar* );
namespace
{
CallbackOutputString onCallbackOutputString = NULL;
}
UNITY_INTERFACE_EXPORT void SetCallbackOutputString( CallbackOutputString func )
{
onCallbackOutputString = func;
}
UNITY_INTERFACE_EXPORT void ExecuteScript( const SQChar* pPath )
{
if ( onCallbackOutputString == NULL )
return;
HSQUIRRELVM v;
v = sq_open( 1024 );
sqstd_seterrorhandlers( v );
sq_setprintfunc( v, printfunc, printfunc );
sq_pushroottable( v );
//c/c++関数の登録
register_global_func( v, print_args, "print_args" );
if( SQ_SUCCEEDED( sqstd_dofile( v, pPath, 0, 1 ) ) )
{
printf("Call Failed!");
}
//squirrel関数の呼び出し
CallSquirrelFunc( v );
sq_close(v);
}
UNITY_INTERFACE_EXPORT void ExecuteScriptInMemory( const SQChar* pBuffer )
{
if ( onCallbackOutputString == NULL )
return;
HSQUIRRELVM v;
v = sq_open( 1024 );
sqstd_seterrorhandlers( v );
sq_setprintfunc( v, printfunc, printfunc );
sq_pushroottable( v );
sq_compilebuffer( v, pBuffer,(int)strlen( pBuffer ) * sizeof( SQChar ), "compile", 1 );
sq_pushroottable(v);
sq_call(v,1,1,0);
sq_close(v);
}
static void CallSquirrelFunc( HSQUIRRELVM v )
{
//SQInteger saveStack = sq_gettop( v );
sq_pushroottable( v );
sq_pushstring( v, _SC( "TestFunc" ), -1 );
if( SQ_SUCCEEDED( sq_get( v, -2 ) ) )
{
}
int n = 123;
float f = 345.67f;
const SQChar* s = _SC( "abcd" );
sq_pushroottable( v );
sq_pushinteger( v, n );
sq_pushfloat( v, f );
sq_pushstring( v, s, -1 );
sq_call( v, 4, SQTrue, 0 );
if( sq_gettype( v, -1 ) == OT_INTEGER )
{
SQInteger ret;
sq_getinteger( v, -1, &ret );
sq_pop( v, 1 );
// sq_settop( v, saveStack );
char str[64] = "";
snprintf( str, sizeof( str ) - 1, "%d", ret );
onCallbackOutputString( str );
}
}
static void printfunc( HSQUIRRELVM v, const SQChar* pFormat, ... )
{
va_list arglist;
va_start( arglist, pFormat );
SQChar buffer[ 1024 ] = _SC( "" );
vsnprintf( buffer, sizeof(buffer), pFormat, arglist );
va_end( arglist );
onCallbackOutputString( buffer );
}
static SQInteger print_args( HSQUIRRELVM v )
{
SQInteger nargs = sq_gettop(v); //number of arguments
for(SQInteger n=1;n<=nargs;n++)
{
printf("arg %d is ",n);
switch(sq_gettype(v,n))
{
case OT_NULL:
onCallbackOutputString("null");
break;
case OT_INTEGER:
onCallbackOutputString("integer");
break;
case OT_FLOAT:
onCallbackOutputString("float");
break;
case OT_STRING:
onCallbackOutputString("string");
break;
case OT_TABLE:
onCallbackOutputString("table");
break;
case OT_ARRAY:
onCallbackOutputString("array");
break;
case OT_USERDATA:
onCallbackOutputString("userdata");
break;
case OT_CLOSURE:
onCallbackOutputString("closure(function)");
break;
case OT_NATIVECLOSURE:
onCallbackOutputString("native closure(C function)");
break;
case OT_GENERATOR:
onCallbackOutputString("generator");
break;
case OT_USERPOINTER:
onCallbackOutputString("userpointer");
break;
default:
return sq_throwerror(v,"invalid param"); //throws an exception
}
onCallbackOutputString("\n");
}
sq_pushinteger(v,nargs); //push the number of arguments as return value
return 1; //1 because 1 value is returned
}
static SQInteger register_global_func( HSQUIRRELVM v, SQFUNCTION f, const SQChar* fname )
{
sq_pushroottable(v);
sq_pushstring(v,fname,-1);
sq_newclosure(v,f,0); //create a new function
sq_createslot(v,-3);
sq_pop(v,1); //pops the root table
return 0;
}
}
/Assets/TestSquirrel.cs
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections;
public class TestSquirrel : MonoBehaviour
{
[SerializeField] Text _text = null;
[DllImport ("unisquirrel")]
public static extern void SetCallbackOutputString( UnityAction<string> func );
[DllImport ("unisquirrel")]
public static extern void ExecuteScript( string path );
[DllImport ("unisquirrel")]
public static extern void ExecuteScriptInMemory( string buffer );
private static TestSquirrel _instance = null;
private void Awake()
{
_instance = this;
}
private void OnDestroy()
{
_instance = null;
}
private void OnApplicationQuit()
{
OnDestroy();
}
private void OnEnable()
{
SetCallbackOutputString( OnOutputString );
}
private void OnDisable()
{
SetCallbackOutputString( null );
}
private IEnumerator Start()
{
yield return StartCoroutine( ExecuteScriptProcess( "test1.nut" ) );
yield return StartCoroutine( ExecuteScriptInMemoryProcess( "test0.nut" ) );
}
private IEnumerator ExecuteScriptProcess( string fileName )
{
var filePath = Path.Combine(Application.streamingAssetsPath, fileName );
var scriptData = "";
if ( filePath.Contains( "://" ) == true )
{
WWW www = new WWW( filePath );
yield return www;
scriptData = www.text;
}
else
scriptData = System.IO.File.ReadAllText( filePath );
//persistentDataPathへコピー
var outputPath = Path.Combine( Application.persistentDataPath, fileName );
File.WriteAllText( outputPath, scriptData );
while( File.Exists( outputPath ) == false )
yield return null;
Debug.Log( scriptData );
ExecuteScript( outputPath );
yield break;
}
private IEnumerator ExecuteScriptInMemoryProcess( string fileName )
{
var filePath = Path.Combine( Application.streamingAssetsPath, fileName );
var scriptData = "";
if ( filePath.Contains( "://" ) == true )
{
WWW www = new WWW( filePath );
yield return www;
scriptData = www.text;
}
else
scriptData = File.ReadAllText( filePath );
Debug.Log( scriptData );
ExecuteScriptInMemory( scriptData );
yield break;
}
private void OnOutputString( string message )
{
Debug.Log( message );
_instance.SetText( message );
}
private void SetText( string message )
{
if( _text == null )
return;
_text.text = message;
}
}
Assets/StreamingAssets/test0.nut
print("ハローワールド");
Assets/StreamingAssets/test1.nut
function TestFunc( n, f, s )
{
print( "TestFunc:" + n + "/" + f + "/" + s );
return 789;
}
function Main()
{
print( "ハロー!ワールド" );
print_args( 987, 654.32, "zxcv" );
}
Main();
プラグインでc++と連携する(Android)
この記事は2017年07月06日にqiitaに投稿した内容です。
環境
Unity5.6.2f1
概要
C#側からc++側に関数を登録して、c++側から登録した関数を呼び出します エコープログラムです
AndroidStudioとUnityの事前設定
以下を参照してプロジェクトを作成する Android用ネイティブレンダリングPlugin(c++[so])の作成 「libnativecpp.so」としてエクスポートされるようにする 「MultiThreadedRendering」にチェックを入れなくていい 今回はレンダリングは関係ない為
CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
Test.cpp
)
# Specifies a path to native header files.
include_directories( Unity/ )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log
)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
)
プログラム
Assets/TestNativePlugin.cs
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using System.Runtime.InteropServices;
public class TestNativePlugin : MonoBehaviour
{
[SerializeField] Text _text = null;
[DllImport ("nativecpp")]
public static extern void SetEchoCallbackFunction( UnityAction<string> func );
[DllImport ("nativecpp")]
public static extern void TestEcho( string message );
private static TestNativePlugin _instance = null;
private void Awake()
{
_instance = this;
}
private void OnDestroy()
{
_instance = null;
}
private void OnApplicationQuit()
{
OnDestroy();
}
private void OnEnable()
{
SetEchoCallbackFunction( OnNativeCallback );
}
private void OnDisable()
{
SetEchoCallbackFunction( null );
}
private void Start()
{
TestEcho( "hello world!" );
}
private void OnNativeCallback( string message )
{
Debug.Log( message );
_instance.SetText( message );
}
private void SetText( string message )
{
if( _text == null )
return;
_text.text = message;
}
}
Test.cpp
#include "IUnityInterface.h"
#include <math.h>
#include <stdio.h>
#include <assert.h>
extern "C"
{
using EchoCallback = void(*)( const char* );
namespace
{
EchoCallback onEchoCallback = NULL;
}
UNITY_INTERFACE_EXPORT void SetEchoCallbackFunction( EchoCallback func )
{
onEchoCallback = func;
}
UNITY_INTERFACE_EXPORT void TestEcho( const char* pMessage )
{
if ( onEchoCallback == NULL )
return;
onEchoCallback( pMessage );
}
}
GoogleComputeEngine上にサーバを立ててUNETを動かす
この記事は2017年07月04日にqiitaに投稿した内容です。
環境
Unity5.6.2f1 Windows10 Home
概要
GoogleComputeEngine(AWSのEC2のようなの)上で、Linuxサーバのインスタンスを作成し、UNETのサーバプログラムを動かし、マルチ対戦します
GoogleComputeEngineの常時無料枠
以下のUrlに記載されています https://cloud.google.com/free/docs/always-free-usage-limits https://cloud.google.com/compute/pricing USリージョンの「f1-micro」インスタンスが1つ無料とあるようです(バージニア州北部を除く)
インスタンスの作成
以下のページで詳しく解説されています あぱーブログ 「Compute Engine インスタンスの作成」まで進める コンソールで「外部IP 」を確認しておく。(例:104.198.168.72)
GoogleCloudSDKのインストール
https://cloud.google.com/sdk/downloads?hl=ja 「対話型インストーラ」の記述に沿ってインストールします
ログイン
すでにSDKをインストールしていて別のアカウントで使用していた場合、ログインが必要です ・「gcloud auth login」と入力 ・アカウントを選択する
サーバのポート開放
・「コマンドプロンプト」を開く ・「gcloud compute firewall-rules create VVV --allow tcp:0-10000,udp:0-10000」と打ち込みリターン VVVはルール名(例:unet) 何番を開放すればよかったのかわからないので0から10000まで解放している コンソールの「VPCネットワーク」>「ファイヤーウォールルール」で確認できる https://console.cloud.google.com/networking/firewalls/list?project=heroic-passkey-178708&tab=INGRESS
UNETプログラムの用意
ここにテスト用のUNETプログラムを用意しました ・「Download」を押してzipをダウンロード ・zip内に含まれる「Linux」内のものがサーバにアップするプログラム ・「WinApp」内のものはサーバと接続するクライアントプログラム、またはローカル確認用のサーバプログラムを兼ねる
サーバにデプロイ(コピー)
・ダウンロードしたzipを展開する ・「コマンドプロンプト」を開き、「Linux」フォルダ内に移動する ・「gcloud compute copy-files *. XXX@YYY:」と打ち込みリターン XXXはユーザー名 YYYはインスタンス名 (例:gcloud compute copy-files *. fukaken5050@test-instance:)
sshでサーバに接続
・「コマンドプロンプト」を開き、「Linux」フォルダ内に移動する ・「gcloud compute --project "AAA" ssh --zone "BBB" "XXX@YYY"」と打ち込みリターン AAAはプロジェクト名 BBBはインスタンスのリージョン XXXはユーザー名 YYYはVMインスタンス名 (例:gcloud compute --project "testcomputeengine-171603" ssh --zone "us-central1-a" "fukaken5050@test-instance") 内部で「putty」が実行されてサーバのコマンドラインが入力できるようになる
実行権限の付与
・「putty」上で「chmod u+x EEE」と打ち込みリターン EEEはプログラム名(例:chmod u+x server.x86_64)
サーバプログラムの実行
・「putty」上で「nohup ./EEE -logFile server.log &」と打ち込みリターン EEEはプログラム名(例:nohup ./server.x86_64 -server -logFile server.log &) -serverはUNETプログラム内部で使用している独自のパラメータ ・「Ctrl+C」でプロンプトに戻る
テスト用クライアントプログラムの実行
・ダウンロードしたzipを展開する ・「WinApp」>「test.exe」を実行する ・「接続先」に外部IPを入力する(例:104.198.168.72) ・「設定」を押す ・「クライアント」を押す サーバに接続される ・もう一つ「test.exe」を実行し、「クライアント」を押す ・片方は「募集」、もう一つは「参加」で対戦する
プロセスの停止
・「putty」上で「ps x」と入力 実行されているプロセス一覧が表示される ・「Kill XXX」と入力 XXXはプロセスID
プロセスを監視して再実行
サーバプログラムが落ちてしまった場合に、自動で再実行します
execServer.sh ・「nohup ./execServer.sh &」と入力
#!/bin/bash
while true
do
isAlive=`ps -ef | grep "server.x86_64" | grep -v grep | wc -l`
if [ $isAlive = 0 ]; then
echo "serverを実行します"
nohup ./server.x86_64 -server -logFile server.log &
fi
sleep 10
done