C++幼女先輩

プログラミング成分多め

岡山と東京のIT事情

半分ネタなので おこらないで・・

自己紹介

小学校1年の頃 岡山大学医学部の目の前 鹿田の イナバ小児科の前で 60キロで走る乗用車にはねられ かすり傷の 大怪我をしたのが 事故はじめです 自転車は真っ二つに曲がって、体は車のボンネットで跳ね返り 推定3メートル以上の高さから アスファルトに落ちたんですけど 人間 頑丈ですね ちゃんと頭を打たず 回転で衝撃をゆるめて かすり傷ですよ

跳ねた人は慌てて 車にのせて、目の前に岡大医学部あるのに 表町のほう 川崎病院に送ってくれました お詫びのお菓子おいしかったです

侘び石はよー! ってかんじ

次の事故は、去年原付きで60キロ出して居眠り運転して、ガードレールに衝突しましたね 手袋してたので、かすり傷すらなかったんですが、受け身を取った時に力を入れすぎて 骨が剥離骨折してしまいました もし 骨が筋肉の力に耐えてたら 60キロでバイクで事故ったのに かすり傷すらしなかった! って威張れたのに 悔しいです

なので 牛乳を毎日飲むようにしました

そんなわけで、高校まで岡山市育ち。大学3ヶ月で中退してから なんとなくゲーム作りたくて東京に出てかれこれです

東京のIT事情

結論からいうと、大都会岡山のITは素晴らしい。江戸時代以前、吉備大国時代より大都会であった。 東京も なかなかにIT大国であるが、やはり一馬身ほど足りていない

ITとは何か? IT IT イット イート Eat! つまり 食事の事です

では信じられない東京の IT事情を

うどん

まず東京には うどん屋なるものが存在しない。 ここ数年に、さぬきうどんブームが来て、はなまるうどん丸亀製麺というチェーン店はやってきたものの 基本的に 蕎麦屋のサイドメニューとしてしか 存在しない

大都会岡山では、植民地うどん県で生産される コシの強いうどんを常食しているが 東京の人は 黒くてコシのない 蕎麦というものを食べる この黒い蕎麦というものは 冷でワサビを入れると 結構旨いのだが、温を頼むと 真っ黒な醤油スープの中に黒い麺がはいって、しょっぱい 蕎麦屋でうどんを頼むと だいたい やわらかく ぶよぶよと 黒い汁をすった物体が出て来る f:id:murasame-labo:20161205040259j:plain

我々の知っている、カツオベースの黄金の透き通ったスープとは かけ離れたものが出て来る

そして、うどんのセルフサービス店は存在せず、ぶっかけうどんも ほとんど全滅である

ただ、最近は 丸亀製麺はなまるうどん が出てきて、セルフサービスが無い以外は問題はなくなった

お好み焼き

東京ではお好み焼き=お酒のおつまみ という認識のようである 多くの店が 17時以降にお酒のおつまみとして提供する 昼間から営業しているお好み焼き屋も もんじゃ焼きのサイドメニュー扱いであり 4人卓でセルフスタイルで焼く事を強要される。必ず 大阪スタイルだ。 f:id:murasame-labo:20161205040440j:plain

東京で最初に食べたお店は とてもひどく 大阪スタイルのお好み焼きに 蕎麦がほぐして入っており、蕎麦と小麦粉を混ぜて焼き ねぎ焼きは 白ネギを小麦粉に混ぜてお焼きにしていた

ただ、広島から来た勇者たちが、本場のお好み焼きを作っているお店が何件かあり そこに行けば必ず 広島人と仲良くなれるので もし東京に出る事になったら、そのお店を探しておくと良いだろう

ソース

東京ではブルドッグソースという、酸っぱいソースが好まれる f:id:murasame-labo:20161205041005j:plain 甘いものが好きな岡山人の口には たいてい合わないと思われる もちろん私はオタフクソースが大好きだ

ラーメン

東京ではコッテリ脂だらけのラーメンばかりである 好きな人は好きだと思うが、大都会岡山人にとっては あまり好ましくない 新橋に岡山ラーメンがあるので、どうしても食べたい時はそこへ駆け込め! f:id:murasame-labo:20161206104452j:plain

デミカツ丼

東京のカツ丼は醤油ベースである f:id:murasame-labo:20161205041509j:plain 岡山人の愛するデミカツ丼はどこにもない・・・ やまとも だても 東京にはない・・ あまりに存在しないので、自分で調理するしかない ありがとう クックパッド!!

東京もいいとこあります

お寿司

瀬戸内海の幸が豊富な岡山もお寿司は非常に美味しいですが 金と人口にものを言わし、日本中の良い食材が集まる東京ですから 北海道から九州までの、美味しい魚が豊富 東京きて食に困ったら、とりあえず 寿司か刺身食べておけば間違いない

お肉

こちらも 金と人口でビンタして、北海道から九州までの 有名和牛を取り揃え はっきりいって 肉の分野では東京が一番かも

海外料理

日本以外、世界中で 東京以上に色々な国の料理が、現地と同じ それ以上のクオリティーで食べられる そんな都市は存在しないんじゃないでしょうか 少なくとも 私の行ったことのある10カ国では、東京に匹敵するグルメタウンは存在しなかった

明日は

Uemmra3 さん 中国山地を越えた反対側から(仮) だそうです。 とっとりぃ???

何番煎じか UnitychanをUnreal 4.14で読み込む。 アニメーションステートマシン作成

はじめに

何番煎じか不明だが UnityChanモデルの読み込み 触った感じ 4.14になっても ほとんど変わってないので 本当に何番煎じか・・

前回は UnityChanが操作できるが Tポーズなので 今回は 待機モーション、ジャンプ等を作る

最低限のアニメーション設定(待機、Jump)

Unitychanのボーン情報を使ったアニメーションBluePrintの作成

f:id:murasame-labo:20161204155120p:plain

名前を BP_AnimUnitychanにしました

ThirdPersonCharacterのAnimationを 先程のBlueprintに設定 f:id:murasame-labo:20161204155226p:plain

BP_AnimUnitychanをダブルクリックし AnimGraphを開き New StateMacheneで ステートマシンを新規に作り FinalAnimationPoseに繋ぎ ステートマシンの結果が反映されるようにする f:id:murasame-labo:20161204155717p:plain

待機モーション ステートマシーン作成

ステートマシンをダブルクリックする New StateJuを選び Idleと名前をつける

Idleステートをダブルクリックし Idleを実装する

Play xx で再生するアニメーションを選ぶ 無難なのは unitychan_WAIT00 なのでとりあえずそれを。

実行すると今までTポーズだったのが 待機モーションになっている

もちろん 歩きもジャンプも実装されてないので常に待機モーション。 時々Tポーズが一瞬出るのが気になるが とりあえず待機は完成 f:id:murasame-labo:20161204162816p:plain

ジャンプ

StateMacheneにジャンプを追加 f:id:murasame-labo:20161204162707p:plain JumpStart、JumpLoop、JumpEnd の3つのステートを作成し 図のように繋ぎます この矢印の方向にしか ステートはかわらないので、矢印重要!

矢印の上の記号は、遷移するための条件を指定するもので、あとで設定します

そして JumpStart、Loop、End にアニメーションを設定したいのですが問題発生 UnityChanは その3つが分離されてないので、分離しなければなりません

CreateAnimComposite

アニメーションの部分再生を使います

コンテンツブラウザのUnityChan_Skelton右クリックし、Create->AnimationComposite できたAnimationCompositeを Unitychan_Jump00B_Start にリネーム ダブルクリックする (アニメーションモンタージュでも出来そうだが、どちら使うのがいいのかな?)

右下のAssetBrowserから unitychan_JUMP00Bを選ぶ

f:id:murasame-labo:20161204162715p:plain

タイムラインをクリックすると Detailsが出るので、StartTime EndTimeを入れる 例えばわたしは Start0.3 End0.7にしてみた f:id:murasame-labo:20161204223358p:plain

本当は ジャンプ前のしゃがみモーションや、着地時のしゃがみモーションがついているので、それも再生行いたいが 少し処理が必要になるので、後日ということで

同じく Loopは Start0.7 End0.71、 Endは Start1.0 End1.85に

f:id:murasame-labo:20161204170021p:plainf:id:murasame-labo:20161204170025p:plain

Jumpステートマシンにアニメーション設定

ステートマシンより JumpStart、JumpLoop、JumpEndをダブルクリックし、アニムグラフを表示 それぞれにCompositeを設定する 補間では出てこなかったのでその場合はAssetBrowserから引っ張ってくると良い

f:id:murasame-labo:20161204181731p:plain

ステートマシン 条件追加

このまま実行しても IdleからJumpに遷移しないため 条件追加していきます

色々なやり方あると思いますが、今回はAnimationのTickで、空中かどうかでみます おそらく、ジャンプではなく落下も考えると ジャンプボタン押したかの判定で行うようになるかもしれません

アニメーションブループリントの Variablesに bool型のIsInAir変数を作る。デフォルト値はfalseで

BluePrint作成。アニメーションブループリントのEventGraphiで、キャラが空中の場合上記フラグを立てる

f:id:murasame-labo:20161204180821p:plain

ステートマシンの、IdleからJumpStartへの遷移をダブルクリックし、 IsInAirフラグが立てば遷移するようにする

f:id:murasame-labo:20161204181101p:plain

StartからLoop、EndからIdleには、アニメーション終了したら遷移するよう 以下のBluePrintを使う f:id:murasame-labo:20161204182250p:plain

LoopからEndはとりあえず IsInAirがFalseになった時にしておこう・・・ f:id:murasame-labo:20161204183439p:plain

実行するとジャンプするが、StartとEndが繰り返されるので、StartとEndは Loopを外す

とりあえずは出来た

歩き/走り

待機モーション ピクピク対応

待機モーションが一瞬Tポーズ出るので 上記と同じように AnimationCompositを使い Wait00の頭を抜いて再生する。 例えば StartTime0.1 EndTime2.95

Idleステートマシンのモーションにそれを設定すると ピクピクがなくなる

やること

ブレンドスペース1Dを使う。 ブレンドスペース1Dは、1つのパラメータにより アニメーションを合成できる 2Dだと2つのパラメータで合成。3D以降は予定されているが未実装

今回は Speedパラメータを使い、Idle->walk->run を合成する

とりあえず慣例にしたがい Idleステートマシンを Idle/Runにリネーム

Spped

Speedパラメータを設定

アニメーションブループリントのVariableにて float型のSpeed変数作成 EventGraphにて Velocityの大きさを渡す

f:id:murasame-labo:20161204225040p:plain

BlendSpace1D

ボーンを選び Create->BlendSpace1D を選択 例えば unitychan_BS1Dという名前にした

これをダブルクリックするとBlendSpaceが開かれる 左上の DisplayEditorVerti をチェックし 画面中央右の X Axis Labelに Speedを。 Rangeは グレーマンにみならって 0-375にした Speed0に Wait0 (AnimationCompositeやMontageは指定できなかったのでTポーズが出る・・) Maxに Run、間にWalkを入る あとで画面動かしながら 確認しよう

f:id:murasame-labo:20161204231251p:plain

ステートマシンに反映

Idle/Run ステートのピンを 先程作った BlendSpaceに変更する またSpeedパラメータを渡す

f:id:murasame-labo:20161204231659p:plain

実行するとそれっぽい動作をするはず

問題点

Wait0ポーズの開始時のTポーズが出てしまう (BlendSpaceに AnimationCompositeもMontageも指定できなかった) ジャンプ着地時に動いたら滑ったようになる

何番煎じか不明だが Unreal4.14で Unitychanを読み込む

はじめに

いろいろな人が記事書いてくれているので基本それを見てください たとえば

UE4でゼロからユニティちゃんを表示させるまで - Let's Enjoy Unreal Engine

今回は自分のメモと UE4.14で変更点があると思われるのでチェックです

データのコンバート

上記Blogの通りにします。

UnityChanデータをダウンロード FBXConverterでFBX2013にコンバート

プロジェクト作成

テンプレートより ThirdPartyゲームを選ぶ、BluePrintで。

モデルデータのインポート

コンバートした unitychan.fbx をimportします 上記Blogのとおりに・・

f:id:murasame-labo:20161204150907p:plain

4.14ではメニュー変わってますがとりあえずデフォルトでよさそうな気がします

Warningでましたね・・

f:id:murasame-labo:20161204151211p:plain

マテリアル設定

上記Blogのとおりに・・ テクスチャをimportし、Materialを作成し モデルデータのMaterialを差し替えます チークと目が透過はいってなくおかしいので チークと目の透過設定を行う

f:id:murasame-labo:20161204151235p:plain

ちゃんと表示できましたね!

モーション読み込み

以前読み込んだ時は 寝転んでしまいましたが・・ 果たして大丈夫でしょうか

デフォルトで読み込みすると やはり地面に寝てしまいましたので import時に X軸回転させます

f:id:murasame-labo:20161204152149p:plain

Warningでました・・ f:id:murasame-labo:20161204152210p:plain

が、とりあえずちゃんと表示されたようです

f:id:murasame-labo:20161204152242p:plain

プレイヤーをUnityChanに

デフォルトだと グレーマンですが、UnityChanに変更します

WorldOutlinerの ThirdPersonCharacterを選び、Meshを unitychanに変更

f:id:murasame-labo:20161204152818p:plain

実行すると、Tポーズのままですが UnityChanが動きました

次回は、待機、Jumpあたりのアニメーション (ステートマシン)作ります

Unreal4.13 リプレイ機能調査(キルカメラ) Part 1

はじめに

今回は調査。不確定な要素もあるかもしれない 有識者のツッコミ欲しい所。

UnrealEngineにはリプレイ機能がある。 これは 終了したゲームを例えばファイルから再現をさせる機能である ムービーと違って、後から視点を変更したり出来る

docs.unrealengine.com

ドキュメントを読むかぎりでは UE4.13ではリプレイ機能が3種類存在する

Null Streamer

NULL Streamer はホスト マシンからイベントを直接ディスクに記録します。シングル プレイヤー ゲームや、リプレイをホスト プレイヤー自身のマシンにローカルに保持するゲームに最適です

とあるように、ディスクに保存し、ゲーム終了後にファイルを読み込んで リプレイを見る事が可能のようだ 機能的に、リプレイの記録終了後にしか読み込めない

Memory Streamer

Memory Streamer はクライアント マシンで実行し、メモリにデータを保存します。スポーツ作品のビデオ判定機能やシューティング ゲームのキルカメラに最適です。

モリー上にリプレイを保存し、任意のタイミングで再生可能なので スポーツゲームの得点シーンのリプレイや、FPSのキルカメラで 倒された瞬間の相手のカメラを再生したり リアルタイムで任意の状況を再生できそう

HTTP Sreamer

最後に HTTP Streamer はリプレイ データを LAN またはインターネット上の 2 台めのマシンに送ります。専用サーバーのゲームやプレイヤーに反応し続けながら大勢の観戦者に向けてストリーミングする必要があるゲームに適しています。

おそらく、他のサーバにリプレイデータを送信し、複数のサーバが リプレイをリレー出来るものだと思う。 ゲーム大会で観戦者が大勢いる際に、リプレイサーバを増やす事で容易にスケーリング可能になると思われる

気になる所

リプレイ システムは C++ コードから使用できます。主に、UGameInstance クラスおよび UWorld クラス経由で、またはコンソール コマンドやコマンドライン引数を使って使用できます。C++/Blueprint API を統合したものを構築中であり、エンジンの将来のバージョンでリリース予定です。

つまり、今のリプレイコードは プレビュー版で、今後 ちゃんとしたものをリリースする、作成途中の可能性がある 少なくともBluePrintのインタフェースは存在しない

よろしい、ならば開発だ

と勇んだものの、公式ドキュメントは上記ページのみで、ネットにサンプルもみつけられなかった ので、1から調査しなければならない おそらく今回は、コードを追っかけて色々な無駄をすることになるが ドキュメント読めない私の 問題解決方法をメモがわりに

Unreal Reference

リプレイに直接関連しそうなReferenceは下記

NetworkReplayStreaming NetworkReplayStreaming | Unreal Engine API Reference

NullNetworkReplayStreaming NullNetworkReplayStreaming | Unreal Engine API Reference

HttpNetworkReplayStreaming HttpNetworkReplayStreaming | Unreal Engine API Reference

NullとHttpはわかるが Memory Replayが無い・・・ のでコードをみよう

コードを書きましょう

Source/Runtime/NetworkReplayStreaming以下に NetworkReplayStreaming、NullNetworkReplayStreaming、InMemoryNetworkReplayStreaming、HttpNetworkReplayStreaming が存在する。 InMemoryNetworkReplayStreamingはReferenceにもまだ のってないようだ

また、コードをみると いずれもUPROPERTYがついておらず、BluePrintから使われる想定になっていないことが見て取れる

どこに何を書けばいいか手探り状態なので、とりあえず Characterに書いてみようとおもう

モジュール追加

NetworkReplayStreaming はモジュールなので、まずはビルドスクリプトに追加しよう

プロジェクト名.Build.csのPublicDependencyModuleNamesに "NetworkReplayStreaming" を追加ですね。

色々叩いてみよう

新規プロジェクトを作り、とりあえず Characterクラスを派生し AMyCharacterをつくり 調査しよう 最も機能の少なそうな NullNetworkReplayStreamingを。

BeginPlay あたりにとりあえず Factoryする

 FNullNetworkReplayStreamingFactory factory;
    TSharedPtr<  INetworkReplayStreamer > networkReplayStreamer_ = factory.CreateReplayStreamer();

動くかは知らないがビルド通った そして おそらくリプレイ録画開始メソッドに近いと思われる StartStreamingを呼ぶことを考える しかし引数が多く、最後にコールバックが必要。 コールバックも関数オブジェクトでもなく FOnStreamReadyDelegate型

エンジンコードを検索し StartStreamingを呼ぶ手本がないか探す

DemoNetDriver.cpp

DemoNetDriver.cppにそれはあった

const TCHAR* const StreamerOverride = URL.GetOption(TEXT("ReplayStreamerOverride="), nullptr);
        ReplayStreamer = FNetworkReplayStreaming::Get().GetFactory(StreamerOverride).CreateReplayStreamer();

GetFactoryの引数が不気味だ。Engine.iniの設定により 使うクラスがかわりそうだ 追っていくと

INetworkReplayStreamingFactory& FNetworkReplayStreaming::GetFactory(const TCHAR* FactoryNameOverride)
{
    FString FactoryName = TEXT( "NullNetworkReplayStreaming" );

    if (FactoryNameOverride == nullptr)
    {
        GConfig->GetString( TEXT( "NetworkReplayStreaming" ), TEXT( "DefaultFactoryName" ), FactoryName, GEngineIni );
    }
    else
    {
        FactoryName = FactoryNameOverride;
    }

    // See if we need to forcefully fallback to the null streamer
    if ( !FModuleManager::Get().IsModuleLoaded( *FactoryName ) )
    {
        FModuleManager::Get().LoadModule( *FactoryName );
    
        if ( !FModuleManager::Get().IsModuleLoaded( *FactoryName ) )
        {
            FactoryName = TEXT( "NullNetworkReplayStreaming" );
        }
    }

    return FModuleManager::Get().LoadModuleChecked< INetworkReplayStreamingFactory >( *FactoryName );
}

iniで値をかえているようだ デフォルトでは NullNetworkReplayStreaming を使うようになっているので、このあたりを変更すれば InMemoryやHTTPを使うことが出来そう Iniファイルで変更するか、

bool UDemoNetDriver::InitConnect( FNetworkNotify* InNotify, const FURL& ConnectURL, FString& Error )

を呼び出す時に ConnectURLに ReplayStreamerOverride=好きなStreamingクラス名  を指定すれば出来ると期待

 ReplayStreamer->StartStreaming( 
        DemoFilename, 
        FString(),      // Friendly name isn't important for loading an existing replay.
        UserNames, 
        false, 
        FNetworkVersion::GetReplayVersion(), 
        FOnStreamReadyDelegate::CreateUObject( this, &UDemoNetDriver::ReplayStreamingReady ) );

これを参考にして呼んでみようかと思うも、このDemoNetDriverが何かを軽くしらべる。 ソースを軽く読んだところ、サーバとの通信の間?にたち、そこでリプレイデータを保存したりなんたらしてそうで NetworkReplayStreaming を直接叩かず、DemoNetDriverを操作する方が正しいのではないかとおもい調べる

UDemoNetDriver::InitConnect を呼んでいる奴を検索

UGameInstance

なんとなく 真犯人な雰囲気がする

void UGameInstance::PlayReplay(const FString& Name, UWorld* WorldOverride, const TArray<FString>& AdditionalOptions)
{
    UWorld* CurrentWorld = WorldOverride != nullptr ? WorldOverride : GetWorld();

    if ( CurrentWorld == nullptr )
    {
        UE_LOG( LogDemo, Warning, TEXT( "UGameInstance::PlayReplay: GetWorld() is null" ) );
        return;
    }

    if ( CurrentWorld->WorldType == EWorldType::PIE )
    {
        UE_LOG( LogDemo, Warning, TEXT( "UGameInstance::PlayReplay: Function called while running a PIE instance, this is disabled." ) );
        return;
    }

    CurrentWorld->DestroyDemoNetDriver();

    FURL DemoURL;
    UE_LOG( LogDemo, Log, TEXT( "PlayReplay: Attempting to play demo %s" ), *Name );

    DemoURL.Map = Name;
    
    for ( const FString& Option : AdditionalOptions )
    {
        DemoURL.AddOption(*Option);
    }

    const FName NAME_DemoNetDriver( TEXT( "DemoNetDriver" ) );

    if ( !GEngine->CreateNamedNetDriver( CurrentWorld, NAME_DemoNetDriver, NAME_DemoNetDriver ) )
    {
        UE_LOG(LogDemo, Warning, TEXT( "PlayReplay: failed to create demo net driver!" ) );
        return;
    }

    CurrentWorld->DemoNetDriver = Cast< UDemoNetDriver >( GEngine->FindNamedNetDriver( CurrentWorld, NAME_DemoNetDriver ) );

    check( CurrentWorld->DemoNetDriver != NULL );

    CurrentWorld->DemoNetDriver->SetWorld( CurrentWorld );

    FString Error;

    if ( !CurrentWorld->DemoNetDriver->InitConnect( CurrentWorld, DemoURL, Error ) )
    {
        UE_LOG(LogDemo, Warning, TEXT( "Demo playback failed: %s" ), *Error );
        CurrentWorld->DestroyDemoNetDriver();
    }
    else
    {
        FCoreUObjectDelegates::PostDemoPlay.Broadcast();
    }
}

AdditionalOptionsに先程の ReplayStreamerOverride=好きなStreamingクラス名

で動きそうな雰囲気

GameInstance.cpp

ほぼ絞れた UGameInstance::PlayReplayの呼び口を探すと2個あった

UGameInstance::StartGameInstance

 // Parse replay name if specified on cmdline
    FString ReplayCommand;
    if ( FParse::Value( Tmp, TEXT( "-REPLAY=" ), ReplayCommand ) )
    {
        PlayReplay( ReplayCommand );
        return;
    }

なんと、プロセスを起動する時に -REPLAY= のコマンドライン引数を使って リプレイファイルを指定して再生可能である

仕様上 NullNetworkReplayStreaming しか使えない そして 今まで調べていたのは リプレイ再生であったことがわかる

UWorld::HandleDemoPlayCommand

本命はこちらである

bool UWorld::Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar )
{
    if( FParse::Command( &Cmd, TEXT("TRACETAG") ) )
    {
        return HandleTraceTagCommand( Cmd, Ar );
    }
    else if( FParse::Command( &Cmd, TEXT("FLUSHPERSISTENTDEBUGLINES") ) )
    {       
        return HandleFlushPersistentDebugLinesCommand( Cmd, Ar );
    }
    else if (FParse::Command(&Cmd, TEXT("LOGACTORCOUNTS")))
    {       
        return HandleLogActorCountsCommand( Cmd, Ar, InWorld );
    }
    else if (FParse::Command(&Cmd, TEXT("DEMOREC")))
    {       
        return HandleDemoRecordCommand( Cmd, Ar, InWorld );
    }
    else if( FParse::Command( &Cmd, TEXT("DEMOPLAY") ) )
    {       
        return HandleDemoPlayCommand( Cmd, Ar, InWorld );
    }
    else if( FParse::Command( &Cmd, TEXT("DEMOSTOP") ) )
    {       
        return HandleDemoStopCommand( Cmd, Ar, InWorld );
    }
    else if (FParse::Command(&Cmd, TEXT("DEMOSCRUB")))
    {
        return HandleDemoScrubCommand(Cmd, Ar, InWorld);
    }
    else if (FParse::Command(&Cmd, TEXT("DEMOPAUSE")))
    {
        return HandleDemoPauseCommand(Cmd, Ar, InWorld);
    }
    else if (FParse::Command(&Cmd, TEXT("DEMOSPEED")))
    {
        return HandleDemoSpeedCommand(Cmd, Ar, InWorld);
    }
    else if( ExecPhysCommands( Cmd, &Ar, InWorld ) )
    {
        return HandleLogActorCountsCommand( Cmd, Ar, InWorld );
    }
    else 
    {
        return 0;
    }
}

bool UWorld::HandleDemoPlayCommand( const TCHAR* Cmd, FOutputDevice& Ar, UWorld* InWorld )
{
    FString Temp;
    const TCHAR* ErrorString = nullptr;

    if ( !FParse::Token( Cmd, Temp, 0 ) )
    {
        ErrorString = TEXT( "You must specify a filename" );
    }
    else if ( InWorld == nullptr )
    {
        ErrorString = TEXT( "InWorld is null" );
    }
    else if ( InWorld->GetGameInstance() == nullptr )
    {
        ErrorString = TEXT( "InWorld->GetGameInstance() is null" );
    }
    
    if (ErrorString != nullptr)
    {
        Ar.Log(ErrorString);

        if (GetGameInstance() != nullptr)
        {
            GetGameInstance()->HandleDemoPlaybackFailure(EDemoPlayFailure::Generic, FString(ErrorString));
        }
    }
    else
    {
        InWorld->GetGameInstance()->PlayReplay(Temp);
    }

    return true;
}

非常に簡単だった・・・・・

デバッグコマンド DEMOPLAY にファイル名を入れると、リプレイを再生してくれる

つまり、このデバッグコマンドのコードを見れば リプレイの実装が出来そうな予感

エンジンコード色々読んだけど、単純だった予感

UnrealEngine モジュールを使うときのメモ

必要になった背景

モジュール使ってますか? とりあえず今回 リプレイ機能を調査したかったので

#include "Runtime/NetworkReplayStreaming/NullNetworkReplayStreaming/Public/NullNetworkReplayStreaming.h"

を行いたかったのですが、NullNetworkReplayStreaming.h 内部でコンパイルエラーが出ます

#pragma once

#include "NetworkReplayStreaming.h"
#include "Core.h"
#include "Engine.h"
#include "ModuleManager.h"
#include "UniquePtr.h"
#include "OnlineJsonSerializer.h"
#include "Tickable.h"

当然 内部ヘッダにはパス通ってませんね

パスを通さなければ。。。。

おそらく、プロジェクトパスに Runtime/NetworkReplayStreaming/NullNetworkReplayStreaming/

追加すればビルド通るとおもうけど、それは Unrealの流儀じゃないので 正しい方法で行う

ビルドシステム

UnrealC#コードを使ったビルドシステムがある

プロジェクト名.Build.cs ってのがあるので そこを開く

// Fill out your copyright notice in the Description page of Project Settings.

using UnrealBuildTool;

public class プロジェクト名 : ModuleRules
{
    public プロジェクト名(TargetInfo Target)
    {
        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });

        PrivateDependencyModuleNames.AddRange(new string[] {  });

        // Uncomment if you are using Slate UI
        // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
        
        // Uncomment if you are using online features
        // PrivateDependencyModuleNames.Add("OnlineSubsystem");
        // if ((Target.Platform == UnrealTargetPlatform.Win32) || (Target.Platform == UnrealTargetPlatform.Win64))
        // {
        //      if (UEBuildConfiguration.bCompileSteamOSS == true)
        //      {
        //          DynamicallyLoadedModuleNames.Add("OnlineSubsystemSteam");
        //      }
        // }
    }
}

この PublicDependencyModuleNames.AddRange  の配列が、それなので "NetworkReplayStreaming" を追加してビルドすると OK

さくらVPSで Google G Suiteを使いメールアカウントを作成

メモなのでさらっと

まず、今までは GMailアドレスで仕事をしていたが、ビジネスも大きくしなきゃいけないので murasame-lab.com の、独自ドメインのメールアドレスを作ることにした

さくらVPSを使っているので、メールサーバを建てればよいし、知人と一緒に管理してもいいんだけど とりあえずは便利な外部メールサーバを使うことに

候補はいっぱいあった

Google G Suite

今回これを試用することにした。機能的には豊富で、ノーマルプランが 一人あたり 月500円と少しお高い 容量無制限だし 十分なんだけど。

Office365

Office365入っているので独自ドメインを使う事が可能

BizSpark

調べてないけどおそらく可能ではないか? 有り難いことに 申請は即通った! ただ、向こうのトラブルでBizSparkがまだ使える状態にないので今回は対象外

ロリポップ

暫く使ってない ロリポップアカウントあるので、独自ドメインでメール作れそうだけど そもそも 使ってないから削除してもいいよねと・・

お名前メール

お名前.com でドメイン取ったし、便利 なんと月42円で メンバー無制限。。 容量10Gプランでも77円・・ 安すぎる

Google G Suiteにした

理由は 1ヶ月試用可能なので 期間限定で試す

murasame-lab.com あてのメールを、Googleサーバに流すため、DNSの設定が必要だが その前段階として 認証用に、 http://murasame-lab.com のWebページの metaタグに、認証コードを入れる必要がある ので まずは Webページのmetaを書き換える

このあたりの手順は G Suiteがステップ・バイ・ステップで教えてくれるので便利

最後の関門がDNS設定。

G Suiteの設定ヘルプに さくらVPSがないので 色々と試して結果下記のように設定した

GoogleメールのDNSに転送

エントリ名 @ 種別 MX 値 1 ASPMX.L.GOOGLE.COM.

このような形式で指定されたMXを追加していく 5レコードあった。 さくらVPSの場合は 値の最初の文字が優先度。その後 半角スペースの後に 転送ドメインFQDN。最後にドット忘れずに!

元あったMXを削除

私の場合は 値 10 @ のMXがあったので削除した。優先度下げるだけでも動くと思うが一応。

TXTレコード追加

TXTレコードは本来 コメントだったと思うけど、今ではコメントに設定を書くので必要かもしれない

エントリ @ タイプ TXT 値 "@ v=spf1 mx ~all"

以上でデータを反映させて暫く待つと G Suiteでメール送受信が出来るようになる。 運が悪ければ 反映に1日ぐらいかかったりするけど たいていは数時間で反映される

会社のホームページリニューアル&現在の仕事状況

会社ホームページリニューアル

友達のWebデザイナに会社のページを作ってもらった

株式会社ムラサメ研究所

POPで可愛い感じにというオーダーだったと思う

まだ日付やメニューなど修正していくんだけど

あとはゲーム会社らしく、HTML5でページに遊び要素入れたい。

お仕事状況

現在稼働中ライン

現在 7-8人で、コンシュマータイトルを作成中 Unrealを使った対戦ゲーム 今のところ長期予定

今後

1ラインだけではリスクヘッジ出来ないため、あと2ラインほど確保できるようにしたい コンシュマーは技術力も必要で楽しいけど、リスクが高いし要求技術も高いので 新人育成として、スマホゲームやWebゲームのラインが欲しい

また、Web関連の仕事も欲しい。理由は周りにWeb関係多いので仕事を依頼しやすいから

また、自社案件も 高速ゲームサーバ等行いたいし、研修の意味でもゲームエンジンオープンソースで作りたい

でも基本的には、プログラマは案件のほうが多く 人が足りない。

インドとパキスタンにオフショアする計画もある 中国、ベトナム、エジプト等も 少し話はすすめてるけど

そういえば、お友達から仕事依頼も来ているので、ラインさえ確保すればなんとか・・・ 今はプログラマのみだけど 今後はアートディレクタや営業、プランナいれて ゲーム1本まるっと作れる体制作る!

IT以外

お茶のビジネスが、開始寸前。今 有識者の意見をもらい、ロードマップ作成中

洋服のセレクトショップは、アイディア段階だが、決まれば出資する

釣りビジネスは、まだスタートするには厳しい状態。もう少しアイディア練らないと・・

シェアハウス(ギークハウス)作成は、色々とありストップしている