- Mesaj
- 1.626
- Çözümler
- 57
- Beğeni
- 3.390
- Puan
- 1.839
- Ticaret Puanı
- 0
Bakarız ileride, hala aklımda bin tane fikir varabi bu alt yapı satılık olucakmı keyfimi yapıyorsun
Bakarız ileride, hala aklımda bin tane fikir varabi bu alt yapı satılık olucakmı keyfimi yapıyorsun
[Devlog] Birleşik İkili Harita Formatı (.ashenfallmap): 1.5 Milyon Satır Çöpün Temizliği, Sıfır Gecikmeli Bellek Eşleme ve Deterministik Arazi Hattı
Ashenfall motorunun dosya sistemi ve arazi hattında, 2004 yılından miras kalan ilkel ve parçalanmış map yükleme/yazma mimarisini tamamen çöpe attım. Klasörler dolusu yüz binlerce başıboş dosyanın ana thread üzerinde senkronize I/O darboğazı oluşturduğu, kamera her hareket ettiğinde diski kilitleyen ve komşu harita sınırlarında dikiş izleri (seam drift) yaratan 20 yıllık eski kafayı projeden söküp attım.
136 harita klasörünü, 10.823 adet başıboş dosyayı ve diskteki 1.5 milyon satırlık metin/veri çöpünü tek hamlede temizledim. Yerine, hem istemcinin hem de WorldEditor'ün sıfır dinamik bellek kopyalamasıyla doğrudan okuyup yazabildiği birleşik ikili kapsayıcı mimarimi (.ashenfallmap) sıfırdan geliştirdim.
Eski Yöntem Neydi ve Neden Terk Edildi?
Geleneksel harita yapısında tek bir açık dünya haritası; yüzlerce 000000/, 000001/ alt klasörüne bölünmüş height.raw, tile.raw, attr.atr, water.wtr, minimap.dds ve metin tabanlı areadata.txt, setting.txt gibi binlerce başıboş dosyadan oluşuyordu.
Bu ilkel düzen şu devasa problemleri beraberinde getiriyordu:
- Senkronize CPU ve I/O Darboğazı: Karakter haritada yürürken 3×3'lük chunk penceresi her güncellendiğinde ana thread üzerinde onlarca metin dosyası satır satır ayrıştırılıyor (LoadMultipleTextData), LZO ile sıkıştırılmış küçük dosyalar için pack kilitleri (lock) tetikleniyor ve anlık mikro takılmalar (stutter / hitch) kaçınılmaz oluyordu.
- Sınır Kayması (Border Drift) ve Dikiş İzleri: Komşu arazilerin yükseklik sınırları her iki parça tarafından ayrı ayrı saklanıyordu. Yıllar içinde bu veriler birbirinden kopmuştu; örneğin lonca haritasında (guild_war4) iki komşu chunk arasında 50 metrelik uçurumlar ve uyuşmayan 370'in üzerinde kenar noktası mevcuttu.
- Yanlış Klasörlenen Objeler: 46.000'den fazla dünya nesnesinin 549 tanesi üzerinde durduğu arazinin değil, tamamen farklı koordinatlardaki klasörlerin içine yazılmıştı. Bu durum, kameranın görüş açısına göre ağaçların ve binaların aniden havadan belirmesine ya da erken kaybolmasına (pop-in) sebep oluyordu.
- Çapraz Harita Doku Bozulması: Editörde tek bir haritanın zeminini düzenleyip kaydettiğinizde, ortak kullanılan paylaşımlı textureset dosyası ezildiği için alakasız diğer 10 haritanın zemin kaplamaları geri dönülemez şekilde bozuluyordu.
Yeni Sistem Nasıl Çalışıyor? (Teknik & Mimari Altyapı)
Yeni mimaride artık klasörler, metin dosyaları ve parça parça raw array'ler yok. Harita başına yalnızca tek bir deterministik binary kapsayıcı (.ashenfallmap) bulunuyor.
Kod:┌────────────────────────────────────────────────────────────────────────┐ │ .ashenfallmap MİMARİSİ │ ├───────────────────┬────────────────────────────────────────────────────┤ │ 64-Bayt Header │ PNG-stili Sihirli Baytlar (Magic), Sürüm, CRC-32 │ │ Section Table │ 32-Bayt Hizalı Bölüm Başlıkları (Tag, Offset, CRC) │ │ Sabit Katmanlar │ META (Ayarlar), STRS (Dizgi Havuzu), LAYR, CHNK │ │ Raster Verileri │ HGHT (129² uint16), TILE (256²), ATTR, WATR, MINI │ │ Varlık Tabloları │ INST (48-Bayt POD), AMBI (24-Bayt POD) │ └───────────────────┴────────────────────────────────────────────────────┘
1. Sıfır Kopyalamalı Bellek Eşleme (Zero-Copy Memory-Mapped I/O)
Dosya mimarisi mmap ve doğrudan işaretçi (pointer) aritmetiği için 16-bayt sınırlarına hizalandı. Harita arşivi istemciye EPack32 Type 0 (Stored / Sıkıştırmasız) olarak paketleniyor.
İstemci haritayı açtığında diski belleğe tek bir sanal adres uzayı olarak eşliyor (CEterPack::Get). Pack arşivi açılırken CPU üzerinde hiçbir global kilit (lock) oluşmuyor; sayfalar (pages) belleğe yalnızca dokunuldukça (page fault mantığıyla) işletim sistemi tarafından sıfır gecikmeyle çekiliyor.
2. Katman Bazlı Yükseklik Delta Filtreleme & Blob DEFLATE
Harita geometrisi ve raster katmanları dosya içinde katı bir determinizmle organize edildi:
- Filtrelenmiş Yükseklik Verisi (Height Delta Planes): 129×129'luk ham yükseklikler komşu piksel delta farklarına ayrılarak düşük ve yüksek bayt düzlemlerine (planes) bölündü. Bu filtreleme, salt DEFLATE sıkıştırmasına kıyasla yükseklik verisinde fazladan %27 boyut tasarrufu sağladı.
- Türetilebilir Verilerin Tasfiyesi: Komşu arazilerin sınır halkaları (rings), yüzey normalleri ve splat haritaları dosyada saklanmıyor; yükleme anında bitişik komşulardan dikişsiz olarak türetiliyor (AssembleHeightRing). Kenar yükseklikleri matematiksel olarak eşitlendi ve drift problemi tamamen ortadan kaldırıldı.
- Gömülü Doku Paleti (LAYR): Her harita kendi zemin katmanlarını ve UV ölçeklerini kendi içinde taşıyor. Editörde bir haritayı düzenlemek artık başka hiçbir haritanın zeminini etkileyemiyor.
3. 48-Bayt Sabit POD Nesne Dizilimi
Metin tabanlı areadata.txt ayrıştırması tamamen kaldırıldı. Binalar, zindan blokları, ağaçlar ve efektler harita koordinatlarına göre sıralanmış 48 baytlık sabit POD (Plain Old Data) struct'ları olarak saklanıyor. Yanlış klasörlenen 549 nesne matematiksel olarak üzerinde durdukları doğru chunk sınırlarına taşındı.
Performans & Optimizasyon Kazanımları
Bütün projedeki 136 haritanın (106 bağımsız harita, 30 hafif alias) tamamı yeni formata geçirildiğinde elde edilen net mühendislik verileri:
Gelecekte araziyi doğrudan GPU üzerinde Compute Shader veya Indirect Draw ile tek geçişte çizeceğimiz Full-Map Terrain Renderer mimarisine geçiş için gereken temiz, contigous ve modern veri altyapısını böylece tamamlamış oldum.
- 1.5 Milyon Satır ve 10.823 Dosya Çöpe Gitti: +1.321 / -1.502.382 satırlık diff ile kaynak koddan tüm ilkel loader'lar, metin parser'lar ve başıboş klasörler kalıcı olarak kazındı.
- %78 Disk Ayak İzi Küçülmesi: Eski sistemde 313 MB tutan dağınık harita verisi, yeni mimariyle birlikte kayıpsız olarak 67.4 MB boyutuna indi. En büyük 6×6 kar haritasının (map_n_snowm_01) tüm zemin ve nesne geometrisi yalnızca 2.37 MB.
- 26 Milisaniyede 136 Harita: 136 haritanın tamamını açıp başlık ve CRC doğrulamalarını tamamlamak C++ motorunda toplamda yalnızca 26 ms sürdü.
- 0.06 ms Chunk Açılma Hızı: Karakter arazide ilerlerken yeni bir parçanın bellekten çekilip çözülmesi 0.06 milisaniyeye (60 mikrosaniye) düştü. Chunk geçişlerindeki mikro takılmalar, anlık FPS düşüşleri ve disk I/O beklemesi tamamen sıfırlandı.
- Determinizm ve Pre-Commit Güvenliği: Yazılan MapDocument mimarisi sayesinde, harita WorldEditor ile açılıp hiçbir düzenleme yapılmadan kaydedildiğinde bile diskteki dosyanın tek bir baytı dahi kaymıyor; byte-identical determinizm korunuyor. Repoya eski tip harita dosyalarının girmesi ise CI/CD hattına eklediğim pre-commit gate kontrolüyle engellendi.
┌────────────────────────────────────────────────────────────────────────┐
│ BİRLEŞİK SUNUCU/DÜNYA MİMARİSİ │
├───────────────────┬────────────────────────────────────────────────────┤
│ maps/world... │ .ashenfallworld: Global koordinatlar, Server ID, │
│ (PLCE + STRS) │ Harita boyutları, çakışma kuralları (Single-Source)│
├───────────────────┼────────────────────────────────────────────────────┤
│ Format 1.1 Ekleri │ TOWN (Doğma/İmparatorluk noktaları, 36-Bayt POD) │
│ (Opsiyonel) │ SETS (İsimli spawn setleri: boot, boss, event) │
│ │ SPWN (36-Bayt sabit POD spawn kayıtları) │
└───────────────────┴────────────────────────────────────────────────────┘
Şu anda tam olarak terraine rework atıyordum bunu yazdınız. Bu yazdıklarınızı yapay zekayla taş çatlasın 5 dakika önce tartıştım. Sanki yorumunuzu tam şu an ekranıma bakıp yazmışsınız gibi. Şu anda ufuk çizgisine kadar aralıksız terrain bile çizsek, 1FPS bile zararı dokunmayacak gelişmiş bir terrain sistemi yazıyorum.Editorler cok guzel ve kullanisli duruyor elinize saglik. Aslinda terrain sistemini de sifirdan yazip ustune Unreal Unity'dekine benzer bi tooling insa edilebilir.
Daha da guzeli birbirinde ayri mapler uzerinden calisan bi oyun yerine tamamen open world bi dunya olurdu. Yani oyuncu hic bir loading screen gormeden mavi bayrak 1.koyden sari bayrak 1.koye yuruyebilse. Gerci gunumuz fileslari goz onune alindiginda hic bi oyuncunun umursamayacagi bir ozellik olurdu muhtemelen.
World Editor gibi item editor, mob editor toolari da aslinda yazilip hepsi tek bir program icerisine gomulse oyun icerigini olusturmak ve yonetmek cok kolay bi hale gelebilir. Ilerisi icin boyle bir dusunce var mi?
.open worldlerin bazılarında pasaj ya da ince geçt gibi yerden player yürürken geçtiği mapi yükleme mantığı koyan oyunlar var"great minds think alike" diyelim o zaman hocam.
Buradaki temel problem client tarafinda cikmaz ama server tarafini boyle bir yapiya gecirmek epey zorlu olabilir. Client kendisi tum haritayi cell'lere ayirip oyuncunun pozisyonuna gore etrafindaki celleri yonetebilir. Statik objeler icin is kolay ama mevzu bahis server tarafindan yonetilen oyunculari yuklemeye geldiginde is biraz daha karisiyo. Server tarafinin da bu cell yapisina hakim olup, client'a "bu cell'in etrafinda bu objeler bulunuyor, bunlari yukle" demesi lazim.
Tabi client tarafinda da bazi zor kisimlar var. Mesela oyuncu bir dagin tepesine cikip ufka baktiginda cok uzaktaki cell'leri gorebilir ama oyuncunun gordugu her cell'in memory'e yuklenmesi performans acisindan inanilmaz sakincali bir durum. Orada da Unreal'in HLOD sistemine benzer sistemler lazim. Burada WoW gibi open world mmo'lar nasil cozmus bu problemleri onlari arastirmak lazim.
┌────────────────────────────────────────────────────────────────────────┐
│ GPU-DRIVEN CDLOD & HI-Z PIPELINE │
├───────────────────┬────────────────────────────────────────────────────┤
│ 1. Frame Open │ GPU'da tekil Indirect Args sıfırlama (Upload ring) │
│ 2. Compute Select │ Dörtlü ağaç seçimi & GPU tabanlı CDLOD │
│ 3. Phase 1 Cull │ Önceki karenin Hi-Z derinlik piramidine karşı test │
│ 4. Depth Prepass │ Görünen parçaların derinliği tekil ExecuteIndirect │
│ 5. Hi-Z Pyramid │ Prepass sonu derinlikten mip zinciri inşası (Hi-Z) │
│ 6. Phase 2 Cull │ Elenen parçaları prepass sonu anında kurtarma │
│ 7. Lit Pass │ Shading: Tek geçiş splatting, DXR ışınları, 0 over │
└───────────────────┴────────────────────────────────────────────────────┘
GetHeight), duvara çarpma engelleri (isAttrOn), tıkla-git ışınları (Pick), balıkçılık sorguları ve hatta mini harita hâlâ 2004 yılından miras kalan ilkel bir 3x3'lük chunk streaming penceresine mahkumdu. Karakter her 128 metre yürüdüğünde ana iş parçacığında (main thread) diskten senkronize arazi yükleniyor, kare hızında mikro donmalar (hitch/stutter) yaşanıyor ve 3x3 pencerenin dışına yapılan tüm sorgular zemini "yok (0)" sanıyordu.CTerrain sınıf ailesini, chunk yükleme kuyruklarını ve 3x3 streaming illüzyonunu motor kodundan ebediyen sildik.GetHeight tam ters köşegenden interpolasyon yapıyordu. Sonuç: Dik yokuşlarda karakterlerin ve yere düşen eşyaların bir ayağının toprağa gömülmesi veya havada asılı kalması!┌────────────────────────────────────────────────────────────────────────┐
│ MAPGROUND CPU UNIFIED ARCHITECTURE │
├───────────────────┬────────────────────────────────────────────────────┤
│ 1. Map Load │ .ashenfallmap tek seferde MapGround belleğine açılır│
│ 2. Single Decode │ GPU (TerrainMap) & Su (MapWater) direkt buradan alır│
│ 3. O(1) Queries │ Yükseklik, Attr, Normal, Su: Slot araması YOK │
│ 4. Bounds Raycast │ Quadtree hızlandırmalı sınırsız Pick (Amanatides) │
│ 5. Object Sync │ Statik objeler & ağaçlar 3x3 pencereden bağımsız │
└───────────────────┴────────────────────────────────────────────────────┘
GetHeight, isAttrOn ve WaterLevel sorguları 9 slotluk matrislerde chunk aramaz; $O(1)$ matris indeksiyle anında yanıt verir.MapWater). Haritanın dışına deniz eteği çizilme şartı, haritanın dış çerçeve hücrelerinin (perimeter) en az 1/8'inin açık deniz seviyesinde olması kuralına bağlandı. Kapalı zindanlar ve iç gölleri olan haritalar sahte okyanuslardan kurtuldu.CTerrainAccessor silindi. Yeni MapBrushes mimarisi doğrudan MapGround tamponlarına yazar. İki chunk'ın sınırına fırça vurulduğunda artık dikiş hesapları veya kenar eşitleme (ShareEdges) algoritmaları koşturulmaz; zemin tek parça olduğu için doğal olarak kusursuz boyanır.MapGround'a kenetlendi.MapGroundCheck) kurduk:| Test Edilen Harita | Test Noktası Sayısı | Bit-Level Uyuşmazlık | Raycast (Pick) Testi |
|---|---|---|---|
| metin2_map_a1 | ~2.6 Milyon | 0 | 21.000 Işın (Kusursuz) |
| devilscatacomb | ~2.7 Milyon | 0 | 15.000 Işın (Kusursuz) |
| battleroyale | ~5.0 Milyon | 0 | 16.000 Işın (Kusursuz) |
MapGround bit-seviyesinde kıyaslandı ve sıfır hata ile doğrulandı.CTerrain, CTerrainImpl, CTerrainAccessor ve TerrainType.h dosyaları tamamen silindi.CMapOutdoor içindeki arazi vektörleri, 60 saniyelik silme havuzları (TerrainDeleteVector) söküldü.