DJproject_備忘録_1

# プロジェクト場所
-  https://github.com/masarina/DaijinAi

## 2024-10-24
- ChecksumCheekPlayer のつぎのプレイヤーをつくろう
    - 名前をDecode_g_SpiritBitDataPlayerDir/SpiritBitDataPlayer.py とし、「モード、文字数情報、データ」の3つに分けてメンバ変数に保持するプレイヤーとしよう。
    - 作っていこう
        ```
        """ 入力 """
        woP = self.one_time_world_instance.checksumCheekPlayer
        self.png_file_path = woP.png_file_path # 写真のパス
        self.processed_data = woP.processed_data # 8bit毎にスプリットしたデータ
        
        """ メイン """
        # 8bitデータを1次元的にし、さらにbit文字列に変換する。

        # modeの摘出
        
        # 文字数情報の摘出
        
        # データの摘出
        
        ```
        - mode演算子の取得Ok
        - 文字数情報は…
            ジェネレータのときに
            ```
            """
            指定されたモード指示子に基づいて、文字数のビット数を設定する。
            mode_indicator: str (4bitのモード指示子)
            char_count: int (格納する文字数)
            """
            if mode_indicator == "0001":  # 数字モード
                bit_count = format(char_count, '010b')  # 10bit
            elif mode_indicator == "0010":  # 英数字モード
                bit_count = format(char_count, '09b')  # 9bit
            elif mode_indicator == "0100":  # 8bitバイトモード
                bit_count = format(char_count, '08b')  # 8bit
            elif mode_indicator == "1000":  # 漢字モード
                bit_count = format(char_count, '08b')  # 8bit
            else:
                raise ValueError("Invalid mode_indicator. Ensure the mode is set correctly.")
            
            return bit_count
            ```
            と、したので
            ```
            モードが0010のとき、
            09b
            (↪︎ b(2進数)で09(文字)で表されている)
            なので、9bit取り出す
            ```
            と言った感じになる。

## 2024-10-25
- 文字数情報を取得できた
- データ部分を取得しよう
    ```
    # 8bitデータを1次元的にし、さらにbit文字列に変換する。
    mode_charNumInfo_data_flattenBit = flatten_numbers_and_to_str(self.processed_data)
    
    # modeの摘出
    self.mode = mode_charNumInfo_data_flattenBit[0:5]
    
    # 文字数情報の摘出
    self.charNumInfo_decimal, firstDatas_point = charNumInfo_catcher(
                                    mode=self.mode,
                                    str_bit=mode_charNumInfo_data_flattenBit,
                                )
    ```
    文字数情報を取得する時に、データ部分の最初のインデックスを返すようにして、データを取得としよう。

- つぎのプレイヤーを作ろう
    つぎのプレイヤーは
    モードをもとに
    データを復興するプレイヤーとしよう
    作った。(備忘録してない)
- ServerSideの構築が大幅完了した。
    次、InstanceSide(VRchatのインスタンスで動かす方)も作っていく。
    ServerSideの
    - Transformer
    - 二次元コード
    この2つをU#に変換したものをInstanceSideとする。
- 二次元コードのU#バージョンを作ろう。
    さて…まずは二次元コードを忘れない、新鮮な頭のうちに、二次元コードのU#バージョンを作ろう。
    ジェネレータ、リーダーのUdonSharpバージョンも用意する。
    全てジャグ配列で定義する必要が在る。

## 2024-10-28
- U#バージョンの二次元コードジェネレータを作る。
    プレイヤーのテンプレートは次のような感じ。(Gitに8ヶ月前に作ったU#バージョンのデバッグプレイヤーが残ってたので、それを改良した。)
    ```
    using UdonSharp;
    using UnityEngine;
    
    public class HelloMessagePlayer : SuperPlayer
    {
        private void Start()
        {
            // プレイヤーの名前を初期化
            this.myName = null;
        }
    
        public override string ReturnMyName()
        {
            return "HelloMessagePlayer";
        }
    
        public override string ExecuteMain()
        {
            Debug.Log("\n==== HelloMessagePlayer ExecuteMain ==============================");
    
            // HelloMessageを表示
            if (world != null && world.allDataPlayer != null)
            {
                string helloMessage = world.allDataPlayer.hello_message_str;
                Debug.Log($"HelloMessage: {helloMessage}");
            }
            else
            {
                Debug.LogError("world または allDataPlayer が null です。");
            }
    
            Debug.Log("\n==== HelloMessagePlayer ExecuteMain (END) ==============================\n");
    
            return "Completed";
        }
    }
    ```
    これをテンプレートとして、PythonコードをU#に変換していく。
    この作業はGPT4oで進める。
    直接U#ファイルを作らせるより、PythonをU#に変換させる方が断然、正しいコードをGPTは描いてくれますね。
    - UdonSharpにおいて、Unityでの動作について一つ確認。
        - 親クラスは、必ずしもとりあえず何かしらのオブジェクトにアタッチしなければ、UdonSharpは動かないのかな？
        ↓
        ![IMG_9961.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910368/2f1621b3-57d3-6f54-f6c3-ed4ee521cda6.jpeg)
        つまり、親クラスはオブジェクトにアタッチしなくても使える見たいですね(公式観るのが面倒…)
        (余談、もし親クラスはオブジェクトにアタッチすることが必須だった場合、全てのサブクラス分親クラスを用意する必要がある気がして怖かった。クラスの意味ないじゃん！ってなるの怖かった。)
        さて、確認が出来たのでジェネレータを作っていこう。
    - InitFromQrcodePlayerのUdonSharp化
        このプレイヤーだけ例を書き留めておこう。
        ##### Before
        ```
        import os, sys
        sys.path.append("../..")
        from Players_CommonPlayers.SuperPlayerDir.SuperPlayer import SuperPlayer 
        
        class InitFromQrcodePlayer(SuperPlayer):
            def __init__(self):
                super().__init__()  # スーパークラスの初期化メソッドを呼び出す
                self.my_name = None
                self.data = None
                self.mode = None
        
            def return_my_name(self):
                return "InitFromQrcodePlayer"
        
            def main(self):
                """
                このメソッド実行直前に、
                このスーパークラスのメンバ変数
                one_time_world_instanceに、
                最新のworldインスタンスを代入しています。
                
                このメソッド終了後、
                メインで使用しているworld_instanceを
                このスーパークラスのメンバ変数
                one_time_world_instanceで上書きし、
                更新しています。
                
                → つまり、このメソッド内で
                self.one_time_world_instanceを上書きすると、
                その内容が、反映されます。
                """
                
                print(f"{return_my_name}が実行されました。")
        
                # QRcodeにしたいデータ
                self.data = 12345
                self.mode = "numeric"
                
                # データは自身のイニシャライザのメンバ変数で保持、
                # またはjsonなどに出力した場合、そのパスを保持
                self.one_time_world_instance.initFromQrcodePlayer = self
        
                return "Completed"
        ```
        ##### After
        ```
        using UdonSharp;
        using UnityEngine;
        
        public class InitFromQrcodePlayer : SuperPlayer
        {
            private int data;
            private string mode;
        
            private void Start()
            {
                // プレイヤーの名前を初期化
                this.myName = null;
                this.data = 0;
                this.mode = string.Empty;
            }
        
            public override string ReturnMyName()
            {
                return "InitFromQrcodePlayer";
            }
        
            public override string ExecuteMain()
            {
                Debug.Log("\n==== InitFromQrcodePlayer ExecuteMain ==============================");
        
                // QRコードにしたいデータの設定
                this.data = 12345;
                this.mode = "numeric";
        
                // デバッグ出力でデータを表示
                Debug.Log($"Data: {data}");
                Debug.Log($"Mode: {mode}");
        
                // 実行結果をワールドのインスタンスに反映
                if (world != null)
                {
                    world.initFromQrcodePlayer = this;
                }
                else
                {
                    Debug.LogError("world が null です。");
                }
        
                Debug.Log("\n==== InitFromQrcodePlayer ExecuteMain (END) ==============================\n");
        
                return "Completed";
            }
        }
        ```
        素晴らしいっ
        ```
        string.Empty
        ```
        これは、Pythonみたいに "" でも良いんだってさ。

        ちょっと待ってUdonSharp側のBallPassSchedulePatternはpythonと少し異なるから、しっかり見なくちゃ。Unity的に、オブジェクトにアタッチした時点でファイルはインスタンスとして扱われる点で、BallPassSchedulePatternを調節したんだった。
        お昼休みに、GithubにUnityファイルごとGoogleDriveの方にアップロードしなきゃ…

    アップロードされない…

    
    うーん、なんだかGit上にあるアーカイブには
    ```
    public class FinalPlayer : SuperPlayer
    {
        public bool FinalPlayerReset()
        {
            myName = "FinalPlayer";
    
            return true;
        }
    
        public override string ReturnMyName()
        {
            return "FinalPlayer";
        }
    
        public override string ExecuteMain()
        {
            return "Completed";
        }
    }
    ```
    のように、myNameのリセットは、クラス独自でメソッドを持っている模様。
    ```
        public bool FinalPlayerReset()
        {
            myName = "FinalPlayer";
    
            return true;
        }
    ```
    …なぜnullにしていないのかも気になる…ぁぁ、なんでGoogleDriveって大きなファイルアップロードできないのかしら…
    今日は沢山神様がいじめて来る…残業だし…
        
    - （QRCodeModePlayerのUdonShape化）