State Machine 기반의 로직을 작성할 때

정답이라고 할 수는 없지만 개인적인 생각에는

class StateMachine {
  std::list<StatePtr> stateStack;
public:
  StateMachine(State* baseState) {
    stateStack.push_back(baseState);
  }

  void Push(StatePtr newState) {
    stateStack.front()->Pause();
    stateStack.push_front(newState);
    stateStack.front()->Start();
  }

  void Change(StatePtr newState) {
    if (stateStack.size() <= 1)
      return Push(newState);
    stateStack.front()->Stop();
    stateStack.pop_front();
    stateStack.push_front(newState);
    stateStack.front()->Start();
  }

  void Pop() {
    if (stateStack.size() <= 1)
      return;
    stateStack.front()->Stop();
    stateStack.pop_front();
    stateStack.front()->Resume();
  }

  void Reset() {
    while (stateStack.size() > 1) {
      stateStack.front()->Stop();
      stateStack.pop_front();
    }
  }

  void SendMessage(Message& msg) {
    for (auto& state : stateStack) {
      if (state->OnMessage(msg))
        return;
    }
  }
};

위와 같이 스택 구조로 만들면… 이전 상태가 기록되어 좋다고 생각합니다. 뭐 이런 느낌???

// 선공, 비선공으로 NPC AI 를 시작
aiStateMachine.Push(offensive ? new OffensiveState(this) : new PeacefulState(this));
// 어떤 조건으로 인해 전투 상태로 변경
aiStateMachine.Push(new CombatState(this));
// 다른 조건으로 NPC가 스킬을 시전
aiStateMachine.Push(new UseSkillState(this));

// 스킬 사용 상태
class UseSkillState : public State {
public:
  virtual bool OnMessage(Message& msg) override {
    switch (msg.GetType()) {
    case MessageType::GET_TARGET:
      // 이전 상태에서 구한다
      return false;
    // ...
    }
  }

  virtual void Start() override {
    // 대상을 구한다
    GetTargetMessage msg;
    owner->GetStateMachine().SendMessage(msg);
    if (!msg.HasTarget()) return owner->GetStateMachine().Pop(); // 대상을 못 구했으므로 종료
    // 대상에게 스킬 시전
    // ...
  }
}

Unity Android에서 self signed SSL 인증서 사용하기

Unity로 WWW 클래스를 이용해 통신 중인데 Editor에서는 문제없이 통신이 되다가 Android 폰으로 옮겼더니 통신이 안되는군요.
역시 SSL 인증서를 인식하지 못하는 문제가 발생했습니다.
self signed SSL 인증서는 기본 인증서 서비스가 알아볼 일이 없겠죠.
해결하는 방법으로는 크게 3가지 정도 생각해 볼수 있습니다.



  1. self signed SSL 인증서를 핸드폰에 설치하도록 한다.

  2. Unity의 WWW 을 사용하지 않고 self signed SSL을 지원할 수 있도록 직접 구현한다.

  3. SSL 인증서 인증 과정에 관여하여 조작한다.

그중 3번 방법을 소개합니다.
.NET Framework의 ServicePointManager.ServerCertificateValidationCallback 를 이용하는 방법은 Android + WWW 사용이라는 환경에서는 안되더군요. 그래서 Java에서 바꿔보았습니다.

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

class X509Man implements X509TrustManager {

private X509TrustManager standardTrustManager = null; // 기본 TrustManager 인스턴스

public X509Man() throws KeyStoreException, NoSuchAlgorithmException {

// 기본 KeyStore
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());

// X509 TrustManagerFactory로 기본 TrustManager를 구함
TrustManagerFactory factory = TrustManagerFactory.getInstance(“X509”);
factory.init(keystore);
TrustManager[] trustmanagers = factory.getTrustManagers();
if (trustmanagers.length == 0) {
throw new NoSuchAlgorithmException(“X509 trust manager not supported”);
}
this.standardTrustManager = (X509TrustManager) trustmanagers[0];
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// 클라이언트 인증서는 기본 TrustManager가 처리
this.standardTrustManager.checkClientTrusted(chain, authType);
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// 서버 인증서는 필요한 규칙에 따라 처리
// … 생략

// 필요한 규칙 이외의 인증서는 기본 TrustManager가 처리
this.standardTrustManager.checkServerTrusted(chain, authType);
}

@Override
public X509Certificate[] getAcceptedIssuers() {
// 허용된 Issuer 목록도 기본 TrustManager 처리
return this.standardTrustManager.getAcceptedIssuers();
}
}


이어서 위의 클래스를 사용하는 함수 예제

private void trustOurHost() {

try {

// 기본 Hostname 검증기
final HostnameVerifier origHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();

// 커스텀 Hostname 검증기로 바꾸기
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {

// 필요한 규칙에 따라 hostname과 session으로 검증하여 true 반환
// … 생략

// 그 외의 경우는 기본 Hostname 검증기 사용
return origHostnameVerifier == null || origHostnameVerifier.verify(hostname, session);
}
});

// TLS 통신에서는 위에서 만든 클래스를 사용하는 Socket Factory를 지정
SSLContext context = SSLContext.getInstance(“TLS”);
context.init(null, new X509TrustManager[]{new X509Man()}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

} catch (Exception e) {
// 여기 오면 안되는데…
}
}


참고 자료
[How do I get a hold of Java’s default SSL Trust Manager]
[Java example – EasyX509TrustManager.java]
[Accessing Google APIs in Unity]

PathEngine에서 동적 장애물 처리 방법

BS가 회사에서 만들고 있는 게임에 PathEngine (http://www.pathengine.com/) 을 사용하고 있습니다.
PathEngine은 제품명이자 회사이름입니다. 헐… 회사 이름?
PathEngine is a privately held company located in Lyon, France
Thomas Young이 창립한 회사입니다. 이 사람의 개인 사업체라 생각하시면 될 듯…

암튼 본론으로 들어가서 PathEngine에서 코드를 통한 장애물은 아래의 단계로 처리하게 됩니다.

1. iMesh::newContext()
2. iPathEngine::newShape()
3. iMesh::placeAgent()
4. iCollisionContext::addAgent()

여기까지 하면 iCollisionContext가 준비 완료되는데 이를 가지고

방법1) Mesh에 구워버리기
iMesh::burnContextIntoMesh()
이후 에이전트들 모두 지우기

방법2) 동적으로 사용하기
iMesh::findShortestPath() 등의 함수들에서 iCollisionContext 사용

이렇게 사용하시면 됩니다.

여기에서 궁금사항… 그냥 문서만 보면 아래 방법도 될 듯 한데 해보지는 않았지만서도…

1. iMesh::newContext()
2. iPathEngine::newShape()
3. iMesh::placeAgent()
4. iMesh::newObstacleSet()
5. iObstacleSet::addAgent()
6. iCollisionContext::addObstacleSet()

이렇게 해도 되지 않나?

공개 개임 서버 MaNGOS

보통 World of Warcraft 사설 서버로 알려진 녀석입니다.

메인 페이지에서도 소개글에
The MaNGOS project is a full featured World of Warcraft server suite, including servers for authentication, client updates, world content serving, and battlegrounds.
라고 되어 있지요.
Windows x86, x64 모두 가능하고, GCC 4.3이 가능한 대부분의 플랫폼을 지원합니다.
뭐 말이 필요없죠. WoW 서버의 모든 기능… 심지어 클라이언트 업데이트까지 똑같이 만들고 있다니까요.
에서 자료를 받으실 수 있습니다.

공개 게임 서버 RedDwarf

이전에 Sun Microsystems가 진행하던 Project Dark Star가 Red Dwarf 라는 Source Forge 프로젝트로 진행되고 있습니다. Oracle에서 자른 건가요?

지금 0.10.1이 릴리즈 되었네요.
까만별하고 같이 서버는 Java 기반입니다.
클라이언트는 Java와 C 둘다 지원하지요.
Java만 지원하면 대부분 게임들이 사용하는 DirectX 클라이언트에서 사용을 못하고 그럼 쓸데가 없으니…
과거의 흔적이 남아 Java 패키지 경로가 sun 입니다.
com.sun.sgs 면… Sun Game Server 라는 뜻인가요?
이곳으로 가시면 있습니다.
짬나는대로 한번 간단한 거라도 만들어 볼까 생각 중인데 잘 되려나 모르겠네요…
최근 Java도 상당한 성능을 내고 있는지라…
아… 이것 저것 만들어보고 실험하는 R&D 연구소 같은 곳에 있으면 좋겠습니다.

무료 3D 게임 엔진 – Irrlicht

http://irrlicht.sourceforge.net

역시 없는 게 없는 Source Forge 입니다.
엔진의 가장 큰 특징은 DirectX와 OpenGL을 모두 지원하는 것입니다.
블리자드처럼 플랫폼을 다수 지원하는 게임을 만들려면 이런 엔진이 좋을 수도 있을 듯하네요.
뭐 최신의 DX11에 추가된 기능들은 지원하지 않지만…
상용 엔진처럼 다양한 기능도 없지만…
공짜! 라는 거
이게 중요하죠. ㅎㅎㅎ

Esenthel – 3D 게임 엔진

공짜부터 390,000 달러 (현재 환율로 약 4억 4천만원)까지 다양한 라이센스가 있는 엔진입니다.

상용엔진으로의 대부분의 기능을 제공합니다.
소개글을 적어보면
Esenthel Engine은 AAA 등급 게임을 만드는데 완벽한 개발 플랫폼이다.
상용 게임 개발에 특화되어 있다. (게임 코드를 맘대로, 차세대 그래픽, 개발 과정을 단순화 시켜주는 도구들)
물론 게임 개발 경험이 없는 소규모 업체나 팀도 쉽게 사용할 수 있다.
(BS의 발사이즈 토익 점수로 번역한 내용입니다. ㅎㅎㅎ)
이거 눈에 띄네요…
Free To Test
비상업용도로 공짜로 쓰세요~ 그리고 상업 용도로 정해지면 구매하세요~
Free Web Hosting
우리꺼 구매하면 당신네 웹사이트를 위해 웹호스팅을 제공해 주겠습니다~
뭐 사이트 자료보면 DX11도 어느정도 준비되어 있는 듯 하고…
가격도 적당하니 괜찮지 않을까 생각되네요.

길찾기를 위한 엔진

지금 회사에서는 PathEngine 을 사용하고 있습니다.(http://www.pathengine.com/)

가격이 만만치는 않지만 상용버전인만큼 사용하기에는 편리하게 되어 있습니다.
그리고 어쩌다 알게된 다른 엔진
홈페이지를 보니 어느 국내 개발자님께서 제작하신 듯 하고
메일주고사 @hitel.net 인 걸 보면 게임 업계에 꽤 긴시간을 보낸 분인 듯 합니다.
여기저기에 많은 글이 검색되네요. 이분…
2008년 버전의 소스를 보실 수 있고, 이후 버전은 메일로 문의를 하라 하시네요.
그외 최근 상용 엔진들은 대부분 길찾기를 지원하고 있는 듯 합니다.
회사에서 Unreal 사용중인데 Navigation Mesh를 자동 생성하여 처리할 수 있게 되어 있네요.
근데 왜 PathEngine을 다시 구매하느냐? 서버를 Unreal로 만들지 않고 Unreal에서 그 부분만 떼어내기가 만만치 않아서 말이죠. ㅋㅋ