public static void SetupSkeletonEquipmentForCharacter( ICharacter character, IItemsContainer containerEquipment, IComponentSkeleton skeletonRenderer, ProtoCharacterSkeleton skeleton, List <IClientComponent> skeletonComponents, bool isPreview = false) { if (!(skeleton is SkeletonHumanMale) && !(skeleton is SkeletonHumanFemale)) { // not a human // setup only implants using var equipmentImplants = Api.Shared.WrapInTempList( containerEquipment.GetItemsOfProto <IProtoItemEquipmentImplant>()); foreach (var item in equipmentImplants.AsList()) { var proto = (IProtoItemEquipmentImplant)item.ProtoGameObject; proto.ClientSetupSkeleton(item, character, skeletonRenderer, skeletonComponents, isPreview); } return; } bool isMale, isHeadEquipmentHiddenForSelfAndPartyMembers; CharacterHumanFaceStyle faceStyle; if (character.ProtoCharacter is PlayerCharacter) { var publicState = PlayerCharacter.GetPublicState(character); faceStyle = publicState.FaceStyle; isMale = publicState.IsMale; isHeadEquipmentHiddenForSelfAndPartyMembers = publicState.IsHeadEquipmentHiddenForSelfAndPartyMembers; if (isMale && !(skeleton is SkeletonHumanMale) || !isMale && !(skeleton is SkeletonHumanFemale)) { throw new Exception( $"Skeleton don\'t match the gender of the player\'s character: isMale={isMale}, {skeleton}"); } } else { // for NPC it will generate a random face isMale = true; faceStyle = SharedCharacterFaceStylesProvider.GetForGender(isMale).GenerateRandomFace(); isHeadEquipmentHiddenForSelfAndPartyMembers = false; } skeletonRenderer.ResetAttachments(); skeleton.ClientResetItemInHand(skeletonRenderer); var skinToneId = faceStyle.SkinToneId; if (string.IsNullOrEmpty(skinToneId)) { skeletonRenderer.DefaultTextureRemapper = null; } else { // use colorizer for the original sprites (to apply the skin tone) skeletonRenderer.DefaultTextureRemapper = textureResource => { var filePath = textureResource.LocalPath; if (filePath.IndexOf("/Weapon", StringComparison.Ordinal) >= 0 || filePath.IndexOf("/Head", StringComparison.Ordinal) >= 0) { // no need to remap the original head and weapon sprites // (they're never used as is) return(textureResource); } return(ClientCharacterSkinTexturesCache.Get(textureResource, skinToneId)); }; } // setup equipment items using var equipmentItems = Api.Shared.WrapInTempList( containerEquipment.GetItemsOfProto <IProtoItemEquipment>()); if (!IsAllowNakedHumans) { if (!equipmentItems.AsList().Any(i => i.ProtoGameObject is IProtoItemEquipmentArmor)) { // no armor equipped - apply generic one var pants = GenericPantsAttachments.Value; ClientSkeletonAttachmentsLoader.SetAttachments( skeletonRenderer, isMale ? pants.SlotAttachmentsMale : pants.SlotAttachmentsFemale); // select a random generic T-shirt based on character ID var allShirts = GenericShirtAttachments.Value; var selectedShirtIndex = character.Id % allShirts.Length; var shirt = allShirts[(int)selectedShirtIndex]; ClientSkeletonAttachmentsLoader.SetAttachments( skeletonRenderer, isMale ? shirt.SlotAttachmentsMale : shirt.SlotAttachmentsFemale); } } IItem headEquipmentForFaceSprite = null; foreach (var item in equipmentItems.AsList()) { var proto = (IProtoItemEquipment)item.ProtoGameObject; proto.ClientSetupSkeleton(item, character, skeletonRenderer, skeletonComponents, isPreview); if (item.ProtoItem is IProtoItemEquipmentHead && headEquipmentForFaceSprite is null) { headEquipmentForFaceSprite = item; } } if (isHeadEquipmentHiddenForSelfAndPartyMembers && (character.IsCurrentClientCharacter || PartySystem.ClientIsPartyMember(character.Name) || PveSystem.ClientIsPve(false))) { headEquipmentForFaceSprite = null; } // generate head sprites for human players const string slotName = "Head", attachmentName = "Head"; headGenerationId++; var spriteQualityOffset = skeletonRenderer.SpriteQualityOffset; skeletonRenderer.SetAttachmentSprite( skeleton.SkeletonResourceFront, slotName, attachmentName, new ProceduralTexture( $"Head Front CharacterID={character.Id} gen={headGenerationId}", proceduralTextureRequest => ClientCharacterHeadSpriteComposer.GenerateHeadSprite( new CharacterHeadSpriteData(faceStyle, headEquipmentForFaceSprite, skeleton.SkeletonResourceFront), proceduralTextureRequest, isMale, headSpriteType: ClientCharacterHeadSpriteComposer.HeadSpriteType.Front, spriteQualityOffset: spriteQualityOffset), isTransparent: true, isUseCache: false)); skeletonRenderer.SetAttachmentSprite( skeleton.SkeletonResourceBack, slotName, attachmentName, new ProceduralTexture( $"Head Back CharacterID={character.Id} gen={headGenerationId}", proceduralTextureRequest => ClientCharacterHeadSpriteComposer.GenerateHeadSprite( new CharacterHeadSpriteData(faceStyle, headEquipmentForFaceSprite, skeleton.SkeletonResourceBack), proceduralTextureRequest, isMale, headSpriteType: ClientCharacterHeadSpriteComposer.HeadSpriteType.Back, spriteQualityOffset: spriteQualityOffset), isTransparent: true, isUseCache: false)); skeletonRenderer.SetAttachmentSprite( skeleton.SkeletonResourceBack, slotName + "Back", attachmentName, new ProceduralTexture( $"Head Back2 CharacterID={character.Id} gen={headGenerationId}", proceduralTextureRequest => ClientCharacterHeadSpriteComposer.GenerateHeadSprite( new CharacterHeadSpriteData(faceStyle, headEquipmentForFaceSprite, skeleton.SkeletonResourceBack), proceduralTextureRequest, isMale, headSpriteType: ClientCharacterHeadSpriteComposer.HeadSpriteType.BackOverlay, spriteQualityOffset: spriteQualityOffset), isTransparent: true, isUseCache: false)); }
public static void SetupSkeletonEquipmentForCharacter( ICharacter character, IItemsContainer containerEquipment, IComponentSkeleton skeletonRenderer, ProtoCharacterSkeleton skeleton, List <IClientComponent> skeletonComponents) { if (!(skeleton is SkeletonHumanMale) && !(skeleton is SkeletonHumanFemale)) { // not a human return; } skeletonRenderer.ResetAttachments(); bool isMale; CharacterHumanFaceStyle faceStyle; if (character.ProtoCharacter is PlayerCharacter) { var pubicState = PlayerCharacter.GetPublicState(character); faceStyle = pubicState.FaceStyle; isMale = pubicState.IsMale; if (isMale && !(skeleton is SkeletonHumanMale) || !isMale && !(skeleton is SkeletonHumanFemale)) { throw new Exception( $"Skeleton don\'t match the gender of the player\'s character: isMale={isMale}, {skeleton}"); } } else { // for NPC it will generate a random face isMale = true; faceStyle = SharedCharacterFaceStylesProvider.GetForGender(isMale).GenerateRandomFace(); } // setup equipment items var equipmentItems = containerEquipment.GetItemsOfProto <IProtoItemEquipment>().ToList(); if (!IsAllowNakedHumans) { if (!equipmentItems.Any(i => i.ProtoGameObject is IProtoItemEquipmentLegs)) { // no lower cloth - apply generic one ClientSkeletonAttachmentsLoader.SetAttachments( skeletonRenderer, isMale ? GenericPantsAttachments.Value.SlotAttachmentsMale : GenericPantsAttachments.Value.SlotAttachmentsFemale); } if (!equipmentItems.Any(i => i.ProtoGameObject is IProtoItemEquipmentChest)) { // no upper cloth - apply generic one (based on character Id) var allShirts = GenericShirtAttachments.Value; var selectedShirtIndex = character.Id % allShirts.Length; var shirt = allShirts[(int)selectedShirtIndex]; ClientSkeletonAttachmentsLoader.SetAttachments( skeletonRenderer, isMale ? shirt.SlotAttachmentsMale : shirt.SlotAttachmentsFemale); } } IItem headEquipment = null; foreach (var item in equipmentItems) { var proto = (IProtoItemEquipment)item.ProtoGameObject; proto.ClientSetupSkeleton(item, character, skeletonRenderer, skeletonComponents); if (item.ProtoItem is IProtoItemEquipmentHead && headEquipment == null) { headEquipment = item; } } // generate head sprites for human players const string slotName = "Head", attachmentName = "Head"; skeletonRenderer.SetAttachmentSprite( skeleton.SkeletonResourceFront, slotName, attachmentName, new ProceduralTexture( "Head Front CharacterID=" + character.Id, proceduralTextureRequest => ClientCharacterHeadSpriteComposer.GenerateHeadSprite( new CharacterHeadSpriteData(faceStyle, headEquipment, skeleton.SkeletonResourceFront), proceduralTextureRequest, isMale, isFrontFace: true, spriteQualityOffset: skeletonRenderer.SpriteQualityOffset), isTransparent: true, isUseCache: false)); skeletonRenderer.SetAttachmentSprite( skeleton.SkeletonResourceBack, slotName, attachmentName, new ProceduralTexture( "Head Back CharacterID=" + character.Id, proceduralTextureRequest => ClientCharacterHeadSpriteComposer.GenerateHeadSprite( new CharacterHeadSpriteData(faceStyle, headEquipment, skeleton.SkeletonResourceBack), proceduralTextureRequest, isMale, isFrontFace: false, spriteQualityOffset: skeletonRenderer.SpriteQualityOffset), isTransparent: true, isUseCache: false)); ClientResetWeaponAttachments(skeletonRenderer); }