LoginSignup
6
2

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-12-23

プロローグ

「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はここを参考にしました

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

起動

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への投稿コードはこちらを参考にしました。

ソースについて

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://127.0.0.1:8000/quote
にアクセス

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

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

最後に

  • 今回のはほんの小さなサンプルです。
  • 実際はデータベースに入れましょう。
  • quoteのURLもきちんとしましょうね。
  • ファイル名も今回sample.pyとかだったので名前きちんとしましょう。
  • 今回はローカルで行いましが実際はサーバを立てて置きましょう。
  • だれかキチンと作ったらシェアしてね。それか僕が作ったらAssetStoreに置くかも?
  • Prefabも対応するのもいいかも?
6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2