public static void ClientRefreshEquipment( ICharacter character, BaseCharacterClientState clientState, ICharacterPublicStateWithEquipment publicState) { var selectedItem = character.IsCurrentClientCharacter ? ClientHotbarSelectedItemManager.SelectedItem : publicState.SelectedHotbarItem; var containerEquipment = publicState.ContainerEquipment; if (clientState.LastEquipmentContainerHash == containerEquipment.StateHash && clientState.SkeletonRenderer != null && clientState.LastSelectedItem == selectedItem) { return; } clientState.LastEquipmentContainerHash = containerEquipment.StateHash; ClientRebuildAppearance( character, clientState, publicState, selectedItem); }
public static void ClientRebuildAppearance( ICharacter character, BaseCharacterClientState clientState, ICharacterPublicState publicState, IItem selectedItem) { if (!character.IsNpc) { var vehicle = character.SharedGetCurrentVehicle(); if (vehicle is not null && !vehicle.IsInitialized) { // Character has a vehicle which is not yet initialized. // Don't build a skeleton for it now. // When vehicle will be initialized, // it will automatically re-initialize the character and invoke this method. return; } } IProtoCharacterSkeleton newProtoSkeleton = null; double skeletonScaleMultiplier = 0; if (publicState is PlayerCharacterPublicState playerCharacterPublicState && playerCharacterPublicState.CurrentVehicle is not null && playerCharacterPublicState.CurrentVehicle.IsInitialized) { var protoVehicle = (IProtoVehicle)playerCharacterPublicState.CurrentVehicle.ProtoWorldObject; protoVehicle.SharedGetSkeletonProto(null, out var protoSkeletonVehicle, out var scaleResult); if (protoSkeletonVehicle is not null) { newProtoSkeleton = (ProtoCharacterSkeleton)protoSkeletonVehicle; skeletonScaleMultiplier = scaleResult; } } if (newProtoSkeleton is null) { character.ProtoCharacter.SharedGetSkeletonProto( character, out newProtoSkeleton, out skeletonScaleMultiplier); } var isSkeletonChanged = newProtoSkeleton != clientState.CurrentProtoSkeleton; clientState.CurrentProtoSkeleton = (ProtoCharacterSkeleton)newProtoSkeleton; clientState.CurrentProtoSkeletonScaleMultiplier = skeletonScaleMultiplier; var skeletonRenderer = clientState.SkeletonRenderer; var skeletonComponents = clientState.SkeletonComponents; if (skeletonComponents.Count > 0) { foreach (var comp in skeletonComponents) { try { comp.Destroy(); } catch (Exception ex) { Api.Logger.Exception(ex); } } skeletonComponents.Clear(); } var isNewSkeleton = false; // create shadow renderer clientState.RendererShadow?.Destroy(); clientState.RendererShadow = ((ProtoCharacterSkeleton)newProtoSkeleton) .ClientCreateShadowRenderer(character, skeletonScaleMultiplier); if (skeletonRenderer is null || isSkeletonChanged) { skeletonRenderer?.Destroy(); if (newProtoSkeleton is null || newProtoSkeleton.SkeletonResourceFront is null) { return; } var scale = clientState.CurrentProtoSkeleton.WorldScale * clientState.CurrentProtoSkeletonScaleMultiplier; // create new skeleton renderer skeletonRenderer = CreateCharacterSkeleton(character.ClientSceneObject, newProtoSkeleton, scale); clientState.SkeletonRenderer = skeletonRenderer; isNewSkeleton = true; //Api.Logger.Write("Skeleton created for " + character); } if (clientState.LastSelectedItem != selectedItem) { clientState.LastSelectedItem = selectedItem; if (!isNewSkeleton) { // cleanup skeleton skeletonRenderer.ResetSkeleton(); } } var containerEquipment = (publicState as ICharacterPublicStateWithEquipment) ?.ContainerEquipment; if (containerEquipment is not null) { SetupSkeletonEquipmentForCharacter( character, containerEquipment, skeletonRenderer, clientState.CurrentProtoSkeleton, skeletonComponents); } if (!character.IsNpc) { var vehicle = character.SharedGetCurrentVehicle(); if (vehicle is not null && vehicle.IsInitialized) { var protoVehicle = (IProtoVehicle)vehicle.ProtoGameObject; protoVehicle.ClientSetupSkeleton(vehicle, newProtoSkeleton, skeletonRenderer, skeletonComponents); } } if (selectedItem is not null) { var activeProtoItem = selectedItem.ProtoGameObject as IProtoItemWithCharacterAppearance; activeProtoItem?.ClientSetupSkeleton(selectedItem, character, clientState.CurrentProtoSkeleton, skeletonRenderer, skeletonComponents); } if (character.IsCurrentClientCharacter && character.ProtoCharacter is PlayerCharacter) { TryAddArtificialLightArea(character, skeletonComponents); } // ensure all the added skeleton components are instantly updated // to make them ready for rendering (fixes light flickering issue) foreach (var c in skeletonComponents) { if (!(c is ClientComponent component) || !component.IsEnabled) { continue; } component.Update(0); if (component.IsLateUpdateEnabled) { component.LateUpdate(0); } } }
public static void ClientRebuildAppearance( ICharacter character, BaseCharacterClientState clientState, ICharacterPublicState publicState, IItem selectedItem) { character.ProtoCharacter.SharedGetSkeletonProto( character, out var newProtoSkeleton, out var skeletonScaleMultiplier); var isSkeletonChanged = newProtoSkeleton != clientState.CurrentProtoSkeleton; clientState.CurrentProtoSkeleton = (ProtoCharacterSkeleton)newProtoSkeleton; clientState.CurrentProtoSkeletonScaleMultiplier = skeletonScaleMultiplier; var skeletonRenderer = clientState.SkeletonRenderer; var skeletonComponents = clientState.SkeletonComponents; if (skeletonComponents.Count > 0) { foreach (var comp in skeletonComponents) { try { comp.Destroy(); } catch (Exception ex) { Api.Logger.Exception(ex); } } skeletonComponents.Clear(); } var isNewSkeleton = false; if (skeletonRenderer == null || isSkeletonChanged) { skeletonRenderer?.Destroy(); if (newProtoSkeleton == null || newProtoSkeleton.SkeletonResourceFront == null) { return; } var sceneObject = Api.Client.Scene.GetSceneObject(character); var scale = clientState.CurrentProtoSkeleton.WorldScale * clientState.CurrentProtoSkeletonScaleMultiplier; // create new skeleton renderer skeletonRenderer = CreateCharacterSkeleton(sceneObject, newProtoSkeleton, scale); clientState.SkeletonRenderer = skeletonRenderer; isNewSkeleton = true; //Api.Logger.Write("Skeleton created for " + character); } if (clientState.LastSelectedItem != selectedItem) { clientState.LastSelectedItem = selectedItem; if (!isNewSkeleton) { // cleanup skeleton skeletonRenderer.ResetSkeleton(); } } var containerEquipment = (publicState as ICharacterPublicStateWithEquipment) ?.ContainerEquipment; if (containerEquipment != null) { SetupSkeletonEquipmentForCharacter( character, containerEquipment, skeletonRenderer, clientState.CurrentProtoSkeleton, skeletonComponents); } if (selectedItem != null) { var activeProtoItem = selectedItem.ProtoGameObject as IProtoItemWithCharacterAppearance; activeProtoItem?.ClientSetupSkeleton(selectedItem, character, skeletonRenderer, skeletonComponents); } if (character.IsCurrentClientCharacter && character.ProtoCharacter is PlayerCharacter && !skeletonComponents.Any(c => c is ClientComponentLightInSkeleton)) { // this is current client character and it doesn't have light in hand // create a faint light source (see called method comments) var lightSource = PlayerCharacter.ClientCreateDefaultLightSource(character); if (lightSource != null) { skeletonComponents.Add(lightSource); } } }