[TIL] 251120

๊น€์„ธํฌยท2025๋…„ 11์›” 20์ผ

โœ๏ธToday I Learned

ย ๐Ÿ“… 2025-11-20

  • ์–ธ๋ฆฌ์–ผ GAS: ํด๋ผ์ด์–ธํŠธ์—์„œ ์‹คํ–‰๋˜์ง€ ์•Š๋Š” ํŒจ์‹œ๋ธŒ ์–ด๋นŒ๋ฆฌํ‹ฐ ๋ฌธ์ œ ํ•ด๊ฒฐ

์–ธ๋ฆฌ์–ผ GAS: ํด๋ผ์ด์–ธํŠธ์—์„œ ์‹คํ–‰๋˜์ง€ ์•Š๋Š” ํŒจ์‹œ๋ธŒ ์–ด๋นŒ๋ฆฌํ‹ฐ ๋ฌธ์ œ ํ•ด๊ฒฐ

1. ๐ŸŽฏ ๋‚ด๊ฐ€ ํ•˜๋ ค๋˜ ๊ฒƒ (Goal)

  • ๋ชฉํ‘œ: ์–ธ๋ฆฌ์–ผ ์—”์ง„์˜ Gameplay Ability System (GAS)์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ์Šจ ์„œ๋ฒ„ ๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด ํ™˜๊ฒฝ์—์„œ ์ƒํƒœ ์œ ์ง€ํ˜• ํŒจ์‹œ๋ธŒ ์–ด๋นŒ๋ฆฌํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ์˜ ํŠน์ • ์ž…๋ ฅ(์˜ˆ: ์ˆซ์žํ‚ค 1)์ด ์žˆ์„ ๋•Œ ์ด ์–ด๋นŒ๋ฆฌํ‹ฐ๊ฐ€ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์•„ ํŠน์ • ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ๋งŒ๋“ค๊ณ ์ž ํ–ˆ๋‹ค.
  • ๊ตฌํ˜„ ๋ฐฉ์‹:
    1. ์–ด๋นŒ๋ฆฌํ‹ฐ ๋ถ€์—ฌ ์‹œ, ๋Šฅ๋ ฅ์ด ์ข…๋ฃŒ๋˜์ง€ ์•Š๊ณ  ํ™œ์„ฑํ™” ์ƒํƒœ๋ฅผ ์œ ์ง€.
    2. ํ™œ์„ฑํ™”๋œ ๋Šฅ๋ ฅ ๋‚ด์—์„œ Wait Gameplay Event ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ํƒœ๊ทธ๋ฅผ ๊ธฐ๋‹ค๋ฆผ.
    3. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ‚ค๋ฅผ ๋ˆ„๋ฅด๋ฉด SendGameplayEventToActor๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋ƒ„.

2. ๐Ÿคฏ ์ง๋ฉดํ•œ ๋ฌธ์ œ (Problem)

  • ํ˜„์ƒ: ์–ด๋นŒ๋ฆฌํ‹ฐ๊ฐ€ ํ˜ธ์ŠคํŠธ(์„œ๋ฒ„ ๊ฒธ ํด๋ผ์ด์–ธํŠธ)์—์„œ๋Š” ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ–ˆ์œผ๋‚˜, ์ผ๋ฐ˜ ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ์–ด๋นŒ๋ฆฌํ‹ฐ๊ฐ€ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š๊ฑฐ๋‚˜, ํ™œ์„ฑํ™”๋˜๋”๋ผ๋„ ํ‚ค ์ž…๋ ฅ์— ๋”ฐ๋ฅธ ํ›„์† ๋™์ž‘์ด ์‹คํ–‰๋˜์ง€ ์•Š์Œ.

  • ์˜ค๋ฅ˜ ์ฝ”๋“œ:

    UGA_Hotkey::UGA_Hotkey() {
        // ...
        NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalOnly; // ๋ฌธ์ œ์˜ ์›์ธ 1
    }
    
    void UGA_Hotkey::OnGiveAbility(...) {
        // ...
        if (ActorInfo->IsLocallyControlled() && !Spec.IsActive()) { // ๋ฌธ์ œ์˜ ์›์ธ 2
           // ... TryActivateAbility ํ˜ธ์ถœ
        }
    }

3. ๐Ÿ’ก ๋ฌธ์ œ์˜ ์›์ธ ๋ฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• (Cause & Solution)

1. ์ดˆ๊ธฐ ํ™œ์„ฑํ™” ๊ถŒํ•œ ๋ฌธ์ œ

๋Šฅ๋ ฅ์˜ NetExecutionPolicy๊ฐ€ LocalOnly๋กœ ์„ค์ •๋˜์–ด ์žˆ์–ด ์„œ๋ฒ„์˜ ๊ถŒํ•œ์ด ์žˆ๋Š” ์ƒํƒœ์—์„œ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์Œ. ๋˜ํ•œ OnGiveAbility์—์„œ IsLocallyControlled() ์กฐ๊ฑด๋งŒ ํ™•์ธํ•˜์—ฌ, ํด๋ผ์ด์–ธํŠธ์˜ ๋กœ์ปฌ ๋ณต์‚ฌ๋ณธ์—์„œ๋งŒ ํ™œ์„ฑํ™”๊ฐ€ ์‹œ๋„๋˜์–ด ์„œ๋ฒ„์—๋Š” ์ƒํƒœ๊ฐ€ ๋ณต์ œ๋˜์ง€ ์•Š์Œ.

ํ•ด๊ฒฐ: ์„œ๋ฒ„ ๊ถŒํ•œ์œผ๋กœ ์ดˆ๊ธฐ ํ™œ์„ฑํ™”

  1. NetExecutionPolicy๋ฅผ EGameplayAbilityNetExecutionPolicy::ServerOnly๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์–ด๋นŒ๋ฆฌํ‹ฐ์˜ ์‹คํ–‰ ๊ถŒํ•œ์„ ์„œ๋ฒ„๋กœ ์œ„์ž„.
  2. OnGiveAbility์—์„œ ActorInfo->IsNetAuthority() (์„œ๋ฒ„)์ผ ๋•Œ๋งŒ TryActivateAbility๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋Šฅ๋ ฅ์ด ์„œ๋ฒ„์—์„œ ๊ถŒํ•œ ์žˆ๊ฒŒ ํ™œ์„ฑํ™”๋˜๋„๋ก ์ˆ˜์ •.

2. ์ด๋ฒคํŠธ ์ „์†ก ๋ฌธ์ œ

๋Šฅ๋ ฅ์ด ServerOnly๋กœ ์„œ๋ฒ„์—์„œ ํ™œ์„ฑํ™”๋˜์–ด Wait Gameplay Event ๋…ธ๋“œ๊ฐ€ ์„œ๋ฒ„์—์„œ๋งŒ ์‹คํ–‰๋จ. ๊ทธ๋Ÿฐ๋ฐ ํด๋ผ์ด์–ธํŠธ์—์„œ ํ˜ธ์ถœ๋œ SendGameplayEventToActor๋Š” ๋กœ์ปฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ผ ๋ฟ, ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์— ์ „๋‹ฌ๋˜์ง€ ์•Š์•„ ์„œ๋ฒ„์˜ ๋Œ€๊ธฐ ์ค‘์ธ ๋Šฅ๋ ฅ์ด ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์ง€ ๋ชปํ•จ.

ํ•ด๊ฒฐ: Server RPC๋ฅผ ํ†ตํ•œ ์ด๋ฒคํŠธ ์ „๋‹ฌ

  1. ํด๋ผ์ด์–ธํŠธ์˜ ํ‚ค ์ž…๋ ฅ ์ฒ˜๋ฆฌ ๋ถ€๋ถ„์—์„œ SendGameplayEventToActor๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์‹ , ์„œ๋ฒ„๋กœ ์ „์†ก๋˜๋Š” Server RPC ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ.
  2. ์„œ๋ฒ„ RPC ํ•จ์ˆ˜ ์•ˆ์—์„œ UAbilitySystemComponent::HandleGameplayEvent ๋˜๋Š” SendGameplayEventToActor๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์„œ๋ฒ„์˜ ๋Šฅ๋ ฅ์—๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌ.

๐Ÿ’ก ๋А๋‚€ ์  (What I Felt)

๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด ํ™˜๊ฒฝ์—์„œ Gameplay Ability System (GAS)์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š”, ๋‹จ์ˆœํžˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ ์ด์ƒ์œผ๋กœ "์ด ์ฝ”๋“œ๊ฐ€ ์ง€๊ธˆ ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜๋Š”๊ฐ€, ํด๋ผ์ด์–ธํŠธ์—์„œ ์‹คํ–‰๋˜๋Š”๊ฐ€?"์— ๋Œ€ํ•œ ๋„คํŠธ์›Œํฌ ๊ถŒํ•œ(Authority) ์ดํ•ด๊ฐ€ ๊ฐ€์žฅ ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๋‹ค์‹œ ํ•œ๋ฒˆ ๊นจ๋‹ฌ์•˜๋‹ค. ํŠนํžˆ ํŒจ์‹œ๋ธŒ ์–ด๋นŒ๋ฆฌํ‹ฐ๋ผ๋„ ์„œ๋ฒ„์—์„œ ๊ถŒํ•œ์„ ๊ฐ€์ง€๊ณ  ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ ์ž…๋ ฅ์ด ์„œ๋ฒ„์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ Server RPC๋ฅผ ์‚ฌ์šฉํ•ด ์•ˆ์ „ํ•˜๊ฒŒ ๊ถŒํ•œ์„ ๋„˜๊ฒจ์•ผ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์‹ฑํฌ(Sync) ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. LocalOnly ์ •์ฑ…์€ ์‹ ์ค‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ๊ฒ ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€