Help us understand the problem. What is going on with this article?

他人のシーン編集を見える化するぜ!

More than 3 years have passed since last update.

プロローグ

「Advent Calendar2016Unity 2 Advent Calendar 2016」の記事だよ。
だれかが書こうとしてたけど、12月12日はとっくに過ぎてたんで上書きますw
もとの方はUniRxで書こうとしてたっぽいから、僕もUniRxも使うことにしますね。

前書き

チームでUnity使っていて、シーン編集をするときにいちいちチャット部屋で共有とか、他の人に確認するの手間かと思います。
それを見える化する方法を考えました。

今回使うもの

  • Unity 5.5.0x1-CollabOreview
  • UniRx 5.5.0 (Unityとほぼ同じだw)
  • Python 3.5
  • gunicorn 19.6.0
  • Falcon 1.1.0

※今回DBは面倒なのでプレーンテキストにしますw

サーバ準備

API作るのにFalconが楽そうだったのでそうします。
PHP使いたい人はPHP使って下さい。

バーチャル環境

virtualenv-3.4 falcon_apps
source bin/activate

Falconとgunicorn入れるよ

pip install falcon gunicorn

Pythonのコード

sample.py
#!/usr/bin/env python
# -*- coding:utf-8 *-

import falcon
import json

FNAME = 'text.json' 

class QuoteResource:
    def on_get(self, req, resp):
        str = self.read()
        # resp.body = json.dumps(str)
        resp.body = str

    def on_post(self, req, resp):
        resp.status = falcon.HTTP_200
        resp.content_type = 'text/plain'
        resp.body = 'post!!'
        # リクエストボディを読み込んで JSON を解析
        body = req.stream.read().decode('utf-8')
        print(body)
        self.write(body)

    # 本当はDBから書く
    def write(self, data):
        # 追記なのでa
        with open(FNAME, 'a') as outfile:
            json.dump(data, outfile, indent=4, sort_keys=True, separators=(',', ':'))
            # これがないと改行がない
            outfile.write('\n')

    # 本当はDBから読む
    def read(self):
        content = ''
        with open(FNAME) as fp:
            for line in fp:
                data = json.loads(line)
                dic = json.loads(data)
                msg = '{} が {} の {} を編集しました ({})'.format(dic['user'], dic['screenPath'] , dic['sceneName'], dic['time'])
                print(msg)
                content += msg + '\n'

        return content

api = falcon.API()
api.add_route('/quote', QuoteResource())

Falconはここを参考にしました

https://freedom-man.com/blog/python-falcon/

jsonのファイル記載と、読み込み系はここから参考に(Martin Thomaさんのコメント)

http://stackoverflow.com/questions/12309269/how-do-i-write-json-data-to-a-file-in-python

起動

gunicorn sample:api

sampleはファイル名sample.pyから、
apiは中にある変数名。

Unity側

UniRXはAsseetStoreからとってきて下さい。
別にUniRXを使わずにWWWを生で書いてもOKです。
こちらを書きます。Editorフォルダに入れなくてもいいですが、入れた方がいいかも?

MyAssetModificationProcessor.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UniRx;

public class MyAssetModificationProcessor : AssetModificationProcessor
{
    [Serializable]
    public class CustomModel
    {
        public string user;
        public string screenPath;
        public string sceneName;
        public string time;
    }

    public static string[] OnWillSaveAssets(string[] paths)
    {
        // Get the name of the scene to save.
        string user = "shinriyo";
        string scenePath = string.Empty;
        string sceneName = string.Empty;

        foreach (string path in paths)
        {
            if (path.Contains (".unity")) {
                scenePath = Path.GetDirectoryName (path);
                sceneName = Path.GetFileNameWithoutExtension (path);
                string msg= string.Format ("{0}が{1}パスの{2}ファイルを編集中です.",
                    user, scenePath, sceneName
                );
                Debug.Log (msg);

                // Postリクエスト
                // form要素設定
                var obj = JsonUtility.ToJson(new CustomModel {
                    user = user,
                    screenPath = scenePath,
                    sceneName = sceneName,
                    time = DateTime.Now.ToString ()
                });

                WWWForm form = new WWWForm();
                form.AddField("data", obj);

//              ObservableWWW.Post ("http://127.0.0.1:8000/quote", form)
                byte[] data = System.Text.Encoding.UTF8.GetBytes (obj);
                ObservableWWW.Post ("http://127.0.0.1:8000/quote", data)
                    // タイムアウト時間設定.
                    .Timeout(TimeSpan.FromSeconds(30))
                    .Subscribe(result =>
                        {
                            try
                            {
                                // JSONをパース.
                                Debug.Log("ok");
                            }
                            catch (System.Exception e)
                            {
                                Debug.Log("JSONのパースに失敗しました.");
                            }
                        },
                        err =>
                        {
                            if (err.GetType() == typeof(System.TimeoutException))
                            {
                                Debug.Log("タイムアウトしました.");
                            }
                            else
                            {
                                Debug.Log("通信に失敗しました.");
                            }
                        });
            }

            if (sceneName.Length == 0)
            {
                return paths;
            }
        }

        return paths;
    }
}

これを記載して配置しておくだけで、スクリプトが勝手にPOSTしてくれます。。

Webへの投稿コードはこちらを参考にしました。

http://belhb.hateblo.jp/entry/2016/05/02/025713

ソースについて

CustomModelとかわざわざ作るの面倒なので、無名クラス(new {hoge="val1", bar="val2"})とかでできればよいのに!

Formでやるとdata=パラメータがくっついてしまう。

WWWForm form = new WWWForm();
form.AddField("data", obj);
ObservableWWW.Post ("http://127.0.0.1:8000/quote", form)

substringとかで一生懸命data=を消したりとかやろうとしてしてしまいましたが、

今回のソースコードのようにbyte[]にしました。

この時ここを参考

http://naichilab.blogspot.jp/2014/08/unityunirxrest-apipost.html

実行

シーンを編集して保存してみて下さい。

http://127.0.0.1:8000/quote
にアクセス

Screen Shot 2016-12-23 at 9.02.22 PM.png

こんな感じのログが見えます。

最後に

  • 今回のはほんの小さなサンプルです。
  • 実際はデータベースに入れましょう。
  • quoteのURLもきちんとしましょうね。
  • ファイル名も今回sample.pyとかだったので名前きちんとしましょう。
  • 今回はローカルで行いましが実際はサーバを立てて置きましょう。
  • だれかキチンと作ったらシェアしてね。それか僕が作ったらAssetStoreに置くかも?
  • Prefabも対応するのもいいかも?
shinriyo
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away