Total: Today: Yesterday:
개발/Unity | 2021. 7. 22. 11:33 | Posted by 자수씨

유니티에서 쓰는 Dictionary는 직렬화가 되지 않기 때문에 Inspector에서 제어가 되지 않는다. key-value 쌍으로 관리해야 하는 데이터가 있는 경우 불편함이 있는데, 이전에 검색을 통해 적용했던 Dictionary 보다 사용성이 좋아서 테스트 해 보았다. (2021년 3월에 업데이트 된 것으로 보인다.)

 

관련 사이트: https://wiki.unity3d.com/index.php/SerializableDictionary

 

SerializableDictionary - Unify Community Wiki

Author: Fredrik Ludvigsen (Steinbitglis) Notice 1 This collection has been updated (as of Mar. 2021). Check the document history for the old version. Notice 2 A much more advanced version is now available at Rain Games office server. This can be added as a

wiki.unity3d.com

 

설치

Project Settings > Package Manager에 새로운 Registry를 추가한다. (2020 이상 버전부터 사용 가능)

 

Package Manager에서 SerializableDictionary 패키지를 설치한다.

 

사용 예

public class 클래스이름 : MonoBehaviour
{

    [SerializeField] private SerializableDictionary<int, GameObject> m_MonsterRepository;

    ...
}

위와 같이 public이나 SerializeField로 선언되면 Inspector에 아래와 같이 표시가 된다.

key가 enum으로도 지원이 되는지는 별도로 테스트 해 볼 예정이다.

개발/Unity | 2021. 7. 21. 22:19 | Posted by 자수씨

unity Cannot perform upm operation: EBUSY: resource busy or locked, open

 

Project Manager를 통해 새로운 package를 설치하다보면 위와 같은 오류가 발생할 수 있다. 여러가지 원인이 있겠지만 검색한 유니티 포럼에 의하면 스크립트 편집을 위한 VS Code를 열어두어서 발생할 수 있다고 한다.

 

VS Code 종료 후 설치하니 오류 없이 진행된다.

개발/Unity | 2021. 7. 21. 12:05 | Posted by 자수씨

테스트를 위해 새로운 프로젝트를 생성하여 Play를 하게 되면 Hierarchy의 Scene 트리가 접히는 문제가 있었다. 처음에는 대수롭지 않게 생각했는데, 게임오브젝트를 선택하려면 씬 트리를 열어야 하는 불편함이 생겼다.

유니티 포럼에 비슷한 문제를 겪는 사람들이 있었다.

#if UNITY_EDITOR
         UnityEditor.EditorGUIUtility.PingObject (gameObject);
#endif

처음 시도했던 방법은 씬에 포함되어 있는 GameObject의 스크립트에 위와 같은 코드를 삽입하는 것이다. 매번 코드에 삽인하는 것은 해결책이 되지 않을 것 같아 포럼 댓글들을 더 찾아보았다.

 

댓글에 있는 링크를 따라가다보니 Addressable 관련 버그라고 하며 Simulate Groups (advanced)로 설정되어 있는 경우 발생하는 문제로 보여진다. Use Asset Database (fastest)로 설정하면 해당문제가 발생하지 않는다.

개발/Unity | 2021. 7. 20. 23:52 | Posted by 자수씨

기존에 진행하던 프로젝트에 Unity를 최신버전으로 적용한 이후 Unity Editor를 실행할 때 마다 아래와 같은 오류가 발생하였다. (2020.1.16ff >> 2020.3.11f1)

 

여러 사이트를 조회해본 결과 Spine 초기화 시에 발생하는 문제로 추측되었다. 기존에는 3.8 버전을 사용했는데 아래의 문제로는 해결이 되지 않았다.

--- a/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs
+++ b/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs
@@ -97,7 +97,7 @@ namespace Spine.Unity.Editor {
 
 #region Initialization
                static SpineEditorUtilities () {
-                       Initialize();
+                       EditorApplication.delayCall += () => Initialize();
                }
 
                static void Initialize () {

Spine 라이브러리를 제거한 후 Unity Editor를 재시작하였더니 해당 오류가 발생하지 않는 것을 봐서는 문제의 원인이 맞는 것 같다.

 

Spine-Unity 다운로드 페이지에서 최신버전(4.0)을 설치한 이후에도 오류가 발생하지 않았다.

아직까지 다른 문제가 발생하지 않으므로 본 포스트는 마무리한다.

개발/Unity | 2020. 8. 11. 12:14 | Posted by 자수씨

PlayServicesResolver 를 프로젝트에 추가한 이후로 빌드 시 마다 아래와 같은 에러가 발생한다.

 

Assembly 'Assets/PlayServicesResolver/Editor/Google.IOSResolver_v1.2.135.0.dll' will not be loaded due to errors:
Unable to resolve reference 'UnityEditor.iOS.Extensions.Xcode'. Is the assembly missing or incompatible with the current platform?
Reference validation can be disabled in the Plugin Inspector.

 

실행에는 문제가 없으나 항상 뜨는 오류라서 신경이 쓰여서 구글링을 하였으나 만족할만한 결과는 찾지 못하였다.

 

 

혹시나 하는 생각에 iOS 모듈을 추가로 설치했더니 오류가 사라졌다. 윈도우라서 iOS 빌드가 안될 것 같아 설치를 안했는데 PlayServicesResolver 를 추가한 경우에는 iOS 모듈도 설치가 필요한 것으로 보인다.

 

개발/Unity | 2020. 8. 10. 16:36 | Posted by 자수씨

안드로이드 빌드 시 keystore 를 설정한 후 빌드를 하게 되면 Project Settings 에서 keystore 에 대한 패스워드를 지정해야 한다.

 

Unity 의 보안 정책인지 모르겠지만 Unity Editor 를 재시작하게 되면 패스워드가 초기화 된다.

 

BuildPipeline.BuildPlayer() 로 빌드할 경우 항상 패스워드를 설정해주어야 하는 불편함이 발생한다.

 

구글링을 통해 확인된 해결 방법은 keystore 패스워드를 스크립트에서 설정하는 것인데, BuildPlayer 바로 위에 설정할 경우 동일한 에러가 발생한다.

PlayerSettings.Android.keystorePass = "$$password$$";
PlayerSettings.Android.keyaliasPass = "$$password$$";

BuildPipeline.BuildPlayer(...);

 

 

[InitializeOnLoad]  Attribute 와 static 생성자(?) 를 이용하여 설정하게되면 스크립트 내에서 패스워드 설정이 가능한 것을 확인하였다.

[InitializeOnLoad]
public class LocalBuild : MonoBehaviour
{
    static LocalBuild()
    {
        PlayerSettings.Android.keystorePass = "$$password$$";
        PlayerSettings.Android.keyaliasPass = "$$password$$";
    }
    ...
    
}

 

ㅁ 참고자료

https://answers.unity.com/questions/757834/publishing-settings-keystore-password-not-saving.html

개발/Unity | 2020. 8. 7. 18:48 | Posted by 자수씨

Facebook 로그인 테스트를 위해 사이트(https://developers.facebook.com/docs/unity/) 에서 SDK 를 내려받고 매뉴얼(https://developers.facebook.com/docs/unity/gettingstarted)을 보고 초기화 설정까지 완료했는데, 앱을 빌드하고 로그인 로직이 처리되는 순간 crash 가 발생한다.

FB.LogInWithPublishPermissions() 메소드를 호출하는 순간 발생하는 것 같은데...

구글링을 하다보니 LogInWithReadPermissions, LogInWithPublishPermissions 메소드의 차이로 인해 발생하는 것으로 보인다.

var perms = new List<string>(){"public_profile", "email"};
FB.LogInWithReadPermissions(perms, AuthCallback);

public_profileemail 조회 시에는 LogInWithReadPermissions 를 사용한다.

참고자료

개발/Unity | 2020. 8. 7. 14:29 | Posted by 자수씨

Unity 빌드를 Jenkins 로 이용하고 있는데, Editor 를 최신버전으로 업데이트 한 이후부터 아래와 같은 오류가 발생한다.

 

Could not open file /Users/*****/Documents/unity/2020.1.1f1/PlaybackEngines/AndroidPlayer/modules.asset for read 
(Filename: ./Runtime/File/OpenFileCache.cpp Line: 61)
 
Assertion failed on expression: 'res' 
(Filename: ./Runtime/Serialize/SerializationCaching/FileCacherRead.cpp Line: 133)
 
Unknown error occurred while loading '/Users/*****/Documents/unity/2020.1.1f1/PlaybackEngines/AndroidPlayer/modules.asset'. 
(Filename:  Line: 0)
 
[Unity Package Manager (Upm)]
Parent process [30691] was terminated

 

Jenkins 는 추후 iOS 빌드를 위해 MacOS 환경에 구축되었는데, MacOS 에서 Unity Editor 로 빌드를 하면 오류가 발생하지 않는다.

 

한가지 특이한 사항은 이전 버전이 2019.3.0f6 인데 경로가 Documents 가 아닌 Developments 라고 별도의 경로에 있었다. 기억을 더듬어 보니 기존에도 이러한 이슈가 발생한 것 같은데 정리를 안해 놓은 듯...

 

기존 버전과 같이 Unity Editor 를 /Users/[사용자]/Documents 가 아닌 다른 경로(/Users/[사용자]/Developments) 로 이동시키고 빌드를 했더니 오류가 발생하지 않았다.

 

Jenkins 프로세스가 MacOS 의 권한으로 인해 Documents 에 접근이 안되는 것으로 마무리 짓는다.

(이전에는 관련된 정보를 찾았던 것 같은데 기억이 나지 않는다...)

개발/Unity | 2020. 6. 10. 12:11 | Posted by 자수씨

어드레서블에 대한 이해를 하고자 해보았으나 실제 사용하는 방법은 약간 차이가 있다.

일단 하던 번역은 마무리하고 실제 사용 전략에 대해 정리할 예정이다.

2020/06/09 - [개발/Unity] - Addressable Assets development cycle (1)
2020/06/10 - [개발/Unity] - Addressable Assets development cycle (2)

컨텐츠 업데이트 빌드 (Building for content updates)

컨텐츠 업데이트를 빌드하려면 다음을 수행한다.

  1. 유니티 에디터에서 Addressable Groups window 를 연다 (Window > Asset Management > Addressables > Gruops)
  2. Addressable Groups window 에서 탑 메뉴의 Build > Update a Previous Build 를 선택한다.
  3. 빌드 데이터 파일 (Build Data File) 다이얼로그 팝업이 열리면 addressable_content_state.bin 파일을 선택한다.

빌드를 통해 컨텐츠 카탈로그, 해시 파일 및 에셋번들이 생성된다.

생성된 컨텐츠 카탈로그는 선택된 애플리케이션 빌드의 카탈로그와 동일한 이름을 가지며 이전 카탈로그 및 해시 파일을 겹쳐 쓴다. 애플리케이션은 새 카탈로그가 사용가능한지 판별하기 위해 해시 파일을 로드한다. 시스템은 애플리케이션과 함께 제공되거나 이미 다운로드 된 기존 번들에서 수정되지 않은 에셋을 로드한다.

시스템은 addressables_content_state.bin 에서 컨텐츠 버전 문자열과 위치 정보를 사용하여 에셋 번들을 생성한다. 업데이트 된 컨텐츠를 포함하지 않는 에셋 번들은 업데이트를 위해 선택된 빌드의 파일 이름과 동일한 이름을 사용하여 작성된다. 에셋 번들에 업데이트 된 컨텐츠가 포함된 경우 원래 파일과 공존할 수 있도록 업데이트가 된 컨텐츠를 포함하는 새 에셋 번들이 새로운 파일 이름으로 작성된다. 새 파일 이름을 가진 에셋 번들만 컨텐츠를 호스팅 하는 위치로 복사되어야 한다.

또한 시스템은 변경할 수 없는 컨텐츠에 대한 에셋 번들을 빌드하지만 어드레서블 에셋 항목이 참조하지 않으므로 컨텐츠 호스팅 위치에 업로드할 필요는 없다.

새 플레이어를 빌드하고 컨텐츠를 업데이트 하는 (예: 플레이어 코드, 어드레서블) 빌드 스크립트를 변경해서는 안된다. 애플리케이션에서 예기치 않은 동작이 발생될 수 있다.

 

 

런타임 시 컨텐츠 업데이트 확인 (Checking for content updates at runtime)

새로운 어드레서블 컨텐츠 업데이트가 있는지 정기적으로 확인하기 위해 사용자 정의 스크립트를 추가할 수 있다. 다음 함수 호출을 사용하여 업데이트를 시작한다.

public static AsyncOperationHandle<List<string>> CheckForCatalogUpdates(bool autoReleaseHandle = true)

리턴 값의 List<string> 은 수정된 위치 ID 목록이 포함된다. 이 ID를 필터링하여 특정 ID 만 업데이트하거나 완전히 UpdateCatalogs API 로 전달할 수 있다.

새로운 컨텐츠가 있는 경우 업데이트를 수행할 수 있는 버튼을 사용자에게 제공하거나 자동으로 수행할 수 있다. 오래된 에셋이 릴리즈되었는지 확인하는 것은 개발자의 책임이다.

카탈로그 목록은 null이 될 수 있으며, 필요한 경우 다음 스크립트는 업데이트가 필요한 모든 카탈로그를 업데이트한다.

public static AsyncOperationHandle<List<IResourceLocator>> UpdateCatalogs(IEnumerable<string> catalogs = null, bool autoReleaseHandle = true)

리턴 값은 업데이트 된 위치 목록이다.

 

 

컨텐츠 업데이트 예 (Content update examples)

이 예제에서 제공된 애플리케이션은 다음 그룹을 인식한다.

Local_Static Remote_Static Remote_NonStatic
AssetA AssetL AssetX
AssetB AssetM AssetY
AssetC AssetN AssetZ

참고: Local_StaticRemote_StaticCannot Change Post Release 그룹의 일부이다.

이 버전은 라이브 버전이므로 디바이스에 Local_Static 를 가지고 있는 플레이어가 있고 원격 번들 중 하나 또는 둘 모두가 로컬로 캐시되어 있을 수 있다.

각 그룹에서 하나의 에셋 (AssetA, AssetL, AssetX) 을 수정한 다음 Check for Content Update Restrictions 를 실행하면 로컬 어드레서블 설정의 결과는 아래와 같다.

Local_Static Remote_Static Remote_NonStatic content_update_group (non-static)
    AssetX AssetA
AssetB AssetM AssetY AssetL
AssetC AssetN AssetZ  

참고: 준비 작업은 실제로 Cannot Change Post Release 그룹을 편집하므로 직관적이지 않을 수 있다.그러나 핵심은 시스템이 위의 레이아웃을 빌드하지만 이러한 그룹에 대한 빌드 결과를 버리는 것이다. 따라서 플레이어의 관점에서 다음과 같이 정리된다.

 

Local_Static
AssetA
AssetB
AssetC

Local_Static 번들은 변경할 수 없는 플레이어 장치에 이미 있다. 이 이전 버전 AssetA 는 더 이상 참조되지 않는다. 대신 플레이어 장치에 죽은 데이터로 남아있게 된다.

 

Remote_Static
AssetL
AssetM
AssetN

Remote_Static 번들은 변경되지 않는다. AssetM 이나 AssetN 이 플레이어 장치에 아직 캐시되지 않은 경우 요청 시 다운로드 된다. AssetA 와 같이 이전 버전 AssetN 은 더 이상 참조되지 않는다.

 

Remote_NonStatic (old)
AssetX
AssetY
AssetZ

Remote_NonStatic 번들은 이제 오래되었다. 서버에서 삭제할 수 있으며 이 시점부터는 다운로드 되지 않는다. 캐시가 되더라도 결국 캐시에서 삭제된다. AssetAAssetL 처럼 이전 버전 AssetX 는 더 이상 참조되지 않는다.

 

Remote_NonStatic (new)
AssetX
AssetY
AssetZ

이전 Remote_NonStatic 번들은 해시 파일로 구별되는 새 버전으로 대체된다. 수정된 버전은 AssetX 가 새 번들로 업데이트 된다.

 

content_update_group
AssetA
AssetL

 

이전 content_update_group 번들은 전진 참조(referenced moving forward)될 수정된 에셋으로 구성되어 있다.

위의 예는 다음과 같은 의미를 갖는다.

  1. 변경된 로컬 에셋은 사용자 장치에서 영원히 사용되지 않은 상태로 유지된다.
  2. 사용자가 비정적(non-static) 번들을 이미 캐시한 경우 변경되지 않은 에셋 (예: AssetY, AssetZ) 을 포함하여 번들을 다시 다운로드해야 한다. 이상적으로 사용자는 번들을 캐시하지 않았으므로 새로운 Remote_NonStatic 번들을 다운로드하면 된다.
  3. 사용자가 이미 Static_Remote 번들을 캐시한 경우 업데이트 된 에셋만 다운로드하면 된다. ( 이 경우 AssetLcontent_update_group 을 통해). 이 경우에는 이상적이다. 사용자가 번들을 캐시하지 않은 경우 수정되지 않은 번들을 통해 content_update_group 을 통해 새로운 AssetL 과 수정되지 않은 Remote_Static 번들을 통해 현재 없어진 AssetL 을 모두 다운로드 해야 한다. 초기 캐시 상태와 상관없이, 어느 시점에 사용자는 장치에 기능이 없는 AssetL 을 갖게 되며, 액세스하지 않아도 무기한으로 캐시된다.

개발/Unity | 2020. 6. 10. 12:10 | Posted by 자수씨

컨텐츠 업데이트 워크플로우 (Content update workflow)

유니티는 게임 컨텐츠를 두 가지 범주로 구성하는 것을 권장한다.

  • Cannot Change Post Release: 업데이트 하지 않을 것으로 예상되는 정적 컨텐츠
  • Can Change Post Release: 업데이트 될 수 있는 동적 컨텐츠

이 구조에서 Cannot Change Post Release 로 지정된 컨텐츠는 애플리케이션과 함께 제공(설치 즉시 다운로드되어 로드되거나) 되고 매우 작은 번들에 상주한다. Can Change Post Release 로 지정된 컨텐츠는 각 업데이트에 필요한 데이터 양을 최소화하기 위해 작은 번들에 온라인으로 상주한다. 어드레서블 에셋 시스템의 목표 중 하나는 스크립트를 변경하지 않고도 이 구조를 쉽게 작업하고 변경할 수 있도록 하는 것이다.

 

작동 원리 (How it works)

어드레서블은 컨텐츠 카탈로그를 사용하여 로드하는 위치와 방법을 지정하여 각 에셋의 주소를 매핑한다. 앱에 매핑이 변경되는 기능을 제공하려면 원본 앱이 카탈로그의 온라인 사본을 알고 있어야 한다. 이러한 설정을 하기 위해서는 AddressableAssetSettings 인스펙터에서 Build Remote Catalog 설정을 활성화해야 한다. 이를 통해 카탈로그 사본이 지정된 경로에 빌드되어 로드되는 것을 보장한다. 앱이 제공된 이후에는 이 로드 경로를 변경할 수 없다. 컨텐츠 업데이트 프로세스는 파일 이름이 동일한 카탈로그의 새 버전을 작성하여 이전에 지정된 로드 경로에서 파일을 겹쳐 쓴다.

애플리케이션을 빌드하면 고유한 앱 컨텐츠 버전 문자열이 생성되어 각 앱이 로드해야 하는 컨텐츠 카탈로그를 식별한다. 서버는 충돌없이 여러 버전의 앱 카탈로그가 포함될 수 있다. 필요한 데이터는 addressables_content_state.bin 파일에 저장된다. 여기에는 Cannot Change Post Release 로 지정된 그룹에 포함된 모든 에셋에 대한 새시 정보와 함께 버전 문자열이 저장된다. 기본적으로 프로젝트 디렉토리의 Assets/AddressableAssetsData/\<platform\> 에 위치한다.

addressables_content_state.bin 파일에는 어드레서블 시스템의 모든 Cannot Change Post Release 에셋 그룹에 대한 해시 및 종속성 정보가 포함되어 있다. StreamingAssets 폴더에 빌드된 모든 그룹은 Cannot Change Post Release 로 지정되어야 하지만 대규모 원격 그룹도 이러한 지정에 이점을 가질 수 있다. 다음 단계 (아래에 설명된 컨텐츠 업데이트 준비)에서 이 해시 정보는 Cannot Change Post Release 그룹에 변경된 자산이 포함되어 있는지 여부를 결정하므로 해당 에셋을 다른 곳으로 이동해야 한다.

 

고유 번들 ID (Unique Bundle IDs)

에셋 번들을 메모리에 로드할 때 유니티는 동일한 내부 이름으로 두 개의 번들을 로드할 수 없도록 강제한다. 이로 인해 런타임 시 번들 업데이트에 제한이 있을 수 있다. 현재 어드레서블은 초기화 외부에서 카탈로그 업데이트를 지원하므로 이미 로드된 컨텐츠를 업데이트 할 수 있다.

이 작업을 수행하려면 두 가지 중 하나가 발생해야 한다. 한 가지 옵션은 카탈로그를 업데이트하기 전에 모든 어드레서블 컨텐츠를 언로드하는 것이다. 두 번째 옵션은 업데이트 된 에셋번들에 고유한 내부 식별자가 있는지 확인하는 것이다. 이를 통해 새 번들을 로드할 수 있으며 이전 번들은 여전히 메모리에 있게 된다. 두 번째 옵션을 활성화하는 옵션은 AddressableAssetSettings 인스펙터에서 "Unique Bundle IDs" 를 켜는 것이다. 이 옵션의 단점은 번들을 종속성 체인으로 재구성해야 한다는 것이다. 한 그룹에서 매터리얼을 변경한 경우 기본적으로 매터리얼 번들만 다시 작성하면 되지만 "Unique Bundle IDs" 옵션이 활성화되면 해당 매터리얼을 참조하는 모든 에셋을 리빌딩해야 한다.

 

컨텐츠 업데이트 준비 (Preparing for content updates)

Cannot Change Post Release 그룹에서 에셋을 수정한 경우 Check for Content Update Restrictions 명령을 실행해야 한다. 이 명령을 통해 수정된 에셋이 Cannot Change Post Release 그룹에서 제거되어 새 그룹으로 이동한다. 새 에셋 그룹을 생성하려면 아래와 같다.

  1. 유니티 에디터에서 Addressable Groups window 를 연다. (Window > Asset Management > Addressables > Groups)
  2. Addressable Groups window 에서 메뉴바의 Tools > Check for Content Update Restrictions 를 선택한다.
  3. 빌드 데이터 파일 (Build Data File) 다이얼로그 팝업이 열리면 addressable_content_state.bin 파일을 선택한다.

이 데이터는 애플리케이션이 마지막으로 빌드 된 이후 수정된 에셋 또는 종속성을 결정하는데 사용된다. 시스템은 컨텐츠 업데이트 빌드를 준비하기 위해 이러한 에셋을 새 그룹으로 옮긴다.

참고: 이 명령은 모든 변경 사항이 Can Change Post Release 그룹으로 제한된 경우 아무 작업도 수행하지 않는다.

중요: 준비 작업을 실행하기 전에 버전 관리 시스템을 분기하는 것이 좋다. 준비 작업은 컨텐츠 업데이트에 적합한 방식으로 에셋 그룹을 재정렬한다. 분기는 다음에 새 플레이어의 제공 시점에 원하는 컨텐츠 배열로 돌아갈 수 있도록 한다.