목차

반응형

1. 롤 공격 애니메이션 속도 분석

2. 원하는 결과물

3. 스크립트 설명

 

 

 

 

1. 롤 공격 애니메이션 속도 분석

게임에서 공격 속도에 따라서 애니메이션을 어떻게 해야 할까?

일단 갓겜 롤을 기준으로 생각해보자.

 

먼저 공격 속도 변수에 대해서 생각해보자. 공격속도는 1회 공격하는 회수에 대한 값이다.

2.5 -> 초당 2.5회 공격

0.5 -> 초당 0.5회 공격

 

두 개의 영상을 준비했다. 크 친절함 보소

 

 

첫 번째 영상은 공격속도 0.2의 그레이브즈

 

두 번째 영상은 공격속도 4.5의 제이스

 

그레이브즈

그레이브즈의 경우 공격 속도가 0.2면 5초에 한 번 공격하는 꼴인데 정상 속도의 공격 애니메이션을 재생하고 약 3~4초간 기다리는 것을 볼 수 있다.

 

제이스

제이스의 경우 공격 속도가 4.5니까 1초에 대략 4대를 때리는데 어찌 보면 좀 어색할 정도로 망치를 엄청 빨리 휘두른다. 즉 애니메이션의 배속이 된 것을 알 수 있다.

 

우리가 구현해야 하는 공격 애니메이션 속도 방식은 다음과 같다.

 

공격 애니메이션을 기본적으로 재생했을 때 걸리는 시간을 1초라고 가정하자.

그렇다면 해당 캐릭터는 공격 속도가 1이면 애니메이션 속도를 변경하지 않고 계속해서 공격하면 문제없다.

만약에 버프나 통하여 공격 속도가 1보다 빨라지면 애니메이션의 재생속도도 빨라진만큼 배속을 해줘야하고 공격속도가 디버프를 통하여 1보다 느려지면 기본 속도로 재생을 시켜주고 남은 시간은 기다리도록 하면 된다.

 

여기서 프레임 개념이 필요하다.

 

이것은 유니티 캐릭터가 공격하는 애니메이션이다.

공격 애니메이션은 기본적으로 1초에 한번 재생되는 것을 기본으로 하였다.

그리고 프레임 재생 비율은 1초에 30 프레임이다.

 

공격 속도 개념과 같이 설명하자면...

공격속도 2 -> 1초에 두번 공격 -> 1초에 60 프레임재생 -> 60/30 비율로 재생 -> 두 배속

공격 속도 1 -> 1초에 한번 공격 -> 1초에 30 프레임재생 -> 30/30 비율로 재생 -> 정배 속

공격 속도 0.5 -> 2초에 한번 공격 -> 2초에 30 프레임재생 -> 30/60 비율로 재생? -> 정배 속으로 재생하고 대기

 

 

2. 원하는 결과물

설명이 좀 길었는데 최대한 친절하게 설명하기 위해서 노력했다.

내가 만들고 싶은 결과물은 다음과 같다.

 

롤과 똑같은 방식이다.

 

3. 유니티 프로젝트 설명

 

공격 애니메이션 에셋은 아래 무료 에셋을 사용했다.

https://assetstore.unity.com/packages/3d/animations/warrior-pack-bundle-1-free-36405

 

Warrior Pack Bundle 1 FREE - Asset Store

This is a sample package of the Warrior Pack Bundle 1 Note: This asset works in Unity 5. This asset contains 3 animations for each of the 4 warriors in the pack (12 animations total), so that you can test and evaluate if they will work for your project bef

assetstore.unity.com

 

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class AttackController : MonoBehaviour
{
    
    /// <summary>
    /// 캐릭터의 애니메이터
    /// </summary>
    [SerializeField] private Animator animator;

    /// <summary>
    /// UI - 공격속도 인풋박스
    /// </summary>
    [SerializeField] private InputField inputFieldAttackSpeed;
    
    /// <summary>
    /// UI - 공격 정보 표기
    /// </summary>
    [SerializeField] private Text textInfo;

    
    // Start is called before the first frame update
    void Start()
    {
        //최초 공격속도 설정
        SetAttackSpeed(attackSpeed);
    }

    /// <summary>
    /// UI로 공격 속도 변경시
    /// </summary>
    public void OnInputFieldChange(InputField inputField)
    {
        SetAttackSpeed(float.Parse(inputField.text));
    }

    /// <summary>
    /// 실제 공격속도 변경해주기
    /// </summary>
    private void SetAttackSpeed(float _attackSpeed)
    {
        attackSpeed = _attackSpeed;
        
        //공격 쿨타임 계산
        attackCoolTime = 1f / attackSpeed;
        
        //최초 공격 바로 시작하도록 설정
        currentAttackCoolTime = attackCoolTime;
        
        //공격속도가 1보다 빠르면 애니메이션 빠르게 재생하기 위해서 배속 설정, 아니면 기본속도 1로 재생
        if (attackSpeed > 1) animator.SetFloat("AttackSpeed", attackSpeed);
        else animator.SetFloat("AttackSpeed", 1);
        
        //UI 초기화
        inputFieldAttackSpeed.text = attackSpeed.ToString();
        textInfo.text = string.Format("공격 속도 : {0}\n" +
                                      "공격 애니메이션 재생하는데 걸리는 시간 : {1}\n" +
                                      "공격 쿨타임 {2}/{3}",attackSpeed,1f/attackSpeed, currentAttackCoolTime,attackCoolTime);
    }
    
    /// <summary>
    /// 공격 시작
    /// </summary>
    public void StartAttack()
    {
        StartCoroutine("EnumAttack");
    }

    /// <summary>
    /// 공격 종료
    /// </summary>
    public void EndAttack()
    {
        StopCoroutine("EnumAttack");
    }

    /// <summary>
    /// 공격속도
    /// </summary>
    private float attackSpeed;

    /// <summary>
    /// 1회 공격하는데 기다려야하는 시간 -> 공격속도 변경시 계산
    /// </summary>
    private float attackCoolTime;

    /// <summary>
    /// 공격하고나서 시간이 얼마나 경과했는지 카운트
    /// </summary>
    private float currentAttackCoolTime;
    
    /// <summary>
    /// 지속적으로 공격
    /// </summary>
    private IEnumerator EnumAttack()
    {
        while (true)
        {
            //만약 공격 쿨타임이 돌았으면
            if (currentAttackCoolTime >= attackCoolTime)
            {
                //쿨타임 초기화하고 공격을 개시한다.
                currentAttackCoolTime = 0;
                Attack();
            }

            textInfo.text = string.Format("공격 속도 : {0}\n" +
                                          "공격 애니메이션 재생하는데 걸리는 시간 : {1}\n" +
                                          "공격 쿨타임 {2}/{3}",attackSpeed,1f/attackSpeed, currentAttackCoolTime.ToString("F2"),attackCoolTime);
            currentAttackCoolTime += Time.deltaTime;       
            yield return null;
        }
    }

    /// <summary>
    /// 공격 트리거 발동
    /// </summary>
    private void Attack()
    {
        animator.SetTrigger("PunchTrigger");
    }
}

 

 

 

이 부분이 핵심이다. 공격 속도가 빠르면 애니메이션의 Speed Multipler 설정에 추가해둔 AttackSpeed라는 Parameter에 따라 빠르게 재생될 수 있도록 하면 된다.

 

해당 스크립트 파일과 전체 프로젝트는 파일로 공유하도록 하겠다.

 

 

프로젝트 전체 다운로드

 

AttackController.cs
0.00MB

 

반응형
반응형

1. 개요

2. ASLR : 메모리 주소는 항상 바뀐다

3. 게임 가디언 VS 유니티 앱

3-1. 메모리 주소 접근 unsafe 코드

4. 게임 가디언 VS 안티 치트 변수 암호화 기능

4-1. 안티 치트 obscured 변수 암호화 원리

5. 게임 가디언 VS 안티 치트 변수 암호화 기능 강화 버전

5-1. 개발 도중 이상한 점(슈뢰딩거의 변수)

6. 게임 가디언 VS 메모리 변조 디텍터

7. 결론

 

 

 

 

 

 

 

1. 개요

와 목차만 봐도 양이 굉장히 많다.

근데 실제로 회사에서 이것만 연구하느라 거의 2일 정도 시간을 소비했다.

회사에서 안티치트라는 무려 50$짜리 해킹 방지 에셋을 사용하는데 쓰는 것은 좋은데 어떤 원리로 작동하는지 그리고 실제로 해커 입장에서 테스트해보면서 해킹 방지가 되는지 누군가는 확인해보고 연구해볼 필요가 있다고 생각이 되어서 연구를 하게 되었다.

유니티 게임 개발자들도 이 글을 읽고 많은 도움이 되었으면 좋겠다.

재밌게 탐구하기도 했고 안티 치트를 뚫어서 메모리 변조를 해보고 싶다는 생각이 들었다. 언젠가 시간이 나보면 해볼 거다.

해킹 개깐지

 

계속해서 언급할 안티 치트 에셋(꼭 없어도 괜찮다. 어떤 식으로 암호화를 하는지 세세하게 보여줄 것이기 때문에 이해만 하면 되겠다.)

https://assetstore.unity.com/packages/tools/utilities/anti-cheat-toolkit-152334

 

Anti-Cheat Toolkit - Asset Store

🌎 demo ▶ videos 💬 forum 📄 API reference 💌 support 🕵 Anti-Cheat Toolkit (ACTk) 🕵 is here to add some extra pain to the guys who cheat / hack / crack something in your game. Includes various anti cheat tricks and techniques in one place, easy to use, with fu

assetstore.unity.com

 

2. ASLR : 메모리 주소는 항상 바뀐다

먼저 본격적으로 실험에 들어가기 전에 한 가지 알아둬야 하는 개념이 있다.

Address Space Layout Randomization

 

간단히 말하자면 앱이 실행될 때마다 메모리 주소가 랜덤 하게 배정되어서 내가 만든 게임에서 gold 변수가 가지는 메모리가 앱을 실행할 때마다 다른 메모리 주소를 갖게 되는 것이다.

이렇게 함으로써 앱의 보안을 강화시킬 수 있다고 한다.

그렇기 때문에 앞으로 있을 메모리 해킹에서 해킹할 변수는 동일하지만 메모리 주소는 계속해서 바뀐다는 것을 알아두도록 하자.

 

ASLR에 대한 자세한 내용은 아래 위키에 잘 나와있다.

https://en.wikipedia.org/wiki/Address_space_layout_randomization

 

Address space layout randomization - Wikipedia

Address space layout randomization (ASLR) is a computer security technique involved in preventing exploitation of memory corruption vulnerabilities. In order to prevent an attacker from reliably jumping to, for example, a particular exploited function in m

en.wikipedia.org

 

좀 특이한 점이라면 생각보다 고안되고 적용된 지 오래된 기술은 아니라는 점

안드로이드는 2015년도에 본격적으로 채택, MAC, 리눅스, 윈도우 전부 2000년대에 본격적으로 도입되었다.

 

 

3. 게임 가디언 VS 유니티 앱

자 그럼 이제 본격적으로 유니티 앱에서 게임 가디언을 통해 메모리 변조를 해볼 건데 간단하게 정말로 게임 가디언이 해킹하는 변수의 주소가 실제 변수의 주소가 맞는지 확인해볼 것이다.

 

해킹할 변수는 InGameGold 인게임 골드다.

코드를 보면 

inGameGold라는 private 변수의 메모리 주소를 받아와서 출력해준다.

이 주소를 유니티의 텍스트에다가 넣어줘서 핸드폰에서 확인이 가능하도록 하였다.

 

그리고 평범하게 게임 가디언으로 쉽게 뚫어서 변수의 주소를 찾았다.

 

게임의 한가운데에 보면 텍스트가 하나 있는데 인게임 골드 변수의 주소다. 둘이 일치하는 것을 확인할 수 있다.

 

그렇다면 궁금증은 풀렸다. 게임 가디언이 접근하는 변수의 주소와 실제 앱에서 할당받는 주소는 동일하구나!

 

3-1. 메모리 주소 접근 unsafe 코드

메모리 주소 접근하는 코드를 사용하기 위해서는 unsafe와 fixed 기능을 사용해야 한다.

 

아래 게시물을 참고하자

https://ajh322.tistory.com/223

 

유니티 오류 Unsafe code may only appear if compiling with /unsafe. Enable "Allow 'unsafe' code" in Player Settings to fix this error.

유니티에서 메모리 주소에 접근하는 코드를 사용하면 unsafe 관련하여 아래 에러가 발생한다. Unsafe code may only appear if compiling with /unsafe. Enable "Allow 'unsafe' code" in Player Settings to fix..

ajh322.tistory.com

 

4. 게임 가디언 VS 안티 치트 변수 암호화 기능

이제 본 게임 시작 안티 치트에서 제공하는 변수 암호화 기능을 사용하고 게임 가디언으로 뚫으려고 하면 어떻게 될지 확인해보자

 

먼저 변수 암호화 기능(obscured)에 대하여 알아보자

그냥 기존에 쓰던 데이터 타입에 Obscured를 붙여주면 된다. 그러면 알아서 암호화가 된다. 암시적 형 변환도 되기 때문에 불편함 없다.

그러면 코드가 위에처럼 int에서 ObscuredInt로 바뀐다.

그것뿐이다.

얼마나 간편한가!

 

그러면 이제 암호화를 했는데 게임 가디언으로 한번 메모리 변조를 시도해보겠다.

암호화를 하면 해커들이 못 찾을 거라고 하는데 과연...

 

오... 정말로 못 찾는다!

 

하지만 게임 가디언의 암호화된 값 검색을 하면 어떻게 될까?

 

 

검색 결과가 하나 나온다. 특이한 점은 80을 검색했는데 444,492라는 값을 찾아온다.

 

뚫린다... 조금 허무하네...

일단 그냥 검색이 막히기는 하지만 여전히 게임 가디언에 손쉽게 뚫린다.

 

여기서 안티 치트의 말도 한번 들어보자

대략 unknown value 검색에 의하여 암호화가 뚫릴 수 있다고 경고한다. 그렇기 때문에 암호화된 값을 바꿔줘야 한다는 말이다.

암호화 된 값을 바꾸는 기능은 Obscured 객체에 딸려있는 RandomizeCryptoKey 함수를 이용하면 된다.

 

4-1. 안티 치트 obscured 변수 암호화 원리

암호화 값을 바꿔주는 기능을 사용해보기 전에 obscured 변수 암호화에 대한 간단한 원리를 짚고 넘어가 보자

암호화란 평문을 특정 알고리즘에 의하여 암호화된 값으로 바꿔주는 것을 의미한다.

 

실제로 안티 치트에서 실 데이터에 대하여 암호화를 시키면 특정 알고리즘에 의하여 값이 바뀌고 메모리에는 암호화된 값이 저장된다. 그리고 필요할때만 복호화하여 원래 값으로 되돌려서 사용하고 다시 암호화 시켜서 암호화 된 값으로 저장해놓는 것이다.

 

 

444536이라는 암호화 된 값이 100이라는 실제 값을 가지고 있다.

그리고 해당 값을 가지고 있는 변수에는 암호화 된 값을 들고 있다.

 

게임 가디언에서는 아래와 같은 방법으로 암호화 된 값을 찾아낸다고 한다.

게임 가디언 개발자인데 호그와트에서 배운 마법으로 찾는다고 설명한다. 대단하다.

원리는 암호화가 보통 xor 연산으로 이루어지는데 그 방법을 뚫는 방법이 있다고 한다.

구글에 how game guardian detect encrypted value라고 검색하면 내용이 많이 나온다.

 

5. 게임 가디언 VS 안티 치트 변수 암호화 기능 강화 버전

그러면 단순 암호화로는 게임 가디언에게 쉽게 뚫린다는 것을 감안하여 암호화 값을 랜덤으로 바꿔주는 기능을 사용해보도록 한다.

이렇게 되면 1초마다 inGameGold의 암호화 값이 랜덤 하게 값을 가지게 된다.

즉 게임 가디언 입장에서 암호화 키가 되는 값이 확실하지는 않지만 특정 값이라고 가정하여 값을 찾다가 암호화 값이 완전히 바뀌어버리면 데이터를 놓치게 되는 것이다.

 

RandomizeKey를 사용할 때마다 실제로 암호화된 값이 계속해서 바뀐다.

 

그리고 게임 가디언에서 암호화 된 값 검색을 하여도 도중에 찾지 못한다고 나온다.

오... 안티 치트의 승리다.

 

하지만 메모리 주소에 대한 직접적인 변조는 막지 못한다.

아마 더 고도화된 메모리 변조 방지 기법은 직접 메모리 변조하는 것까지 막아야 한다고 생각한다.

 

5-1. 개발 도중 이상한 점(슈뢰딩거의 암호화)

상자 안에 1시간 뒤 50%의 확률로 죽을 수 있는 고양이가 있는데 고양이는 1시간 뒤 살았을까 죽었을까?

갑자기 뭔 개소리냐 싶은데 ㄹㅇ 슈뢰딩거 고양이 뺨치는 상황이 발생했다.

 

5번의 랜덤 암호화 기능을 구현하고 있는데 RandomizeKey 함수를 통하여 암호화 값을 랜덤 값으로 바꾸고 나서 암호화 값이 바뀌었는지 안 바뀌었는지 확인하기 위해 encrypt 값을 받아와서 라벨에 표출해주었다.

 

일단 먼저 GetEncrypted 함수를 통하여 hiddenValue(암호화 값) 값을 가져온다.

그러면 ApplyNewCrpytoKey 함수를 거치는데...

 

ApplyNewCryptoKey 함수의 내용은 위와 같다.

currentCryptoKey와 cryptoKey가 다르면 암호화 값을 cryptoKey로 암호화한 값을 넣어버리는 것이다.

currentCryptoKey는 randomizeKey를 하면 새로운 값으로 바뀌는데 cryptoKey는 바뀔 일이 절대 없다. 다시 말해서 if문은 항상 참이라는 것이다.

아마도 에셋 개발자가 암호화 값 확인을 할 때 헷갈리지 않도록 암호화 값을 받아오면 무조건 원래 암호화 키로 다시 암호화를 해주는 것 같다.

즉 암호화 값을 확인하고 싶어서 확인하는 순간 랜덤 암호키로 바꾼 암호화 값이 랜덤 하지 않은 단 하나의 암호키로 바꾼 암호화 값으로 초기화되는 것이다.

실제로 내가 테스트하면서 GetEncrypted를 계속해서 호출했는데 랜덤 암호화가 제대로 되지 않아서 랜덤 암호화 기능을 사용하였음에도 불구하고 게임 가디언에 뚫렸다.

관측하지 않은 상태에서는 암호화가 제대로 되고 있지만 관측하려는 순간 암호화가 풀려버리는 그런 것이다. 중요하지는 않지만 나중에 테스트한답시고 나처럼 허튼짓 하지 않기를 바란다.

 

6. 게임 가디언 VS 메모리 변조 디텍터

안티 치트에서 제공하는 기능 중에 메모리 변조를 시도를 탐지하는 기능이 있다고 한다.

 

원리는 암호화되지 않은 변수 값을 일부러 노출시키고 유저가 그 값을 바꾸면(해당 값을 바꿔도 실제 값은 바뀌지 않음) 메모리 변조를 시도했다고 판단하는 것이다.

가짜 덫을 만들어 놓는 것이다.

 

게임 오브젝트에 Obscured Cheating Detector를 만들어두고 Detection Event에 함수를 달아놓는다.

게임 매니저에 GotchaBitch 라는 함수를 달아놓았다.

 

이 함수를 발동시키면 텍스트를 GotchBitch!로 바꾸게 된다.

 

한번 이 기능을 넣어보고 게임 가디언으로 메모리 변조를 시도해보겠다.

 

암호화하지 않고 검색을 하면 가짜 값을 찾을 줄 알았는데 못 찾는다.

 

Randomize를 돌리지 않고 Obscured만 사용한 뒤, 암호화 검색을 하면 가짜 값이 나온다. 그래서 가운데 보면 텍스트가 바뀐 것을 알 수 있다. 근데 진짜 값도 탐지가 가능해서 해킹도 되고 해킹 감지도 된다. 좋지 않은 상황이다.

 

암호화된 상태에서 Randomize까지 작동시키면 아무것도 못 찾는다. 차라리 이게 나은 것 같다.

 

7. 결론

 

기본 Int

ObscuredInt

ObscuredInt + RandomizeKey

변조 가능

O

O

X

디텍터 반응

 

O

X

각 상황별로 게임 가디언으로 해킹을 시도했을 때 결과는 위와 같다.

 

 

메모리 변조와 관련된 게시물

게임 가디언 설치, 사용 방법

게임 가디언 사용 방법 - 실제 게임 해킹

유니티 메모리 변조 방지 - 안티 치트

반응형
반응형

유니티에서 메모리 주소에 접근하는 코드를 사용하면 unsafe 관련하여 아래 에러가 발생한다.

Unsafe code may only appear if compiling with /unsafe. Enable "Allow 'unsafe' code" in Player Settings to fix this error.

 

메모리 주소 접근하는 코드를 사용하기 위해서는 unsafe와 fixed 기능을 사용해야 한다.

 

Build Settings > Other Settings > Allow 'unsafe Code'

 

체크를 해준다.

 

그러면 unsafe 함수 사용이 가능하다.

 

언세이프 신택스는 꼭 불안전한건 아니지만 CLR 단에서 에러가 없는지 검증 불가능한 영역이라서 조심히 사용해야하는 부분이라고 나와있다.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/unsafe-code-pointers/index

 

Unsafe code and pointers - C# Programming Guide

Unsafe code and pointers (C# Programming Guide) In this article --> To maintain type safety and security, C# does not support pointer arithmetic, by default. However, by using the unsafe keyword, you can define an unsafe context in which pointers can be us

docs.microsoft.com

 

반응형
반응형

문제

유니티에서 Navmesh 사용하다가 아래와 같은 오류를 만났다.

RuntimeNavMeshBuilder: Source mesh Plane does not allow read access. This will work in playmode in the editor but not in player

UnityEngine.AI.NavMeshSurface:BuildNavMesh()

Plane이라는 mesh에 대한 오류였다.

 

해결

해당 mesh의 상위 모델 파일에서 Read/Write Enabled를 체크하고 Apply를 하면 해결된다.

반응형
반응형

문제

유니티에서 권한 요청을 하고 나서 수락을 하면 화면이 멈춘다.

 

원인

문제가 발생했을 때 떠놓은 로그다.

음성 녹음 권한을 물어본다. -> Activity pause timeout for ActivityRecord

권한을 물어보는 창에서 잠시 기다리면

Timeout while trying to puase the Unity Engine.이 뜬다. 아마 유니티 엔진이 멈춘 것 같다.

아마 권한 요청을 하면서 잠시 유니티를 멈춘 것 같은데 수락을 해도 아무 로그가 나오지 않고 그 상태에서 멈춰버린다.

 

 

해결

안드로이드 권한을 런타임 중에 획득할 수 있도록 하는 에셋을 이용해서 해결

https://assetstore.unity.com/packages/tools/integration/android-runtime-permissions-117803

 

Android Runtime Permissions - Asset Store

Introductory price.. Not! It will always remain Free. Grab it whenever you want! About This plugin helps you query/request runtime permissions synchronously on Android M and later. Features - It is synchronous! Request a permission and process the result i

assetstore.unity.com

 

필요한 것 3가지

1. android manifest 설정

/Plugins/Android/AndroidManifest.xml

파일에 application 태그 안에 <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" /> 를 추가해준다.

위의 설정으로 유니티에서 자체적으로 권한을 요청하지 않도록 설정한다.

 

2. 필요한 권한 코드 확인

아마 AndroidManifest.xml파일에 필요한 권한이 쓰여있을 것이다.

필요한 권한 코드를 확인해서 기록해놓는다.

3. 권한 획득하는 소스코드 작성

나 같은 경우는 게임을 시작할 때 권한을 요청하고 권한 습득하면 화면을 넘어가도록 해놨다.

 

더 자세한 튜토리얼이 궁금하다면 에셋의 깃 설명서를 참고하도록 하자.

https://github.com/yasirkula/UnityAndroidRuntimePermissions

 

yasirkula/UnityAndroidRuntimePermissions

A native Unity plugin to handle runtime permissions on Android M+ - yasirkula/UnityAndroidRuntimePermissions

github.com

 

반응형
반응형

유니티로 ios로 export하고 xcode로 빌드할 때 발생하는 오류를 모아봤다.

오류파튀~

목차

1. bitcode 활성화 오류

You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.

2. 페이스북 sdk 오류

duplicate symbol _OBJC_CLASS_$_FBSDKTypeUtility duplicate symbols for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation)

3. 빌드하고 실행 시 Uncaught exception

 

4. Undefined symbols for architecture x86_64: _sqlite3_closed

 

5. Undefined symbols for architecture x86_64: _deflate

 

 

 

 

 

1. bitcode 활성화 오류

You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.

현재 xcode 빌드 옵션에서 bitcode가 켜져 있는데 특정 sdk에 bitcode 적용이 안되어있어서 그렇다.

나의 경우 GA가 비트 코드가 없는 버전인데 비트코드가 있는 sdk로 교체를 해주던가 빌드 옵션에서 꺼주면 된다.

sdk

위의 sdk에서 bitcode가 있는 버전을 받아서 적용하면 정상적으로 빌드가 된다.

또는

Build Settings > Build Options > Enable Bitcode > No

요렇게 해주면 된다.

일단 빌드가 급하다면 bitcode를 끄도록 하자. 결론만 말하자면 비트코드 꺼도 상관없다.

비트 코드에 대한 설명은 다음 글을 확인하도록 하자.

https://ajh322.tistory.com/203

불러오는 중입니다...

2. 페이스북 sdk 오류

duplicate symbol _OBJC_CLASS_$_FBSDKTypeUtility duplicate symbols for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation)

라이브러리가 겹쳐서 발생한다고 하는데 정확히 무슨 오류인지까지는 안 찾아봤고 해결하려면

Build Phases > Link Binary With Libraries 에서 FBSDKCoreKit.framework를 없애주면 잘 작동한다.

3. 빌드하고 실행 시 Uncaught exception

실행하면 gsCrashReporterUEHandler 에서 오류가 잡히는데 이 오류가 뜨면 빌드까지는 됐는데 앱 실행하고 나서 오류가 발생하는 것이다. 콘솔을 보면 GA 키값을 입력 안 했는데 이 오류가 뜨면 대부분 plist에 써드파티 sdk 키값을 입력하지 않아서 발생한다.

4. Undefined symbols for architecture x86_64: _sqlite3_closed

라이브러리 중에 sqlite와 관련된 라이브러리가 안 들어가 있어서 발생한다고 하는데 아직도 잘 모르겠는데 어느 날부터 이 오류가 안 생기기 시작했다.

Build Phases > Link Binary With Libraries > 추가

Add Other 클릭 > Cmd + Shift + G를 눌러서 경로 입력창 띄움.

/usr/lib 이동

lib 경로에서 libsqlite3.dylib 추가

라이브러리 추가해주고 빌드하면 된다.

5. Undefined symbols for architecture x86_64: _deflate

4번과 비슷한 오류다.

lib 경로 아래에서 libz.dylib를 추가해준다.

반응형
반응형

잘 모르고 있었는데 인터넷에 안나와있어서 모르고 있다가 회사 동료가 알려주었다.

 

크기를 줄이고자 하는 스프라이트 선택

 

Max Size가 기본이 2048로 되어있는데 모든 이미지를 2048로 하면매우 작게 보여줘도 되는 이미지임에도 불구하고 용량이 크게 잡히는 경우가 있다.

 

그렇다고 Max Size를 무조건 낮추면 이미지 해상도가 낮아져서 이미지가 깨져보이는데 경우에 따라 적당한 값을 찾아주도록 하자.

반응형
반응형

유니티 빌드할때 apk 파일 용량 확인하는 방법.

일단 Android apk 빌드를 한다.

 

 콘솔 우클릭 > Open Editor Log

 

로그 파일을 위로 쭉 올리다보면 어떤 파일이 얼마나 용량을 차지하는지 나와있다.

반응형
반응형

애드몹에서 리워드 비디오를 보면 보상을 설정하고 싶은데 나와있는 부분이 하나도 없다.

마치 전세계가 약속을 한 것처럼 아무도 그 부분에 대해서 언급을 안한다. 덕분에 별거아닌데 삽질을 엄청했다.

 

https://developers.google.com/admob/android/rewarded-video?hl=ko

 

보상형 동영상 광고  |  Android  |  Google Developers

보상형 동영상 광고는 동영상 광고를 끝까지 시청한 사용자에게 인앱 보상을 제공하는 전체화면 동영상 광고입니다. 이 가이드에는 AdMob의 보상형 동영상 광고를 Android 앱에 게재하는 방법이 나와 있습니다. 기본 요건 보상형 동영상 광고 초기화 자바 package ... import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.MobileAds; import com.g

developers.google.com

여기 보면

이걸로 광고를 호출하고

 

이걸로 광고 보상을 지급해준다는데

 

저 Reward args는 대체 어떻게 전달해주냐 이거다

 

 

무려 유니티에서 하는 것이 아니라 애드몹에서 RV를 설정하는 부분에서 설정해야한다. 리워드를 클릭한다.

 

여기서 이렇게 설정을 하는 것이었다.

 

리워드를 생성하고나서 발급받은 광고키를 적용한다.

 

나는 위와 같이 설정하였다.

 

로그캣에서 찍히는 값이다.

만약 애드몹에서 기본적으로 제공하는 기본 광고키를 사용하면 amount는 10, Type은 coins가 나올 것이다.

반응형
반응형

오 드뎌 마지막이다 이번엔 별다른 건 아니고 래그돌이 자꾸 고장 나는 경우가 있는데 그 부분에 대해서 간단하게 기재하고 마무리하고자 한다.

 

https://docs.unity3d.com/kr/530/Manual/RagdollStability.html

 

유니티 - 매뉴얼: Joint And Ragdoll Stability

Joint And Ragdoll Stability Tips for improving joint and ragdoll stability. Avoid small joint angles of “Angular Y Limit” and “Angular Z Limit”. Depending on your setup the minimum angles should be around 5 to 15 degrees in order to be stable. Instead of u

docs.unity3d.com

항목

1. Enable prjection

2. 래그돌 재생성

3. 인위적인 멈춤 사용하지 않기

4. 부위 떨림 발생

 

 

 

1. Enable prjection 활성화

 

구글에서 unity ragdoll strech 라고 검색해보면 대부분 관절에 붙어있는 Enable proejction을 켜주라고 말한다.

 

Enable projection을 하면 무슨 원리로 안정적으로 되는 건지 찾아보았으나 정확한 정보는 얻지 못했고 디컴파일러로 열어보니 해당 불린 변수에 대한 주석으로 위와 같이 나와있었다. 아마 정상적이지 못한 래그돌의 흔들림처리를 이전 상태로 다시 되돌려주는 것이 아닐까 추측해본다.

 

 

2. 래그돌 재생성

나의 경우 래그돌이 두 개의 문제가 있었다. 하나는 래그돌의 양팔이 벌려지고나서부터는 접혀지지가 않는 문제였고 다른 문제는 신체의 일부가 가만히 있고 연결부위가 엿처럼 쭈욱 늘어나는 문제였는데 둘다 래그돌 생성 시 올바른 오브젝트를 매칭 시키지 않아서 발생한 문제였다.

유니티 ragdoll 발사하기 - 2.래그돌 만들기 - 1. 모델 rig 휴머노이드 변경해서 본 정보 알아내기 부분을 참고해서 래그돌을 다시 생성해보도록 하자.

 

 

3. 인위적인 멈춤 사용하지 않기

리지드 바디를 껐다가 켜주면 래그돌이 고장날수도 있다고 적어놨는데 해당 부분을 참고하도록 하자. 고장의 원인이 이것일 수도 있다.

유니티 ragdoll 발사하기 - 6. 래그돌 멈추기 - 글의 2. 두 번째 방법(인위적인 멈춤) 참고

 

 

4. 부위 떨림 발생

래그돌의 일부가 투두ㅜㄱㄷ구국두 하면서 계속 떨린다면

Edit -> Project Settings -> Physics -> “Solver Iteration Count”를 높여보도록 하자

유니티 ragdoll 발사하기 - 2.래그돌 만들기 - 글의 3. 충돌 테스트 참고

 

 

 

 

유니티 ragdoll 발사하기 글 모음

1. 목차

2. 래그돌 만들기

3. 래그돌 발사하기

4. 래그돌이 날아갈 때 한쪽 축으로만 이동되게 하기

5. 현재 래그돌이 멈췄는지 안멈췄는지 판단하기

6. 래그돌 멈추기

7. 래그돌 고장 방지

반응형