# Character Clone Documentation

## Overview

Fitur **Clone Character** memungkinkan admin untuk menyalin data dari satu karakter (source) ke karakter lain (target) melalui admin panel `/admin/manage/characters`. Clone dilakukan secara parsial berdasarkan section yang dipilih.

## Clone Sections

Dialog clone menyediakan **4 section** yang dapat dipilih secara independen:

| Section | Label | Data yang Disalin |
|---------|-------|-------------------|
| `base` | Base + Status | Base fields (race, cls/class, gender, custom_data, dll) + **SELURUH** status fields (level, exp, sp, pp, hp, mp, reputation, skills, waypointlist, property, meridian_data, title_data, force_data, dsb) |
| `pocket` | Pocket (Inventory + Money) | Seluruh isi inventory, money, timestamp, icapacity |
| `equipment` | Equipment (+ War Avatar) | Seluruh equipment yang sedang dipakai |
| `storehouse` | Storehouse (+ Dress, Material, General Card) | Bank storage, dress, material, generalcard |

> **Perbedaan dengan versi lama:** Section `status` terpisah sudah **dihapus**. Sekarang semua data status (termasuk exp, sp, hp, mp) tersalin otomatis bersama section `base` menggunakan single `putRole` call.

## Base Fields Preservation

Saat section `base` dicentang, field berikut dari **target** tetap dipertahankan (tidak ditimpa):

- `id` — Role ID target
- `name` — Nama karakter target
- `userid` — User ID pemilik target
- `delete_time` — Jadwal hapus (jika ada)
- `create_time` — Waktu pembuatan karakter
- `lastlogin_time` — Waktu login terakhir
- `forbidcount` & `forbid` — Data ban/mute
- `status` — Status byte

Semua field base lainnya (race, cls, gender, custom_data, config_data, custom_stamp, help_states, spouse, cross_data, reserved) akan disalin dari source.

## Status Fields yang Disalin (Semua)

`role.status` structure dari `app/Services/protocols/pw_v156.php`:

```php
'status' => [
    'sversion' => 'byte',
    'level' => 'int',
    'level2' => 'int',
    'exp' => 'int',
    'sp' => 'int',
    'pp' => 'int',
    'hp' => 'int',
    'mp' => 'int',
    'posx' => 'float',
    'posy' => 'float',
    'posz' => 'float',
    'worldtag' => 'int',
    'invader_state' => 'int',
    'invader_time' => 'int',
    'pariah_time' => 'int',
    'reputation' => 'int',
    'custom_status' => 'octets',
    'filter_data' => 'octets',
    'charactermode' => 'octets',
    'instancekeylist' => 'octets',
    'dbltime_expire' => 'int',
    'dbltime_mode' => 'int',
    'dbltime_begin' => 'int',
    'dbltime_used' => 'int',
    'dbltime_max' => 'int',
    'time_used' => 'int',
    'dbltime_data' => 'octets',
    'storesize' => 'short',
    'petcorral' => 'octets',
    'property' => 'octets',
    'var_data' => 'octets',
    'skills' => 'octets',
    'storehousepasswd' => 'octets',
    'waypointlist' => 'octets',
    'coolingtime' => 'octets',
    'npc_relation' => 'octets',
    'multi_exp_ctrl' => 'octets',
    'storage_task' => 'octets',
    'faction_contrib' => 'octets',
    'force_data' => 'octets',
    'online_award' => 'octets',
    'profit_time_data' => 'octets',
    'country_data' => 'octets',
    'king_data' => 'octets',
    'meridian_data' => 'octets',
    'extraprop' => 'octets',
    'title_data' => 'octets',
    'reincarnation_data' => 'octets',
    'realm_data' => 'octets',
    'reserved2' => 'byte',
    'reserved3' => 'byte',
],
```

Semua field di atas disalin dari source ke target tanpa pengecualian.

## Arsitektur Clone

```
CloneDialog (React)
    |
    v
POST /admin/manage/characters/clone
    |
    v
CharacterController::cloneRole()
    |
    v
CharacterActionService::cloneCharacter()
    |
    v
processPartialClone()
    |-- cloneBaseFields()       --> CloneService::cloneRoleBaseProtocol()
    |-- pocket  (if checked)    --> CloneService::cloneSection('pocket')
    |-- equipment (if checked)  --> CloneService::cloneSection('equipment')
    |-- storehouse (if checked) --> CloneService::cloneSection('storehouse')
```

## `cloneRoleBaseProtocol` — How It Works

Method ini menggabungkan copy base + status dalam satu `putRole` call:

1. **Get source** base + status via `getRoleBase` / `getRoleStatus`
2. **Get target** base + pocket + equipment + storehouse + task
3. **Overwrite** target base fields (kecuali preserved fields) dengan source base
4. **Replace** target status dengan **source status** (full replacement)
5. **Marshal** seluruh role structure (base, status, pocket, equipment, storehouse, task)
6. **Send** via `putRole` (protocol code 8002 untuk v156)
7. **Verify** dengan membaca ulang base target

```php
$fullRole = [
    'base'       => $targetBase,      // source race/cls/gender + preserved target id/name/userid
    'status'     => $sourceStatus,    // SELURUH status dari source
    'pocket'     => $targetPocket,    // tetap target (kecuali centang pocket)
    'equipment'  => $targetEquipment, // tetap target (kecuali centang equipment)
    'storehouse' => $targetStorehouse,// tetap target (kecuali centang storehouse)
    'task'       => $targetTask,      // tetap target
];

$this->putRole($targetRoleId, $fullRole);
```

## Important Notes

- **Kedua karakter harus offline** saat clone dilakukan
- Target name dan userid **tidak akan berubah** — hanya stats/appearance/class yang disalin
- Clone base sekarang **juga menyalin exp, sp, pp, hp, mp** — tidak ada lagi exclude field
- Untuk v156, `putRole` (code 8002) harus dikirim dengan full role structure; `putRoleBase` (3012) dan `putRoleStatus` (3014) tidak digunakan karena server v156 tidak menerimanya secara individual

## File Terkait

| File | Deskripsi |
|------|-----------|
| `app/Services/PwApi/Clone/CloneService.php` | Core clone logic (cloneRoleBaseProtocol, cloneSection, copyRole) |
| `app/Services/Character/CharacterActionService.php` | Orchestrasi clone (cloneCharacter, processPartialClone, cloneBaseFields) |
| `app/Http/Controllers/Admin/Manage/CharacterController.php` | Controller endpoint `cloneRole()` |
| `app/Http/Requests/Character/CloneCharacterRequest.php` | Validasi request (sections: base, pocket, equipment, storehouse) |
| `resources/js/components/character-dialogs/clone-dialog.tsx` | UI dialog React untuk clone |
| `app/Services/protocols/pw_v156.php` | Definisi protocol role.base dan role.status |
