fivem-assets · diff

git:20260821.1e83288 to git:20260913.51d9296

175 added, 961 removed. Audit A to A.

---
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" ve ayrıca "decal", "graffiti", "leke", "kan izi", "yüzeye yapıştır", "yansıtma", "projeksiyon", "AddDecal", "decal.sps", "render bucket", "Surface Painter", "alfa maskesi", ve ayrıca "timecycle", "timecycle modifier", "karanlık", "loş", "atmosfer", "TIMECYCLEMOD_FILE", "vignette", "postfx", "hava cycle", ve ayrıca "ışık yanmıyor", "TimeFlags", "Flashiness", "flicker", "titreyen ışık", "emissive panel", "emissiveMultiplier", "tavan lambası", "floresan", "ışık ekle", "koni açısı", ve ayrıca "Child Of", "Copy Transforms", "HAS_ANIM", "AUTOSTART_ANIM", "fragment physics bones", "Sollumz Discord", "Rokoko", "Auto Scale", "Mesh Domain", "Face Corner" geçen her görevde kullan.
+ description: GTA V / FiveM asset data and measured production rules — props, objects, doors, ytyp/ymap/MLO, LOD, grass, flags, particles (.ypt), shader/texture/light/timecycle/decal/parallax, clothing, vehicles; vanilla animation name and bone tag lookup. Use it to look at the real data BEFORE WRITING CODE in any prop, door, map, effect or look task, even if the user does not ask. Triggers — model name (prop_*, v_ilev_*, des_*), door does not open, object does not move, AddDoorToSystem, TaskPlayAnim, anim dict, bone tag, specialAttribute, flag number (1572872), LOD, disappears at distance, fxName, StartParticleFx, light does not turn on, TimeFlags, dark interior, timecycle, decal, parallax, DUI screen, fragment, RayFire destruction, freemode clothing, handling, modkit, Sollumz, CodeWalker. Use for GTA V / FiveM props, doors, maps, particles, materials, lights and clothing.
+ license: MIT
+ compatibility: Python 3.10+. Windows PowerShell 5.1 runs the .ps1 build scripts. Data layers are built from your own GTA V install with CodeWalker.Core (scripts/setup.py). The scripts live at the muto-atlas repository root, outside this folder - outside Claude Code install with scripts/install_skills.py or use scripts/mcp_server.py.
---
- # 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ı:
+ # FiveM Asset Data — trunk
- ```
- specialAttribute = 0 → bu obje kapı DEĞİL, kapı sisteminde menteşesi yok
- ```
+ This file is the **trunk**: the rules that hold in every branch, and the map of the tree.
+ Details are in the branch and leaf files; from here you are only **routed**.
+ A fact is written once, in the widest place where it holds.
- Tek sorgu (`assetdb.py door v_ilev_gb_teldr`) bunu baştan söylerdi.
+ ## TREE — trunk / branch / leaf
- ## OTOMATİK SORGU TABLOSU — kullanıcı komut vermez, sen bakarsın
+ - **Trunk** — this file + `trunk/`: **GTA V's own rules** (data model, file
+ types, hash, coordinates, **texture/DDS**, streaming, resource format, client/server),
+ our working discipline, tool pitfalls, verification ladder, flags, bone tags.
+ **Criterion:** an item that does not hold in every branch and every leaf does not go in the trunk.
+ - **Branch** — `branches/<branch>/_branch.md`: the category's broad rules + the leaf list.
+ - **Leaf** — `branches/<branch>/<leaf>.md`: only what is specific to that task.
+ A leaf is defined by *the thing wanted*; "road destruction / bridge destruction / explosion" is one leaf.
- 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ç.
+ **Use:** when a topic comes up, open the branch first (`_branch.md`), then a single leaf.
+ Do not scan every file; keyword → branch → leaf.
- | 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` |
- | **decal** — Blender'da yüzeye **geometri yansıtma** (graffiti, leke, tabela) | `references/decal-isik-timecycle-bulgulari.md` · `/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` |
+ | branch | command | file | keywords |
+ |---|---|---|---|
+ | Map | `/map` | `branches/map/_branch.md` | ymap, ytyp, MLO, vanilla part, destruction, RayFire, LOD, extent, grass |
+ | Prop | `/prop` | `branches/prop/_branch.md` | prop, door, does not move, fragment, raw pack, DUI, NUI HUD, ox_target |
+ | Clothing | `/clothing` | `branches/clothing/_branch.md` | clothing, freemode component, skintone, ped prop, hat |
+ | Particle | `/particle` | `branches/particle/_branch.md` | ptfx, .ypt, effect, smoke, flipbook, emitter, catalog |
+ | Look | `/look` | `branches/look/_branch.md` | shader, texture, parallax, light, TimeFlags, decal, timecycle, emissive, bake |
+ | Vehicle | `/vehicle` | `branches/vehicle/_branch.md` | vehicle bone, handling, modkit, siren |
- **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.
+ The full keyword list is at the top of every `_branch.md`.
- **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`
+ ### ⛔ Route by CLASS, not by KEYWORD
- ## OYUNA GİRMEDEN DOĞRULA — CodeWalker merdiveni
+ Keywords are **an accelerator, not a dictionary.** The set of words is infinite
+ (*roller shutter · sign · fountain*), the set of classes is closed: **6 branches.**
- **Tam reçete: `references/oyuna-girmeden-dogrulama.md`**
- Araç: `scripts/cw_anim_check.ps1`
+ 1. If a keyword matches → the branch is known, open it.
+ 2. If none matches, **do not stop**: look at the **`What belongs here:`** definition at the top of
+ `branches/<branch>/_branch.md` and **classify** the sentence.
+ *"Make the roller shutter open"* → a roller shutter is a door object → `/prop`.
+ 3. Adding a keyword to the list is **the exception**: only for a term that comes up often and
+ cannot be inferred from the definition. Do not add every word — the list bloats.
- 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.
+ If the class definition does not settle it either → **ask.**
- **Kural: bir basamakta yakalanabilecek hatayı alt basamağa taşıma.**
+ ## TRUNK FILES
- | Ne doğrulanacak | Basamak |
+ | file | when |
|---|---|
- | 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.
+ | `trunk/gta-fundamentals.md` | **the engine's own contract** — archetype/entity/drawable split, file types, joaat, coordinates/units, **texture and DDS rules**, streaming, RSC7, client/server, render bucket |
+ | `trunk/tool-pitfalls.md` | Sollumz · Blender · CodeWalker · PowerShell · Python/Lua · FiveM runtime — when a tool behaves unexpectedly, **come here first** |
+ | `trunk/verification-ladder.md` | verifying an asset without taking it into the game: measure in Blender → read back → CodeWalker headless → render → GUI → game |
+ | `trunk/flags.md` | ytyp/ymap/collision flags, the 21 `specialAttribute` values, 14 extension types, nametables |
+ | `trunk/bone-tags.md` | vehicle / weapon / ped bones: **is the name fixed or the tag fixed** |
+ | `sources/external-tools.md` | *(not a rule, source note)* the measurable part of external tools; [verified]/[refuted] labels; tool inventory |
+ | `sources/community-resources.md` | *(not a rule, source note)* full dump of the Sollumz Discord `#resources` — index of ready-made templates/rigs/tools, `bloodfx.dat` fields |
- ## KOORDİNAT — config'e sabit yazmadan önce
+ ## ⛔ IF DATA IS MISSING, DO NOT GUESS
- Bir prop/kapı için koordinat gerekiyorsa **oyuncudan isteme, indeksten al**:
+ Every answer rests on the `data/` layers. If a layer is missing, the query returns **exit 2**;
+ at that point the only thing to do is **stop**:
```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.
-
- ⚠️ **Ama bu TEK YOL DEĞİL — yolu seç ve ona sadık kal.** Expression
- kullanmayan ikinci bir reçete ölçüldü: **fragment physics bones + `Child Of`
- constraint + ytyp `HAS_ANIM`/`AUTOSTART_ANIM`** →
- `references/sollumz-discord-tutorials.md` §1. Hangi durumda hangisinin doğru
- olduğu **henüz ölçülmedi**; kullanıcıya iki yolu da anlat, birini seç, sonra
- **içinde varyasyon yapma ve ikisini MELEZLEME** — melez asset bir kez üretildi
- ve hiç çalışmadı. ⛔ İki constraint farklıdır: animasyonlu prop → `Child Of` +
- Set Inverse, kırılabilir fragment → `Copy Transforms`.
-
- ## 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
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/setup.py" --plan # shows the state, writes nothing
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/setup.py" # installs the missing layers (/asset-setup)
```
- - `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.
+ Exit codes: `0` found · `1` the query ran, **the name is not in the authority** · `2` **the layer
+ is not installed** — says nothing about the result · `3` internal error, not "absent".
+ Confusing `2` with `1` means reading a "0 results" that came from a missing layer as
+ "does not exist in the game".
- ```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'ı
- ```
+ ## CORE RULE — data first, code second
- 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**.
+ Before writing code about an object/prop/door/animation, look at that asset's data.
+ Real case: four natives were tried in turn on the Fleeca teller door `v_ilev_gb_teldr`;
+ the answer was in one line of the ytyp — `specialAttribute = 0`,
+ i.e. not a door. `assetdb.py door v_ilev_gb_teldr` would have said so from the start.
- Ölçülmüş, tahmin edilmemiş:
+ ## WORKING DISCIPLINE — in every branch, with every tool
- - **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.
+ 1. **Measurement > guess.** A number (tag, flag, duration, lodDist, `fxName`) is not guessed,
+ it is queried. A number from an external tool is **a claim**; without a `[verified]`
+ label, measure it first (`sources/external-tools.md`).
+ 2. **A tool not showing something does not mean that thing is absent.** CodeWalker cannot
+ write `.yed` bytecode, PowerShell returns `$null.Length=0` on a property that does not exist,
+ Sollumz imports a binary "in 0.0 seconds" — all three were taken for "absent".
+ 3. **A tool raising no error does not mean the work is right.** Nearly all the bugs in this
+ repository are silent: the file is created, it says "success", nothing happens in the game.
+ All of them are in `trunk/tool-pitfalls.md`.
+ 4. **A screenshot is not a measurement.** Before saying something is broken,
+ read: the pixel, the file, the read-back. (In one round the screenshot was looked at three
+ times and the wrong diagnosis was made.)
+ 5. **"The object was created, the numbers look reasonable" does not mean it works.** Numbers and
+ screen are both needed; working at one synthetic point is not enough, a fix is not
+ delivered before it has been tried **in the user's real situation**.
+ 6. **Read back what you wrote.** File size is not a validity criterion (RSC7 zlib);
+ the only criterion is reading back. If a script crashes midway, the next `Write` does not run —
+ `cat`/`grep` before saying "written". After a copy, compare size/hash.
+ 7. **The order of operations is part of the measurement.** Do not look at a single number but at
+ **two independent numbers agreeing** (`reached` vs `target`). A number can be right while
+ *when* it was measured is wrong.
+ 8. **The reference itself can be broken.** Two independent decoders can share the same mistake;
+ do not say "I measured" without comparing against vanilla.
+ 9. **One variable at a time.** If something does not work, split the chain into parts,
+ set up A/B; do not ask for a test before the chain is complete; do not jump from symptom to
+ hypothesis and try things one by one.
+ 10. **A grid can ask the wrong question** — "100/100 points filled" does not mean the place
+ that was not sampled does not exist. The measurement can be right and the question wrong.
+ 11. **A tool's constant is tuned to its own scale** — do not copy the constant, copy what it is
+ normalised against (shadow bias was right for a 0.15 m prop, in a 660 m
+ scene it shadowed 72% of the ground).
+ 12. **Before guessing a field's meaning from its distribution, look at how the tool names that
+ field** (`bl_rna.properties[...].enum_items`). All three guesses for `Flashiness`
+ were wrong; Sollumz had a named enum.
+ 13. **Do not write 0 into an `Unknown*` field** — look at its distribution, take the most common value.
+ 14. **Pick a recipe and apply it to the end; do NOT HYBRIDISE two recipes.** A hybrid of two paths
+ that are each correct on their own never worked. If the recipe is unclear,
+ clarify it with `AskUserQuestion`.
- - **`Flashiness` (flicker) hiçbir yerde yazmaz**, 72.539 ışığın dağılımından
- okundu: **15** alarm · **17** tünel · **9** acil durum · **19** hasarlı gemi
- (68.036'sı 0). ⚠️ Adı "broken light" olan vanilla prop'un flashiness'i
- **0**'dır — GTA "kırık"ı modelle yapar, titremeyle değil.
- - **Emissive panelin ışığı yoktur** — parlaklık `emissiveMultiplier`'dadır ve
- bir odadaki paneller **tek geometriyi paylaşır**; birini kırmak için
- geometriyi bölmek gerekir. Emissive geometri **titreyemez**.
- - **Kendi timecycle modifier'ını `data_file 'TIMECYCLEMOD_FILE'` ile KAYDET** —
- kaydedilmezse oyun onu hiç aramaz. Paylaşılan vanilla modifier'a dokunma
- (`morgue_dark` 6 DLC'de tanımlı, hangisinin kazandığı veriden okunamaz).
+ ## ENGINE INVARIANTS — whatever the branch
- Tam matematik + timecycle üç katmanı: `references/isik-matematigi-ve-onizleme.md`
- Işık/timecycle/emissive alan bulguları: `references/decal-isik-timecycle-bulgulari.md`
+ - **Asset changed → leave the server and reconnect.** The stream is cached, a restart
+ is not enough; skip it and you test a stale asset. Remind the user before asking for a test.
+ - **A broken stream asset silently drops the whole resource** — no command registers on the
+ client, no error. If commands suddenly vanished, look at `stream/`, not at the Lua.
+ If a resource is **in two folders**, one is ignored → server log.
+ - **A magic number is not copied, it is decoded:** `assetdb.py flags <number> [--entity]`.
+ `1572872` = LOD in Parented YMAP + Cast Static/Dynamic → for a ymap; `18350080`
+ = Dont Render In Reflections + two shadow bits → for an MLO entity. Mixing them up
+ silently deletes the object. → `trunk/flags.md`
+ - **Bone: is the name fixed or the tag?** The script side (`GetEntityBoneIndexByName`) uses
+ **the name**, the file side (`.ycd`/`.yed`/`specialAttribute`) uses **the tag**.
+ `GetPedBoneIndex` takes a TAG. → `trunk/bone-tags.md`
+ - **The bbox must cover the whole animation — in two separate places:** the `.ydr`'s own
+ `BoundingBox`/`Sphere` **and** the ytyp archetype box. If one is fixed and the other
+ stays at rest, the object flickers and disappears at distance.
+ - **`physicsDictionary` never 0** — the model is visible and you walk through it.
+ - **An object spawned by script is not a map object**; props are not placed inside an MLO
+ with a ymap; `SetEntityCollision(false)` is unreliable on a map object.
+ - **`CreateObject` places at the collision-bound BASE, `CreateObjectNoOffset` at the ORIGIN** — a stale bound lifts the object into the air,
+ the bound is regenerated from the visual. An attached object is positioned from its **origin**; adding a bone to a prop gives no alignment,
+ the alignment is baked into the model.
+ - **Collision is not chased with script** — `SetEntityCollision` / `Freeze` /
+ `SetEntityHeading` / `DoorSystemSetOpenRatio` break the animation chain.
+ - **Custom ped skeletons are forbidden**; the engine accepts only its own skeleton.
+ - **DUI/NUI is client-side** — password/code/price comparison happens on the server.
+ - **Texture: DDS required, both edges a power of two, DXT + mip chain.** PNG is skipped
+ silently, a texture that is not a power of two flickers, DXT1 carries no alpha (holes close).
+ → `trunk/gta-fundamentals.md` §5
+ - **Archetype (what) ≠ entity (where) ≠ drawable (how it looks)** — three separate files;
+ fixing the ytyp affects **every place** that uses that model. → `trunk/gta-fundamentals.md` §1
+ - **Clip name = prop model name** (detecting an item animation). Duration is not guessed,
+ it is taken from the index.
- ## DECAL — üç ayrı sistem, karıştırma (`/decal`)
+ ## QUERY TABLE — the user gives no command, you look
- "Şuraya kan/graffiti/leke/logo koyalım" üç ayrı işten biridir ve hiçbiri
- diğerinin yerine geçmez:
+ The moment the topic comes up, before writing code:
- | istenen | yol |
+ | topic | run |
|---|---|
- | çalışma anında iz (kan, lastik, mermi, sızıntı) | `AddDecal` → `assetdb.py decal <tür>` (194 tipli tablo) |
- | haritaya **kalıcı gömülü** (graffiti, logo, tabela) | `decal.sps` shader + render bucket **2** → `assetdb.py shader decal` |
- | Blender'da yüzeye **geometri yansıtma** | `references/decal-isik-timecycle-bulgulari.md` |
-
- Yansıtmanın üç yöntemi ölçüldü, üçünün de sert sınırı var:
-
- - **Işın ızgarası ışına paralel yüzeye ASLA vuramaz** — merdivende 4096
- ışının 2732'si, odanın iç köşesinde 1344'ü boşa gitti.
- - **Kutu yöntemi** sarar (silindirde 39 normal bandı, ışında 2) ama desen
- köşede yeniden başlar. İnce boru/ızgarada **hiçbiri çalışmaz** — orası
- boyama işidir (Surface Painter).
- - ⛔ **`bmesh.ops.bisect_plane` açık geometride kırpmaz, YÜZ SİLER** (altı
- çağrıda yüz sayısı 637'de sabit kalırken alan 3.553 → 0.941 m²). Boolean
- INTERSECT de güvenilmez. Doğrusu **Sutherland–Hodgman** — çözücüsü yok,
- başarısızlık modu yok.
-
- Decal görünmüyorsa **sırayla** şuna bak (hepsi sessiz):
- UV katmanının adı materyalinkiyle aynı mı (`"UVMap 0"`) · hedefin eski UV
- katmanı silindi mi · `Color 1` alfası 1.0 mı (kopyalanan geometri hedefinkini
- getirir, ölçülen vakada 0.498) · alfa haritasında **satır 0 görüntünün ALTIDIR**.
-
- ⛔ **`object.dimensions` DÖNÜŞÜ İÇERMEZ** (yerel bbox × ölçek) — "en uzun
- ekseni yatır" mantığını bununla kurmak sessizce hiçbir şey yapmaz.
- ⛔ **Gizli objede `select_set()` sessizce çalışmaz**: export "successfully"
- der, dosya **0 bayt** çıkar (yedi objeden beşi böyle yazıldı).
-
- Blender aracı bu depoda değil — **MutoLab eklentisi** (`ops/decal`,
- `panels/decal.py`, `props/decal.py`). Bu belge o aracın ölçülmüş
- sözleşmesidir; araç değişirse belge ölçüt olarak kalır.
-
- ## 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
+ | prop / object / door name · "door does not open" | `assetdb.py show <name>` · `door <name>` |
+ | where in the world · what is near me | `where <name>` · `near x y z --radius 10` |
+ | animation / clip · prop animation · which model plays it | `anim <query>` · `propanim <prop>` · `clipfit <dict> <clip>` |
+ | bone / tag / skeleton | `bones <model>` |
+ | ped identity (clip dictionary, expression, clipset) | `pedmeta <ped>` |
+ | expression / `.yed` / spring-sag | `expr <query>` · `ext <name>` |
+ | particle · "does this effect exist" · `fxName` | `ptfx <prop\|effect>` · `fx <name> --exact` · `ptfx --type 4` |
+ | flag number · ytyp extension | `flags <number> [--entity]` · `ext <name>` |
+ | LOD · "disappears at distance" · is something wrong with my map | `lod` · `lodchain <name>` · `lodaudit` |
+ | grass / ground / `Procedural ID` | `proc [<name>\|--id N]` |
+ | collision material | `mat [<name>\|--index N]` |
+ | decal by script · embedded decal shader · shader type | `decal <type>` · `shader decal` · `shader <type>` |
+ | light · weather · room timecycle | `light <ydr>` · `cycle w_clear --hour 20` · `timecycle <name>` |
+ | weapon · vehicle · MLO · IPL | `weapon <name> --parts` · `vehicle <name>` · `mlo <name>` · `ipl <name>` |
+ | loot/spawn point, ATM/CCTV location | `world --near x,y,z --radius 50` · `--family <family>` |
+ | does the model have a screen (`AddReplaceTexture`) | `screentex.ps1 -Model <name> -All` |
+ | native name / signature / side | the `fivem-natives` skill (`/native`, `/native-lint`) |
- 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).
+ All of them are `python "${CLAUDE_PLUGIN_ROOT}/scripts/assetdb.py" <subcommand>`. Summarise the
+ result in a sentence or two, then move to the code. The index is built from the vanilla RPFs + the
+ server's own ytyps; rebuilding it is `/asset-build`.
- **`references/vanilla-parca-degistirme.md`**
- Doku sözlüğü indeksi: `scripts/ytd_index.ps1` · `scripts/ytd_ara.ps1`
+ ## VERIFICATION LADDER — the game is the last resort
- ## GÖRSEL GEREKTİĞİNDE — üretme, öner ve prompt ver
+ **Do not carry a bug that one step can catch down to a lower step.**
+ Full recipe: `trunk/verification-ladder.md`.
- Ekran arka planı, ikon, logo, doku, UI görseli gerektiğinde **rastgele bir
- şey üretme ya da yer tutucu uydurma.** Sırayla:
+ | what to verify | step |
+ |---|---|
+ | weights, deform, pivot, dimensions | **measure** in Blender (`evaluated_get`) |
+ | shader/bucket, bone tag, hierarchy, `<Hash>`, clip count | `res_to_xml.ps1` + structural diff against vanilla |
+ | "does it look right" | Blender render → send the user a **file** |
+ | vanilla asset, world placement, MLO layout | CodeWalker GUI (by hand, the user drives) |
+ | script, physics, real look, streaming, resmon | **the game** — for particles the test bench `scripts/ptfx_bench.py` |
- 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.
+ ## WHEN AN IMAGE IS NEEDED — do not generate it, suggest it and give a prompt
- ## NE ZAMAN YETMEZ
+ Screen background, icon, logo, texture: **do not invent a placeholder.** Describe the idea (what,
+ where, from what distance, tone) → give the user a **ready prompt** with the aspect ratio and
+ resolution → until the image arrives, build the layout in code and leave an empty box of the
+ right size. An invented image does not fit the tone; the work is done twice.
- - **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.
+ ## WHEN IT IS NOT ENOUGH
- Bu durumlarda tahmin yürütme; kullanıcıya CodeWalker'da neye bakması
- gerektiğini söyle veya oyun içi ölçüm iste.
+ Fragment internals → inspect the `.yft` · animation duration/events → `.ycd` ·
+ internal layout of the server's own MLOs → `/asset-build -ExtraFolders`
+ brings the archetypes, the internal entity expansion depends on vanilla ymaps.
+ In these cases do not guess; say what to look at in CodeWalker or ask for an
+ in-game measurement.