プログラム研究 備忘録

java,C#,Unity等の備忘録です。経済理論も少し。

備忘録について

まずはお話を頂いていた企業様。

個別に挨拶はさせて頂いたのですが、

こちらの備忘録へアクセスされる方も多いようですので、

こちらにも、記載させて頂きます。

 

就職活動を行っておりましたが、

御陰様で、貰い手が決まりました。

 

現在はそちらの会社で全力で働きたいと考えておりますので、

皆様には、ご迷惑をおかけしますが、

何卒ご容赦下さい。

 

 

そして、一旦プログラムとは別のことを学ぶ必要がありそうなので、

記事の内容も経済理論等へシフトしていく予定です。

 

忙しくなるといいですなぁ。

 

ipadでリモートデスクトップ

前々からやろうと思って、忘れていたリモートデスクトップをやってみました。

方法もアプリの数も沢山あるみたいですねぇ。

 

以前、教えてもらったのですがバタバタしていて忘れてしまいました。

どこにメモったかなぁ。。。

 

とりあえず試したのは2つ

 

・PocketCloud Remote Desktop

・TeamViewer

 

2つとも無料でいけます。

気になる方は検索してみてください。

 

気に入ったのはTeamViewerですかね。

なんせ楽です。PoketCloudの後で入れたんですが、衝撃のお手軽感。

インストール終われば1分でできます。

 

進化してるのねぇ。。。

あ、ちなみに脱獄しなくてもできます。

 

これで寝ながら色々できるぞ!

ゲームサーバの起動方法② Scriptメモ

using UnityEngine;
using System.Collections;

public class NetworkManager : MonoBehaviour {
    // ゲームタイプ名.
    const string GameTypeName = "SampleDaze"; //
    
    // ローカルIPアドレスとポート.
    const string LocalServerIP = "127.0.0.1"; // 開発用.
    const int ServerPort = 25000;
    
    string playerName;
    string gameServerName;
    
    void Start()
    {
        playerName = "Player"+Random.Range(0,99999999).ToString();
        gameServerName = "Server"+Random.Range(0,99999999).ToString();
        UpdateHostList();
    }
    
    
    // 状態.
    public enum Status {
        NoError,                // エラーなし.
        
        LaunchingServer,        // サーバー起動中.
        ServerLaunched,            // サーバーが起動に成功.
        LaunchServerFailed,        // サーバーの起動に失敗.
        
        ConnectingToServer,        // サーバーに接続中.
        ConnectedToServer,        // サーバーに接続に成功.
        ConnectToServerFailed,    // サーバーへの接続に失敗.
        
        DisconnectedFromServer, // サーバーから切断された.
    };
    
    
    Status _status = Status.NoError;
    public Status status {get{return _status;} private set{_status = value;}}
    
    // サーバーを起動する.
    public void LaunchServer(string roomName)
    {
        status = Status.LaunchingServer;
        StartCoroutine(LaunchServerCoroutine(gameServerName));
    }
    
    bool useNat = false; // natパンチスルーを使用するか.
    IEnumerator CheckNat()
    {
        bool doneTesting = false; // 接続テストが終わったか.
        bool probingPublicIP = false;
        float timer = 0;
        useNat = false;
        
        // 接続テストをしてNATパンチスルーが必要かしらべる.
        while (!doneTesting) {
            ConnectionTesterStatus connectionTestResult = Network.TestConnection();
            switch (connectionTestResult) {
            case ConnectionTesterStatus.Error:
                // 問題が発生した.
                doneTesting = true;
                break;
                
            case ConnectionTesterStatus.Undetermined:
                // 調査中.
                doneTesting = false;
                break;
                
            case ConnectionTesterStatus.PublicIPIsConnectable:
                // パブリックIPアドレスを持っているのでNATパンチスルーは使わなくていい.
                useNat = false;
                doneTesting = true;
                break;
                
                
            case ConnectionTesterStatus.PublicIPPortBlocked:
                // パブリックIPアドレスを持っているようだがポートがブロックされていて接続できない.
                useNat = false;
                if (!probingPublicIP) {
                    connectionTestResult = Network.TestConnectionNAT();
                    probingPublicIP = true;
                    timer = Time.time + 10;
                }
                
                else if (Time.time > timer) {
                    probingPublicIP = false;         // reset
                    useNat = true;
                    doneTesting = true;
                }
                break;
            case ConnectionTesterStatus.PublicIPNoServerStarted:
                // パブリックIPアドレスを持っているがサーバーが起動していない.
                break;
                
            case ConnectionTesterStatus.LimitedNATPunchthroughPortRestricted:
            case ConnectionTesterStatus.LimitedNATPunchthroughSymmetric:
                // NATパンチスルーに制限がある.
                // サーバーに接続できないクライアントがあるかもしれない.
                useNat = true;
                doneTesting = true;
                break;
            case ConnectionTesterStatus.NATpunchthroughAddressRestrictedCone:
            case ConnectionTesterStatus.NATpunchthroughFullCone:
                // NATパンチスルーによりサーバーとクライアンは問題なく接続できる.
                useNat = true;
                doneTesting = true;
                break;
                
            default:
                Debug.Log ( "Error in test routine, got " + connectionTestResult);
                break;
            }
            yield return null;
        }
    }

    
    
    // サーバーを起動するコルーチン.
    IEnumerator LaunchServerCoroutine(string roomName)
    {
        yield return  StartCoroutine(CheckNat());
        
        // サーバーを起動する.
        NetworkConnectionError error = Network.InitializeServer(32,ServerPort,useNat);
        if (error !=  NetworkConnectionError.NoError) {
            Debug.Log("Can't Launch Server");
            status = Status.LaunchServerFailed;
        } else {
            // マスターサーバーにゲームサーバーを登録する.
            MasterServer.RegisterHost(GameTypeName, gameServerName);
        }
        
    }
    
    // サーバーに接続する.
    public void ConnectToServer(string serverGuid,bool connectLocalServer)
    {
        status = Status.ConnectingToServer;
        if (connectLocalServer)
            Network.Connect(LocalServerIP,ServerPort);
        else
            Network.Connect(serverGuid);
    }
    
    
    // サーバーが起動した.
    void OnServerInitialized()
    {
        status = Status.ServerLaunched;
    }
    
    // サーバーに接続した.
    void OnConnectedToServer()
    {
        status = Status.ConnectedToServer;
    }
    
    // サーバーへの接続に失敗した.
    void OnFailedToConnect(NetworkConnectionError error) {
        Debug.Log("FailedToConnect: " + error.ToString());
        status = Status.ConnectToServerFailed;
    }
    
    // プレイヤーが切断した.
    // (サーバーが動作しているコンピュータで呼び出される).
    void OnPlayerDisconnected(NetworkPlayer player) {
        Network.RemoveRPCs(player);
        Network.DestroyPlayerObjects(player);
    }
    
    // サーバーから切断された.
    void OnDisconnectedFromServer(NetworkDisconnection info) {
        Debug.Log("DisconnectedFromServer: " + info.ToString());
        status = Status.DisconnectedFromServer;
        Application.LoadLevel(0);
    }    
    
    // ステータスを得る.
    public Status GetStatus()
    {
        return status;
    }

    // プレイヤーネームを得る.
    public string GetPlayerName()
    {
        return playerName;
    }


    void OnDestroy()
    {
        if (Network.isServer) {
            MasterServer.UnregisterHost ();
            Network.Disconnect ();
        }
    }

    //-------------------- ロビー関連. --------------------
    // マスターサーバに登録されているゲームサーバのリストを更新する.
    public void UpdateHostList()
    {
        MasterServer.ClearHostList();
        MasterServer.RequestHostList(GameTypeName);
    }
    
    // スターサーバに登録されているゲームサーバのリストを取得する.
    public HostData GetHostList()
    {
        return MasterServer.PollHostList();
    }
    
    // マスターサーバとNATファシリテータのIPアドレスを設定する.
    void SetMasterServerAndNatFacilitatorIP(string masterServerAddress,string facilitatorAddress)
    {
        MasterServer.ipAddress = masterServerAddress;
        Network.natFacilitatorIP = facilitatorAddress;
    }
    
    // マスターサーバーへの登録を削除する.
    public void UnregisterHost()
    {
        MasterServer.UnregisterHost();
    }
    
    //-------------------- 設定GUI -------------------
    void OnGUI()
    {
        if ((Network.isServer || Network.isClient))
            return;
        
        // 高さ480の(0,0)中心を基準にする.
        float scale = Screen.height / 480.0f;
        GUI.matrix = Matrix4x4.TRS(new Vector3(Screen.width * 0.5f,Screen.height * 0.5f,0),Quaternion.identity,new Vector3(scale,scale,1.0f));
        
        GUI.Window(0, new Rect(-200,-200,400,400), NetworkSettingWindow, "Network Setting");
    }
    
    Vector2 scrollPosition;
    
    void NetworkSettingWindow(int windowID) {
        // プレイヤー名の設定.
        GUILayout.BeginHorizontal();
        GUILayout.Label("Player Name: ");
        playerName = GUILayout.TextField(playerName,32);
        GUILayout.EndHorizontal();
        
        // ゲームサーバー名の設定.
        GUILayout.BeginHorizontal();
        GUILayout.Label("Game Server Name: ");
        gameServerName = GUILayout.TextField(gameServerName,32);
        GUILayout.EndHorizontal();
        
        // ゲームサーバーを起動する.
        GUILayout.BeginHorizontal();
        GUILayout.FlexibleSpace();
        if (GUILayout.Button ("Launch"))
            LaunchServer(gameServerName);
        GUILayout.EndHorizontal();
        GUILayout.Space(20);
        
        // ゲームサーバーリスト.
        GUILayout.BeginHorizontal();
        GUILayout.Label("Game Server List (Click To Connect):");
        GUILayout.FlexibleSpace();
        if (GUILayout.Button("Refresh"))
            UpdateHostList();
        GUILayout.EndHorizontal();
        
        scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.Width(380), GUILayout.Height(200));
        HostData
hosts = GetHostList();  // サーバ一覧を取得.
        if (hosts.Length > 0) {
            foreach (HostData host in hosts)
                if (GUILayout.Button(host.gameName,GUI.skin.box,GUILayout.Width(360)))
                    ConnectToServer(host.guid,false);
        } else
            GUILayout.Label("No Server");
        GUILayout.EndScrollView();
        
        // ローカルサーバに接続.
        if (GUILayout.Button("Connect Local Server")) {
            ConnectToServer("",true);
        }
        
        // ステータスの表示.
        GUILayout.Label("Status: "+status.ToString());
        
    }
}

ゲームサーバの起動方法①(Script後述)

・ゲームサーバへの登録

クライアントが起動したゲームサーバを参照するには、起動したゲームサーバを、

マスターサーバに登録する必要がある。マスターサーバは広く公開されているので、

クライアントはマスターサーバに接続して目的のゲームサーバを探し出す。

 

MasterServer.RegisterHost(ゲームタイプ名、ゲーム名、コメント);

※コメントは検索時に表示するが、省略してもよい。

 

・ゲームサーバの検索

クライアントはNetWorkクラスのConnect関数を呼び出すことでゲームサーバに接続できるが、接続するゲームサーバを探索し指定しなくてはならない。

以下の2つの方法

 

IPアドレスとポート番号を直接指定する

・マスターサーバからサーバ一覧を取得し選択する

 

 

IPアドレスとポート番号から直接指定

ゲームサーバが固定されたIPアドレスを持ている場合に使用。

※NATパンチスルーが必要ない。

通常は使用しないが、ゲーム開発中など1台でサーバとクライアントを動作させたいときは、以下の方法で自分自身のサーバに接続することができる。

 

Network.Connect("000.0.0.1",00000);

 

ゲームサーバのポートが00000で待ち受けていると仮定すると、CPがNTに接続されていない場合や、マスターサーバが混み合っていて使用できない時などに利用ができる。(遅延がない)

 

・マスターサーバからゲームサーバ一覧を取得

マスターサーバに問い合わせる方法。通常はこちらを使用する。

MSに登録されているリスト一覧を送信してくれるようにリクエストを出す。

サンプルだぜサーバであれば、、、

 

MasterServer.RequestHostList("SampleDaze");

となる。

 

次にゲームサーバから送られてきたリストを受け取る。

MasterServerClassのPollHostList関数で受け取る。

 

HostData[] hosts = MasterServer.PollHostList();

 

リストは徐々に到着してくるため、PollHostList関数の戻り値を毎フレーム監視し、

サーバのリストを更新する必要がある。

 

PollHostList関数の戻り値によって、ゲームサーバの一覧はHostData型の配列で渡される。この型にはゲームサーバをマスターサーバに登録した時のゲーム名(ルーム名)やコメントが入っている。

これを表示させ、ユーザーにどのゲームに参加するかを選ばせる。

そしてHostData型に含まれるguid変数を使用して接続を行う。

 

Network.Connect(host[0].guid);

 

接続が完了したら、、、

OnConnectedToServer();

ゲームサーバ側は、

OnPlayerConnected(NetworkPlayer otherPlayer);

がUnityから呼び出され通知される。

 

NATによるアドレス変換

・基本概念整理

インターネットにはCPの住所としてのIPアドレスが存在する。

IPアドレスを宛先としてCP同士は通信し合うことができる。

しかし、INで広く通用するグローバルアドレスではなく、限られた範囲内の

プライベートアドレスが割り当てられることがある。

その割当は、プロバイダ、自宅等のルータによって行われる。

 

このプライベートIPアドレスではINにアクセスすることはできないので、

アクセスする際にルーターによって、プライベートとグローバルと相互変換される。

 

・NATによるアドレス変換

上記の変換がNATと呼ばれる。

グローバルIPアドレスとプライベートIPアドレスの変換は変更されることもあり、

さらに以前に送信を行ったCPからしか通信を受け取らない制限がある場合もある。

これでは、ゲームに参加するCP同士を接続することはできない。

 

UnityにはマスターサーバとNATファシリテータと呼ばれる2つのサーバを使用して、

プライベートなCPと接続できるようにする、NATパンチスルーと呼ばれる機能がある

 

・NAT

Full cone NAT

Address-Restricted cone NAT

Port-Restricted cone NAT

Symmetric NAT

 

のTypeがあり、ゲームに参加しているCPのNATの組み合わせがPort-Restricted cone NAT、Symmetric NATの組み合わせ、およびSymmetric NAT同士の組み合わせでは、

NATパンチスルーは行えない。

マスターサーバとNATファシリテータはテスト用にUnity社に設置されており、

初期設定ではこのUnity社のマスターサーバに接続される。

 

 

ネットワーク基礎メモ

実装すること

 

・数人のユーザーが集まってゲームを始めることができる

・自分のプレイヤーキャラクターが他のユーザのゲーム中に登場する

・自分のプレイヤーキャラクターを移動させると、他のユーザーのゲームでも

 同じようにプレイヤーキャラクターが移動する。敵も同様

・自分が敵に攻撃を当てると、敵がダメージを受けて、みんなで攻撃すれば

 早く倒せる

・みんなとアイテムを奪い合って、誰が先にアテムをとったか競う

 

クライアントとサーバーについて

クライアントサーバ:要求を受け取り処理する役目のCP

 

クライアント:サーバに処理を要求するCP

 

マスターサーバ:ユーザーが起動した無数に存在するゲームサーバを管理するための

        サーバ

 

NATファシリータ:クライアンとサーバ間の通信の仲介を行ってくれる

 

回線速度:bps(bit per seconds)1秒間に転送できるビット数

     128bps = 128000ビット(約16KB)