using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Sandbox; partial class Dedugan { [Property] public List WorkshopItems { get; set; } [Property] public ClothingContainer CurrentClothing { get; set; } public static IReadOnlyList All => InternalPlayers; public static List InternalPlayers = new List(); public List Clothings { get; set; } public static Dedugan Local { get; set; } private Guid _guid; public static Dedugan FindLocalPlayer() => Local; [Sync( SyncFlags.FromHost )] public Guid ConnectionID { get => _guid; set { _guid = value; Connection = Connection.Find( _guid ); if ( _guid == Connection.Local.Id ) { Local = this; // ILocalPlayerEvent.Post( x => x.OnInitialized() ); } InternalPlayers.RemoveAll( x => !x.IsValid() ); if ( !InternalPlayers.Contains( this ) ) InternalPlayers.Add( this ); } } public Connection Connection { get; private set; } public ulong SteamID => Connection.SteamId; public string Name => Connection.DisplayName; public void SetupConnection( Connection connection ) { ConnectionID = connection.Id; GameObject.Name = $"{Name} / {SteamID}"; } public static Dedugan GetByID( Guid id ) => InternalPlayers.FirstOrDefault( x => x.ConnectionID == id ); public void OnNetworkSpawn( Connection owner ) { CurrentClothing = ClothingContainer.CreateFromJson( owner.GetUserData( "avatar" ) ); var allowedCategories = new[] { Clothing.ClothingCategory.Skin, Clothing.ClothingCategory.Facial, Clothing.ClothingCategory.Eyes, Clothing.ClothingCategory.Eyebrows, Clothing.ClothingCategory.Eyelashes, Clothing.ClothingCategory.MakeupLips, Clothing.ClothingCategory.MakeupEyeshadow, Clothing.ClothingCategory.MakeupEyeliner, Clothing.ClothingCategory.MakeupHighlighter, Clothing.ClothingCategory.MakeupBlush, Clothing.ClothingCategory.MakeupSpecial, Clothing.ClothingCategory.ComplexionFreckles, Clothing.ClothingCategory.ComplexionScars, Clothing.ClothingCategory.ComplexionAcne, Clothing.ClothingCategory.FacialHairMustache, Clothing.ClothingCategory.FacialHairBeard, Clothing.ClothingCategory.FacialHairStubble, Clothing.ClothingCategory.FacialHairSideburns, Clothing.ClothingCategory.FacialHairGoatee, Clothing.ClothingCategory.PierceNose, Clothing.ClothingCategory.PierceEyebrow, Clothing.ClothingCategory.PierceSpecial, Clothing.ClothingCategory.Hair, Clothing.ClothingCategory.HairShort, Clothing.ClothingCategory.HairMedium, Clothing.ClothingCategory.HairLong, Clothing.ClothingCategory.HairUpdo, Clothing.ClothingCategory.HairSpecial, }; CurrentClothing.Clothing.RemoveAll( entry => !allowedCategories.Contains( entry.Clothing.Category ) ); CurrentClothing.Apply( Renderer ); } CancellationTokenSource _cts; [Rpc.Broadcast] public async void WearWorkshop( List workshopItems ) { _cts = new CancellationTokenSource(); var token = _cts.Token; // var clothing = new ClothingContainer(); // clothing.AddRange( Clothings ); if ( workshopItems != null && workshopItems.Count > 0 ) { var tasks = workshopItems.Select( x => InstallWorkshopClothing( x, token ) ); foreach ( var task in tasks ) { var c = await task; if ( c is null ) continue; CurrentClothing.Add( c ); } } CurrentClothing.Normalize(); CurrentClothing.Apply( Renderer ); Renderer.PostAnimationUpdate(); } [Rpc.Broadcast] public void StripByName( string name ) { CurrentClothing.Clothing.RemoveAll( entry => entry.Clothing.Title == name ); CurrentClothing.Normalize(); CurrentClothing.Apply( Renderer ); Renderer.PostAnimationUpdate(); } public void CancelDressing() { _cts?.Cancel(); _cts?.Dispose(); _cts = default; } async Task InstallWorkshopClothing( string ident, CancellationToken ct ) { if ( string.IsNullOrEmpty( ident ) ) return default; var package = await Package.FetchAsync( ident, false ); if ( package is null ) return default; if ( package.TypeName != "clothing" ) return default; if ( ct.IsCancellationRequested ) return default; var primaryAsset = package.GetMeta( "PrimaryAsset" ); if ( string.IsNullOrWhiteSpace( primaryAsset ) ) return default; var fs = await package.MountAsync(); if ( fs is null ) return default; if ( ct.IsCancellationRequested ) return default; // try to load it return ResourceLibrary.Get( primaryAsset ); } }