ํฌ์ŠคํŠธ

๐ŸŒ” Photon Fusion 2

๐Ÿ’ซ Memo


๐Ÿซง NetworkRunner

  • ํฌํ†ค ๋งค๋‹ˆ์ €
    • ํฌํ†ค๊ณผ ๊ด€๋ จ๋œ ์„ค์ •, ์กฐ์ž‘์„ ํ•˜๊ธฐ ์œ„ํ•œ
  • INetworkRunnerCallbacks
    • ํฌํ†ค ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค, ๋งค๊ฐœ๋ณ€์ˆ˜์— runner๊ฐ€ ๋“ค์–ด๊ฐ
  • runner.Spawn (๋„คํŠธ์›Œํฌ Instantiate)
  • runner.Despawn (๋„คํŠธ์›Œํฌ Destroy)

๐Ÿซง NetworkObject

  • ๋™๊ธฐํ™” ๋˜๊ธฐ ์œ„ํ•œ ๋ชจ๋“  ์˜ค๋ธŒ์ ํŠธ๋Š” NetworkObject๊ฐ€ ๋‹ฌ๋ ค์žˆ์–ด์•ผ ํ•จ
  • ํŠน๋ณ„ํ•œ ๊ธฐ๋Šฅ์€ ์—†๊ณ , ๋‹จ์ˆœํžˆ ๋„คํŠธ์›Œํฌ ์ƒ์—์„œ ๋ˆ„๊ตฐ์ง€ ๊ตฌ๋ณ„ํ•˜๋Š” ID๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ

๐Ÿซง NetworkTransform

  • Transform์„ ๋™๊ธฐํ™” ์‹œํ‚ค๋Š” Class
  • ์ด๋ฅผ ์ƒ์† ๋ฐ›์œผ๋ฉด ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Transform์„ ๋™๊ธฐํ™”

  • Interpolation
    • ๋„คํŠธ์›Œํฌ ์ƒ์˜ ์ด์œ ๋กœ ์›€์ง์ž„์ด ๋š๋š ๋Š๊ฒจ๋ณด์ด๋Š” ๊ฒƒ์„ ๋ณด๊ฐ„์‹œ์ผœ์ฃผ๋Š”
    • ๋•Œ๋ฌธ์— ์ตœ์ƒ์œ„/๋ถ€๋ชจ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ, ์ž์‹ ์˜ค๋ธŒ์ ํŠธ(Mesh, Sprite ๋“ฑ ์‹œ๊ฐ์ ์ธ ํ‘œํ˜„)๋ฅผ ํƒ€๊ฒŸ์œผ๋กœ ์ง€์ •ํ•ด์ค˜์•ผ ํ•จ

๐Ÿซง NetworkBehaviour

  • FixedUpdateNetwork๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

๐Ÿซง FixedUpdateNetwork

  • ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ‹ฑ, ์˜ˆ์ธก๊ณผ ์‹ค์ œ ์—ฐ์‚ฐ, ์žฌ์˜ˆ์ธก ๋“ฑ ํ•œ ํ”„๋ ˆ์ž„์— ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰ ๋  ์ˆ˜ ์žˆ์Œ
  • Update, FixedUpdate ๋Œ€์‹  ์‚ฌ์šฉ
  • (Update, FixedUpdate๋Š” ์œ ๋‹ˆํ‹ฐ ์ด๋ฒคํŠธ๋‹ˆ๊นŒ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰๋˜๋ฉด ์–ด์ƒ‰ํ•˜๋‹ˆ๊นŒ)
  • GetInput(out ์ž…๋ ฅ ๊ตฌ์กฐ์ฒด)๋กœ ์ž…๋ ฅ์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ์Œ

  • Fusion2
  • Proxies ๋” ์ด์ƒ ๊ธฐ๋ณธ์ ์œผ๋กœ FixedUpdateNetwork๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š์Œ
  • Runner.SetIsSimulated(Object, true)๋กœ ์„ค์ • ๊ฐ€๋Šฅ (Spawned์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒŒ ๋ฒ ์ŠคํŠธ)

๐Ÿซง Runner.Spawn

  • onBeforeSpawned์€ Server/Host์—์„œ๋งŒ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Network ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์— ์“ธ ๊ฒƒ

๐Ÿซง Spawned

  • if (Object.HasStateAuthority == false) return;์™€ ํ•จ๊ป˜ ์“ด๋‹ค๋ฉด, VRChat์—์„œ Start-IsMaster ๊ฐ™์ด ๋งˆ์Šคํ„ฐ(Host)๊ฐ€ ๋”ฑ ํ•œ ๋ฒˆ ์‹คํ–‰ํ•˜๋Š” ๋ช…๋ น ๊ฐ€๋Šฅ
    • ๊ฒŒ์ž„ ์ƒํƒœ, ์˜ค๋ธŒ์ ํŠธ ์ƒํƒœ ์ดˆ๊ธฐํ™”

๐Ÿซง PlayerRef

  • ํ”Œ๋ ˆ์ด์–ด๋ฅผ ๊ตฌ๋ถ„ ์ง“๋Š”
  • NetworkObject Spawn ์‹œ, ์ด ์˜ค๋ธŒ์ ํŠธ์˜ ์ž…๋ ฅ ๊ถŒํ•œ์„ ๋ˆ„๊ฐ€ ๊ฐ€์งˆ์ง€ PlayerRef๋กœ ์„ค์ • ๊ฐ€๋Šฅ
    • NetworkBehaviour์˜ FixedUpdateNetwork, GetInput์—์„œ ์–ด๋–ค ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ง€

๐Ÿซง TickTimer

  • ์ฒ˜์Œ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ๊ธฐ์ค€ Timer
  • TickTimer.CreateFromSeonds(Runner, ์‹œ๊ฐ„)
  • FixedUpdateNetwork์—์„œ timer.Expired(Runner)๋กœ ์ฒดํฌํ•˜๊ณ  Despawn

  • Awake๋Š” ๋„คํŠธ์›Œํฌ๋ž‘ ๋™๊ธฐํ™” ๋˜์ง€์•Š๊ธฐ ๋•Œ๋ฌธ์— Awake์—์„œ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ์•ˆ๋จ
  • ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ ์‹œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋กœ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•จ (๊ทธ๋ž˜์•ผ ์ฒ˜์Œ ์ƒ์„ฑ๋  ๋•Œ ๋™๊ธฐํ™”)

๐Ÿซง ๋ฌผ๋ฆฌ ์—ฐ์‚ฐ

  • Rigidbody, NetworkRigidbody
    • ์„ฑ๋Šฅ ์ƒ์˜ ์ด์œ ๋กœ dll(์–ด์…ˆ๋ธ”๋ฆฌ)๋กœ
  • NetworkTransform ๋งˆ์ฐฌ ๊ฐ€์ง€๋กœ Interpolation
  • NetworkTransform๋ฅผ ๋ถ™์ด์ง€ ์•Š์Œ
  • ์„ฑ๋Šฅ์ด ์•ˆ์ข‹์•„์„œ ์‚ฌ์šฉ ์ž์ œ

๐Ÿซง ์ž…๋ ฅ

  • OnInput์„ ํ†ตํ•ด ์ž…๋ ฅ์„ ๋ฐ›์Œ (INetworkRunnerCallbacks)
    • INetworkInput์„ ์ƒ์† ๋ฐ›๋Š”, ์‚ฌ์šฉ์ž ์ •์˜ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•ด์•ผ ํ•จ (i.e. NetworkInputData)
    • OnInput์—์„œ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ๊ฐ’์„ ์„ค์ •ํ•˜๊ณ , input.Set(๊ตฌ์กฐ์ฒด); ๋กœ ํ• ๋‹น
  • ์ž…๋ ฅ์„ ๋ฐ›์•„์˜ฌ ๋•Œ๋„ ์ด๋ฅผ ๋ฐ›์•„์™€์•ผ ํ•จ

  • ์™œ ์ด๋ ‡๊ฒŒ ํ•˜๋Š๋ƒ
    • ์„œ๋ฒ„๊ฐ€ ์ด๋™์„ ์‹œ์ผœ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ
      • ๋„คํŠธ์›Œํฌ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹œ๊ฐ„ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•œ๋‹ค
      • ํ•œ ๋ช…์ด ๋ชจ๋“  ๊ถŒํ•œ์„ ๊ฐ€์ง€๋Š” ์„œ๋ฒ„๊ฐ€ ๋˜๊ณ , ํด๋ผ๋Š” ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด ์„œ๋ฒ„๊ฐ€ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋„๋ก ํ•˜๋Š”๋ฐ,
      • ํด๋ผ๊ฐ€ ๊ณต๊ฒฉ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €๋‹ค
      • ์„œ๋ฒ„์—์„œ ์Šน์ธ์„ ๋ฐ›์•„์•ผ ํ•˜๋Š”๋ฐ
      • ๊ฐ€๋Š”๋ฐ 2ํ‹ฑ, ๋Œ์•„์˜ค๋Š”๋ฐ 2ํ‹ฑ -> 4ํ‹ฑ ํ›„์— ๊ณต๊ฒฉ ํ•˜๋Š” ๊ฒŒ ๋ณด์—ฌ์ง (์ง€์—ฐ)
      • ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์˜ˆ์ธก์„ ์‚ฌ์šฉ
        • 2ํ‹ฑ ์ •๋„ ๊ฑธ๋ฆด๊ฑฐ๋ผ ์˜ˆ์ƒํ•˜๊ณ  2ํ‹ฑ ์ดํ›„ ๋ฏธ๋ฆฌ ๋กœ์ปฌ๋กœ ๊ณต๊ฒฉ
      • ํด๋ผ๋Š” ์ด๋™์— ๊ด€ํ•œ ๊ถŒํ•œ์€ ์—†๊ณ , ์ž…๋ ฅ์— ๊ด€ํ•œ ๊ถŒํ•œ๋งŒ ์žˆ์Œ
        • ์„œ๋ฒ„๊ฐ€ ์ด๋™ ์‹œํ‚ด
      • ํด๋ผ๊ฐ€ ์ด๋™ ์‹œํ‚จ ๊ฒƒ์€ ์˜ˆ์ธก

๐Ÿซง ์˜ˆ์ธก

  • ์˜ˆ๋ฅผ ๋“ค์–ด ์ด์•Œ์ด๋‚˜ ๊ณต
  • ๋ชจ๋“  ์ด๋™์„ ์„œ๋ฒ„๋กœ ๊ฒ€์ฆ ๋ฐ›์œผ๋ฉด ๋š๋š ๋Š๊ฒจ ๋ณด์ผ ๊ฒƒ
  • ํ•˜์ง€๋งŒ ์•ž์œผ๋กœ ๊ณ„์†ํ•ด์„œ ๊ฐˆ ๊ฒƒ ๊ฐ™์Œ -> ๋”œ๋ ˆ์ด ๋งŒํผ ์˜ˆ์ธก
  • ๋”œ๋ ˆ์ด ์ดํ›„ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์ด๋™ ๋ฐ์ดํ„ฐ๊ฐ€ ๋„์ฐฉํ•œ ์ดํ›„ ๋‹ค์‹œ ๋˜ ๋”œ๋ ˆ์ด ๋งŒํผ ์˜ˆ์ธก, ๋ฐ˜๋ณต
  • ์ฐธ๊ณ  : ์˜ˆ์ธกํ•  ๋•Œ ๋งˆ๋‹ค FixedUpdateNetwork๊ฐ€ ์‹คํ–‰, FixedUpdateNetwork๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์˜ˆ์ธก

๐Ÿซง NetworkBool

  • ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด์…ˆ๋ธ”๋ฆฌ ๋งˆ๋‹ค ๋ถˆ ๋ฐ”์ดํŠธ ํฌ๊ธฐ๊ฐ€ ๋‹ค๋ฅด๋‹ค?
  • ํ†ต์‹ ํ•  ๋•Œ ๋ฐ”์ดํŠธ ํฌ๊ธฐ๊ฐ€ ๋‹ค๋ฅด๋ฉด ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์–ด์„œ
  • ํฌ๊ธฐ๊ฐ€ ๊ฐ™์€ ๊ฒƒ์ด ๋ณด์žฅ๋˜๋„๋ก, NetworkBool
  • ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋Š” ์ƒ๊ด€ ์—†์Œ

๐Ÿซง Network ์–ดํŠธ๋ฆฌ๋ทฐํŠธ

  • ํ”„๋กœํผํ‹ฐ ๋™๊ธฐํ™”
  • StateAuthority ํ”Œ๋ ˆ์ด์–ด ๊ธฐ์ค€
  • OnChanged = nameof(ํ•จ์ˆ˜ ์ด๋ฆ„)
    • FixedUpdateNetwork๋Š” ์˜ˆ์ธก, ์‹ค์ œ ์—ฐ์‚ฐ, ์žฌ์˜ˆ์ธก ๋“ฑ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœ ๋  ์ˆ˜ ์žˆ์Œ
    • OnChanged๋Š” ํ”„๋ ˆ์ž„ ๊ธฐ์ค€์œผ๋กœ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€
      • ํ•œ ํ”„๋ ˆ์ž„ ์‚ฌ์ด์— True, False, True๋กœ ๋ณ€ํ™”ํ–ˆ๋‹ค๋ฉด, ํ•œ ํ”„๋ ˆ์ž„ ์‚ฌ์ด์— ๊ฐ’์ด ๋ณ€ํ™”ํ•˜์ง€ ์•Š์•˜์Œ์œผ๋กœ OnChanged๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Œ
  • VRChat๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, StateAuthority(VRChat์—์„  Owner)๊ฐ€ ์•„๋‹Œ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด, ๋กœ์ปฌ๋กœ๋งŒ ๋™์ž‘ํ•˜๊ณ , ์–ธ์ œ๋“ ์ง€ StateAuthority(Owner)์˜ ๊ฐ’์œผ๋กœ ๋™๊ธฐํ™” ๋  ์ˆ˜ ์žˆ์Œ

  • Fusion 2
  • ํ”„๋กœํผํ‹ฐ์˜ Get/Set์„ ์ปค์Šคํ…€ ์ฝ”๋“œ๋กœ ๋Œ€์‹ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Get/Set์„ ๊ธฐ์ค€์œผ๋กœ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜๋ฉด ์•ˆ๋˜๊ณ , ๋ณ„๋„์˜ Setter ๊ตฌํ˜„๋„ ๋กœ์ปฌ๋กœ๋งŒ ๋™์ž‘ํ•จ
  • Spawned์—์„œ ChangeDetector ๋ณ€์ˆ˜์— GetChangeDetector(ChangeDetector.Scoure.SimulationState)๋ฅผ ํ• ๋‹นํ•˜๊ณ , Render์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€
1
2
3
4
5
6
7
8
9
10
11
12
public override void Render()
{
	foreach (var change in _changeDetector.DetectChanges(this))
	{
		switch (change)
		{
			case nameof(๋ณ€์ˆ˜):
				// ๋ณ€ํ™” ์‹œ ์ˆ˜ํ–‰ํ•  ๋ช…๋ น
				break;
		}
	}
}
  • ์ด๋Ÿฌํ•œ ๋™์ž‘์€ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ณ  (์˜ˆ์ธก ์ดํ›„ ํ‹€๋ฆฐ ์˜ˆ์ธก์„ ๊ณ ์น˜๋ ค๊ณ  ํ•œ ๋ฒˆ ๋” ์‹คํ–‰๋œ๋‹ค๋˜์ง€), ์Šคํ‚ต ๋  ์ˆ˜ ์žˆ๊ณ  (๋ฐ์ดํ„ฐ๊ฐ€ ๋„๋‹ฌํ•˜๊ธฐ๋„ ์ฑ„ ์ „์— ์›๋ž˜ ๊ฐ’์œผ๋กœ ๋Œ์•„์˜จ๋‹ค๋˜์ง€), ๋ˆ„๋ฝ๋  ์ˆ˜ ์žˆ์Œ (Packet Drop)
  • RPC๋ณด๋‹ค ๋น ๋ฅธ ์‹œ์ ์— ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Œ (๊ฐ’์ด ๋ณ€ํ™”ํ•œ ๋„คํŠธ์›Œํฌ Tick ์ดํ›„ ๋ฐ”๋กœ)

  • Spawned๊ฐ€ ์‹คํ–‰๋˜๋Š” ์‹œ์ ์—๋Š” ์ด๋ฏธ Network ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ ๋ถ™์€ ์†์„ฑ๋“ค์ด ๋ชจ๋‘ ๋™๊ธฐํ™” ๋œ ์ดํ›„

๐Ÿซง Render

  • ์‹œ๊ฐ์ ์ธ ๊ณ„์‚ฐ์€ Render์—์„œ Like LateUpdate
  • FixedUpdateNetwork๋Š” ์˜ˆ์ธก, ์‹ค์ œ ์—ฐ์‚ฐ, ์žฌ์˜ˆ์ธก ๋“ฑ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœ ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋„คํŠธ์›Œํฌ๊ฐ€ ํ•„์š”์—†๋Š” ์‹œ๊ฐ ์ ์ธ ์—ฐ์‚ฐ์€ ์ค‘๋ณต ์—ฐ์‚ฐ์œผ๋กœ ์ž์› ๋‚ญ๋น„๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ

๐Ÿซง Remote Procedure Calls, RPC

  • ์›๊ฒฉ Procedure/ํ•จ์ˆ˜ ์ฝœ
  • ์—„๊ฒฉํ•˜๊ฒŒ ๋™๊ธฐํ™” ๋˜์ง€ ์•Š์Œ, ํ‹ฑ๋„ ์‚ฌ์šฉ ์•ˆํ•จ
    • ์ง€์—ฐ๋˜๊ฑฐ๋‚˜, ๋กœ์Šค, ์†์‹ค๋  ์ˆ˜ ์žˆ์Œ
    • Update์—์„œ ๊ทธ๋ƒฅ ๋ณด๋ƒ„
      • if (Input && Object.HasInputAuthority) RPC_SendMessage("Sans");
  • ํฌ๊ฒŒ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒƒ, Like ํ•˜์Šค ๊ฐ์ •ํ‘œํ˜„

๐Ÿซง ETC

  • ์œ„๋Š” ํ˜ธ์ŠคํŠธ ๋ชจ๋“œ
  • Shared Mode : ๊ฐ์ž ์ด๋™ ๊ถŒํ•œ์„ ๊ฐ€์ง
  • Predictive Spawn : ํด๋ผ์—์„œ Spawning๋„ ์˜ˆ์ธก
  • Lag Compensation : ์ง€์—ฐ ๋ณด์ƒ, ํด๋ผ ๊ธฐ์กด์œผ๋กœ ํŒ์ • (ํ•ต ๋ฌธ์ œ)
  • Area Of Interest : Interest Area์— ์žˆ์ง€ ์•Š๋Š” ์˜ค๋ธŒ์ ํŠธ๋Š” ๋™๊ธฐํ™”ํ•˜์ง€ ์•Š๋Š”
์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.