using Synty.SidekickCharacters.API; using Synty.SidekickCharacters.Database; using Synty.SidekickCharacters.Database.DTO; using Synty.SidekickCharacters.Enums; using Synty.SidekickCharacters.Utils; using System; using System.Collections.Generic; using System.IO; using System.Linq; using TMPro; using UnityEngine; using Random = UnityEngine.Random; namespace Synty.SidekickCharacters.Demo { /// /// An example script to show how to interact with the Sidekick API in regards to presets at runtime. /// public class RuntimePresetDemo : MonoBehaviour { private readonly string _OUTPUT_MODEL_NAME = "Sidekick Character"; private Dictionary _availableHeadPresetDictionary = new Dictionary(); private Dictionary _availableUpperBodyPresetDictionary = new Dictionary(); private Dictionary _availableLowerBodyPresetDictionary = new Dictionary(); private List _availableBodyShapes = new List(); private List _availableColorPresets = new List(); private int _currentHeadPresetIndex = 0; private int _currentUpperBodyPresetIndex = 0; private int _currentLowerBodyPresetIndex = 0; private int _currentBodyShapePresetIndex = 0; private int _currentColorPresetIndex = 0; private DatabaseManager _dbManager; private SidekickRuntime _sidekickRuntime; private Dictionary> _partLibrary; public TextMeshProUGUI _loadingText; /// void Start() { _dbManager = new DatabaseManager(); GameObject model = Resources.Load("Meshes/SK_BaseModel"); Material material = Resources.Load("Materials/M_BaseMaterial"); _sidekickRuntime = new SidekickRuntime(model, material, null, _dbManager); SidekickRuntime.PopulateToolData(_sidekickRuntime); _partLibrary = _sidekickRuntime.MappedPartDictionary; foreach (PartGroup partGroup in Enum.GetValues(typeof(PartGroup))) { // only filter head part presets by species List presets = SidekickPartPreset.GetAllByGroup(_dbManager, partGroup); List presetNames = new List(); if (presets.Count < 1) { Debug.LogWarning("No parts found for " + partGroup + ". Please add at least 1 Sidekicks content pack."); continue; } foreach (SidekickPartPreset preset in presets) { if (preset.HasAllPartsAvailable(_dbManager)) { switch (partGroup) { case PartGroup.Head: _availableHeadPresetDictionary.Add(preset.Name, preset); break; case PartGroup.UpperBody: _availableUpperBodyPresetDictionary.Add(preset.Name, preset); break; case PartGroup.LowerBody: _availableLowerBodyPresetDictionary.Add(preset.Name, preset); break; } presetNames.Add(preset.Name); } } } _availableBodyShapes = SidekickBodyShapePreset.GetAll(_dbManager); // An example of how to retrieve color presets from the database. To retrieve presets for other areas of the material, use the ColorGroup // enum to retrieve other presets. _availableColorPresets = SidekickColorPreset.GetAllByColorGroup(_dbManager, ColorGroup.Outfits); _currentHeadPresetIndex = Random.Range(0, _availableHeadPresetDictionary.Count - 1); _currentUpperBodyPresetIndex = Random.Range(0, _availableUpperBodyPresetDictionary.Count - 1); _currentLowerBodyPresetIndex = Random.Range(0, _availableLowerBodyPresetDictionary.Count - 1); _currentBodyShapePresetIndex = Random.Range(0, _availableBodyShapes.Count - 1); _currentColorPresetIndex = Random.Range(0, _availableColorPresets.Count - 1); _loadingText.enabled = false; UpdateModel(); } /// /// Handles the click on the forward button for the Head Preset. /// public void ForwardHeadPreset() { _currentHeadPresetIndex++; if (_currentHeadPresetIndex >= _availableHeadPresetDictionary.Count) { _currentHeadPresetIndex = 0; } UpdateModel(); } /// /// Handles the click on the backward button for the Head Preset. /// public void BackwardHeadPreset() { _currentHeadPresetIndex--; if (_currentHeadPresetIndex < 0) { _currentHeadPresetIndex = _availableHeadPresetDictionary.Count - 1; } UpdateModel(); } /// /// Handles the click on the forward button for the Upper Body Preset. /// public void ForwardUpperBodyPreset() { _currentUpperBodyPresetIndex++; if (_currentUpperBodyPresetIndex >= _availableUpperBodyPresetDictionary.Count) { _currentUpperBodyPresetIndex = 0; } UpdateModel(); } /// /// Handles the click on the backward button for the Upper Body Preset. /// public void BackwardUpperBodyPreset() { _currentUpperBodyPresetIndex--; if (_currentUpperBodyPresetIndex < 0) { _currentUpperBodyPresetIndex = _availableUpperBodyPresetDictionary.Count - 1; } UpdateModel(); } /// /// Handles the click on the forward button for the Lower Body Preset. /// public void ForwardLowerBodyPreset() { _currentLowerBodyPresetIndex++; if (_currentLowerBodyPresetIndex >= _availableLowerBodyPresetDictionary.Count) { _currentLowerBodyPresetIndex = 0; } UpdateModel(); } /// /// Handles the click on the backward button for the Lower Body Preset. /// public void BackwardLowerBodyPreset() { _currentLowerBodyPresetIndex--; if (_currentLowerBodyPresetIndex < 0) { _currentLowerBodyPresetIndex = _availableLowerBodyPresetDictionary.Count - 1; } UpdateModel(); } /// /// Handles the click on the forward button for the Body Shape Preset. /// public void ForwardBodyShapePreset() { _currentBodyShapePresetIndex++; if (_currentBodyShapePresetIndex >= _availableBodyShapes.Count) { _currentBodyShapePresetIndex = 0; } UpdateModel(); } /// /// Handles the click on the backward button for the Body Shape Preset. /// public void BackwardBodyShapePreset() { _currentBodyShapePresetIndex--; if (_currentBodyShapePresetIndex < 0) { _currentBodyShapePresetIndex = _availableBodyShapes.Count - 1; } UpdateModel(); } /// /// Handles the click on the forward button for the Color Preset. /// public void ForwardColorPreset() { _currentColorPresetIndex++; if (_currentColorPresetIndex >= _availableColorPresets.Count) { _currentColorPresetIndex = 0; } UpdateModel(); } /// /// Handles the click on the backward button for the Color Preset. /// public void BackwardColorPreset() { _currentColorPresetIndex--; if (_currentColorPresetIndex < 0) { _currentColorPresetIndex = _availableColorPresets.Count - 1; } UpdateModel(); } /// /// Updates the created character model. /// private void UpdateModel() { // If there aren't enough presets, stop trying to update the model. if (_availableHeadPresetDictionary.Values.Count < 1 || _availableUpperBodyPresetDictionary.Values.Count < 1 || _availableLowerBodyPresetDictionary.Values.Count < 1) { return; } // Create and populate the list of parts to use from the parts list, and the selected presets. List presets = new List() { _availableHeadPresetDictionary.Values.ToArray()[_currentHeadPresetIndex], _availableUpperBodyPresetDictionary.Values.ToArray()[_currentUpperBodyPresetIndex], _availableLowerBodyPresetDictionary.Values.ToArray()[_currentLowerBodyPresetIndex] }; List partsToUse = new List(); foreach (SidekickPartPreset preset in presets) { List rows = SidekickPartPresetRow.GetAllByPreset(_dbManager, preset); foreach (SidekickPartPresetRow row in rows) { if (!string.IsNullOrEmpty(row.PartName)) { CharacterPartType type = Enum.Parse(CharacterPartTypeUtils.GetTypeNameFromShortcode(row.PartType)); Dictionary partLocationDictionary = _partLibrary[type]; GameObject selectedPart = partLocationDictionary[row.PartName].GetPartModel(); SkinnedMeshRenderer selectedMesh = selectedPart.GetComponentInChildren(); partsToUse.Add(selectedMesh); } } } SidekickBodyShapePreset bodyPreset = _availableBodyShapes[_currentBodyShapePresetIndex]; _sidekickRuntime.BodyTypeBlendValue = bodyPreset.BodyType; _sidekickRuntime.BodySizeHeavyBlendValue = bodyPreset.BodySize > 0 ? bodyPreset.BodySize : 0; _sidekickRuntime.BodySizeSkinnyBlendValue = bodyPreset.BodySize < 0 ? -bodyPreset.BodySize : 0; _sidekickRuntime.MusclesBlendValue = bodyPreset.Musculature; List colorRows = SidekickColorPresetRow.GetAllByPreset(_dbManager, _availableColorPresets[_currentColorPresetIndex]); foreach (SidekickColorPresetRow row in colorRows) { SidekickColorRow colorRow = SidekickColorRow.CreateFromPresetColorRow(row); foreach (ColorType property in Enum.GetValues(typeof(ColorType))) { _sidekickRuntime.UpdateColor(property, colorRow); } } // Check for an existing copy of the model, if it exists, delete it so that we don't end up with duplicates. GameObject character = GameObject.Find(_OUTPUT_MODEL_NAME); if (character != null) { Destroy(character); } // Create a new character using the selected parts using the Sidekicks API. character = _sidekickRuntime.CreateCharacter(_OUTPUT_MODEL_NAME, partsToUse, false, true); } /// /// Gets a resource path for using with Resources.Load() from a full path. /// /// The full path to get the resource path from. /// The resource path. private string GetResourcePath(string fullPath) { string directory = Path.GetDirectoryName(fullPath); int startIndex = directory.IndexOf("Resources") + 10; directory = directory.Substring(startIndex, directory.Length - startIndex); return Path.Combine(directory, Path.GetFileNameWithoutExtension(fullPath)); } } }