1 Ağustos 2021 Pazar

HLA Engine

Giriş
Bu yazıda bir HLA Engine tasarımının özeti var. Tasarımı ben yapmadım. Sadece gördüklerimi not almak istedim.

Finite State Machine
Engine aslında bir Finite State Machine. Şu state'lerden oluşuyor.
1. BeginState
2. JoinSynchronizationState
3. LoadState
4. RunState
5. LeaveSynchronizationState
6. EndState
7. FailState

Eğer herhangi bir yerde hata olursa FailState'e geçilir.

Slave Engine İçin State Geçişi
BeginState -> otomatik olarak JoinSynchronizationState -> 
LoadState -> RunState -> LeaveSynchronizationState -> EndState

Commander Engine İçin State Geçişi
BeginState -> GUI'den loadScenario olunca JoinSynchronizationState -> 
LoadState -> RunState -> LeaveSynchronizationState -> EndState

Tüm engine'ler JoinSynchronizationState içindeki aynı noktaya gelince hep aynı anda başlar.

HLA Management Commands
Engine içinde bir kuyruk bulunur ve kuyruğa benim ismine Management Command dediğim nesneler eklenir. Amaç HLA thread'i ile Engine thread'ini birbirinden bağımsız hale getirmektir.

Örneğin HLA SaveFederation emri gelince HLA thread'i bloke olmadan Engine thread'i save işlemini yerine getirir.

Örneğin HLA RestoreFederation emri gelince HLA thread'i bloke olmadan Engine thread'i restore işlemini yerine getirir.

Tüm engine'ler belli bir frame içinde çeşitli işleri yapıp en son TimeAdvanceGrant komutunu beklerler.

Data Reconstruction Layer
HLA verisini saklamak ve bu verinin geldiğini üst katmanlara bildirmek gerekir. Bunun için belki adına Data Reconstruction Layer diyebileceğimiz bir katman bulunur. Bu katman gelen veriyi deserialize edip event'lere çevirir.

Bu katman da iki tane kuyruk bulunur
1. Engine Thread kuyruğu
2. HLA Thread Kuyruğu

Aslında daha kolay anlamak için iki tane federe düşünelim. Birinci federe viewer olsun. İkinci federe ise bir araba olsun. Her iki federe için time frame 0 olsun.

Birinci federe hemen time advance request yapar ve ben artık birinci frame'e geçmek istiyorum der.
İkinci federe arabanın yeni konumunu hesaplar ve birinci frame'de benim yeni konumum X der gönderir. Sonra time advance request yapar.

HLA her iki federeye de time advance granted gönderir ve birinci federeye X mesajını HLA thread'i üzerinden verir. Birinci federe bu mesajı HLA kuyruğuna ekler. Birinci federe Engine kuyruğu boş olduğu için hemen time advance request yapar.

İkinci federe yeni konumunu Y olarak hesaplar ve ikinci frame'deki konumum Y diye gönderir.

HLA her iki federeye de time advance granted gönderir ve birinci federeye Y mesajını HLA thread'i üzerinden verir. Birinci federe bu mesajı HLA kuyruğuna ekler. Birinci federe Engine kuyruğundaki  X mesajını işler hemen time advance request yapar.

Frame Başında
1. Her frame'in başında Engine Thread thread kuyruğunda bekleyen veri gerçek verinin üzerine yazılır. Daha sonra yeni veri hakkında ilgili observer'lara notificaiton gönderilir.

2. Kendi uygulamam tarafından veriyi değiştirmek üzere verilen asenkron komutlar işlenir ve yeni veri hakkında ilgili observer'lara notificaiton gönderilir.

Frame Sonunda
HLA kuyruğunda bekleyen nesneler Engine Thread kuyruğuna aktarılır. Örneğin benim frame sayım 1 olsun. İkinci frame'e geçmeden önce birinci frame'de HLA tarafından gönderilen tüm veriyi alır Engine kuyruğuna aktarırım. Bu nesneler ben ikinci frame'e başlarken işlenir.

Engine Tipleri
İki çeşit engine tipi var.
1. Commander Engine
2. Slave Engine

Commander engine synchronization point'leri yaratır ve tüm slave engine'lerin gelmesini bekler.

SynchronizationPoint
Basti bir CountDownLatch wrapper sınıfı yeterli. HLA tüm syncronization point'lere isim verdiği için wrapper sınıf isim bilgisi + CountDownLatch nesnesini saklar.

1. BeginState
Commander Engine şu çağrıları yapar.
1. rtiAmbassador.destroyFederationExecution()
 Tedbir amaçlı eğer eski federasyon varsa yok edilir.

2. rtiAmbassador.createFederationExecution()
 Yeni federasyon yaratılır

Bu state içinde Data Reconstruction Layer olaylarını işlemeye gerek yok.

2. JoinSynchronizationState

Yani bu state içinde belki Data Reconstruction Layer olaylarını işlemeye gerek olabilir.

Commander Engine şu çağrıları yapar.
2.1 rtiAmbassador.registerFederationSynchronizationPoint(pointName)
Burada 3 tane barrier kullanılır.
 - synchPointRegisteredBarrier
-  synchPointAnnouncedBarrier
- synchPointAchievedBarrier

 a. HLA synchronization point'i register etttim/yarattım deyinceya kadar synchPointRegisteredBarrier beklenir.
 b. HLA synchronization point'i anons ettim deyinceya kadar synchPointAnnouncedBarrier beklenir.
 c. rtiAmbassador.synchronizationPointAchieved() çağrısı yapılır. HLA tüm katılımcıların bu çağrıyı yapmasını bekler. Tüm katılımcılar yaptıktan sonra HLA federateAmbassador.federationSynchronized() callback'ini çağırır. Bu çağrı da geldikten sonra synchPointAchievedBarrier barrier de indirilir ve LoadState'e geçilir.

Slave Engine şu çağrıları yapar.
Burada 3 tane barrier kullanılır.
-  synchPointAnnouncedBarrier
- synchPointAchievedBarrier

2.1

a. HLA synchronization point'i anons ettim deyinceye kadar synchPointAnnouncedBarrier beklenir.
b. rtiAmbassador.synchronizationPointAchieved() çağrısı yapılır. HLA tüm katılımcıların bu çağrıyı yapmasını bekler. Tüm katılımcılar yaptıktan sonra HLA federateAmbassador.federationSynchronized() callback'ini çağırır. Bu çağrı da geldikten sonra synchPointAchievedBarrier barrier de indirilir ve LoadState'e geçilir.

3. LoadState
Bu state 3 frame boyunca çalışır.

Frame 1 
Commander engine paylaşmak istediği bilgileri paylaşır

Frame 2
Slave engine'ler bu bigileri okur ve işler

Frame 3
Tüm katılımcılar senaryoyu yüklerler. Senaryo ortak bir yerdeki dosya olabilir. Dosya okunur ve engine içinde her frame içinde çalışması gereken nesneler yaratılır.

Eğer senaryo bir engine tarafından dağıtılacaksa bu state içinde gelen HLA verisi deserialize edilir ve işlenir.

Yani bu state içinde belki Data Reconstruction Layer olaylarını işlemeye gerek olabilir.

4. RunState
Yani bu state içinde Data Reconstruction Layer olaylarını işlemeye gerek var.
Ayrıca bu state içinde HLA Management Commands olaylarını işlemeye gerek var.

rtiAmbassador.timeAdvanceRequest()
rtiAmbassador.setTimeToSent

Fixed Timestep Game Loop yazısına da bakılabilir.

5. LeaveSynchronizationState
Commander Engine şu çağrıları yapar.
rtiAmbassador.registerFederationSynchronizationPoint(pointName)
Burada
 1. HLA synchronization point'i yarattım deyinceya kadar beklenir.
 2. HLA synchronization point'i anons ettim deyinceya kadar beklenir.

3. rtiAmbassador.synchronizationPointAchieved() çağrısı yapılır ve EndState'e geçilir.

Slave Engine şu çağrıları yapar.
1. HLA synchronization point'i anons ettim deyinceya kadar beklenir. Daha sonra
rtiAmbassador.synchronizationPointAchieved() çağrısı yapılır ve EndState'e geçilir.

6. EndState
Her Engine şu çağrıları yapar.
rtiAmbassador.resignFederationExecution()
rtiAmbassador.destroyFederationExecution()

Hiç yorum yok:

Yorum Gönder