3
2

【Unity】Photon Fusion 向け拡張メソッドの紹介メモ

Last updated at Posted at 2023-04-03

※たまにコードを改修しているため、説明が古くなっています

コード

説明

Second.ToTick()

// 秒単位 と Tick単位 の変換をします
public static int ToTick(this int second, NetworkRunner runner) => (int)(second / runner.DeltaTime);
public static int ToTick(this float second, NetworkRunner runner) => (int)(second / runner.DeltaTime);
public static float ToSecond(this int tick, NetworkRunner runner) => tick * runner.DeltaTime;

// Runner.Tick から second 秒経過した際の Tick を返します
public static int GetTickAfter(this NetworkRunner runner, float second) => runner.Tick + (int)(second / runner.DeltaTime);

// Runner.Tick が tick を超えてから経過した秒数を返します
public static float ElapsedTime(this NetworkRunner runner, int tick) => (runner.Tick - tick) * runner.DeltaTime;
// Runner.Tick が tick になるまでの秒数を返します
public static float RemainingTime(this NetworkRunner runner, int tick) => -runner.ElapsedTime(tick);

// Runner.Tick が tick を超えたかどうか判定します
public static bool HasPassed(this NetworkRunner runner, int tick) => (runner.Tick - tick) > 0;
public static bool HasReached(this NetworkRunner runner, int tick) => (runner.Tick - tick) >= 0;
public static bool IsAt(this NetworkRunner runner, int tick) => runner.Tick == tick;
public static bool HasntPassed(this NetworkRunner runner, int tick) => (runner.Tick - tick) <= 0;
public static bool HasntReached(this NetworkRunner runner, int tick) => (runner.Tick - tick) < 0;

Array

NetworkArray.ForLoop()

使用例.cs
NetArray.ForEach(item => Debug.Log(item));
NetArray.ForLoop((i, item) => Debug.Log(i + " : " + item));

NetworkArray.Replace()

NetworkArray の要素から一致する条件を探し、そこに value を代入します。

使用例.cs
// 全要素を -1 に変更
NetArray.ReplaceAll(-1);
// 全要素を 2 倍
NetArray.ReplaceAll(v => v * 2);
// -2 の要素を全て 0 に変更
NetArray.Replace(v => v == -2, 0);
// 0 の要素を1つだけ 100 に変更
int index = NetArray.ReplaceOne(v => v == 0, v => 100);
// 0 の要素3つを 100, 200, 300 に変更
bool success = NetArray.ReplaceOneByOne(v => v == 0, 100, 200, 300);

NetworkArray.OnValueChanged()

NetworkArray で変化した要素を探し、処理を行います。

使用例.cs
[Networked(OnChanged = nameof(OnChangedArray)), Capacity(16)] NetworkArray<int> Array { get; }
private static void OnChangedArray(Changed<ClassName> changed) => changed.Behaviour.ChangedArray(changed);
private void ChangedArray(Changed<ClassName> changed)
{
    Array.OnValueChanged(changed, c => c.Array, (index, beforeValue, afterValue) => { /* 省略 */ } );
}

v2 は Changed の代わりに ChangeDetector で取得した前の値を引数に入れてください。

UniRx

TickTimer.OnCompleted()

使用例.cs
//  完了時に実行
tickTimer.OnCompleted(Runner).Subscribe(_ => { /* 省略 */ } ).AddTo(this);
// 有効の間、常に実行 
tickTimer.OnUpdated(Runner).Subscribe(_ => { /* 省略 */ } ).AddTo(this);
// 有効の間、Runner.DeltaTime の間隔で実行
tickTimer.OnRunnerUpdated(Runner).Subscribe(_ => { /* 省略 */ } ).AddTo(this);
// RemainingTime の整数部分が更新された時に実行
tickTimer.OnCountDowned(Runner).Subscribe(_ => { /* 省略 */ } ).AddTo(this);

その他

Changed.LoadOld() ver1のみ

既存のChanged.LoadOld()の利便性を高めました。

使用例.cs
var prevValue = changed.LoadOld(behaviour => behaviour.Value);
var newValue = changed.Behaviour.Value;

UpdateFlow()

Tick の経過時間に応じて実行する関数を変える処理を簡潔に書けます。

使用例.cs
void FixedUpdateNetwork()
{
    Runner.UpdateFlow(ShotTick, new int[] { 5, 10, 5 }, BeforeShot, Shot, AfterShot);
}
void BeforeShot(int elapsedTick) => { /*省略*/ }
void Shot(int elapsedTick) => { /*省略*/ }
void AfterShot(int elapsedTick) => { /*省略*/ }

Runner.Host()

// Host の PlayerRef を取得します
public static PlayerRef Host(this NetworkRunner runner)
    => runner.GameMode == GameMode.Server ? PlayerRef.None : runner.Simulation.Config.DefaultPlayers - 1;
// 専用サーバか判定します。Host Mode と Server Mode を平行に実装する際、専用サーバに対して不要な処理を省く用途で利用します
public static bool IsServerMode(this NetworkRunner runner) => runner.GameMode == GameMode.Server;

PlayerRef.IsHost()

// PlayerRef が Host か判定します
public static bool IsHost(this PlayerRef playerRef, NetworkRunner runner) => playerRef == runner.Simulation.MaxConnections;
// PlayerRef が自分か判定します
public static bool IsMe(this PlayerRef playerRef, NetworkRunner runner) => playerRef == runner.LocalPlayer;
// PlayerRef が NetworkObject/NetworkBehaviour の 入力権限/所有権 を持っているか判定します
public static bool HasInputAuthorityTo(this PlayerRef playerRef, NetworkObject no) => playerRef == no.InputAuthority;
public static bool HasStateAuthorityTo(this PlayerRef playerRef, NetworkObject no) => playerRef == no.StateAuthority;
public static bool HasInputAuthorityTo(this PlayerRef playerRef, NetworkBehaviour nb) => playerRef == nb.Object.InputAuthority;
public static bool HasStateAuthorityTo(this PlayerRef playerRef, NetworkBehaviour nb) => playerRef == nb.Object.StateAuthority;

RpcInfo.Source()

Host/Server が RPC を呼ぶと RpcInfo.Source は None になります。
この拡張メソッドは、Host が RPC を呼んだ際に Host の PlayerRef を利用できるようにしたものです。

public static PlayerRef Source(this RpcInfo info, NetworkRunner runner) => info.Source.IsNone ? runner.Host() : info.Source;

NetworkBehaviour.GetSeed()

乱数のシード値として利用できる値を取得します。
(カスタムプロパティに seed を追加する必要があります)

使用例.cs
Random.InitState(networkBehaviour.GetSeed());

NetworkObject.TryAssignInputAuthority()

再接続や Host Migration を行う際、ConnectionToken を元に NetworkObject の入力権限の変更を試みます。

public static bool TryAssignInputAuthority(this NetworkObject obj, NetworkRunner runner, Guid token, bool noAssignment = true)
{
    foreach (var p in runner.ActivePlayers)
    {
        if (new Guid(runner.GetPlayerConnectionToken(p)) != token) continue;
        obj.AssignInputAuthority(p);
        return true;
    }
    if (noAssignment) obj.AssignInputAuthority(PlayerRef.None);
    return false;
}

PhotonFusionUtil

便利クラスも含めています。

Runner

どこからでも NetworkRunner を取得できます。
Runenr を複数利用している際は一つ目しか取れないので注意が必要です。

var runner = PhotonFusionUtil.Runner;
3
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
3
2