AES256 암호화, 복호화

유니티 C# 2018. 11. 7. 11:12

암호화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private AES256Encrypt(string _Data)
{
    byte[] plainBytes = System.Text.Encoding.UTF8.GetBytes(_Data);
    System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
    {
    Mode = System.Security.Cryptography.CipherMode.CBC,
    Padding = System.Security.Cryptography.PaddingMode.PKCS7,
    KeySize = 256
    };
 
    MemoryStream memoryStream = new MemoryStream();
    System.Security.Cryptography.ICryptoTransform encryptor = rm.CreateEncryptor(
    System.Text.Encoding.UTF8.GetBytes("01234567890123456789012345678901".Substring(0, 256 / 8)),
    System.Text.Encoding.UTF8.GetBytes("01234567890123456789012345678901".Substring(0, 128 / 8)));
    System.Security.Cryptography.CryptoStream cryptoStream = new System.Security.Cryptography.CryptoStream(memoryStream, encryptor, System.Security.Cryptography.CryptoStreamMode.Write);
    cryptoStream.Write(plainBytes, 0, plainBytes.Length);
    cryptoStream.FlushFinalBlock();
    byte[] encryptBytes = memoryStream.ToArray();
    string encryptString = System.Convert.ToBase64String(encryptBytes);
    cryptoStream.Close();
    memoryStream.Close();
    return encryptString;
}
cs

 

복호화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private string AES256Decrypt()
{
    byte[] encryptBytes = System.Convert.FromBase64String(o);
    System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
    {
        Mode = System.Security.Cryptography.CipherMode.CBC,
        Padding = System.Security.Cryptography.PaddingMode.PKCS7,
        KeySize = 256
    };
 
    MemoryStream memoryStream = new MemoryStream(encryptBytes);
    System.Security.Cryptography.ICryptoTransform decryptor = rm.CreateDecryptor(
    System.Text.Encoding.UTF8.GetBytes("01234567890123456789012345678901".Substring(0, 256 / 8)),
    System.Text.Encoding.UTF8.GetBytes("01234567890123456789012345678901".Substring(0, 128 / 8)));
    System.Security.Cryptography.CryptoStream cryptoStream = new System.Security.Cryptography.CryptoStream(memoryStream, decryptor, System.Security.Cryptography.CryptoStreamMode.Read);
    byte[] plainBytes = new byte[encryptBytes.Length];
    int plainCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);
    string plainString = System.Text.Encoding.UTF8.GetString(plainBytes, 0, plainCount);
    cryptoStream.Close();
    memoryStream.Close();
    return plainString;
}
cs

 

클래스 리스트를 클래스 안에있는 정보로 정렬하는법

유니티 C# 2018. 10. 26. 11:15

List<TestClass> Test = new List<TestClass>();


Test.Sort(delegate(TestClass t1, TestClass t2) { return t1.date.CompareTo(t2.date); });


2D상에서의 각도를 기반으로 회전값 구하기

유니티 C# 2018. 1. 29. 16:40

void Start()


{


// z축 +180은 이미지 방향에 따라 수정하여 적용.


// target1은 자신의 객체가 아닌 비교할 해당 객체.


transform.eulerAngles = new Vector3(0, 0, -getAngle(transform.position.x, transform.position.y, target1.position.x, target1.position.y) + 180.0f);


}




private float getAngle(float x1, float y1, float x2, float y2)


{


        float dx = x2 - x1;


        float dy = y2 - y1;


        


        float rad = Mathf.Atan2(dx, dy);


        float degree = rad * Mathf.Rad2Deg;




        return degree;



출처: http://redccoma.tistory.com/110

유니티에서 비동기적으로 scene을 불러오며 progress를 얻는 방법

유니티 C# 2018. 1. 3. 16:06

using UnityEngine;

using System.Collections;


public delegate void ProgressDelegate(float progress);


public class MyScript {


public void OnStartMyScene() {

StartCoroutine(LoadSceneAsyncByName("MySceneName", OnLoadLevelProgressUpdate));

}

public static IEnumerator LoadSceneAsyncByName(string nextLevel, ProgressDelegate progressDelegate) {

AsyncOperation async = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(nextLevel);

while (!async.isDone) {

progressDelegate (async.progress);

async.allowSceneActivation = async.progress > 0.8;

yield return null;

}

}


private void OnLoadLevelProgressUpdate(float progress) {

Debug.Log ("async.progress: " + progress);

}

}





출처: http://crowjdh.blogspot.kr/2016/07/scene-progress-c.html

Tiled GPU perf. warning: RenderTexture color surface (0x0) was not cleared/discarded, doing <run with profiler for info> 경고

유니티 C# 2017. 12. 24. 12:30

Tiled GPU perf. warning: RenderTexture color surface  (0x0) was not cleared/discarded, doing <run with profiler for info>

경고가 뜰때가 있다.


카메라를 여러대 사용할 때 나온다고 대부분 말을 합니다.


https://forum.unity.com/threads/4-2-any-way-to-turn-off-the-tiled-gpu-perf-warning.191906/


주로 여기서 내용을 다뤘으며


카메라 한대의 Depth를 -1로 바꾸면 가능하면 Clear Flags를 Solid Color로 바꿔서 사용하자.

RectTransform Min Max

유니티 C# 2017. 12. 20. 14:59

Min.x = Left

Min.y = Bottom


Max.x = -Right

Max.y = -Top

코드 실행시간 측정 방법

유니티 C# 2017. 11. 11. 02:55

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

sw.Start();


코드 실행


sw.Stop();

Debug.Log(sw.ElapsedMilliseconds.ToString() + "ms");

유니티 최적화

유니티 C# 2017. 10. 11. 15:48
1. Loop


C# 자료구조에는 여러가지 루프문이 제공된다.
for, foreach, enumerator
어느 루프문을 사용해야 할까?
보통 본인에게 편한 루프문을 택한다.
하지만 성능이 다르다면?


- 테스트과정
각각루프를 도는 스크립트를 만들고, 하나의 스크립트에서 컴포넌트로 통합한다.
모바일로 빌드, 프로파일러를 확인한다.

테스트모바일은 갤럭시 노트3다.


-- 소스코드 --






-- 결과 --



- 정리 

Foreach는 속도도 가장 느리고, GC도 24Byte를 남겼다.

Enumerator는 Foreach보다 빠르게 동작했으며,

For는 Enumerator의 2배나 빠르게 동작한다.


가끔 프로파일러의 변동이 있을 때도 있지만 평균적으론 위 성능을 보인다.



- 추가

Dictionary<int, string>


-- 소스코드 --




--  결과 --



foreach

enumerator



이 부분을 보이는게 더 명확할듯 하다.

foreach문의 경우 그래프가 깨지는 구간이 더 많이 존재 한다. (프레임이 끊길 수 있다)

enumerator는 foreach에 비해 안정적이다.



- 결론

For문으로 루프문을 작성하지 못할 경우, enumerator

For문으로 루프문을 작성할 수 있을 경우, for






2. Parse


C#에서 지원하는 Parse는 여러가지가 존재한다.

그 중에서 가장 많이 사용하는 자료형은 string을 다른자료형으로 변환하거나 그 반대로 다른자료형을 string으로 변환하는 일이 잦다.

이번 테스트는 변환방법에 따른 성능을 테스트해본다.

string은 특수한 자료형이지만

그 외 기본자료형들은 비슷한 속도를 낼 거라고 생각한다.



- 테스트과정

string -> int, int -> string 각각루프를 도는 스크립트를 만들고, 하나의 스크립트에서 컴포넌트로 통합한다.
모바일로 빌드, 프로파일러를 확인한다.

테스트모바일은 갤럭시 노트3다.

(루프 10만번 돌렸다가 폰이 죽었다...)




-- 소스코드 --







-- 결과 --




- 정리

int -> string은 사실 이 결과를 믿을 수 없다.

최대한 평균값을 뽑으려고 노력했으나 그냥 뒤죽박죽이다.

코드로 평균값을 뽑아도 오르락 내리락한다.

그냥 입맛에 따라 쓰면 될 것 같다.


string -> int는 의외의 결과다.

tryParse가 눈에 띄게 느리지 않다.

코드로 평균값을 뽑아보면 1000회당 0.01ms정도 느리다.

안전한 코드를 위해 tryParse를 쓰는게 좋을 듯 하다.



- 결론

int -> string은 작성자의 입맛에 따라, string -> int는 tryParse를 사용한다.







3. callback


c#은 간단한 방법의 callback을 제공한다.

그 중에 System.Action, System.Func<T>를 성능 테스트를 해본다.



- 테스트과정

System.Action을 인자로 받는 함수는 두가지 케이스로 나눈다.

인자가 null이면 실행하지 않는 함수

인자를 빈 delegate로 채우는 함수


System.Func는 그냥 콜하고 처리시간 정도만 알아본다.


모바일로 빌드, 프로파일러를 확인한다.
테스트모바일은 갤럭시 노트3다.


-- 소스코드 --





-- 결과




- 정리

UseDelegateEmpty와 UseFunction은 순서가 자주 뒤바뀐다.

평균적으로 비슷한 속도를 뽑아낸다.

null 체크의 경우 약 3배 빠르다.




- 결론

빈 delegate를 작성하지 말자.

소스코드의 안정성과 속도를 위해 callback을 받는 부분에선 무조건 null체크를 하고, null을 인자로 작성한다.







4. transform caching


우리는 유니티에서 transform에 접근 하는 경우가 잦다.

하지만 transform에 접근하는 게 성능에 부담된다는 사실은 잘 모른다.

그리고, 이 성능의 부담은 caching으로 해결 할 수 있다.



- 테스트 과정

루프를 돌며 this.transform.localPosition을 가져오는 두개의 스크립트 작성

하나의 스크립트는 transform을 재정의한다.


모바일로 빌드, 프로파일러를 확인한다.
테스트모바일은 갤럭시 노트3다.


-- 소스코드 --






-- 결과 --





- 정리

이 전에 정리된 사례들을 보면 어느정도 부담되는 지 감이 온다.

caching된 transform이 non-caching trnasform보다 2배정도 빠르다.




- 결론

transform에 자주 접근하게 되는 객체에선 caching은 선택이 아닌 필수다.





5. string compare


개발하다보면 유니티 뿐만 아니라 많은 어플리케이션에서 string을 비교할 일이 많다.

string을 비교하는 방법은 여러가지가 존재한다.

string 비교 방법이 많은 건 이유가 있으니, 찾아보길 권장한다.

현재 테스트는 길이가 1000~1999까지의 문자열을 비교한다.

테스트 조건을 명확히 알아야한다. 무조건 이게 빠르다. 라고 가정해버리면 안된다.

문자열의 성능은 여러가지 변수에 의해 좌우될 수 있다. 사실 이 이유로 인해 문자열 비교는 포스팅하지 않으려 했다.

모든 문자열이 길이가 4이고 비교했을때 이 방법이 가장 빨랐구나. 정도로 이해하면 된다.

조건에 대해서는 계속 명시한다.



- 테스트 과정

루프를 돌며 문자열을 비교하는 다섯가지의 스크립트 작성

1. string.Compare

2. string.CompareTo

3. Equals

4. Operator

5. Hash Operator


모바일로 빌드, 프로파일러를 확인한다.
테스트모바일은 갤럭시 노트3다.


-- 소스코드 --









-- 결과 -- 





- 정리

위와 같은 조건일 때, 빠른 속도로 나열하자면

Operator, HashOperator, Equals, CompareTo, Compare

순이 된다.




- 결론

여러가지 경험을 비추어 봤을 때 문자열을 연산자 이용해서 비교하는 건 사실 권장하지 않는다.

bool string.Equals(string a, string b) 함수를 사용한다.






6. Debug.Log


개발하면서 많은 Debug.Log, Debug.LogWarning, Debug.LogError로 로그들을 남기면서 개발 했을거라고 예상된다.

프로파일링을 할때마다 Debug.Log가 눈에 거슬렸고, 그에 대한 성능 측정 결과 엄청난 비용을 차지하고 있었다.

그에 따른 이유는 검색으로 많은 이유들을 찾아 볼 수 있다.

내가 진행하던 프로젝트에서 Debug. 으로 검색하니 결과는 약 3천개

빌드전에 모든 로그들을 검색해서 지우기엔 시간이 오래걸릴 수 있다.

개발기간 1년, 2년간 쌓인 로그들 한번에 정리해보자.

그리고, 로그를 정리된 성능과 정리되지 않은 성능을 비교한다.



- 로그정리 구현과정

참조 : https://gist.github.com/kimsama/4123043


위 깃허브에 접속해보면 소스코드가 있다. 해당 소스코드를 수정해서 사용한다.

약 2년 전에 처음으로 깃허브에서 이 소스코드를 찾았다.

그 후, 깃허브에 올라오는 유니티 프로젝트에서 이 코드가 간간히 보이기 시작했다.

아직 로그를 그대로 노출시키는 프로젝트도 많다.


기존 소스코드는 유니티 에디터면 로그를 출력하고, 빌드버전에선 로그를 출력하지 않는다.

하지만 난 문제점 확인과 잘 돌아가는지 확인을 위해 로그를 출력하기 원하면 빌드버전에서도 보고 싶다.

그럼 소스코드를 편하게 사용할 수 있도록 수정해보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#if UNITY_EDITOR
#define ENABLE_LOG
#endif
 
using UnityEngine;
 
/// 
/// It overrides UnityEngine.Debug to mute debug messages completely on a platform-specific basis.
/// 
/// Putting this inside of 'Plugins' foloder is ok.
/// 
/// Important:
///     Other preprocessor directives than 'UNITY_EDITOR' does not correctly work.
/// 
/// Note:
///     [Conditional] attribute indicates to compilers that a method call or attribute should be 
///     ignored unless a specified conditional compilation symbol is defined.
/// 
/// See Also: 
///     http://msdn.microsoft.com/en-us/library/system.diagnostics.conditionalattribute.aspx
/// 
/// 2012.11. @kimsama
/// 
public static class Debug
{
    public static bool isDebugBuild
    {
        get { return UnityEngine.Debug.isDebugBuild; }
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void Log(object message)
    {
        UnityEngine.Debug.Log(message);
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void Log(object message, UnityEngine.Object context)
    {
        UnityEngine.Debug.Log(message, context);
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void LogError(object message)
    {
        UnityEngine.Debug.LogError(message);
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void LogError(object message, UnityEngine.Object context)
    {
        UnityEngine.Debug.LogError(message, context);
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void LogWarning(object message)
    {
        UnityEngine.Debug.LogWarning(message.ToString());
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void LogWarning(object message, UnityEngine.Object context)
    {
        UnityEngine.Debug.LogWarning(message.ToString(), context);
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void DrawLine(Vector3 start, Vector3 end, Color color = default(Color), float duration = 0.0f, bool depthTest = true)
    {
        UnityEngine.Debug.DrawLine(start, end, color, duration, depthTest);
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void DrawRay(Vector3 start, Vector3 dir, Color color = default(Color), float duration = 0.0f, bool depthTest = true)
    {
        UnityEngine.Debug.DrawRay(start, dir, color, duration, depthTest);
    }
 
    [System.Diagnostics.Conditional("ENABLE_LOG")]
    public static void Assert(bool condition)
    {
        if (!condition) throw new System.Exception();
    }
}
cs


이렇게.


유니티에디터에선 무조건 로그를 출력한다.

빌드시에는 ENABLE_LOG를 정의했을 경우에 출력한다.


빌드세팅에서 Player Settings -> Other Settings -> Scripting Define Symbols 에 정의하면 된다.






- 테스트 과정

루프를 돌며 100번의 로그를 찍는 스크립트 작성

1. 로그를 출력하지 않는 빌드 프로그램으로 프로파일링 한다.

2. 로그를 출력하는 빌드 프로그램으로 프로파일링 한다.


테스트모바일은 갤럭시 노트3다.



-- 소스코드 --






-- 결과 --


(로그 출력O)



(로그 출력X)






- 정리

로그는 여러면에서 엄청난 비용을 차지한다.

GC, time ms...



- 결론

왠만한 소스코드들은 따라가지 못할 성능을 잡아먹는다.

아무리 소스코드를 최적화 신경써서 작성했다고 하더라도 로그를 많이 찍을 경우 다 무용지물일 것 이다.


그리고 다른 얘기를 해볼까 한다.

현재 마켓에서 다운받을 수 있는 프로젝트들도 몇몇개도 로그를 노출시키고 있다.

중요해 보이는 로그도 찍히는 경우가 있다.


보안상  노출시키지 않아야 하고,

프로그램 성능상 출력하지 말아야 한다.


배포되는 빌드에선 필수로 막아야한다. 


로그를 삭제 시키는 일은 선택이 아닌 필수다.


출처표기 : http://geekcoders.tistory.com/56

유니티 최적화 팁

유니티 C# 2017. 9. 20. 15:17

참고한곳 https://www.slideshare.net/agebreak/141206-42456391


코드 최적화

1. 유니티 객체들을 변수에 저장해서, 캐싱해서 사용하는것이 좋다.


2. FindObject 계열 함수들은 매우 느리다. (미리 찾아서 캐싱)


3. Instanitate 와 Destroy 함수를 이용한 프리팹의 생성/해제는 비용이 크다

- 활성화/비활성화를 활용 -> 오브젝트 풀링


4. Update 함수보다는 CoRoutine을 활용한다.


5. 나눗셈 보다는 곱셈이 몇 십 배 빠르다.


6. 박싱과 언박싱은 부하가 큰 작업이다.


7. magnitude 보다는 sqrMagnitude를 사용해서 비교한다. (제곱근 계산 x)


8. 삼각함수의 값은 상수로 저장하고, 사용하는 것이 좋다.


9. 문자열은 readonly 혹은 const 키워드를 사용하여, 가비지 컬렉션으로부터 벗어나도록 한다.


10. 가비지 컬렉터

- Mono의 동적 메모리 관리 때문에, 메모리 해제를 위해 GC가 자동 호출 된다.

- GC는 언제 일어날지 모른다.

- GC가 일어나면, 게임이 멈추는 현상(랙)이 발생하게 된다.

- 동적 메모리 해제가 가능한 일어나지 않도록 하는것이 GC 관리의 핵심

10.1 오브젝트 풀링

- 오브젝트(or 프리팹)의 동적 생성과 해제는 부하가 크다.

- 오브젝트가 해제되면, 언젠가는 GC가 동작하여 정리 한다 = 랙이 발생

- 오브젝트를 풀을 만들어 미리 많이 만들어 두고, 활성화/비활성화로 사용한다.

- 풀에서 가져와서 사용하고, 사용이 끝나면 비활성화 상태로 풀에 반환

- 오브젝트 풀링 사용은 선택이 아닌 필수!!


11. GC에게 먹이 주지 않기

11.1 문자열 병합은 StringBuilder

- 일반 String + String을 쓰면 임시 문자열이 생성됨

- StringBuilder.Append() 함수를 사용하여 병합

11.2 foreach 대신에 for문 사용

- 일반 array에 한해서...

- Foreach는 한번 돌때마다 24byte의 쓰레기 메모리를 생성

- 10번만 돌아도 240byte의 GC 수거 메모리를 남김

11.3 태그 비교에는 compareTag()를 사용

- if(go.tag == "enemy") 대신에 go.compareTag("enemy")를 사용

- 객체의 tag 프로퍼티를 호출하는것은 추가 메모리를 항당하고, 복사

11.4 데이터 타입에는 Class 대신 구조체 사용

- 구조체는 GC에 들어가지 않는다. Stack에 할당

11.5 즉시 해제할 때는 Dispose 수동 호출

- 오브젝트의 dispose를 수동으로 호출하여, 즉시 cleanup

11.6 임시 객체들을 만들어내는 API들을 조심

- Ex) GetComponents<T>, Mesh.Vertices, Camera.allCameras,  etc...


12. C++ <-> C# 오버 헤드

12.1 객체의 변경 사항을 캐싱

- 객체의 이동과 변형에 대한 처리를 캐싱하고, 매프레임에서 딱 한번만 처리한다.

- Ex) Move()

12.2 컴포넌트 참조를 캐싱

- GetComponent()는 한번만 호출하여, 객체를 캐싱해두고 사용한다.

12.3 빈 콜백 함수는 제거

-Start()나 Update()같은 콜백함수는 비어있어도 성능에 영향을 끼친다.



리소스 최적화

1. 권장 압축 텍스쳐 사용하기

- 아이폰(PowerVR) : PVRCT

- 안드로이드(Teger) : DXT

- 안드로이드(Adreno) : ATC

- 안드로이드 (공통) : ETC1


2. 텍스쳐

2.1 텍스쳐 사이즈는 무조건 2의 제곱이어야 한다.

- POT(Power of Tow)

- POT가 아닌경우 POT텍스쳐로 변환되어 로딩 된다.

- 900 x 900 -> 실제로는 1024 x 1024로 변환


2.2 텍스쳐 아틀라스를 활용 하라.

- 텍스쳐 아틀라스로 최대한 묶음

- UI 만이 아니라 같은 재질의 오브젝트들을 묶음


2.3 압축된 텍스쳐와 밉맵을 사용하자. (대역폭 최적화)


2.4 32bit가 아닌 16bit 텍스쳐 사용도 상황에 맞게 고려




오디오 최적화

1. 모바일에서 스테레오는 의미 없다.

- 모두 92kb, 모노로 인코딩


2. 사운드 파일을 임포트하면 디폴트로 3D 사운드로 설정

- 2D 사운드로 변경


3. 압축 사운드(mp3, ogg), 비압축 사운드(wav) 구별

- 비압축 사운드 : 순간적인 효과음, 이펙트 등

- 압축 사운드 : 배경음악

Dictionaty<> for문 돌리기

유니티 C# 2017. 9. 16. 05:50

참조한 곳

http://snowting-mj.tistory.com/28





for(int i = 0; i < Dic.Count; i++)

{

Dic.Keys.ToList()[i];


또는


Dic.Values.ToList()[i];

}