protected override void ClientUpdate(ClientUpdateData data) { var character = data.GameObject; var clientState = data.ClientState; var publicState = data.PublicState; if (!character.IsCurrentClientCharacter) { ClientCharacterEquipmentHelper.ClientRefreshEquipment(character, clientState, publicState); base.ClientUpdate(data); return; } // next code is only for the current client character var privateState = data.PrivateState; if (!publicState.IsDead) { SharedRefreshSelectedHotbarItem(character, privateState); } ClientCharacterEquipmentHelper.ClientRefreshEquipment(character, clientState, publicState); this.ServerRebuildFinalCacheIfNeeded(privateState, publicState); this.SharedApplyInput(character, privateState, publicState); ClientCharacterAnimationHelper.ClientUpdateAnimation( character, clientState, publicState); if (publicState.IsDead) { // dead - stops processing character WindowRespawn.EnsureOpened(); return; } // character is alive - can process its actions WindowRespawn.EnsureClosed(); // update weapon state (fires the weapon if needed) WeaponSystem.SharedUpdateCurrentWeapon(character, privateState.WeaponState, data.DeltaTime); // update current action state (if any) privateState.CurrentActionState?.SharedUpdate(data.DeltaTime); // consumes/restores stamina CharacterStaminaSystem.SharedUpdate(character, publicState, privateState, data.DeltaTime); }
protected override void ClientInitialize(ClientInitializeData data) { base.ClientInitialize(data); var character = data.GameObject; IProtoItem previousSelectedProtoItem = null; var currentItemIdleSoundEmitter = Client.Audio.CreateSoundEmitter(character, SoundResource.NoSound, isLooped: true, volume: 0.5f); var publicState = data.PublicState; var clientState = data.ClientState; ClientCharacterEquipmentHelper.ClientRefreshEquipment(character, clientState, publicState); if (character.IsCurrentClientCharacter) { this.ClientInitializeCurrentCharacter(data); this.ClientInitializeOtherCharacter(data); } else { this.ClientInitializeOtherCharacter(data); } // subscribe on head style change publicState.ClientSubscribe( _ => _.FaceStyle, _ => ResetRendering(resetSkeleton: false), clientState); // subscribe on gender change publicState.ClientSubscribe( _ => _.IsMale, _ => ResetRendering(resetSkeleton: true), clientState); // subscribe on head equipment visibility change publicState.ClientSubscribe( _ => _.IsHeadEquipmentHiddenForSelfAndPartyMembers, _ => ResetRendering(resetSkeleton: false), clientState); // subscribe on vehicle change publicState.ClientSubscribe( _ => _.CurrentVehicle, _ => { // reset input history for lag prediction CurrentCharacterInputHistory.Instance.Clear(); // re-create physics this.SharedCreatePhysics(character); // re-select current item SharedForceRefreshCurrentItem(ClientCurrentCharacterHelper.Character); // reset rendering ResetRendering(resetSkeleton: false); }, clientState); // subscribe on player character public action change publicState.ClientSubscribe( _ => _.CurrentPublicActionState, _ => this.ClientRefreshCurrentPublicActionState(character), clientState); this.ClientRefreshCurrentPublicActionState(character); publicState.ClientSubscribe( _ => _.SelectedItem, _ => { // selected different item RefreshCurrentSelectedItem(); }, clientState); publicState.ClientSubscribe( _ => _.IsDead, _ => { // re-create physics on death state change this.SharedCreatePhysics(character); ResetRendering(); if (character.IsCurrentClientCharacter && publicState.IsDead) { Menu.CloseAll(); } }, clientState); RefreshCurrentSelectedItem(); void RefreshCurrentSelectedItem() { previousSelectedProtoItem?.SharedGetItemSoundPreset() .PlaySound(ItemSound.Deselect, character); currentItemIdleSoundEmitter.Stop(); var currentItem = publicState.SelectedItem; var itemSoundPreset = currentItem? .ProtoItem .SharedGetItemSoundPreset(); previousSelectedProtoItem = currentItem?.ProtoItem; if (itemSoundPreset != null) { itemSoundPreset.PlaySound(ItemSound.Select, character); var idleSoundResource = itemSoundPreset.GetSound(ItemSound.Idle); if (idleSoundResource != null) { currentItemIdleSoundEmitter.SoundResource = idleSoundResource; currentItemIdleSoundEmitter.Delay = 0.1; currentItemIdleSoundEmitter.Play(); } } } void ResetRendering(bool resetSkeleton = false) { // reset hash to force updating equipment/skeleton in the next frame clientState.LastEquipmentContainerHash = null; if (resetSkeleton) { clientState.CurrentProtoSkeleton = null; } } }
protected override void ClientInitialize(ClientInitializeData data) { base.ClientInitialize(data); var character = data.GameObject; IProtoItem previousSelectedProtoItem = null; var currentItemIdleSoundEmitter = Client.Audio.CreateSoundEmitter(character, SoundResource.NoSound, isLooped: true, volume: 0.5f); var publicState = data.SyncPublicState; var clientState = data.ClientState; ClientCharacterEquipmentHelper.ClientRefreshEquipment(character, clientState, publicState); if (character.IsCurrentClientCharacter) { this.ClientInitializeCurrentCharacter(data); } else { this.ClientInitializeOtherCharacter(data); } // subscribe on head style change publicState.ClientSubscribe( _ => _.FaceStyle, _ => ResetRendering(resetSkeleton: true), clientState); // subscribe on gender change publicState.ClientSubscribe( _ => _.IsMale, _ => ResetRendering(), clientState); // subscribe on player character public action change publicState.ClientSubscribe( _ => _.CurrentPublicActionState, _ => this.ClientRefreshCurrentPublicActionState(character), clientState); this.ClientRefreshCurrentPublicActionState(character); publicState.ClientSubscribe( _ => _.SelectedHotbarItem, _ => { // selected different item RefreshCurrentSelectedItem(); }, clientState); publicState.ClientSubscribe( _ => _.IsDead, _ => { // re-create physics on death state change this.SharedCreatePhysics(character); ResetRendering(); }, clientState); RefreshCurrentSelectedItem(); void RefreshCurrentSelectedItem() { previousSelectedProtoItem?.SharedGetItemSoundPreset() .PlaySound(ItemSound.Deselect, limitOnePerFrame: false); currentItemIdleSoundEmitter.Stop(); var currentItem = publicState.SelectedHotbarItem; var itemSoundPreset = currentItem? .ProtoItem .SharedGetItemSoundPreset(); previousSelectedProtoItem = currentItem?.ProtoItem; if (itemSoundPreset == null) { return; } itemSoundPreset.PlaySound(ItemSound.Select, limitOnePerFrame: false); var idleSoundResource = itemSoundPreset.GetSound(ItemSound.Idle); if (idleSoundResource != null) { currentItemIdleSoundEmitter.SoundResource = idleSoundResource; currentItemIdleSoundEmitter.Delay = 0.1; currentItemIdleSoundEmitter.Play(); } } void ResetRendering(bool resetSkeleton = false) { // reset hash to force updating equipment/skeleton in the next frame clientState.LastEquipmentContainerHash = null; if (resetSkeleton) { clientState.CurrentProtoSkeleton = null; } } }