fivem-assets · git:20260816.136d82e · 2026-08-16 · sha256 dc0c1d9112945ed0

fivem-assets git:20260816.136d82eA

Immutable. This exact content is served forever at /api/v1/blob/dc0c1d9112945ed0.

---
name: fivem-assets
description: GTA V/FiveM prop, obje, kapı, animasyon, PED İSKELETİ/KEMİĞİ, YÜZ ANİMASYONU, expression ve ytyp verisine erişim. Bir prop/obje/kapı/animasyon/kemik ile ilgili KOD YAZMADAN ÖNCE bu skill ile gerçek asset verisine bakılır. Kullanıcı bir objeyi hareket ettirmek, kapı açmak/kilitlemek, prop spawn etmek, animasyon oynatmak, ymap/ytyp/MLO ile uğraşmak, ped kemiğiyle iş yapmak, yüz ifadesi/mimik vermek ya da rigging yapmak istediğinde MUTLAKA devreye gir — kullanıcı "skill" demese bile. Model adı geçen (v_ilev_*, prop_*, p_*, ch_prop_*), "kapı açılmıyor", "obje kımıldamıyor", "freeze", "AddDoorToSystem", "TaskPlayAnim", "anim dict", "prop animasyonu", "hangi animasyon", "bu prop var mı" ve ayrıca "kemik", "bone", "SKEL_", "FB_", "PH_R_Hand", "bone tag", "GetPedBoneIndex", "GetPedBoneCoords", "iskelet", "rig", "rigging", "armature", "yüz animasyonu", "mimik", "ifade", "gülümseme", "surat", "facial", "PlayFacialAnim", "SetFacialIdleAnimOverride", "facials@", "expression", ".yed", "blink", "göz kırpma", "kaş", "dudak", "ağız", "viseme", "lipsync" ve ayrıca "retarget", "Sketchfab", "Mixamo", "Rigify", "FBX", "weight paint", "ağırlık boyama", "skinning", "vertex group", "T-pose", "A-pose", "root motion", "mover", "kemik eşleme", "animasyon aktarma", "Blender animasyon", "Sollumz" ve ayrıca "DUI", "3D NUI", "3dnui", "cr-3dnui", "dünyada ekran", "objede ekran", "obje üstünde UI", "CreateDui", "SendDuiMessage", "AddReplaceTexture", "ReplaceTexture", "runtime texture", "CreateRuntimeTxd", "DrawTexturedPoly", "DrawSpritePoly", "render target", "script_rt", "raycast UV", "tıklanabilir ekran", "etkileşimli obje", "ATM ekranı", "keypad UI", "monitör", "laptop ekranı", "kamera monitörü", "tabela", "billboard" ve ayrıca "add-on silah", "addon weapon", "custom weapon", "silah ekleme", "kendi silahım", "silah modeli", "weapons.meta", "weaponarchetypes.meta", "weaponcomponents.meta", "pedpersonality.meta", "vWeaponsToolkit", "WEAPON_", "WAPClip", "AAPClip", "Gun_Main_Bone", "Gun_Trigger_Pr", "Gun_Cock1", "şarjör", "mag", "susturucu", "dürbün", "weapon component", "weapon tint", "GiveWeaponToPed", "str_requestFlush" ve ayrıca "parlayan silah", "glowing gun", "glow", "emissive", "normal_spec_emissive", "wireframe silah", "tel kafes", "silah skini", "weapon skin", "UV animasyon", "UV anim", "animasyonlu silah", "animated weapon", "akan doku", "zincir", "chain", "charm", "silah süsleme", "clip@", "Auto Start Anim", "clip dictionary" ve ayrıca "partikül", "particle", "ptfx", "efekt", "duman", "smoke", "ateş", "fire", "kıvılcım", "spark", "buhar", "steam", "toz", "dust", "su damlası", "sinek", "hamamböceği", "kar", "yaprak", "patlayınca", "kırılınca", "vurulunca", "StartParticleFx", "amb_", "dst_", "brk_", "core.ypt", "fxType", "CExtensionDefParticleEffect" ve ayrıca "LOD", "lod mesafesi", "lodDist", "childLodDist", "SLOD", "uzaktan kaybolma", "titreşiyor", "flicker", "hayalet kopya", "pop-in", "LOD zinciri", "ParentIndex", "LOD Adopt Me", "orphan LOD", "LODTYPES", "ORPHANHD" ve ayrıca "ytyp bayrağı", "ymap bayrağı", "entity flags", "archetype flags", "specialAttribute", "1572872", "18350080", "Enable Door Physics", "Has Anim", "UV anims", "Static entity", "Cast Static Shadows", "extension", "ytyp extension", "Ladder extension", "Buoyancy", "LightShaft", "SpawnPoint", "WindDisturbance", "ProcObject", "Expression extension" ve ayrıca "çim", "grass", "grass batch", "prosedürel", "procedural", "Procedural ID", "@ma collision", "fur grass", "terrain shader", "terrain_cb4", "vertex paint", "zemin dokusu", "nametable", "name table", "hash isim", "Gen8", "Gen9", "GTAV Enhanced", "target_formats", "pymateria", "CWXML" ve ayrıca "araç", "vehicle", "handling", "handlingId", "handling.meta", "modkit", "SetVehicleModKit", "araç ekstra", "SetVehicleExtra", "araç sınıfı", "hangi araç", "araç listesi" ve ayrıca "silah bileşeni", "weapon component", "COMPONENT_", "GiveWeaponComponentToPed", "livery", "AttachBone", "WAPClip", "WAPScop", "mermi tipi", "AmmoType" ve ayrıca "ped meta", "hangi ped", "ped listesi", "MovementClipSet", "SetPedMovementClipset", "ClipDictionaryName", "ExpressionSet", "PedVoiceGroup", "ped tipi", "Pedtype", "hayvan pedi", "animal ped" ve ayrıca "MLO listesi", "iç mekân nerede", "interior konumu", "MLO sürümü", "IPL", "RequestIpl", "RemoveIpl", "ipl adı", "interior yükle" ve ayrıca "loot noktası", "spawn noktası", "ATM nerede", "kamera nerede", "CCTV konumu", "bank konumu", "çöp konteyneri", "sokak lambası", "trafik ışığı", "benzin pompası", "otomat", "vending machine", "dünya nesnesi", "nesne konumu", "yakınımdaki objeler", "rotasyon", "prop rotasyonu" geçen her görevde kullan.
---

# FiveM Asset Verisi — önce bak, sonra kod yaz

## TEMEL KURAL

**Bir obje/prop/kapı/animasyon hakkında kod yazmadan önce o asset'in verisine
bakılır.** Native denemek, "şunu da ekleyelim" demek, üç farklı yaklaşımı
sırayla denemek — bunlar veriye bakmamanın maliyetidir.

Somut örnek (gerçek vaka): Fleeca vezne kapısı `v_ilev_gb_teldr` bir türlü
açılmadı. `AddDoorToSystem`, `FreezeEntityPosition`, `SetEntityDynamic`,
`NetworkRequestControlOfEntity` sırayla denendi. Cevap ytyp'nin tek satırındaydı:

```
specialAttribute = 0   → bu obje kapı DEĞİL, kapı sisteminde menteşesi yok
```

Tek sorgu (`assetdb.py door v_ilev_gb_teldr`) bunu baştan söylerdi.

## OTOMATİK SORGU TABLOSU — kullanıcı komut vermez, sen bakarsın

Bu skill bir **kütüphanedir**: aşağıdaki konu geçtiği anda, kullanıcı hiçbir
komut yazmasa bile ilgili sorgu **kod yazmadan önce** çalıştırılır. Sonucu
kullanıcıya özetle, sonra koda geç.

| Konu geçtiğinde | ÖNCE bunu çalıştır |
|---|---|
| bir prop/obje/kapı adı | `assetdb.py show <ad>` |
| "kapı açılmıyor / kilitlensin" | `assetdb.py door <ad>` |
| partikül, duman, ateş, kıvılcım, efekt | `assetdb.py ptfx <prop\|efekt>` |
| **"şu efekt var mı"**, `fxName` doğrulama, `.ypt` | `assetdb.py fx <ad> --exact` |
| "patlayınca/kırılınca toz çıksın" | `assetdb.py ptfx --type 4` (Destroy) / `--type 3` (Break) |
| bir ytyp bayrak/extension sorusu | `assetdb.py ext <ad>` |
| anlamı bilinmeyen bayrak sayısı | `assetdb.py flags <sayı> [--entity]` |
| LOD, lodDist, "uzakta kayboluyor/titriyor" | `assetdb.py lod [--size <m>]` |
| bir modelin LOD zinciri nasıl kurulmuş | `assetdb.py lodchain <ad>` |
| "haritamda sorun var mı", ymap denetimi | `assetdb.py lodaudit` |
| çim, zemin, `Procedural ID`, @ma | `assetdb.py proc [<ad>\|--id N]` |
| collision materyali, "hangi malzeme", bayraklar | `assetdb.py mat [<ad>\|--index N]` |
| **decal** — kan/iz/leke **script'le** (`AddDecal`) | `assetdb.py decal <kan\|mermi\|ayak\|yanık\|yağ\|benzin>` |
| **decal** — haritaya kalıcı gömülü, "hangi shader" | `assetdb.py shader decal` |
| cam/emissive/terrain/kumaş/araç/su shader'ı | `assetdb.py shader <tür>` |
| animasyon / klip | `assetdb.py anim <ara>` · `propanim <prop>` |
| kemik / tag | `assetdb.py bones <model>` · `pedrig.py` |
| expression / `.yed` / yay-sarkma | `assetdb.py ext <ad>` + `expr <ara>` |
| **ped kimliği** — "bu ped hangi klip sözlüğünü/expression'ı kullanıyor" | `assetdb.py pedmeta <ped>` |
| **silah** — bileşen/livery adı, `AttachBone`, mermi tipi | `assetdb.py weapon <ad> --parcalar` |
| **araç** — `handlingId`, modkit, extra, sınıf, koltuk | `assetdb.py vehicle <ad>` |
| **MLO** — iç mekân listesi, dünya konumu, kaç sürümü var | `assetdb.py mlo <ad>` |
| **IPL** — `RequestIpl`/`RemoveIpl` adı doğrulama | `assetdb.py ipl <ad>` |
| **"şuraya loot/spawn noktası koyalım"**, ATM/CCTV/bank/çöp konumu | `assetdb.py world --near x,y,z --mesafe 50` |
| bir nesne ailesinin tamamı (tüm ATM'ler, tüm kameralar) | `assetdb.py world --family <aile>` · `--aileler` |

**Sihirli sayı görürsen çöz, kopyalama.** `1572872`, `18350080`, `549584896`
gibi bir bayrak değeri geçiyorsa `assetdb.py flags` ile aç ve ne anlama
geldiğini söyle. Bit tabloları `references/ytyp-ymap-bayraklari.md`'de.

**Sessiz hata sınıfı — bu konularda uyarmadan geçme:**
- yanlış yazılmış `fxName` → efekt hiç çıkmaz, hata da vermez
- animasyon ytyp'inde BB min/max kutusu yok → obje uzakta titrer ve kaybolur
- bake edilmemiş animasyon → oyunda ölçeklenir (CodeWalker'da doğru görünür)
- LOD zincirinden bir halka eksik → tüm zincir bozulur
- mesh collision + `Dynamic` → obje yerin içine düşer
- `.ycd` her zaman XML çıkar (`target_formats` ona ulaşmaz) → `xml_to_ycd.ps1`

## OYUNA GİRMEDEN DOĞRULA — CodeWalker merdiveni

**Tam reçete: `references/oyuna-girmeden-dogrulama.md`**
Araç: `scripts/cw_anim_check.ps1`

Bir asset'i (animasyon, doku, model, ytyp) test etmek için sunucuya
bağlanmak **en son çaredir**. FiveM stream dosyalarını cache'lediği için
her oyun-içi tur tam çıkış + yeniden bağlanma gerektiriyor. Sistemde
CodeWalker varsa (`CodeWalker.Core.dll`) doğrulamanın büyük kısmı
saniyeler içinde, oyun açılmadan yapılır.

**Kural: bir basamakta yakalanabilecek hatayı alt basamağa taşıma.**

| Ne doğrulanacak | Basamak |
|---|---|
| ağırlık, deform, pivot, ölçü | Blender'da **ölç** (`evaluated_get`) |
| shader/bucket, kemik tag, hiyerarşi, `<Hash>`, klip sayısı | `res_to_xml.ps1` + vanilla ile **yapısal diff** |
| klip eğrisi, faz→değer, genlik, ölü kuyruk | `cw_anim_check.ps1` (headless CodeWalker.Core) |
| "gözle doğru duruyor mu" | Blender render → **kullanıcıya dosya gönder** |
| vanilla asset incelemek, dünya yerleşimi, MLO düzeni | CodeWalker GUI (**elle**, kullanıcı sürer) |
| script, fizik, gerçek görünüm, streaming, resmon | **oyun** |

- `CodeWalker.Core.dll` bir kütüphanedir: Model Viewer'ın animasyon
  değerlendirme kodu (`GetFramePosition` + `EvaluateVector4/Quaternion`)
  headless çağrılabilir. Klibin hangi kemiğe hangi fazda ne yazdığı
  **sayıyla** okunur.
- **Headless denetim görsel onayın yerine geçmez.** Sayı "doğru" dese de
  kullanıcı göremez; render alıp **dosya olarak ilet**, klasör yolu verme.
- `ClipBase.Name` OKUMA → StackOverflow, süreç exit 253, hata mesajı yok.
- `Add-Type`'a **`netstandard`** referansı şart; `Animation.BoneIds` dizi
  değil → `.data_items`.
- CodeWalker GUI'de `LoadClipDict(string)` sözlüğü **ada göre oyun
  verisinden** çözer: resource klasöründeki serbest `.ycd` listede çıkmaz.
- CodeWalker taşınabilir `.exe` ise computer-use `request_access` onu
  bulamaz → GUI basamağını ajan **süremez**, kullanıcıya tarif verir.
- **Ardışık kliplerde birleşme noktasını ölç.** Klipler mutlak kemik
  dönüşümü yazar: A'nın son karesi ile B'nin ilk karesi **her kanalda**
  eşleşmezse tek karede sıçrar. İki kez yaşandı — biri seviye (dolum %100,
  çalkalanma %72 → sıvı zıpladı), biri eğim (dolum 0.00°, çalkalanma 9.00°
  → "frame skip" görüntüsü). Her klip nötr başlar, nötr biter; ortak
  seviye **tek sabitten** gelir (üretici + önizleme + Lua aynı sabiti okur).
- **Hareketin fiziği de ortak sabit olmalı** — frekans, tepe genliği,
  sönüm. Konum/açı tutsa bile farklı sabitler *hız değişimi* gibi görünür:
  **algılanan hız genliğe bağlıdır**. Yaşandı: sönüm 2.6 vs 2.0, genlik
  5.5° vs 9.0° → "dalgalanma sönerken bir anda darbe alıp hızlanıyor".
  Denetim: iki klibi sönüm başlangıcına hizalayıp aynı sürelerde ölç.
- **Önizleme render'ı klip formülleriyle aynı modülden beslenmeli**, yoksa
  kullanıcıya asset'te olmayan bir davranış gösterilir.

## SORGU ARAÇLARI

Plugin kökü: `${CLAUDE_PLUGIN_ROOT}` (yoksa `~/.claude/muto-atlas`).

```bash
# Obje gerçeği: kapı mı, pivot nerede, fiziği var mı
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" show <model adı>
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" door <model adı>

# Arama
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" search <parça>    # tüm archetype'lar
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" prop   <parça>    # spawn edilebilir proplar

# Dünyada nerede (ymap + MLO iç mekân dahil)
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" where <model adı>
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" near <x> <y> <z> --radius 10 [--filter door]

# --- dump katmanları (build_dumps.py üretir) ---
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" pedmeta <ped>            # klip sözlüğü + expression + clipset
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" weapon  <ad> --parcalar  # bileşen + livery + AttachBone
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" vehicle <ad>             # handlingId, modkit, extra
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" mlo     <ad>             # iç mekân + TÜM dünya konumları
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" ipl     <ad>             # RequestIpl adı doğrulama
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" world --aileler          # 34 nesne ailesi
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" world --near x,y,z --mesafe 50
```

### Çıkış kodları — bir kapıya bağlıyorsan bunlara bak

`assetdb.py` dört ayrı kod döndürür. **Hepsini `!= 0` diye okumak yanlıştır:**

| kod | anlam | ne yapmalı |
|---|---|---|
| 0 | bulundu | devam |
| 1 | sorgu çalıştı, **ad otoritede yok** | asset gerçekten yok ya da yanlış yazılmış |
| 2 | **veri katmanı kurulu değil** | sonuç hakkında HİÇBİR ŞEY denemez — build betiğini çalıştır |
| 3 | iç hata (bozuk dosya, istisna) | veri bozuk, "yok" DEĞİL |

`2` ile `1`'i karıştırmak, katman eksik olduğu için çıkan "0 sonuç"u
"bu asset oyunda yok" diye okumaktır — ev kuralı: *aracın göstermemesi,
o şeyin yok olduğu anlamına gelmez.*

```bash

# Animasyon
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" anim <terim>
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" anim <dict> --dict
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" scenario <terim>

# İndeks durumu
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" stats

# Modelin ekranı var mı — shader/doku eşlemesi (AddReplaceTexture için)
powershell -NoProfile -ExecutionPolicy Bypass \
  -File "${CLAUDE_PLUGIN_ROOT}/scripts/screentex.ps1" -Model <model adı> -All
```

İndeks vanilla RPF'lerden (CodeWalker.Core ile) + sunucunun kendi ytyp'lerinden
üretilir. Yeniden kurmak için `/asset-build`.

## specialAttribute — KAPI TABLOSU

316k archetype'ın dağılımından doğrulandı, tahmin değil:

| Değer | Anlam | Kapı sistemi çalışır mı |
|---|---|---|
| **7** | menteşeli kapı | ✅ evet — `AddDoorToSystem` + `DoorSystemSetDoorState` |
| **8** | sürgülü kapı | ✅ evet |
| **5** | garaj / rulo kapı | ✅ evet |
| **10** | kepenk / asansör kapısı | ✅ evet |
| **12** | demiryolu bariyeri | ✅ evet |
| **0** | kapı DEĞİL | ❌ hayır — kayıt olsa bile obje kımıldamaz |
| diğer | bitki, mobilya, trafik, SLOD... | ❌ hayır |

`specialAttribute = 0` ise:
1. Kapı sistemi **hiçbir şey yapmaz** — denemeye değmez.
2. Tek script-içi yol: `SetEntityHeading` ile transform'u yeniden yazmak.
   Doğru görünmesi için pivot'un kenarda olması gerekir → `show` çıktısındaki
   bbox yorumu bunu söyler.
3. Kalıcı doğru çözüm: ytyp override ile `specialAttribute = 7` vermek.

## OBJE HAREKET ETTİRMENİN KATMANLARI

Bir dünya objesini oynatmak isterken sırayla doğrula:

1. **Sahiplik** — `SetEntityAsMissionEntity` + `NetworkRequestControlOfEntity`.
   Kontrol alınmadan `FreezeEntityPosition` / `SetEntityCoords` /
   `SetEntityHeading` **sessizce yok sayılır**. En sık atlanan adım budur.
2. **Fizik** — `FreezeEntityPosition(false)` tek başına yetmez; obje
   "hareketsiz" işaretliyse `SetEntityDynamic(true)` + `ActivatePhysics()` gerekir.
3. **Menteşe** — kapı sistemi ancak `specialAttribute` uygunsa devreye girer.
4. **Senkron** — harita objeleri networked DEĞİLDİR. Durum server'da tutulup
   her client kendi kopyasına uygular; yoksa sadece sende hareket eder.

## ANİMASYON — temel kurallar

- Animasyon **her zaman** dictionary + clip çiftidir. Biri eksikse oynamaz.
- Kalıp: `RequestAnimDict(dict)` → `HasAnimDictLoaded(dict)` bekle →
  `TaskPlayAnim(ped, dict, clip, ...)`.
- İndekste yoksa **o animasyon yoktur**. Benzer isim uydurma; kullanıcıya
  "bulamadım" de ve arama terimini değiştirerek tekrar dene.
- **Süreyi tahmin etme.** `.ycd`'den gelen gerçek süre indekste var:
  `anim <dict> --dict` çıktısındaki saniye değeri. Progress bar / `Wait()`
  süresini oradan al.

## PROP + KARAKTER BİRLİKTE (senkron sahne)

"Adam çantayı önüne alıp para dolduruyor" tipi sahneler tek bir ped
animasyonu değildir: **ped ve prop ayrı kliplerdir, senkron oynatılır.**

Doğru klip çiftini bulmak:

```bash
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" anim <dict> --dict
```

Çıktı klipleri **süreye göre gruplar**. Bir grupta *aynı süre ama farklı
kemik sayısı* varsa o bir ped+prop çiftidir — araç bunu işaretler:

```
[47.967s]  <-- ayni sure, FARKLI iskelet: ped + prop cifti
  bag_grab              47.967s  kemik=72    <- ped
  cart_cash_dissapear   47.967s  kemik=96    <- prop (para arabası)
```

Sadece "aynı süre" yetmez: `_female` / `_suit` / `_no_armour` varyantları da
aynı süredir ama hepsi ped'dir. Ayırt eden **kemik sayısının farklı olması**.

Oynatma zinciri (native imzaları doğrulandı):

```lua
local scene = NetworkCreateSynchronisedScene(x, y, z, rx, ry, rz, 2, true, false, 1.0, 0.0, 1.0)
NetworkAddPedToSynchronisedScene(ped, scene, dict, pedClip, 4.0, -8.0, 0, 0, 1000.0, 0)
NetworkAddEntityToSynchronisedScene(propObj, scene, dict, propClip, 4.0, -8.0, 0)
NetworkStartSynchronisedScene(scene)
```

Tek oyuncu / lokal sahne için `CreateSynchronizedScene` + `TaskSynchronizedScene`
+ `PlaySynchronizedEntityAnim(entity, scene, animation, propName, ...)`.

## BİR KLİP HANGİ MODELDE OYNAR — kemik tag eşleşmesi

Klip kaç kemik animasyonluyor bilmek yetmez; **hangi kemik tag'lerini**
hedeflediği modeli tek başına belirler.

```bash
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" clipfit <dict> <clip>
```

Gerçek vaka: `bank_vault_door_opens` klibi 8 iz taşıyor ama haritadaki kasa
kapısı `v_ilev_gb_vauldr` tek kemikli. `clipfit` klibin tag'lerini çıkardı
(`0, 10596, 50607`) ve 72.364 kemikli model içinde tek eşleşme buldu:

```
hei_prop_heist_sec_door · 3 kemik
   Prop_Heist_Sec_Door_Root    tag=0
   Prop_Heist_Sec_Door_Main    tag=50607
   Prop_Heist_Sec_Door_Handle  tag=10596
```

bbMin/bbMax'i haritadaki kapıyla **birebir aynı** — yani animasyonlu ikizi.

**PROP SWAP deseni:** harita objesi animasyonlanamıyorsa ama aynı bbox'lı
kemikli bir ikizi varsa; harita objesini gizle, ikizi aynı koordinata spawn
et, animasyonu onda oynat, bitince geri al. Rockstar'ın heist'lerde yaptığı da
budur. `clipfit` + bbox karşılaştırması bu ikizi bulmanın yoludur.

## ARCHETYPE YANLIŞ TANIMLIYSA — ytyp override

Bir obje ytyp'te yanlış tanımlıysa (kapı olması gereken şey
`specialAttribute=0`) doğru çözüm script değil, ytyp düzeltmesidir:

```bash
powershell -File "${CLAUDE_PLUGIN_ROOT}/scripts/make_ytyp_override.ps1" `
    -Models v_ilev_gb_teldr -SpecialAttribute 7 `
    -YtypName <benzersiz_ad> -OutFile "<resource>\stream\<ad>.ytyp"
```

Kaynak archetype'ı RPF'ten okur, **bütün alanları birebir kopyalar**, sadece
istenen değeri değiştirir — uydurma alan olmaz. Çıktı `stream/` klasörüne
konur ve fxmanifest'te `data_file 'DLC_ITYP_REQUEST'` ile bildirilir.

Uyarı: aynı archetype'ı kullanan **her yer** etkilenir (Fleeca örneğinde 6
şube). Etki alanını `assetdb.py where <model>` ile önceden gör.

## PROP İSKELETİ (kemik)

Prop'u bir şeye takmak, kemiğinden offset vermek veya `PlayEntityAnim` ile
oynatmak için modelin **iskeleti olmalı**:

```bash
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" bones <model>
```

- İskeleti yoksa araç bunu açıkça söyler → `PlayEntityAnim` ve bone-index
  işlemleri o modelde **çalışmaz**, boşuna deneme.
- Varsa kemik **adı** (`GetEntityBoneIndexByName`) ve **tag**'i listelenir;
  `AttachEntityToEntity`'ye verilecek boneIndex buradan çıkar.

## EXPRESSION (.yed) — prosedürel / çarpışmaya tepki

`.yed` = Expression Dictionary. Klip oynatmadan, **kemikleri kural ile**
hareket ettirir: yay (spring), lookAt, çarpışma/hız tepkisi. Sallanan
antenler, esneyen kumaş, çarpınca titreyen parçalar bu katmandandır.

```bash
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" expr <terim>
```

`yay=N` (spring) değeri > 0 olan expression'lar fiziksel tepki üretir.
Expression modele bağlıdır; script'ten klip gibi "oynatılmaz" — model/ytyp
tarafında tanımlıdır. Bir prop'un çarpışmayla tepki vermesi isteniyorsa
çözüm script değil, modelin expression'ıdır.

Bytecode'u çözümlemek (hangi giriş kanalı hangi kemiği sürüyor):

```bash
powershell -File "${CLAUDE_PLUGIN_ROOT}/scripts/res_to_xml.ps1" -Path <dosya.yed>
python "${CLAUDE_PLUGIN_ROOT}/scripts/yed_expr.py" channels <dosya.yed.xml> --expr <ad>
```

## PED KEMİĞİ VE YÜZ ANİMASYONU

Ped iskeleti, yüz ifadesi, rigging ya da kemikle iş yapılacaksa **önce**:
`references/ped-kemik-yuz-rigging.md` — 128 kemik, rest pose, 35 yüz
kanalının ölçülmüş haritası, 20 maddelik tuzak kataloğu. Komut: `/ped`.

Kod yazmadan bilinmesi gereken üç şey (hepsi ölçümle doğrulandı):

1. **Yüz animasyonu `FB_` kemiklerini doğrudan sürmez.** `facials@*.ycd`
   soyut float kanalları oynatır (Track 22 float / Track 25 vector3);
   kanalları kemik dönüşüne çeviren şey **`.yed` expression**'dır.
   Genel ped için doğru tüketici `ambient.yed → facial` (33/34 track uyumu),
   `mp_freemode` değil (27/34) — yanlış eşleme sessizce yanlış yüz üretir.
2. **128 kemiğin sadece 65'i klip tarafından keyframe'lenir.** Kalan 63'ü
   (`MH_ RB_ SM_ EO_ SPR_ FB_`) expression ürünü.
3. **Gövde klipleri scale yazmaz, uzuvlara translation da yazmaz.**
   `SKEL_Pelvis` / `SKEL_Spine_Root` rest'te ±90° Y çeviricidir —
   keyframe koymak tüm hiyerarşiyi yatırır.

```bash
python "${CLAUDE_PLUGIN_ROOT}/scripts/pedrig.py" bone mp_m_freemode_01 SKEL_L_Calf
python "${CLAUDE_PLUGIN_ROOT}/scripts/pedrig.py" facial mp_m_freemode_01
```

Kalıcı yüz ifadesi `SetFacialIdleAnimOverride`; `PlayFacialAnim` tek
seferliktir. **`sad` mood'u yoktur** → `mood_sulk_1` / `mood_injured_1`.

## RETARGET (Sketchfab/Mixamo → GTA) VE WEIGHT PAINTING

Yabancı iskeletli animasyonu GTA ped'ine taşımak, Blender'da animasyon
üretmek, skinning/weight paint yapmak gerekiyorsa **önce**:
`references/ped-retarget-weightpaint.md`. Komut: `/retarget`.
Araç: `scripts/blender_retarget_gta.py` (53 kemikte test edildi).

Ölçülmüş dört gerçek:

1. **GTA rest pose'u T-pose DEĞİL, A-pose** — üst kol yataydan 57° aşağı;
   Mixamo 0°. Kapatılmazsa kollar 144°'ye kadar sapar. Doğru yöntem
   `align` (roll farkını temizler + mutlak uzuv yönünü korur); naive dünya
   eşleme her kemikte roll farkı kadar (deneyde 30°) hata verir.
2. **GTA lokomosyonu yerinde üretilir** — koşuda ayak anim-uzayı
   sürüklenmesi 0.000 m, tüm yol (3.656 m / 1.73 s) ayrı **mover track**'inde
   (`SKEL_ROOT.animation_tracks_mover_location`). Mixamo'da yol hips'e
   gömülü → taşınmazsa ped yerinde kayar ya da iki kat hareket eder.
3. **Sollumz rig'inde kemik yönleri anatomik DEĞİL** — hepsi 0.05 m,
   `use_connect=False`; kolda `bone.vector` ile gerçek yön arası 56° fark.
   Yön için `head → çocuğun head'i` kullan. Ayrıca sahne 24 fps'te kalır,
   GTA 30 fps → sessiz %25 zamanlama hatası.
4. **Weight paint**: vertex başına en fazla **4 kemik**, toplam tam **1.0**,
   ağırlıksız vertex yok, ağırlıklar **1/255 adımlı** (0.004 altı kaybolur).
   `MH_`/`RB_` helper kemikleri **skinlenir ama animasyonla sürülmez** —
   retarget'ta bu katman olmadığı için dirsek/diz şişmesi kaybolur.

`_000` / `_045` tuzağı: `.ydd`'nin yüz kemikleri `FB_Jaw_000`, `.yft`'nin
`FB_Jaw_045` — **aynı tag, farklı isim** (21 kemik). Oyunda tag ile bağlanır,
Blender'da isimle → yanlış eşleşirse yüz hiç deforme olmaz, hata da vermez.

### ⛔ Custom iskelet YASAK — insan dışı yaratık rig'i

GTA V motoru yalnızca kendi ped iskeletini kabul eder. Sketchfab'den gelen
yaratığın **kendi armature'ı kullanılamaz**; gerçek `.yft` iskeleti içe alınıp
kemikler yaratığın anatomisine **taşınır**. Serbest olan tek şey **konum ve
boy**; **ad, tag, parent, sayı (128)** birebir korunur. İhlal Blender'da hiçbir
uyarı üretmez — oyunda ped hiç yüklenmez.

Referans §11 + `scripts/blender_creature_rig.py`
(`snapshot / place_chain / move_block / park / skin / verify`).
Sorgu: `pedrig.py animals`. Ölçülmüş noktalar:

- **ÖNCE PED SEÇ.** Oyunda 44 hayvan pedi var, her birinin kendi iskeleti
  **ve animasyon seti**. Dört ayaklıya insan pedi giydirmek çalışır ama oyunda
  insan yürüyüşü oynar. Dört ayaklıların hepsi aynı kalıpta (2×6, 2×5, kuyruk
  5, boyun 3); fark **klip sayısı** → `a_c_rottweiler` **382 klip / 27 sözlük**
  (retriever 113, cougar 80). Yılan gibi tek uzun zincir için `a_c_whalegrey`
  (10 kemik). Ölçüldü: aynı ağırlıklandırmayla gerilme insan iskeletinde
  %1.19, dört ayaklıda **%0.094** — kazanç ped seçiminden geliyor.
- **Ped −Y'ye bakar** (`SKEL_Head` y=−0.286, `SKEL_Tail_05` y=+0.509). Model
  ters bakıyorsa mesh 180° Z çevrilir; atlanırsa doğrulamalar geçer, ped
  oyunda geri geri yürür.
- **Uzuv eşlemesi topolojik**: fazladan bacak dört ayaklıda
  `MH_L/R_ShoulderBladeRoot→ShoulderBlade`'e asılır — klavikulanın çocuğu ve
  expression tarafından klavikula dönüşünden sürülür, yani keyframe kabul
  etmez. Gerçek bir yaratıkta 82 kemiğin 42'si uzuvlara, 29'u kafa bloğuna.
- **Kafa zincir değil, katı blok** (`move_block()`, sapma 3e-8 m); geometri
  ona vertex bazlı ağırlık maskesiyle bağlanır (`skin(force=...)`) — bileşen
  bazlı zorlama çalışmaz, kafa gövdeyle aynı bağlı bileşendedir.
- **Export (§12):** vanilla ped bütçesi 11.303 üçgen — Sketchfab modeli
  321.562'ydi; çapı 5 cm altı parçaları at + decimate → 20.000.
  **Decimate 4-etki kuralını bozar**, sonra yeniden oturt. `.yft` sadece
  iskelet+fizik olmalı (mesh'i geçici yer tutucuyla değiştir: 1.5 MB → 23.7 KB).
  Doku **gömülü + DDS** ise `.ytd` gerekmez (Sollumz `.ytd` üretemez).
  **Ped `.yft`'i FİZİKSİZ gönderilmeli** — Sollumz `ArticulatedBody`
  yazmadığı için fizik gruplu ped oyunu çökertir (ölçüldü, export 0 uyarı
  vermişti); XML'den `<Physics>` çıkarıp `xml_to_res.ps1` ile derle.
  Elle fizik yapılırsa: kapsülde silindir kısmı **0 olamaz**, kemik bağı
  **`COPY_TRANSFORMS` constraint**'tir, isim yetmez.
- **Kullanılmayan kemik silinmez, kısaltılır** (~12 mm) — imza korunur,
  ağırlık filtresi (`length > 0.05`) onları mesh dışında bırakır.
- **N kemiklik zincir N+1 nokta ister**; eksikte son kemik 0.02 m'de kalıp
  **0 vertex** sürer. `verify()` bunu `olu_kemik` diye yakalar.
- **Parçalı mesh'te düz mesafe ağırlığı yırtar**: 10.021 bileşenli yaratıkta
  kenarların **%5.9**'u 2 katı aşıyordu; çapı 0.80 m altındaki her bileşeni
  tek kemiğe katı bağlayıp kalanına Laplacian düzeltme → **%1.2**. Blender'ın
  `ARMATURE_AUTO`'su bu mesh'te *"Bone Heat Weighting: failed"* verir.

## PED ANİMASYON DAVRANIŞI + SIFIRDAN ANİMASYON ÜRETİMİ

Tüm oyun ped'leri üzerinde ölçülmüş davranış verisi ve yeni animasyon
üretme hattı: `references/ped-animasyon-davranis-ve-uretim.md`.
Sorgu: `pedrig.py families` · `pedrig.py compat <ped>` · `assetdb.py propanim <prop>`

- **1070 humanoid ped, 158 rig ailesi.** 98 kemikli ambient rig, 128
  kemikli freemode rig'in **tam alt kümesi** (fark: 30 helper kemik).
  Animasyonu **98-kemik ambient sete yaz**: %64.7 ped'de sorunsuz oynar;
  freemode'a özel yazarsan yalnız %14.4.
- **İki ayrı yüz rig sistemi var**: ambient/freemode 21 kemikli `FB_`
  (rotasyon+scale ile sürülür), hikâye karakterleri 156 kemikli `FACIAL_`
  (**translasyonla** sürülür; rotasyon 10°'de 100 mm sıçratır).
- **Eşya animasyonu tespiti: klip adı = prop model adı** — 1407 prop,
  53.181 klip. Melee klipleri `AnimationList`: 44 gövde + 32 yüz kanalı.
- **Sollumz export tuzakları:** `Animation.target_id` **armature DATA-BLOCK**
  olmalı (Object verilirse 0 kanal yazar); **`.ycd` format sisteminin dışında**
  olduğu için `target_formats` ne olursa olsun XML çıkar (diğer 8 uzantıda
  `NATIVE` gerçekten binary yazar — ayrıntı `ytyp-ymap-bayraklari.md` §7);
  **çok klipli sözlükte klipler birbirini EZER**
  (Sollumz `<Hash>` yazmaz) → `fix_ycd_xml.py` ile hash enjekte et,
  `xml_to_ycd.ps1` çıktısındaki `klip=N` sayısını doğrula.
- **ytyp/ymap bayrakları, `specialAttribute`, extension tipleri, LOD zinciri,
  decal/shader, collision katmanları, Gen8/Gen9:**
  → `references/ytyp-ymap-bayraklari.md`. Sihirli sayılar orada çözülü:
  `1572872` = LOD in Parented YMAP + Cast Static + Cast Dynamic.
- **Neyin doğrulandığı, neyin DOĞRULANMADIĞI:**
  → `references/oynatma-listesi-bulgular.md` (bu turun ham bulguları)
  → **`YETENEK-DURUMU.md`** (plugin kökü) — her yeteneğin güven oranı,
  açık maddeler, araştırılmamış alanlar, önerilen sıra. **Bir tabloya
  dayanarak iş yapmadan önce oradaki güven oranına bak.**
- Poz kurarken Euler verme: `aim()` (yön) ve `ik2()` (konum) kullan —
  Sollumz rig'inde kemik eksenleri anatomik değil.
- **Yüz pozlarken `blender_facepose.py`** kullan: Jacobian ölçer
  (`local = J⁻¹·istenen_dünya`), yüzey profilini takip eder, rol tablosuyla
  dağıtır. Kök kemikler (`UpperLipRoot`/`LowerLipRoot`) sürülmezse dudak
  bütün olarak hareket etmez — kendi derileri olmadığı için naif ölçüm
  onları atlar.
- **Hedef görsele bakıp söz vermeden `fp.topology()` çalıştır.** Freemode
  kafası **1514 vertex**, ortalama kenar **11.2 mm**. Aşırı ağız
  deformasyonu kemik pozlayarak elde edilemez; kemik eklemek de çözmez
  (denendi — eklenen kemik o bölgede 2 vertex bulabildi). Ötesi mesh
  düzenleme işidir.
- Kafa mesh'ini vertex sayısıyla seçme: **dişler (4517) kafadan (1514)
  büyüktür**, `max()` yanlış mesh'i seçer ve ölçüm sessizce 0 döner.

## KOORDİNAT — config'e sabit yazmadan önce

Bir prop/kapı için koordinat gerekiyorsa **oyuncudan isteme, indeksten al**:

```bash
python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" where v_ilev_gb_teldr
# -> 6 benzersiz konum (6 Fleeca şubesi)
```

İki şeye dikkat:

1. **Aynı prop haritada birden fazla yerde olabilir.** Fleeca vezne kapısı 6
   şubede var. Config'i tek koordinata göre kurma; ya hepsini yaz ya da
   oyuncunun etrafında ara.
2. **`[mlo]` işaretli konumlar bir iç mekâna aittir** — o prop ancak o MLO
   yüklüyken vardır. `near` çıktısındaki köşeli parantez hangi MLO olduğunu
   söyler.

## COLLISION'IN ANİMASYONU TAKİP ETMESİ

**Tam reçete: `references/yed-collision-animasyon.md`** — .yft + .yed + ytyp
extension + .ycd + Lua zinciri. Çalışan yöntem odur; aşağıdaki fragment
kuralları o zincirin 1. adımıdır.

## FRAGMENT ÜRETİMİ (zincirin 1. adımı)

Bir prop'un çarpışması kemik animasyonuyla birlikte hareket etsin istiyorsan
tek yol **fragment**tir. Denenip elenen yollar:

- `ASSET_TYPE_DRAWABLE`: tek statik bound, entity transform'una bağlı.
  Kemik animasyonu sadece görseli oynatır, çarpışma yerinde kalır.
- **YED / expression**: ÇALIŞAN YOL BUDUR. Tam reçete:
  `references/yed-collision-animasyon.md`

  > ⚠️ Bu satırda önceden **"YED ile collision animasyonu diye bir şey yok"**
  > yazıyordu. YANLIŞTI ve saatlerce yanlış yöne gidilmesine sebep oldu.
  > Hatanın kaynağı: CodeWalker ile `.yed` açılıp `ExprMap.Count == 0`
  > görülmesi ve "dosya boş" sanılması. Gerçek şu ki **CodeWalker
  > expression bytecode'unu (Streams) YAZAMAZ, sadece okuyabilir** — ve bu
  > kullanımda `Streams` zaten boştur, iş `Tracks` tarafında döner.
  > Yani ölçülen şey aracın sınırıydı, dosyanın içeriği değil.
  > **Bir aracın bir şeyi göstermemesi, o şeyin yok olduğu anlamına gelmez.**

### Sollumz'da fragment kurma — bound'u kemiğe bağlayan şey

`parent_bone` **DEĞİL**, isim eşleşmesi de **DEĞİL**. Sollumz bağı
`COPY_TRANSFORMS` constraint'inden okur (`tools/blenderhelper.py`,
`get_child_of_bone`). Constraint yoksa `does_bone_have_collision` false
döner, kemik sessizce atlanır ve export **uyarı bile vermeden**
`PhysicsLODGroup`'u boş bırakır — dosya üretilir ama işe yaramaz.

Her collision objesi için:

```python
c = col_obj.constraints.new("COPY_TRANSFORMS")
c.target = frag_armature_obj
c.subtarget = "KemikAdi"
c.mix_mode = "BEFORE_FULL"   # set_child_of_constraint_space ile aynı
c.target_space = "POSE"
c.owner_space = "LOCAL"
```

Ayrıca:
- `bone.sollumz_use_physics = True` **sadece** collision'ı olan kemikte.
- `col_obj.child_properties.mass` varsayılan 0; 0 bırakılırsa archetype
  kütlesi de 0 olur. Bound hacmine göre dağıt.
- Kırılmasın istiyorsan `bone.group_properties.strength = -1`.
- Bound composite fragment armature'ının **doğrudan** çocuğu olmalı,
  drawable'ın altında değil.
- Kemik başına birden fazla bound serbesttir (`child_cols` kemik adına göre
  gruplanır).

### EN ÇOK VAKIT KAYBETTİREN TUZAK: kök grup

`parentIdx = 255` olan grup **entity gövdesidir**. Onun çarpışması entity
transformuna kaynaklıdır ve **kemiği takip etmez**. Tek gruplu bir fragment
üretirsen o grup zorunlu olarak kök olur; export kusursuz görünür,
`PhysicsLODGroup` dolu çıkar, ama oyunda animasyon oynar ve collision
yerinde kalır — yani hiçbir şey kazanmamış olursun.

**En az iki grup gerekir:**

```
grup[0]  kök kemik (tag 0)   parentIdx=255   -> SABIT taban/menteşe
grup[1]  hareketli kemik      parentIdx=0     -> DÖNEN parça (kanat, kapak)
```

Hareket eden parça **çocuk** grupta olmalı. Kök gruba da mutlaka bir
collision ver (yoksa Sollumz o kemiği atlar ve tek gruba düşersin) —
dönme ekseni üzerindeki küçük parçalar bu iş için idealdir, döndüklerinde
konumları zaten değişmez.

Doğrulama: `Groups` listesinde parentIdx=255 olanın boneTag'i **0**
olmalı; hareketli kemiğin tag'i çocuk grupta görünmeli.

### physicsDictionary asla 0 bırakılmaz

Collision `.ydr`/`.yft` içine gömülü olsa bile oyun onu **archetype'ın
physicsDictionary'sinden** bulur. 0 verirsen model görünür ama içinden
geçilir. Vanilla arşivinde tek bir kapı prop'unda bile 0 yoktur
(`v_ilev_gb_teldr` → 2110158618, `prop_ld_garaged_01` → 427433450).

Kendi prop'umuzda doğrusu **kendi ad hash'i**: `-PhysicsDictSelf`.
`textureDictionary` ise dokular gömülüyse 0 kalabilir.

### ytyp tarafı

`assetType` bir **property**dir (alan değil), tipi
`rage__fwArchetypeDef__eAssetType`. Fragment için:

- `assetType = ASSET_TYPE_FRAGMENT` — drawable kalırsa oyun per-bone
  collision kurmaz, tüm emek boşa gider.
- `physicsDictionary = kendi ad hash'i` (0 değil).
- `textureDictionary = 0` — Sollumz dokuları .yft'ye gömer.
- `specialAttribute = 0` — animasyonu script oynatıyorsa bu bir kapı
  sistemi kapısı değildir.

`make_ytyp_override.ps1 -AssetType ASSET_TYPE_FRAGMENT -ClearDicts
-PhysicsDictSelf` bunu üretir.

### Doğrulama

Export "FINISHED" demesi yeterli değil. `cw_to_xml` ile .yft'yi döküp bak:
`<Physics><LOD1>` altında `<Groups>` dolu mu, `<Children>` sayısı bound
sayısına eşit mi, hepsinin `<BoneTag>`'i doğru kemiğin tag'i mi. Çalışan bir
referans fragment varsa aynı alanları yan yana karşılaştır.

## HARİTADAKİ BİR OBJEYİ DÜZELTMEK (spawn etme — ytyp'yi değiştir)

Haritada duran bir prop yanlış tanımlıysa (kapı olması gereken obje
`specialAttribute=0`), **onu gizleyip yerine kendi kopyanı spawn etme.**
Bu yol test edildi ve çöktü:

- Script'le üretilen obje **harita objesi değildir**. Kapı sistemi kapıyı
  model+konum ile haritada arar, script objesini bulamaz.
- Geriye serbest bir fizik prop'u kalır: oyun içinde kapıya dokununca
  zeminin içinden düştü.
- `FreezeEntityPosition` ile düşmesini durdurursan bu sefer kapı sistemi
  onu itemez — kazandığın bir şey olmaz.

Denenip **elenen** diğer yollar (hepsi oyun içi ölçümle):

- **Kendi ymap'inle yerleştirmek** — MLO İÇ MEKÂNINDA ÇALIŞMAZ. Oda/portal
  sistemi dışarıdan konan entity'yi eler; obje hiç gelmez. Sadece MLO
  dışındaki (sokak, açık alan) proplar için geçerlidir. Referans bir
  resource'un ymap kullanması seni yanıltmasın — **önce o prop'un
  koordinatı MLO içinde mi dışında mı ona bak.**
- **Vanilla prop ytyp'sinde `specialAttribute` düzeltmek**
  (`int_lev_des.ytyp` gibi) — dosya doğru üretildi (348/348 archetype
  birebir) ama oyun içinde kapı fiziği yine yüklenmedi.
- **Vanilla adıyla YENİ bir ytyp eklemek** — oyun ilk tanımı zaten
  kaydettiği için çakışır, tutmaz.

**ÇALIŞAN YOL: MLO'nun kendi entity listesinde model adını değiştirmek.**

Objeyi MLO'nun KENDİSİ yerleştirir: doğru odada, doğru konumda, gizleme /
ymap / spawn olmadan, o MLO haritada kaç yerde varsa hepsinde birden.

```
patch_vanilla_ytyp.ps1 -YtypName v_int_10.ytyp `
  -SwapEntity @('v_ilev_gb_teldr=muto_teldr','v_ilev_gb_vauldr=muto_vauldr') `
  -OutDir <...>\stream
```

- `data_file 'DLC_ITYP_REQUEST'` **EKLENMEZ** — bu bir dosya değişimidir,
  yeni ityp kaydı değil. `stream/` zaten otomatik streamlenir.
  (Kendi yeni ytyp'in için EKLENİR.)
- Script yazdıktan sonra dosyayı geri okuyup imzayı (archetype / oda /
  portal / entity sayıları) kaynakla karşılaştırır ve yeni modelin kaç
  entity'de olduğunu sayar; tutmazsa dosyayı siler. Bozuk ytyp streamlemek
  MLO'yu komple bozar.
- PowerShell'e dizi geçerken `-Command "& script.ps1 -SwapEntity @('a=b','c=d')"`
  kullan; `-File` ile virgüllü liste TEK STRING olarak gider ve sessizce
  uydurma bir ada dönüşür.

Tam adım adım reçete: `references/mlo-obje-degistirme.md`

### Harita objesinin çarpışmasını kaldırma

`SetEntityCollision(mapObj, false, false)` **güvenilir değil** — obje
görünmez olur ama çarpışma yerinde kalır. Belirti: takas ettiğin kapı
açılmış görünür, yine de geçemezsin. Doğrusu `CreateModelHide(x,y,z,r,
hash, true)`; geri almak için `RemoveModelHide` (unutulursa harita objesi
bir daha gelmez). Hide çağrısı handle'ı geçersizleştirir, çarpışmayı
**önce** kapat.

## BİR MODELİN OYNAYAN ANİMASYONU VAR MI?

Prop'un iç parçasını oynatacak klip aramadan önce **böyle bir klip var mı**
diye bak. Model→klip yönü: modelin kemik tag'lerini `skeletons.tsv.gz`'den
al, sonra `clips.tsv.gz`'nin `bones` kolonunda o tag'leri ara.

Örnek sonuç: `hei_prop_heist_deposit_box` (Root=0, Main=28016, b1=57862,
b2=57863) → 312.748 klibin **hiçbiri** iç kemiklere dokunmuyor. Yani
çekmeceyi açan vanilla animasyon yok; kendi klibini üretmen gerekir.
Bunu baştan bilmek, olmayan bir klibi aramakla geçen saatleri önler.

### Kök-kemik klipleri donmuş objede çalışmaz

Bir klip sadece tag 0'ı oynatıyorsa objenin **kendisini** taşır, iç
parçasını değil. `FreezeEntityPosition(obj, true)` bunu tamamen engeller:
klip oynar, `PlayEntityAnim` true döner, ekranda hiçbir şey olmaz.
Kök hareketli klip oynatmadan önce dondurmayı kaldır.


## MLO İÇİNE KENDİ PROP'UNU ÜRETME — TAM HAT

Kendi modelini bir iç mekâna kalıcı olarak koymak (kapı değiştirmek, yeni
obje eklemek, animasyonlu yapmak) için uçtan uca reçete ve **tekrarlanmaması
gereken hatalar listesi**:

**`references/mlo-prop-uretim-hatti.md`**

Kapsam: MLO içi/dışı ayrımı · entity swap · entity ekleme (oda ataması
şart) · fragment kök grup tuzağı · statik bit · kendi `.ycd`'n
(Sollumz'un yazmadığı hash alanları) · ytyp Expression extension ·
ped/prop klip ayrımı · 19 maddelik hata kataloğu.

## OBJENİN ÜSTÜNDE CANLI EKRAN (DUI PANEL)

ATM tuş takımı, kasa terminali, kamera monitörü, laptop, keypad — objenin
üstünde **gerçek HTML/JS çalışan, tıklanabilir bir ekran**. Tam reçete,
ölçülmüş değerler ve 13 maddelik tuzak kataloğu:

**`references/3dnui-dui-panel.md`** · komut: `/3dnui`

Kod yazmadan bilinmesi gereken beş şey:

- **Üç render yolu vardır ve seçimi veri belirler.** Modelin gerçek ekran
  dokusu varsa `AddReplaceTexture` (en gerçekçi), yoksa dünya uzayında quad
  (`CreatePanel`), hareketli entity'de `AttachPanelToEntity`. Hangisi
  olduğunu **sor, deneme**: `screentex.ps1 -Model <model>`.
- **`AddReplaceTexture` materyal bazında ve GLOBAL'dir.** O istemcide o
  dokuyu kullanan bütün objeler değişir. Bankada 3 ATM varsa üçü de aynı
  sayfayı gösterir → farklı içerik gerekiyorsa bu yol yanlıştır.
- **Ekran = `emissive*` shader ve doku neredeyse her zaman modele GÖMÜLÜDÜR**
  → `origTxd` = **model adının kendisi**. Ölçüldü: `prop_atm_01` →
  `prop_cashpoint_screen`, `prop_laptop_lester` → `prop_lester_screen`,
  `prop_tv_flat_01` → `script_rt_tvscreen`. **ytyp'deki `textureDict` alanı
  ekran sözlüğü DEĞİLDİR** — oraya bakıp `origTxd` yazma.
- **Keypad'lerin ve CCTV kameralarının ekran dokusu YOKTUR** (üç keypad
  prop'unda ölçüldü; `hei_prop_hei_keypad_01`'de gömülü doku sayısı 0).
  Keypad UI'si ancak dünya quad'ı ile yapılır.
- **DUI client-only ve senkronize DEĞİLDİR.** Panel bir dünya objesi değil;
  her istemci kendi panelini kurar. Durum sunucuda tutulur, `SendMessage` ile
  yansıtılır. **Şifre/kod karşılaştırması sayfada değil sunucuda yapılır** —
  sayfanın JS'i okunabilir, mesajı taklit edilebilir.

Panel kurarken: `faceCamera=false` + `frontOnly=true` + normale **dik hale
getirilmiş** `up` (ikisi birden verilmezse basis önbelleği açılmaz ve roll
desteklenmez), `resW:resH` panel oranıyla aynı, URL dosyası tüketici kaynağın
`files { }` listesinde.

## KENDİ SİLAHINI EKLEME (ADD-ON WEAPON)

Kendi 3D silah modelini oyuna sokmak (iskelet eşleme, bileşen/şarjör, meta
üretimi, kaynak yapısı) gerekiyorsa **önce**:

**`references/addon-silah-uretimi.md`** · komut: `/weapon`

Blender açmadan bilinmesi gereken dört şey:

- **Add-on silah vanilla iskeletin üzerine kurulur.** Serbest olan tek şey
  kemiklerin **konumu**; ad ve tag korunur. Referans silahta olmayan
  eklenti yuvası (`WAPScop`, `WAPSupp`...) sonradan eklenemez — şablonu
  buna göre seç. Önce sorgula: `assetdb.py bones <referans_model>`.
- **⛔ `AAPClip` ile `WAPClip` aynı şey değildir.** [ölçüm: 868 model —
  410 ana silah, 458 tek kemikli bileşen] Kural: **modelin kökü `AAP*`,
  silahtaki yuva `WAP*`**. `WAPClip` (tag **1477**) **silahın**
  `.ydr`'sindeki takma noktası; `AAPClip` (tag **0**) **şarjör modelinin**
  kök kemiği — ana silah iskeletinde **hiç geçmez**. Şarjör drawable'ının
  tek vertex group'u `AAPClip` olacak; `WAPClip` yazılırsa şarjör hiç
  bağlanmaz. Aynı kalıp: `AAPSupp`↔`WAPSupp`, `AAPScop`↔`WAPScop`,
  `AAPGrip`↔`WAPGrip`.
- **⚠️ `skeletons.tsv.gz`'de silah satırları 4 kez tekrarlar** (aynı model
  birden fazla RPF/DLC kopyasından indekslendi; `w_ar_assaultrifle` = 64
  satır / **16** kemik). Satır sayarak kemik ya da model sınıflandırma
  yapma — `boneCount` alanını kullan veya `(index, ad, tag)` ile deduplike
  et. Bu atlanırsa 458 bileşen modeli "çok kemikli ana silah" sayılır.
  `assetdb.py bones` **artık deduplike ediyor**, her kemik bir kez basılır;
  dosyayı kendin okuyorsan tuzak yerinde duruyor.
- **Kemik tag'leri sabittir** [ölçüm]: `Gun_Root 0 · Gun_Main_Bone 3360 ·
  Gun_Trigger_Pr 56099 · Gun_Cock1 39439 · Gun_Muzzle 17833 · WAPClip 1477 ·
  WAPSupp 4230 · WAPScop 64805`. Tek istisna kural: **kök kemiğin tag'i
  her zaman 0'dır** (`Gun_GripR` normalde 18308'dir ama kendi modelinin
  kökü olduğunda 0 görünür). Vertex group adları kemik adlarıyla
  **birebir** aynı olmalı, yoksa o parça sessizce hiç sürülmez.
- **⛔ Silahta weight painting YOKTUR, rijit atama vardır.** [ölçüm:
  `w_ar_assaultrifle.ydr` çözüldü] 2556 vertex'in **%100'ü tam 1 kemiğe**
  bağlı, ağırlık toplamı her vertex'te tam **255 (1.0)**, 2+ kemik etkileyen
  vertex **0**, ağırlıksız vertex **0**. Ped'in "4 kemiğe harmanla"
  mantığını silaha taşıma — metal esnemez, parçalar katı döner. Blender'da
  `Assign` **Weight = 1.000** ile yapılır.
- **Kaynak beş `data_file` bildirir** [oyun konsolundan okundu]:
  `WEAPONINFO_FILE`→`meta/weapons.meta`, `WEAPON_METADATA_FILE`→
  `meta/weaponarchetypes.meta`, `WEAPON_ANIMATIONS_FILE`→
  `meta/weaponanimations.meta`, `PED_PERSONALITY_FILE`→
  `meta/pedpersonality.meta`, `WEAPONCOMPONENTSINFO_FILE`→
  `meta/components/<COMPONENT>/weaponcomponents.meta`. **Her bileşen kendi
  klasörünü ve kendi satırını ister**; tek satır bırakmak diğer bileşenleri
  sessizce düşürür.

Meta üretimi **vWeaponsToolkit 1.0.3** ile yapılır (sonraki build'ler bozuk).
Test: `restart <kaynak>` + `str_requestFlush` (istemci konsolu, canary build)
— **silahı önce elden bırak**; tutmazsa sunucudan çıkıp yeniden bağlan.

İki nokta daha, ikisi de sessiz arıza kaynağı:

- **⛔ `weaponcomponents.meta` → `<AttachBone>` alanına `AAP*` yazılır,
  `WAP*` değil.** [ölçüm: 4 vanilla dosyada 318 girdi — 318'i `AAP*`,
  sıfırı `WAP*`] Alan silahtaki yuvayı değil, **bileşen modelinin kendi
  kök kemiğini** gösterir. İskelet tarafındaki `WAP*`/`AAP*` ayrımıyla
  karıştırma.
- **⛔ Base **ve** `_hi` modelin ikisi de gerekir.** Kemik taşındığında
  **ikisinde de aynı yere** taşınır ve taşınan kemiğin flag'leri tam iki
  tane olur: `LimitRotation` + `LimitTranslation`. Yalnız biri
  düzeltilirse silah LOD değişiminde zıplar. Referans silahta kaç vertex
  group varsa senin modelinde de o kadar olmalı — karşılığı olmayanı
  **boş olarak yarat**, silme.

## SİLAH GÖRSELLERİ: GLOW / WIREFRAME / UV ANİMASYONLU SKIN

Çalışan bir silahın üstüne görsel katman (parlayan bölge, tel kafes,
zincir/charm, **akan doku**) eklenecekse:

**`references/silah-gorsel-ve-uv-animasyon.md`** · komut: `/weaponfx`

- **Glow** = `normal_spec_emissive` shader + `emissiveMultiplier`.
  ⛔ İki sessiz tuzak: ana glow dokusu **`.ytd`'ye eklenmezse bölge beyaz
  kalır**, ve parlama **OpenIV'de ve gündüz görünmez** — gece, oyun içinde
  test edilir. Bu ikisi yüzünden çalışan kurulum defalarca bozuk sanılıyor.
- **Zincir / charm** birleştirildikten sonra **tek drawable**'dır —
  ayrı bileşen ve meta gerektirmez. Charm'da `Rotation X = 90` şart.
- **UV animasyonlu skin** ayrı model + `.ycd` + `.ytyp` + bileşen ister.
  Üç kritik nokta: ⛔ **`Target ID` MATERYALDİR** (armature değil — ped
  alışkanlığı en sık hata), ⛔ klip **`Name` = `<hash>.clip`** (ek yoksa
  sessizce hiç oynamaz), ⛔ archetype **`Flags = 525312`** = 1024
  (`UV anims`) + 524288 (`Auto Start Anim`) — `Has Anim (YCD)` **başka
  bir bayraktır**. İlk kontrol noktası CodeWalker: skin orada animasyonlu
  değilse oyunda da değildir.

## IŞIK — oku, çöz, geri yaz (`/light`)

Işıkla ilgili **her** iş burada başlar.

```bash
assetdb.py light prop_lamp.ydr              # oku ve ÇÖZ (sihirli sayıları aç)
assetdb.py light prop_lamp.ydr --table      # 72.539 vanilla ışığın ölçülmüş bandı
assetdb.py light prop_lamp.ydr --apply duzenleme.json
assetdb.py light prop_lamp.ydr --set 0.Intensity=8 --set 0.ConeOuterAngle=35
assetdb.py light prop_lamp.ydr --add | --remove 1
assetdb.py cycle w_clear --hour 20          # hava cycle'ının taban katmanı
assetdb.py timecycle int_hospital_dark      # odanın modifier'ı
```

Geri yazma `res_to_xml → XML → xml_to_res` turudur ve her yazma **geri
okunarak** doğrulanır. Değer önerirken `--table`'nun ölçülmüş bandını kullan
(alan başına p05 / medyan / p95); katman kurulu değilse aralık **uydurma**.

Ölçülmüş, tahmin edilmemiş:

- **Işık kemiğe bağlıdır.** `prop_worklight_01a`'da `BoneId 41615` zincirde
  **1.737 m** yukarıdadır; kemik zinciri uygulanmazsa ışık yerde durur.
  `Position/Direction/Tangent` **kemik uzayındadır**, model orijininde değil.
- **`TimeFlags` bir sayı değil saat kümesidir.** `14680095` = 21:00–05:00;
  saat 20'de ışık **yanmaz**. "Yanmıyor" şikâyetinde ilk bakılacak yer budur —
  çoğu vakada ışık sağlamdır, saat yanlıştır.
- **Boyut geçerlilik ölçütü değildir** (RSC7 zlib'dir): 15.056 → 15.904 bayt
  aynı içeriktir. Tek ölçüt **geri okumadır**; `--apply` her zaman geri
  okur ve ışık sayısı tutmuyorsa yazmaz.

Tam matematik + timecycle üç katmanı: `references/light-matematigi-ve-onizleme.md`

## SAHNE — çoklu obje, klip çözümü, ymap (`/scene`)

```bash
assetdb.py scene --file s.json --add a.ydr --add b.yft
assetdb.py scene --file s.json --anim "kapi.ycd:kapi_ac"
assetdb.py scene --file s.json                   # özet + klip doğrulaması
assetdb.py scene --file s.json --ymap out.ymap   # yerleşimi haritaya çıkar
```

`.ycd` okuma `ycd_oku.py`'dedir. Altı kanal tipi desteklenir; ölçülen dağılım
(tek sözlük, 71 animasyon): `StaticQuaternion` 2717 · `StaticFloat` 1246 ·
`StaticVector3` 575 · `CachedQuaternion1` 345 · `QuantizeFloat` 314 ·
`IndirectQuantizeFloat` 2.

Sessiz kıranlar — hepsi ölçüldü:

- **CodeWalker XML'e çevirirken nicemlemeyi ZATEN çözer.** `<Values>` kare kare
  düz float taşır; kendi kuantum çözücünü yazma.
- **`CachedQuaternion` kanal değil İŞARETÇİDİR** — `<QuatIndex>` düşürülen
  bileşeni söyler, eksik olan `sqrt(1−Σ)` ile kurulur, işaret tipin adından
  (`…1` → +, `…2` → −). Doğrulandı: 47.499 karede birim olmayan quaternion **0**,
  en büyük sapma **1.72e-08**.
- **`.//Animations` YANLIŞ düğümü yakalar** — klibin *içindeki* referans
  listesini de alır ve sessizce "kare=1, kemik=0" üretir. Kökün **doğrudan**
  çocuğunu kullan.
- **İki klip tipi var:** `Animation` ve `AnimationList`. Tek biçim varsaymak
  ölçülen dosyada 8 klibin 4'ünü düşürüyordu.
- **Animasyona geometri bağlanacaksa pişirilmez** (`bake=False`); pişirilmiş
  vertex'e animasyon uygulanırsa kemik dönüşümü iki kez girer. Doğrulandı:
  bind pozunda skinning ↔ pişirilmiş sonuç farkı **0.000e+00 m**.
- **`bidx` slot 0 boş olabilir** — bir kapının 330 vertexinin %100'ünde slot 0
  ağırlıksızdı. Körlemesine slot 0 almak bbox'ı **1.096 m** kaydırdı.
- **ymap extent entity birleşiminden**; dışında kalan entity sessizce görünmez.
  `CalcFlags()` çağırma (contentFlags 65→1 düşer), `CalcExtents()` kullanma
  (sıfır kutu bırakır), `CEntityDefs`'i doğrudan yazma (0 entity çıkar).

## YIKIM / KOREOGRAFİLİ HAREKET (RayFire `des_*`)

Bir şeyin **yıkılması**, bir **collision'ın hareket ettirilmesi** ya da
**senaryo benzeri** koreografili bir dizi geçtiğinde önce yol seçilir —
`.yed` zinciri mi (tek prop'un kapağı), RayFire mı (bina çöküyor).
Karıştırmak turlarca kaybettirir; iki reçetenin melezi hiç çalışmaz.

**`references/rayfire-des-uretim.md`** · komut: `/rayfire`

## VANİLLA HARİTA PARÇASINI DEĞİŞTİRME

Yol, prop ya da yapı parçasını kendi modelinle değiştirme. Dört şey
**sessizce** kırar: extent'e dokunmak (haritanın tamamında collision gitti),
LOD zincirinin tamamı + `hei_` ikizleri, dokuların modelde **olmaması**
(yedi vanilla modelin hiçbirinde gömülü doku yok), aynı doku adının farklı
sözlükte farklı içerik taşıması (175 kopyadan 22'si).

**`references/vanilla-parca-degistirme.md`**
Doku sözlüğü indeksi: `scripts/ytd_index.ps1` · `scripts/ytd_ara.ps1`

## GÖRSEL GEREKTİĞİNDE — üretme, öner ve prompt ver

Ekran arka planı, ikon, logo, doku, UI görseli gerektiğinde **rastgele bir
şey üretme ya da yer tutucu uydurma.** Sırayla:

1. Fikri anlat: ne göstereceği, hangi objede duracağı, hangi mesafeden
   okunacağı, ton/renk.
2. Kullanıcıya **hazır bir prompt** ver ve fotoğrafı **kullanıcının**
   üretmesini iste. Prompt en-boy oranını (panelin `resW:resH` oranıyla aynı),
   çözünürlüğü ve arka plan davranışını içersin.
3. Görsel gelene kadar düzeni CSS ile kur, doğru ölçüde boş kutu bırak —
   görsel gelince tek dosya değişir.

## NE ZAMAN YETMEZ

- **Fragment iç yapısı / bone listesi** → .yft incelenmeli.
- **Animasyonun süresi / eventleri** → .ycd incelenmeli.
- **Custom (sunucu) MLO'larının iç yerleşimi** → indeks vanilla MLO'ları
  genişletir; sunucunun kendi MLO'ları için `/asset-build` ile `-ExtraFolders`
  vermek archetype'ları getirir ama iç entity genişletmesi vanilla ymap'lere
  bağlıdır.

Bu durumlarda tahmin yürütme; kullanıcıya CodeWalker'da neye bakması
gerektiğini söyle veya oyun içi ölçüm iste.