Ir para conteúdo
  • 2 Quem está por aqui   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.

mesh


baphomet-
 Compartilhar

Posts Recomendados

qual arquivo que cria ou armazena as faces dos mobs? exemplo como o mob batoreto sabe que a face dele e 361? como saber a ef_class de uma face? igual do batoreto 55?? pra criar um mob novo vc registra as mesh, boneany, id no npcgenner mais em qual arquivo que seta a mesh no mob novo? como ele vai achar a face dele? e como vai saber a ef_class desse mob novo criado?

Editado por baphomet-
Link para o comentário
Compartilhar em outros sites

no client tem um switch que retorna o id do arquivo utilizado

 

exemplo:

a face do tigre de fogo na itemlist EF_CLASS,51


no client(n lembro o nome do arquivo, pesquisa pelo case abaixo) tem :

 

    case 51:
        return 38;

 

no arquivo BoneAni4.txt tem os ids das meshs

 

38 7 2 mesh\tg01

 

38= Id da mesh

7= Número de animações

2= Número de meshs

 

----

 

No seu caso seria:

    case 55:
        return 10;

 

id 10 no boneani4.txt é:

10 8 8 mesh\bm02

se vc abrir o arquivo bm020101 será o batorero

 

 

  • Curtir 3
Link para o comentário
Compartilhar em outros sites

no meu caso a bone ta registrada no id 

 

56 9 4 mesh\an01
57 9 5 mesh\an02

 

e la no basdef.cpp

 

case 73: return 56;
case 74: return 57;

 

ai na itemlist eu faço

 

192,Anubis,0.0,0.0.0.0.0,0,0,1,0,0,EF_CLASS,73,EF_RANGE,2

ai no game ele fica invisivel. 

mesmo caso acontece com 

 

4557,Traje_Mont:_Lobisomem,0.0,0.0.0.0.0,0,1200,0,0,0,EF_CLASS,79,EF_VOLATILE,184

 

88 11 1 mesh\fr01

 

  case 79: return 88;

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

1 hora atrás, baphomet- disse:

no meu caso a bone ta registrada no id 

 

56 9 4 mesh\an01
57 9 5 mesh\an02

 

e la no basdef.cpp

 

case 73: return 56;
case 74: return 57;

 

ai na itemlist eu faço

 

192,Anubis,0.0,0.0.0.0.0,0,0,1,0,0,EF_CLASS,73,EF_RANGE,2

ai no game ele fica invisivel. 

mesmo caso acontece com 

 

4557,Traje_Mont:_Lobisomem,0.0,0.0.0.0.0,0,1200,0,0,0,EF_CLASS,79,EF_VOLATILE,184

 

88 11 1 mesh\fr01

 

  case 79: return 88;

Você ainda precisa registrar a textura no meshtexturelist normalmente, o traje de montaria funciona de forma diferente(você não utiliza ele como face na itemlist, apenas registra e faz a montaria utilizar a mesh através do código e item equipado), precisa registrar no validindex.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

31 minutos atrás, gnib disse:

Você ainda precisa registrar a textura no meshtexturelist normalmente, o traje de montaria funciona de forma diferente(você não utiliza ele como face na itemlist, apenas registra e faz a montaria utilizar a mesh através do código e item equipado), precisa registrar no validindex.

eu registrei as mesh tudo certinho tanto do mob quanto da montaria. mas o foco mesmo e o mob eu crio no NPCGenner, itemlist... registro as meshtexturelist, boneani4, basedef.cpp e fica invisivel. ja tentei colocar tambem o id da mesh ali no começo do codigo da item list de todas formas fica invisivel so aparece o nome andando 

Link para o comentário
Compartilhar em outros sites

7 horas atrás, baphomet- disse:

no meu caso a bone ta registrada no id 

 

56 9 4 mesh\an01
57 9 5 mesh\an02

 

e la no basdef.cpp

 

case 73: return 56;
case 74: return 57;

 

ai na itemlist eu faço

 

192,Anubis,0.0,0.0.0.0.0,0,0,1,0,0,EF_CLASS,73,EF_RANGE,2

ai no game ele fica invisivel. 

mesmo caso acontece com 

 

4557,Traje_Mont:_Lobisomem,0.0,0.0.0.0.0,0,1200,0,0,0,EF_CLASS,79,EF_VOLATILE,184

 

88 11 1 mesh\fr01

 

  case 79: return 88;

provavelmente as animações não estao registadas no validindex.bin... então o mob aparece invisivel

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

no WYDConverter eu fiz uma área de tutorial e um deles é a criação de novos itens/mobs, veja se te ajuda. copia e crie um .md pode ser no próprio VS que vai ficar bem mais legível.
 

# Guia: Criar Mobs, Objetos e Meshes Novos para o WYD

> Passo a passo completo para criar conteudo 3D novo e integrar no cliente WYD.
> Cobre mobs (MSH skinned), objetos estaticos (MSA), modelagem, exportacao,
> conversao e registro nos arquivos do cliente.

---

## 1. Sistema de Arquivos do WYD

### 1.1 Arquivos 3D por mob

| Arquivo | Exemplo | Conteudo | Formato |
|---|---|---|---|
| `.msh` | `nm010101.msh` | Mesh skinned (vertices, indices, bones, skinning) | Binario 32B header |
| `.bon` | `nm01.bon` | Hierarquia do esqueleto (pares parentID/boneID) | Binario 8B por bone |
| `.ani` | `nm010101.ani` | Animacao (matrizes 4x4 locais por bone por frame) | Binario 8B header + matrices |
| `.wys` | `nm010101.wys` | Textura DXT1 comprimida | Binario WYS |
| `.wyt` | `nm010101.wyt` | Textura BGRA raw (formato antigo) | Binario WYT |

### 1.2 Convencao de nomes

```
{prefixo}{PPVV}.ext

prefixo = skeleton type (4 chars): nm01, ch01, ch02, tr09, hs01...
PP       = parte/slot (2 digitos): 01=corpo, 02=helm, 03=armor...
VV       = visual/variante (2 digitos): 01=base, 02=alt...
```

**Regra critica:** os primeiros 4 caracteres definem o skeleton. Todos os arquivos
com mesmo prefixo compartilham o mesmo `.bon` e os mesmos `.ani`.

Exemplos:
- `nm010101.msh`, `nm010102.msh` → usam `nm01.bon`
- `ch010597.msh` → usa `ch01.bon`, slot 05 (luva), visual 97

### 1.3 Arquivos de registro do cliente

Estes arquivos precisam ser editados para o cliente reconhecer mobs novos.

| Arquivo | Path | Funcao | Editar quando |
|---|---|---|---|
| `BoneAni4.txt` | `Mesh\BoneAni4.txt` | Registra skeletons: index, num ANIs, num partes, prefixo | Skeleton NOVO |
| `ValidIndex.bin` | `Mesh\ValidIndex.bin` | Mapeia quais ANIs existem para cada skeleton | Skeleton NOVO |
| `MeshTextureList.bin` | `Mesh\MeshTextureList.bin` | Tabela de texturas de meshes (nome → index) | Textura NOVA |
| `MeshList.txt` | `Mesh\MeshList.txt` | Registra objetos estaticos MSA: index → path | MSA NOVO |
| `AniSound4.txt` | `AniSound4.txt` | Tabela de animacoes/velocidades/sons por skeleton type | Skeleton NOVO |
| `ItemList.bin` | Server-side | Define nClass do mob → mapeia para skeleton via `BASE_DefineSkinMeshType` | Mob NOVO |
| `Basedef.cpp` | Compilado no .exe | `BASE_DefineSkinMeshType(nClass)` → nBoneAniIndex (hardcoded switch) | Skeleton NOVO (recompilacao) |

**Para mob com skeleton EXISTENTE:** nenhum destes arquivos precisa ser editado.
Basta colocar o MSH + WYS na pasta `Mesh\` com o prefixo correto.

**Para mob com skeleton NOVO:** todos os arquivos acima precisam ser editados.

---

## 2. Formatos Binarios Detalhados

### 2.1 MSH (Mesh Skinned)

```
Header (32 bytes):
  [00] DWORD dwParentID        — ID do bone pai (0xFFFFFFFF = root)
  [04] DWORD dwMeshID          — ID do bone deste mesh
  [08] DWORD dwFVF             — Flexible Vertex Format (D3D9)
  [0C] DWORD sizeVertex        — Bytes por vertice
  [10] DWORD numFaceInfluence   — Numero de face influences
  [14] DWORD numPalette        — Numero de bones na palette
  [18] DWORD vertexCount       — Numero de vertices
  [1C] DWORD faceCount         — Numero de INDICES (nao faces!)

Bones (se numPalette > 0):
  XMFLOAT4X4[numPalette]       — Offset matrices (64 bytes cada)
  DWORD[numPalette]             — Bone IDs (4 bytes cada)

Vertices:
  Layout depende do FVF. Tipico para skinned:
    Position XYZ (12B) + BlendWeights (4-12B) + PackedBoneIndices (4B)
    + Normal (12B) + UV (8B)

Indices:
  uint16[faceCount]             — Index buffer 16-bit
```

### 2.2 BON (Bone Hierarchy)

```
Arquivo = array de pares (8 bytes cada):
  [parentID: DWORD] [boneID: DWORD]

parentID = 0xFFFFFFFF ou 0 → root (sem pai)
parentID = N → bone filho de bone N

Tamanho total = numBones * 8 bytes
```

Exemplo para esqueleto com 5 bones:
```
[0xFFFFFFFF] [0]    — Bone 0 e root
[0]          [1]    — Bone 1 filho de Bone 0
[0]          [2]    — Bone 2 filho de Bone 0
[1]          [3]    — Bone 3 filho de Bone 1
[1]          [4]    — Bone 4 filho de Bone 1
```

### 2.3 ANI (Animation)

```
Header (8 bytes):
  [00] DWORD numTicks    — Numero de keyframes (frames de animacao)
  [04] DWORD numBones    — Numero de bones no skeleton

Dados:
  Para cada tick (0..numTicks-1):
    XMFLOAT4X4[numBones]  — Matriz LOCAL de cada bone neste frame (64 bytes cada)

Tamanho total = 8 + (numTicks * numBones * 64) bytes
```

As matrizes sao LOCAL (relativas ao pai na hierarquia BON).
O cliente propaga pela hierarquia para obter as combined (world) matrices:
`combined[bone] = local[bone] * combined[parent]`

### 2.4 BoneAni4.txt

```
Formato texto, uma linha por skeleton:
{index} {numAniTypes} {numParts} {szAniName}

Campos:
  index         — Indice no array m_BoneAnimationList (0-99)
  numAniTypes   — Quantos ANIs diferentes este skeleton tem
  numParts      — Quantos slots de equipamento (1 para mobs simples, 7 para players)
  szAniName     — Prefixo completo com path (ex: mesh\nm01, mesh\ch01)
```

Exemplo:
```
0 38 7 mesh\ch01      <- personagem masculino, 38 animacoes, 7 partes
1 37 7 mesh\ch02      <- personagem feminino
2  1 1 mesh\hs01      <- cavalo, 1 animacao, 1 parte
3  2 1 mesh\nm01      <- mob tipo 1, 2 animacoes, 1 parte
...
```

### 2.5 ValidIndex.bin

```
Array binario fixo:
  stValidAniList[100][186]

  stValidAniList = struct { int nI; }  — 4 bytes

Tamanho total = 100 * 186 * 4 = 74.400 bytes

Indexacao:
  m_stValidAniList[skeletonIndex][aniSlot].nI = aniFileIndex

O cliente usa nI+1 para montar o nome do ANI:
  sprintf(szTemp, "%s%04d.ani", szAniName, m_stValidAniList[nCount][nFI].nI + 1)

Exemplo:
  m_stValidAniList[3][0].nI = 0   → mesh\nm010001.ani (idle)
  m_stValidAniList[3][1].nI = 1   → mesh\nm010002.ani (walk)
  m_stValidAniList[3][2].nI = 100 → mesh\nm010101.ani (arma 01, idle)
```

Codificacao dos 4 digitos do ANI:
```
XXYY onde:
  XX = tipo de arma (weapon): nArrayIndex / 100 - 1
  YY = tipo de acao (motion): nArrayIndex % 100 - 1

Exemplos (nI+1 → arquivo):
  0001 → arma 0, acao 0 (idle)
  0002 → arma 0, acao 1 (walk)
  0003 → arma 0, acao 2 (run)
  0004 → arma 0, acao 3 (attack1)
  0101 → arma 1, acao 0 (idle com espada)
```

### 2.6 MeshList.txt

```
Formato texto, uma linha por objeto estatico:
{index} {path_relativo}

Campos:
  index          — Indice no array m_stCommonMesh (0-3047)
  path_relativo  — Caminho do MSA relativo ao diretorio do cliente
```

Exemplo:
```
0 mesh\cas001.msa
1 mesh\cas002.msa
50 mesh\tree01.msa
100 mesh\sword01.msa
```

O engine chama `GetCommonMesh(dwObjType)` onde dwObjType = index.
Mapas (.trn) referenciam objetos pelo dwObjType.

### 2.7 MeshTextureList.bin

```
Array binario fixo de stTextureListInfo (264 bytes cada):
  char szFileName[255]      — path relativo da textura (ex: "mesh\nm010101.wys")
  char cAlpha               — tipo de alpha: 'N'=none, 'A'=alpha, 'a'=1bit, 'C'=compressed
  DWORD dwLastUsedTime      — runtime (ignorar, preencher com 0)
  DWORD dwShowTime          — runtime (ignorar, preencher com 0)

Tamanho por versao:
  TMProject classico: 2048 slots = 540.672 bytes
  WYD Global:         6096 slots = 1.609.344 bytes
```

O cliente busca textura por nome (`GetModelTextureIndex`): percorre TODOS os slots
comparando `szFileName` com o nome calculado pelo `TMSkinMesh`. Se nao encontra,
o mesh **NAO CARREGA** (retorna erro).

**Para adicionar textura nova:**
1. Encontrar um slot vazio (szFileName[0] == '\0')
2. Preencher szFileName com path relativo (ex: `mesh\xx010101.wys`)
3. Preencher cAlpha com 'N' (sem alpha) ou 'A' (com alpha)
4. dwLastUsedTime e dwShowTime = 0

### 2.8 AniSound4.txt

```
Formato texto. Uma secao por skeleton type (MAX_ANI_TYPE = 60 skeletons).
Cada secao tem 56 linhas (MAX_ANI_MOTION), uma por tipo de acao.

Para skeleton types 0 e 1 (players):
  {nomeAcao} {ani0} {speed0} {ani1} {speed1} {ani2} {speed2} {ani3} {speed3} {sound}

Para skeleton types 2+ (mobs/NPCs):
  {nomeAcao} {aniIndex} {speed} {sound}

Campos:
  nomeAcao  — label (ex: "IDLE", "WALK", "ATK1") — ignorado pelo parser
  aniIndex  — indice na lista de animacoes do skeleton (posicao no array concatenado)
  speed     — velocidade da animacao (ticks por frame)
  sound     — indice do som a tocar
```

Controla qual animacao tocar para cada acao do mob (idle, walk, attack, death, etc.)
e a velocidade de reproducao. Se o skeleton novo for um mob simples, basta preencher
as acoes basicas (idle=0, walk=1, attack=2, death=3).

### 2.9 Fluxo de resolucao no cliente

```
Servidor envia pacote com mob → nClass (tipo do mob)
        ↓
BASE_DefineSkinMeshType(nClass) → nBoneAniIndex (switch hardcoded em Basedef.cpp)
        ↓
BoneAni4.txt[nBoneAniIndex] → szAniName (ex: "mesh\nm01"), numParts, numAniTypes
        ↓
Skeleton:  szAniName + ".bon"                    → mesh\nm01.bon
Mesh:      szAniName + PPVV + ".msh"             → mesh\nm010101.msh
Textura:   szAniName + PPVV + ".wys"             → mesh\nm010101.wys
           → GetModelTextureIndex(texName)       → busca em MeshTextureList.bin
Animacao:  ValidIndex.bin[nBoneAniIndex][slot]    → nI+1 → mesh\nm010001.ani
           → AniSound4.txt[nBoneAniIndex]        → mapeia acao → indice de animacao
```

### 2.10 STRUCT_ITEMLIST (ItemList.bin)

```
Struct STRUCT_ITEMLIST — 120 bytes por item:
  char Name[64]                  — Nome do item
  short nIndexMesh               — Indice visual do mesh
  short nIndexTexture            — Indice visual da textura
  short nIndexVisualEffect       — Efeito visual (brilho, aura)
  short nReqLvl                  — Nivel minimo
  short nReqStr / nReqInt /      — Requisitos de atributo
        nReqDex / nReqCon
  STRUCT_STATICEFFECT stEffect[12] — 12 efeitos estaticos (4 bytes cada)
  int nPrice                     — Preco do item
  short nUnique                  — Tipo de raridade
  short nPos                     — Bitmask de slots onde pode equipar
  short nExtra                   — Dados extras
  short nGrade                   — Grau/rank do item
```

**nIndexMesh e nIndexTexture** sao os campos que conectam o item ao mesh visual.
O significado muda COMPLETAMENTE dependendo do tipo de item:

**ARMAS E ESCUDOS (slots 6 e 7 — MSA):**
  nIndexMesh = indice DIRETO no MeshList.txt
  O cliente chama: GetCommonMesh(nIndexMesh) → LoadMsa(MeshList[nIndexMesh])
  Nenhuma formula intermediaria. Se a arma esta no index 500 do MeshList,
  nIndexMesh = 500.
  nIndexTexture = preenche LOOK_INFO.SkinX mas NAO e usado para renderizar
  a arma 3D. A textura da arma vem do nome embeddado no MSA → MeshTextureList.
  Na pratica, para armas, nIndexTexture = 0.

**EQUIPAMENTOS SKINNED (slots 0-5 — MSH):**
  nIndexMesh = variante visual usada na FORMULA do nome do MSH:
    sprintf("%s%02d%02d.msh", szAniName, slot+1, nIndexMesh + offset + 1)
  NAO e um indice de MeshList. E um numero de variante (0, 1, 2...).
  Exemplo: nIndexMesh=5 no slot coat → ch010306.msh (prefixo + slot03 + visual06)

  nIndexTexture = modificador de textura na FORMULA do nome da WYS:
    sprintf("%s%02d%02d.wys", szAniName, slot+1, (nIndexTexture & 0xFFF) + nIndexMesh + offset + 1)
  Permite usar texturas diferentes para o mesmo mesh visual.
  Exemplo: nIndexMesh=5, nIndexTexture=2 + 1 → ch010308.wys

**MONTARIAS (slot 14 — MSH skinned, skeleton proprio):**
  O item de montaria fica em Equip[14].
  sIndex do item → transformado (sIndex - 2045, com overrides hardcoded)
  → sIndex final usado como indice no g_pItemList:
    nIndexMesh = g_pItemList[sIndex].nIndexMesh → Mesh0 (variante visual)
    nIndexTexture = g_pItemList[sIndex].nIndexTexture → Skin0 (variante textura)
    nClass (efeito 18) → BASE_DefineSkinMeshType(nClass) → skeleton da montaria
  Funciona igual a equipamentos skinned: nIndexMesh e variante visual,
  NAO indice do MeshList. Vem do ItemList.bin.

**nPos** — bitmask de slots de equipamento:
```
  Bit 0 (0x01) = Slot 0: Face/Corpo
  Bit 1 (0x02) = Slot 1: Helm (elmo)
  Bit 2 (0x04) = Slot 2: Coat (armadura)
  Bit 3 (0x08) = Slot 3: Pants (calca)
  Bit 4 (0x10) = Slot 4: Gloves (luva)
  Bit 5 (0x20) = Slot 5: Boots (bota)
  Bit 6 (0x40) = Slot 6: Left (mao esq/escudo)
  Bit 7 (0x80) = Slot 7: Right (mao dir/arma)
```

**nClass (efeito 18)** — tipo de classe que determina o skeleton:
  Usado por `BASE_DefineSkinMeshType(nClass)` para mobs e montarias.
  Para players: nClass 1/4 = masculino (ch01), 2/8 = feminino (ch02).
  Para mobs: nClass 16-74 mapeiam para indices 2-57 no BoneAni4.txt.

### 2.11 Fluxo visual de armas

```
Item no Equip[7] (mao direita) ou Equip[6] (mao esquerda)
        ↓
g_pItemList[sIndex].nIndexMesh → nIndexMesh
        ↓
GetCommonMesh(nIndexMesh)   ← DIRETO, sem formula intermediaria!
        ↓
MeshList.txt[nIndexMesh] → path do MSA (ex: mesh\wp001.msa)
        ↓
TMMesh::LoadMsa(path) → carrega MSA
        ↓
Textura: nome embeddado no MSA → GetModelTextureIndex → MeshTextureList.bin
```

### 2.12 Fluxo visual de equipamentos (armaduras, helmos, etc.)

```
Item no Equip[0-5] (face, helm, coat, pants, gloves, boots)
        ↓
g_pItemList[sIndex].nIndexMesh → LOOK_INFO.MeshX (variante)
g_pItemList[sIndex].nIndexTexture → LOOK_INFO.SkinX (textura mod)
        ↓
TMSkinMesh monta nome do arquivo:
  Mesh: sprintf("%s%02d%02d.msh", szAniName, slot+1, MeshX + offset + 1)
  Tex:  sprintf("%s%02d%02d.wys", szAniName, slot+1, (SkinX & 0xFFF) + MeshX + offset + 1)
        ↓
Exemplo: ch01, slot 3 (coat), nIndexMesh=5, nIndexTexture=0
  Mesh: ch010306.msh
  Tex:  ch010306.wys
```

---

## 3. Restricoes Tecnicas do Cliente

### 3.1 MSH (Skinned Meshes)

| Item | Limite | Origem |
|---|---|---|
| Bones por mesh | 40 max | `safePalette = min(n, 40)` em CMesh |
| Influences por vertice | 4 max | FVF XYZB1-B4 + LASTBETA_UBYTE4 |
| Vertices por mesh | 65535 max | Indices 16-bit no MSH |
| Textura por mesh | 1 | MSH nao tem attribute ranges |
| Textura dimensao | Potencia de 2 | DXT1 |
| Coordenadas | Z-Up | Nativo WYD |
| UV | V=0 no topo (D3D) | Nativo WYD e 3ds Max |
| Skeletons registrados | 100 max | MAX_BONE_ANIMATION_LIST |
| ANIs por skeleton | 186 max | Array fixo ValidAniList |
| Bones por skeleton | Sem limite hard | Limitado pela RAM |

### 3.2 MSA (Static Meshes)

| Item | Limite | Origem |
|---|---|---|
| Vertices por mesh | 65535 max | Indices 16-bit |
| Materiais por mesh | 32 max | dwAttCount no header |
| Texturas por material | 1 | Uma WYS por attribute range |
| Textura dimensao | Potencia de 2 | DXT1 |
| Coordenadas | Z-Up | Nativo WYD |
| UV | V=0 no topo (D3D) | Nativo WYD |
| Objetos em MeshList | 3048 max | MAX_COMMON_MESH |
| FVF suportados | 274 (normal) ou 322 (diffuse) | Engine hardcoded |

---

## 4. Workflow: Novo Mob com Skeleton Existente

**Cenario:** criar um mob novo que reutiliza o esqueleto e animacoes de um mob existente.
Este e o caminho mais rapido e seguro.

### Passo 1 — Exportar mob de referencia

No WYDConverter, abrir o MSH do mob que quer reusar (ex: `nm010101.msh`).
Exportar como FBX (target 3ds Max). O FBX contem:
- Geometria do mob original
- Esqueleto completo com bone IDs
- Animacao do ANI companion
- Textura companion como PNG

### Passo 2 — Importar no 3ds Max

Importar o FBX. O mesh aparece:
- Z-Up (nativo do Max e do WYD — sem conversao)
- Escala amplificada (conversor aplica x100 para edicao confortavel)
- Bones com nomes `Bone_000`, `Bone_001`, etc.

**NAO mover, rotacionar ou escalar o Armature.** A posicao dos bones e o bind pose
que as animacoes existentes esperam.

### Passo 3 — Modelar

- Deletar a geometria do mob original (so poligonos, NAO os bones)
- Modelar o novo mob ao redor do esqueleto existente
- Manter o mesh alinhado com os bones na posicao de bind

Regras:
- Apenas triangulos (sem quads/n-gons)
- Max 65535 vertices
- 1 material/textura por mesh
- Polycount razoavel (~500-3000 tris para mobs)

### Passo 4 — Skinning

- Aplicar Skin modifier no mesh
- Adicionar os bones do esqueleto importado
- Pintar weights: max 4 influences por vertice
- Weights devem somar 1.0
- Todo vertice deve ter pelo menos 1 bone com peso > 0

### Passo 5 — UV e Textura

- UV Unwrap no Max (UV convention D3D: V=0 topo — default do Max)
- Textura PNG/TGA em potencia de 2 (256x256 ou 512x512)
- O WYDConverter converte para WYS automaticamente

### Passo 6 — Exportar FBX

File → Export → FBX:
- Formato: FBX Binary
- Eixos: Z-Up (default Max)
- Smoothing Groups: ON
- Skin/Deformers: ON
- Embed Media: OFF

### Passo 7 — Converter

No WYDConverter:
1. Abrir o FBX exportado
2. Converter para MSH
3. Nomear: `nm010199.msh` (mesmo prefixo, numero livre)
4. Converter textura PNG → WYS: `nm010199.wys`
5. Copiar para `Mesh\` do cliente

### Passo 8 — Testar

O cliente carrega automaticamente:
- `nm010199.msh` — mesh novo
- `nm01.bon` — hierarquia (ja existe)
- `nm010001.ani` etc — animacoes (ja existem)
- `nm010199.wys` — textura nova

Nenhuma edicao de BoneAni4.txt ou ValidIndex.bin necessaria (mesmo skeleton).

---

## 5. Workflow: Mob com Skeleton e Animacoes Novas

**Cenario:** criar um mob completamente novo com esqueleto e animacoes proprias.
Requer ferramentas adicionais e edicao de arquivos de registro.

### Passo 1 — Modelar e Riggar no 3ds Max

- Modelar o mob
- Criar esqueleto com bones (usar nomes `Bone_000`, `Bone_001`, etc.)
- Bone 0 deve ser o root
- Max 40 bones
- Skin modifier com max 4 influences

### Passo 2 — Criar Animacoes

No 3ds Max, criar as animacoes necessarias:
- Idle (parado)
- Walk (andando)
- Run (correndo)
- Attack (atacando)
- Death (morrendo)
- etc.

Cada animacao sera exportada como um FBX separado (ou ranges no mesmo FBX).

### Passo 3 — Exportar

Exportar cada animacao como arquivo separado com mesh + skeleton + animation.
Formatos suportados:
- **FBX Binary** (3ds Max, Maya, Blender via plugin)
- **GLB/GLTF** (Blender nativo, qualquer DCC moderno)

### Passo 4 — Converter

Usar o WYDConverter para gerar:

| De | Para | Ferramenta | Status |
|---|---|---|---|
| FBX mesh | `.msh` | MSHEncoder (FBX→MSH) | Funciona |
| GLB/GLTF mesh | `.msh` | MSHEncoder (GLTF→MSH) | Funciona |
| FBX skeleton | `.bon` | **BONEncoder (FBX)** | NAO EXISTE |
| GLB/GLTF skeleton | `.bon` | **BONEncoder (GLTF)** | NAO EXISTE |
| FBX animation | `.ani` | **ANIEncoder (FBX)** | NAO EXISTE |
| GLB/GLTF animation | `.ani` | **ANIEncoder (GLTF)** | NAO EXISTE |
| PNG textura | `.wys` | WYSEncoder | Funciona |

### Passo 5 — Registrar no cliente

Para um skeleton completamente novo, TODOS estes arquivos precisam ser editados:

#### 5.1 Editar BoneAni4.txt

Adicionar uma linha para o novo skeleton:
```
{novoIndex} {numAnis} {numParts} mesh\{prefixo}
```

Exemplo: adicionar mob `xx01` com 3 animacoes, 1 parte:
```
50 3 1 mesh\xx01
```

O index (50) deve ser um slot livre no array (0-99).

#### 5.2 Editar ValidIndex.bin

Adicionar as entradas para mapear os ANIs do novo skeleton:
```
m_stValidAniList[50][0].nI = 0    → mesh\xx010001.ani (idle)
m_stValidAniList[50][1].nI = 1    → mesh\xx010002.ani (walk)
m_stValidAniList[50][2].nI = 2    → mesh\xx010003.ani (attack)
```

O ValidIndex.bin e um array binario fixo de 74400 bytes.
Offset para skeleton index N = N * 186 * 4 bytes.
Cada slot = 4 bytes (int).

#### 5.3 Editar MeshTextureList.bin

Adicionar a textura do novo mob em um slot vazio:
```
Slot livre → szFileName = "mesh\xx010101.wys", cAlpha = 'N'
```

**CRITICO:** sem esta entrada, o cliente NAO encontra a textura e o mesh nao carrega.
O `GetModelTextureIndex` faz busca linear por nome — se nao encontra, retorna -1,
e o CMesh aborta o carregamento.

Para encontrar slots vazios: qualquer entrada com `szFileName[0] == '\0'`.
Cada slot tem 264 bytes. Para editar diretamente no binario:
```
Offset = slotIndex * 264
  [+0..+254]   = szFileName (null-terminated, zero-padded)
  [+255]       = cAlpha ('N' ou 'A')
  [+256..+259] = dwLastUsedTime (0)
  [+260..+263] = dwShowTime (0)
```

#### 5.4 Editar AniSound4.txt

Adicionar uma secao para o novo skeleton type.
A posicao na lista corresponde ao nBoneAniIndex.

Para mob simples (56 linhas, formato `{nome} {aniIdx} {speed} {sound}`):
```
TYPE50
IDLE     0 30 0
WALK     1 30 0
RUN      1 20 0
ATK1     2 25 0
ATK2     2 25 0
DEATH    2 30 0
...      (preencher restante com 0 0 0)
```

#### 5.5 Editar BASE_DefineSkinMeshType (recompilacao)

Em `Basedef.cpp`, a funcao `BASE_DefineSkinMeshType(nClass)` e um switch hardcoded
que mapeia o nClass do item/mob → nBoneAniIndex.

Para adicionar um novo mob com nClass=75:
```cpp
case 75:
    return 50;  // nosso novo skeleton xx01, index 50 no BoneAni4.txt
```

**Isto requer recompilacao do cliente.** Nao ha como evitar — o mapeamento e
hardcoded no executavel.

#### 5.6 Registrar no servidor (ItemList)

O servidor define o `nClass` de cada mob/NPC no `ItemList.bin` ou na
tabela de mobs. O nClass e o que o cliente recebe no pacote e usa para
chamar `BASE_DefineSkinMeshType`.

#### 5.7 Colocar arquivos

```
Mesh\xx01.bon          — hierarquia
Mesh\xx010001.ani      — idle
Mesh\xx010002.ani      — walk
Mesh\xx010003.ani      — attack
Mesh\xx010101.msh      — mesh
Mesh\xx010101.wys      — textura
```

---

## 6. Plano de Implementacao: Encoders Faltantes

### 6.1 BONEncoder (FBX/GLTF/GLB → BON)

**Complexidade:** Baixa (formato trivial: pares de DWORDs)

**Input:** FBX ou GLTF/GLB com skeleton
**Output:** arquivo .bon

**Algoritmo (FBX path):**
1. Percorrer todos os FbxNode com FbxSkeleton attribute
2. Para cada bone, extrair o boneID do nome (`Bone_XXX` → XXX)
3. Para cada bone, determinar o parentID:
   - Root: parentID = 0xFFFFFFFF
   - Outros: parentID = boneID do pai
4. Escrever pares [parentID, boneID] em ordem (root primeiro, BFS)

**Algoritmo (GLTF/GLB path):**
1. Carregar documento GLTF com glTF SDK
2. Ler `doc.skins[0].jointIds` — lista de nodes que sao joints
3. Para cada joint node, extrair boneID do nome (`Bone_XXX` → XXX)
4. Para cada joint, determinar parentID pela hierarquia de nodes:
   - Se parent node nao esta em jointIds → root (0xFFFFFFFF)
   - Senao → boneID do parent node
5. Escrever pares [parentID, boneID]

**Arquivos a criar:**
- `Conversores/BON/BONEncoder.h` — declaracao
- `Conversores/BON/BONEncoder.cpp` — `FromFBX()` e `FromGLTF()` + `SaveBON()` compartilhado

**Estimativa:** ~120 linhas de codigo, 2-3 horas.

### 6.2 ANIEncoder (FBX/GLTF/GLB → ANI)

**Complexidade:** Media (precisa avaliar animacao por frame e extrair matrizes locais)

**Input:** FBX ou GLTF/GLB com skeleton + animation
**Output:** arquivo .ani

**Algoritmo (FBX path):**
1. Ler o FBX com FBX SDK
2. Determinar numBones (do skeleton) e numTicks (do animation stack)
3. Para cada tick (frame):
   a. Setar o tempo: `FbxTime::SetFrame(tick, eFrames30)`
   b. Para cada bone (por boneID, 0..numBones-1):
      - Avaliar `node->EvaluateLocalTransform(time)` → FbxAMatrix
      - Converter FbxAMatrix para XMFLOAT4X4
      - Se o FBX veio do WYDConverter: reverter anchor correction e scale
      - Se e novo conteudo: usar local transforms direto
   c. Gravar as numBones matrizes para este tick
4. Escrever header (numTicks, numBones) + todas as matrizes

**Algoritmo (GLTF/GLB path):**
1. Carregar documento GLTF com glTF SDK
2. Ler `doc.animations[0]` — channels e samplers
3. Determinar numTicks pelo max timestamp / (1/30) + 1
4. Para cada tick:
   a. Calcular tempo: `t = tick / 30.0f`
   b. Para cada bone:
      - Interpolar TRS dos samplers (translation, rotation, scale) no tempo t
      - Rotation: quaternion → matrix (GLTF usa quaternions nativamente)
      - Compor local matrix: S * R * T
      - Converter Y-Up → Z-Up (GLTF e Y-Up, ANI e Z-Up)
   c. Gravar as numBones matrizes
5. Escrever header + matrizes

**Cuidados comuns:**
- As matrizes no ANI sao LOCAL (relativas ao pai), nao world
- FBX: `EvaluateLocalTransform` ja retorna local
- GLTF: channels ja sao local (por spec)
- FBX Z-Up (nosso export) = WYD Z-Up → sem conversao
- GLTF Y-Up → precisa converter para Z-Up: conjugar cada local matrix
- Scale: matrizes ANI sao puras (rotacao + translacao)
  - Normalizar rotation columns para magnitude 1.0 antes de salvar
- Frame rate: WYD usa 30fps
- GLTF: samplers podem ter interpolacao LINEAR ou STEP
  - LINEAR: interpolar entre keyframes
  - STEP: usar valor anterior

**Arquivos a criar:**
- `Conversores/ANI/ANIEncoder.h` — declaracao
- `Conversores/ANI/ANIEncoder.cpp` — `FromFBX()`, `FromGLTF()` + `SaveANI()` compartilhado

**Estimativa:** ~350 linhas de codigo, 5-8 horas.

### 6.3 ValidIndexEditor (editor de ValidIndex.bin)

**Complexidade:** Baixa (array binario fixo, UI simples)

**Funcionalidade:**
- Carregar ValidIndex.bin (74400 bytes)
- Mostrar grid: skeleton index × ani slot → nI value
- Editar nI values
- Salvar ValidIndex.bin

**Integracao:** nova tab ou dialog no WYDConverter.

**Estimativa:** ~150 linhas, 2-3 horas.

### 6.4 BoneAni4Editor (editor de BoneAni4.txt)

**Complexidade:** Baixa (texto simples, UI simples)

**Funcionalidade:**
- Carregar BoneAni4.txt
- Mostrar tabela: index, numAniTypes, numParts, szAniName
- Adicionar/remover/editar linhas
- Salvar BoneAni4.txt

**Integracao:** mesma tab do ValidIndexEditor.

**Estimativa:** ~100 linhas, 1-2 horas.

### 6.5 MeshTextureListEditor (editor de MeshTextureList.bin)

**Complexidade:** Baixa (array binario fixo, ja temos decoder)

**Funcionalidade:**
- Carregar MeshTextureList.bin (auto-detecta classico 2048 vs Global 6096 slots)
- Mostrar tabela: index, szFileName, cAlpha
- Busca por nome (filtro)
- Adicionar textura em slot vazio (auto-encontrar proximo livre)
- Editar/remover entradas
- Salvar MeshTextureList.bin

**Nota:** Ja temos `MeshTextureListDecoder` com `LoadBIN`, `SaveBIN`, `LoadTXT`, `SaveTXT`.
O editor so precisa de UI — a logica de I/O ja existe.

**Integracao:** tab no DataEditor do WYDConverter.

**Estimativa:** ~120 linhas (UI apenas), 2-3 horas.

### 6.6 AniSound4Editor (editor de AniSound4.txt)

**Complexidade:** Baixa (texto formatado, parser simples)

**Funcionalidade:**
- Carregar AniSound4.txt
- Mostrar: skeleton type → 56 linhas (acao, aniIndex, speed, sound)
- Editar valores por celula
- Duplicar secao de skeleton existente (template para novo mob)
- Salvar AniSound4.txt

**Integracao:** mesma tab dos editores de registro.

**Estimativa:** ~150 linhas, 2-3 horas.

### 6.7 Ordem de Implementacao

```
Fase 1 — BONEncoder FBX + GLTF/GLB (2-3h)
  Permite: criar hierarquia de skeleton novo de qualquer formato
  Dependencias: nenhuma
  Teste: exportar mob existente MSH→FBX→BON e MSH→GLB→BON, comparar com original

Fase 2 — ANIEncoder FBX (3-5h)
  Permite: criar animacoes novas a partir de FBX
  Dependencias: nenhuma
  Teste: exportar mob existente MSH+ANI→FBX→ANI, comparar com original

Fase 3 — ANIEncoder GLTF/GLB (3-5h)
  Permite: criar animacoes novas a partir de GLTF/GLB
  Dependencias: SaveANI() da Fase 2
  Teste: exportar mob existente MSH+ANI→GLB→ANI, comparar com original
  Nota: GLTF usa quaternions + timestamps flutuantes (vs FBX Euler + frames fixos)
        Precisa: interpolacao de samplers, quat→matrix, Y-Up→Z-Up

Fase 4 — Editores de registro (5-8h)
  4a. BoneAni4Editor (1-2h) — ja temos parser
  4b. ValidIndexEditor (2-3h) — binario fixo
  4c. MeshTextureListEditor (2-3h) — ja temos LoadBIN/SaveBIN
  4d. AniSound4Editor (2-3h) — parser texto
  Permite: registrar skeleton, animacoes, texturas e sons
  Teste: adicionar entradas, verificar que cliente carrega

Fase 5 — Workflow integrado (3-4h)
  Batch: FBX/GLB → MSH + BON + ANI + WYS em um click
  Auto-registro: adiciona entradas nos 4 arquivos de registro
  UI: wizard "Novo Mob" no WYDConverter
  Validacao: checar limites (40 bones, 65535 verts, etc.)
  Suporte: arrastar FBX ou GLB, detectar conteudo automaticamente
```

**Total estimado: 18-27 horas de desenvolvimento.**

---

## 7. Checklist Final

### Para mob com skeleton existente:
- [ ] Exportar mob de referencia como FBX ou GLB
- [ ] Modelar novo mesh no DCC ao redor do skeleton
- [ ] Skin com max 4 influences, weights somam 1.0
- [ ] UV unwrap, textura potencia de 2
- [ ] Exportar FBX Binary Z-Up ou GLB
- [ ] Converter FBX/GLB → MSH no WYDConverter
- [ ] Converter textura → WYS
- [ ] Adicionar textura nova em MeshTextureList.bin (se textura nova)
- [ ] Copiar MSH + WYS para Mesh\ do cliente
- [ ] Testar in-game

### Para mob com skeleton novo:
- [ ] Tudo acima +
- [ ] Criar skeleton com bones `Bone_000` a `Bone_NNN`
- [ ] Criar animacoes (idle, walk, attack, death)
- [ ] Exportar FBX ou GLB por animacao
- [ ] Gerar BON via BONEncoder (FBX ou GLTF)
- [ ] Gerar ANIs via ANIEncoder (FBX ou GLTF)
- [ ] Editar BoneAni4.txt (adicionar linha com index, numAnis, numParts, prefixo)
- [ ] Editar ValidIndex.bin (mapear slots → nI para cada ANI)
- [ ] Editar MeshTextureList.bin (adicionar textura em slot vazio)
- [ ] Editar AniSound4.txt (adicionar secao com aniIndex/speed/sound por acao)
- [ ] Editar BASE_DefineSkinMeshType em Basedef.cpp (nClass → nBoneAniIndex)
- [ ] Registrar mob no servidor (ItemList: nClass + LOOK_INFO)
- [ ] Copiar BON + ANIs + MSH + WYS para Mesh\ do cliente
- [ ] Testar in-game

---

## 8. Criar Objetos Estaticos Novos (MSA)

Objetos MSA sao meshes estaticos SEM bones nem animacao. Usados para:
- Construcoes (casas, torres, portais, altares)
- Decoracoes de cenario (arvores, pedras, caixas, barris)
- Armas e itens de chao (espadas, escudos, pocoes)
- Efeitos estaticos (circulos, plataformas)

### 8.1 Diferenca entre MSH e MSA

| Aspecto | MSH (Skinned) | MSA (Static) |
|---|---|---|
| Bones/Skeleton | Sim (max 40) | Nao |
| Animacao | Sim (.ani + .bon) | Nao |
| Skinning/Weights | Sim (max 4 por vertice) | Nao |
| Multi-material | Nao (1 textura) | Sim (1-32 attribute ranges) |
| Diffuse color | Nao (FVF 274) | Opcional (FVF 322) |
| Uso tipico | Personagens, mobs, montarias | Cenario, itens, armas |

### 8.2 Sistema de registro MSA

MSA sao registrados via **MeshList.txt** — uma tabela texto simples:
```
{index} {path_relativo}

Exemplo:
0 mesh\cas001.msa
1 mesh\cas002.msa
2 mesh\tree01.msa
...
```

O index e o `dwObjType` que o engine usa para referenciar o objeto.
`GetCommonMesh(dwObjType)` busca o path no MeshList e chama `LoadMsa()`.

As texturas sao resolvidas de 2 formas:
1. Nome embeddado no MSA (campo de 11 bytes por attribute range)
2. Busca em MeshTextureList.bin por `mesh\{nomeBase}.wys`

### 8.3 Formatos de vertice MSA (FVF)

| FVF | Hex | Layout | Bytes | Uso |
|---|---|---|---|---|
| 274 | 0x112 | Position(12) + Normal(12) + UV(8) | 32 | Maioria dos objetos |
| 322 | 0x142 | Position(12) + Diffuse(4) + UV(8) | 24 | Objetos com vertex color |

**CRITICO:** o FVF deve ser preservado no round-trip. Converter um MSA de FVF 322
para FVF 274 QUEBRA a renderizacao no cliente (o engine trata 322 de forma especial).

### 8.4 Workflow: Criar MSA Novo

#### Passo 1 — Modelar

Crie o objeto no 3ds Max ou Blender:
- Apenas geometria (sem bones, sem skeleton)
- Triangulos apenas (sem quads/n-gons)
- Max 65.535 vertices
- Escala: 1 unidade = proporcional ao mundo WYD (exporte um objeto existente como referencia)

#### Passo 2 — Multi-material (opcional)

MSA suporta ate 32 materiais/texturas por mesh:
- Atribua materiais diferentes a grupos de faces
- Cada material pode ter sua propria textura
- Os attribute ranges sao preservados no round-trip

Para objetos simples, 1 material e suficiente.

#### Passo 3 — UV e Textura

- UV Unwrap normal
- Textura PNG ou TGA em potencia de 2 (256x256, 512x512)
- Para multi-material: 1 textura por material
- O WYDConverter converte PNG → WYS

#### Passo 4 — Exportar

No 3ds Max:
  File > Export > FBX Binary, Z-Up, Smoothing Groups ON

No Blender:
  File > Export > glTF 2.0 (.glb), +Y Up, Apply Modifiers ON

**NAO precisa** incluir Skin/Deformers (MSA e estatico).

#### Passo 5 — Converter no WYDConverter

1. Abrir o FBX ou GLB no WYDConverter
2. Dropdown "MSA" > "FBX -> MSA" (ou "GLB -> MSA")
3. Nomear: `cas999.msa` (ou qualquer nome livre)
4. Converter textura: PNG -> WYS: `cas999.wys`

#### Passo 6 — Registrar

**MeshList.txt** — adicionar linha:
```
{indexLivre} mesh\cas999.msa
```
O index deve ser um slot livre (0-3047, MAX_COMMON_MESH = 3048).

**MeshTextureList.bin** — adicionar textura:
```
Slot vazio → szFileName = "mesh\cas999.wys", cAlpha = 'N'
```

Para multi-material, adicionar CADA textura separadamente.

#### Passo 7 — Colocar e testar

```
Mesh\cas999.msa    ← mesh estatico
Mesh\cas999.wys    ← textura
```

O engine carrega via `GetCommonMesh(index)` quando o terreno
ou objeto referencia o `dwObjType` correspondente ao index.

Para testar: colocar o objeto em um mapa editando o .trn
(terrain file) com o index do MeshList.txt.

### 8.5 Checklist MSA

- [ ] Modelar objeto (sem bones, triangulos apenas)
- [ ] UV unwrap, textura potencia de 2
- [ ] Exportar FBX ou GLB (sem skeleton)
- [ ] Converter FBX/GLB → MSA no WYDConverter
- [ ] Converter textura → WYS
- [ ] Adicionar textura em MeshTextureList.bin
- [ ] Adicionar entrada em MeshList.txt (index + path)
- [ ] Copiar MSA + WYS para Mesh\ do cliente
- [ ] Testar no mapa (colocar objeto no .trn)
 

Editado por gcr_fc
  • Curtir 7

Discord: GuiCandiotto

Link para o comentário
Compartilhar em outros sites

11 horas atrás, gcr_fc disse:

no WYDConverter eu fiz uma área de tutorial e um deles é a criação de novos itens/mobs, veja se te ajuda. copia e crie um .md pode ser no próprio VS que vai ficar bem mais legível.
 

# Guia: Criar Mobs, Objetos e Meshes Novos para o WYD

> Passo a passo completo para criar conteudo 3D novo e integrar no cliente WYD.
> Cobre mobs (MSH skinned), objetos estaticos (MSA), modelagem, exportacao,
> conversao e registro nos arquivos do cliente.

---

## 1. Sistema de Arquivos do WYD

### 1.1 Arquivos 3D por mob

| Arquivo | Exemplo | Conteudo | Formato |
|---|---|---|---|
| `.msh` | `nm010101.msh` | Mesh skinned (vertices, indices, bones, skinning) | Binario 32B header |
| `.bon` | `nm01.bon` | Hierarquia do esqueleto (pares parentID/boneID) | Binario 8B por bone |
| `.ani` | `nm010101.ani` | Animacao (matrizes 4x4 locais por bone por frame) | Binario 8B header + matrices |
| `.wys` | `nm010101.wys` | Textura DXT1 comprimida | Binario WYS |
| `.wyt` | `nm010101.wyt` | Textura BGRA raw (formato antigo) | Binario WYT |

### 1.2 Convencao de nomes

```
{prefixo}{PPVV}.ext

prefixo = skeleton type (4 chars): nm01, ch01, ch02, tr09, hs01...
PP       = parte/slot (2 digitos): 01=corpo, 02=helm, 03=armor...
VV       = visual/variante (2 digitos): 01=base, 02=alt...
```

**Regra critica:** os primeiros 4 caracteres definem o skeleton. Todos os arquivos
com mesmo prefixo compartilham o mesmo `.bon` e os mesmos `.ani`.

Exemplos:
- `nm010101.msh`, `nm010102.msh` → usam `nm01.bon`
- `ch010597.msh` → usa `ch01.bon`, slot 05 (luva), visual 97

### 1.3 Arquivos de registro do cliente

Estes arquivos precisam ser editados para o cliente reconhecer mobs novos.

| Arquivo | Path | Funcao | Editar quando |
|---|---|---|---|
| `BoneAni4.txt` | `Mesh\BoneAni4.txt` | Registra skeletons: index, num ANIs, num partes, prefixo | Skeleton NOVO |
| `ValidIndex.bin` | `Mesh\ValidIndex.bin` | Mapeia quais ANIs existem para cada skeleton | Skeleton NOVO |
| `MeshTextureList.bin` | `Mesh\MeshTextureList.bin` | Tabela de texturas de meshes (nome → index) | Textura NOVA |
| `MeshList.txt` | `Mesh\MeshList.txt` | Registra objetos estaticos MSA: index → path | MSA NOVO |
| `AniSound4.txt` | `AniSound4.txt` | Tabela de animacoes/velocidades/sons por skeleton type | Skeleton NOVO |
| `ItemList.bin` | Server-side | Define nClass do mob → mapeia para skeleton via `BASE_DefineSkinMeshType` | Mob NOVO |
| `Basedef.cpp` | Compilado no .exe | `BASE_DefineSkinMeshType(nClass)` → nBoneAniIndex (hardcoded switch) | Skeleton NOVO (recompilacao) |

**Para mob com skeleton EXISTENTE:** nenhum destes arquivos precisa ser editado.
Basta colocar o MSH + WYS na pasta `Mesh\` com o prefixo correto.

**Para mob com skeleton NOVO:** todos os arquivos acima precisam ser editados.

---

## 2. Formatos Binarios Detalhados

### 2.1 MSH (Mesh Skinned)

```
Header (32 bytes):
  [00] DWORD dwParentID        — ID do bone pai (0xFFFFFFFF = root)
  [04] DWORD dwMeshID          — ID do bone deste mesh
  [08] DWORD dwFVF             — Flexible Vertex Format (D3D9)
  [0C] DWORD sizeVertex        — Bytes por vertice
  [10] DWORD numFaceInfluence   — Numero de face influences
  [14] DWORD numPalette        — Numero de bones na palette
  [18] DWORD vertexCount       — Numero de vertices
  [1C] DWORD faceCount         — Numero de INDICES (nao faces!)

Bones (se numPalette > 0):
  XMFLOAT4X4[numPalette]       — Offset matrices (64 bytes cada)
  DWORD[numPalette]             — Bone IDs (4 bytes cada)

Vertices:
  Layout depende do FVF. Tipico para skinned:
    Position XYZ (12B) + BlendWeights (4-12B) + PackedBoneIndices (4B)
    + Normal (12B) + UV (8B)

Indices:
  uint16[faceCount]             — Index buffer 16-bit
```

### 2.2 BON (Bone Hierarchy)

```
Arquivo = array de pares (8 bytes cada):
  [parentID: DWORD] [boneID: DWORD]

parentID = 0xFFFFFFFF ou 0 → root (sem pai)
parentID = N → bone filho de bone N

Tamanho total = numBones * 8 bytes
```

Exemplo para esqueleto com 5 bones:
```
[0xFFFFFFFF] [0]    — Bone 0 e root
[0]          [1]    — Bone 1 filho de Bone 0
[0]          [2]    — Bone 2 filho de Bone 0
[1]          [3]    — Bone 3 filho de Bone 1
[1]          [4]    — Bone 4 filho de Bone 1
```

### 2.3 ANI (Animation)

```
Header (8 bytes):
  [00] DWORD numTicks    — Numero de keyframes (frames de animacao)
  [04] DWORD numBones    — Numero de bones no skeleton

Dados:
  Para cada tick (0..numTicks-1):
    XMFLOAT4X4[numBones]  — Matriz LOCAL de cada bone neste frame (64 bytes cada)

Tamanho total = 8 + (numTicks * numBones * 64) bytes
```

As matrizes sao LOCAL (relativas ao pai na hierarquia BON).
O cliente propaga pela hierarquia para obter as combined (world) matrices:
`combined[bone] = local[bone] * combined[parent]`

### 2.4 BoneAni4.txt

```
Formato texto, uma linha por skeleton:
{index} {numAniTypes} {numParts} {szAniName}

Campos:
  index         — Indice no array m_BoneAnimationList (0-99)
  numAniTypes   — Quantos ANIs diferentes este skeleton tem
  numParts      — Quantos slots de equipamento (1 para mobs simples, 7 para players)
  szAniName     — Prefixo completo com path (ex: mesh\nm01, mesh\ch01)
```

Exemplo:
```
0 38 7 mesh\ch01      <- personagem masculino, 38 animacoes, 7 partes
1 37 7 mesh\ch02      <- personagem feminino
2  1 1 mesh\hs01      <- cavalo, 1 animacao, 1 parte
3  2 1 mesh\nm01      <- mob tipo 1, 2 animacoes, 1 parte
...
```

### 2.5 ValidIndex.bin

```
Array binario fixo:
  stValidAniList[100][186]

  stValidAniList = struct { int nI; }  — 4 bytes

Tamanho total = 100 * 186 * 4 = 74.400 bytes

Indexacao:
  m_stValidAniList[skeletonIndex][aniSlot].nI = aniFileIndex

O cliente usa nI+1 para montar o nome do ANI:
  sprintf(szTemp, "%s%04d.ani", szAniName, m_stValidAniList[nCount][nFI].nI + 1)

Exemplo:
  m_stValidAniList[3][0].nI = 0   → mesh\nm010001.ani (idle)
  m_stValidAniList[3][1].nI = 1   → mesh\nm010002.ani (walk)
  m_stValidAniList[3][2].nI = 100 → mesh\nm010101.ani (arma 01, idle)
```

Codificacao dos 4 digitos do ANI:
```
XXYY onde:
  XX = tipo de arma (weapon): nArrayIndex / 100 - 1
  YY = tipo de acao (motion): nArrayIndex % 100 - 1

Exemplos (nI+1 → arquivo):
  0001 → arma 0, acao 0 (idle)
  0002 → arma 0, acao 1 (walk)
  0003 → arma 0, acao 2 (run)
  0004 → arma 0, acao 3 (attack1)
  0101 → arma 1, acao 0 (idle com espada)
```

### 2.6 MeshList.txt

```
Formato texto, uma linha por objeto estatico:
{index} {path_relativo}

Campos:
  index          — Indice no array m_stCommonMesh (0-3047)
  path_relativo  — Caminho do MSA relativo ao diretorio do cliente
```

Exemplo:
```
0 mesh\cas001.msa
1 mesh\cas002.msa
50 mesh\tree01.msa
100 mesh\sword01.msa
```

O engine chama `GetCommonMesh(dwObjType)` onde dwObjType = index.
Mapas (.trn) referenciam objetos pelo dwObjType.

### 2.7 MeshTextureList.bin

```
Array binario fixo de stTextureListInfo (264 bytes cada):
  char szFileName[255]      — path relativo da textura (ex: "mesh\nm010101.wys")
  char cAlpha               — tipo de alpha: 'N'=none, 'A'=alpha, 'a'=1bit, 'C'=compressed
  DWORD dwLastUsedTime      — runtime (ignorar, preencher com 0)
  DWORD dwShowTime          — runtime (ignorar, preencher com 0)

Tamanho por versao:
  TMProject classico: 2048 slots = 540.672 bytes
  WYD Global:         6096 slots = 1.609.344 bytes
```

O cliente busca textura por nome (`GetModelTextureIndex`): percorre TODOS os slots
comparando `szFileName` com o nome calculado pelo `TMSkinMesh`. Se nao encontra,
o mesh **NAO CARREGA** (retorna erro).

**Para adicionar textura nova:**
1. Encontrar um slot vazio (szFileName[0] == '\0')
2. Preencher szFileName com path relativo (ex: `mesh\xx010101.wys`)
3. Preencher cAlpha com 'N' (sem alpha) ou 'A' (com alpha)
4. dwLastUsedTime e dwShowTime = 0

### 2.8 AniSound4.txt

```
Formato texto. Uma secao por skeleton type (MAX_ANI_TYPE = 60 skeletons).
Cada secao tem 56 linhas (MAX_ANI_MOTION), uma por tipo de acao.

Para skeleton types 0 e 1 (players):
  {nomeAcao} {ani0} {speed0} {ani1} {speed1} {ani2} {speed2} {ani3} {speed3} {sound}

Para skeleton types 2+ (mobs/NPCs):
  {nomeAcao} {aniIndex} {speed} {sound}

Campos:
  nomeAcao  — label (ex: "IDLE", "WALK", "ATK1") — ignorado pelo parser
  aniIndex  — indice na lista de animacoes do skeleton (posicao no array concatenado)
  speed     — velocidade da animacao (ticks por frame)
  sound     — indice do som a tocar
```

Controla qual animacao tocar para cada acao do mob (idle, walk, attack, death, etc.)
e a velocidade de reproducao. Se o skeleton novo for um mob simples, basta preencher
as acoes basicas (idle=0, walk=1, attack=2, death=3).

### 2.9 Fluxo de resolucao no cliente

```
Servidor envia pacote com mob → nClass (tipo do mob)
        ↓
BASE_DefineSkinMeshType(nClass) → nBoneAniIndex (switch hardcoded em Basedef.cpp)
        ↓
BoneAni4.txt[nBoneAniIndex] → szAniName (ex: "mesh\nm01"), numParts, numAniTypes
        ↓
Skeleton:  szAniName + ".bon"                    → mesh\nm01.bon
Mesh:      szAniName + PPVV + ".msh"             → mesh\nm010101.msh
Textura:   szAniName + PPVV + ".wys"             → mesh\nm010101.wys
           → GetModelTextureIndex(texName)       → busca em MeshTextureList.bin
Animacao:  ValidIndex.bin[nBoneAniIndex][slot]    → nI+1 → mesh\nm010001.ani
           → AniSound4.txt[nBoneAniIndex]        → mapeia acao → indice de animacao
```

### 2.10 STRUCT_ITEMLIST (ItemList.bin)

```
Struct STRUCT_ITEMLIST — 120 bytes por item:
  char Name[64]                  — Nome do item
  short nIndexMesh               — Indice visual do mesh
  short nIndexTexture            — Indice visual da textura
  short nIndexVisualEffect       — Efeito visual (brilho, aura)
  short nReqLvl                  — Nivel minimo
  short nReqStr / nReqInt /      — Requisitos de atributo
        nReqDex / nReqCon
  STRUCT_STATICEFFECT stEffect[12] — 12 efeitos estaticos (4 bytes cada)
  int nPrice                     — Preco do item
  short nUnique                  — Tipo de raridade
  short nPos                     — Bitmask de slots onde pode equipar
  short nExtra                   — Dados extras
  short nGrade                   — Grau/rank do item
```

**nIndexMesh e nIndexTexture** sao os campos que conectam o item ao mesh visual.
O significado muda COMPLETAMENTE dependendo do tipo de item:

**ARMAS E ESCUDOS (slots 6 e 7 — MSA):**
  nIndexMesh = indice DIRETO no MeshList.txt
  O cliente chama: GetCommonMesh(nIndexMesh) → LoadMsa(MeshList[nIndexMesh])
  Nenhuma formula intermediaria. Se a arma esta no index 500 do MeshList,
  nIndexMesh = 500.
  nIndexTexture = preenche LOOK_INFO.SkinX mas NAO e usado para renderizar
  a arma 3D. A textura da arma vem do nome embeddado no MSA → MeshTextureList.
  Na pratica, para armas, nIndexTexture = 0.

**EQUIPAMENTOS SKINNED (slots 0-5 — MSH):**
  nIndexMesh = variante visual usada na FORMULA do nome do MSH:
    sprintf("%s%02d%02d.msh", szAniName, slot+1, nIndexMesh + offset + 1)
  NAO e um indice de MeshList. E um numero de variante (0, 1, 2...).
  Exemplo: nIndexMesh=5 no slot coat → ch010306.msh (prefixo + slot03 + visual06)

  nIndexTexture = modificador de textura na FORMULA do nome da WYS:
    sprintf("%s%02d%02d.wys", szAniName, slot+1, (nIndexTexture & 0xFFF) + nIndexMesh + offset + 1)
  Permite usar texturas diferentes para o mesmo mesh visual.
  Exemplo: nIndexMesh=5, nIndexTexture=2 + 1 → ch010308.wys

**MONTARIAS (slot 14 — MSH skinned, skeleton proprio):**
  O item de montaria fica em Equip[14].
  sIndex do item → transformado (sIndex - 2045, com overrides hardcoded)
  → sIndex final usado como indice no g_pItemList:
    nIndexMesh = g_pItemList[sIndex].nIndexMesh → Mesh0 (variante visual)
    nIndexTexture = g_pItemList[sIndex].nIndexTexture → Skin0 (variante textura)
    nClass (efeito 18) → BASE_DefineSkinMeshType(nClass) → skeleton da montaria
  Funciona igual a equipamentos skinned: nIndexMesh e variante visual,
  NAO indice do MeshList. Vem do ItemList.bin.

**nPos** — bitmask de slots de equipamento:
```
  Bit 0 (0x01) = Slot 0: Face/Corpo
  Bit 1 (0x02) = Slot 1: Helm (elmo)
  Bit 2 (0x04) = Slot 2: Coat (armadura)
  Bit 3 (0x08) = Slot 3: Pants (calca)
  Bit 4 (0x10) = Slot 4: Gloves (luva)
  Bit 5 (0x20) = Slot 5: Boots (bota)
  Bit 6 (0x40) = Slot 6: Left (mao esq/escudo)
  Bit 7 (0x80) = Slot 7: Right (mao dir/arma)
```

**nClass (efeito 18)** — tipo de classe que determina o skeleton:
  Usado por `BASE_DefineSkinMeshType(nClass)` para mobs e montarias.
  Para players: nClass 1/4 = masculino (ch01), 2/8 = feminino (ch02).
  Para mobs: nClass 16-74 mapeiam para indices 2-57 no BoneAni4.txt.

### 2.11 Fluxo visual de armas

```
Item no Equip[7] (mao direita) ou Equip[6] (mao esquerda)
        ↓
g_pItemList[sIndex].nIndexMesh → nIndexMesh
        ↓
GetCommonMesh(nIndexMesh)   ← DIRETO, sem formula intermediaria!
        ↓
MeshList.txt[nIndexMesh] → path do MSA (ex: mesh\wp001.msa)
        ↓
TMMesh::LoadMsa(path) → carrega MSA
        ↓
Textura: nome embeddado no MSA → GetModelTextureIndex → MeshTextureList.bin
```

### 2.12 Fluxo visual de equipamentos (armaduras, helmos, etc.)

```
Item no Equip[0-5] (face, helm, coat, pants, gloves, boots)
        ↓
g_pItemList[sIndex].nIndexMesh → LOOK_INFO.MeshX (variante)
g_pItemList[sIndex].nIndexTexture → LOOK_INFO.SkinX (textura mod)
        ↓
TMSkinMesh monta nome do arquivo:
  Mesh: sprintf("%s%02d%02d.msh", szAniName, slot+1, MeshX + offset + 1)
  Tex:  sprintf("%s%02d%02d.wys", szAniName, slot+1, (SkinX & 0xFFF) + MeshX + offset + 1)
        ↓
Exemplo: ch01, slot 3 (coat), nIndexMesh=5, nIndexTexture=0
  Mesh: ch010306.msh
  Tex:  ch010306.wys
```

---

## 3. Restricoes Tecnicas do Cliente

### 3.1 MSH (Skinned Meshes)

| Item | Limite | Origem |
|---|---|---|
| Bones por mesh | 40 max | `safePalette = min(n, 40)` em CMesh |
| Influences por vertice | 4 max | FVF XYZB1-B4 + LASTBETA_UBYTE4 |
| Vertices por mesh | 65535 max | Indices 16-bit no MSH |
| Textura por mesh | 1 | MSH nao tem attribute ranges |
| Textura dimensao | Potencia de 2 | DXT1 |
| Coordenadas | Z-Up | Nativo WYD |
| UV | V=0 no topo (D3D) | Nativo WYD e 3ds Max |
| Skeletons registrados | 100 max | MAX_BONE_ANIMATION_LIST |
| ANIs por skeleton | 186 max | Array fixo ValidAniList |
| Bones por skeleton | Sem limite hard | Limitado pela RAM |

### 3.2 MSA (Static Meshes)

| Item | Limite | Origem |
|---|---|---|
| Vertices por mesh | 65535 max | Indices 16-bit |
| Materiais por mesh | 32 max | dwAttCount no header |
| Texturas por material | 1 | Uma WYS por attribute range |
| Textura dimensao | Potencia de 2 | DXT1 |
| Coordenadas | Z-Up | Nativo WYD |
| UV | V=0 no topo (D3D) | Nativo WYD |
| Objetos em MeshList | 3048 max | MAX_COMMON_MESH |
| FVF suportados | 274 (normal) ou 322 (diffuse) | Engine hardcoded |

---

## 4. Workflow: Novo Mob com Skeleton Existente

**Cenario:** criar um mob novo que reutiliza o esqueleto e animacoes de um mob existente.
Este e o caminho mais rapido e seguro.

### Passo 1 — Exportar mob de referencia

No WYDConverter, abrir o MSH do mob que quer reusar (ex: `nm010101.msh`).
Exportar como FBX (target 3ds Max). O FBX contem:
- Geometria do mob original
- Esqueleto completo com bone IDs
- Animacao do ANI companion
- Textura companion como PNG

### Passo 2 — Importar no 3ds Max

Importar o FBX. O mesh aparece:
- Z-Up (nativo do Max e do WYD — sem conversao)
- Escala amplificada (conversor aplica x100 para edicao confortavel)
- Bones com nomes `Bone_000`, `Bone_001`, etc.

**NAO mover, rotacionar ou escalar o Armature.** A posicao dos bones e o bind pose
que as animacoes existentes esperam.

### Passo 3 — Modelar

- Deletar a geometria do mob original (so poligonos, NAO os bones)
- Modelar o novo mob ao redor do esqueleto existente
- Manter o mesh alinhado com os bones na posicao de bind

Regras:
- Apenas triangulos (sem quads/n-gons)
- Max 65535 vertices
- 1 material/textura por mesh
- Polycount razoavel (~500-3000 tris para mobs)

### Passo 4 — Skinning

- Aplicar Skin modifier no mesh
- Adicionar os bones do esqueleto importado
- Pintar weights: max 4 influences por vertice
- Weights devem somar 1.0
- Todo vertice deve ter pelo menos 1 bone com peso > 0

### Passo 5 — UV e Textura

- UV Unwrap no Max (UV convention D3D: V=0 topo — default do Max)
- Textura PNG/TGA em potencia de 2 (256x256 ou 512x512)
- O WYDConverter converte para WYS automaticamente

### Passo 6 — Exportar FBX

File → Export → FBX:
- Formato: FBX Binary
- Eixos: Z-Up (default Max)
- Smoothing Groups: ON
- Skin/Deformers: ON
- Embed Media: OFF

### Passo 7 — Converter

No WYDConverter:
1. Abrir o FBX exportado
2. Converter para MSH
3. Nomear: `nm010199.msh` (mesmo prefixo, numero livre)
4. Converter textura PNG → WYS: `nm010199.wys`
5. Copiar para `Mesh\` do cliente

### Passo 8 — Testar

O cliente carrega automaticamente:
- `nm010199.msh` — mesh novo
- `nm01.bon` — hierarquia (ja existe)
- `nm010001.ani` etc — animacoes (ja existem)
- `nm010199.wys` — textura nova

Nenhuma edicao de BoneAni4.txt ou ValidIndex.bin necessaria (mesmo skeleton).

---

## 5. Workflow: Mob com Skeleton e Animacoes Novas

**Cenario:** criar um mob completamente novo com esqueleto e animacoes proprias.
Requer ferramentas adicionais e edicao de arquivos de registro.

### Passo 1 — Modelar e Riggar no 3ds Max

- Modelar o mob
- Criar esqueleto com bones (usar nomes `Bone_000`, `Bone_001`, etc.)
- Bone 0 deve ser o root
- Max 40 bones
- Skin modifier com max 4 influences

### Passo 2 — Criar Animacoes

No 3ds Max, criar as animacoes necessarias:
- Idle (parado)
- Walk (andando)
- Run (correndo)
- Attack (atacando)
- Death (morrendo)
- etc.

Cada animacao sera exportada como um FBX separado (ou ranges no mesmo FBX).

### Passo 3 — Exportar

Exportar cada animacao como arquivo separado com mesh + skeleton + animation.
Formatos suportados:
- **FBX Binary** (3ds Max, Maya, Blender via plugin)
- **GLB/GLTF** (Blender nativo, qualquer DCC moderno)

### Passo 4 — Converter

Usar o WYDConverter para gerar:

| De | Para | Ferramenta | Status |
|---|---|---|---|
| FBX mesh | `.msh` | MSHEncoder (FBX→MSH) | Funciona |
| GLB/GLTF mesh | `.msh` | MSHEncoder (GLTF→MSH) | Funciona |
| FBX skeleton | `.bon` | **BONEncoder (FBX)** | NAO EXISTE |
| GLB/GLTF skeleton | `.bon` | **BONEncoder (GLTF)** | NAO EXISTE |
| FBX animation | `.ani` | **ANIEncoder (FBX)** | NAO EXISTE |
| GLB/GLTF animation | `.ani` | **ANIEncoder (GLTF)** | NAO EXISTE |
| PNG textura | `.wys` | WYSEncoder | Funciona |

### Passo 5 — Registrar no cliente

Para um skeleton completamente novo, TODOS estes arquivos precisam ser editados:

#### 5.1 Editar BoneAni4.txt

Adicionar uma linha para o novo skeleton:
```
{novoIndex} {numAnis} {numParts} mesh\{prefixo}
```

Exemplo: adicionar mob `xx01` com 3 animacoes, 1 parte:
```
50 3 1 mesh\xx01
```

O index (50) deve ser um slot livre no array (0-99).

#### 5.2 Editar ValidIndex.bin

Adicionar as entradas para mapear os ANIs do novo skeleton:
```
m_stValidAniList[50][0].nI = 0    → mesh\xx010001.ani (idle)
m_stValidAniList[50][1].nI = 1    → mesh\xx010002.ani (walk)
m_stValidAniList[50][2].nI = 2    → mesh\xx010003.ani (attack)
```

O ValidIndex.bin e um array binario fixo de 74400 bytes.
Offset para skeleton index N = N * 186 * 4 bytes.
Cada slot = 4 bytes (int).

#### 5.3 Editar MeshTextureList.bin

Adicionar a textura do novo mob em um slot vazio:
```
Slot livre → szFileName = "mesh\xx010101.wys", cAlpha = 'N'
```

**CRITICO:** sem esta entrada, o cliente NAO encontra a textura e o mesh nao carrega.
O `GetModelTextureIndex` faz busca linear por nome — se nao encontra, retorna -1,
e o CMesh aborta o carregamento.

Para encontrar slots vazios: qualquer entrada com `szFileName[0] == '\0'`.
Cada slot tem 264 bytes. Para editar diretamente no binario:
```
Offset = slotIndex * 264
  [+0..+254]   = szFileName (null-terminated, zero-padded)
  [+255]       = cAlpha ('N' ou 'A')
  [+256..+259] = dwLastUsedTime (0)
  [+260..+263] = dwShowTime (0)
```

#### 5.4 Editar AniSound4.txt

Adicionar uma secao para o novo skeleton type.
A posicao na lista corresponde ao nBoneAniIndex.

Para mob simples (56 linhas, formato `{nome} {aniIdx} {speed} {sound}`):
```
TYPE50
IDLE     0 30 0
WALK     1 30 0
RUN      1 20 0
ATK1     2 25 0
ATK2     2 25 0
DEATH    2 30 0
...      (preencher restante com 0 0 0)
```

#### 5.5 Editar BASE_DefineSkinMeshType (recompilacao)

Em `Basedef.cpp`, a funcao `BASE_DefineSkinMeshType(nClass)` e um switch hardcoded
que mapeia o nClass do item/mob → nBoneAniIndex.

Para adicionar um novo mob com nClass=75:
```cpp
case 75:
    return 50;  // nosso novo skeleton xx01, index 50 no BoneAni4.txt
```

**Isto requer recompilacao do cliente.** Nao ha como evitar — o mapeamento e
hardcoded no executavel.

#### 5.6 Registrar no servidor (ItemList)

O servidor define o `nClass` de cada mob/NPC no `ItemList.bin` ou na
tabela de mobs. O nClass e o que o cliente recebe no pacote e usa para
chamar `BASE_DefineSkinMeshType`.

#### 5.7 Colocar arquivos

```
Mesh\xx01.bon          — hierarquia
Mesh\xx010001.ani      — idle
Mesh\xx010002.ani      — walk
Mesh\xx010003.ani      — attack
Mesh\xx010101.msh      — mesh
Mesh\xx010101.wys      — textura
```

---

## 6. Plano de Implementacao: Encoders Faltantes

### 6.1 BONEncoder (FBX/GLTF/GLB → BON)

**Complexidade:** Baixa (formato trivial: pares de DWORDs)

**Input:** FBX ou GLTF/GLB com skeleton
**Output:** arquivo .bon

**Algoritmo (FBX path):**
1. Percorrer todos os FbxNode com FbxSkeleton attribute
2. Para cada bone, extrair o boneID do nome (`Bone_XXX` → XXX)
3. Para cada bone, determinar o parentID:
   - Root: parentID = 0xFFFFFFFF
   - Outros: parentID = boneID do pai
4. Escrever pares [parentID, boneID] em ordem (root primeiro, BFS)

**Algoritmo (GLTF/GLB path):**
1. Carregar documento GLTF com glTF SDK
2. Ler `doc.skins[0].jointIds` — lista de nodes que sao joints
3. Para cada joint node, extrair boneID do nome (`Bone_XXX` → XXX)
4. Para cada joint, determinar parentID pela hierarquia de nodes:
   - Se parent node nao esta em jointIds → root (0xFFFFFFFF)
   - Senao → boneID do parent node
5. Escrever pares [parentID, boneID]

**Arquivos a criar:**
- `Conversores/BON/BONEncoder.h` — declaracao
- `Conversores/BON/BONEncoder.cpp` — `FromFBX()` e `FromGLTF()` + `SaveBON()` compartilhado

**Estimativa:** ~120 linhas de codigo, 2-3 horas.

### 6.2 ANIEncoder (FBX/GLTF/GLB → ANI)

**Complexidade:** Media (precisa avaliar animacao por frame e extrair matrizes locais)

**Input:** FBX ou GLTF/GLB com skeleton + animation
**Output:** arquivo .ani

**Algoritmo (FBX path):**
1. Ler o FBX com FBX SDK
2. Determinar numBones (do skeleton) e numTicks (do animation stack)
3. Para cada tick (frame):
   a. Setar o tempo: `FbxTime::SetFrame(tick, eFrames30)`
   b. Para cada bone (por boneID, 0..numBones-1):
      - Avaliar `node->EvaluateLocalTransform(time)` → FbxAMatrix
      - Converter FbxAMatrix para XMFLOAT4X4
      - Se o FBX veio do WYDConverter: reverter anchor correction e scale
      - Se e novo conteudo: usar local transforms direto
   c. Gravar as numBones matrizes para este tick
4. Escrever header (numTicks, numBones) + todas as matrizes

**Algoritmo (GLTF/GLB path):**
1. Carregar documento GLTF com glTF SDK
2. Ler `doc.animations[0]` — channels e samplers
3. Determinar numTicks pelo max timestamp / (1/30) + 1
4. Para cada tick:
   a. Calcular tempo: `t = tick / 30.0f`
   b. Para cada bone:
      - Interpolar TRS dos samplers (translation, rotation, scale) no tempo t
      - Rotation: quaternion → matrix (GLTF usa quaternions nativamente)
      - Compor local matrix: S * R * T
      - Converter Y-Up → Z-Up (GLTF e Y-Up, ANI e Z-Up)
   c. Gravar as numBones matrizes
5. Escrever header + matrizes

**Cuidados comuns:**
- As matrizes no ANI sao LOCAL (relativas ao pai), nao world
- FBX: `EvaluateLocalTransform` ja retorna local
- GLTF: channels ja sao local (por spec)
- FBX Z-Up (nosso export) = WYD Z-Up → sem conversao
- GLTF Y-Up → precisa converter para Z-Up: conjugar cada local matrix
- Scale: matrizes ANI sao puras (rotacao + translacao)
  - Normalizar rotation columns para magnitude 1.0 antes de salvar
- Frame rate: WYD usa 30fps
- GLTF: samplers podem ter interpolacao LINEAR ou STEP
  - LINEAR: interpolar entre keyframes
  - STEP: usar valor anterior

**Arquivos a criar:**
- `Conversores/ANI/ANIEncoder.h` — declaracao
- `Conversores/ANI/ANIEncoder.cpp` — `FromFBX()`, `FromGLTF()` + `SaveANI()` compartilhado

**Estimativa:** ~350 linhas de codigo, 5-8 horas.

### 6.3 ValidIndexEditor (editor de ValidIndex.bin)

**Complexidade:** Baixa (array binario fixo, UI simples)

**Funcionalidade:**
- Carregar ValidIndex.bin (74400 bytes)
- Mostrar grid: skeleton index × ani slot → nI value
- Editar nI values
- Salvar ValidIndex.bin

**Integracao:** nova tab ou dialog no WYDConverter.

**Estimativa:** ~150 linhas, 2-3 horas.

### 6.4 BoneAni4Editor (editor de BoneAni4.txt)

**Complexidade:** Baixa (texto simples, UI simples)

**Funcionalidade:**
- Carregar BoneAni4.txt
- Mostrar tabela: index, numAniTypes, numParts, szAniName
- Adicionar/remover/editar linhas
- Salvar BoneAni4.txt

**Integracao:** mesma tab do ValidIndexEditor.

**Estimativa:** ~100 linhas, 1-2 horas.

### 6.5 MeshTextureListEditor (editor de MeshTextureList.bin)

**Complexidade:** Baixa (array binario fixo, ja temos decoder)

**Funcionalidade:**
- Carregar MeshTextureList.bin (auto-detecta classico 2048 vs Global 6096 slots)
- Mostrar tabela: index, szFileName, cAlpha
- Busca por nome (filtro)
- Adicionar textura em slot vazio (auto-encontrar proximo livre)
- Editar/remover entradas
- Salvar MeshTextureList.bin

**Nota:** Ja temos `MeshTextureListDecoder` com `LoadBIN`, `SaveBIN`, `LoadTXT`, `SaveTXT`.
O editor so precisa de UI — a logica de I/O ja existe.

**Integracao:** tab no DataEditor do WYDConverter.

**Estimativa:** ~120 linhas (UI apenas), 2-3 horas.

### 6.6 AniSound4Editor (editor de AniSound4.txt)

**Complexidade:** Baixa (texto formatado, parser simples)

**Funcionalidade:**
- Carregar AniSound4.txt
- Mostrar: skeleton type → 56 linhas (acao, aniIndex, speed, sound)
- Editar valores por celula
- Duplicar secao de skeleton existente (template para novo mob)
- Salvar AniSound4.txt

**Integracao:** mesma tab dos editores de registro.

**Estimativa:** ~150 linhas, 2-3 horas.

### 6.7 Ordem de Implementacao

```
Fase 1 — BONEncoder FBX + GLTF/GLB (2-3h)
  Permite: criar hierarquia de skeleton novo de qualquer formato
  Dependencias: nenhuma
  Teste: exportar mob existente MSH→FBX→BON e MSH→GLB→BON, comparar com original

Fase 2 — ANIEncoder FBX (3-5h)
  Permite: criar animacoes novas a partir de FBX
  Dependencias: nenhuma
  Teste: exportar mob existente MSH+ANI→FBX→ANI, comparar com original

Fase 3 — ANIEncoder GLTF/GLB (3-5h)
  Permite: criar animacoes novas a partir de GLTF/GLB
  Dependencias: SaveANI() da Fase 2
  Teste: exportar mob existente MSH+ANI→GLB→ANI, comparar com original
  Nota: GLTF usa quaternions + timestamps flutuantes (vs FBX Euler + frames fixos)
        Precisa: interpolacao de samplers, quat→matrix, Y-Up→Z-Up

Fase 4 — Editores de registro (5-8h)
  4a. BoneAni4Editor (1-2h) — ja temos parser
  4b. ValidIndexEditor (2-3h) — binario fixo
  4c. MeshTextureListEditor (2-3h) — ja temos LoadBIN/SaveBIN
  4d. AniSound4Editor (2-3h) — parser texto
  Permite: registrar skeleton, animacoes, texturas e sons
  Teste: adicionar entradas, verificar que cliente carrega

Fase 5 — Workflow integrado (3-4h)
  Batch: FBX/GLB → MSH + BON + ANI + WYS em um click
  Auto-registro: adiciona entradas nos 4 arquivos de registro
  UI: wizard "Novo Mob" no WYDConverter
  Validacao: checar limites (40 bones, 65535 verts, etc.)
  Suporte: arrastar FBX ou GLB, detectar conteudo automaticamente
```

**Total estimado: 18-27 horas de desenvolvimento.**

---

## 7. Checklist Final

### Para mob com skeleton existente:
- [ ] Exportar mob de referencia como FBX ou GLB
- [ ] Modelar novo mesh no DCC ao redor do skeleton
- [ ] Skin com max 4 influences, weights somam 1.0
- [ ] UV unwrap, textura potencia de 2
- [ ] Exportar FBX Binary Z-Up ou GLB
- [ ] Converter FBX/GLB → MSH no WYDConverter
- [ ] Converter textura → WYS
- [ ] Adicionar textura nova em MeshTextureList.bin (se textura nova)
- [ ] Copiar MSH + WYS para Mesh\ do cliente
- [ ] Testar in-game

### Para mob com skeleton novo:
- [ ] Tudo acima +
- [ ] Criar skeleton com bones `Bone_000` a `Bone_NNN`
- [ ] Criar animacoes (idle, walk, attack, death)
- [ ] Exportar FBX ou GLB por animacao
- [ ] Gerar BON via BONEncoder (FBX ou GLTF)
- [ ] Gerar ANIs via ANIEncoder (FBX ou GLTF)
- [ ] Editar BoneAni4.txt (adicionar linha com index, numAnis, numParts, prefixo)
- [ ] Editar ValidIndex.bin (mapear slots → nI para cada ANI)
- [ ] Editar MeshTextureList.bin (adicionar textura em slot vazio)
- [ ] Editar AniSound4.txt (adicionar secao com aniIndex/speed/sound por acao)
- [ ] Editar BASE_DefineSkinMeshType em Basedef.cpp (nClass → nBoneAniIndex)
- [ ] Registrar mob no servidor (ItemList: nClass + LOOK_INFO)
- [ ] Copiar BON + ANIs + MSH + WYS para Mesh\ do cliente
- [ ] Testar in-game

---

## 8. Criar Objetos Estaticos Novos (MSA)

Objetos MSA sao meshes estaticos SEM bones nem animacao. Usados para:
- Construcoes (casas, torres, portais, altares)
- Decoracoes de cenario (arvores, pedras, caixas, barris)
- Armas e itens de chao (espadas, escudos, pocoes)
- Efeitos estaticos (circulos, plataformas)

### 8.1 Diferenca entre MSH e MSA

| Aspecto | MSH (Skinned) | MSA (Static) |
|---|---|---|
| Bones/Skeleton | Sim (max 40) | Nao |
| Animacao | Sim (.ani + .bon) | Nao |
| Skinning/Weights | Sim (max 4 por vertice) | Nao |
| Multi-material | Nao (1 textura) | Sim (1-32 attribute ranges) |
| Diffuse color | Nao (FVF 274) | Opcional (FVF 322) |
| Uso tipico | Personagens, mobs, montarias | Cenario, itens, armas |

### 8.2 Sistema de registro MSA

MSA sao registrados via **MeshList.txt** — uma tabela texto simples:
```
{index} {path_relativo}

Exemplo:
0 mesh\cas001.msa
1 mesh\cas002.msa
2 mesh\tree01.msa
...
```

O index e o `dwObjType` que o engine usa para referenciar o objeto.
`GetCommonMesh(dwObjType)` busca o path no MeshList e chama `LoadMsa()`.

As texturas sao resolvidas de 2 formas:
1. Nome embeddado no MSA (campo de 11 bytes por attribute range)
2. Busca em MeshTextureList.bin por `mesh\{nomeBase}.wys`

### 8.3 Formatos de vertice MSA (FVF)

| FVF | Hex | Layout | Bytes | Uso |
|---|---|---|---|---|
| 274 | 0x112 | Position(12) + Normal(12) + UV(8) | 32 | Maioria dos objetos |
| 322 | 0x142 | Position(12) + Diffuse(4) + UV(8) | 24 | Objetos com vertex color |

**CRITICO:** o FVF deve ser preservado no round-trip. Converter um MSA de FVF 322
para FVF 274 QUEBRA a renderizacao no cliente (o engine trata 322 de forma especial).

### 8.4 Workflow: Criar MSA Novo

#### Passo 1 — Modelar

Crie o objeto no 3ds Max ou Blender:
- Apenas geometria (sem bones, sem skeleton)
- Triangulos apenas (sem quads/n-gons)
- Max 65.535 vertices
- Escala: 1 unidade = proporcional ao mundo WYD (exporte um objeto existente como referencia)

#### Passo 2 — Multi-material (opcional)

MSA suporta ate 32 materiais/texturas por mesh:
- Atribua materiais diferentes a grupos de faces
- Cada material pode ter sua propria textura
- Os attribute ranges sao preservados no round-trip

Para objetos simples, 1 material e suficiente.

#### Passo 3 — UV e Textura

- UV Unwrap normal
- Textura PNG ou TGA em potencia de 2 (256x256, 512x512)
- Para multi-material: 1 textura por material
- O WYDConverter converte PNG → WYS

#### Passo 4 — Exportar

No 3ds Max:
  File > Export > FBX Binary, Z-Up, Smoothing Groups ON

No Blender:
  File > Export > glTF 2.0 (.glb), +Y Up, Apply Modifiers ON

**NAO precisa** incluir Skin/Deformers (MSA e estatico).

#### Passo 5 — Converter no WYDConverter

1. Abrir o FBX ou GLB no WYDConverter
2. Dropdown "MSA" > "FBX -> MSA" (ou "GLB -> MSA")
3. Nomear: `cas999.msa` (ou qualquer nome livre)
4. Converter textura: PNG -> WYS: `cas999.wys`

#### Passo 6 — Registrar

**MeshList.txt** — adicionar linha:
```
{indexLivre} mesh\cas999.msa
```
O index deve ser um slot livre (0-3047, MAX_COMMON_MESH = 3048).

**MeshTextureList.bin** — adicionar textura:
```
Slot vazio → szFileName = "mesh\cas999.wys", cAlpha = 'N'
```

Para multi-material, adicionar CADA textura separadamente.

#### Passo 7 — Colocar e testar

```
Mesh\cas999.msa    ← mesh estatico
Mesh\cas999.wys    ← textura
```

O engine carrega via `GetCommonMesh(index)` quando o terreno
ou objeto referencia o `dwObjType` correspondente ao index.

Para testar: colocar o objeto em um mapa editando o .trn
(terrain file) com o index do MeshList.txt.

### 8.5 Checklist MSA

- [ ] Modelar objeto (sem bones, triangulos apenas)
- [ ] UV unwrap, textura potencia de 2
- [ ] Exportar FBX ou GLB (sem skeleton)
- [ ] Converter FBX/GLB → MSA no WYDConverter
- [ ] Converter textura → WYS
- [ ] Adicionar textura em MeshTextureList.bin
- [ ] Adicionar entrada em MeshList.txt (index + path)
- [ ] Copiar MSA + WYS para Mesh\ do cliente
- [ ] Testar no mapa (colocar objeto no .trn)
 

manual completo do wyd haha

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

2 horas atrás, badcorp disse:

manual completo do wyd haha

no WYDConverter fica melhor a visualização

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

  • Curtir 13

Discord: GuiCandiotto

Link para o comentário
Compartilhar em outros sites

16 horas atrás, m4chado1 disse:

provavelmente as animações não estao registadas no validindex.bin... então o mob aparece invisivel

tem algum editor de validindex ou edita pelo hexxeditor?

16 horas atrás, gcr_fc disse:

no WYDConverter eu fiz uma área de tutorial e um deles é a criação de novos itens/mobs, veja se te ajuda. copia e crie um .md pode ser no próprio VS que vai ficar bem mais legível.
 

# Guia: Criar Mobs, Objetos e Meshes Novos para o WYD

> Passo a passo completo para criar conteudo 3D novo e integrar no cliente WYD.
> Cobre mobs (MSH skinned), objetos estaticos (MSA), modelagem, exportacao,
> conversao e registro nos arquivos do cliente.

---

## 1. Sistema de Arquivos do WYD

### 1.1 Arquivos 3D por mob

| Arquivo | Exemplo | Conteudo | Formato |
|---|---|---|---|
| `.msh` | `nm010101.msh` | Mesh skinned (vertices, indices, bones, skinning) | Binario 32B header |
| `.bon` | `nm01.bon` | Hierarquia do esqueleto (pares parentID/boneID) | Binario 8B por bone |
| `.ani` | `nm010101.ani` | Animacao (matrizes 4x4 locais por bone por frame) | Binario 8B header + matrices |
| `.wys` | `nm010101.wys` | Textura DXT1 comprimida | Binario WYS |
| `.wyt` | `nm010101.wyt` | Textura BGRA raw (formato antigo) | Binario WYT |

### 1.2 Convencao de nomes

```
{prefixo}{PPVV}.ext

prefixo = skeleton type (4 chars): nm01, ch01, ch02, tr09, hs01...
PP       = parte/slot (2 digitos): 01=corpo, 02=helm, 03=armor...
VV       = visual/variante (2 digitos): 01=base, 02=alt...
```

**Regra critica:** os primeiros 4 caracteres definem o skeleton. Todos os arquivos
com mesmo prefixo compartilham o mesmo `.bon` e os mesmos `.ani`.

Exemplos:
- `nm010101.msh`, `nm010102.msh` → usam `nm01.bon`
- `ch010597.msh` → usa `ch01.bon`, slot 05 (luva), visual 97

### 1.3 Arquivos de registro do cliente

Estes arquivos precisam ser editados para o cliente reconhecer mobs novos.

| Arquivo | Path | Funcao | Editar quando |
|---|---|---|---|
| `BoneAni4.txt` | `Mesh\BoneAni4.txt` | Registra skeletons: index, num ANIs, num partes, prefixo | Skeleton NOVO |
| `ValidIndex.bin` | `Mesh\ValidIndex.bin` | Mapeia quais ANIs existem para cada skeleton | Skeleton NOVO |
| `MeshTextureList.bin` | `Mesh\MeshTextureList.bin` | Tabela de texturas de meshes (nome → index) | Textura NOVA |
| `MeshList.txt` | `Mesh\MeshList.txt` | Registra objetos estaticos MSA: index → path | MSA NOVO |
| `AniSound4.txt` | `AniSound4.txt` | Tabela de animacoes/velocidades/sons por skeleton type | Skeleton NOVO |
| `ItemList.bin` | Server-side | Define nClass do mob → mapeia para skeleton via `BASE_DefineSkinMeshType` | Mob NOVO |
| `Basedef.cpp` | Compilado no .exe | `BASE_DefineSkinMeshType(nClass)` → nBoneAniIndex (hardcoded switch) | Skeleton NOVO (recompilacao) |

**Para mob com skeleton EXISTENTE:** nenhum destes arquivos precisa ser editado.
Basta colocar o MSH + WYS na pasta `Mesh\` com o prefixo correto.

**Para mob com skeleton NOVO:** todos os arquivos acima precisam ser editados.

---

## 2. Formatos Binarios Detalhados

### 2.1 MSH (Mesh Skinned)

```
Header (32 bytes):
  [00] DWORD dwParentID        — ID do bone pai (0xFFFFFFFF = root)
  [04] DWORD dwMeshID          — ID do bone deste mesh
  [08] DWORD dwFVF             — Flexible Vertex Format (D3D9)
  [0C] DWORD sizeVertex        — Bytes por vertice
  [10] DWORD numFaceInfluence   — Numero de face influences
  [14] DWORD numPalette        — Numero de bones na palette
  [18] DWORD vertexCount       — Numero de vertices
  [1C] DWORD faceCount         — Numero de INDICES (nao faces!)

Bones (se numPalette > 0):
  XMFLOAT4X4[numPalette]       — Offset matrices (64 bytes cada)
  DWORD[numPalette]             — Bone IDs (4 bytes cada)

Vertices:
  Layout depende do FVF. Tipico para skinned:
    Position XYZ (12B) + BlendWeights (4-12B) + PackedBoneIndices (4B)
    + Normal (12B) + UV (8B)

Indices:
  uint16[faceCount]             — Index buffer 16-bit
```

### 2.2 BON (Bone Hierarchy)

```
Arquivo = array de pares (8 bytes cada):
  [parentID: DWORD] [boneID: DWORD]

parentID = 0xFFFFFFFF ou 0 → root (sem pai)
parentID = N → bone filho de bone N

Tamanho total = numBones * 8 bytes
```

Exemplo para esqueleto com 5 bones:
```
[0xFFFFFFFF] [0]    — Bone 0 e root
[0]          [1]    — Bone 1 filho de Bone 0
[0]          [2]    — Bone 2 filho de Bone 0
[1]          [3]    — Bone 3 filho de Bone 1
[1]          [4]    — Bone 4 filho de Bone 1
```

### 2.3 ANI (Animation)

```
Header (8 bytes):
  [00] DWORD numTicks    — Numero de keyframes (frames de animacao)
  [04] DWORD numBones    — Numero de bones no skeleton

Dados:
  Para cada tick (0..numTicks-1):
    XMFLOAT4X4[numBones]  — Matriz LOCAL de cada bone neste frame (64 bytes cada)

Tamanho total = 8 + (numTicks * numBones * 64) bytes
```

As matrizes sao LOCAL (relativas ao pai na hierarquia BON).
O cliente propaga pela hierarquia para obter as combined (world) matrices:
`combined[bone] = local[bone] * combined[parent]`

### 2.4 BoneAni4.txt

```
Formato texto, uma linha por skeleton:
{index} {numAniTypes} {numParts} {szAniName}

Campos:
  index         — Indice no array m_BoneAnimationList (0-99)
  numAniTypes   — Quantos ANIs diferentes este skeleton tem
  numParts      — Quantos slots de equipamento (1 para mobs simples, 7 para players)
  szAniName     — Prefixo completo com path (ex: mesh\nm01, mesh\ch01)
```

Exemplo:
```
0 38 7 mesh\ch01      <- personagem masculino, 38 animacoes, 7 partes
1 37 7 mesh\ch02      <- personagem feminino
2  1 1 mesh\hs01      <- cavalo, 1 animacao, 1 parte
3  2 1 mesh\nm01      <- mob tipo 1, 2 animacoes, 1 parte
...
```

### 2.5 ValidIndex.bin

```
Array binario fixo:
  stValidAniList[100][186]

  stValidAniList = struct { int nI; }  — 4 bytes

Tamanho total = 100 * 186 * 4 = 74.400 bytes

Indexacao:
  m_stValidAniList[skeletonIndex][aniSlot].nI = aniFileIndex

O cliente usa nI+1 para montar o nome do ANI:
  sprintf(szTemp, "%s%04d.ani", szAniName, m_stValidAniList[nCount][nFI].nI + 1)

Exemplo:
  m_stValidAniList[3][0].nI = 0   → mesh\nm010001.ani (idle)
  m_stValidAniList[3][1].nI = 1   → mesh\nm010002.ani (walk)
  m_stValidAniList[3][2].nI = 100 → mesh\nm010101.ani (arma 01, idle)
```

Codificacao dos 4 digitos do ANI:
```
XXYY onde:
  XX = tipo de arma (weapon): nArrayIndex / 100 - 1
  YY = tipo de acao (motion): nArrayIndex % 100 - 1

Exemplos (nI+1 → arquivo):
  0001 → arma 0, acao 0 (idle)
  0002 → arma 0, acao 1 (walk)
  0003 → arma 0, acao 2 (run)
  0004 → arma 0, acao 3 (attack1)
  0101 → arma 1, acao 0 (idle com espada)
```

### 2.6 MeshList.txt

```
Formato texto, uma linha por objeto estatico:
{index} {path_relativo}

Campos:
  index          — Indice no array m_stCommonMesh (0-3047)
  path_relativo  — Caminho do MSA relativo ao diretorio do cliente
```

Exemplo:
```
0 mesh\cas001.msa
1 mesh\cas002.msa
50 mesh\tree01.msa
100 mesh\sword01.msa
```

O engine chama `GetCommonMesh(dwObjType)` onde dwObjType = index.
Mapas (.trn) referenciam objetos pelo dwObjType.

### 2.7 MeshTextureList.bin

```
Array binario fixo de stTextureListInfo (264 bytes cada):
  char szFileName[255]      — path relativo da textura (ex: "mesh\nm010101.wys")
  char cAlpha               — tipo de alpha: 'N'=none, 'A'=alpha, 'a'=1bit, 'C'=compressed
  DWORD dwLastUsedTime      — runtime (ignorar, preencher com 0)
  DWORD dwShowTime          — runtime (ignorar, preencher com 0)

Tamanho por versao:
  TMProject classico: 2048 slots = 540.672 bytes
  WYD Global:         6096 slots = 1.609.344 bytes
```

O cliente busca textura por nome (`GetModelTextureIndex`): percorre TODOS os slots
comparando `szFileName` com o nome calculado pelo `TMSkinMesh`. Se nao encontra,
o mesh **NAO CARREGA** (retorna erro).

**Para adicionar textura nova:**
1. Encontrar um slot vazio (szFileName[0] == '\0')
2. Preencher szFileName com path relativo (ex: `mesh\xx010101.wys`)
3. Preencher cAlpha com 'N' (sem alpha) ou 'A' (com alpha)
4. dwLastUsedTime e dwShowTime = 0

### 2.8 AniSound4.txt

```
Formato texto. Uma secao por skeleton type (MAX_ANI_TYPE = 60 skeletons).
Cada secao tem 56 linhas (MAX_ANI_MOTION), uma por tipo de acao.

Para skeleton types 0 e 1 (players):
  {nomeAcao} {ani0} {speed0} {ani1} {speed1} {ani2} {speed2} {ani3} {speed3} {sound}

Para skeleton types 2+ (mobs/NPCs):
  {nomeAcao} {aniIndex} {speed} {sound}

Campos:
  nomeAcao  — label (ex: "IDLE", "WALK", "ATK1") — ignorado pelo parser
  aniIndex  — indice na lista de animacoes do skeleton (posicao no array concatenado)
  speed     — velocidade da animacao (ticks por frame)
  sound     — indice do som a tocar
```

Controla qual animacao tocar para cada acao do mob (idle, walk, attack, death, etc.)
e a velocidade de reproducao. Se o skeleton novo for um mob simples, basta preencher
as acoes basicas (idle=0, walk=1, attack=2, death=3).

### 2.9 Fluxo de resolucao no cliente

```
Servidor envia pacote com mob → nClass (tipo do mob)
        ↓
BASE_DefineSkinMeshType(nClass) → nBoneAniIndex (switch hardcoded em Basedef.cpp)
        ↓
BoneAni4.txt[nBoneAniIndex] → szAniName (ex: "mesh\nm01"), numParts, numAniTypes
        ↓
Skeleton:  szAniName + ".bon"                    → mesh\nm01.bon
Mesh:      szAniName + PPVV + ".msh"             → mesh\nm010101.msh
Textura:   szAniName + PPVV + ".wys"             → mesh\nm010101.wys
           → GetModelTextureIndex(texName)       → busca em MeshTextureList.bin
Animacao:  ValidIndex.bin[nBoneAniIndex][slot]    → nI+1 → mesh\nm010001.ani
           → AniSound4.txt[nBoneAniIndex]        → mapeia acao → indice de animacao
```

### 2.10 STRUCT_ITEMLIST (ItemList.bin)

```
Struct STRUCT_ITEMLIST — 120 bytes por item:
  char Name[64]                  — Nome do item
  short nIndexMesh               — Indice visual do mesh
  short nIndexTexture            — Indice visual da textura
  short nIndexVisualEffect       — Efeito visual (brilho, aura)
  short nReqLvl                  — Nivel minimo
  short nReqStr / nReqInt /      — Requisitos de atributo
        nReqDex / nReqCon
  STRUCT_STATICEFFECT stEffect[12] — 12 efeitos estaticos (4 bytes cada)
  int nPrice                     — Preco do item
  short nUnique                  — Tipo de raridade
  short nPos                     — Bitmask de slots onde pode equipar
  short nExtra                   — Dados extras
  short nGrade                   — Grau/rank do item
```

**nIndexMesh e nIndexTexture** sao os campos que conectam o item ao mesh visual.
O significado muda COMPLETAMENTE dependendo do tipo de item:

**ARMAS E ESCUDOS (slots 6 e 7 — MSA):**
  nIndexMesh = indice DIRETO no MeshList.txt
  O cliente chama: GetCommonMesh(nIndexMesh) → LoadMsa(MeshList[nIndexMesh])
  Nenhuma formula intermediaria. Se a arma esta no index 500 do MeshList,
  nIndexMesh = 500.
  nIndexTexture = preenche LOOK_INFO.SkinX mas NAO e usado para renderizar
  a arma 3D. A textura da arma vem do nome embeddado no MSA → MeshTextureList.
  Na pratica, para armas, nIndexTexture = 0.

**EQUIPAMENTOS SKINNED (slots 0-5 — MSH):**
  nIndexMesh = variante visual usada na FORMULA do nome do MSH:
    sprintf("%s%02d%02d.msh", szAniName, slot+1, nIndexMesh + offset + 1)
  NAO e um indice de MeshList. E um numero de variante (0, 1, 2...).
  Exemplo: nIndexMesh=5 no slot coat → ch010306.msh (prefixo + slot03 + visual06)

  nIndexTexture = modificador de textura na FORMULA do nome da WYS:
    sprintf("%s%02d%02d.wys", szAniName, slot+1, (nIndexTexture & 0xFFF) + nIndexMesh + offset + 1)
  Permite usar texturas diferentes para o mesmo mesh visual.
  Exemplo: nIndexMesh=5, nIndexTexture=2 + 1 → ch010308.wys

**MONTARIAS (slot 14 — MSH skinned, skeleton proprio):**
  O item de montaria fica em Equip[14].
  sIndex do item → transformado (sIndex - 2045, com overrides hardcoded)
  → sIndex final usado como indice no g_pItemList:
    nIndexMesh = g_pItemList[sIndex].nIndexMesh → Mesh0 (variante visual)
    nIndexTexture = g_pItemList[sIndex].nIndexTexture → Skin0 (variante textura)
    nClass (efeito 18) → BASE_DefineSkinMeshType(nClass) → skeleton da montaria
  Funciona igual a equipamentos skinned: nIndexMesh e variante visual,
  NAO indice do MeshList. Vem do ItemList.bin.

**nPos** — bitmask de slots de equipamento:
```
  Bit 0 (0x01) = Slot 0: Face/Corpo
  Bit 1 (0x02) = Slot 1: Helm (elmo)
  Bit 2 (0x04) = Slot 2: Coat (armadura)
  Bit 3 (0x08) = Slot 3: Pants (calca)
  Bit 4 (0x10) = Slot 4: Gloves (luva)
  Bit 5 (0x20) = Slot 5: Boots (bota)
  Bit 6 (0x40) = Slot 6: Left (mao esq/escudo)
  Bit 7 (0x80) = Slot 7: Right (mao dir/arma)
```

**nClass (efeito 18)** — tipo de classe que determina o skeleton:
  Usado por `BASE_DefineSkinMeshType(nClass)` para mobs e montarias.
  Para players: nClass 1/4 = masculino (ch01), 2/8 = feminino (ch02).
  Para mobs: nClass 16-74 mapeiam para indices 2-57 no BoneAni4.txt.

### 2.11 Fluxo visual de armas

```
Item no Equip[7] (mao direita) ou Equip[6] (mao esquerda)
        ↓
g_pItemList[sIndex].nIndexMesh → nIndexMesh
        ↓
GetCommonMesh(nIndexMesh)   ← DIRETO, sem formula intermediaria!
        ↓
MeshList.txt[nIndexMesh] → path do MSA (ex: mesh\wp001.msa)
        ↓
TMMesh::LoadMsa(path) → carrega MSA
        ↓
Textura: nome embeddado no MSA → GetModelTextureIndex → MeshTextureList.bin
```

### 2.12 Fluxo visual de equipamentos (armaduras, helmos, etc.)

```
Item no Equip[0-5] (face, helm, coat, pants, gloves, boots)
        ↓
g_pItemList[sIndex].nIndexMesh → LOOK_INFO.MeshX (variante)
g_pItemList[sIndex].nIndexTexture → LOOK_INFO.SkinX (textura mod)
        ↓
TMSkinMesh monta nome do arquivo:
  Mesh: sprintf("%s%02d%02d.msh", szAniName, slot+1, MeshX + offset + 1)
  Tex:  sprintf("%s%02d%02d.wys", szAniName, slot+1, (SkinX & 0xFFF) + MeshX + offset + 1)
        ↓
Exemplo: ch01, slot 3 (coat), nIndexMesh=5, nIndexTexture=0
  Mesh: ch010306.msh
  Tex:  ch010306.wys
```

---

## 3. Restricoes Tecnicas do Cliente

### 3.1 MSH (Skinned Meshes)

| Item | Limite | Origem |
|---|---|---|
| Bones por mesh | 40 max | `safePalette = min(n, 40)` em CMesh |
| Influences por vertice | 4 max | FVF XYZB1-B4 + LASTBETA_UBYTE4 |
| Vertices por mesh | 65535 max | Indices 16-bit no MSH |
| Textura por mesh | 1 | MSH nao tem attribute ranges |
| Textura dimensao | Potencia de 2 | DXT1 |
| Coordenadas | Z-Up | Nativo WYD |
| UV | V=0 no topo (D3D) | Nativo WYD e 3ds Max |
| Skeletons registrados | 100 max | MAX_BONE_ANIMATION_LIST |
| ANIs por skeleton | 186 max | Array fixo ValidAniList |
| Bones por skeleton | Sem limite hard | Limitado pela RAM |

### 3.2 MSA (Static Meshes)

| Item | Limite | Origem |
|---|---|---|
| Vertices por mesh | 65535 max | Indices 16-bit |
| Materiais por mesh | 32 max | dwAttCount no header |
| Texturas por material | 1 | Uma WYS por attribute range |
| Textura dimensao | Potencia de 2 | DXT1 |
| Coordenadas | Z-Up | Nativo WYD |
| UV | V=0 no topo (D3D) | Nativo WYD |
| Objetos em MeshList | 3048 max | MAX_COMMON_MESH |
| FVF suportados | 274 (normal) ou 322 (diffuse) | Engine hardcoded |

---

## 4. Workflow: Novo Mob com Skeleton Existente

**Cenario:** criar um mob novo que reutiliza o esqueleto e animacoes de um mob existente.
Este e o caminho mais rapido e seguro.

### Passo 1 — Exportar mob de referencia

No WYDConverter, abrir o MSH do mob que quer reusar (ex: `nm010101.msh`).
Exportar como FBX (target 3ds Max). O FBX contem:
- Geometria do mob original
- Esqueleto completo com bone IDs
- Animacao do ANI companion
- Textura companion como PNG

### Passo 2 — Importar no 3ds Max

Importar o FBX. O mesh aparece:
- Z-Up (nativo do Max e do WYD — sem conversao)
- Escala amplificada (conversor aplica x100 para edicao confortavel)
- Bones com nomes `Bone_000`, `Bone_001`, etc.

**NAO mover, rotacionar ou escalar o Armature.** A posicao dos bones e o bind pose
que as animacoes existentes esperam.

### Passo 3 — Modelar

- Deletar a geometria do mob original (so poligonos, NAO os bones)
- Modelar o novo mob ao redor do esqueleto existente
- Manter o mesh alinhado com os bones na posicao de bind

Regras:
- Apenas triangulos (sem quads/n-gons)
- Max 65535 vertices
- 1 material/textura por mesh
- Polycount razoavel (~500-3000 tris para mobs)

### Passo 4 — Skinning

- Aplicar Skin modifier no mesh
- Adicionar os bones do esqueleto importado
- Pintar weights: max 4 influences por vertice
- Weights devem somar 1.0
- Todo vertice deve ter pelo menos 1 bone com peso > 0

### Passo 5 — UV e Textura

- UV Unwrap no Max (UV convention D3D: V=0 topo — default do Max)
- Textura PNG/TGA em potencia de 2 (256x256 ou 512x512)
- O WYDConverter converte para WYS automaticamente

### Passo 6 — Exportar FBX

File → Export → FBX:
- Formato: FBX Binary
- Eixos: Z-Up (default Max)
- Smoothing Groups: ON
- Skin/Deformers: ON
- Embed Media: OFF

### Passo 7 — Converter

No WYDConverter:
1. Abrir o FBX exportado
2. Converter para MSH
3. Nomear: `nm010199.msh` (mesmo prefixo, numero livre)
4. Converter textura PNG → WYS: `nm010199.wys`
5. Copiar para `Mesh\` do cliente

### Passo 8 — Testar

O cliente carrega automaticamente:
- `nm010199.msh` — mesh novo
- `nm01.bon` — hierarquia (ja existe)
- `nm010001.ani` etc — animacoes (ja existem)
- `nm010199.wys` — textura nova

Nenhuma edicao de BoneAni4.txt ou ValidIndex.bin necessaria (mesmo skeleton).

---

## 5. Workflow: Mob com Skeleton e Animacoes Novas

**Cenario:** criar um mob completamente novo com esqueleto e animacoes proprias.
Requer ferramentas adicionais e edicao de arquivos de registro.

### Passo 1 — Modelar e Riggar no 3ds Max

- Modelar o mob
- Criar esqueleto com bones (usar nomes `Bone_000`, `Bone_001`, etc.)
- Bone 0 deve ser o root
- Max 40 bones
- Skin modifier com max 4 influences

### Passo 2 — Criar Animacoes

No 3ds Max, criar as animacoes necessarias:
- Idle (parado)
- Walk (andando)
- Run (correndo)
- Attack (atacando)
- Death (morrendo)
- etc.

Cada animacao sera exportada como um FBX separado (ou ranges no mesmo FBX).

### Passo 3 — Exportar

Exportar cada animacao como arquivo separado com mesh + skeleton + animation.
Formatos suportados:
- **FBX Binary** (3ds Max, Maya, Blender via plugin)
- **GLB/GLTF** (Blender nativo, qualquer DCC moderno)

### Passo 4 — Converter

Usar o WYDConverter para gerar:

| De | Para | Ferramenta | Status |
|---|---|---|---|
| FBX mesh | `.msh` | MSHEncoder (FBX→MSH) | Funciona |
| GLB/GLTF mesh | `.msh` | MSHEncoder (GLTF→MSH) | Funciona |
| FBX skeleton | `.bon` | **BONEncoder (FBX)** | NAO EXISTE |
| GLB/GLTF skeleton | `.bon` | **BONEncoder (GLTF)** | NAO EXISTE |
| FBX animation | `.ani` | **ANIEncoder (FBX)** | NAO EXISTE |
| GLB/GLTF animation | `.ani` | **ANIEncoder (GLTF)** | NAO EXISTE |
| PNG textura | `.wys` | WYSEncoder | Funciona |

### Passo 5 — Registrar no cliente

Para um skeleton completamente novo, TODOS estes arquivos precisam ser editados:

#### 5.1 Editar BoneAni4.txt

Adicionar uma linha para o novo skeleton:
```
{novoIndex} {numAnis} {numParts} mesh\{prefixo}
```

Exemplo: adicionar mob `xx01` com 3 animacoes, 1 parte:
```
50 3 1 mesh\xx01
```

O index (50) deve ser um slot livre no array (0-99).

#### 5.2 Editar ValidIndex.bin

Adicionar as entradas para mapear os ANIs do novo skeleton:
```
m_stValidAniList[50][0].nI = 0    → mesh\xx010001.ani (idle)
m_stValidAniList[50][1].nI = 1    → mesh\xx010002.ani (walk)
m_stValidAniList[50][2].nI = 2    → mesh\xx010003.ani (attack)
```

O ValidIndex.bin e um array binario fixo de 74400 bytes.
Offset para skeleton index N = N * 186 * 4 bytes.
Cada slot = 4 bytes (int).

#### 5.3 Editar MeshTextureList.bin

Adicionar a textura do novo mob em um slot vazio:
```
Slot livre → szFileName = "mesh\xx010101.wys", cAlpha = 'N'
```

**CRITICO:** sem esta entrada, o cliente NAO encontra a textura e o mesh nao carrega.
O `GetModelTextureIndex` faz busca linear por nome — se nao encontra, retorna -1,
e o CMesh aborta o carregamento.

Para encontrar slots vazios: qualquer entrada com `szFileName[0] == '\0'`.
Cada slot tem 264 bytes. Para editar diretamente no binario:
```
Offset = slotIndex * 264
  [+0..+254]   = szFileName (null-terminated, zero-padded)
  [+255]       = cAlpha ('N' ou 'A')
  [+256..+259] = dwLastUsedTime (0)
  [+260..+263] = dwShowTime (0)
```

#### 5.4 Editar AniSound4.txt

Adicionar uma secao para o novo skeleton type.
A posicao na lista corresponde ao nBoneAniIndex.

Para mob simples (56 linhas, formato `{nome} {aniIdx} {speed} {sound}`):
```
TYPE50
IDLE     0 30 0
WALK     1 30 0
RUN      1 20 0
ATK1     2 25 0
ATK2     2 25 0
DEATH    2 30 0
...      (preencher restante com 0 0 0)
```

#### 5.5 Editar BASE_DefineSkinMeshType (recompilacao)

Em `Basedef.cpp`, a funcao `BASE_DefineSkinMeshType(nClass)` e um switch hardcoded
que mapeia o nClass do item/mob → nBoneAniIndex.

Para adicionar um novo mob com nClass=75:
```cpp
case 75:
    return 50;  // nosso novo skeleton xx01, index 50 no BoneAni4.txt
```

**Isto requer recompilacao do cliente.** Nao ha como evitar — o mapeamento e
hardcoded no executavel.

#### 5.6 Registrar no servidor (ItemList)

O servidor define o `nClass` de cada mob/NPC no `ItemList.bin` ou na
tabela de mobs. O nClass e o que o cliente recebe no pacote e usa para
chamar `BASE_DefineSkinMeshType`.

#### 5.7 Colocar arquivos

```
Mesh\xx01.bon          — hierarquia
Mesh\xx010001.ani      — idle
Mesh\xx010002.ani      — walk
Mesh\xx010003.ani      — attack
Mesh\xx010101.msh      — mesh
Mesh\xx010101.wys      — textura
```

---

## 6. Plano de Implementacao: Encoders Faltantes

### 6.1 BONEncoder (FBX/GLTF/GLB → BON)

**Complexidade:** Baixa (formato trivial: pares de DWORDs)

**Input:** FBX ou GLTF/GLB com skeleton
**Output:** arquivo .bon

**Algoritmo (FBX path):**
1. Percorrer todos os FbxNode com FbxSkeleton attribute
2. Para cada bone, extrair o boneID do nome (`Bone_XXX` → XXX)
3. Para cada bone, determinar o parentID:
   - Root: parentID = 0xFFFFFFFF
   - Outros: parentID = boneID do pai
4. Escrever pares [parentID, boneID] em ordem (root primeiro, BFS)

**Algoritmo (GLTF/GLB path):**
1. Carregar documento GLTF com glTF SDK
2. Ler `doc.skins[0].jointIds` — lista de nodes que sao joints
3. Para cada joint node, extrair boneID do nome (`Bone_XXX` → XXX)
4. Para cada joint, determinar parentID pela hierarquia de nodes:
   - Se parent node nao esta em jointIds → root (0xFFFFFFFF)
   - Senao → boneID do parent node
5. Escrever pares [parentID, boneID]

**Arquivos a criar:**
- `Conversores/BON/BONEncoder.h` — declaracao
- `Conversores/BON/BONEncoder.cpp` — `FromFBX()` e `FromGLTF()` + `SaveBON()` compartilhado

**Estimativa:** ~120 linhas de codigo, 2-3 horas.

### 6.2 ANIEncoder (FBX/GLTF/GLB → ANI)

**Complexidade:** Media (precisa avaliar animacao por frame e extrair matrizes locais)

**Input:** FBX ou GLTF/GLB com skeleton + animation
**Output:** arquivo .ani

**Algoritmo (FBX path):**
1. Ler o FBX com FBX SDK
2. Determinar numBones (do skeleton) e numTicks (do animation stack)
3. Para cada tick (frame):
   a. Setar o tempo: `FbxTime::SetFrame(tick, eFrames30)`
   b. Para cada bone (por boneID, 0..numBones-1):
      - Avaliar `node->EvaluateLocalTransform(time)` → FbxAMatrix
      - Converter FbxAMatrix para XMFLOAT4X4
      - Se o FBX veio do WYDConverter: reverter anchor correction e scale
      - Se e novo conteudo: usar local transforms direto
   c. Gravar as numBones matrizes para este tick
4. Escrever header (numTicks, numBones) + todas as matrizes

**Algoritmo (GLTF/GLB path):**
1. Carregar documento GLTF com glTF SDK
2. Ler `doc.animations[0]` — channels e samplers
3. Determinar numTicks pelo max timestamp / (1/30) + 1
4. Para cada tick:
   a. Calcular tempo: `t = tick / 30.0f`
   b. Para cada bone:
      - Interpolar TRS dos samplers (translation, rotation, scale) no tempo t
      - Rotation: quaternion → matrix (GLTF usa quaternions nativamente)
      - Compor local matrix: S * R * T
      - Converter Y-Up → Z-Up (GLTF e Y-Up, ANI e Z-Up)
   c. Gravar as numBones matrizes
5. Escrever header + matrizes

**Cuidados comuns:**
- As matrizes no ANI sao LOCAL (relativas ao pai), nao world
- FBX: `EvaluateLocalTransform` ja retorna local
- GLTF: channels ja sao local (por spec)
- FBX Z-Up (nosso export) = WYD Z-Up → sem conversao
- GLTF Y-Up → precisa converter para Z-Up: conjugar cada local matrix
- Scale: matrizes ANI sao puras (rotacao + translacao)
  - Normalizar rotation columns para magnitude 1.0 antes de salvar
- Frame rate: WYD usa 30fps
- GLTF: samplers podem ter interpolacao LINEAR ou STEP
  - LINEAR: interpolar entre keyframes
  - STEP: usar valor anterior

**Arquivos a criar:**
- `Conversores/ANI/ANIEncoder.h` — declaracao
- `Conversores/ANI/ANIEncoder.cpp` — `FromFBX()`, `FromGLTF()` + `SaveANI()` compartilhado

**Estimativa:** ~350 linhas de codigo, 5-8 horas.

### 6.3 ValidIndexEditor (editor de ValidIndex.bin)

**Complexidade:** Baixa (array binario fixo, UI simples)

**Funcionalidade:**
- Carregar ValidIndex.bin (74400 bytes)
- Mostrar grid: skeleton index × ani slot → nI value
- Editar nI values
- Salvar ValidIndex.bin

**Integracao:** nova tab ou dialog no WYDConverter.

**Estimativa:** ~150 linhas, 2-3 horas.

### 6.4 BoneAni4Editor (editor de BoneAni4.txt)

**Complexidade:** Baixa (texto simples, UI simples)

**Funcionalidade:**
- Carregar BoneAni4.txt
- Mostrar tabela: index, numAniTypes, numParts, szAniName
- Adicionar/remover/editar linhas
- Salvar BoneAni4.txt

**Integracao:** mesma tab do ValidIndexEditor.

**Estimativa:** ~100 linhas, 1-2 horas.

### 6.5 MeshTextureListEditor (editor de MeshTextureList.bin)

**Complexidade:** Baixa (array binario fixo, ja temos decoder)

**Funcionalidade:**
- Carregar MeshTextureList.bin (auto-detecta classico 2048 vs Global 6096 slots)
- Mostrar tabela: index, szFileName, cAlpha
- Busca por nome (filtro)
- Adicionar textura em slot vazio (auto-encontrar proximo livre)
- Editar/remover entradas
- Salvar MeshTextureList.bin

**Nota:** Ja temos `MeshTextureListDecoder` com `LoadBIN`, `SaveBIN`, `LoadTXT`, `SaveTXT`.
O editor so precisa de UI — a logica de I/O ja existe.

**Integracao:** tab no DataEditor do WYDConverter.

**Estimativa:** ~120 linhas (UI apenas), 2-3 horas.

### 6.6 AniSound4Editor (editor de AniSound4.txt)

**Complexidade:** Baixa (texto formatado, parser simples)

**Funcionalidade:**
- Carregar AniSound4.txt
- Mostrar: skeleton type → 56 linhas (acao, aniIndex, speed, sound)
- Editar valores por celula
- Duplicar secao de skeleton existente (template para novo mob)
- Salvar AniSound4.txt

**Integracao:** mesma tab dos editores de registro.

**Estimativa:** ~150 linhas, 2-3 horas.

### 6.7 Ordem de Implementacao

```
Fase 1 — BONEncoder FBX + GLTF/GLB (2-3h)
  Permite: criar hierarquia de skeleton novo de qualquer formato
  Dependencias: nenhuma
  Teste: exportar mob existente MSH→FBX→BON e MSH→GLB→BON, comparar com original

Fase 2 — ANIEncoder FBX (3-5h)
  Permite: criar animacoes novas a partir de FBX
  Dependencias: nenhuma
  Teste: exportar mob existente MSH+ANI→FBX→ANI, comparar com original

Fase 3 — ANIEncoder GLTF/GLB (3-5h)
  Permite: criar animacoes novas a partir de GLTF/GLB
  Dependencias: SaveANI() da Fase 2
  Teste: exportar mob existente MSH+ANI→GLB→ANI, comparar com original
  Nota: GLTF usa quaternions + timestamps flutuantes (vs FBX Euler + frames fixos)
        Precisa: interpolacao de samplers, quat→matrix, Y-Up→Z-Up

Fase 4 — Editores de registro (5-8h)
  4a. BoneAni4Editor (1-2h) — ja temos parser
  4b. ValidIndexEditor (2-3h) — binario fixo
  4c. MeshTextureListEditor (2-3h) — ja temos LoadBIN/SaveBIN
  4d. AniSound4Editor (2-3h) — parser texto
  Permite: registrar skeleton, animacoes, texturas e sons
  Teste: adicionar entradas, verificar que cliente carrega

Fase 5 — Workflow integrado (3-4h)
  Batch: FBX/GLB → MSH + BON + ANI + WYS em um click
  Auto-registro: adiciona entradas nos 4 arquivos de registro
  UI: wizard "Novo Mob" no WYDConverter
  Validacao: checar limites (40 bones, 65535 verts, etc.)
  Suporte: arrastar FBX ou GLB, detectar conteudo automaticamente
```

**Total estimado: 18-27 horas de desenvolvimento.**

---

## 7. Checklist Final

### Para mob com skeleton existente:
- [ ] Exportar mob de referencia como FBX ou GLB
- [ ] Modelar novo mesh no DCC ao redor do skeleton
- [ ] Skin com max 4 influences, weights somam 1.0
- [ ] UV unwrap, textura potencia de 2
- [ ] Exportar FBX Binary Z-Up ou GLB
- [ ] Converter FBX/GLB → MSH no WYDConverter
- [ ] Converter textura → WYS
- [ ] Adicionar textura nova em MeshTextureList.bin (se textura nova)
- [ ] Copiar MSH + WYS para Mesh\ do cliente
- [ ] Testar in-game

### Para mob com skeleton novo:
- [ ] Tudo acima +
- [ ] Criar skeleton com bones `Bone_000` a `Bone_NNN`
- [ ] Criar animacoes (idle, walk, attack, death)
- [ ] Exportar FBX ou GLB por animacao
- [ ] Gerar BON via BONEncoder (FBX ou GLTF)
- [ ] Gerar ANIs via ANIEncoder (FBX ou GLTF)
- [ ] Editar BoneAni4.txt (adicionar linha com index, numAnis, numParts, prefixo)
- [ ] Editar ValidIndex.bin (mapear slots → nI para cada ANI)
- [ ] Editar MeshTextureList.bin (adicionar textura em slot vazio)
- [ ] Editar AniSound4.txt (adicionar secao com aniIndex/speed/sound por acao)
- [ ] Editar BASE_DefineSkinMeshType em Basedef.cpp (nClass → nBoneAniIndex)
- [ ] Registrar mob no servidor (ItemList: nClass + LOOK_INFO)
- [ ] Copiar BON + ANIs + MSH + WYS para Mesh\ do cliente
- [ ] Testar in-game

---

## 8. Criar Objetos Estaticos Novos (MSA)

Objetos MSA sao meshes estaticos SEM bones nem animacao. Usados para:
- Construcoes (casas, torres, portais, altares)
- Decoracoes de cenario (arvores, pedras, caixas, barris)
- Armas e itens de chao (espadas, escudos, pocoes)
- Efeitos estaticos (circulos, plataformas)

### 8.1 Diferenca entre MSH e MSA

| Aspecto | MSH (Skinned) | MSA (Static) |
|---|---|---|
| Bones/Skeleton | Sim (max 40) | Nao |
| Animacao | Sim (.ani + .bon) | Nao |
| Skinning/Weights | Sim (max 4 por vertice) | Nao |
| Multi-material | Nao (1 textura) | Sim (1-32 attribute ranges) |
| Diffuse color | Nao (FVF 274) | Opcional (FVF 322) |
| Uso tipico | Personagens, mobs, montarias | Cenario, itens, armas |

### 8.2 Sistema de registro MSA

MSA sao registrados via **MeshList.txt** — uma tabela texto simples:
```
{index} {path_relativo}

Exemplo:
0 mesh\cas001.msa
1 mesh\cas002.msa
2 mesh\tree01.msa
...
```

O index e o `dwObjType` que o engine usa para referenciar o objeto.
`GetCommonMesh(dwObjType)` busca o path no MeshList e chama `LoadMsa()`.

As texturas sao resolvidas de 2 formas:
1. Nome embeddado no MSA (campo de 11 bytes por attribute range)
2. Busca em MeshTextureList.bin por `mesh\{nomeBase}.wys`

### 8.3 Formatos de vertice MSA (FVF)

| FVF | Hex | Layout | Bytes | Uso |
|---|---|---|---|---|
| 274 | 0x112 | Position(12) + Normal(12) + UV(8) | 32 | Maioria dos objetos |
| 322 | 0x142 | Position(12) + Diffuse(4) + UV(8) | 24 | Objetos com vertex color |

**CRITICO:** o FVF deve ser preservado no round-trip. Converter um MSA de FVF 322
para FVF 274 QUEBRA a renderizacao no cliente (o engine trata 322 de forma especial).

### 8.4 Workflow: Criar MSA Novo

#### Passo 1 — Modelar

Crie o objeto no 3ds Max ou Blender:
- Apenas geometria (sem bones, sem skeleton)
- Triangulos apenas (sem quads/n-gons)
- Max 65.535 vertices
- Escala: 1 unidade = proporcional ao mundo WYD (exporte um objeto existente como referencia)

#### Passo 2 — Multi-material (opcional)

MSA suporta ate 32 materiais/texturas por mesh:
- Atribua materiais diferentes a grupos de faces
- Cada material pode ter sua propria textura
- Os attribute ranges sao preservados no round-trip

Para objetos simples, 1 material e suficiente.

#### Passo 3 — UV e Textura

- UV Unwrap normal
- Textura PNG ou TGA em potencia de 2 (256x256, 512x512)
- Para multi-material: 1 textura por material
- O WYDConverter converte PNG → WYS

#### Passo 4 — Exportar

No 3ds Max:
  File > Export > FBX Binary, Z-Up, Smoothing Groups ON

No Blender:
  File > Export > glTF 2.0 (.glb), +Y Up, Apply Modifiers ON

**NAO precisa** incluir Skin/Deformers (MSA e estatico).

#### Passo 5 — Converter no WYDConverter

1. Abrir o FBX ou GLB no WYDConverter
2. Dropdown "MSA" > "FBX -> MSA" (ou "GLB -> MSA")
3. Nomear: `cas999.msa` (ou qualquer nome livre)
4. Converter textura: PNG -> WYS: `cas999.wys`

#### Passo 6 — Registrar

**MeshList.txt** — adicionar linha:
```
{indexLivre} mesh\cas999.msa
```
O index deve ser um slot livre (0-3047, MAX_COMMON_MESH = 3048).

**MeshTextureList.bin** — adicionar textura:
```
Slot vazio → szFileName = "mesh\cas999.wys", cAlpha = 'N'
```

Para multi-material, adicionar CADA textura separadamente.

#### Passo 7 — Colocar e testar

```
Mesh\cas999.msa    ← mesh estatico
Mesh\cas999.wys    ← textura
```

O engine carrega via `GetCommonMesh(index)` quando o terreno
ou objeto referencia o `dwObjType` correspondente ao index.

Para testar: colocar o objeto em um mapa editando o .trn
(terrain file) com o index do MeshList.txt.

### 8.5 Checklist MSA

- [ ] Modelar objeto (sem bones, triangulos apenas)
- [ ] UV unwrap, textura potencia de 2
- [ ] Exportar FBX ou GLB (sem skeleton)
- [ ] Converter FBX/GLB → MSA no WYDConverter
- [ ] Converter textura → WYS
- [ ] Adicionar textura em MeshTextureList.bin
- [ ] Adicionar entrada em MeshList.txt (index + path)
- [ ] Copiar MSA + WYS para Mesh\ do cliente
- [ ] Testar no mapa (colocar objeto no .trn)
 

ótimo tutorial cara vou estudar aqui vlw 

2 horas atrás, gcr_fc disse:

no WYDConverter fica melhor a visualização

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

É necessário se cadastrar para acessar o conteúdo.

tem o link desse wyd convert?

 

  • Curtir 4
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora
 Compartilhar

×
×
  • Criar Novo...

Informação Importante

Nós fazemos uso de cookies no seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies , caso contrário, vamos supor que você está bem para continuar.