Compare commits
5 Commits
feat/attri
...
6391372f00
| Author | SHA1 | Date | |
|---|---|---|---|
| 6391372f00 | |||
| f832c1a4df | |||
| c3df705a7a | |||
| a354d9eefc | |||
| ca304a99dd |
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
> **Extensões da arquitetura** (documentos normativos paralelos, escopo específico):
|
> **Extensões da arquitetura** (documentos normativos paralelos, escopo específico):
|
||||||
> - [`ARQUITETURA_SERVER_SELECT.md`](ARQUITETURA_SERVER_SELECT.md) — Server Select, lista de mundos, handoff CharServer↔WorldServer, multi-region, queue, Valkey. Roadmap em 7 fases.
|
> - [`ARQUITETURA_SERVER_SELECT.md`](ARQUITETURA_SERVER_SELECT.md) — Server Select, lista de mundos, handoff CharServer↔WorldServer, multi-region, queue, Valkey. Roadmap em 7 fases.
|
||||||
> - [`ARQUITETURA_CHARACTER_MODEL.md`](ARQUITETURA_CHARACTER_MODEL.md) — Stats primários (STR/AGI/VIT/INT/DEX/LUK), classes (Aprendiz → especializações), fórmulas de stats derivados (ATK/MATK/DEF/...), `jobs.yml` data-driven, stat allocation server-side. Espelha rathena.
|
> - [`ARQUITETURA_CHARACTER_MODEL.md`](ARQUITETURA_CHARACTER_MODEL.md) — Stats primários (STR/AGI/VIT/INT/DEX/LUK), classes (Novato → especializações), fórmulas de stats derivados (ATK/MATK/DEF/...), `jobs.yml` data-driven, stat allocation server-side. Espelha rathena.
|
||||||
|
|
||||||
> **Sumário de mudanças (2026-05-11):** adicionada secção de **temas sazonais
|
> **Sumário de mudanças (2026-05-11):** adicionada secção de **temas sazonais
|
||||||
> de UI** (`UI/Themes/`), com tutorial §4.7, regra de "no hard ref a textura
|
> de UI** (`UI/Themes/`), com tutorial §4.7, regra de "no hard ref a textura
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
O ZMMO usa modelo de atributos estilo Ragnarok Online — 6 stats primários que o jogador aloca pontos (STR/AGI/VIT/INT/DEX/LUK), com stats derivados calculados a partir deles + level + classe + equip. Jogador nasce **Aprendiz** (Novice) e especializa em outras classes ao chegar a critérios (job level + quest de mudança).
|
O ZMMO usa modelo de atributos estilo Ragnarok Online — 6 stats primários que o jogador aloca pontos (STR/AGI/VIT/INT/DEX/LUK), com stats derivados calculados a partir deles + level + classe + equip. Jogador nasce **Novato** (Novice) e especializa em outras classes ao chegar a critérios (job level + quest de mudança).
|
||||||
|
|
||||||
Este doc fixa:
|
Este doc fixa:
|
||||||
1. O que persiste no MySQL (CharServer) vs o que vive em memória (WorldServer).
|
1. O que persiste no MySQL (CharServer) vs o que vive em memória (WorldServer).
|
||||||
@@ -58,10 +58,10 @@ Padrão rathena: `db/re/job_stats.yml` carregado no boot. Hot-reloadable.
|
|||||||
|
|
||||||
| Componente | Quem decide | Quem persiste |
|
| Componente | Quem decide | Quem persiste |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Criar char (stats iniciais, class=Aprendiz) | CharServer (valida) | CharServer → MySQL |
|
| Criar char (stats iniciais, class=Novato) | CharServer (valida) | CharServer → MySQL |
|
||||||
| Stat allocation (gastar `status_point` em STR/etc.) | CharServer **ou** WorldServer | CharServer → MySQL (via writeback) |
|
| Stat allocation (gastar `status_point` em STR/etc.) | CharServer **ou** WorldServer | CharServer → MySQL (via writeback) |
|
||||||
| Subir de level / ganhar EXP | WorldServer (kill mob, quest) | WorldServer → writeback → CharServer → MySQL |
|
| Subir de level / ganhar EXP | WorldServer (kill mob, quest) | WorldServer → writeback → CharServer → MySQL |
|
||||||
| Mudar classe (Aprendiz → Espadachim) | WorldServer (cumpre quest) | WorldServer → writeback → CharServer → MySQL |
|
| Mudar classe (Novato → Espadachim) | WorldServer (cumpre quest) | WorldServer → writeback → CharServer → MySQL |
|
||||||
| Recalcular ATK/MATK/DEF/etc. | WorldServer (memória, toda hora) | NÃO persiste |
|
| Recalcular ATK/MATK/DEF/etc. | WorldServer (memória, toda hora) | NÃO persiste |
|
||||||
| Casting de skill | WorldServer | NÃO persiste (efêmero) |
|
| Casting de skill | WorldServer | NÃO persiste (efêmero) |
|
||||||
| Resultado de skill (HP perdido, item dropado) | WorldServer | WorldServer → writeback |
|
| Resultado de skill (HP perdido, item dropado) | WorldServer | WorldServer → writeback |
|
||||||
@@ -260,7 +260,7 @@ version: 1
|
|||||||
jobs:
|
jobs:
|
||||||
- id: 0
|
- id: 0
|
||||||
name: Novice # nome técnico (inglês, estável)
|
name: Novice # nome técnico (inglês, estável)
|
||||||
display_name_ptbr: Aprendiz
|
display_name_ptbr: Novato
|
||||||
parent_job: null
|
parent_job: null
|
||||||
max_base_level: 99
|
max_base_level: 99
|
||||||
max_job_level: 10
|
max_job_level: 10
|
||||||
@@ -322,7 +322,7 @@ jobs:
|
|||||||
|
|
||||||
## 5. Fluxos
|
## 5. Fluxos
|
||||||
|
|
||||||
### 5.1 Criação de personagem (Aprendiz)
|
### 5.1 Criação de personagem (Novato)
|
||||||
|
|
||||||
```
|
```
|
||||||
Cliente → C_CHAR_CREATE { name, world_id, class_id=NOVICE, appearance }
|
Cliente → C_CHAR_CREATE { name, world_id, class_id=NOVICE, appearance }
|
||||||
@@ -342,7 +342,7 @@ CharServer:
|
|||||||
4. → S_CHAR_CREATE_OK
|
4. → S_CHAR_CREATE_OK
|
||||||
```
|
```
|
||||||
|
|
||||||
**Nota:** o player **sempre** nasce Aprendiz. Outras classes só via job change in-game (Fase pós-Fase 3).
|
**Nota:** o player **sempre** nasce Novato. Outras classes só via job change in-game (Fase pós-Fase 3).
|
||||||
|
|
||||||
### 5.2 Stat allocation (após level up)
|
### 5.2 Stat allocation (após level up)
|
||||||
|
|
||||||
@@ -377,7 +377,7 @@ WorldServer (em kill mob / complete quest):
|
|||||||
|
|
||||||
Mesmo padrão pra job_exp/job_level (com skill_point em vez de status_point).
|
Mesmo padrão pra job_exp/job_level (com skill_point em vez de status_point).
|
||||||
|
|
||||||
### 5.4 Job change (Aprendiz → Espadachim, etc.)
|
### 5.4 Job change (Novato → Espadachim, etc.)
|
||||||
|
|
||||||
```
|
```
|
||||||
WorldServer (player cumpriu quest):
|
WorldServer (player cumpriu quest):
|
||||||
@@ -571,13 +571,13 @@ Audit log entries (Fase 3 do ServerSelect doc): toda mudança de zeny>1000, leve
|
|||||||
|
|
||||||
## 8. Roadmap de implementação
|
## 8. Roadmap de implementação
|
||||||
|
|
||||||
### Fase A — Schema + criação de char Aprendiz (parte da Fase 1 do ServerSelect)
|
### Fase A — Schema + criação de char Novato (parte da Fase 1 do ServerSelect)
|
||||||
|
|
||||||
- Schema `characters` com todos os campos (já especificado no `ARQUITETURA_SERVER_SELECT.md`).
|
- Schema `characters` com todos os campos (já especificado no `ARQUITETURA_SERVER_SELECT.md`).
|
||||||
- `jobs.yml` apenas com `Novice` (Aprendiz) — outras classes ficam pra B.
|
- `jobs.yml` apenas com `Novice` (Novato) — outras classes ficam pra B.
|
||||||
- CharServer carrega `jobs.yml` no boot.
|
- CharServer carrega `jobs.yml` no boot.
|
||||||
- `C_CHAR_CREATE` valida `class_id == NOVICE` e usa defaults do yml.
|
- `C_CHAR_CREATE` valida `class_id == NOVICE` e usa defaults do yml.
|
||||||
- Cliente UI: tela de criação com nome + appearance (sem stat allocation aqui — Aprendiz nasce com todos os stats=1).
|
- Cliente UI: tela de criação com nome + appearance (sem stat allocation aqui — Novato nasce com todos os stats=1).
|
||||||
|
|
||||||
### Fase B — Classes adicionais + job change
|
### Fase B — Classes adicionais + job change
|
||||||
|
|
||||||
@@ -628,7 +628,7 @@ Audit log entries (Fase 3 do ServerSelect doc): toda mudança de zeny>1000, leve
|
|||||||
1. **Stats primários flat** na tabela `characters` (str/agi/vit/int/dex/luk + level/exp + hp/sp/max_hp/max_sp + status_point/skill_point + zeny + class_id). **Sem entidade separada.**
|
1. **Stats primários flat** na tabela `characters` (str/agi/vit/int/dex/luk + level/exp + hp/sp/max_hp/max_sp + status_point/skill_point + zeny + class_id). **Sem entidade separada.**
|
||||||
2. **Stats derivados NUNCA persistidos** — sempre recalculados em runtime no WorldServer (`StatusCalc::ComputeAll`).
|
2. **Stats derivados NUNCA persistidos** — sempre recalculados em runtime no WorldServer (`StatusCalc::ComputeAll`).
|
||||||
3. **Jobs data-driven** via `Server/ZeusCharServer/data/jobs.yml` (versionado no git, hot-reloadable). `characters.class_id` é lookup lógico.
|
3. **Jobs data-driven** via `Server/ZeusCharServer/data/jobs.yml` (versionado no git, hot-reloadable). `characters.class_id` é lookup lógico.
|
||||||
4. **Player nasce Aprendiz** (`class_id=NOVICE`); especialização via quest in-game (Fase B).
|
4. **Player nasce Novato** (`class_id=NOVICE`); especialização via quest in-game (Fase B).
|
||||||
5. **Stat allocation acontece no WorldServer** (não CharServer). Validação `cost = (s-1)/10 + 2` server-side.
|
5. **Stat allocation acontece no WorldServer** (não CharServer). Validação `cost = (s-1)/10 + 2` server-side.
|
||||||
6. **Anti-cheat:** toda mudança de estado é server-authoritative. Cliente apenas renderiza.
|
6. **Anti-cheat:** toda mudança de estado é server-authoritative. Cliente apenas renderiza.
|
||||||
7. **Fórmulas espelham rathena** (`status_calc_pc_` em `src/map/status.cpp:4996`) — adapta valores pra balanceamento Zeus depois.
|
7. **Fórmulas espelham rathena** (`status_calc_pc_` em `src/map/status.cpp:4996`) — adapta valores pra balanceamento Zeus depois.
|
||||||
|
|||||||
@@ -311,11 +311,11 @@ ALTER TABLE characters
|
|||||||
**Notas:**
|
**Notas:**
|
||||||
- `world_id` é nullable (sem chars em prod hoje — evita downtime futuro). Validação no service: novos chars devem ter `world_id`.
|
- `world_id` é nullable (sem chars em prod hoje — evita downtime futuro). Validação no service: novos chars devem ter `world_id`.
|
||||||
- Estrutura flat segue rathena (`.bases/rathena/rathena-master/sql-files/main.sql:209-296`) — padrão da indústria emuladora. Sem entidade `character_stats` separada (1:1 FK seria JOIN inútil).
|
- Estrutura flat segue rathena (`.bases/rathena/rathena-master/sql-files/main.sql:209-296`) — padrão da indústria emuladora. Sem entidade `character_stats` separada (1:1 FK seria JOIN inútil).
|
||||||
- Defaults vêm da row Aprendiz no `jobs.yml` (ver doc Character Model).
|
- Defaults vêm da row Novato no `jobs.yml` (ver doc Character Model).
|
||||||
- **Stats derivados (ATK/MATK/DEF/MDEF/hit/flee/crit/aspd) NÃO entram aqui** — são sempre recalculados em runtime no WorldServer via fórmulas. Persistir é bug fest (esquece atualizar quando muda equip/buff/level).
|
- **Stats derivados (ATK/MATK/DEF/MDEF/hit/flee/crit/aspd) NÃO entram aqui** — são sempre recalculados em runtime no WorldServer via fórmulas. Persistir é bug fest (esquece atualizar quando muda equip/buff/level).
|
||||||
- `version` (optimistic locking) usado em writeback da Fase 3.
|
- `version` (optimistic locking) usado em writeback da Fase 3.
|
||||||
|
|
||||||
> **Para o detalhamento do modelo de personagem** (stats primários vs derivados, fórmulas de ATK/MATK/DEF, jobs.yml, stat allocation, leveling curve, classes Aprendiz → especialização), ver doc dedicado [`ARQUITETURA_CHARACTER_MODEL.md`](ARQUITETURA_CHARACTER_MODEL.md).
|
> **Para o detalhamento do modelo de personagem** (stats primários vs derivados, fórmulas de ATK/MATK/DEF, jobs.yml, stat allocation, leveling curve, classes Novato → especialização), ver doc dedicado [`ARQUITETURA_CHARACTER_MODEL.md`](ARQUITETURA_CHARACTER_MODEL.md).
|
||||||
|
|
||||||
### Schema Valkey (Fase 2+)
|
### Schema Valkey (Fase 2+)
|
||||||
|
|
||||||
|
|||||||
BIN
Content/ZMMO/Data/Jobs/Beginner/DA_Job_Novice.uasset
Normal file
BIN
Content/ZMMO/Data/Jobs/Beginner/DA_Job_Novice.uasset
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Arcanist.uasset
Normal file
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Arcanist.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Artisan.uasset
Normal file
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Artisan.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Devout.uasset
Normal file
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Devout.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Ranger.uasset
Normal file
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Ranger.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Rogue.uasset
Normal file
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Rogue.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Warrior.uasset
Normal file
BIN
Content/ZMMO/Data/Jobs/Vocation/DA_Job_Warrior.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -27,6 +27,7 @@ enum class EZMMOInGameUIState : uint8
|
|||||||
None, ///< Antes do player local spawnar; UI in-game inativa.
|
None, ///< Antes do player local spawnar; UI in-game inativa.
|
||||||
Playing, ///< HUD principal visivel (HP/SP/level/etc).
|
Playing, ///< HUD principal visivel (HP/SP/level/etc).
|
||||||
StatusWindow, ///< Janela de atributos + botões de alocacao (Fase 4).
|
StatusWindow, ///< Janela de atributos + botões de alocacao (Fase 4).
|
||||||
|
JobChangePanel, ///< Painel de promocao de classe (Jobs.1). Toggle tecla J.
|
||||||
Inventory, ///< (futuro) Bag/equipamentos.
|
Inventory, ///< (futuro) Bag/equipamentos.
|
||||||
SkillTree, ///< (futuro) Arvore de skills.
|
SkillTree, ///< (futuro) Arvore de skills.
|
||||||
EscapeMenu, ///< (futuro) Pausa, settings, logout.
|
EscapeMenu, ///< (futuro) Pausa, settings, logout.
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ void AZMMOPlayerController::SetupInputComponent()
|
|||||||
this, &AZMMOPlayerController::ToggleStatusWindow);
|
this, &AZMMOPlayerController::ToggleStatusWindow);
|
||||||
Binding.bConsumeInput = true;
|
Binding.bConsumeInput = true;
|
||||||
Binding.bExecuteWhenPaused = true; // dispara mesmo com StatusWindow aberto (CommonUI menu mode)
|
Binding.bExecuteWhenPaused = true; // dispara mesmo com StatusWindow aberto (CommonUI menu mode)
|
||||||
|
|
||||||
|
// Hotkey J -> toggle JobChangePanel (Jobs.1).
|
||||||
|
FInputKeyBinding& JobBinding = InputComponent->BindKey(
|
||||||
|
FInputChord(EKeys::J, /*bShift*/ false, /*bCtrl*/ false, /*bAlt*/ false, /*bCmd*/ false),
|
||||||
|
IE_Pressed,
|
||||||
|
this, &AZMMOPlayerController::ToggleJobChangePanel);
|
||||||
|
JobBinding.bConsumeInput = true;
|
||||||
|
JobBinding.bExecuteWhenPaused = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +126,17 @@ void AZMMOPlayerController::ToggleStatusWindow()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AZMMOPlayerController::ToggleJobChangePanel()
|
||||||
|
{
|
||||||
|
if (UGameInstance* GI = GetGameInstance())
|
||||||
|
{
|
||||||
|
if (UUIInGameFlowSubsystem* Flow = GI->GetSubsystem<UUIInGameFlowSubsystem>())
|
||||||
|
{
|
||||||
|
Flow->ToggleScreen(EZMMOInGameUIState::JobChangePanel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool AZMMOPlayerController::ShouldUseTouchControls() const
|
bool AZMMOPlayerController::ShouldUseTouchControls() const
|
||||||
{
|
{
|
||||||
return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls;
|
return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls;
|
||||||
|
|||||||
@@ -50,4 +50,7 @@ protected:
|
|||||||
|
|
||||||
/** Hotkey Alt+A → toggle StatusWindow via UUIInGameFlowSubsystem. */
|
/** Hotkey Alt+A → toggle StatusWindow via UUIInGameFlowSubsystem. */
|
||||||
void ToggleStatusWindow();
|
void ToggleStatusWindow();
|
||||||
|
|
||||||
|
/** Hotkey J → toggle JobChangePanel (Jobs.1 — promocao de classe). */
|
||||||
|
void ToggleJobChangePanel();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -57,7 +57,11 @@ void UZMMOGameInstance::BindZeusDelegates(UZeusNetworkSubsystem* Zeus)
|
|||||||
Zeus->OnConnected.AddDynamic(this, &UZMMOGameInstance::HandleZeusConnected);
|
Zeus->OnConnected.AddDynamic(this, &UZMMOGameInstance::HandleZeusConnected);
|
||||||
Zeus->OnConnectionFailed.AddDynamic(this, &UZMMOGameInstance::HandleZeusConnectionFailed);
|
Zeus->OnConnectionFailed.AddDynamic(this, &UZMMOGameInstance::HandleZeusConnectionFailed);
|
||||||
Zeus->OnDisconnected.AddDynamic(this, &UZMMOGameInstance::HandleZeusDisconnected);
|
Zeus->OnDisconnected.AddDynamic(this, &UZMMOGameInstance::HandleZeusDisconnected);
|
||||||
Zeus->OnNetworkLog.AddDynamic(this, &UZMMOGameInstance::HandleZeusNetworkLog);
|
// OnNetworkLog: NAO assinamos. Plugin ja loga em LogZeusNetwork (console)
|
||||||
|
// + arquivo proprio em Saved/Logs/ZeusNetwork/. Forwarding em LogZMMO era
|
||||||
|
// diagnostico inicial (sessao 2026-05-07); agora gera duplicacao de cada
|
||||||
|
// linha. Remova esta nota e descomente abaixo se quiser ver no LogZMMO:
|
||||||
|
// Zeus->OnNetworkLog.AddDynamic(this, &UZMMOGameInstance::HandleZeusNetworkLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UZMMOGameInstance::UnbindZeusDelegates(UZeusNetworkSubsystem* Zeus)
|
void UZMMOGameInstance::UnbindZeusDelegates(UZeusNetworkSubsystem* Zeus)
|
||||||
@@ -69,7 +73,7 @@ void UZMMOGameInstance::UnbindZeusDelegates(UZeusNetworkSubsystem* Zeus)
|
|||||||
Zeus->OnConnected.RemoveDynamic(this, &UZMMOGameInstance::HandleZeusConnected);
|
Zeus->OnConnected.RemoveDynamic(this, &UZMMOGameInstance::HandleZeusConnected);
|
||||||
Zeus->OnConnectionFailed.RemoveDynamic(this, &UZMMOGameInstance::HandleZeusConnectionFailed);
|
Zeus->OnConnectionFailed.RemoveDynamic(this, &UZMMOGameInstance::HandleZeusConnectionFailed);
|
||||||
Zeus->OnDisconnected.RemoveDynamic(this, &UZMMOGameInstance::HandleZeusDisconnected);
|
Zeus->OnDisconnected.RemoveDynamic(this, &UZMMOGameInstance::HandleZeusDisconnected);
|
||||||
Zeus->OnNetworkLog.RemoveDynamic(this, &UZMMOGameInstance::HandleZeusNetworkLog);
|
// OnNetworkLog: nao foi assinado (ver BindZeusDelegates) — nada a remover.
|
||||||
}
|
}
|
||||||
|
|
||||||
void UZMMOGameInstance::HandleZeusConnected()
|
void UZMMOGameInstance::HandleZeusConnected()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Snapshot completo dos atributos do char vindo do server via
|
* Snapshot completo dos atributos do char vindo do server via
|
||||||
* S_ATTRIBUTE_SNAPSHOT_FULL (opcode 1200).
|
* S_ATTRIBUTE_SNAPSHOT_FULL (opcode 1500).
|
||||||
*
|
*
|
||||||
* Cliente NUNCA recalcula derivados — apenas exibe o que recebe. Os campos
|
* Cliente NUNCA recalcula derivados — apenas exibe o que recebe. Os campos
|
||||||
* HP/MaxHp/SP/MaxSp ja sao os "efetivos" (base + equip + buff somados no
|
* HP/MaxHp/SP/MaxSp ja sao os "efetivos" (base + equip + buff somados no
|
||||||
|
|||||||
67
Source/ZMMOJobs/Private/ZMMOJobChangeNetworkHandler.cpp
Normal file
67
Source/ZMMOJobs/Private/ZMMOJobChangeNetworkHandler.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include "ZMMOJobChangeNetworkHandler.h"
|
||||||
|
|
||||||
|
#include "Engine/GameInstance.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
|
#include "ZeusNetworkSubsystem.h"
|
||||||
|
|
||||||
|
DEFINE_LOG_CATEGORY_STATIC(LogZMMOJobChange, Log, All);
|
||||||
|
|
||||||
|
bool UZMMOJobChangeNetworkHandler::ShouldCreateSubsystem(UObject* Outer) const
|
||||||
|
{
|
||||||
|
// Mesmo criterio do AttributeNetworkHandler — so' em mundos de gameplay
|
||||||
|
// (PIE / standalone in-game). Editor preview / front-end menu nao precisa.
|
||||||
|
const UWorld* World = Cast<UWorld>(Outer);
|
||||||
|
if (World == nullptr) { return false; }
|
||||||
|
return World->WorldType == EWorldType::Game
|
||||||
|
|| World->WorldType == EWorldType::PIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UZMMOJobChangeNetworkHandler::Initialize(FSubsystemCollectionBase& Collection)
|
||||||
|
{
|
||||||
|
Super::Initialize(Collection);
|
||||||
|
|
||||||
|
if (UZeusNetworkSubsystem* Net = GetZeusNetSubsystem())
|
||||||
|
{
|
||||||
|
JobChangeResultHandle = Net->OnJobChangeResult.AddUObject(
|
||||||
|
this, &UZMMOJobChangeNetworkHandler::HandleJobChangeResult);
|
||||||
|
UE_LOG(LogZMMOJobChange, Log,
|
||||||
|
TEXT("[ZMMOJobChangeNetworkHandler] Bind OnJobChangeResult OK"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UE_LOG(LogZMMOJobChange, Warning,
|
||||||
|
TEXT("[ZMMOJobChangeNetworkHandler] ZeusNetworkSubsystem indisponivel — bind pulado"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UZMMOJobChangeNetworkHandler::Deinitialize()
|
||||||
|
{
|
||||||
|
if (UZeusNetworkSubsystem* Net = GetZeusNetSubsystem())
|
||||||
|
{
|
||||||
|
if (JobChangeResultHandle.IsValid())
|
||||||
|
{
|
||||||
|
Net->OnJobChangeResult.Remove(JobChangeResultHandle);
|
||||||
|
JobChangeResultHandle.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OnJobChangeResult.Clear();
|
||||||
|
Super::Deinitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UZMMOJobChangeNetworkHandler::HandleJobChangeResult(
|
||||||
|
bool bAccepted, int32 Reason, int32 NewClassId)
|
||||||
|
{
|
||||||
|
UE_LOG(LogZMMOJobChange, Log,
|
||||||
|
TEXT("[ZMMOJobChangeNetworkHandler] S_JOB_CHANGE_RESULT accepted=%d reason=%d newClassId=%d"),
|
||||||
|
bAccepted ? 1 : 0, Reason, NewClassId);
|
||||||
|
OnJobChangeResult.Broadcast(bAccepted, Reason, NewClassId);
|
||||||
|
}
|
||||||
|
|
||||||
|
UZeusNetworkSubsystem* UZMMOJobChangeNetworkHandler::GetZeusNetSubsystem() const
|
||||||
|
{
|
||||||
|
const UWorld* World = GetWorld();
|
||||||
|
if (World == nullptr) { return nullptr; }
|
||||||
|
UGameInstance* GI = World->GetGameInstance();
|
||||||
|
if (GI == nullptr) { return nullptr; }
|
||||||
|
return GI->GetSubsystem<UZeusNetworkSubsystem>();
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Engine/World.h"
|
#include "Engine/World.h"
|
||||||
#include "ZMMOJobDataAsset.h"
|
#include "ZMMOJobDataAsset.h"
|
||||||
#include "ZMMOJobsSubsystem.h"
|
#include "ZMMOJobsSubsystem.h"
|
||||||
|
#include "ZeusNetworkSubsystem.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -52,3 +53,37 @@ bool UZMMOJobsLibrary::IsJobRegistered(const UObject* WorldContextObject, int32
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TArray<UZMMOJobDataAsset*> UZMMOJobsLibrary::GetJobsByTier(
|
||||||
|
const UObject* WorldContextObject, EZMMOJobTier Tier)
|
||||||
|
{
|
||||||
|
if (UZMMOJobsSubsystem* Sub = ResolveSubsystem(WorldContextObject))
|
||||||
|
{
|
||||||
|
return Sub->GetJobsByTier(Tier);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<UZMMOJobDataAsset*> UZMMOJobsLibrary::GetEligibleNextJobs(
|
||||||
|
const UObject* WorldContextObject, int32 CurrentClassId)
|
||||||
|
{
|
||||||
|
if (UZMMOJobsSubsystem* Sub = ResolveSubsystem(WorldContextObject))
|
||||||
|
{
|
||||||
|
return Sub->GetEligibleNextJobs(CurrentClassId);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void UZMMOJobsLibrary::SendJobChangeRequest(
|
||||||
|
const UObject* WorldContextObject, int32 TargetClassId)
|
||||||
|
{
|
||||||
|
if (WorldContextObject == nullptr) { return; }
|
||||||
|
const UWorld* World = WorldContextObject->GetWorld();
|
||||||
|
if (World == nullptr) { return; }
|
||||||
|
UGameInstance* GI = World->GetGameInstance();
|
||||||
|
if (GI == nullptr) { return; }
|
||||||
|
if (UZeusNetworkSubsystem* Net = GI->GetSubsystem<UZeusNetworkSubsystem>())
|
||||||
|
{
|
||||||
|
Net->SendJobChangeRequest(TargetClassId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,3 +65,32 @@ UZMMOJobDataAsset* UZMMOJobsSubsystem::GetJobData(int32 ClassId) const
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TArray<UZMMOJobDataAsset*> UZMMOJobsSubsystem::GetJobsByTier(EZMMOJobTier Tier) const
|
||||||
|
{
|
||||||
|
TArray<UZMMOJobDataAsset*> Out;
|
||||||
|
Out.Reserve(CachedJobs.Num());
|
||||||
|
for (const TPair<int32, TObjectPtr<UZMMOJobDataAsset>>& Pair : CachedJobs)
|
||||||
|
{
|
||||||
|
if (Pair.Value && Pair.Value->Tier == Tier)
|
||||||
|
{
|
||||||
|
Out.Add(Pair.Value.Get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<UZMMOJobDataAsset*> UZMMOJobsSubsystem::GetEligibleNextJobs(int32 CurrentClassId) const
|
||||||
|
{
|
||||||
|
TArray<UZMMOJobDataAsset*> Out;
|
||||||
|
Out.Reserve(4); // tipico: 2-6 destinos
|
||||||
|
for (const TPair<int32, TObjectPtr<UZMMOJobDataAsset>>& Pair : CachedJobs)
|
||||||
|
{
|
||||||
|
if (Pair.Value && Pair.Value->ParentClassId == CurrentClassId
|
||||||
|
&& Pair.Value->ClassId != CurrentClassId)
|
||||||
|
{
|
||||||
|
Out.Add(Pair.Value.Get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Out;
|
||||||
|
}
|
||||||
|
|||||||
54
Source/ZMMOJobs/Public/ZMMOJobChangeNetworkHandler.h
Normal file
54
Source/ZMMOJobs/Public/ZMMOJobChangeNetworkHandler.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Subsystems/WorldSubsystem.h"
|
||||||
|
#include "ZMMOJobChangeNetworkHandler.generated.h"
|
||||||
|
|
||||||
|
class UZeusNetworkSubsystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multicast dinamico assignable em Blueprint. WBP de promocao binda no
|
||||||
|
* OnJobChangeResult pra reagir ao S_JOB_CHANGE_RESULT (1520) do server.
|
||||||
|
*
|
||||||
|
* Parametros:
|
||||||
|
* - bAccepted : true = promocao aplicada (S_ATTRIBUTE_SNAPSHOT_FULL
|
||||||
|
* chega logo apos com state novo).
|
||||||
|
* - Reason : EJobChangeRejectReason (None/NoSession/UnknownJob/
|
||||||
|
* NotParent/WrongTier/JobLevelTooLow/AlreadyAtTarget/
|
||||||
|
* JobsDbUnavailable). Significativo apenas se !bAccepted.
|
||||||
|
* - NewClassId : significativo apenas se bAccepted=true (redundante com
|
||||||
|
* snapshot que vem junto, mas util pra triggers/toasts).
|
||||||
|
*/
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FZMMOOnJobChangeResultBP,
|
||||||
|
bool, bAccepted, int32, Reason, int32, NewClassId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bridge entre o `UZeusNetworkSubsystem` (do plugin ZeusNetwork) e a UI
|
||||||
|
* Blueprint (WBP de promocao). Mesmo pattern do `UZMMOAttributeNetworkHandler`
|
||||||
|
* — converte o delegate C++-only `FZeusOnJobChangeResult` num dynamic
|
||||||
|
* multicast (`FZMMOOnJobChangeResultBP`) assignavel em BP.
|
||||||
|
*
|
||||||
|
* Por que UWorldSubsystem? Player so' faz promocao quando ja' esta no
|
||||||
|
* WorldServer (com mundo carregado). No front-end / lobby, esse subsystem
|
||||||
|
* nao existe — economiza memoria.
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class ZMMOJOBS_API UZMMOJobChangeNetworkHandler : public UWorldSubsystem
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||||
|
virtual void Deinitialize() override;
|
||||||
|
virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
|
||||||
|
|
||||||
|
/// Assignavel em BP: WBP_JobChangePanel.OnEvent_OnJobChangeResult.
|
||||||
|
UPROPERTY(BlueprintAssignable, Category = "Zeus|Jobs")
|
||||||
|
FZMMOOnJobChangeResultBP OnJobChangeResult;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void HandleJobChangeResult(bool bAccepted, int32 Reason, int32 NewClassId);
|
||||||
|
UZeusNetworkSubsystem* GetZeusNetSubsystem() const;
|
||||||
|
|
||||||
|
FDelegateHandle JobChangeResultHandle;
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "Engine/DataAsset.h"
|
#include "Engine/DataAsset.h"
|
||||||
|
#include "ZMMOJobTypes.h"
|
||||||
#include "ZMMOJobDataAsset.generated.h"
|
#include "ZMMOJobDataAsset.generated.h"
|
||||||
|
|
||||||
class UTexture2D;
|
class UTexture2D;
|
||||||
@@ -39,11 +40,28 @@ public:
|
|||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job")
|
||||||
FString TechnicalName;
|
FString TechnicalName;
|
||||||
|
|
||||||
/// Nome localizado exibido na UI (pt-BR no projeto base). Ex: "Aprendiz".
|
/// Nome localizado exibido na UI (pt-BR no projeto base). Ex: "Novato".
|
||||||
/// Pode usar FText Localization tables pra multi-idioma futuro.
|
/// Pode usar FText Localization tables pra multi-idioma futuro.
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job")
|
||||||
FText DisplayName;
|
FText DisplayName;
|
||||||
|
|
||||||
|
/// Tier hierarquico — espelha `JobDef::tier` do server. UI usa pra agrupar
|
||||||
|
/// jobs (ex: lista de Vocacoes possiveis quando promovendo Novato).
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job")
|
||||||
|
EZMMOJobTier Tier = EZMMOJobTier::Beginner;
|
||||||
|
|
||||||
|
/// ClassId do parent na arvore de promocao. 0 = sem parent (Novato eh root).
|
||||||
|
/// Espelha `JobDef::parentJobId` do server. UI usa pra filtrar destinos
|
||||||
|
/// possiveis ao mostrar painel de promocao.
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job")
|
||||||
|
int32 ParentClassId = 0;
|
||||||
|
|
||||||
|
/// Lista de armas que o job pode equipar. Espelha `JobDef::allowedWeaponsMask`
|
||||||
|
/// do server (mas como TArray pra editor visual em vez de bitmask cru).
|
||||||
|
/// Inventory UI usa pra hint "nao pode equipar" + filtro de catalogo.
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job")
|
||||||
|
TArray<EZMMOWeaponType> AllowedWeapons;
|
||||||
|
|
||||||
/// Icone do job — usado em StatusWindow, CharacterCard, JobChangeUI.
|
/// Icone do job — usado em StatusWindow, CharacterCard, JobChangeUI.
|
||||||
/// Soft ptr: nao carrega ate alguem chamar LoadSynchronous() ou async load.
|
/// Soft ptr: nao carrega ate alguem chamar LoadSynchronous() ou async load.
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job|Assets")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Zeus|Job|Assets")
|
||||||
|
|||||||
57
Source/ZMMOJobs/Public/ZMMOJobTypes.h
Normal file
57
Source/ZMMOJobs/Public/ZMMOJobTypes.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "ZMMOJobTypes.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tier hierarquico de um job. Espelha `EJobTier` do server em
|
||||||
|
* `Server/.../JobsSystem/Public/JobTypes.hpp`. Valores TEM que bater
|
||||||
|
* byte-a-byte com a enum do server porque o snapshot pode carregar
|
||||||
|
* tier como uint8 no futuro.
|
||||||
|
*
|
||||||
|
* Renascer (RO pre-renewal): char no Tier 2 (Specialization) que cumpre
|
||||||
|
* condicao volta pra Tier 3 (RebornBeginner) com bonus permanente,
|
||||||
|
* abrindo path paralelo RebornVocation → Mastery (coroa final).
|
||||||
|
*/
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum class EZMMOJobTier : uint8
|
||||||
|
{
|
||||||
|
Beginner = 0 UMETA(DisplayName = "Iniciante"),
|
||||||
|
Vocation = 1 UMETA(DisplayName = "Vocacao"),
|
||||||
|
Specialization = 2 UMETA(DisplayName = "Especializacao"),
|
||||||
|
RebornBeginner = 3 UMETA(DisplayName = "Iniciante Renascido"),
|
||||||
|
RebornVocation = 4 UMETA(DisplayName = "Vocacao Renascida"),
|
||||||
|
Mastery = 5 UMETA(DisplayName = "Mestria"),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tipos de arma. Espelha `EWeaponType` do server. Usado em `AllowedWeapons`
|
||||||
|
* do DA pra UI (filtrar items equipaveis) + validacao server-side futura
|
||||||
|
* quando InventorySystem entrar.
|
||||||
|
*
|
||||||
|
* Ordem TEM que bater com server porque o bitmask `allowedWeaponsMask` no
|
||||||
|
* JobDef usa bit N = EWeaponType(N).
|
||||||
|
*/
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum class EZMMOWeaponType : uint8
|
||||||
|
{
|
||||||
|
Fist = 0 UMETA(DisplayName = "Punho"),
|
||||||
|
Dagger = 1 UMETA(DisplayName = "Adaga"),
|
||||||
|
Sword1H = 2 UMETA(DisplayName = "Espada 1M"),
|
||||||
|
Sword2H = 3 UMETA(DisplayName = "Espada 2M"),
|
||||||
|
Spear1H = 4 UMETA(DisplayName = "Lanca 1M"),
|
||||||
|
Spear2H = 5 UMETA(DisplayName = "Lanca 2M"),
|
||||||
|
Axe1H = 6 UMETA(DisplayName = "Machado 1M"),
|
||||||
|
Axe2H = 7 UMETA(DisplayName = "Machado 2M"),
|
||||||
|
Mace1H = 8 UMETA(DisplayName = "Maca 1M"),
|
||||||
|
Mace2H = 9 UMETA(DisplayName = "Maca 2M"),
|
||||||
|
Staff1H = 10 UMETA(DisplayName = "Cajado 1M"),
|
||||||
|
Staff2H = 11 UMETA(DisplayName = "Cajado 2M"),
|
||||||
|
Bow = 12 UMETA(DisplayName = "Arco"),
|
||||||
|
Knuckle = 13 UMETA(DisplayName = "Soqueira"),
|
||||||
|
Musical = 14 UMETA(DisplayName = "Instrumento Musical"),
|
||||||
|
Whip = 15 UMETA(DisplayName = "Chicote"),
|
||||||
|
Book = 16 UMETA(DisplayName = "Livro"),
|
||||||
|
Katar = 17 UMETA(DisplayName = "Katar"),
|
||||||
|
Gun = 18 UMETA(DisplayName = "Arma de Fogo"),
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||||
|
#include "ZMMOJobTypes.h"
|
||||||
#include "ZMMOJobsLibrary.generated.h"
|
#include "ZMMOJobsLibrary.generated.h"
|
||||||
|
|
||||||
class UZMMOJobDataAsset;
|
class UZMMOJobDataAsset;
|
||||||
@@ -36,4 +37,26 @@ public:
|
|||||||
UFUNCTION(BlueprintPure, Category = "Zeus|Jobs",
|
UFUNCTION(BlueprintPure, Category = "Zeus|Jobs",
|
||||||
meta = (WorldContext = "WorldContextObject"))
|
meta = (WorldContext = "WorldContextObject"))
|
||||||
static bool IsJobRegistered(const UObject* WorldContextObject, int32 ClassId);
|
static bool IsJobRegistered(const UObject* WorldContextObject, int32 ClassId);
|
||||||
|
|
||||||
|
/// Lista jobs num tier (UI dropdown). Vazio se subsystem indisponivel.
|
||||||
|
UFUNCTION(BlueprintPure, Category = "Zeus|Jobs",
|
||||||
|
meta = (WorldContext = "WorldContextObject"))
|
||||||
|
static TArray<UZMMOJobDataAsset*> GetJobsByTier(
|
||||||
|
const UObject* WorldContextObject, EZMMOJobTier Tier);
|
||||||
|
|
||||||
|
/// Destinos de promocao a partir do char atual. WBP de promocao consome
|
||||||
|
/// direto. Vazio se nao houver filhos (ex: char ja' esta em Tier 3
|
||||||
|
/// Mastery — Jobs.4 introduzira terminal de progressao).
|
||||||
|
UFUNCTION(BlueprintPure, Category = "Zeus|Jobs",
|
||||||
|
meta = (WorldContext = "WorldContextObject"))
|
||||||
|
static TArray<UZMMOJobDataAsset*> GetEligibleNextJobs(
|
||||||
|
const UObject* WorldContextObject, int32 CurrentClassId);
|
||||||
|
|
||||||
|
/// Helper de send via ZeusNetworkSubsystem. Conveniencia pra WBP nao
|
||||||
|
/// precisar pegar o subsystem manualmente. Idempotente: rejeitado
|
||||||
|
/// silenciosamente se nao conectado.
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Zeus|Jobs",
|
||||||
|
meta = (WorldContext = "WorldContextObject"))
|
||||||
|
static void SendJobChangeRequest(
|
||||||
|
const UObject* WorldContextObject, int32 TargetClassId);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "Subsystems/GameInstanceSubsystem.h"
|
#include "Subsystems/GameInstanceSubsystem.h"
|
||||||
|
#include "ZMMOJobTypes.h"
|
||||||
#include "ZMMOJobsSubsystem.generated.h"
|
#include "ZMMOJobsSubsystem.generated.h"
|
||||||
|
|
||||||
class UZMMOJobDataAsset;
|
class UZMMOJobDataAsset;
|
||||||
@@ -41,6 +42,22 @@ public:
|
|||||||
UFUNCTION(BlueprintPure, Category = "Zeus|Jobs")
|
UFUNCTION(BlueprintPure, Category = "Zeus|Jobs")
|
||||||
int32 GetJobCount() const { return CachedJobs.Num(); }
|
int32 GetJobCount() const { return CachedJobs.Num(); }
|
||||||
|
|
||||||
|
/// Lista jobs num tier especifico (UI agrupa por tier — ex: dropdown
|
||||||
|
/// "Vocacoes possiveis"). Ordem do retorno e' a do AssetRegistry scan
|
||||||
|
/// — UI pode reordenar por ClassId/DisplayName se precisar.
|
||||||
|
UFUNCTION(BlueprintPure, Category = "Zeus|Jobs")
|
||||||
|
TArray<UZMMOJobDataAsset*> GetJobsByTier(EZMMOJobTier Tier) const;
|
||||||
|
|
||||||
|
/// Destinos de promocao validos a partir do `CurrentClassId`. Filtra
|
||||||
|
/// pelos jobs que tem `ParentClassId == CurrentClassId`. WBP de
|
||||||
|
/// promocao consome direto pra montar botoes "Tornar-se X".
|
||||||
|
///
|
||||||
|
/// NOTA: condicao de elegibilidade real (jobLevel >= cap, quest, item)
|
||||||
|
/// e' do server — UI apenas LISTA opcoes possiveis pelo schema. Server
|
||||||
|
/// reponde rejeicao via S_JOB_CHANGE_RESULT (Jobs::EJobChangeRejectReason).
|
||||||
|
UFUNCTION(BlueprintPure, Category = "Zeus|Jobs")
|
||||||
|
TArray<UZMMOJobDataAsset*> GetEligibleNextJobs(int32 CurrentClassId) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Scan AssetRegistry + popula CachedJobs. Sincronizo (V1) — chamado UMA
|
/// Scan AssetRegistry + popula CachedJobs. Sincronizo (V1) — chamado UMA
|
||||||
/// vez no Initialize. Pra 50 jobs eh aceitavel; se crescer pra 200+ pode
|
/// vez no Initialize. Pra 50 jobs eh aceitavel; se crescer pra 200+ pode
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class ZMMOJobs : ModuleRules
|
|||||||
});
|
});
|
||||||
|
|
||||||
PrivateDependencyModuleNames.AddRange(new string[] {
|
PrivateDependencyModuleNames.AddRange(new string[] {
|
||||||
"AssetRegistry" // FAssetRegistryModule pra scan de DA_Job_*
|
"AssetRegistry", // FAssetRegistryModule pra scan de DA_Job_*
|
||||||
|
"ZeusNetwork" // UZeusNetworkSubsystem (SendJobChangeRequest)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Espelho do `Server/.../JobsSystem/module.json` (modulo nucleo MMO).
|
// Espelho do `Server/.../JobsSystem/module.json` (modulo nucleo MMO).
|
||||||
|
|||||||
Reference in New Issue
Block a user