【Unity】【Photon Fusion】GetKeyDownみたいに入力した瞬間を取得する方法

# はじめに
こちらのチュートリアルを参考にPhotonFusionのお勉強をしていたところ、
ジャンプ処理を`GetKey()`で処理してるのを、ボタン押したときだけ適用させたいな～と思ったので、
この記事を書いてみました

https://zenn.dev/photon_japan/articles/c5218f06215d88

# つくりかた
めっちゃ悩んだけど、全然難しいことではなかった
**結論：入力構造体(`INetworkInput`)に`Update`で入力状態して、コールバックの`OnInput`でセットする**

<br><br>

1. 入力管理する感じのクラス作って、`INetworkRunnerCallbacks`実装する
    ```.cs
    public class GameLauncher : SimulationBehaviour, INetworkRunnerCallbacks {}
    ```
    <br>
1. そんなかにコールバック定義
    ```.cs
    // これだけ使います
    public void OnInput(NetworkRunner runner, NetworkInput input)
    {

    }

    public void OnPlayerJoined(NetworkRunner runner, PlayerRef player) { }
    public void OnPlayerLeft(NetworkRunner runner, PlayerRef player) { }
    public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input) { }
    public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason) { }
    public void OnConnectedToServer(NetworkRunner runner) { }
    public void OnDisconnectedFromServer(NetworkRunner runner) { }
    public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token) { }
    public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason) { }
    public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message) { }
    public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList) { }
    public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data) { }
    public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }
    public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ArraySegment<byte> data) { }
    public void OnSceneLoadDone(NetworkRunner runner) { }
    public void OnSceneLoadStart(NetworkRunner runner) { }
    ```

    <br>
1. 自作の入力構造体とボタン列挙体作る
    - ボタンは`NetworkButtons`というのを使います
    ```.cs
    // 構造体
    public struct NetworkInputData : INetworkInput {
        public Vector3 Dir;
        public NetworkButtons Buttons;
    }

    // ボタン列挙体
    public enum InputButtons {
        Jump,
    }
    ```

    <br>
1. 入力構造体を入力管理クラスに宣言
    ```.cs
    public class GameLauncher : SimulationBehaviour, INetworkRunnerCallbacks {
        NetworkInputData inputData;

        // ...
    }
    ```

    <br>
1. `Update`にボタンの判定処理実装する
    - `NetworkButtons.Set()`で列挙体の値と入力判定値を入れる
    ```.cs
    void Update(){
        inputData.Buttons.Set(InputButtons.Jump, Input.GetKeyDown(KeyCode.Space));
    }
    ```

    <br>
1. `OnInput`コールバックにこんな感じで書く
    - `input.Set()`で入力値をセットする
    - 最後に`default`を代入して、現在のフレームの入力データをリセットする
    ```.cs
    public void OnInput(NetworkRunner runner, NetworkInput input)
    {
        // データ適用
        input.Set(inputData);

        // データリセット
        inputData = default;
    }
    ```


# 取得
`NetworkBehavior`を継承させたクラスの`FixedUpdateNetwork`内にこんな感じの処理書く
- `GetInput()`で`OnInput`コールバック内でセットされた値を取得できる
- `Buttons.IsSet()`で、指定したボタンの入力状態を取得できる

```Client.cs
if(Object.HasStateAuthority){
    if (GetInput(out NetworkInputData data)) {
        // ジャンプ入力判定
        if (data.Buttons.IsSet(InputButtons.Jump)) {
            print("pressed");
        }
    }
}
```


# 参考
https://zenn.dev/photon_japan/articles/c5218f06215d88

https://doc.photonengine.com/ja-jp/fusion/current/manual/network-input#sv0fkeph50qfqp5q