Compare commits
28 Commits
server-mes
...
84f552b4fa
| Author | SHA1 | Date | |
|---|---|---|---|
| 84f552b4fa | |||
| 1308338953 | |||
| 21d42d9846 | |||
| 2895889e2b | |||
| 1114ddbb11 | |||
| 9a430dabc3 | |||
| a3f2fa9c06 | |||
| 1f2441bde7 | |||
| 216e580548 | |||
| de294f4075 | |||
| 4d737829f5 | |||
| 341e6895c9 | |||
| 5f4c88637f | |||
| 77d52a703b | |||
| 9f5ccd3a05 | |||
| c0f6d32d95 | |||
| f21d059b67 | |||
| e87b2cec6c | |||
| 9422522d6d | |||
| c3b32bc1a1 | |||
| cda5fea776 | |||
| 16de963301 | |||
| 8d73cc9df8 | |||
| d5402216a2 | |||
| ff75ad92eb | |||
| 98dce2f855 | |||
| 94442feca5 | |||
| 6a6a28a086 |
@@ -2,9 +2,9 @@
|
|||||||
GameDefaultMap=/Game/ZMMO/Maps/FrontEnd/L_FrontEnd.L_FrontEnd
|
GameDefaultMap=/Game/ZMMO/Maps/FrontEnd/L_FrontEnd.L_FrontEnd
|
||||||
EditorStartupMap=/Game/ZMMO/Maps/FrontEnd/L_FrontEnd.L_FrontEnd
|
EditorStartupMap=/Game/ZMMO/Maps/FrontEnd/L_FrontEnd.L_FrontEnd
|
||||||
; GameMode/PlayerController/PlayerCharacter agora moram em C++ (Game/Modes/Entity/Controller).
|
; GameMode/PlayerController/PlayerCharacter agora moram em C++ (Game/Modes/Entity/Controller).
|
||||||
; O motor pode spawnar AZMMOGameMode directamente; um BP filho continua opcional.
|
; O motor pode spawnar AZeusGameMode directamente; um BP filho continua opcional.
|
||||||
GlobalDefaultGameMode=/Script/ZMMO.ZMMOGameMode
|
GlobalDefaultGameMode=/Script/ZMMO.ZeusGameMode
|
||||||
GameInstanceClass=/Script/ZMMO.ZMMOGameInstance
|
GameInstanceClass=/Script/ZMMO.ZeusGameInstance
|
||||||
|
|
||||||
[/Script/Engine.RendererSettings]
|
[/Script/Engine.RendererSettings]
|
||||||
r.ReflectionMethod=1
|
r.ReflectionMethod=1
|
||||||
@@ -80,12 +80,30 @@ GameViewportClientClassName=/Script/CommonUI.CommonGameViewportClient
|
|||||||
+ActiveGameNameRedirects=(OldGameName="TP_ThirdPerson",NewGameName="/Script/ZMMO")
|
+ActiveGameNameRedirects=(OldGameName="TP_ThirdPerson",NewGameName="/Script/ZMMO")
|
||||||
+ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPerson",NewGameName="/Script/ZMMO")
|
+ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPerson",NewGameName="/Script/ZMMO")
|
||||||
; Redirects do template antigo para a nova arquitectura (Game/Modes/Entity/Controller).
|
; Redirects do template antigo para a nova arquitectura (Game/Modes/Entity/Controller).
|
||||||
; ZMMOCharacter foi reescrito como ZMMOPlayerCharacter (ACharacter local com CMC livre).
|
; Pipeline: TP_ThirdPerson* -> ZMMO* (legado) -> Zeus* (atual). Os redirects de
|
||||||
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonPlayerController",NewClassName="ZMMOPlayerController")
|
; ZMMO*->Zeus* preservam asset/BP refs criadas durante o periodo ZMMO* (Batches 1-3).
|
||||||
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonGameMode",NewClassName="ZMMOGameMode")
|
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonPlayerController",NewClassName="ZeusPlayerController")
|
||||||
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="ZMMOPlayerCharacter")
|
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonGameMode",NewClassName="ZeusGameMode")
|
||||||
+ActiveClassRedirects=(OldClassName="ZMMOCharacter",NewClassName="ZMMOPlayerCharacter")
|
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="ZeusCharacter")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOCharacter",NewClassName="ZeusCharacter")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOPlayerCharacter",NewClassName="ZeusCharacter")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOPlayerController",NewClassName="ZeusPlayerController")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOFrontEndPlayerController",NewClassName="ZeusFrontEndPlayerController")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOGameMode",NewClassName="ZeusGameMode")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOFrontEndGameMode",NewClassName="ZeusFrontEndGameMode")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOGameInstance",NewClassName="ZeusGameInstance")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOHUD",NewClassName="ZeusHUD")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOPlayerState",NewClassName="ZeusPlayerState")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOEntity",NewClassName="ZeusEntity")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOPlayerProxy",NewClassName="ZeusPlayerProxy")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOProxyMovementComponent",NewClassName="ZeusProxyMovementComponent")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOWorldSubsystem",NewClassName="ZeusWorldSubsystem")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOThemeDataAsset",NewClassName="ZeusThemeDataAsset")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOThemeSubsystem",NewClassName="ZeusThemeSubsystem")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOLoginSaveGame",NewClassName="ZeusLoginSaveGame")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOHudWidget",NewClassName="ZeusHudWidget")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOHudPlayerVitalsWidget",NewClassName="ZeusHudPlayerVitalsWidget")
|
||||||
|
+ActiveClassRedirects=(OldClassName="ZMMOLoadingProfilesDataAsset",NewClassName="ZeusLoadingProfilesDataAsset")
|
||||||
[CoreRedirects]
|
[CoreRedirects]
|
||||||
; Migração v1→v2 do FUIStylePanel: TMap<EUIPanelTexture,...> (Enum) → TMap<FName,...>.
|
; Migração v1→v2 do FUIStylePanel: TMap<EUIPanelTexture,...> (Enum) → TMap<FName,...>.
|
||||||
; Os campos *_DEPRECATED preservam a leitura do asset antigo; PostSerialize copia
|
; Os campos *_DEPRECATED preservam a leitura do asset antigo; PostSerialize copia
|
||||||
@@ -95,6 +113,27 @@ GameViewportClientClassName=/Script/CommonUI.CommonGameViewportClient
|
|||||||
+PropertyRedirects=(OldName="/Script/ZMMO.UIStylePanel.PanelOutline",NewName="/Script/ZMMO.UIStylePanel.PanelOutline_DEPRECATED")
|
+PropertyRedirects=(OldName="/Script/ZMMO.UIStylePanel.PanelOutline",NewName="/Script/ZMMO.UIStylePanel.PanelOutline_DEPRECATED")
|
||||||
+PropertyRedirects=(OldName="/Script/ZMMO.UIStylePanel.PanelOutlineEffect",NewName="/Script/ZMMO.UIStylePanel.PanelOutlineEffect_DEPRECATED")
|
+PropertyRedirects=(OldName="/Script/ZMMO.UIStylePanel.PanelOutlineEffect",NewName="/Script/ZMMO.UIStylePanel.PanelOutlineEffect_DEPRECATED")
|
||||||
|
|
||||||
|
; --- M7: Modulo cliente "ZMMOJobs" foi renomeado pra "ZeusJobs" + classe
|
||||||
|
; UZMMOJobDataAsset -> UZeusJobDataAsset. Os 7 DA_Job_* em /Game/ZMMO/Data/Jobs/
|
||||||
|
; foram salvos apontando pra /Script/ZMMOJobs.ZMMOJobDataAsset (modulo + classe
|
||||||
|
; antigos). ActiveClassRedirects so' troca o NOME da classe, nao o package;
|
||||||
|
; precisamos de CoreRedirects com path completo + PackageRedirect.
|
||||||
|
+PackageRedirects=(OldName="/Script/ZMMOJobs",NewName="/Script/ZeusJobs")
|
||||||
|
+ClassRedirects=(OldName="/Script/ZMMOJobs.ZMMOJobDataAsset",NewName="/Script/ZeusJobs.ZeusJobDataAsset")
|
||||||
|
|
||||||
|
; --- M7: USTRUCTs renomeadas (mesmo modulo ZMMO). DTs salvos com Row Structure
|
||||||
|
; apontando pro nome antigo (ZMMOMapDef, ZMMOLoadingTipRow). USTRUCT usa
|
||||||
|
; +StructRedirects (nao +ClassRedirects).
|
||||||
|
+StructRedirects=(OldName="/Script/ZMMO.ZMMOMapDef",NewName="/Script/ZMMO.ZeusMapDef")
|
||||||
|
+StructRedirects=(OldName="/Script/ZMMO.ZMMOLoadingTipRow",NewName="/Script/ZMMO.ZeusLoadingTipRow")
|
||||||
|
; DA_LoadingProfiles salvo com TMap<EZMMOLoadingContext, FZMMOLoadingProfile>;
|
||||||
|
; FZMMOLoadingProfile contem TArray<FZMMOLoadingStepDef>. Precisa de 3 redirects
|
||||||
|
; (1 enum + 2 struct) pra carregar sem warnings nem perda de dados.
|
||||||
|
+EnumRedirects=(OldName="/Script/ZMMO.EZMMOLoadingContext",NewName="/Script/ZMMO.EZeusLoadingContext")
|
||||||
|
+EnumRedirects=(OldName="/Script/ZMMO.EZMMOLoadingStepStatus",NewName="/Script/ZMMO.EZeusLoadingStepStatus")
|
||||||
|
+StructRedirects=(OldName="/Script/ZMMO.ZMMOLoadingProfile",NewName="/Script/ZMMO.ZeusLoadingProfile")
|
||||||
|
+StructRedirects=(OldName="/Script/ZMMO.ZMMOLoadingStepDef",NewName="/Script/ZMMO.ZeusLoadingStepDef")
|
||||||
|
|
||||||
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
|
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
|
||||||
bEnablePlugin=True
|
bEnablePlugin=True
|
||||||
bAllowNetworkConnection=True
|
bAllowNetworkConnection=True
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ ProjectID=FC3E256F43B2AFD43009F4949B0814BE
|
|||||||
ProjectName=Third Person Game Template
|
ProjectName=Third Person Game Template
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; ZMMO Theme subsystem (see Source/ZMMO/Game/UI/ZMMOThemeSubsystem.h and
|
; ZMMO Theme subsystem (see Source/ZMMO/Game/UI/ZeusThemeSubsystem.h and
|
||||||
; ARQUITETURA.md §1.10 / §4.7).
|
; ARQUITETURA.md §1.10 / §4.7).
|
||||||
;
|
;
|
||||||
; - DefaultThemeAsset is the fallback theme (must define every EZMMOThemeKey).
|
; - DefaultThemeAsset is the fallback theme (must define every EZeusThemeKey).
|
||||||
; - ThemeRegistry maps ThemeId -> seasonal DA_Theme_* asset.
|
; - ThemeRegistry maps ThemeId -> seasonal DA_Theme_* asset.
|
||||||
; - CalendarTable points to DT_ThemeCalendar (FThemeCalendarRow rows).
|
; - CalendarTable points to DT_ThemeCalendar (FThemeCalendarRow rows).
|
||||||
; - UIStyleTable points to DT_UI_Styles (FUIStyleRow rows): tokens de estilo
|
; - UIStyleTable points to DT_UI_Styles (FUIStyleRow rows): tokens de estilo
|
||||||
@@ -18,7 +18,7 @@ ProjectName=Third Person Game Template
|
|||||||
; assets are actually created in the editor.
|
; assets are actually created in the editor.
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
[/Script/ZMMO.ZMMOThemeSubsystem]
|
[/Script/ZMMO.ZeusThemeSubsystem]
|
||||||
;DefaultThemeAsset=/Game/ZMMO/UI/Themes/DA_Theme_Default.DA_Theme_Default
|
;DefaultThemeAsset=/Game/ZMMO/UI/Themes/DA_Theme_Default.DA_Theme_Default
|
||||||
;+ThemeRegistry=(("Christmas", "/Game/ZMMO/UI/Themes/DA_Theme_Christmas.DA_Theme_Christmas"))
|
;+ThemeRegistry=(("Christmas", "/Game/ZMMO/UI/Themes/DA_Theme_Christmas.DA_Theme_Christmas"))
|
||||||
;+ThemeRegistry=(("Halloween", "/Game/ZMMO/UI/Themes/DA_Theme_Halloween.DA_Theme_Halloween"))
|
;+ThemeRegistry=(("Halloween", "/Game/ZMMO/UI/Themes/DA_Theme_Halloween.DA_Theme_Halloween"))
|
||||||
@@ -33,20 +33,20 @@ ScreenSetAsset=/Game/ZMMO/UI/FrontEnd/DA_FrontEndScreenSet.DA_FrontEndScreenSet
|
|||||||
|
|
||||||
; Fase 4 — char spawn DB-driven. DT_Maps espelha o `maps_config.json` do
|
; Fase 4 — char spawn DB-driven. DT_Maps espelha o `maps_config.json` do
|
||||||
; server (Server/ZeusServerEngine/Config/DataTables/maps_config.json) — o
|
; server (Server/ZeusServerEngine/Config/DataTables/maps_config.json) — o
|
||||||
; cliente resolve `mapId -> ClientLevel/spawns` via FZMMOMapDef rows.
|
; cliente resolve `mapId -> ClientLevel/spawns` via FZeusMapDef rows.
|
||||||
MapsTableAsset=/Game/ZMMO/Data/World/DT_Maps.DT_Maps
|
MapsTableAsset=/Game/ZMMO/Data/World/DT_Maps.DT_Maps
|
||||||
|
|
||||||
; Loading dinâmico (etapas + dicas). DA_LoadingProfiles tem 1 perfil por
|
; Loading dinâmico (etapas + dicas). DA_LoadingProfiles tem 1 perfil por
|
||||||
; contexto (EZMMOLoadingContext); DT_LoadingTips rotaciona durante o load.
|
; contexto (EZeusLoadingContext); DT_LoadingTips rotaciona durante o load.
|
||||||
; Cliente local marca etapas via eventos (sem opcode novo).
|
; Cliente local marca etapas via eventos (sem opcode novo).
|
||||||
LoadingProfilesAsset=/Game/ZMMO/Data/UI/Loading/DA_LoadingProfiles.DA_LoadingProfiles
|
LoadingProfilesAsset=/Game/ZMMO/Data/UI/Loading/DA_LoadingProfiles.DA_LoadingProfiles
|
||||||
LoadingTipsAsset=/Game/ZMMO/Data/UI/Loading/DT_LoadingTips.DT_LoadingTips
|
LoadingTipsAsset=/Game/ZMMO/Data/UI/Loading/DT_LoadingTips.DT_LoadingTips
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; UI in-game (PR 19+). Espelho do front-end pattern:
|
; UI in-game (PR 19+). Espelho do front-end pattern:
|
||||||
; - ScreenSetAsset mapeia EZMMOInGameUIState -> WBP (Playing -> WBP_HUD,
|
; - ScreenSetAsset mapeia EZeusInGameUIState -> WBP (Playing -> WBP_HUD,
|
||||||
; StatusWindow -> WBP_StatusWindow, etc.)
|
; StatusWindow -> WBP_StatusWindow, etc.)
|
||||||
; - Subsystem orquestra: AZMMOHUD::BeginPlay chama StartInGame que vai pra
|
; - Subsystem orquestra: AZeusHUD::BeginPlay chama StartInGame que vai pra
|
||||||
; Playing.
|
; Playing.
|
||||||
; Asset criado via MCP em /Game/ZMMO/UI/InGame/DA_InGameScreenSet.
|
; Asset criado via MCP em /Game/ZMMO/UI/InGame/DA_InGameScreenSet.
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
@@ -56,16 +56,27 @@ ScreenSetAsset=/Game/ZMMO/UI/InGame/DA_InGameScreenSet.DA_InGameScreenSet
|
|||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; PlayerState Component Registry (PR 19+). Cada módulo MMO registra seus
|
; PlayerState Component Registry (PR 19+). Cada módulo MMO registra seus
|
||||||
; UActorComponent aqui. O AZMMOPlayerState lê esta lista no construtor e
|
; UActorComponent aqui. O AZeusPlayerState lê esta lista no construtor e
|
||||||
; instancia cada classe como subobject — pattern Open-Closed: adicionar
|
; instancia cada classe como subobject — pattern Open-Closed: adicionar
|
||||||
; Inventory/Skills/Guild = mais uma linha aqui, sem editar AZMMOPlayerState.
|
; Inventory/Skills/Guild = mais uma linha aqui, sem editar AZeusPlayerState.
|
||||||
;
|
;
|
||||||
; Convenção: usa o path /Script/<Module>.<ClassName> (sem o "U" do prefixo
|
; Convenção: usa o path /Script/<Module>.<ClassName> (sem o "U" do prefixo
|
||||||
; C++; UClass resolve pelo nome curto).
|
; C++; UClass resolve pelo nome curto).
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
[/Script/ZMMO.ZMMOPlayerState]
|
[/Script/ZMMO.ZeusPlayerState]
|
||||||
+ComponentClasses=/Script/ZMMOAttributes.ZMMOAttributeComponent
|
; UZeusGASComponent (plugin ZeusGAS) — dono unico dos atributos do char (M7).
|
||||||
|
; Owns UZeusAbilitySystemComponent + UZeusAttributeSet (26 atributos
|
||||||
|
; espelhados do server CharAttributeSet). Bridge via UZeusGASNetworkHandler
|
||||||
|
; (UWorldSubsystem) subscribe nos delegates do UZeusNetworkSubsystem.
|
||||||
|
+ComponentClasses=/Script/ZeusGAS.ZeusGASComponent
|
||||||
|
|
||||||
|
; === GAS Cue paths (Batch 2.5 — S_ABILITY_CUE multicast cosmetico) ===
|
||||||
|
; UGameplayCueManager scaneia esses paths no boot pra mapear FGameplayTag
|
||||||
|
; -> AGameplayCueNotify_Actor BP. UZeusGASComponent::DispatchAbilityCue chama
|
||||||
|
; ASC->ExecuteGameplayCueLocal(CueTag, params) -> manager resolve pelo path.
|
||||||
|
[/Script/GameplayAbilities.AbilitySystemGlobals]
|
||||||
|
+GameplayCueNotifyPaths="/Game/ZMMO/GAS/Cues"
|
||||||
|
|
||||||
[/Script/Engine.AssetManagerSettings]
|
[/Script/Engine.AssetManagerSettings]
|
||||||
-PrimaryAssetTypesToScan=(PrimaryAssetType="Map",AssetBaseClass=/Script/Engine.World,bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game/Maps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
|
-PrimaryAssetTypesToScan=(PrimaryAssetType="Map",AssetBaseClass=/Script/Engine.World,bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game/Maps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
|
||||||
@@ -80,3 +91,12 @@ bShouldAcquireMissingChunksOnLoad=False
|
|||||||
bShouldWarnAboutInvalidAssets=True
|
bShouldWarnAboutInvalidAssets=True
|
||||||
MetaDataTagsForAssetRegistry=()
|
MetaDataTagsForAssetRegistry=()
|
||||||
|
|
||||||
|
|
||||||
|
[/Script/GameplayAbilities.AbilitySystemGlobals]
|
||||||
|
bUseDebugTargetFromHud=true
|
||||||
|
|
||||||
|
[ConsoleVariables]
|
||||||
|
; mostra cooldowns, ativações, falhas
|
||||||
|
AbilitySystem.LogAbilityTriggers=1
|
||||||
|
; mostra effects aplicados/removidos com magnitude
|
||||||
|
AbilitySystem.DebugAbilityTags=1
|
||||||
19
Config/DefaultZeusV1.ini
Normal file
19
Config/DefaultZeusV1.ini
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
; DefaultZeusV1.ini
|
||||||
|
; Config inicial pra UZeusNetworkingClientSubsystem (P9-6/P9-7 plugin).
|
||||||
|
; Editar via UE Project Settings -> Plugins -> Zeus V1 OU editar este arquivo
|
||||||
|
; e relancar o editor.
|
||||||
|
;
|
||||||
|
; PORT 7777: ZeusGateway. NodeService popula routes via charId lookup quando
|
||||||
|
; cliente conecta (validado: handshake routed charId=7 -> SP_01 cell 0). Fluxo
|
||||||
|
; padrao de producao -- UE conecta no Gateway, Gateway resolve cell ownership
|
||||||
|
; via lease em Valkey + encaminha pro ZS correto.
|
||||||
|
;
|
||||||
|
; ALTERNATIVO (debug only -- bug aberto pendente investigacao):
|
||||||
|
; ServerPort=9001 conecta DIRETO em SP_01 mas hoje pacote UE nao chega no
|
||||||
|
; server (FUdpSocketBuilder + Windows multi-NIC loopback issue). Use 7777.
|
||||||
|
|
||||||
|
[/Script/ZeusNetwork.ZeusNetworkingClientSubsystem]
|
||||||
|
ServerHost=127.0.0.1
|
||||||
|
ServerPort=7777
|
||||||
|
bUseZeusNetworkingV1=True
|
||||||
|
bAutoConnectOnStart=True
|
||||||
97
Config/Tags/ZeusServerTags.ini
Normal file
97
Config/Tags/ZeusServerTags.ini
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
; Gerado por ZeusTool tags sync -- tags do ZeusServer p/ o cliente UE.
|
||||||
|
; NAO editar a mao: regenere com `ZeusTool tags sync <json> <ini>`.
|
||||||
|
[/Script/GameplayTags.GameplayTagsList]
|
||||||
|
GameplayTagList=(Tag="Zeus",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Casting",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Channeling",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Melee",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Melee.Kick",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Movement",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Movement.Dash",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Recovery",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Spell",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Ability.Spell.FireballRain",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Agi",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Aspd",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Atk",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.BaseExp",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.BaseLevel",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Crit",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Def",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Dex",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Flee",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Hit",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Hp",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Int",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.JobExp",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.JobLevel",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Luk",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Matk",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.MatkMax",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.MatkMin",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.MaxHp",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.MaxSp",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Mdef",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.SkillPoint",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Sp",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Stamina",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.StatusPoint",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Str",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Attribute.Vit",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combat",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combat.Blocking",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combat.Dodging",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combat.InCombat",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combat.LockOn",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combo",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combo.Slot1",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combo.Slot2",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combo.Slot3",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Combo.Window",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Cooldown",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Cooldown.FireballRain",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Cue",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Cue.Melee",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Cue.Melee.Kick",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Cue.Movement",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Cue.Movement.Dash",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Earth",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Fire",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Holy",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Magical",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Physical",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Poison",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Shadow",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Water",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Damage.Wind",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Buff",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Buff.StrUp",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Cooldown",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Cooldown.Dash",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Cooldown.FireballRain",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Cooldown.Kick",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Cost",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Cost.Sp_10",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Cost.Sp_50",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Effect.Cost.Stamina_5",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.Buff",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.CC",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.CC.Disarmed",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.CC.Feared",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.CC.Frozen",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.CC.KnockedDown",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.CC.Rooted",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.CC.Silenced",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.CC.Stunned",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.Dead",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.Debuff",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.Invulnerable",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.Regen",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.Regen.Blocked",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.Regen.Boosted",DevComment="")
|
||||||
|
GameplayTagList=(Tag="Zeus.Status.Regen.Poisoned",DevComment="")
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Input/Actions/IA_Dash.uasset
Normal file
BIN
Content/Input/Actions/IA_Dash.uasset
Normal file
Binary file not shown.
BIN
Content/Input/Actions/IA_Kick.uasset
Normal file
BIN
Content/Input/Actions/IA_Kick.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/ZMMO/Core/Player/BP_PlayerState.uasset
Normal file
BIN
Content/ZMMO/Core/Player/BP_PlayerState.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Core/Player/BP_ZeusPlayerCharacter.uasset
Normal file
BIN
Content/ZMMO/Core/Player/BP_ZeusPlayerCharacter.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Data/Abilities/DT_Abilities.uasset
Normal file
BIN
Content/ZMMO/Data/Abilities/DT_Abilities.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/ZMMO/GAS/Abilities/GA_Dash.uasset
Normal file
BIN
Content/ZMMO/GAS/Abilities/GA_Dash.uasset
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/ZMMO/GAS/Abilities/Kick/Animations/AS_Kick.uasset
Normal file
BIN
Content/ZMMO/GAS/Abilities/Kick/Animations/AS_Kick.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/GAS/Abilities/Kick/GA_Kick.uasset
Normal file
BIN
Content/ZMMO/GAS/Abilities/Kick/GA_Kick.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/GAS/Cues/GC_Dash.uasset
Normal file
BIN
Content/ZMMO/GAS/Cues/GC_Dash.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/GAS/Cues/GC_Kick.uasset
Normal file
BIN
Content/ZMMO/GAS/Cues/GC_Kick.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/ZMMO/Sounds/Abilities/SA_Dash.uasset
Normal file
BIN
Content/ZMMO/Sounds/Abilities/SA_Dash.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Sounds/Abilities/SC_Dash.uasset
Normal file
BIN
Content/ZMMO/Sounds/Abilities/SC_Dash.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Sounds/Abilities/SW_Dash_Source.uasset
Normal file
BIN
Content/ZMMO/Sounds/Abilities/SW_Dash_Source.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/Sounds/Abilities/SW_Dash_Source.wav
Normal file
BIN
Content/ZMMO/Sounds/Abilities/SW_Dash_Source.wav
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/ZMMO/VFX/Abilities/Dash/NS_Dash_Burst.uasset
Normal file
BIN
Content/ZMMO/VFX/Abilities/Dash/NS_Dash_Burst.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/VFX/Abilities/Dash/T_DashShard_Source.png
Normal file
BIN
Content/ZMMO/VFX/Abilities/Dash/T_DashShard_Source.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,17 +10,17 @@
|
|||||||
*
|
*
|
||||||
* Fluxo: Boot → Connecting → Login → ServerSelect → Lobby → EnteringWorld
|
* Fluxo: Boot → Connecting → Login → ServerSelect → Lobby → EnteringWorld
|
||||||
* → InWorld. O Lobby é o hub principal logado; suas páginas internas são
|
* → InWorld. O Lobby é o hub principal logado; suas páginas internas são
|
||||||
* EZMMOLobbyPage (não são estados de topo — ver ARQUITETURA.md §4.8).
|
* EZeusLobbyPage (não são estados de topo — ver ARQUITETURA.md §4.8).
|
||||||
*/
|
*/
|
||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class EZMMOFrontEndState : uint8
|
enum class EZeusFrontEndState : uint8
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Boot, // splash inicial enquanto subsistemas sobem
|
Boot, // splash inicial enquanto subsistemas sobem
|
||||||
Connecting, // conectando ao servidor Zeus (UDP)
|
Connecting, // conectando ao servidor Zeus (UDP)
|
||||||
Login, // autenticação
|
Login, // autenticação
|
||||||
ServerSelect, // escolha de servidor/realm
|
ServerSelect, // escolha de servidor/realm
|
||||||
Lobby, // hub principal logado (host das EZMMOLobbyPage)
|
Lobby, // hub principal logado (host das EZeusLobbyPage)
|
||||||
EnteringWorld, // loading/handoff: OpenLevel do mapa de mundo
|
EnteringWorld, // loading/handoff: OpenLevel do mapa de mundo
|
||||||
InWorld // no mundo (HUD de gameplay assume)
|
InWorld // no mundo (HUD de gameplay assume)
|
||||||
};
|
};
|
||||||
@@ -30,7 +30,7 @@ enum class EZMMOFrontEndState : uint8
|
|||||||
* de Lobby ("Switch principal"), não pelo fluxo de topo.
|
* de Lobby ("Switch principal"), não pelo fluxo de topo.
|
||||||
*/
|
*/
|
||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class EZMMOLobbyPage : uint8
|
enum class EZeusLobbyPage : uint8
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
CharacterSelect,
|
CharacterSelect,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Estados da UI in-game. Dirigidos pelo UUIInGameFlowSubsystem; cada estado
|
* Estados da UI in-game. Dirigidos pelo UUIInGameFlowSubsystem; cada estado
|
||||||
* resolve uma tela (UCommonActivatableWidget) via DA_InGameScreenSet.
|
* resolve uma tela (UCommonActivatableWidget) via DA_InGameScreenSet.
|
||||||
*
|
*
|
||||||
* Espelha simetricamente EZMMOFrontEndState (Data/UI/FrontEndTypes.h):
|
* Espelha simetricamente EZeusFrontEndState (Data/UI/FrontEndTypes.h):
|
||||||
* - Front-end usa estados pra Login/ServerSelect/Lobby (UI.Layer.Menu)
|
* - Front-end usa estados pra Login/ServerSelect/Lobby (UI.Layer.Menu)
|
||||||
* - In-game usa estados pra HUD/Status/Inventory/Skills (UI.Layer.Game + GameMenu)
|
* - In-game usa estados pra HUD/Status/Inventory/Skills (UI.Layer.Game + GameMenu)
|
||||||
*
|
*
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
* Layer.GameMenu por cima dele.
|
* Layer.GameMenu por cima dele.
|
||||||
*/
|
*/
|
||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class EZMMOInGameUIState : uint8
|
enum class EZeusInGameUIState : 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).
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Contexto do loading screen genérico. Cada contexto resolve um perfil
|
* Contexto do loading screen genérico. Cada contexto resolve um perfil
|
||||||
* (lista de etapas) no UZMMOLoadingProfilesDataAsset.
|
* (lista de etapas) no UZeusLoadingProfilesDataAsset.
|
||||||
*
|
*
|
||||||
* Cliente local rastreia o progresso assinando eventos próprios
|
* Cliente local rastreia o progresso assinando eventos próprios
|
||||||
* (HandlePostLoadMap, OnPlayerSpawned, etc) — server não envia opcode de
|
* (HandlePostLoadMap, OnPlayerSpawned, etc) — server não envia opcode de
|
||||||
* progresso, ver decisão em [[project_ui_loading_dynamic]].
|
* progresso, ver decisão em [[project_ui_loading_dynamic]].
|
||||||
*/
|
*/
|
||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class EZMMOLoadingContext : uint8
|
enum class EZeusLoadingContext : uint8
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
FrontEndEnteringWorld, ///< FrontEnd → mundo (handoff CharServer→WorldServer + spawn).
|
FrontEndEnteringWorld, ///< FrontEnd → mundo (handoff CharServer→WorldServer + spawn).
|
||||||
@@ -21,7 +21,7 @@ enum class EZMMOLoadingContext : uint8
|
|||||||
};
|
};
|
||||||
|
|
||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class EZMMOLoadingStepStatus : uint8
|
enum class EZeusLoadingStepStatus : uint8
|
||||||
{
|
{
|
||||||
Pending, ///< Ainda não começou.
|
Pending, ///< Ainda não começou.
|
||||||
Running, ///< Em andamento (o "barber pole").
|
Running, ///< Em andamento (o "barber pole").
|
||||||
@@ -34,7 +34,7 @@ enum class EZMMOLoadingStepStatus : uint8
|
|||||||
* pra chamar MarkStepDone(StepId); Label é o texto localizado mostrado.
|
* pra chamar MarkStepDone(StepId); Label é o texto localizado mostrado.
|
||||||
*/
|
*/
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct FZMMOLoadingStepDef
|
struct FZeusLoadingStepDef
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
@@ -52,13 +52,13 @@ struct FZMMOLoadingStepDef
|
|||||||
* consulta StepId pra avançar etapa.
|
* consulta StepId pra avançar etapa.
|
||||||
*/
|
*/
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct FZMMOLoadingProfile
|
struct FZeusLoadingProfile
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
/** Etapas em ordem. ProgressBar = #Done / #Steps. */
|
/** Etapas em ordem. ProgressBar = #Done / #Steps. */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Loading")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Loading")
|
||||||
TArray<FZMMOLoadingStepDef> Steps;
|
TArray<FZeusLoadingStepDef> Steps;
|
||||||
|
|
||||||
/** Título da tela (vazio = usa default da classe). */
|
/** Título da tela (vazio = usa default da classe). */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Loading")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Loading")
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "ThemeKeys.generated.h"
|
#include "ThemeKeys.generated.h"
|
||||||
|
|
||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class EZMMOThemeKey : uint8
|
enum class EZeusThemeKey : uint8
|
||||||
{
|
{
|
||||||
// HUD
|
// HUD
|
||||||
HUD_Frame UMETA(DisplayName = "HUD - Frame"),
|
HUD_Frame UMETA(DisplayName = "HUD - Frame"),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "UI/UILayerTags.h"
|
#include "UI/UILayerTags.h"
|
||||||
|
|
||||||
namespace ZMMOUITags
|
namespace ZeusUITags
|
||||||
{
|
{
|
||||||
UE_DEFINE_GAMEPLAY_TAG(UI_Layer_Game, "UI.Layer.Game");
|
UE_DEFINE_GAMEPLAY_TAG(UI_Layer_Game, "UI.Layer.Game");
|
||||||
UE_DEFINE_GAMEPLAY_TAG(UI_Layer_GameMenu, "UI.Layer.GameMenu");
|
UE_DEFINE_GAMEPLAY_TAG(UI_Layer_GameMenu, "UI.Layer.GameMenu");
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
* UI.Layer.Menu — front-end (Boot/Login/ServerSelect/Lobby)
|
* UI.Layer.Menu — front-end (Boot/Login/ServerSelect/Lobby)
|
||||||
* UI.Layer.Modal — diálogos/loading por cima de tudo
|
* UI.Layer.Modal — diálogos/loading por cima de tudo
|
||||||
*/
|
*/
|
||||||
namespace ZMMOUITags
|
namespace ZeusUITags
|
||||||
{
|
{
|
||||||
ZMMO_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(UI_Layer_Game);
|
ZMMO_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(UI_Layer_Game);
|
||||||
ZMMO_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(UI_Layer_GameMenu);
|
ZMMO_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(UI_Layer_GameMenu);
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ struct ZMMO_API FUIStyle
|
|||||||
/**
|
/**
|
||||||
* Linha de DT_UI_Styles. O Row Name é o ThemeId (ex.: "Default", "RPG"),
|
* Linha de DT_UI_Styles. O Row Name é o ThemeId (ex.: "Default", "RPG"),
|
||||||
* espelhando DT_ThemeCalendar e ThemeRegistry — assim a camada de estilo
|
* espelhando DT_ThemeCalendar e ThemeRegistry — assim a camada de estilo
|
||||||
* é consumidora do ThemeId já resolvido pelo UZMMOThemeSubsystem.
|
* é consumidora do ThemeId já resolvido pelo UZeusThemeSubsystem.
|
||||||
*/
|
*/
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct ZMMO_API FUIStyleRow : public FTableRowBase
|
struct ZMMO_API FUIStyleRow : public FTableRowBase
|
||||||
@@ -87,7 +87,7 @@ struct ZMMO_API FUIStyleRow : public FTableRowBase
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style")
|
||||||
EUITheme Theme = EUITheme::None;
|
EUITheme Theme = EUITheme::None;
|
||||||
|
|
||||||
/** Ponte para o ThemeId resolvido pelo UZMMOThemeSubsystem. */
|
/** Ponte para o ThemeId resolvido pelo UZeusThemeSubsystem. */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style")
|
||||||
FName ThemeId;
|
FName ThemeId;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Enums do sistema de UI Style (tokens de tema visual).
|
* Enums do sistema de UI Style (tokens de tema visual).
|
||||||
*
|
*
|
||||||
* Espelha ThemeKeys.h: enums fortes, BlueprintType, primeiro valor None.
|
* Espelha ThemeKeys.h: enums fortes, BlueprintType, primeiro valor None.
|
||||||
* O conceito de "tema ativo" continua sendo do UZMMOThemeSubsystem
|
* O conceito de "tema ativo" continua sendo do UZeusThemeSubsystem
|
||||||
* (resolvido por FName ThemeId). EUITheme é apenas validação tipada de
|
* (resolvido por FName ThemeId). EUITheme é apenas validação tipada de
|
||||||
* design-time ao preencher DT_UI_Styles — não é a chave de runtime.
|
* design-time ao preencher DT_UI_Styles — não é a chave de runtime.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "MapDef.generated.h"
|
#include "MapDef.generated.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FZMMOMapSpawn
|
* FZeusMapSpawn
|
||||||
*
|
*
|
||||||
* Ponto de spawn dentro de um mapa, identificado por `Tag`. Usado pelo
|
* Ponto de spawn dentro de um mapa, identificado por `Tag`. Usado pelo
|
||||||
* server pra decidir onde materializar um char quando ele entra:
|
* server pra decidir onde materializar um char quando ele entra:
|
||||||
@@ -15,12 +15,12 @@
|
|||||||
* - Char saindo de raid: pode pedir tag="raid_return"
|
* - Char saindo de raid: pode pedir tag="raid_return"
|
||||||
* - Char morto: pode pedir tag="graveyard"
|
* - Char morto: pode pedir tag="graveyard"
|
||||||
*
|
*
|
||||||
* ZeusEditorTools pode auto-popular o `Spawns[]` do FZMMOMapDef varrendo
|
* ZeusEditorTools pode auto-popular o `Spawns[]` do FZeusMapDef varrendo
|
||||||
* todos APlayerStart (ou ator custom AZMMOMapSpawnPoint) presentes no
|
* todos APlayerStart (ou ator custom AZeusMapSpawnPoint) presentes no
|
||||||
* `.umap` do `ClientLevel` — botao "Sync from level".
|
* `.umap` do `ClientLevel` — botao "Sync from level".
|
||||||
*/
|
*/
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct ZMMO_API FZMMOMapSpawn
|
struct ZMMO_API FZeusMapSpawn
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ struct ZMMO_API FZMMOMapSpawn
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FZMMOMapDef
|
* FZeusMapDef
|
||||||
*
|
*
|
||||||
* Definicao canonica de um mapa do MMO. Linha da DT_Maps no cliente.
|
* Definicao canonica de um mapa do MMO. Linha da DT_Maps no cliente.
|
||||||
* Exportada para `Server/ZeusServerEngine/Config/DataTables/maps_config.json`
|
* Exportada para `Server/ZeusServerEngine/Config/DataTables/maps_config.json`
|
||||||
@@ -55,7 +55,7 @@ struct ZMMO_API FZMMOMapSpawn
|
|||||||
* `mapName` (string), evitando ~10-30 bytes por handoff.
|
* `mapName` (string), evitando ~10-30 bytes por handoff.
|
||||||
*/
|
*/
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct ZMMO_API FZMMOMapDef : public FTableRowBase
|
struct ZMMO_API FZeusMapDef : public FTableRowBase
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ struct ZMMO_API FZMMOMapDef : public FTableRowBase
|
|||||||
* Pelo menos um com Tag="default" e esperado.
|
* Pelo menos um com Tag="default" e esperado.
|
||||||
*/
|
*/
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Map|Spawns")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Map|Spawns")
|
||||||
TArray<FZMMOMapSpawn> Spawns;
|
TArray<FZeusMapSpawn> Spawns;
|
||||||
|
|
||||||
/** Regras PvP/Safe/Dungeon. Reusa enum de FZoneRow. */
|
/** Regras PvP/Safe/Dungeon. Reusa enum de FZoneRow. */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Map")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Map")
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#include "ZMMOFrontEndPlayerController.h"
|
#include "ZeusFrontEndPlayerController.h"
|
||||||
|
|
||||||
#include "UIFrontEndFlowSubsystem.h"
|
#include "UIFrontEndFlowSubsystem.h"
|
||||||
#include "Engine/GameInstance.h"
|
#include "Engine/GameInstance.h"
|
||||||
|
|
||||||
AZMMOFrontEndPlayerController::AZMMOFrontEndPlayerController()
|
AZeusFrontEndPlayerController::AZeusFrontEndPlayerController()
|
||||||
{
|
{
|
||||||
bShowMouseCursor = true;
|
bShowMouseCursor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOFrontEndPlayerController::BeginPlay()
|
void AZeusFrontEndPlayerController::BeginPlay()
|
||||||
{
|
{
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
|
|
||||||
@@ -2,24 +2,24 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GameFramework/PlayerController.h"
|
#include "GameFramework/PlayerController.h"
|
||||||
#include "ZMMOFrontEndPlayerController.generated.h"
|
#include "ZeusFrontEndPlayerController.generated.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AZMMOFrontEndPlayerController
|
* AZeusFrontEndPlayerController
|
||||||
*
|
*
|
||||||
* Controller do mapa de front-end. Não herda de AZMMOPlayerController (sem
|
* Controller do mapa de front-end. Não herda de AZeusPlayerController (sem
|
||||||
* Enhanced Input de gameplay/touch). Em BeginPlay arranca o fluxo de
|
* Enhanced Input de gameplay/touch). Em BeginPlay arranca o fluxo de
|
||||||
* front-end (UUIFrontEndFlowSubsystem) — feito aqui, e não no
|
* front-end (UUIFrontEndFlowSubsystem) — feito aqui, e não no
|
||||||
* GameInstance::Init, porque os subsistemas já existem neste ponto (ver
|
* GameInstance::Init, porque os subsistemas já existem neste ponto (ver
|
||||||
* aviso no header do ZeusNetworkSubsystem).
|
* aviso no header do ZeusNetworkSubsystem).
|
||||||
*/
|
*/
|
||||||
UCLASS(Blueprintable, BlueprintType)
|
UCLASS(Blueprintable, BlueprintType)
|
||||||
class ZMMO_API AZMMOFrontEndPlayerController : public APlayerController
|
class ZMMO_API AZeusFrontEndPlayerController : public APlayerController
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AZMMOFrontEndPlayerController();
|
AZeusFrontEndPlayerController();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void BeginPlay() override;
|
virtual void BeginPlay() override;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "ZMMOPlayerController.h"
|
#include "ZeusPlayerController.h"
|
||||||
|
|
||||||
#include "Blueprint/UserWidget.h"
|
#include "Blueprint/UserWidget.h"
|
||||||
#include "Components/InputComponent.h"
|
#include "Components/InputComponent.h"
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
#include "UI/InGame/UIInGameFlowSubsystem.h"
|
#include "UI/InGame/UIInGameFlowSubsystem.h"
|
||||||
#include "UI/InGameTypes.h"
|
#include "UI/InGameTypes.h"
|
||||||
|
|
||||||
AZMMOPlayerController::AZMMOPlayerController()
|
AZeusPlayerController::AZeusPlayerController()
|
||||||
{
|
{
|
||||||
// Defaults dos Input Mapping Contexts (alinhados ao ZClientMMO). Permitem
|
// Defaults dos Input Mapping Contexts (alinhados ao ZClientMMO). Permitem
|
||||||
// instanciar AZMMOPlayerController directamente como
|
// instanciar AZeusPlayerController directamente como
|
||||||
// `PlayerControllerClass` do AZMMOGameMode sem exigir um BP filho. Se o
|
// `PlayerControllerClass` do AZeusGameMode sem exigir um BP filho. Se o
|
||||||
// projeto adicionar mais IMCs, podemos extender via BP filho ou via
|
// projeto adicionar mais IMCs, podemos extender via BP filho ou via
|
||||||
// arquivos de Config (UPROPERTY EditAnywhere abaixo).
|
// arquivos de Config (UPROPERTY EditAnywhere abaixo).
|
||||||
static ConstructorHelpers::FObjectFinder<UInputMappingContext> DefaultImc(
|
static ConstructorHelpers::FObjectFinder<UInputMappingContext> DefaultImc(
|
||||||
@@ -35,7 +35,7 @@ AZMMOPlayerController::AZMMOPlayerController()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerController::BeginPlay()
|
void AZeusPlayerController::BeginPlay()
|
||||||
{
|
{
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ void AZMMOPlayerController::BeginPlay()
|
|||||||
{
|
{
|
||||||
// Limpa estado de input herdado da UI do FrontEnd (UIManagerSubsystem
|
// Limpa estado de input herdado da UI do FrontEnd (UIManagerSubsystem
|
||||||
// e LocalPlayerSubsystem — sobrevive ao travel, e o controller anterior
|
// e LocalPlayerSubsystem — sobrevive ao travel, e o controller anterior
|
||||||
// (AZMMOFrontEndPlayerController) tinha setado FInputModeUIOnly +
|
// (AZeusFrontEndPlayerController) tinha setado FInputModeUIOnly +
|
||||||
// bShowMouseCursor=true). Sem este reset, WASD/Look podem nao chegar
|
// bShowMouseCursor=true). Sem este reset, WASD/Look podem nao chegar
|
||||||
// ao pawn porque o Slate ainda esta com foco no widget antigo.
|
// ao pawn porque o Slate ainda esta com foco no widget antigo.
|
||||||
FInputModeGameOnly InputMode;
|
FInputModeGameOnly InputMode;
|
||||||
@@ -67,7 +67,7 @@ void AZMMOPlayerController::BeginPlay()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerController::SetupInputComponent()
|
void AZeusPlayerController::SetupInputComponent()
|
||||||
{
|
{
|
||||||
Super::SetupInputComponent();
|
Super::SetupInputComponent();
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ void AZMMOPlayerController::SetupInputComponent()
|
|||||||
FInputKeyBinding& Binding = InputComponent->BindKey(
|
FInputKeyBinding& Binding = InputComponent->BindKey(
|
||||||
FInputChord(EKeys::A, /*bShift*/ false, /*bCtrl*/ false, /*bAlt*/ true, /*bCmd*/ false),
|
FInputChord(EKeys::A, /*bShift*/ false, /*bCtrl*/ false, /*bAlt*/ true, /*bCmd*/ false),
|
||||||
IE_Pressed,
|
IE_Pressed,
|
||||||
this, &AZMMOPlayerController::ToggleStatusWindow);
|
this, &AZeusPlayerController::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)
|
||||||
|
|
||||||
@@ -109,35 +109,35 @@ void AZMMOPlayerController::SetupInputComponent()
|
|||||||
FInputKeyBinding& JobBinding = InputComponent->BindKey(
|
FInputKeyBinding& JobBinding = InputComponent->BindKey(
|
||||||
FInputChord(EKeys::J, /*bShift*/ false, /*bCtrl*/ false, /*bAlt*/ false, /*bCmd*/ false),
|
FInputChord(EKeys::J, /*bShift*/ false, /*bCtrl*/ false, /*bAlt*/ false, /*bCmd*/ false),
|
||||||
IE_Pressed,
|
IE_Pressed,
|
||||||
this, &AZMMOPlayerController::ToggleJobChangePanel);
|
this, &AZeusPlayerController::ToggleJobChangePanel);
|
||||||
JobBinding.bConsumeInput = true;
|
JobBinding.bConsumeInput = true;
|
||||||
JobBinding.bExecuteWhenPaused = true;
|
JobBinding.bExecuteWhenPaused = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerController::ToggleStatusWindow()
|
void AZeusPlayerController::ToggleStatusWindow()
|
||||||
{
|
{
|
||||||
if (UGameInstance* GI = GetGameInstance())
|
if (UGameInstance* GI = GetGameInstance())
|
||||||
{
|
{
|
||||||
if (UUIInGameFlowSubsystem* Flow = GI->GetSubsystem<UUIInGameFlowSubsystem>())
|
if (UUIInGameFlowSubsystem* Flow = GI->GetSubsystem<UUIInGameFlowSubsystem>())
|
||||||
{
|
{
|
||||||
Flow->ToggleScreen(EZMMOInGameUIState::StatusWindow);
|
Flow->ToggleScreen(EZeusInGameUIState::StatusWindow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerController::ToggleJobChangePanel()
|
void AZeusPlayerController::ToggleJobChangePanel()
|
||||||
{
|
{
|
||||||
if (UGameInstance* GI = GetGameInstance())
|
if (UGameInstance* GI = GetGameInstance())
|
||||||
{
|
{
|
||||||
if (UUIInGameFlowSubsystem* Flow = GI->GetSubsystem<UUIInGameFlowSubsystem>())
|
if (UUIInGameFlowSubsystem* Flow = GI->GetSubsystem<UUIInGameFlowSubsystem>())
|
||||||
{
|
{
|
||||||
Flow->ToggleScreen(EZMMOInGameUIState::JobChangePanel);
|
Flow->ToggleScreen(EZeusInGameUIState::JobChangePanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AZMMOPlayerController::ShouldUseTouchControls() const
|
bool AZeusPlayerController::ShouldUseTouchControls() const
|
||||||
{
|
{
|
||||||
return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls;
|
return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls;
|
||||||
}
|
}
|
||||||
@@ -2,26 +2,26 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GameFramework/PlayerController.h"
|
#include "GameFramework/PlayerController.h"
|
||||||
#include "ZMMOPlayerController.generated.h"
|
#include "ZeusPlayerController.generated.h"
|
||||||
|
|
||||||
class UInputMappingContext;
|
class UInputMappingContext;
|
||||||
class UUserWidget;
|
class UUserWidget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AZMMOPlayerController
|
* AZeusPlayerController
|
||||||
*
|
*
|
||||||
* Player controller do cliente Zeus MMO. Responsavel apenas pela camada de
|
* Player controller do cliente Zeus MMO. Responsavel apenas pela camada de
|
||||||
* input do Unreal (Enhanced Input Mapping Contexts e widget opcional de
|
* input do Unreal (Enhanced Input Mapping Contexts e widget opcional de
|
||||||
* controlos touch). Toda a logica de identidade Zeus, envio de input e
|
* controlos touch). Toda a logica de identidade Zeus, envio de input e
|
||||||
* reconciliacao vive em `AZMMOPlayerCharacter`.
|
* reconciliacao vive em `AZeusCharacter`.
|
||||||
*/
|
*/
|
||||||
UCLASS(Blueprintable, BlueprintType)
|
UCLASS(Blueprintable, BlueprintType)
|
||||||
class ZMMO_API AZMMOPlayerController : public APlayerController
|
class ZMMO_API AZeusPlayerController : public APlayerController
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AZMMOPlayerController();
|
AZeusPlayerController();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Mapping contexts default (sempre adicionados). */
|
/** Mapping contexts default (sempre adicionados). */
|
||||||
@@ -1,490 +0,0 @@
|
|||||||
#include "ZMMOPlayerCharacter.h"
|
|
||||||
|
|
||||||
#include "Animation/AnimInstance.h"
|
|
||||||
#include "Camera/CameraComponent.h"
|
|
||||||
#include "Components/CapsuleComponent.h"
|
|
||||||
#include "Components/SkeletalMeshComponent.h"
|
|
||||||
#include "EnhancedInputComponent.h"
|
|
||||||
#include "Engine/GameInstance.h"
|
|
||||||
#include "Engine/SkeletalMesh.h"
|
|
||||||
#include "Engine/World.h"
|
|
||||||
#include "GameFramework/CharacterMovementComponent.h"
|
|
||||||
#include "GameFramework/Controller.h"
|
|
||||||
#include "GameFramework/SpringArmComponent.h"
|
|
||||||
#include "InputAction.h"
|
|
||||||
#include "InputActionValue.h"
|
|
||||||
#include "GameFramework/PlayerState.h"
|
|
||||||
#include "Subsystems/WorldSubsystem.h"
|
|
||||||
#include "UObject/ConstructorHelpers.h"
|
|
||||||
#include "ZMMO.h"
|
|
||||||
#include "ZMMOAttributeComponent.h"
|
|
||||||
#include "ZMMOPlayerState.h"
|
|
||||||
#include "ZMMOWorldSubsystem.h"
|
|
||||||
#include "ZeusNetworkSubsystem.h"
|
|
||||||
#include "UI/FrontEnd/UIFrontEndFlowSubsystem.h"
|
|
||||||
|
|
||||||
DEFINE_LOG_CATEGORY(LogZMMOPlayer);
|
|
||||||
|
|
||||||
AZMMOPlayerCharacter::AZMMOPlayerCharacter()
|
|
||||||
{
|
|
||||||
PrimaryActorTick.bCanEverTick = true;
|
|
||||||
PrimaryActorTick.bStartWithTickEnabled = true;
|
|
||||||
|
|
||||||
GetCapsuleComponent()->InitCapsuleSize(42.0f, 96.0f);
|
|
||||||
|
|
||||||
bUseControllerRotationPitch = false;
|
|
||||||
bUseControllerRotationYaw = false;
|
|
||||||
bUseControllerRotationRoll = false;
|
|
||||||
|
|
||||||
UCharacterMovementComponent* CMC = GetCharacterMovement();
|
|
||||||
CMC->bOrientRotationToMovement = true;
|
|
||||||
CMC->RotationRate = FRotator(0.0f, 500.0f, 0.0f);
|
|
||||||
CMC->JumpZVelocity = 500.0f;
|
|
||||||
CMC->AirControl = 0.35f;
|
|
||||||
CMC->MaxWalkSpeed = 500.0f;
|
|
||||||
CMC->MinAnalogWalkSpeed = 20.0f;
|
|
||||||
CMC->BrakingDecelerationWalking = 2000.0f;
|
|
||||||
CMC->BrakingDecelerationFalling = 1500.0f;
|
|
||||||
|
|
||||||
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
|
|
||||||
CameraBoom->SetupAttachment(RootComponent);
|
|
||||||
CameraBoom->TargetArmLength = 400.0f;
|
|
||||||
CameraBoom->bUsePawnControlRotation = true;
|
|
||||||
|
|
||||||
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
|
|
||||||
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
|
|
||||||
FollowCamera->bUsePawnControlRotation = false;
|
|
||||||
|
|
||||||
// AttributeComponent migrou pro PlayerState (AZMMOPlayerState + Component
|
|
||||||
// Registry config-driven). Pawn fica leve — so' movement/input/camera.
|
|
||||||
|
|
||||||
// Defaults visuais (mesh + AnimBP) — alinhados ao ZClientMMO. Permitem ao
|
|
||||||
// motor spawnar AZMMOPlayerCharacter directamente como DefaultPawnClass do
|
|
||||||
// AZMMOGameMode sem exigir um BP filho. Um BP filho continua opcional para
|
|
||||||
// trocar mesh/AnimBP por mapa.
|
|
||||||
if (USkeletalMeshComponent* MeshComponent = GetMesh())
|
|
||||||
{
|
|
||||||
static ConstructorHelpers::FObjectFinder<USkeletalMesh> QuinnMesh(
|
|
||||||
TEXT("/Game/Characters/Mannequins/Meshes/SKM_Quinn_Simple.SKM_Quinn_Simple"));
|
|
||||||
static ConstructorHelpers::FClassFinder<UAnimInstance> QuinnAnimBp(
|
|
||||||
TEXT("/Game/Characters/Mannequins/Anims/Unarmed/ABP_Unarmed"));
|
|
||||||
|
|
||||||
if (QuinnMesh.Succeeded())
|
|
||||||
{
|
|
||||||
MeshComponent->SetSkeletalMesh(QuinnMesh.Object);
|
|
||||||
MeshComponent->SetRelativeLocation(FVector(0.0f, 0.0f, -90.0f));
|
|
||||||
MeshComponent->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UE_LOG(LogZMMOPlayer, Warning, TEXT("Default mesh SKM_Quinn_Simple not found for AZMMOPlayerCharacter."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QuinnAnimBp.Succeeded())
|
|
||||||
{
|
|
||||||
MeshComponent->SetAnimationMode(EAnimationMode::AnimationBlueprint);
|
|
||||||
MeshComponent->SetAnimInstanceClass(QuinnAnimBp.Class);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UE_LOG(LogZMMOPlayer, Warning, TEXT("Default anim blueprint ABP_Unarmed not found for AZMMOPlayerCharacter."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Input Actions defaults (Enhanced Input) — IMCs sao adicionados pelo
|
|
||||||
// AZMMOPlayerController. As IAs aqui resolvem o asset por path; um BP filho
|
|
||||||
// pode sobrescrever caso queira inputs custom.
|
|
||||||
static ConstructorHelpers::FObjectFinder<UInputAction> MoveActionAsset(
|
|
||||||
TEXT("/Game/Input/Actions/IA_Move.IA_Move"));
|
|
||||||
static ConstructorHelpers::FObjectFinder<UInputAction> LookActionAsset(
|
|
||||||
TEXT("/Game/Input/Actions/IA_Look.IA_Look"));
|
|
||||||
static ConstructorHelpers::FObjectFinder<UInputAction> MouseLookActionAsset(
|
|
||||||
TEXT("/Game/Input/Actions/IA_MouseLook.IA_MouseLook"));
|
|
||||||
static ConstructorHelpers::FObjectFinder<UInputAction> JumpActionAsset(
|
|
||||||
TEXT("/Game/Input/Actions/IA_Jump.IA_Jump"));
|
|
||||||
|
|
||||||
if (MoveActionAsset.Succeeded()) { MoveAction = MoveActionAsset.Object; }
|
|
||||||
if (LookActionAsset.Succeeded()) { LookAction = LookActionAsset.Object; }
|
|
||||||
if (MouseLookActionAsset.Succeeded()) { MouseLookAction = MouseLookActionAsset.Object; }
|
|
||||||
if (JumpActionAsset.Succeeded()) { JumpAction = JumpActionAsset.Object; }
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::BeginPlay()
|
|
||||||
{
|
|
||||||
Super::BeginPlay();
|
|
||||||
ResolveZeusNetworkSubsystem();
|
|
||||||
BindZeusSpawnDelegate();
|
|
||||||
TryRegisterLocalEntityFromCachedSpawn();
|
|
||||||
|
|
||||||
// Fase 4: reposiciona o pawn na pos salva no DB (vinda no S_CHAR_SELECT_OK
|
|
||||||
// e memorizada no Flow). Substitui o PlayerStart default do level. Se nao
|
|
||||||
// ha pose pendente (primeiro boot / debug PIE direto no level), mantem o
|
|
||||||
// PlayerStart.
|
|
||||||
if (const UGameInstance* GI = GetGameInstance())
|
|
||||||
{
|
|
||||||
if (UUIFrontEndFlowSubsystem* Flow = GI->GetSubsystem<UUIFrontEndFlowSubsystem>())
|
|
||||||
{
|
|
||||||
FVector PosCm = FVector::ZeroVector;
|
|
||||||
float YawDeg = 0.0f;
|
|
||||||
if (Flow->ConsumePendingSpawnPose(PosCm, YawDeg))
|
|
||||||
{
|
|
||||||
const FRotator NewRot(0.0f, YawDeg, 0.0f);
|
|
||||||
SetActorLocationAndRotation(PosCm, NewRot, /*bSweep=*/false, nullptr, ETeleportType::TeleportPhysics);
|
|
||||||
if (AController* C = GetController())
|
|
||||||
{
|
|
||||||
C->SetControlRotation(NewRot);
|
|
||||||
}
|
|
||||||
UE_LOG(LogZMMOPlayer, Log,
|
|
||||||
TEXT("AZMMOPlayerCharacter: pawn reposicionado pra pos do DB (%s) yaw=%.1f"),
|
|
||||||
*PosCm.ToString(), YawDeg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
|
||||||
{
|
|
||||||
UnbindZeusSpawnDelegate();
|
|
||||||
ZeusNetwork = nullptr;
|
|
||||||
Super::EndPlay(EndPlayReason);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::Tick(const float DeltaSeconds)
|
|
||||||
{
|
|
||||||
Super::Tick(DeltaSeconds);
|
|
||||||
FlushInputAxisToServer(DeltaSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
|
||||||
{
|
|
||||||
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
|
|
||||||
{
|
|
||||||
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &AZMMOPlayerCharacter::OnJumpPressed);
|
|
||||||
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &AZMMOPlayerCharacter::OnJumpReleased);
|
|
||||||
|
|
||||||
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AZMMOPlayerCharacter::Move);
|
|
||||||
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Completed, this, &AZMMOPlayerCharacter::MoveCompleted);
|
|
||||||
|
|
||||||
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AZMMOPlayerCharacter::Look);
|
|
||||||
EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &AZMMOPlayerCharacter::Look);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UE_LOG(LogZMMOPlayer, Error, TEXT("'%s' Failed to find an Enhanced Input component."), *GetNameSafe(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::Move(const FInputActionValue& Value)
|
|
||||||
{
|
|
||||||
const FVector2D MovementVector = Value.Get<FVector2D>();
|
|
||||||
DoMove(MovementVector.X, MovementVector.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::MoveCompleted(const FInputActionValue& Value)
|
|
||||||
{
|
|
||||||
(void)Value;
|
|
||||||
DoMove(0.0f, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::Look(const FInputActionValue& Value)
|
|
||||||
{
|
|
||||||
const FVector2D LookAxisVector = Value.Get<FVector2D>();
|
|
||||||
DoLook(LookAxisVector.X, LookAxisVector.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::OnJumpPressed()
|
|
||||||
{
|
|
||||||
bPendingJumpPressed = true;
|
|
||||||
DoJumpStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::OnJumpReleased()
|
|
||||||
{
|
|
||||||
bPendingJumpReleased = true;
|
|
||||||
DoJumpEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::DoMove(const float Right, const float Forward)
|
|
||||||
{
|
|
||||||
PendingMoveRight = FMath::Clamp(Right, -1.0f, 1.0f);
|
|
||||||
PendingMoveForward = FMath::Clamp(Forward, -1.0f, 1.0f);
|
|
||||||
|
|
||||||
if (GetController() != nullptr)
|
|
||||||
{
|
|
||||||
const FRotator Rotation = GetController()->GetControlRotation();
|
|
||||||
const FRotator YawRotation(0.0f, Rotation.Yaw, 0.0f);
|
|
||||||
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
|
||||||
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
|
|
||||||
AddMovementInput(ForwardDirection, Forward);
|
|
||||||
AddMovementInput(RightDirection, Right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::DoLook(const float Yaw, const float Pitch)
|
|
||||||
{
|
|
||||||
if (GetController() != nullptr)
|
|
||||||
{
|
|
||||||
AddControllerYawInput(Yaw);
|
|
||||||
AddControllerPitchInput(Pitch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::DoJumpStart()
|
|
||||||
{
|
|
||||||
Jump();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::DoJumpEnd()
|
|
||||||
{
|
|
||||||
StopJumping();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::ApplyEntitySnapshot(const FZMMOEntitySnapshot& /*Snapshot*/)
|
|
||||||
{
|
|
||||||
// Cliente local solto: o servidor nao reconcilia posicao em V0 (ADR 0038).
|
|
||||||
// Quando colisao de objetos chegar, podemos ligar uma reconciliacao opcional
|
|
||||||
// horizontal aqui (XY only), preservando o Z do CMC local.
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::SetEntityRelevant(bool /*bRelevant*/)
|
|
||||||
{
|
|
||||||
// Nunca despawnamos o jogador local via AOI.
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::ResolveZeusNetworkSubsystem()
|
|
||||||
{
|
|
||||||
if (ZeusNetwork)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UGameInstance* GI = GetGameInstance();
|
|
||||||
if (!GI)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZeusNetwork = GI->GetSubsystem<UZeusNetworkSubsystem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::BindZeusSpawnDelegate()
|
|
||||||
{
|
|
||||||
if (bSpawnDelegateBound || !IsLocallyControlled())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!ZeusNetwork)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZeusNetwork->OnPlayerSpawned.AddDynamic(this, &AZMMOPlayerCharacter::HandleZeusPlayerSpawned);
|
|
||||||
ZeusNetwork->OnCharInfoReceived.AddDynamic(this, &AZMMOPlayerCharacter::HandleZeusCharInfo);
|
|
||||||
bSpawnDelegateBound = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::UnbindZeusSpawnDelegate()
|
|
||||||
{
|
|
||||||
if (!bSpawnDelegateBound || !ZeusNetwork)
|
|
||||||
{
|
|
||||||
bSpawnDelegateBound = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ZeusNetwork->OnPlayerSpawned.RemoveDynamic(this, &AZMMOPlayerCharacter::HandleZeusPlayerSpawned);
|
|
||||||
ZeusNetwork->OnCharInfoReceived.RemoveDynamic(this, &AZMMOPlayerCharacter::HandleZeusCharInfo);
|
|
||||||
bSpawnDelegateBound = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::TryRegisterLocalEntityFromCachedSpawn()
|
|
||||||
{
|
|
||||||
if (!ZeusNetwork)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64 CachedEntityId = 0;
|
|
||||||
FVector CachedPosCm = FVector::ZeroVector;
|
|
||||||
float CachedYawDeg = 0.0f;
|
|
||||||
int64 CachedServerTimeMs = 0;
|
|
||||||
if (ZeusNetwork->TryGetLastLocalSpawn(CachedEntityId, CachedPosCm, CachedYawDeg, CachedServerTimeMs))
|
|
||||||
{
|
|
||||||
HandleLocalSpawnReady(CachedEntityId, CachedPosCm, CachedYawDeg, CachedServerTimeMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Race fix: o S_CHAR_INFO chega ANTES de S_SPAWN_PLAYER mas o pawn pode
|
|
||||||
// nao existir ainda (OpenLevel em andamento). Aplica o ultimo cacheado.
|
|
||||||
TryApplyCachedCharInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::HandleZeusPlayerSpawned(const int64 InEntityId, const bool bIsLocal,
|
|
||||||
const FVector PosCm, const float YawDeg, const int64 ServerTimeMs)
|
|
||||||
{
|
|
||||||
if (!bIsLocal)
|
|
||||||
{
|
|
||||||
// Remote spawns sao tratados pelo `UZMMOWorldSubsystem`; aqui so reagimos
|
|
||||||
// ao spawn do pawn possessivel local (S_SPAWN_PLAYER com bIsLocal=true).
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
HandleLocalSpawnReady(InEntityId, PosCm, YawDeg, ServerTimeMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::HandleLocalSpawnReady(const int64 InEntityId, const FVector PosCm,
|
|
||||||
const float YawDeg, const int64 ServerTimeMs)
|
|
||||||
{
|
|
||||||
if (InEntityId == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PR-HANDOFF-007 — InEntityId é int64 (era int32)
|
|
||||||
if (ZMMOEntityId == InEntityId)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZMMOEntityId = InEntityId;
|
|
||||||
|
|
||||||
UE_LOG(LogZMMOPlayer, Log,
|
|
||||||
TEXT("AZMMOPlayerCharacter: local spawn captured EntityId=%lld pos=(%s) yaw=%.1f t=%lld"),
|
|
||||||
InEntityId, *PosCm.ToString(), YawDeg, ServerTimeMs);
|
|
||||||
|
|
||||||
if (UWorld* World = GetWorld())
|
|
||||||
{
|
|
||||||
if (UZMMOWorldSubsystem* WorldSubsystem = World->GetSubsystem<UZMMOWorldSubsystem>())
|
|
||||||
{
|
|
||||||
WorldSubsystem->RegisterLocalEntity(InEntityId, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Identidade publica (EntityId) + seed no AttributeComponent. CharName/Guild
|
|
||||||
// vem separado via S_CHAR_INFO -> HandleZeusCharInfo. AttributeComponent vive
|
|
||||||
// como subobject e recebe seed pra que o ZMMOAttributeNetworkHandler consiga
|
|
||||||
// rotear o snapshot por EntityId desde o primeiro pacote.
|
|
||||||
if (APlayerState* PS = GetPlayerState())
|
|
||||||
{
|
|
||||||
if (AZMMOPlayerState* ZMMOPs = Cast<AZMMOPlayerState>(PS))
|
|
||||||
{
|
|
||||||
ZMMOPs->SetPublicIdentity(InEntityId, /*CharId*/ FString(),
|
|
||||||
/*BaseLevel*/ 1, /*ClassId*/ 0);
|
|
||||||
}
|
|
||||||
if (UZMMOAttributeComponent* AttrComp = PS->FindComponentByClass<UZMMOAttributeComponent>())
|
|
||||||
{
|
|
||||||
AttrComp->SeedEntityId(InEntityId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aplica char info cacheada (caso S_CHAR_INFO tenha chegado antes do PS existir).
|
|
||||||
TryApplyCachedCharInfo();
|
|
||||||
|
|
||||||
// UI in-game e' responsabilidade do AZMMOHUD (GameMode.HUDClass), nao do
|
|
||||||
// Pawn. AHUD::BeginPlay chama UUIInGameFlowSubsystem::StartInGame, que
|
|
||||||
// pushea WBP_HUD em UI.Layer.Game. UZMMOHudWidget::NativeOnActivated auto-binda
|
|
||||||
// no UZMMOAttributeComponent via PlayerState.
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::HandleZeusCharInfo(const int64 InEntityId, const FString& CharName, const FString& GuildName)
|
|
||||||
{
|
|
||||||
UE_LOG(LogZMMOPlayer, Log,
|
|
||||||
TEXT("AZMMOPlayerCharacter: S_CHAR_INFO recebido EntityId=%lld name=%s guild=%s"),
|
|
||||||
InEntityId, *CharName, *GuildName);
|
|
||||||
|
|
||||||
APlayerState* PS = GetPlayerState();
|
|
||||||
if (!PS)
|
|
||||||
{
|
|
||||||
// Race fix: pawn pode nao ter PlayerState ainda. Subsystem ja cacheou
|
|
||||||
// (LastLocalCharInfoCache); TryApplyCachedCharInfo aplica em
|
|
||||||
// HandleLocalSpawnReady ou em outra oportunidade.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (AZMMOPlayerState* ZMMOPs = Cast<AZMMOPlayerState>(PS))
|
|
||||||
{
|
|
||||||
ZMMOPs->SetCharInfo(CharName, GuildName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::TryApplyCachedCharInfo()
|
|
||||||
{
|
|
||||||
if (!ZeusNetwork)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int64 CachedEntityId = 0;
|
|
||||||
FString CachedCharName;
|
|
||||||
FString CachedGuildName;
|
|
||||||
if (!ZeusNetwork->TryGetLastLocalCharInfo(CachedEntityId, CachedCharName, CachedGuildName))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (APlayerState* PS = GetPlayerState())
|
|
||||||
{
|
|
||||||
if (AZMMOPlayerState* ZMMOPs = Cast<AZMMOPlayerState>(PS))
|
|
||||||
{
|
|
||||||
ZMMOPs->SetCharInfo(CachedCharName, CachedGuildName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::FlushInputAxisToServer(const float DeltaSeconds)
|
|
||||||
{
|
|
||||||
ResolveZeusNetworkSubsystem();
|
|
||||||
if (!ZeusNetwork || !ZeusNetwork->IsConnected())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float SendInterval = 1.0f / FMath::Max(1, InputSendRateHz);
|
|
||||||
SendAccumulatorSec += DeltaSeconds;
|
|
||||||
TimeSinceLastSendSec += DeltaSeconds;
|
|
||||||
|
|
||||||
const bool bMovingInput = !FMath::IsNearlyZero(PendingMoveForward) || !FMath::IsNearlyZero(PendingMoveRight);
|
|
||||||
const bool bJumpEvent = bPendingJumpPressed || bPendingJumpReleased;
|
|
||||||
const bool bRateReached = SendAccumulatorSec >= SendInterval;
|
|
||||||
const bool bHeartbeatReached = TimeSinceLastSendSec >= HeartbeatIntervalSec;
|
|
||||||
|
|
||||||
// IsFalling é estado contínuo do CMC (espelhado em PlayerStatePayload::grounded
|
|
||||||
// para alimentar o MovementMode dos proxies). Forçar envio em transições
|
|
||||||
// walking↔falling garante que a animação de queda/pulo dispare nos outros
|
|
||||||
// clientes mesmo quando estamos em rate limit / sem input de movimento.
|
|
||||||
const UCharacterMovementComponent* CMCForFalling = GetCharacterMovement();
|
|
||||||
const bool bIsFalling = CMCForFalling != nullptr && CMCForFalling->IsFalling();
|
|
||||||
const bool bFallingChanged = (bIsFalling != bPreviousFalling);
|
|
||||||
|
|
||||||
const bool bShouldSend = bJumpEvent || bFallingChanged || (bMovingInput && bRateReached) || (!bMovingInput && bHeartbeatReached);
|
|
||||||
if (!bShouldSend)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++InputSequence;
|
|
||||||
const int32 ClientTimeMs = static_cast<int32>(FPlatformTime::Seconds() * 1000.0);
|
|
||||||
// ADR 0040: yaw da camara/controller para que o servidor consiga rotar o
|
|
||||||
// input (referencial-camara) para velocidade mundial. Fallback para o yaw
|
|
||||||
// do actor se nao houver controller (e.g. tela de loading).
|
|
||||||
const float ViewYawDeg = (GetController()
|
|
||||||
? static_cast<float>(GetController()->GetControlRotation().Yaw)
|
|
||||||
: static_cast<float>(GetActorRotation().Yaw));
|
|
||||||
// ADR 0041: cliente autoritativo da posicao XYZ + velocidade XY. O CMC ja
|
|
||||||
// integrou o input local antes deste flush, portanto `GetActorLocation` e
|
|
||||||
// `GetVelocity` reflectem o estado real que o servidor deve replicar para
|
|
||||||
// os outros clientes (sujeito ao clamp anti-cheat).
|
|
||||||
const FVector PosCm = GetActorLocation();
|
|
||||||
const FVector Vel = GetVelocity();
|
|
||||||
ZeusNetwork->SendInputAxis(
|
|
||||||
PendingMoveForward,
|
|
||||||
PendingMoveRight,
|
|
||||||
bPendingJumpPressed,
|
|
||||||
bPendingJumpReleased,
|
|
||||||
InputSequence,
|
|
||||||
ClientTimeMs,
|
|
||||||
ViewYawDeg,
|
|
||||||
PosCm,
|
|
||||||
FVector2D(Vel.X, Vel.Y),
|
|
||||||
bIsFalling,
|
|
||||||
static_cast<float>(Vel.Z));
|
|
||||||
|
|
||||||
SendAccumulatorSec = 0.0f;
|
|
||||||
TimeSinceLastSendSec = 0.0f;
|
|
||||||
bPendingJumpPressed = false;
|
|
||||||
bPendingJumpReleased = false;
|
|
||||||
bPreviousFalling = bIsFalling;
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "GameFramework/CharacterMovementComponent.h"
|
|
||||||
|
|
||||||
#include "ZMMOProxyMovementComponent.generated.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CMC customizado para AZMMOPlayerProxy. Expõe escrita direta de Acceleration
|
|
||||||
* (protected na base) para que o AnimBP veja Acceleration!=0 quando o proxy
|
|
||||||
* recebe snapshots, alimentando a fórmula ShouldMove e a transição Jump_Start
|
|
||||||
* do ABP_Unarmed (ambas dependem de aceleração não-nula). Espelha
|
|
||||||
* UZeusProxyMovementComponent do ZClientMMO.
|
|
||||||
*/
|
|
||||||
UCLASS(ClassGroup = (ZMMO), meta = (BlueprintSpawnableComponent))
|
|
||||||
class ZMMO_API UZMMOProxyMovementComponent : public UCharacterMovementComponent
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
void SetZMMOExternalAcceleration(const FVector& InAccelerationCmS2)
|
|
||||||
{
|
|
||||||
Acceleration = InAccelerationCmS2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
717
Source/ZMMO/Game/Entity/ZeusCharacter.cpp
Normal file
717
Source/ZMMO/Game/Entity/ZeusCharacter.cpp
Normal file
@@ -0,0 +1,717 @@
|
|||||||
|
#include "ZeusCharacter.h"
|
||||||
|
|
||||||
|
#include "Animation/AnimInstance.h"
|
||||||
|
#include "Camera/CameraComponent.h"
|
||||||
|
#include "Components/CapsuleComponent.h"
|
||||||
|
#include "Components/SkeletalMeshComponent.h"
|
||||||
|
#include "EnhancedInputComponent.h"
|
||||||
|
#include "Engine/GameInstance.h"
|
||||||
|
#include "Engine/SkeletalMesh.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
|
#include "GameFramework/CharacterMovementComponent.h"
|
||||||
|
#include "GameFramework/Controller.h"
|
||||||
|
#include "GameFramework/SpringArmComponent.h"
|
||||||
|
#include "InputAction.h"
|
||||||
|
#include "InputActionValue.h"
|
||||||
|
#include "GameFramework/PlayerState.h"
|
||||||
|
#include "Subsystems/WorldSubsystem.h"
|
||||||
|
#include "UObject/ConstructorHelpers.h"
|
||||||
|
#include "ZMMO.h"
|
||||||
|
#include "GameplayTagContainer.h"
|
||||||
|
#include "GameplayTagsManager.h"
|
||||||
|
#include "ZeusGASComponent.h"
|
||||||
|
#include "ZeusAOIComponent.h"
|
||||||
|
#include "ZeusPlayerState.h"
|
||||||
|
#include "Blueprint/UserWidget.h"
|
||||||
|
#include "GameFramework/PlayerController.h"
|
||||||
|
#include "ZeusWorldSubsystem.h"
|
||||||
|
#include "ZeusNetworkSubsystem.h"
|
||||||
|
#include "ZeusNetworkingClientSubsystem.h"
|
||||||
|
#include "UI/FrontEnd/UIFrontEndFlowSubsystem.h"
|
||||||
|
|
||||||
|
DEFINE_LOG_CATEGORY(LogZeusPlayer);
|
||||||
|
|
||||||
|
AZeusCharacter::AZeusCharacter()
|
||||||
|
{
|
||||||
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
PrimaryActorTick.bStartWithTickEnabled = true;
|
||||||
|
|
||||||
|
GetCapsuleComponent()->InitCapsuleSize(42.0f, 96.0f);
|
||||||
|
|
||||||
|
bUseControllerRotationPitch = false;
|
||||||
|
bUseControllerRotationYaw = false;
|
||||||
|
bUseControllerRotationRoll = false;
|
||||||
|
|
||||||
|
UCharacterMovementComponent* CMC = GetCharacterMovement();
|
||||||
|
CMC->bOrientRotationToMovement = true;
|
||||||
|
CMC->RotationRate = FRotator(0.0f, 500.0f, 0.0f);
|
||||||
|
CMC->JumpZVelocity = 500.0f;
|
||||||
|
CMC->AirControl = 0.35f;
|
||||||
|
CMC->MaxWalkSpeed = 500.0f;
|
||||||
|
CMC->MinAnalogWalkSpeed = 20.0f;
|
||||||
|
CMC->BrakingDecelerationWalking = 2000.0f;
|
||||||
|
CMC->BrakingDecelerationFalling = 1500.0f;
|
||||||
|
|
||||||
|
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
|
||||||
|
CameraBoom->SetupAttachment(RootComponent);
|
||||||
|
CameraBoom->TargetArmLength = 400.0f;
|
||||||
|
CameraBoom->bUsePawnControlRotation = true;
|
||||||
|
|
||||||
|
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
|
||||||
|
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
|
||||||
|
FollowCamera->bUsePawnControlRotation = false;
|
||||||
|
|
||||||
|
// AOI do cliente (+ overlays de debug). Implementa IZeusAOIDebugTarget; o
|
||||||
|
// Zeus Admin Tools acha este componente no pawn e dirige os overlays.
|
||||||
|
AOIComponent = CreateDefaultSubobject<UZeusAOIComponent>(TEXT("ZeusAOIComponent"));
|
||||||
|
|
||||||
|
// AdminPanelClass NAO e' resolvido aqui via FClassFinder: na criacao do CDO
|
||||||
|
// (load do modulo) o asset registry pode nao estar pronto e o static cacheia
|
||||||
|
// null pra sempre. Resolvido lazy em ToggleAdminPanel (LoadClass em runtime).
|
||||||
|
|
||||||
|
// AttributeComponent migrou pro PlayerState (AZeusPlayerState + Component
|
||||||
|
// Registry config-driven). Pawn fica leve — so' movement/input/camera.
|
||||||
|
|
||||||
|
// Defaults visuais (mesh + AnimBP). Permitem ao motor spawnar AZeusCharacter
|
||||||
|
// directamente como DefaultPawnClass do AZeusGameMode sem exigir um BP filho.
|
||||||
|
// Um BP filho continua opcional para trocar mesh/AnimBP por mapa.
|
||||||
|
if (USkeletalMeshComponent* MeshComponent = GetMesh())
|
||||||
|
{
|
||||||
|
static ConstructorHelpers::FObjectFinder<USkeletalMesh> QuinnMesh(
|
||||||
|
TEXT("/Game/Characters/Mannequins/Meshes/SKM_Quinn_Simple.SKM_Quinn_Simple"));
|
||||||
|
static ConstructorHelpers::FClassFinder<UAnimInstance> QuinnAnimBp(
|
||||||
|
TEXT("/Game/Characters/Mannequins/Anims/Unarmed/ABP_Unarmed"));
|
||||||
|
|
||||||
|
if (QuinnMesh.Succeeded())
|
||||||
|
{
|
||||||
|
MeshComponent->SetSkeletalMesh(QuinnMesh.Object);
|
||||||
|
MeshComponent->SetRelativeLocation(FVector(0.0f, 0.0f, -90.0f));
|
||||||
|
MeshComponent->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UE_LOG(LogZeusPlayer, Warning, TEXT("Default mesh SKM_Quinn_Simple not found for AZeusCharacter."));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QuinnAnimBp.Succeeded())
|
||||||
|
{
|
||||||
|
MeshComponent->SetAnimationMode(EAnimationMode::AnimationBlueprint);
|
||||||
|
MeshComponent->SetAnimInstanceClass(QuinnAnimBp.Class);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UE_LOG(LogZeusPlayer, Warning, TEXT("Default anim blueprint ABP_Unarmed not found for AZeusCharacter."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input Actions defaults (Enhanced Input) — IMCs sao adicionados pelo
|
||||||
|
// AZeusPlayerController. As IAs aqui resolvem o asset por path; um BP filho
|
||||||
|
// pode sobrescrever caso queira inputs custom.
|
||||||
|
static ConstructorHelpers::FObjectFinder<UInputAction> MoveActionAsset(
|
||||||
|
TEXT("/Game/Input/Actions/IA_Move.IA_Move"));
|
||||||
|
static ConstructorHelpers::FObjectFinder<UInputAction> LookActionAsset(
|
||||||
|
TEXT("/Game/Input/Actions/IA_Look.IA_Look"));
|
||||||
|
static ConstructorHelpers::FObjectFinder<UInputAction> MouseLookActionAsset(
|
||||||
|
TEXT("/Game/Input/Actions/IA_MouseLook.IA_MouseLook"));
|
||||||
|
static ConstructorHelpers::FObjectFinder<UInputAction> JumpActionAsset(
|
||||||
|
TEXT("/Game/Input/Actions/IA_Jump.IA_Jump"));
|
||||||
|
static ConstructorHelpers::FObjectFinder<UInputAction> DashActionAsset(
|
||||||
|
TEXT("/Game/Input/Actions/IA_Dash.IA_Dash"));
|
||||||
|
|
||||||
|
if (MoveActionAsset.Succeeded()) { MoveAction = MoveActionAsset.Object; }
|
||||||
|
if (LookActionAsset.Succeeded()) { LookAction = LookActionAsset.Object; }
|
||||||
|
if (MouseLookActionAsset.Succeeded()) { MouseLookAction = MouseLookActionAsset.Object; }
|
||||||
|
if (JumpActionAsset.Succeeded()) { JumpAction = JumpActionAsset.Object; }
|
||||||
|
if (DashActionAsset.Succeeded()) { DashAction = DashActionAsset.Object; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::BeginPlay()
|
||||||
|
{
|
||||||
|
Super::BeginPlay();
|
||||||
|
ResolveZeusNetworkSubsystem();
|
||||||
|
BindZeusSpawnDelegate();
|
||||||
|
TryRegisterLocalEntityFromCachedSpawn();
|
||||||
|
|
||||||
|
// Fase 4: reposiciona o pawn na pos salva no DB (vinda no S_CHAR_SELECT_OK
|
||||||
|
// e memorizada no Flow). Substitui o PlayerStart default do level. Se nao
|
||||||
|
// ha pose pendente (primeiro boot / debug PIE direto no level), mantem o
|
||||||
|
// PlayerStart.
|
||||||
|
if (const UGameInstance* GI = GetGameInstance())
|
||||||
|
{
|
||||||
|
if (UUIFrontEndFlowSubsystem* Flow = GI->GetSubsystem<UUIFrontEndFlowSubsystem>())
|
||||||
|
{
|
||||||
|
FVector PosCm = FVector::ZeroVector;
|
||||||
|
float YawDeg = 0.0f;
|
||||||
|
if (Flow->ConsumePendingSpawnPose(PosCm, YawDeg))
|
||||||
|
{
|
||||||
|
const FRotator NewRot(0.0f, YawDeg, 0.0f);
|
||||||
|
SetActorLocationAndRotation(PosCm, NewRot, /*bSweep=*/false, nullptr, ETeleportType::TeleportPhysics);
|
||||||
|
if (AController* C = GetController())
|
||||||
|
{
|
||||||
|
C->SetControlRotation(NewRot);
|
||||||
|
}
|
||||||
|
UE_LOG(LogZeusPlayer, Log,
|
||||||
|
TEXT("AZeusCharacter: pawn reposicionado pra pos do DB (%s) yaw=%.1f"),
|
||||||
|
*PosCm.ToString(), YawDeg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||||
|
{
|
||||||
|
UnbindZeusSpawnDelegate();
|
||||||
|
ZeusNetwork = nullptr;
|
||||||
|
Super::EndPlay(EndPlayReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::Tick(const float DeltaSeconds)
|
||||||
|
{
|
||||||
|
Super::Tick(DeltaSeconds);
|
||||||
|
FlushInputAxisToServer(DeltaSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||||
|
{
|
||||||
|
// IMPORTANTE: chamar Super:: pra que BPs filhos consigam auto-bindar
|
||||||
|
// nodes EnhancedInputAction no Event Graph (ex: GA_Kick / IA_Kick no
|
||||||
|
// BP_ThirdPersonCharacter). Sem isso, bindings em BP ficam orfaos --
|
||||||
|
// so' bindings C++ (Move/Look/Jump/Dash abaixo) recebem input.
|
||||||
|
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
||||||
|
|
||||||
|
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
|
||||||
|
{
|
||||||
|
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &AZeusCharacter::OnJumpPressed);
|
||||||
|
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &AZeusCharacter::OnJumpReleased);
|
||||||
|
|
||||||
|
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AZeusCharacter::Move);
|
||||||
|
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Completed, this, &AZeusCharacter::MoveCompleted);
|
||||||
|
|
||||||
|
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AZeusCharacter::Look);
|
||||||
|
EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &AZeusCharacter::Look);
|
||||||
|
|
||||||
|
if (DashAction)
|
||||||
|
{
|
||||||
|
EnhancedInputComponent->BindAction(DashAction, ETriggerEvent::Triggered, this, &AZeusCharacter::OnDashTriggered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UE_LOG(LogZeusPlayer, Error, TEXT("'%s' Failed to find an Enhanced Input component."), *GetNameSafe(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug: F8 abre/fecha o Zeus Admin Tools (AIO Debug). Legacy BindKey
|
||||||
|
// convive com Enhanced Input. Trocar a tecla aqui se conflitar.
|
||||||
|
PlayerInputComponent->BindKey(EKeys::F8, IE_Pressed, this, &AZeusCharacter::ToggleAdminPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::ToggleAdminPanel()
|
||||||
|
{
|
||||||
|
APlayerController* PC = Cast<APlayerController>(GetController());
|
||||||
|
if (!PC)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aberto -> fecha + devolve input pro jogo.
|
||||||
|
if (AdminPanelInstance && AdminPanelInstance->IsInViewport())
|
||||||
|
{
|
||||||
|
AdminPanelInstance->RemoveFromParent();
|
||||||
|
PC->SetInputMode(FInputModeGameOnly());
|
||||||
|
PC->bShowMouseCursor = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lazy load (runtime): no F8 o asset ja' esta carregavel; evita o pitfall do
|
||||||
|
// FClassFinder na criacao do CDO. Path do generated class (_C).
|
||||||
|
// A UI vive no CONTENT DO PLUGIN (mount /ZeusAdminTools/), nao no /Game do projeto:
|
||||||
|
// o plugin ZeusAdminTools e' autocontido (C++ + UI no repo Server).
|
||||||
|
if (!AdminPanelClass)
|
||||||
|
{
|
||||||
|
AdminPanelClass = LoadClass<UUserWidget>(nullptr,
|
||||||
|
TEXT("/ZeusAdminTools/UI/WBP_AdminToolsAIO.WBP_AdminToolsAIO_C"));
|
||||||
|
}
|
||||||
|
if (!AdminPanelClass)
|
||||||
|
{
|
||||||
|
UE_LOG(LogZeusPlayer, Warning, TEXT("[AdminPanel] AdminPanelClass nao resolvido (WBP_AdminToolsAIO ausente?)."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AdminPanelInstance)
|
||||||
|
{
|
||||||
|
AdminPanelInstance = CreateWidget<UUserWidget>(PC, AdminPanelClass);
|
||||||
|
}
|
||||||
|
if (AdminPanelInstance)
|
||||||
|
{
|
||||||
|
AdminPanelInstance->AddToViewport(1000);
|
||||||
|
|
||||||
|
// UIOnly: trava a acao do jogo enquanto o menu esta aberto e garante que
|
||||||
|
// os cliques vao 100% pra UI (no GameAndUI o viewport rouba o clique).
|
||||||
|
// O mundo continua renderizando + os overlays de debug seguem desenhando.
|
||||||
|
FInputModeUIOnly Mode;
|
||||||
|
Mode.SetWidgetToFocus(AdminPanelInstance->TakeWidget());
|
||||||
|
Mode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
|
||||||
|
PC->SetInputMode(Mode);
|
||||||
|
PC->bShowMouseCursor = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::Move(const FInputActionValue& Value)
|
||||||
|
{
|
||||||
|
const FVector2D MovementVector = Value.Get<FVector2D>();
|
||||||
|
DoMove(MovementVector.X, MovementVector.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::MoveCompleted(const FInputActionValue& Value)
|
||||||
|
{
|
||||||
|
(void)Value;
|
||||||
|
DoMove(0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::Look(const FInputActionValue& Value)
|
||||||
|
{
|
||||||
|
const FVector2D LookAxisVector = Value.Get<FVector2D>();
|
||||||
|
DoLook(LookAxisVector.X, LookAxisVector.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::OnJumpPressed()
|
||||||
|
{
|
||||||
|
bPendingJumpPressed = true;
|
||||||
|
DoJumpStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::OnJumpReleased()
|
||||||
|
{
|
||||||
|
bPendingJumpReleased = true;
|
||||||
|
DoJumpEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::OnDashTriggered()
|
||||||
|
{
|
||||||
|
// Resolve UZeusGASComponent do PlayerState. Component vive la' via
|
||||||
|
// AZeusPlayerState Component Registry (config-driven). Sem el, ASC ausente
|
||||||
|
// e RequestActivateAbilityByTag falha — log warning.
|
||||||
|
const APlayerState* PS = GetPlayerState();
|
||||||
|
if (!PS)
|
||||||
|
{
|
||||||
|
UE_LOG(LogZeusPlayer, Warning, TEXT("OnDashTriggered: PlayerState nullptr — ignorado"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UZeusGASComponent* Comp = PS->FindComponentByClass<UZeusGASComponent>();
|
||||||
|
if (!Comp)
|
||||||
|
{
|
||||||
|
UE_LOG(LogZeusPlayer, Warning, TEXT("OnDashTriggered: UZeusGASComponent nao achado"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag canonica casa com row do DT + JSON do server. Hash FNV calculado
|
||||||
|
// dentro do componente (RequestActivateAbilityByTag).
|
||||||
|
const FGameplayTag DashTag = UGameplayTagsManager::Get().RequestGameplayTag(
|
||||||
|
FName(TEXT("Zeus.Ability.Movement.Dash")));
|
||||||
|
if (!DashTag.IsValid())
|
||||||
|
{
|
||||||
|
UE_LOG(LogZeusPlayer, Warning,
|
||||||
|
TEXT("OnDashTriggered: tag Zeus.Ability.Movement.Dash nao registrada no cliente"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool bSent = Comp->RequestActivateAbilityByTag(DashTag);
|
||||||
|
UE_LOG(LogZeusPlayer, Log, TEXT("OnDashTriggered -> RequestActivateAbilityByTag = %s"),
|
||||||
|
bSent ? TEXT("OK (C_ABILITY_TRY_ACTIVATE enviado)") : TEXT("FALHOU"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::DoMove(const float Right, const float Forward)
|
||||||
|
{
|
||||||
|
PendingMoveRight = FMath::Clamp(Right, -1.0f, 1.0f);
|
||||||
|
PendingMoveForward = FMath::Clamp(Forward, -1.0f, 1.0f);
|
||||||
|
|
||||||
|
if (GetController() != nullptr)
|
||||||
|
{
|
||||||
|
const FRotator Rotation = GetController()->GetControlRotation();
|
||||||
|
const FRotator YawRotation(0.0f, Rotation.Yaw, 0.0f);
|
||||||
|
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
||||||
|
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
|
||||||
|
AddMovementInput(ForwardDirection, Forward);
|
||||||
|
AddMovementInput(RightDirection, Right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::DoLook(const float Yaw, const float Pitch)
|
||||||
|
{
|
||||||
|
if (GetController() != nullptr)
|
||||||
|
{
|
||||||
|
AddControllerYawInput(Yaw);
|
||||||
|
AddControllerPitchInput(Pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::DoJumpStart()
|
||||||
|
{
|
||||||
|
Jump();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::DoJumpEnd()
|
||||||
|
{
|
||||||
|
StopJumping();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::ApplyEntitySnapshot(const FZeusEntitySnapshot& /*Snapshot*/)
|
||||||
|
{
|
||||||
|
// Cliente local solto: o servidor nao reconcilia posicao em V0 (ADR 0038).
|
||||||
|
// Quando colisao de objetos chegar, podemos ligar uma reconciliacao opcional
|
||||||
|
// horizontal aqui (XY only), preservando o Z do CMC local.
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::SetEntityRelevant(bool /*bRelevant*/)
|
||||||
|
{
|
||||||
|
// Nunca despawnamos o jogador local via AOI.
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::ResolveZeusNetworkSubsystem()
|
||||||
|
{
|
||||||
|
if (ZeusNetwork && NetClient)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UGameInstance* GI = GetGameInstance();
|
||||||
|
if (!GI)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ZeusNetwork)
|
||||||
|
{
|
||||||
|
ZeusNetwork = GI->GetSubsystem<UZeusNetworkSubsystem>();
|
||||||
|
}
|
||||||
|
if (!NetClient)
|
||||||
|
{
|
||||||
|
NetClient = GI->GetSubsystem<UZeusNetworkingClientSubsystem>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::BindZeusSpawnDelegate()
|
||||||
|
{
|
||||||
|
if (bSpawnDelegateBound || !IsLocallyControlled())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!NetClient && !ZeusNetwork)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self-entity (entityId do proprio char) vem do sistema de rede novo.
|
||||||
|
if (NetClient)
|
||||||
|
{
|
||||||
|
NetClient->OnSelfEntityAssigned.AddDynamic(this, &AZeusCharacter::HandleSelfEntityAssigned);
|
||||||
|
}
|
||||||
|
// CHAR_INFO (nome/guild) ainda nao tem equivalente no sistema novo -> legacy.
|
||||||
|
if (ZeusNetwork)
|
||||||
|
{
|
||||||
|
ZeusNetwork->OnCharInfoReceived.AddDynamic(this, &AZeusCharacter::HandleZeusCharInfo);
|
||||||
|
}
|
||||||
|
bSpawnDelegateBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::UnbindZeusSpawnDelegate()
|
||||||
|
{
|
||||||
|
if (!bSpawnDelegateBound)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (NetClient)
|
||||||
|
{
|
||||||
|
NetClient->OnSelfEntityAssigned.RemoveDynamic(this, &AZeusCharacter::HandleSelfEntityAssigned);
|
||||||
|
}
|
||||||
|
if (ZeusNetwork)
|
||||||
|
{
|
||||||
|
ZeusNetwork->OnCharInfoReceived.RemoveDynamic(this, &AZeusCharacter::HandleZeusCharInfo);
|
||||||
|
}
|
||||||
|
bSpawnDelegateBound = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::TryRegisterLocalEntityFromCachedSpawn()
|
||||||
|
{
|
||||||
|
// Self-entity vem do sistema de rede novo (ENT_SELF). O subsystem e'
|
||||||
|
// per-GameInstance e sobrevive ao OpenLevel, entao o entityId pode ja' ter
|
||||||
|
// chegado antes deste pawn existir -- puxa o cache agora. Caso ainda nao
|
||||||
|
// tenha chegado, o bind em OnSelfEntityAssigned cobre quando chegar.
|
||||||
|
// A pos/yaw vem do proprio pawn (ja posicionado via PendingSpawnPose do DB);
|
||||||
|
// o sistema novo so' carrega o entityId.
|
||||||
|
if (NetClient)
|
||||||
|
{
|
||||||
|
const int64 SelfId = NetClient->GetLocalEntityId();
|
||||||
|
if (SelfId != 0)
|
||||||
|
{
|
||||||
|
HandleLocalSpawnReady(SelfId, GetActorLocation(), GetActorRotation().Yaw, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Race fix CHAR_INFO (ainda legacy): o S_CHAR_INFO pode ter chegado antes do
|
||||||
|
// pawn existir; aplica o ultimo nome/guild cacheado.
|
||||||
|
TryApplyCachedCharInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::HandleSelfEntityAssigned(const int64 InEntityId)
|
||||||
|
{
|
||||||
|
// Sistema novo informou o entityId do proprio char (ENT_SELF). Reusa o mesmo
|
||||||
|
// caminho do spawn local legacy (seta ZeusEntityId + RegisterLocalEntity).
|
||||||
|
// pos/yaw vem do pawn (ja posicionado); o sistema novo so' traz o entityId.
|
||||||
|
HandleLocalSpawnReady(InEntityId, GetActorLocation(), GetActorRotation().Yaw, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::HandleZeusPlayerSpawned(const int64 InEntityId, const bool bIsLocal,
|
||||||
|
const FVector PosCm, const float YawDeg, const int64 ServerTimeMs)
|
||||||
|
{
|
||||||
|
if (!bIsLocal)
|
||||||
|
{
|
||||||
|
// Remote spawns sao tratados pelo `UZeusWorldSubsystem`; aqui so reagimos
|
||||||
|
// ao spawn do pawn possessivel local (S_SPAWN_PLAYER com bIsLocal=true).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HandleLocalSpawnReady(InEntityId, PosCm, YawDeg, ServerTimeMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::HandleLocalSpawnReady(const int64 InEntityId, const FVector PosCm,
|
||||||
|
const float YawDeg, const int64 ServerTimeMs)
|
||||||
|
{
|
||||||
|
if (InEntityId == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PR-HANDOFF-007 — InEntityId é int64 (era int32)
|
||||||
|
if (ZeusEntityId == InEntityId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeusEntityId = InEntityId;
|
||||||
|
|
||||||
|
UE_LOG(LogZeusPlayer, Log,
|
||||||
|
TEXT("AZeusCharacter: local spawn captured EntityId=%lld pos=(%s) yaw=%.1f t=%lld"),
|
||||||
|
InEntityId, *PosCm.ToString(), YawDeg, ServerTimeMs);
|
||||||
|
|
||||||
|
if (UWorld* World = GetWorld())
|
||||||
|
{
|
||||||
|
if (UZeusWorldSubsystem* WorldSubsystem = World->GetSubsystem<UZeusWorldSubsystem>())
|
||||||
|
{
|
||||||
|
WorldSubsystem->RegisterLocalEntity(InEntityId, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identidade publica (EntityId) + seed no GAS Component. CharName/Guild
|
||||||
|
// vem separado via S_CHAR_INFO -> HandleZeusCharInfo. UZeusGASComponent
|
||||||
|
// vive como subobject do PlayerState (Component Registry) e recebe seed
|
||||||
|
// pra que o UZeusGASNetworkHandler consiga rotear o snapshot por
|
||||||
|
// EntityId desde o primeiro pacote.
|
||||||
|
if (APlayerState* PS = GetPlayerState())
|
||||||
|
{
|
||||||
|
if (AZeusPlayerState* ZeusPs = Cast<AZeusPlayerState>(PS))
|
||||||
|
{
|
||||||
|
ZeusPs->SetPublicIdentity(InEntityId, /*CharId*/ FString(),
|
||||||
|
/*BaseLevel*/ 1, /*ClassId*/ 0);
|
||||||
|
}
|
||||||
|
if (UZeusGASComponent* GASComp = PS->FindComponentByClass<UZeusGASComponent>())
|
||||||
|
{
|
||||||
|
GASComp->SeedEntityId(InEntityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aplica char info cacheada (caso S_CHAR_INFO tenha chegado antes do PS existir).
|
||||||
|
TryApplyCachedCharInfo();
|
||||||
|
|
||||||
|
// UI in-game e' responsabilidade do AZeusHUD (GameMode.HUDClass), nao do
|
||||||
|
// Pawn. AHUD::BeginPlay chama UUIInGameFlowSubsystem::StartInGame, que
|
||||||
|
// pushea WBP_HUD em UI.Layer.Game. UZeusHudWidget::NativeOnActivated auto-binda
|
||||||
|
// no UZeusGASComponent via PlayerState.
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::HandleZeusCharInfo(const int64 InEntityId, const FString& CharName, const FString& GuildName)
|
||||||
|
{
|
||||||
|
UE_LOG(LogZeusPlayer, Log,
|
||||||
|
TEXT("AZeusCharacter: S_CHAR_INFO recebido EntityId=%lld name=%s guild=%s"),
|
||||||
|
InEntityId, *CharName, *GuildName);
|
||||||
|
|
||||||
|
// 2026-06-03 fix: server envia S_CHAR_INFO de TODOS os players (proprio +
|
||||||
|
// catch-up de proxies pre-existentes). Sem este filtro, o nome do ultimo
|
||||||
|
// proxy recebido sobrescrevia o do pawn local (ex: player Mateuus loga e
|
||||||
|
// ve "Olatudook" em si mesmo porque o catch-up do Olatudook chegou depois
|
||||||
|
// do S_CHAR_INFO proprio). Proxies remotos sao roteados pelo registry no
|
||||||
|
// UZeusWorldSubsystem (futuro nameplate por EntityId).
|
||||||
|
if (ZeusEntityId != 0 && InEntityId != ZeusEntityId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
APlayerState* PS = GetPlayerState();
|
||||||
|
if (!PS)
|
||||||
|
{
|
||||||
|
// Race fix: pawn pode nao ter PlayerState ainda. Subsystem ja cacheou
|
||||||
|
// (LastLocalCharInfoCache); TryApplyCachedCharInfo aplica em
|
||||||
|
// HandleLocalSpawnReady ou em outra oportunidade.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (AZeusPlayerState* ZeusPs = Cast<AZeusPlayerState>(PS))
|
||||||
|
{
|
||||||
|
ZeusPs->SetCharInfo(CharName, GuildName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::TryApplyCachedCharInfo()
|
||||||
|
{
|
||||||
|
if (!ZeusNetwork)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int64 CachedEntityId = 0;
|
||||||
|
FString CachedCharName;
|
||||||
|
FString CachedGuildName;
|
||||||
|
if (!ZeusNetwork->TryGetLastLocalCharInfo(CachedEntityId, CachedCharName, CachedGuildName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (APlayerState* PS = GetPlayerState())
|
||||||
|
{
|
||||||
|
if (AZeusPlayerState* ZeusPs = Cast<AZeusPlayerState>(PS))
|
||||||
|
{
|
||||||
|
ZeusPs->SetCharInfo(CachedCharName, CachedGuildName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZeusCharacter::FlushInputAxisToServer(const float DeltaSeconds)
|
||||||
|
{
|
||||||
|
ResolveZeusNetworkSubsystem();
|
||||||
|
// Sistema de rede novo (canonico) tem prioridade; legacy e' fallback.
|
||||||
|
const bool bV1 = (NetClient
|
||||||
|
&& NetClient->GetConnectionState() == EZeusV1ConnectionState::Accepted);
|
||||||
|
if (!bV1 && (!ZeusNetwork || !ZeusNetwork->IsConnected()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float SendInterval = 1.0f / FMath::Max(1, InputSendRateHz);
|
||||||
|
SendAccumulatorSec += DeltaSeconds;
|
||||||
|
TimeSinceLastSendSec += DeltaSeconds;
|
||||||
|
|
||||||
|
// Movimento p/ efeitos de rate NAO e' so' o input (W/A/S/D): o CMC do dono
|
||||||
|
// continua desacelerando (braking) por ~0.3s depois de soltar a tecla. Se
|
||||||
|
// pararmos de enviar no rate rapido assim que o input zera, o servidor fica
|
||||||
|
// congelado na ultima `simpleVelCmS` alta e o proxy remoto extrapola ~1m alem
|
||||||
|
// (NewPos = Last.Pos + Last.Vel*ExtrapSec) ate o heartbeat corrigir -> overshoot
|
||||||
|
// + snap-back ("velocidade grande que demora a zerar" + jitter). Tratar a
|
||||||
|
// velocidade residual como movimento mantem o envio a InputSendRateHz ate o
|
||||||
|
// dono realmente parar, alimentando o proxy com a curva de desaceleracao.
|
||||||
|
const bool bHasInputAxis = !FMath::IsNearlyZero(PendingMoveForward) || !FMath::IsNearlyZero(PendingMoveRight);
|
||||||
|
const FVector OwnerVelNow = GetVelocity();
|
||||||
|
constexpr float kResidualSpeedSqCmS = 25.0f * 25.0f; // abaixo de 25 cm/s tratamos como parado
|
||||||
|
const bool bHasResidualVel = OwnerVelNow.SizeSquared() > kResidualSpeedSqCmS;
|
||||||
|
const bool bMovingInput = bHasInputAxis || bHasResidualVel;
|
||||||
|
const bool bJumpEvent = bPendingJumpPressed || bPendingJumpReleased;
|
||||||
|
const bool bRateReached = SendAccumulatorSec >= SendInterval;
|
||||||
|
const bool bHeartbeatReached = TimeSinceLastSendSec >= HeartbeatIntervalSec;
|
||||||
|
|
||||||
|
// IsFalling é estado contínuo do CMC (espelhado em PlayerStatePayload::grounded
|
||||||
|
// para alimentar o MovementMode dos proxies). Forçar envio em transições
|
||||||
|
// walking↔falling garante que a animação de queda/pulo dispare nos outros
|
||||||
|
// clientes mesmo quando estamos em rate limit / sem input de movimento.
|
||||||
|
const UCharacterMovementComponent* CMCForFalling = GetCharacterMovement();
|
||||||
|
const bool bIsFalling = CMCForFalling != nullptr && CMCForFalling->IsFalling();
|
||||||
|
const bool bFallingChanged = (bIsFalling != bPreviousFalling);
|
||||||
|
|
||||||
|
const bool bShouldSend = bJumpEvent || bFallingChanged || (bMovingInput && bRateReached) || (!bMovingInput && bHeartbeatReached);
|
||||||
|
// DEBUG-INPUT (2026-06-12): log ~1x/s COM o PIE. Remover apos achar o gap.
|
||||||
|
{
|
||||||
|
static float DbgInputAcc = 0.0f;
|
||||||
|
DbgInputAcc += DeltaSeconds;
|
||||||
|
if (DbgInputAcc >= 1.0f)
|
||||||
|
{
|
||||||
|
DbgInputAcc = 0.0f;
|
||||||
|
const int32 PieId = (GetWorld() && GetWorld()->GetOutermost())
|
||||||
|
? GetWorld()->GetOutermost()->GetPIEInstanceID() : -1;
|
||||||
|
UE_LOG(LogZeusPlayer, Warning,
|
||||||
|
TEXT("[PIE%d][InputDbg] bV1=%d state=%d moving=%d rate=%d should=%d hbReached=%d fwd=%.2f right=%.2f"),
|
||||||
|
PieId, bV1 ? 1 : 0,
|
||||||
|
NetClient ? static_cast<int32>(NetClient->GetConnectionState()) : -99,
|
||||||
|
bMovingInput ? 1 : 0, bRateReached ? 1 : 0, bShouldSend ? 1 : 0,
|
||||||
|
bHeartbeatReached ? 1 : 0, PendingMoveForward, PendingMoveRight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bShouldSend)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
++InputSequence;
|
||||||
|
const int32 ClientTimeMs = static_cast<int32>(FPlatformTime::Seconds() * 1000.0);
|
||||||
|
// YAW DO CORPO (nao da mira): GetActorRotation().Yaw reflete o orient-to-movement
|
||||||
|
// do CMC (bOrientRotationToMovement=true, RotationRate=(0,500,0)) -> o corpo vira
|
||||||
|
// pra direcao do MOVIMENTO (WASD), suave a 500 deg/s, e o MOUSE nao gira o corpo
|
||||||
|
// (bUseControllerRotationYaw=false). O servidor usa este yaw direto e o proxy nos
|
||||||
|
// outros clientes o replica -> o proxy vira IDENTICO ao corpo do dono.
|
||||||
|
//
|
||||||
|
// (Historico bug 2026-06-13: antes mandava GetControlRotation().Yaw -- a MIRA --
|
||||||
|
// e o servidor fazia atan2(vel) INSTANTANEO quando movia (proxy "virava demais"
|
||||||
|
// 45 graus) e usava a mira quando parado (proxy seguia o mouse). ADR 0040: o
|
||||||
|
// servidor NAO rotaciona mais o input por este yaw (ADR 0041 manda pos+vel
|
||||||
|
// mundiais), entao trocar a mira pelo corpo e' seguro. Quando precisar da MIRA
|
||||||
|
// real (aim/combate), adicionar um campo aimYawDeg dedicado -- nao reusar este.)
|
||||||
|
const float BodyYawDeg = static_cast<float>(GetActorRotation().Yaw);
|
||||||
|
// ADR 0041: cliente autoritativo da posicao XYZ + velocidade XY. O CMC ja
|
||||||
|
// integrou o input local antes deste flush, portanto `GetActorLocation` e
|
||||||
|
// `GetVelocity` reflectem o estado real que o servidor deve replicar para
|
||||||
|
// os outros clientes (sujeito ao clamp anti-cheat).
|
||||||
|
const FVector PosCm = GetActorLocation();
|
||||||
|
const FVector Vel = GetVelocity();
|
||||||
|
if (bV1)
|
||||||
|
{
|
||||||
|
// Sistema novo: INPUT 6077 com a pose absoluta (ADR 0040/0041).
|
||||||
|
const bool bSent = NetClient->EmitInput(
|
||||||
|
PendingMoveForward,
|
||||||
|
PendingMoveRight,
|
||||||
|
bPendingJumpPressed,
|
||||||
|
bPendingJumpReleased,
|
||||||
|
InputSequence,
|
||||||
|
ClientTimeMs,
|
||||||
|
BodyYawDeg,
|
||||||
|
PosCm,
|
||||||
|
FVector2D(Vel.X, Vel.Y),
|
||||||
|
bIsFalling,
|
||||||
|
static_cast<float>(Vel.Z));
|
||||||
|
// DEBUG-INPUT (2026-06-12): confirma chamada + retorno do SendPacket.
|
||||||
|
static float DbgEmitAcc = 0.0f;
|
||||||
|
DbgEmitAcc += DeltaSeconds;
|
||||||
|
if (DbgEmitAcc >= 1.0f)
|
||||||
|
{
|
||||||
|
DbgEmitAcc = 0.0f;
|
||||||
|
const int32 PieId = (GetWorld() && GetWorld()->GetOutermost())
|
||||||
|
? GetWorld()->GetOutermost()->GetPIEInstanceID() : -1;
|
||||||
|
UE_LOG(LogZeusPlayer, Warning,
|
||||||
|
TEXT("[PIE%d][InputDbg] EmitInput seq=%d sent=%d pos=%s"),
|
||||||
|
PieId, InputSequence, bSent ? 1 : 0, *PosCm.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ZeusNetwork)
|
||||||
|
{
|
||||||
|
ZeusNetwork->SendInputAxis(
|
||||||
|
PendingMoveForward,
|
||||||
|
PendingMoveRight,
|
||||||
|
bPendingJumpPressed,
|
||||||
|
bPendingJumpReleased,
|
||||||
|
InputSequence,
|
||||||
|
ClientTimeMs,
|
||||||
|
BodyYawDeg,
|
||||||
|
PosCm,
|
||||||
|
FVector2D(Vel.X, Vel.Y),
|
||||||
|
bIsFalling,
|
||||||
|
static_cast<float>(Vel.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
SendAccumulatorSec = 0.0f;
|
||||||
|
TimeSinceLastSendSec = 0.0f;
|
||||||
|
bPendingJumpPressed = false;
|
||||||
|
bPendingJumpReleased = false;
|
||||||
|
bPreviousFalling = bIsFalling;
|
||||||
|
}
|
||||||
@@ -3,23 +3,25 @@
|
|||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GameFramework/Character.h"
|
#include "GameFramework/Character.h"
|
||||||
#include "Logging/LogMacros.h"
|
#include "Logging/LogMacros.h"
|
||||||
#include "ZMMOEntityInterface.h"
|
#include "ZeusEntityInterface.h"
|
||||||
#include "ZMMOEntityTypes.h"
|
#include "ZeusEntityTypes.h"
|
||||||
#include "ZMMOPlayerCharacter.generated.h"
|
#include "ZeusCharacter.generated.h"
|
||||||
|
|
||||||
class USpringArmComponent;
|
class USpringArmComponent;
|
||||||
class UCameraComponent;
|
class UCameraComponent;
|
||||||
class UInputAction;
|
class UInputAction;
|
||||||
class UZeusNetworkSubsystem;
|
class UZeusNetworkSubsystem;
|
||||||
|
class UZeusNetworkingClientSubsystem;
|
||||||
|
class UZeusAOIComponent;
|
||||||
|
class UUserWidget;
|
||||||
struct FInputActionValue;
|
struct FInputActionValue;
|
||||||
|
|
||||||
DECLARE_LOG_CATEGORY_EXTERN(LogZMMOPlayer, Log, All);
|
DECLARE_LOG_CATEGORY_EXTERN(LogZeusPlayer, Log, All);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AZMMOPlayerCharacter
|
* AZeusCharacter
|
||||||
*
|
*
|
||||||
* Personagem do jogador local. Diferente do template `ThirdPersonCharacter`
|
* Personagem do jogador local. Parte do pipeline de rede Zeus:
|
||||||
* e do antigo `AZMMOCharacter`, este ator e parte do pipeline de rede Zeus:
|
|
||||||
*
|
*
|
||||||
* - Continua a usar o `UCharacterMovementComponent` LIVRE para correr a
|
* - Continua a usar o `UCharacterMovementComponent` LIVRE para correr a
|
||||||
* fisica do landscape (ADR 0038): o cliente e autoritativo localmente
|
* fisica do landscape (ADR 0038): o cliente e autoritativo localmente
|
||||||
@@ -27,15 +29,15 @@ DECLARE_LOG_CATEGORY_EXTERN(LogZMMOPlayer, Log, All);
|
|||||||
* - Envia `C_INPUT_AXIS` ao `UZeusNetworkSubsystem` na cadencia
|
* - Envia `C_INPUT_AXIS` ao `UZeusNetworkSubsystem` na cadencia
|
||||||
* `InputSendRateHz` (com heartbeat 5 Hz quando parado para evitar
|
* `InputSendRateHz` (com heartbeat 5 Hz quando parado para evitar
|
||||||
* starvation do `MovementSystem` no servidor).
|
* starvation do `MovementSystem` no servidor).
|
||||||
* - Implementa `IZMMOEntityInterface` para participar do registry do
|
* - Implementa `IZeusEntityInterface` para participar do registry do
|
||||||
* `UZMMOWorldSubsystem`, mas `ApplyEntitySnapshot` e `SetEntityRelevant`
|
* `UZeusWorldSubsystem`, mas `ApplyEntitySnapshot` e `SetEntityRelevant`
|
||||||
* sao no-op em V0 — o cliente local nao reconcilia (cliente solto).
|
* sao no-op em V0 — o cliente local nao reconcilia (cliente solto).
|
||||||
*
|
*
|
||||||
* TODO V1: reconciliacao opcional XY quando colisao de objetos chegar; AOI
|
* TODO V1: reconciliacao opcional XY quando colisao de objetos chegar; AOI
|
||||||
* debug spheres; visual smoothing apos correcao do servidor.
|
* debug spheres; visual smoothing apos correcao do servidor.
|
||||||
*/
|
*/
|
||||||
UCLASS(Blueprintable, BlueprintType)
|
UCLASS(Blueprintable, BlueprintType)
|
||||||
class ZMMO_API AZMMOPlayerCharacter : public ACharacter, public IZMMOEntityInterface
|
class ZMMO_API AZeusCharacter : public ACharacter, public IZeusEntityInterface
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
@@ -47,8 +49,12 @@ class ZMMO_API AZMMOPlayerCharacter : public ACharacter, public IZMMOEntityInter
|
|||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
||||||
UCameraComponent* FollowCamera;
|
UCameraComponent* FollowCamera;
|
||||||
|
|
||||||
// AttributeComponent vive no PlayerState (AZMMOPlayerState + Component Registry).
|
/** AOI do cliente (+ overlays de debug dirigidos pelo Zeus Admin Tools). */
|
||||||
// Acesso: GetPlayerState<AZMMOPlayerState>()->GetZMMOComponent<UZMMOAttributeComponent>().
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Zeus|AOI", meta = (AllowPrivateAccess = "true"))
|
||||||
|
TObjectPtr<UZeusAOIComponent> AOIComponent;
|
||||||
|
|
||||||
|
// GAS Component vive no PlayerState (AZeusPlayerState + Component Registry).
|
||||||
|
// Acesso: GetPlayerState<AZeusPlayerState>()->GetZeusComponent<UZeusGASComponent>().
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UPROPERTY(EditAnywhere, Category = "Input")
|
UPROPERTY(EditAnywhere, Category = "Input")
|
||||||
@@ -63,8 +69,18 @@ protected:
|
|||||||
UPROPERTY(EditAnywhere, Category = "Input")
|
UPROPERTY(EditAnywhere, Category = "Input")
|
||||||
UInputAction* MouseLookAction;
|
UInputAction* MouseLookAction;
|
||||||
|
|
||||||
|
/// IA_Dash — dispara C_ABILITY_TRY_ACTIVATE pra Zeus.Ability.Movement.Dash
|
||||||
|
/// via UZeusGASComponent. Bind padrao no IMC_Default: LeftShift -> Pressed.
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Input")
|
||||||
|
UInputAction* DashAction;
|
||||||
|
|
||||||
|
/** Painel Zeus Admin Tools (AIO Debug), aberto/fechado por F8. Default =
|
||||||
|
* WBP_AdminToolsAIO (resolvido no construtor). */
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Zeus|Admin")
|
||||||
|
TSubclassOf<UUserWidget> AdminPanelClass;
|
||||||
|
|
||||||
/** Cadencia de envio dos pacotes `C_INPUT_AXIS` (Hz). */
|
/** Cadencia de envio dos pacotes `C_INPUT_AXIS` (Hz). */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ZMMO|Networking", meta = (ClampMin = "1", ClampMax = "120"))
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zeus|Networking", meta = (ClampMin = "1", ClampMax = "120"))
|
||||||
int32 InputSendRateHz = 30;
|
int32 InputSendRateHz = 30;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,22 +89,22 @@ protected:
|
|||||||
* evitar starvation do servidor caso pacotes sejam perdidos. Em movimento
|
* evitar starvation do servidor caso pacotes sejam perdidos. Em movimento
|
||||||
* o envio segue `InputSendRateHz` (30 Hz).
|
* o envio segue `InputSendRateHz` (30 Hz).
|
||||||
*/
|
*/
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ZMMO|Networking", meta = (ClampMin = "0.05", ClampMax = "5.0"))
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zeus|Networking", meta = (ClampMin = "0.05", ClampMax = "5.0"))
|
||||||
float HeartbeatIntervalSec = 0.2f;
|
float HeartbeatIntervalSec = 0.2f;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AZMMOPlayerCharacter();
|
AZeusCharacter();
|
||||||
|
|
||||||
virtual void Tick(float DeltaSeconds) override;
|
virtual void Tick(float DeltaSeconds) override;
|
||||||
|
|
||||||
// --- IZMMOEntityInterface ---
|
// --- IZeusEntityInterface ---
|
||||||
virtual int64 GetZMMOEntityId() const override { return ZMMOEntityId; }
|
virtual int64 GetZeusEntityId() const override { return ZeusEntityId; }
|
||||||
virtual EZMMOEntityType GetZMMOEntityType() const override { return EZMMOEntityType::Player; }
|
virtual EZeusEntityType GetZeusEntityType() const override { return EZeusEntityType::Player; }
|
||||||
virtual void ApplyEntitySnapshot(const FZMMOEntitySnapshot& Snapshot) override;
|
virtual void ApplyEntitySnapshot(const FZeusEntitySnapshot& Snapshot) override;
|
||||||
virtual void SetEntityRelevant(bool bRelevant) override;
|
virtual void SetEntityRelevant(bool bRelevant) override;
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "ZMMO|Entity")
|
UFUNCTION(BlueprintCallable, Category = "Zeus|Entity")
|
||||||
void SetZMMOEntityId(int64 InEntityId) { ZMMOEntityId = InEntityId; }
|
void SetZeusEntityId(int64 InEntityId) { ZeusEntityId = InEntityId; }
|
||||||
|
|
||||||
FORCEINLINE USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
|
FORCEINLINE USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
|
||||||
FORCEINLINE UCameraComponent* GetFollowCamera() const { return FollowCamera; }
|
FORCEINLINE UCameraComponent* GetFollowCamera() const { return FollowCamera; }
|
||||||
@@ -105,6 +121,14 @@ protected:
|
|||||||
void OnJumpPressed();
|
void OnJumpPressed();
|
||||||
void OnJumpReleased();
|
void OnJumpReleased();
|
||||||
|
|
||||||
|
/// IA_Dash Triggered -> resolve UZeusGASComponent do PlayerState e chama
|
||||||
|
/// RequestActivateAbilityByTag("Zeus.Ability.Movement.Dash"). Server valida
|
||||||
|
/// + responde S_ABILITY_ACTIVATED (HP/SP atualizado, montage roda local).
|
||||||
|
void OnDashTriggered();
|
||||||
|
|
||||||
|
/** F8: cria/mostra ou esconde o painel Zeus Admin Tools (input mode UI + cursor). */
|
||||||
|
void ToggleAdminPanel();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Wrappers expostos a Blueprint (UI / mobile / automation). */
|
/** Wrappers expostos a Blueprint (UI / mobile / automation). */
|
||||||
UFUNCTION(BlueprintCallable, Category = "Input")
|
UFUNCTION(BlueprintCallable, Category = "Input")
|
||||||
@@ -131,7 +155,7 @@ private:
|
|||||||
void TryRegisterLocalEntityFromCachedSpawn();
|
void TryRegisterLocalEntityFromCachedSpawn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memoriza `EntityId` autoritativo e regista o pawn no `UZMMOWorldSubsystem`
|
* Memoriza `EntityId` autoritativo e regista o pawn no `UZeusWorldSubsystem`
|
||||||
* para o registry partilhado por proxies remotos (filtra snapshots locais).
|
* para o registry partilhado por proxies remotos (filtra snapshots locais).
|
||||||
* Metadados publicos do char (Name/Guild) chegam via S_CHAR_INFO em
|
* Metadados publicos do char (Name/Guild) chegam via S_CHAR_INFO em
|
||||||
* HandleZeusCharInfo (servidor envia ANTES de S_SPAWN_PLAYER).
|
* HandleZeusCharInfo (servidor envia ANTES de S_SPAWN_PLAYER).
|
||||||
@@ -141,6 +165,11 @@ private:
|
|||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void HandleZeusPlayerSpawned(int64 InEntityId, bool bIsLocal, FVector PosCm, float YawDeg, int64 ServerTimeMs);
|
void HandleZeusPlayerSpawned(int64 InEntityId, bool bIsLocal, FVector PosCm, float YawDeg, int64 ServerTimeMs);
|
||||||
|
|
||||||
|
// Self-entity do sistema de rede novo (ENT_SELF): o cliente aprende o
|
||||||
|
// proprio entityId. Substitui o caminho legacy OnPlayerSpawned(bIsLocal=true).
|
||||||
|
UFUNCTION()
|
||||||
|
void HandleSelfEntityAssigned(int64 InEntityId);
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void HandleZeusCharInfo(int64 InEntityId, const FString& CharName, const FString& GuildName);
|
void HandleZeusCharInfo(int64 InEntityId, const FString& CharName, const FString& GuildName);
|
||||||
|
|
||||||
@@ -149,11 +178,19 @@ private:
|
|||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TObjectPtr<UZeusNetworkSubsystem> ZeusNetwork;
|
TObjectPtr<UZeusNetworkSubsystem> ZeusNetwork;
|
||||||
|
|
||||||
|
// Sistema de rede novo (canonico): fonte do self-entity (ENT_SELF).
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<UZeusNetworkingClientSubsystem> NetClient;
|
||||||
|
|
||||||
|
/** Instancia viva do painel admin (criada lazy no primeiro F8). */
|
||||||
|
UPROPERTY(Transient)
|
||||||
|
TObjectPtr<UUserWidget> AdminPanelInstance;
|
||||||
|
|
||||||
bool bSpawnDelegateBound = false;
|
bool bSpawnDelegateBound = false;
|
||||||
|
|
||||||
/** Identidade autoritativa atribuida quando o servidor envia S_SPAWN_PLAYER local. */
|
/** Identidade autoritativa atribuida quando o servidor envia S_SPAWN_PLAYER local. */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity", meta = (AllowPrivateAccess = "true"))
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity", meta = (AllowPrivateAccess = "true"))
|
||||||
int64 ZMMOEntityId = 0;
|
int64 ZeusEntityId = 0;
|
||||||
|
|
||||||
float PendingMoveForward = 0.0f;
|
float PendingMoveForward = 0.0f;
|
||||||
float PendingMoveRight = 0.0f;
|
float PendingMoveRight = 0.0f;
|
||||||
@@ -1,31 +1,31 @@
|
|||||||
#include "ZMMOEntity.h"
|
#include "ZeusEntity.h"
|
||||||
|
|
||||||
AZMMOEntity::AZMMOEntity()
|
AZeusEntity::AZeusEntity()
|
||||||
{
|
{
|
||||||
PrimaryActorTick.bCanEverTick = false;
|
PrimaryActorTick.bCanEverTick = false;
|
||||||
bReplicates = false;
|
bReplicates = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOEntity::SetZMMOIdentity(const int64 InEntityId, const EZMMOEntityType InEntityType)
|
void AZeusEntity::SetZeusIdentity(const int64 InEntityId, const EZeusEntityType InEntityType)
|
||||||
{
|
{
|
||||||
EntityId = InEntityId;
|
EntityId = InEntityId;
|
||||||
EntityType = InEntityType;
|
EntityType = InEntityType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOEntity::ApplyEntitySnapshot(const FZMMOEntitySnapshot& Snapshot)
|
void AZeusEntity::ApplyEntitySnapshot(const FZeusEntitySnapshot& Snapshot)
|
||||||
{
|
{
|
||||||
const FRotator NewRotation(0.0f, Snapshot.YawDeg, 0.0f);
|
const FRotator NewRotation(0.0f, Snapshot.YawDeg, 0.0f);
|
||||||
SetActorLocationAndRotation(Snapshot.PositionCm, NewRotation);
|
SetActorLocationAndRotation(Snapshot.PositionCm, NewRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOEntity::SetEntityRelevant(const bool bRelevant)
|
void AZeusEntity::SetEntityRelevant(const bool bRelevant)
|
||||||
{
|
{
|
||||||
if (bIsZMMORelevant == bRelevant)
|
if (bIsZeusRelevant == bRelevant)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bIsZMMORelevant = bRelevant;
|
bIsZeusRelevant = bRelevant;
|
||||||
SetActorHiddenInGame(!bRelevant);
|
SetActorHiddenInGame(!bRelevant);
|
||||||
SetActorEnableCollision(bRelevant);
|
SetActorEnableCollision(bRelevant);
|
||||||
SetActorTickEnabled(bRelevant);
|
SetActorTickEnabled(bRelevant);
|
||||||
@@ -2,22 +2,22 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GameFramework/Actor.h"
|
#include "GameFramework/Actor.h"
|
||||||
#include "ZMMOEntityInterface.h"
|
#include "ZeusEntityInterface.h"
|
||||||
#include "ZMMOEntityTypes.h"
|
#include "ZeusEntityTypes.h"
|
||||||
#include "ZMMOEntity.generated.h"
|
#include "ZeusEntity.generated.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AZMMOEntity
|
* AZeusEntity
|
||||||
*
|
*
|
||||||
* Classe base para entidades replicadas pelo servidor que NAO precisam de
|
* Classe base para entidades replicadas pelo servidor que NAO precisam de
|
||||||
* capsula + `UCharacterMovementComponent` — tipicamente NPCs estaticos,
|
* capsula + `UCharacterMovementComponent` — tipicamente NPCs estaticos,
|
||||||
* objetos dinamicos do mundo, mobs simples sem locomotion fisica.
|
* objetos dinamicos do mundo, mobs simples sem locomotion fisica.
|
||||||
*
|
*
|
||||||
* Para personagens com capsula + CMC (proxy de jogador, mobs com locomotion
|
* Para personagens com capsula + CMC (proxy de jogador, mobs com locomotion
|
||||||
* por capsula), use `AZMMOPlayerProxy` ou uma futura `AZMMOMob` que herde
|
* por capsula), use `AZeusPlayerProxy` ou uma futura `AZeusMob` que herde
|
||||||
* de `ACharacter`.
|
* de `ACharacter`.
|
||||||
*
|
*
|
||||||
* Implementa `IZMMOEntityInterface` com:
|
* Implementa `IZeusEntityInterface` com:
|
||||||
* - getters para `EntityId` / `EntityType`;
|
* - getters para `EntityId` / `EntityType`;
|
||||||
* - `ApplyEntitySnapshot` default: `SetActorLocationAndRotation` (sem
|
* - `ApplyEntitySnapshot` default: `SetActorLocationAndRotation` (sem
|
||||||
* interpolacao temporal — V1 podera adicionar ring-buffer + lerp);
|
* interpolacao temporal — V1 podera adicionar ring-buffer + lerp);
|
||||||
@@ -25,33 +25,33 @@
|
|||||||
* desativa tick (preserva o ator no mundo para futuro pooling).
|
* desativa tick (preserva o ator no mundo para futuro pooling).
|
||||||
*/
|
*/
|
||||||
UCLASS(Blueprintable, BlueprintType)
|
UCLASS(Blueprintable, BlueprintType)
|
||||||
class ZMMO_API AZMMOEntity : public AActor, public IZMMOEntityInterface
|
class ZMMO_API AZeusEntity : public AActor, public IZeusEntityInterface
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AZMMOEntity();
|
AZeusEntity();
|
||||||
|
|
||||||
// --- IZMMOEntityInterface ---
|
// --- IZeusEntityInterface ---
|
||||||
virtual int64 GetZMMOEntityId() const override { return EntityId; }
|
virtual int64 GetZeusEntityId() const override { return EntityId; }
|
||||||
virtual EZMMOEntityType GetZMMOEntityType() const override { return EntityType; }
|
virtual EZeusEntityType GetZeusEntityType() const override { return EntityType; }
|
||||||
virtual void ApplyEntitySnapshot(const FZMMOEntitySnapshot& Snapshot) override;
|
virtual void ApplyEntitySnapshot(const FZeusEntitySnapshot& Snapshot) override;
|
||||||
virtual void SetEntityRelevant(bool bRelevant) override;
|
virtual void SetEntityRelevant(bool bRelevant) override;
|
||||||
|
|
||||||
/** Setter usado pelo `UZMMOWorldSubsystem` apos o spawn para registrar a identidade. */
|
/** Setter usado pelo `UZeusWorldSubsystem` apos o spawn para registrar a identidade. */
|
||||||
UFUNCTION(BlueprintCallable, Category = "ZMMO|Entity")
|
UFUNCTION(BlueprintCallable, Category = "Zeus|Entity")
|
||||||
void SetZMMOIdentity(int64 InEntityId, EZMMOEntityType InEntityType);
|
void SetZeusIdentity(int64 InEntityId, EZeusEntityType InEntityType);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Identificador autoritativo do servidor. Atribuido em `SetZMMOIdentity`. */
|
/** Identificador autoritativo do servidor. Atribuido em `SetZeusIdentity`. */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
int64 EntityId = 0;
|
int64 EntityId = 0;
|
||||||
|
|
||||||
/** Categoria autoritativa (Player/Mob/NPC/Object). */
|
/** Categoria autoritativa (Player/Mob/NPC/Object). */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
EZMMOEntityType EntityType = EZMMOEntityType::Object;
|
EZeusEntityType EntityType = EZeusEntityType::Object;
|
||||||
|
|
||||||
/** Estado de relevancia atual (espelha as transicoes Hidden<->Relevant do servidor). */
|
/** Estado de relevancia atual (espelha as transicoes Hidden<->Relevant do servidor). */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
bool bIsZMMORelevant = true;
|
bool bIsZeusRelevant = true;
|
||||||
};
|
};
|
||||||
@@ -2,27 +2,27 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "UObject/Interface.h"
|
#include "UObject/Interface.h"
|
||||||
#include "ZMMOEntityTypes.h"
|
#include "ZeusEntityTypes.h"
|
||||||
#include "ZMMOEntityInterface.generated.h"
|
#include "ZeusEntityInterface.generated.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UZMMOEntityInterface
|
* UZeusEntityInterface
|
||||||
*
|
*
|
||||||
* Marcador `UInterface` necessario para o sistema de reflexao da Unreal. Todo o
|
* Marcador `UInterface` necessario para o sistema de reflexao da Unreal. Todo o
|
||||||
* contrato vive em `IZMMOEntityInterface` (puro C++).
|
* contrato vive em `IZeusEntityInterface` (puro C++).
|
||||||
*/
|
*/
|
||||||
UINTERFACE(BlueprintType, MinimalAPI, meta = (CannotImplementInterfaceInBlueprint))
|
UINTERFACE(BlueprintType, MinimalAPI, meta = (CannotImplementInterfaceInBlueprint))
|
||||||
class UZMMOEntityInterface : public UInterface
|
class UZeusEntityInterface : public UInterface
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IZMMOEntityInterface
|
* IZeusEntityInterface
|
||||||
*
|
*
|
||||||
* Contrato comum de todas as entidades replicadas pelo Zeus Server (player
|
* Contrato comum de todas as entidades replicadas pelo Zeus Server (player
|
||||||
* local, players remotos, mobs, NPCs, objetos). Inspirado em `IZeusEntityInterface`
|
* local, players remotos, mobs, NPCs, objetos). Adaptado para o nosso modelo
|
||||||
* (ZeusV1) e adaptado para o nosso modelo "cliente solto + servidor valida input".
|
* "cliente solto + servidor valida input".
|
||||||
*
|
*
|
||||||
* Decisoes:
|
* Decisoes:
|
||||||
* 1. **Identidade autoritativa**: `EntityId` e `EntityType` vem do servidor; o
|
* 1. **Identidade autoritativa**: `EntityId` e `EntityType` vem do servidor; o
|
||||||
@@ -30,28 +30,28 @@ class UZMMOEntityInterface : public UInterface
|
|||||||
* 2. **Visibilidade gated por AOI**: o servidor envia spawn/despawn quando o
|
* 2. **Visibilidade gated por AOI**: o servidor envia spawn/despawn quando o
|
||||||
* target entra/sai da area de interesse. O cliente reage via
|
* target entra/sai da area de interesse. O cliente reage via
|
||||||
* `SetEntityRelevant(bool)`.
|
* `SetEntityRelevant(bool)`.
|
||||||
* 3. **Player local nao reconcilia em V0**: para o `AZMMOPlayerCharacter` o
|
* 3. **Player local nao reconcilia em V0**: para o `AZeusCharacter` o
|
||||||
* `ApplyEntitySnapshot` e no-op (cliente solto controla landscape). Quando
|
* `ApplyEntitySnapshot` e no-op (cliente solto controla landscape). Quando
|
||||||
* a colisao de objetos chegar no servidor podemos ligar reconciliacao
|
* a colisao de objetos chegar no servidor podemos ligar reconciliacao
|
||||||
* horizontal opcional.
|
* horizontal opcional.
|
||||||
*
|
*
|
||||||
* Por que UInterface (e nao heranca classica)?
|
* Por que UInterface (e nao heranca classica)?
|
||||||
* - `AZMMOPlayerCharacter` ja herda de `ACharacter`. Forcar uma classe base
|
* - `AZeusCharacter` ja herda de `ACharacter`. Forcar uma classe base
|
||||||
* `AZMMOEntity : AActor` para todos perderia o `ACharacter` gratuito.
|
* `AZeusEntity : AActor` para todos perderia o `ACharacter` gratuito.
|
||||||
* A interface permite que o player local (`ACharacter`), o proxy remoto
|
* A interface permite que o player local (`ACharacter`), o proxy remoto
|
||||||
* (`ACharacter`) e entidades genericas (`AActor`) implementem o mesmo
|
* (`ACharacter`) e entidades genericas (`AActor`) implementem o mesmo
|
||||||
* contrato sem heranca multipla concreta.
|
* contrato sem heranca multipla concreta.
|
||||||
*/
|
*/
|
||||||
class ZMMO_API IZMMOEntityInterface
|
class ZMMO_API IZeusEntityInterface
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Identificador autoritativo da entidade no servidor. */
|
/** Identificador autoritativo da entidade no servidor. */
|
||||||
virtual int64 GetZMMOEntityId() const = 0;
|
virtual int64 GetZeusEntityId() const = 0;
|
||||||
|
|
||||||
/** Categoria da entidade (Player, Mob, NPC, Object). */
|
/** Categoria da entidade (Player, Mob, NPC, Object). */
|
||||||
virtual EZMMOEntityType GetZMMOEntityType() const = 0;
|
virtual EZeusEntityType GetZeusEntityType() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aplica um snapshot autoritativo. Implementacoes podem extender com
|
* Aplica um snapshot autoritativo. Implementacoes podem extender com
|
||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
* fisica do landscape de forma autoritativa local, e o servidor apenas
|
* fisica do landscape de forma autoritativa local, e o servidor apenas
|
||||||
* valida input/velocidade (ADR 0038).
|
* valida input/velocidade (ADR 0038).
|
||||||
*/
|
*/
|
||||||
virtual void ApplyEntitySnapshot(const FZMMOEntitySnapshot& Snapshot) = 0;
|
virtual void ApplyEntitySnapshot(const FZeusEntitySnapshot& Snapshot) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alterna entre estado visivel/ativo (`true`) e oculto/desativado (`false`).
|
* Alterna entre estado visivel/ativo (`true`) e oculto/desativado (`false`).
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "ZMMOEntityTypes.generated.h"
|
#include "ZeusEntityTypes.generated.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Categoria autoritativa replicada pelo servidor. Determina que classe de ator
|
* Categoria autoritativa replicada pelo servidor. Determina que classe de ator
|
||||||
* o `UZMMOWorldSubsystem` deve spawnar para um snapshot recebido.
|
* o `UZeusWorldSubsystem` deve spawnar para um snapshot recebido.
|
||||||
*/
|
*/
|
||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class EZMMOEntityType : uint8
|
enum class EZeusEntityType : uint8
|
||||||
{
|
{
|
||||||
Player UMETA(DisplayName = "Player"),
|
Player UMETA(DisplayName = "Player"),
|
||||||
Mob UMETA(DisplayName = "Mob"),
|
Mob UMETA(DisplayName = "Mob"),
|
||||||
@@ -17,48 +17,48 @@ enum class EZMMOEntityType : uint8
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Snapshot autoritativo aplicado por `IZMMOEntityInterface::ApplyEntitySnapshot`.
|
* Snapshot autoritativo aplicado por `IZeusEntityInterface::ApplyEntitySnapshot`.
|
||||||
*
|
*
|
||||||
* Construido pelo `UZMMOWorldSubsystem` a partir dos delegates do
|
* Construido pelo `UZeusWorldSubsystem` a partir dos delegates do
|
||||||
* `UZeusNetworkSubsystem` (`OnPlayerStateUpdate` em V0; opcodes para mobs/NPCs
|
* `UZeusNetworkSubsystem` (`OnPlayerStateUpdate` em V0; opcodes para mobs/NPCs
|
||||||
* em V1+). Mantemos os campos minimos que o servidor ja replica hoje
|
* em V1+). Mantemos os campos minimos que o servidor ja replica hoje
|
||||||
* (`S_PLAYER_STATE`); novos campos sao adicionados aqui sempre que o protocolo
|
* (`S_PLAYER_STATE`); novos campos sao adicionados aqui sempre que o protocolo
|
||||||
* evoluir, sem mexer nas classes de proxy.
|
* evoluir, sem mexer nas classes de proxy.
|
||||||
*/
|
*/
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct FZMMOEntitySnapshot
|
struct FZeusEntitySnapshot
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
/** EntityId autoritativo do servidor. */
|
/** EntityId autoritativo do servidor. */
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
int64 EntityId = 0;
|
int64 EntityId = 0;
|
||||||
|
|
||||||
/** Categoria do ator (define qual proxy class spawnar). */
|
/** Categoria do ator (define qual proxy class spawnar). */
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
EZMMOEntityType EntityType = EZMMOEntityType::Player;
|
EZeusEntityType EntityType = EZeusEntityType::Player;
|
||||||
|
|
||||||
/** Sequencia de input processada no servidor (so faz sentido para players). */
|
/** Sequencia de input processada no servidor (so faz sentido para players). */
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
int32 LastProcessedInputSeq = 0;
|
int32 LastProcessedInputSeq = 0;
|
||||||
|
|
||||||
/** Posicao mundo (cm). */
|
/** Posicao mundo (cm). */
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
FVector PositionCm = FVector::ZeroVector;
|
FVector PositionCm = FVector::ZeroVector;
|
||||||
|
|
||||||
/** Velocidade mundo (cm/s) — usada para network smoothing e drivers de animacao. */
|
/** Velocidade mundo (cm/s) — usada para network smoothing e drivers de animacao. */
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
FVector VelocityCmS = FVector::ZeroVector;
|
FVector VelocityCmS = FVector::ZeroVector;
|
||||||
|
|
||||||
/** Yaw em graus (orientacao visual). */
|
/** Yaw em graus (orientacao visual). */
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
float YawDeg = 0.0f;
|
float YawDeg = 0.0f;
|
||||||
|
|
||||||
/** Indica se o servidor considera o ator em solo. */
|
/** Indica se o servidor considera o ator em solo. */
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
bool bGrounded = false;
|
bool bGrounded = false;
|
||||||
|
|
||||||
/** Tempo do servidor (ms desde epoch) quando este snapshot foi gerado. */
|
/** Tempo do servidor (ms desde epoch) quando este snapshot foi gerado. */
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
int64 ServerTimeMs = 0;
|
int64 ServerTimeMs = 0;
|
||||||
};
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "ZMMOPlayerProxy.h"
|
#include "ZeusPlayerProxy.h"
|
||||||
|
|
||||||
#include "Animation/AnimInstance.h"
|
#include "Animation/AnimInstance.h"
|
||||||
#include "Components/CapsuleComponent.h"
|
#include "Components/CapsuleComponent.h"
|
||||||
@@ -8,10 +8,10 @@
|
|||||||
#include "GameFramework/CharacterMovementComponent.h"
|
#include "GameFramework/CharacterMovementComponent.h"
|
||||||
#include "UObject/ConstructorHelpers.h"
|
#include "UObject/ConstructorHelpers.h"
|
||||||
#include "ZMMO.h"
|
#include "ZMMO.h"
|
||||||
#include "ZMMOProxyMovementComponent.h"
|
#include "ZeusProxyMovementComponent.h"
|
||||||
|
|
||||||
AZMMOPlayerProxy::AZMMOPlayerProxy(const FObjectInitializer& ObjectInitializer)
|
AZeusPlayerProxy::AZeusPlayerProxy(const FObjectInitializer& ObjectInitializer)
|
||||||
: Super(ObjectInitializer.SetDefaultSubobjectClass<UZMMOProxyMovementComponent>(ACharacter::CharacterMovementComponentName))
|
: Super(ObjectInitializer.SetDefaultSubobjectClass<UZeusProxyMovementComponent>(ACharacter::CharacterMovementComponentName))
|
||||||
{
|
{
|
||||||
PrimaryActorTick.bCanEverTick = true;
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
PrimaryActorTick.bStartWithTickEnabled = true;
|
PrimaryActorTick.bStartWithTickEnabled = true;
|
||||||
@@ -43,7 +43,7 @@ AZMMOPlayerProxy::AZMMOPlayerProxy(const FObjectInitializer& ObjectInitializer)
|
|||||||
CMC->BrakingFrictionFactor = 0.0f;
|
CMC->BrakingFrictionFactor = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaults visuais (mesh + AnimBP) em paridade com `AZMMOPlayerCharacter`.
|
// Defaults visuais (mesh + AnimBP) em paridade com `AZeusCharacter`.
|
||||||
if (USkeletalMeshComponent* MeshComponent = GetMesh())
|
if (USkeletalMeshComponent* MeshComponent = GetMesh())
|
||||||
{
|
{
|
||||||
static ConstructorHelpers::FObjectFinder<USkeletalMesh> QuinnMesh(
|
static ConstructorHelpers::FObjectFinder<USkeletalMesh> QuinnMesh(
|
||||||
@@ -60,7 +60,7 @@ AZMMOPlayerProxy::AZMMOPlayerProxy(const FObjectInitializer& ObjectInitializer)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
UE_LOG(LogZMMO, Warning,
|
UE_LOG(LogZMMO, Warning,
|
||||||
TEXT("AZMMOPlayerProxy: SKM_Quinn_Simple nao encontrado em /Game/Characters/Mannequins/Meshes."));
|
TEXT("AZeusPlayerProxy: SKM_Quinn_Simple nao encontrado em /Game/Characters/Mannequins/Meshes."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (QuinnAnimBp.Succeeded())
|
if (QuinnAnimBp.Succeeded())
|
||||||
@@ -71,7 +71,7 @@ AZMMOPlayerProxy::AZMMOPlayerProxy(const FObjectInitializer& ObjectInitializer)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
UE_LOG(LogZMMO, Warning,
|
UE_LOG(LogZMMO, Warning,
|
||||||
TEXT("AZMMOPlayerProxy: ABP_Unarmed nao encontrado em /Game/Characters/Mannequins/Anims/Unarmed."));
|
TEXT("AZeusPlayerProxy: ABP_Unarmed nao encontrado em /Game/Characters/Mannequins/Anims/Unarmed."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ AZMMOPlayerProxy::AZMMOPlayerProxy(const FObjectInitializer& ObjectInitializer)
|
|||||||
bUseControllerRotationRoll = false;
|
bUseControllerRotationRoll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerProxy::BeginPlay()
|
void AZeusPlayerProxy::BeginPlay()
|
||||||
{
|
{
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ void AZMMOPlayerProxy::BeginPlay()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerProxy::Tick(const float DeltaSeconds)
|
void AZeusPlayerProxy::Tick(const float DeltaSeconds)
|
||||||
{
|
{
|
||||||
Super::Tick(DeltaSeconds);
|
Super::Tick(DeltaSeconds);
|
||||||
|
|
||||||
@@ -131,18 +131,25 @@ void AZMMOPlayerProxy::Tick(const float DeltaSeconds)
|
|||||||
// Sem snapshot futuro: extrapolacao curta com a ultima velocidade
|
// Sem snapshot futuro: extrapolacao curta com a ultima velocidade
|
||||||
// conhecida, clampada por `MaxExtrapolationSeconds` para nao deixar
|
// conhecida, clampada por `MaxExtrapolationSeconds` para nao deixar
|
||||||
// o proxy fugir se a rede ficar muda.
|
// o proxy fugir se a rede ficar muda.
|
||||||
const FZMMOProxySnapshot& Last = SnapshotBuffer.Last();
|
const FZeusProxySnapshot& Last = SnapshotBuffer.Last();
|
||||||
const float ExtrapSec = FMath::Clamp(
|
const float RawExtrapSec =
|
||||||
static_cast<float>(RenderMs - Last.ServerTimeMs) / 1000.0f,
|
static_cast<float>(RenderMs - Last.ServerTimeMs) / 1000.0f;
|
||||||
0.0f, MaxExtrapolationSeconds);
|
const float ExtrapSec = FMath::Clamp(RawExtrapSec, 0.0f, MaxExtrapolationSeconds);
|
||||||
NewPos = Last.PosCm + Last.VelCmS * ExtrapSec;
|
NewPos = Last.PosCm + Last.VelCmS * ExtrapSec;
|
||||||
NewVel = Last.VelCmS;
|
// STARVATION (buffer=1 por muito tempo -- ex: 1o login sem DELTA_BATCH por
|
||||||
|
// segundos): a extrapolacao satura no clamp e a POSE congela, mas manter a
|
||||||
|
// velocidade faz o AnimBP rodar locomocao PARADO ("andar no lugar"/moonwalk
|
||||||
|
// = o "jitter" reportado). Se ja passamos bem do clamp, zera a vel visual
|
||||||
|
// pra o proxy ir pra Idle ate' os deltas voltarem (em vez de animar
|
||||||
|
// andando travado). Quando os deltas chegam, o ramo de interpolacao retoma.
|
||||||
|
const bool bStarved = RawExtrapSec > (MaxExtrapolationSeconds + 0.15f);
|
||||||
|
NewVel = bStarved ? FVector::ZeroVector : Last.VelCmS;
|
||||||
bExtrapolating = ExtrapSec > KINDA_SMALL_NUMBER;
|
bExtrapolating = ExtrapSec > KINDA_SMALL_NUMBER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const FZMMOProxySnapshot& A = SnapshotBuffer[IdxB - 1];
|
const FZeusProxySnapshot& A = SnapshotBuffer[IdxB - 1];
|
||||||
const FZMMOProxySnapshot& B = SnapshotBuffer[IdxB];
|
const FZeusProxySnapshot& B = SnapshotBuffer[IdxB];
|
||||||
const double Span = FMath::Max<double>(1.0, static_cast<double>(B.ServerTimeMs - A.ServerTimeMs));
|
const double Span = FMath::Max<double>(1.0, static_cast<double>(B.ServerTimeMs - A.ServerTimeMs));
|
||||||
InterpAlpha = static_cast<float>(FMath::Clamp(
|
InterpAlpha = static_cast<float>(FMath::Clamp(
|
||||||
static_cast<double>(RenderMs - A.ServerTimeMs) / Span, 0.0, 1.0));
|
static_cast<double>(RenderMs - A.ServerTimeMs) / Span, 0.0, 1.0));
|
||||||
@@ -150,12 +157,32 @@ void AZMMOPlayerProxy::Tick(const float DeltaSeconds)
|
|||||||
NewVel = FMath::Lerp(A.VelCmS, B.VelCmS, InterpAlpha);
|
NewVel = FMath::Lerp(A.VelCmS, B.VelCmS, InterpAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yaw deriva da velocidade interpolada: locomotion mantem face na direcao
|
// ORIENTACAO DO CORPO = REPLICA do yaw autoritativo do servidor (Snapshot.YawDeg),
|
||||||
// do movimento; em idle preserva o yaw atual para nao "snappar".
|
// interpolado shortest-path entre os MESMOS A/B da posicao. Esse yaw agora carrega
|
||||||
|
// o yaw do CORPO do dono (orient-to-movement do CMC: vira pra direcao do MOVIMENTO
|
||||||
|
// /WASD, suave a 500 deg/s; parado mantem; o MOUSE nao gira o corpo) -- o cliente
|
||||||
|
// dono manda GetActorRotation().Yaw e o servidor repassa direto. Por isso o proxy
|
||||||
|
// so' REPLICA: vira identico ao corpo do dono, sem re-derivar nada.
|
||||||
|
//
|
||||||
|
// NAO derivamos de Atan2(velocidade): isso era a fonte do bug 2026-06-13 ("virava
|
||||||
|
// demais 45 graus") -- a direcao da velocidade salta, o yaw do corpo nao. A
|
||||||
|
// suavizacao correta ja' aconteceu no CMC do dono; aqui so' interpolamos amostras.
|
||||||
|
//
|
||||||
|
// FUTURO -- Motion Matching/aim: quando "a mira dita a locomocao" (strafe/aim
|
||||||
|
// offset), o servidor passara a mandar um aimYawDeg separado e o AnimBP usara a
|
||||||
|
// velocidade relativa a este yaw pra escolher fwd/back/left/right. Por ORA, 1 yaw.
|
||||||
FRotator NewRot = GetActorRotation();
|
FRotator NewRot = GetActorRotation();
|
||||||
if (FVector(NewVel.X, NewVel.Y, 0.0f).SizeSquared() > 1.0f)
|
if (IdxB == INDEX_NONE)
|
||||||
{
|
{
|
||||||
NewRot.Yaw = FMath::RadiansToDegrees(FMath::Atan2(NewVel.Y, NewVel.X));
|
NewRot.Yaw = SnapshotBuffer.Last().YawDeg; // extrapolando: segura o ultimo yaw
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const float YawA = SnapshotBuffer[IdxB - 1].YawDeg;
|
||||||
|
const float YawB = SnapshotBuffer[IdxB].YawDeg;
|
||||||
|
// FindDeltaAngleDegrees -> menor arco (-180..180); evita girar "o lado longo".
|
||||||
|
const float DeltaYaw = FMath::FindDeltaAngleDegrees(YawA, YawB);
|
||||||
|
NewRot.Yaw = YawA + DeltaYaw * InterpAlpha;
|
||||||
}
|
}
|
||||||
NewRot.Pitch = 0.0f;
|
NewRot.Pitch = 0.0f;
|
||||||
NewRot.Roll = 0.0f;
|
NewRot.Roll = 0.0f;
|
||||||
@@ -207,33 +234,96 @@ void AZMMOPlayerProxy::Tick(const float DeltaSeconds)
|
|||||||
LastDiagLogSec = NowSec;
|
LastDiagLogSec = NowSec;
|
||||||
const int64 NewestMs = SnapshotBuffer.Last().ServerTimeMs;
|
const int64 NewestMs = SnapshotBuffer.Last().ServerTimeMs;
|
||||||
const int64 RenderLagMs = ServerNowMs - NewestMs;
|
const int64 RenderLagMs = ServerNowMs - NewestMs;
|
||||||
UE_LOG(LogZMMO, Verbose,
|
// === DIAG PERMANENTE -- jitter por FOME DE DELTAS ========================
|
||||||
TEXT("ZMMOPlayerProxy[%lld] buffer=%d renderLagMs=%lld interpAlpha=%.2f extrap=%d delayMs=%.0f"),
|
// Bug investigado/resolvido 2026-06-13 (ver memoria
|
||||||
EntityId, SnapshotBuffer.Num(), RenderLagMs, InterpAlpha,
|
// project_proxy_delta_starvation_jitter). Este Warning FICA DE PROPOSITO
|
||||||
bExtrapolating ? 1 : 0, InterpolationDelayMs);
|
// (decisao do dono: NAO rebaixar p/ Verbose nem remover) -- e' a sonda pra
|
||||||
|
// cacar regressao do jitter de proxy. Como ler:
|
||||||
|
// secsSinceSnap = ha quanto tempo o proxy NAO recebe snapshot. Sobe = FOME
|
||||||
|
// (player remoto parado -> ComputeDelta suprime no server -> sem DELTA_BATCH).
|
||||||
|
// newestMs = serverTimeMs do ultimo snapshot; CONGELA na fome (deveria avancar).
|
||||||
|
// renderLagMs = ServerNowMs - newestMs; cresce 1:1 com o wall-clock na fome.
|
||||||
|
// speed=0 na fome = a mitigacao (zera a vel visual -> Idle, sem "moonwalk") agindo.
|
||||||
|
// Ao o player voltar a se mover sai "buffer STALE ... reset+reseed" (anti-stale)
|
||||||
|
// e renderLagMs/secsSinceSnap voltam a ~0 (snap limpo, sem salto/jitter).
|
||||||
|
// =========================================================================
|
||||||
|
const double SecsSinceSnap =
|
||||||
|
(LastSnapshotRecvSec > 0.0) ? (NowSec - LastSnapshotRecvSec) : -1.0;
|
||||||
|
UE_LOG(LogZMMO, Warning,
|
||||||
|
TEXT("ZeusPlayerProxy[%lld] buffer=%d renderLagMs=%lld newestMs=%lld secsSinceSnap=%.1f interpAlpha=%.2f extrap=%d speed=%.0f"),
|
||||||
|
EntityId, SnapshotBuffer.Num(), RenderLagMs, NewestMs, SecsSinceSnap, InterpAlpha,
|
||||||
|
bExtrapolating ? 1 : 0,
|
||||||
|
FVector(VisualVelocity.X, VisualVelocity.Y, 0.0f).Size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerProxy::SetZMMOIdentity(const int64 InEntityId, const EZMMOEntityType InEntityType)
|
void AZeusPlayerProxy::SetZeusIdentity(const int64 InEntityId, const EZeusEntityType InEntityType)
|
||||||
{
|
{
|
||||||
EntityId = InEntityId;
|
EntityId = InEntityId;
|
||||||
EntityType = InEntityType;
|
EntityType = InEntityType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerProxy::ApplyEntitySnapshot(const FZMMOEntitySnapshot& Snapshot)
|
void AZeusPlayerProxy::ApplyEntitySnapshot(const FZeusEntitySnapshot& Snapshot)
|
||||||
{
|
{
|
||||||
// Estabiliza o offset de relogio na primeira amostra. Subsequente nao
|
LastSnapshotRecvSec = FPlatformTime::Seconds(); // DIAG: marca chegada (mede a fome no Tick)
|
||||||
// re-sincroniza para evitar saltos visuais; um esquema mais sofisticado
|
|
||||||
// (ema do offset) cabe quando tivermos ping/RTT estabilizado por sessao.
|
// 2026-06-06 H3 fix — disciplina o ServerClockOffsetMs via EMA com clamp.
|
||||||
if (SnapshotBuffer.Num() == 0)
|
// Antes: offset congelado na 1a amostra. Em cross-server handoff a fonte
|
||||||
{
|
// do ServerTimeMs muda (publisher antigo -> novo) e o offset fica
|
||||||
|
// permanentemente skewed, alimentando tremor pos-handoff e drift cumulativo
|
||||||
|
// de clock cliente vs server. Agora cada amostra recalcula candidato e
|
||||||
|
// suaviza (alpha=0.02, ~50 amostras pra convergir) com clamp max 2ms/snapshot
|
||||||
|
// pra evitar salto visual durante transicao.
|
||||||
const int64 LocalNowMs = static_cast<int64>(FPlatformTime::Seconds() * 1000.0);
|
const int64 LocalNowMs = static_cast<int64>(FPlatformTime::Seconds() * 1000.0);
|
||||||
ServerClockOffsetMs = LocalNowMs - Snapshot.ServerTimeMs;
|
const int64 OffsetCandidate = LocalNowMs - Snapshot.ServerTimeMs;
|
||||||
|
|
||||||
|
// Anti-stale (2026-06-13): se este snapshot esta MUITO a frente do mais novo
|
||||||
|
// do buffer, o proxy ficou "mudo" por segundos -- player remoto parado ->
|
||||||
|
// ComputeDelta suprime -> sem DELTA_BATCH novo -> renderLagMs disparou pra
|
||||||
|
// dezenas de segundos. Manter os snapshots velhos faz a interpolacao usar um
|
||||||
|
// span gigante (pose de ~100s atras -> agora) quando o player volta a se mover,
|
||||||
|
// causando rasteio/salto (o jitter reportado). Descarta o buffer obsoleto +
|
||||||
|
// re-bootstrapa o relogio pra a interpolacao recomecar limpa neste keyframe.
|
||||||
|
if (SnapshotBuffer.Num() > 0
|
||||||
|
&& (Snapshot.ServerTimeMs - SnapshotBuffer.Last().ServerTimeMs) > 1000)
|
||||||
|
{
|
||||||
|
UE_LOG(LogZMMO, Warning,
|
||||||
|
TEXT("ZeusPlayerProxy[%lld] buffer STALE gap=%lldms -> reset+reseed"),
|
||||||
|
EntityId, Snapshot.ServerTimeMs - SnapshotBuffer.Last().ServerTimeMs);
|
||||||
|
SnapshotBuffer.Reset();
|
||||||
|
ServerClockOffsetMs = OffsetCandidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
FZMMOProxySnapshot S;
|
if (SnapshotBuffer.Num() == 0)
|
||||||
|
{
|
||||||
|
// Primeira amostra: bootstrap direto (nao tem baseline pra suavizar).
|
||||||
|
ServerClockOffsetMs = OffsetCandidate;
|
||||||
|
// DIAG (jitter 1o login): confirma o seed do relogio. serverTimeMs deve ser
|
||||||
|
// != 0 e o offset razoavel; se vier 0 aqui, o keyframe/catch-up corrompeu o
|
||||||
|
// bootstrap (hipotese descartada, mas o log fecha a questao em campo).
|
||||||
|
UE_LOG(LogZMMO, Warning,
|
||||||
|
TEXT("ZeusPlayerProxy[%lld] SEED clock serverTimeMs=%lld localNowMs=%lld offset=%lld"),
|
||||||
|
EntityId, Snapshot.ServerTimeMs, LocalNowMs, ServerClockOffsetMs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double Alpha = 0.02;
|
||||||
|
const int64 RawTarget = static_cast<int64>(
|
||||||
|
static_cast<double>(ServerClockOffsetMs) * (1.0 - Alpha)
|
||||||
|
+ static_cast<double>(OffsetCandidate) * Alpha);
|
||||||
|
// Clamp max 2ms por amostra — em 30Hz isso converge a 60ms/s, mais que
|
||||||
|
// o suficiente pra absorver drift normal sem causar tremor visual.
|
||||||
|
const int64 Delta = RawTarget - ServerClockOffsetMs;
|
||||||
|
const int64 ClampedDelta = (Delta > 2) ? 2
|
||||||
|
: (Delta < -2) ? -2
|
||||||
|
: Delta;
|
||||||
|
ServerClockOffsetMs += ClampedDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
FZeusProxySnapshot S;
|
||||||
S.PosCm = Snapshot.PositionCm;
|
S.PosCm = Snapshot.PositionCm;
|
||||||
S.VelCmS = Snapshot.VelocityCmS;
|
S.VelCmS = Snapshot.VelocityCmS;
|
||||||
|
S.YawDeg = Snapshot.YawDeg; // yaw do CORPO do dono (orient-to-movement; mouse nao gira)
|
||||||
S.bGrounded = Snapshot.bGrounded;
|
S.bGrounded = Snapshot.bGrounded;
|
||||||
S.ServerTimeMs = Snapshot.ServerTimeMs;
|
S.ServerTimeMs = Snapshot.ServerTimeMs;
|
||||||
|
|
||||||
@@ -282,20 +372,20 @@ void AZMMOPlayerProxy::ApplyEntitySnapshot(const FZMMOEntitySnapshot& Snapshot)
|
|||||||
ApplyCollisionPolicy();
|
ApplyCollisionPolicy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerProxy::SetEntityRelevant(const bool bRelevant)
|
void AZeusPlayerProxy::SetEntityRelevant(const bool bRelevant)
|
||||||
{
|
{
|
||||||
if (bIsZMMORelevant == bRelevant)
|
if (bIsZeusRelevant == bRelevant)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bIsZMMORelevant = bRelevant;
|
bIsZeusRelevant = bRelevant;
|
||||||
SetActorHiddenInGame(!bRelevant);
|
SetActorHiddenInGame(!bRelevant);
|
||||||
SetActorTickEnabled(bRelevant);
|
SetActorTickEnabled(bRelevant);
|
||||||
ApplyCollisionPolicy();
|
ApplyCollisionPolicy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerProxy::RefreshAnimationDrivers()
|
void AZeusPlayerProxy::RefreshAnimationDrivers()
|
||||||
{
|
{
|
||||||
UCharacterMovementComponent* CMC = GetCharacterMovement();
|
UCharacterMovementComponent* CMC = GetCharacterMovement();
|
||||||
if (!CMC)
|
if (!CMC)
|
||||||
@@ -314,13 +404,13 @@ void AZMMOPlayerProxy::RefreshAnimationDrivers()
|
|||||||
|
|
||||||
// Acceleration externa via CMC custom — alimenta `Get Current Acceleration`
|
// Acceleration externa via CMC custom — alimenta `Get Current Acceleration`
|
||||||
// que o AnimBP do Quinn usa em `ShouldMove` e nas transições de Jump_Start.
|
// que o AnimBP do Quinn usa em `ShouldMove` e nas transições de Jump_Start.
|
||||||
if (UZMMOProxyMovementComponent* ProxyCMC = Cast<UZMMOProxyMovementComponent>(CMC))
|
if (UZeusProxyMovementComponent* ProxyCMC = Cast<UZeusProxyMovementComponent>(CMC))
|
||||||
{
|
{
|
||||||
ProxyCMC->SetZMMOExternalAcceleration(LastDerivedAccelerationCmS2);
|
ProxyCMC->SetZeusExternalAcceleration(LastDerivedAccelerationCmS2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerProxy::ApplyCollisionPolicy()
|
void AZeusPlayerProxy::ApplyCollisionPolicy()
|
||||||
{
|
{
|
||||||
UCapsuleComponent* Capsule = GetCapsuleComponent();
|
UCapsuleComponent* Capsule = GetCapsuleComponent();
|
||||||
if (!Capsule)
|
if (!Capsule)
|
||||||
@@ -328,6 +418,6 @@ void AZMMOPlayerProxy::ApplyCollisionPolicy()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool bShouldCollide = bIsZMMORelevant && bHasFirstSnapshot;
|
const bool bShouldCollide = bIsZeusRelevant && bHasFirstSnapshot;
|
||||||
Capsule->SetCollisionEnabled(bShouldCollide ? ECollisionEnabled::QueryOnly : ECollisionEnabled::NoCollision);
|
Capsule->SetCollisionEnabled(bShouldCollide ? ECollisionEnabled::QueryOnly : ECollisionEnabled::NoCollision);
|
||||||
}
|
}
|
||||||
@@ -2,19 +2,18 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GameFramework/Character.h"
|
#include "GameFramework/Character.h"
|
||||||
#include "ZMMOEntityInterface.h"
|
#include "ZeusEntityInterface.h"
|
||||||
#include "ZMMOEntityTypes.h"
|
#include "ZeusEntityTypes.h"
|
||||||
#include "ZMMOPlayerProxy.generated.h"
|
#include "ZeusPlayerProxy.generated.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AZMMOPlayerProxy
|
* AZeusPlayerProxy
|
||||||
*
|
*
|
||||||
* Proxy visual para jogadores remotos (e, no futuro, mobs com locomotion
|
* Proxy visual para jogadores remotos (e, no futuro, mobs com locomotion
|
||||||
* por capsula) cuja posicao vem 100% do servidor via snapshots
|
* por capsula) cuja posicao vem 100% do servidor via snapshots
|
||||||
* (`UZeusNetworkSubsystem::OnPlayerStateUpdate`).
|
* (`UZeusNetworkSubsystem::OnPlayerStateUpdate`).
|
||||||
*
|
*
|
||||||
* Inspirado em `AZeusRemoteCharacter` (ZeusV1). Diferencas chave vs.
|
* Diferencas chave vs. `AZeusCharacter` (jogador local):
|
||||||
* `AZMMOPlayerCharacter` (jogador local):
|
|
||||||
* - SEM `EnhancedInput`, sem envio de `C_INPUT_AXIS`.
|
* - SEM `EnhancedInput`, sem envio de `C_INPUT_AXIS`.
|
||||||
* - SEM buffer de pending inputs nem reconciliacao.
|
* - SEM buffer de pending inputs nem reconciliacao.
|
||||||
* - Posicao aplicada por snapshot (`ApplyEntitySnapshot`); a `ACharacter`
|
* - Posicao aplicada por snapshot (`ApplyEntitySnapshot`); a `ACharacter`
|
||||||
@@ -22,19 +21,18 @@
|
|||||||
* mas o CMC fica em modo "kinematic-ish" (nao integra fisica).
|
* mas o CMC fica em modo "kinematic-ish" (nao integra fisica).
|
||||||
*
|
*
|
||||||
* Animacao no AnimBP do Quinn (`ABP_Unarmed`): a formula `ShouldMove` exige
|
* Animacao no AnimBP do Quinn (`ABP_Unarmed`): a formula `ShouldMove` exige
|
||||||
* `Acceleration != 0`. Como proxies nao tem input, adoptamos a mesma
|
* `Acceleration != 0`. Como proxies nao tem input, adoptamos a estrategia
|
||||||
* estrategia do ZClientMMO: CMC custom (`UZMMOProxyMovementComponent`) com
|
* de CMC custom (`UZeusProxyMovementComponent`) com escrita externa de
|
||||||
* escrita externa de `Acceleration`, alimentada pela derivada da velocidade
|
* `Acceleration`, alimentada pela derivada da velocidade entre snapshots.
|
||||||
* entre snapshots. Tick do proxy roda **antes** do mesh tick para que
|
* Tick do proxy roda **antes** do mesh tick para que Velocity+Acceleration
|
||||||
* Velocity+Acceleration estejam populados quando o `NativeUpdateAnimation`
|
* estejam populados quando o `NativeUpdateAnimation` do AnimBP os ler.
|
||||||
* do AnimBP os ler.
|
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Snapshot bruto guardado no buffer de interpolacao. Mantido como struct privada
|
* Snapshot bruto guardado no buffer de interpolacao. Mantido como struct privada
|
||||||
* ao .h porque so o proxy (e debugging local) precisa olhar para ele.
|
* ao .h porque so o proxy (e debugging local) precisa olhar para ele.
|
||||||
*/
|
*/
|
||||||
USTRUCT()
|
USTRUCT()
|
||||||
struct FZMMOProxySnapshot
|
struct FZeusProxySnapshot
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
@@ -44,6 +42,15 @@ struct FZMMOProxySnapshot
|
|||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
FVector VelCmS = FVector::ZeroVector;
|
FVector VelCmS = FVector::ZeroVector;
|
||||||
|
|
||||||
|
/** Yaw autoritativo do servidor (graus) = o MESMO yaw que o player LOCAL aplicou
|
||||||
|
* ao virar. O proxy replica EXATAMENTE a viradinha do local (apertou D = mesma
|
||||||
|
* virada nos dois). Sem armazenar isto, o proxy derivava o yaw da velocidade
|
||||||
|
* (Atan2) e "virava totalmente pra direcao do movimento" (bug 2026-06-13).
|
||||||
|
* NAO confundir com "mira dita a locomocao" (strafe / Motion Matching) -- isso
|
||||||
|
* esta' DESABILITADO por ora (ver AVISO em ZeusPlayerProxy.cpp::Tick). */
|
||||||
|
UPROPERTY()
|
||||||
|
float YawDeg = 0.0f;
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
bool bGrounded = true;
|
bool bGrounded = true;
|
||||||
|
|
||||||
@@ -53,37 +60,37 @@ struct FZMMOProxySnapshot
|
|||||||
};
|
};
|
||||||
|
|
||||||
UCLASS(Blueprintable, BlueprintType)
|
UCLASS(Blueprintable, BlueprintType)
|
||||||
class ZMMO_API AZMMOPlayerProxy : public ACharacter, public IZMMOEntityInterface
|
class ZMMO_API AZeusPlayerProxy : public ACharacter, public IZeusEntityInterface
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AZMMOPlayerProxy(const FObjectInitializer& ObjectInitializer);
|
AZeusPlayerProxy(const FObjectInitializer& ObjectInitializer);
|
||||||
|
|
||||||
virtual void BeginPlay() override;
|
virtual void BeginPlay() override;
|
||||||
virtual void Tick(float DeltaSeconds) override;
|
virtual void Tick(float DeltaSeconds) override;
|
||||||
|
|
||||||
// --- IZMMOEntityInterface ---
|
// --- IZeusEntityInterface ---
|
||||||
virtual int64 GetZMMOEntityId() const override { return EntityId; }
|
virtual int64 GetZeusEntityId() const override { return EntityId; }
|
||||||
virtual EZMMOEntityType GetZMMOEntityType() const override { return EntityType; }
|
virtual EZeusEntityType GetZeusEntityType() const override { return EntityType; }
|
||||||
virtual void ApplyEntitySnapshot(const FZMMOEntitySnapshot& Snapshot) override;
|
virtual void ApplyEntitySnapshot(const FZeusEntitySnapshot& Snapshot) override;
|
||||||
virtual void SetEntityRelevant(bool bRelevant) override;
|
virtual void SetEntityRelevant(bool bRelevant) override;
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "ZMMO|Entity")
|
UFUNCTION(BlueprintCallable, Category = "Zeus|Entity")
|
||||||
void SetZMMOIdentity(int64 InEntityId, EZMMOEntityType InEntityType);
|
void SetZeusIdentity(int64 InEntityId, EZeusEntityType InEntityType);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
int64 EntityId = 0;
|
int64 EntityId = 0;
|
||||||
|
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
EZMMOEntityType EntityType = EZMMOEntityType::Player;
|
EZeusEntityType EntityType = EZeusEntityType::Player;
|
||||||
|
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
bool bIsZMMORelevant = true;
|
bool bIsZeusRelevant = true;
|
||||||
|
|
||||||
/** True apos o primeiro snapshot ser aplicado — antes disso o ator pode ficar oculto. */
|
/** True apos o primeiro snapshot ser aplicado — antes disso o ator pode ficar oculto. */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
bool bHasFirstSnapshot = false;
|
bool bHasFirstSnapshot = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,15 +98,15 @@ protected:
|
|||||||
* de `InterpolatedPosCm` (visual) — separar os dois e essencial para
|
* de `InterpolatedPosCm` (visual) — separar os dois e essencial para
|
||||||
* comparar drift autoritativo vs visual via debug overlay/logs.
|
* comparar drift autoritativo vs visual via debug overlay/logs.
|
||||||
*/
|
*/
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
FVector AuthoritativePosCm = FVector::ZeroVector;
|
FVector AuthoritativePosCm = FVector::ZeroVector;
|
||||||
|
|
||||||
/** Posicao **visual** atual (resultado da interpolacao do tick). */
|
/** Posicao **visual** atual (resultado da interpolacao do tick). */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
FVector InterpolatedPosCm = FVector::ZeroVector;
|
FVector InterpolatedPosCm = FVector::ZeroVector;
|
||||||
|
|
||||||
/** Compat: alias para `AuthoritativePosCm` (preserva binding de Blueprint, se houver). */
|
/** Compat: alias para `AuthoritativePosCm` (preserva binding de Blueprint, se houver). */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
FVector LastSnapshotPosition = FVector::ZeroVector;
|
FVector LastSnapshotPosition = FVector::ZeroVector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,7 +115,7 @@ protected:
|
|||||||
* em cada `Tick` para manter os drivers de animacao alimentados entre
|
* em cada `Tick` para manter os drivers de animacao alimentados entre
|
||||||
* updates de rede.
|
* updates de rede.
|
||||||
*/
|
*/
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Entity")
|
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Zeus|Entity")
|
||||||
FVector VisualVelocity = FVector::ZeroVector;
|
FVector VisualVelocity = FVector::ZeroVector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,23 +123,23 @@ protected:
|
|||||||
* expresso no dominio do tempo do servidor. Padrao 100 ms (~3 snapshots a 30 Hz)
|
* expresso no dominio do tempo do servidor. Padrao 100 ms (~3 snapshots a 30 Hz)
|
||||||
* cobre 1 perda + 1 jitter sem extrapolar.
|
* cobre 1 perda + 1 jitter sem extrapolar.
|
||||||
*/
|
*/
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ZMMO|Network",
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|Network",
|
||||||
meta = (ClampMin = "0.0", ClampMax = "500.0"))
|
meta = (ClampMin = "0.0", ClampMax = "500.0"))
|
||||||
double InterpolationDelayMs = 100.0;
|
double InterpolationDelayMs = 100.0;
|
||||||
|
|
||||||
/** Tamanho maximo do buffer (em snapshots). Cobre ~270 ms a 30 Hz. */
|
/** Tamanho maximo do buffer (em snapshots). Cobre ~270 ms a 30 Hz. */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ZMMO|Network",
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|Network",
|
||||||
meta = (ClampMin = "2", ClampMax = "32"))
|
meta = (ClampMin = "2", ClampMax = "32"))
|
||||||
int32 SnapshotBufferCapacity = 8;
|
int32 SnapshotBufferCapacity = 8;
|
||||||
|
|
||||||
/** Limite duro de extrapolacao (s) quando nao ha snapshot futuro. */
|
/** Limite duro de extrapolacao (s) quando nao ha snapshot futuro. */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ZMMO|Network",
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|Network",
|
||||||
meta = (ClampMin = "0.0", ClampMax = "0.5"))
|
meta = (ClampMin = "0.0", ClampMax = "0.5"))
|
||||||
float MaxExtrapolationSeconds = 0.1f;
|
float MaxExtrapolationSeconds = 0.1f;
|
||||||
|
|
||||||
/** Buffer ordenado por `ServerTimeMs` ascendente. */
|
/** Buffer ordenado por `ServerTimeMs` ascendente. */
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TArray<FZMMOProxySnapshot> SnapshotBuffer;
|
TArray<FZeusProxySnapshot> SnapshotBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Offset entre o relogio local (`FPlatformTime::Seconds * 1000`) e o
|
* Offset entre o relogio local (`FPlatformTime::Seconds * 1000`) e o
|
||||||
@@ -142,6 +149,12 @@ protected:
|
|||||||
*/
|
*/
|
||||||
int64 ServerClockOffsetMs = 0;
|
int64 ServerClockOffsetMs = 0;
|
||||||
|
|
||||||
|
/** DIAG (2026-06-13): instante (s, monotonic) do ultimo snapshot recebido em
|
||||||
|
* ApplyEntitySnapshot. Usado no log do Tick pra medir "secsSinceSnap" = quanto
|
||||||
|
* tempo o proxy ficou MUDO (sem delta). secsSinceSnap grande == fome (player
|
||||||
|
* remoto parado -> ComputeDelta suprime). 0 = nenhum snapshot ainda. */
|
||||||
|
double LastSnapshotRecvSec = 0.0;
|
||||||
|
|
||||||
/** Aceleracao derivada (com smoothing) escrita no CMC custom para alimentar
|
/** Aceleracao derivada (com smoothing) escrita no CMC custom para alimentar
|
||||||
* o AnimBP (`ShouldMove`/`Jump_Start` exigem Acceleration!=0). */
|
* o AnimBP (`ShouldMove`/`Jump_Start` exigem Acceleration!=0). */
|
||||||
FVector LastDerivedAccelerationCmS2 = FVector::ZeroVector;
|
FVector LastDerivedAccelerationCmS2 = FVector::ZeroVector;
|
||||||
24
Source/ZMMO/Game/Entity/ZeusProxyMovementComponent.h
Normal file
24
Source/ZMMO/Game/Entity/ZeusProxyMovementComponent.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFramework/CharacterMovementComponent.h"
|
||||||
|
|
||||||
|
#include "ZeusProxyMovementComponent.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CMC customizado para AZeusPlayerProxy. Expõe escrita direta de Acceleration
|
||||||
|
* (protected na base) para que o AnimBP veja Acceleration!=0 quando o proxy
|
||||||
|
* recebe snapshots, alimentando a fórmula ShouldMove e a transição Jump_Start
|
||||||
|
* do ABP_Unarmed (ambas dependem de aceleração não-nula).
|
||||||
|
*/
|
||||||
|
UCLASS(ClassGroup = (Zeus), meta = (BlueprintSpawnableComponent))
|
||||||
|
class ZMMO_API UZeusProxyMovementComponent : public UCharacterMovementComponent
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
void SetZeusExternalAcceleration(const FVector& InAccelerationCmS2)
|
||||||
|
{
|
||||||
|
Acceleration = InAccelerationCmS2;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include "ZMMOFrontEndGameMode.h"
|
|
||||||
|
|
||||||
#include "ZMMOFrontEndPlayerController.h"
|
|
||||||
|
|
||||||
AZMMOFrontEndGameMode::AZMMOFrontEndGameMode()
|
|
||||||
{
|
|
||||||
// UI pura: sem pawn. O controller cria o root layout e arranca o fluxo.
|
|
||||||
DefaultPawnClass = nullptr;
|
|
||||||
PlayerControllerClass = AZMMOFrontEndPlayerController::StaticClass();
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user