chore: 외부 에셋 권한 및 줄바꿈 재기록 반영

- Assets/External 하위 샘플 및 서드파티 에셋 파일의 실행 비트 변경을 별도 커밋으로 분리
- PolygonGeneric, SidekickCharacters, Synty 도구 자산 전반의 줄바꿈 및 재직렬화 차이를 그대로 보존
- 프로젝트 고유 로직 변경과 분리해 이후 히스토리에서 외부 에셋 노이즈 범위를 식별하기 쉽게 정리
This commit is contained in:
2026-04-06 14:04:09 +09:00
parent c8edf838fd
commit cf103baf57
140 changed files with 15090 additions and 14829 deletions

View File

@@ -1,140 +1,140 @@
using UnityEngine;
using UnityEngine.UI;
public class RandomisedLayerWeight : MonoBehaviour
{
[SerializeField] private Animator animator;
[Header("Random Variance Settings")]
[SerializeField, Range(0f, 1f)] private float maxRandomVariance = 0.5f;
[SerializeField] private Slider randomVarianceSlider;
[SerializeField] private Text maxRandomVarianceText; // UI Text to display maxRandomVariance
[Header("Layer Weight Settings")] // Changed header name to "Layer Weight Settings"
[SerializeField, Range(0f, 1f)] private float layerWeight = 1f; // Changed variable name to layerWeight
[SerializeField] private Slider layerWeightSlider; // Changed slider name to layerWeightSlider
[SerializeField] private Text layerWeightText; // Changed UI Text name to layerWeightText
[Header("Transition Settings")]
[SerializeField] private string layerName = "Emotion_Additive"; // Adjust this layer name in the Inspector
[SerializeField] private float averageTransitionTime = 0.4f;
[SerializeField] private float transitionVariationAmount = 0.3f;
[Header("Hold Settings")]
[SerializeField] private float averageHoldTime = 1.0f;
[SerializeField] private float holdVariationAmount = 1.0f;
private int layerIndex;
private float currentWeight = 0f;
private float targetWeight = 0f;
private float transitionTimer = 0f;
private float holdTimer = 0f;
void Start()
{
if (animator == null)
{
Debug.LogError("Animator component is not assigned.");
enabled = false;
return;
}
layerIndex = animator.GetLayerIndex(layerName);
if (layerIndex == -1)
{
Debug.LogError($"Layer '{layerName}' not found in the Animator.");
enabled = false;
return;
}
// Initialize sliders and UI Texts
if (randomVarianceSlider != null)
{
randomVarianceSlider.value = maxRandomVariance;
randomVarianceSlider.onValueChanged.AddListener(SetMaxRandomVariance);
}
if (layerWeightSlider != null) // Changed to layerWeightSlider
{
layerWeightSlider.value = layerWeight; // Changed to layerWeight
layerWeightSlider.onValueChanged.AddListener(SetLayerWeight); // Changed to SetLayerWeight
}
// Initialize UI Texts
if (maxRandomVarianceText != null)
{
maxRandomVarianceText.text = $"Random Variance: {maxRandomVariance:P0}";
}
if (layerWeightText != null) // Changed to layerWeightText
{
layerWeightText.text = $"Layer Weight: {layerWeight:P0}"; // Changed to Layer Weight
}
// Initialize the weight to a random value between 0 and 1
currentWeight = Random.value;
animator.SetLayerWeight(layerIndex, currentWeight * layerWeight); // Changed to layerWeight
// Start the initial transition
StartTransition();
}
void Update()
{
// Update timers
transitionTimer -= Time.deltaTime;
holdTimer -= Time.deltaTime;
// Check if it's time to transition to a new weight
if (transitionTimer <= 0f)
{
StartTransition();
}
// Otherwise, check if it's time to hold the current weight
else if (holdTimer <= 0f)
{
holdTimer = GenerateHoldTime();
}
// Smoothly adjust the weight towards the target weight
currentWeight = Mathf.Lerp(currentWeight, targetWeight, Time.deltaTime / averageTransitionTime);
animator.SetLayerWeight(layerIndex, currentWeight * layerWeight); // Changed to layerWeight
}
private void StartTransition()
{
// Set a new target weight
targetWeight = Random.Range(Mathf.Max(0f, 1f - maxRandomVariance), 1f) * layerWeight; // Changed to layerWeight
transitionTimer = GenerateTransitionTime();
}
private float GenerateTransitionTime()
{
float variation = Random.Range(-transitionVariationAmount, transitionVariationAmount);
return Mathf.Max(0f, averageTransitionTime + variation);
}
private float GenerateHoldTime()
{
float variation = Random.Range(-holdVariationAmount, holdVariationAmount);
return Mathf.Max(0f, averageHoldTime + variation);
}
private void SetMaxRandomVariance(float value)
{
maxRandomVariance = value;
if (maxRandomVarianceText != null)
{
maxRandomVarianceText.text = $"Random Variance: {maxRandomVariance:P0}";
}
}
private void SetLayerWeight(float value) // Changed method name to SetLayerWeight
{
layerWeight = value; // Changed to layerWeight
if (layerWeightText != null) // Changed to layerWeightText
{
layerWeightText.text = $"Layer Weight: {layerWeight:P0}"; // Changed to Layer Weight
}
}
}
using UnityEngine;
using UnityEngine.UI;
public class RandomisedLayerWeight : MonoBehaviour
{
[SerializeField] private Animator animator;
[Header("Random Variance Settings")]
[SerializeField, Range(0f, 1f)] private float maxRandomVariance = 0.5f;
[SerializeField] private Slider randomVarianceSlider;
[SerializeField] private Text maxRandomVarianceText; // UI Text to display maxRandomVariance
[Header("Layer Weight Settings")] // Changed header name to "Layer Weight Settings"
[SerializeField, Range(0f, 1f)] private float layerWeight = 1f; // Changed variable name to layerWeight
[SerializeField] private Slider layerWeightSlider; // Changed slider name to layerWeightSlider
[SerializeField] private Text layerWeightText; // Changed UI Text name to layerWeightText
[Header("Transition Settings")]
[SerializeField] private string layerName = "Emotion_Additive"; // Adjust this layer name in the Inspector
[SerializeField] private float averageTransitionTime = 0.4f;
[SerializeField] private float transitionVariationAmount = 0.3f;
[Header("Hold Settings")]
[SerializeField] private float averageHoldTime = 1.0f;
[SerializeField] private float holdVariationAmount = 1.0f;
private int layerIndex;
private float currentWeight = 0f;
private float targetWeight = 0f;
private float transitionTimer = 0f;
private float holdTimer = 0f;
void Start()
{
if (animator == null)
{
Debug.LogError("Animator component is not assigned.");
enabled = false;
return;
}
layerIndex = animator.GetLayerIndex(layerName);
if (layerIndex == -1)
{
Debug.LogError($"Layer '{layerName}' not found in the Animator.");
enabled = false;
return;
}
// Initialize sliders and UI Texts
if (randomVarianceSlider != null)
{
randomVarianceSlider.value = maxRandomVariance;
randomVarianceSlider.onValueChanged.AddListener(SetMaxRandomVariance);
}
if (layerWeightSlider != null) // Changed to layerWeightSlider
{
layerWeightSlider.value = layerWeight; // Changed to layerWeight
layerWeightSlider.onValueChanged.AddListener(SetLayerWeight); // Changed to SetLayerWeight
}
// Initialize UI Texts
if (maxRandomVarianceText != null)
{
maxRandomVarianceText.text = $"Random Variance: {maxRandomVariance:P0}";
}
if (layerWeightText != null) // Changed to layerWeightText
{
layerWeightText.text = $"Layer Weight: {layerWeight:P0}"; // Changed to Layer Weight
}
// Initialize the weight to a random value between 0 and 1
currentWeight = Random.value;
animator.SetLayerWeight(layerIndex, currentWeight * layerWeight); // Changed to layerWeight
// Start the initial transition
StartTransition();
}
void Update()
{
// Update timers
transitionTimer -= Time.deltaTime;
holdTimer -= Time.deltaTime;
// Check if it's time to transition to a new weight
if (transitionTimer <= 0f)
{
StartTransition();
}
// Otherwise, check if it's time to hold the current weight
else if (holdTimer <= 0f)
{
holdTimer = GenerateHoldTime();
}
// Smoothly adjust the weight towards the target weight
currentWeight = Mathf.Lerp(currentWeight, targetWeight, Time.deltaTime / averageTransitionTime);
animator.SetLayerWeight(layerIndex, currentWeight * layerWeight); // Changed to layerWeight
}
private void StartTransition()
{
// Set a new target weight
targetWeight = Random.Range(Mathf.Max(0f, 1f - maxRandomVariance), 1f) * layerWeight; // Changed to layerWeight
transitionTimer = GenerateTransitionTime();
}
private float GenerateTransitionTime()
{
float variation = Random.Range(-transitionVariationAmount, transitionVariationAmount);
return Mathf.Max(0f, averageTransitionTime + variation);
}
private float GenerateHoldTime()
{
float variation = Random.Range(-holdVariationAmount, holdVariationAmount);
return Mathf.Max(0f, averageHoldTime + variation);
}
private void SetMaxRandomVariance(float value)
{
maxRandomVariance = value;
if (maxRandomVarianceText != null)
{
maxRandomVarianceText.text = $"Random Variance: {maxRandomVariance:P0}";
}
}
private void SetLayerWeight(float value) // Changed method name to SetLayerWeight
{
layerWeight = value; // Changed to layerWeight
if (layerWeightText != null) // Changed to layerWeightText
{
layerWeightText.text = $"Layer Weight: {layerWeight:P0}"; // Changed to Layer Weight
}
}
}

View File

@@ -1,223 +1,223 @@
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 UnityEngine.UI;
using Random = UnityEngine.Random;
namespace Synty.SidekickCharacters.Demo
{
/// <summary>
/// An example script to show how to interact with the Sidekick API in regards to colors at runtime.
/// </summary>
public class RuntimeColorDemo : MonoBehaviour
{
private readonly string _OUTPUT_MODEL_NAME = "Sidekick Character";
private Dictionary<string, SidekickPartPreset> _availableHeadPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private Dictionary<string, SidekickPartPreset> _availableUpperBodyPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private Dictionary<string, SidekickPartPreset> _availableLowerBodyPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private List<SidekickBodyShapePreset> _availableBodyShapes = new List<SidekickBodyShapePreset>();
private List<SidekickColorPreset> _availableColorPresets = new List<SidekickColorPreset>();
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<CharacterPartType, Dictionary<string, SidekickPart>> _partLibrary;
public TextMeshProUGUI _loadingText;
/// <inheritdoc cref="Start"/>
void Start()
{
_dbManager = new DatabaseManager();
GameObject model = Resources.Load<GameObject>("Meshes/SK_BaseModel");
Material material = Resources.Load<Material>("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<SidekickPartPreset> presets = SidekickPartPreset.GetAllByGroup(_dbManager, partGroup);
List<string> presetNames = new List<string>();
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)
{
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();
}
/// <summary>
/// Processes the change of the skin color on the character.
/// </summary>
/// <param name="image">The image tile that contains the color to change to.</param>
public void ProcessSkinColorChange(Image image)
{
ColorType colorType = ColorType.MainColor;
List<SidekickColorProperty> allProperties = SidekickColorProperty.GetAll(_dbManager);
List<SidekickColorProperty> selectedProperties = allProperties.FindAll(scp => scp.Name.ToLower().Contains("skin"));
foreach (SidekickColorProperty property in selectedProperties)
{
SidekickColorRow row = new SidekickColorRow()
{
ColorProperty = property,
MainColor = ColorUtility.ToHtmlStringRGB(image.color),
};
_sidekickRuntime.UpdateColor(colorType, row);
}
}
/// <summary>
/// Processes the change of the outfit color on the character.
/// </summary>
/// <param name="image">The image tile that contains the color to change to.</param>
public void ProcessOutfitColorChange(Image image)
{
ColorType colorType = ColorType.MainColor;
List<SidekickColorProperty> allProperties = SidekickColorProperty.GetAll(_dbManager);
List<SidekickColorProperty> selectedProperties = allProperties.FindAll(scp => scp.Name.ToLower().Contains("outfit"));
foreach (SidekickColorProperty property in selectedProperties)
{
SidekickColorRow row = new SidekickColorRow()
{
ColorProperty = property,
MainColor = ColorUtility.ToHtmlStringRGB(image.color),
};
_sidekickRuntime.UpdateColor(colorType, row);
}
}
/// <summary>
/// Updates the created character model.
/// </summary>
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 colors.
List<SidekickPartPreset> presets = new List<SidekickPartPreset>()
{
_availableHeadPresetDictionary.Values.ToArray()[_currentHeadPresetIndex],
_availableUpperBodyPresetDictionary.Values.ToArray()[_currentUpperBodyPresetIndex],
_availableLowerBodyPresetDictionary.Values.ToArray()[_currentLowerBodyPresetIndex]
};
List<SkinnedMeshRenderer> partsToUse = new List<SkinnedMeshRenderer>();
foreach (SidekickPartPreset preset in presets)
{
List<SidekickPartPresetRow> rows = SidekickPartPresetRow.GetAllByPreset(_dbManager, preset);
foreach (SidekickPartPresetRow row in rows)
{
if (!string.IsNullOrEmpty(row.PartName))
{
CharacterPartType type = Enum.Parse<CharacterPartType>(CharacterPartTypeUtils.GetTypeNameFromShortcode(row.PartType));
Dictionary<string, SidekickPart> partLocationDictionary = _partLibrary[type];
GameObject selectedPart = partLocationDictionary[row.PartName].GetPartModel();
SkinnedMeshRenderer selectedMesh = selectedPart.GetComponentInChildren<SkinnedMeshRenderer>();
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<SidekickColorPresetRow> 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);
}
/// <summary>
/// Gets a resource path for using with Resources.Load() from a full path.
/// </summary>
/// <param name="fullPath">The full path to get the resource path from.</param>
/// <returns>The resource path.</returns>
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));
}
}
}
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 UnityEngine.UI;
using Random = UnityEngine.Random;
namespace Synty.SidekickCharacters.Demo
{
/// <summary>
/// An example script to show how to interact with the Sidekick API in regards to colors at runtime.
/// </summary>
public class RuntimeColorDemo : MonoBehaviour
{
private readonly string _OUTPUT_MODEL_NAME = "Sidekick Character";
private Dictionary<string, SidekickPartPreset> _availableHeadPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private Dictionary<string, SidekickPartPreset> _availableUpperBodyPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private Dictionary<string, SidekickPartPreset> _availableLowerBodyPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private List<SidekickBodyShapePreset> _availableBodyShapes = new List<SidekickBodyShapePreset>();
private List<SidekickColorPreset> _availableColorPresets = new List<SidekickColorPreset>();
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<CharacterPartType, Dictionary<string, SidekickPart>> _partLibrary;
public TextMeshProUGUI _loadingText;
/// <inheritdoc cref="Start"/>
void Start()
{
_dbManager = new DatabaseManager();
GameObject model = Resources.Load<GameObject>("Meshes/SK_BaseModel");
Material material = Resources.Load<Material>("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<SidekickPartPreset> presets = SidekickPartPreset.GetAllByGroup(_dbManager, partGroup);
List<string> presetNames = new List<string>();
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)
{
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();
}
/// <summary>
/// Processes the change of the skin color on the character.
/// </summary>
/// <param name="image">The image tile that contains the color to change to.</param>
public void ProcessSkinColorChange(Image image)
{
ColorType colorType = ColorType.MainColor;
List<SidekickColorProperty> allProperties = SidekickColorProperty.GetAll(_dbManager);
List<SidekickColorProperty> selectedProperties = allProperties.FindAll(scp => scp.Name.ToLower().Contains("skin"));
foreach (SidekickColorProperty property in selectedProperties)
{
SidekickColorRow row = new SidekickColorRow()
{
ColorProperty = property,
MainColor = ColorUtility.ToHtmlStringRGB(image.color),
};
_sidekickRuntime.UpdateColor(colorType, row);
}
}
/// <summary>
/// Processes the change of the outfit color on the character.
/// </summary>
/// <param name="image">The image tile that contains the color to change to.</param>
public void ProcessOutfitColorChange(Image image)
{
ColorType colorType = ColorType.MainColor;
List<SidekickColorProperty> allProperties = SidekickColorProperty.GetAll(_dbManager);
List<SidekickColorProperty> selectedProperties = allProperties.FindAll(scp => scp.Name.ToLower().Contains("outfit"));
foreach (SidekickColorProperty property in selectedProperties)
{
SidekickColorRow row = new SidekickColorRow()
{
ColorProperty = property,
MainColor = ColorUtility.ToHtmlStringRGB(image.color),
};
_sidekickRuntime.UpdateColor(colorType, row);
}
}
/// <summary>
/// Updates the created character model.
/// </summary>
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 colors.
List<SidekickPartPreset> presets = new List<SidekickPartPreset>()
{
_availableHeadPresetDictionary.Values.ToArray()[_currentHeadPresetIndex],
_availableUpperBodyPresetDictionary.Values.ToArray()[_currentUpperBodyPresetIndex],
_availableLowerBodyPresetDictionary.Values.ToArray()[_currentLowerBodyPresetIndex]
};
List<SkinnedMeshRenderer> partsToUse = new List<SkinnedMeshRenderer>();
foreach (SidekickPartPreset preset in presets)
{
List<SidekickPartPresetRow> rows = SidekickPartPresetRow.GetAllByPreset(_dbManager, preset);
foreach (SidekickPartPresetRow row in rows)
{
if (!string.IsNullOrEmpty(row.PartName))
{
CharacterPartType type = Enum.Parse<CharacterPartType>(CharacterPartTypeUtils.GetTypeNameFromShortcode(row.PartType));
Dictionary<string, SidekickPart> partLocationDictionary = _partLibrary[type];
GameObject selectedPart = partLocationDictionary[row.PartName].GetPartModel();
SkinnedMeshRenderer selectedMesh = selectedPart.GetComponentInChildren<SkinnedMeshRenderer>();
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<SidekickColorPresetRow> 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);
}
/// <summary>
/// Gets a resource path for using with Resources.Load() from a full path.
/// </summary>
/// <param name="fullPath">The full path to get the resource path from.</param>
/// <returns>The resource path.</returns>
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));
}
}
}

View File

View File

@@ -1,380 +1,380 @@
using Synty.SidekickCharacters.API;
using Synty.SidekickCharacters.Database;
using Synty.SidekickCharacters.Database.DTO;
using Synty.SidekickCharacters.Enums;
using Synty.SidekickCharacters.Utils;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
namespace Synty.SidekickCharacters.Demo
{
/// <summary>
/// An example script to show how to interact with the Sidekick API in regards to parts at runtime.
/// </summary>
public class RuntimePartsDemo : MonoBehaviour
{
private readonly string _OUTPUT_MODEL_NAME = "Sidekick Character";
Dictionary<CharacterPartType, int> _partIndexDictionary = new Dictionary<CharacterPartType, int>();
Dictionary<CharacterPartType, Dictionary<string, SidekickPart>> _availablePartDictionary = new Dictionary<CharacterPartType, Dictionary<string, SidekickPart>>();
private DatabaseManager _dbManager;
private SidekickRuntime _sidekickRuntime;
private Dictionary<CharacterPartType, Dictionary<string, SidekickPart>> _partLibrary;
public TextMeshProUGUI _loadingText;
/// <inheritdoc cref="Start"/>
void Start()
{
// Create a new instance of the database manager to access database content.
_dbManager = new DatabaseManager();
// Load the base model and material required to create an instance of the Sidekick Runtime API.
GameObject model = Resources.Load<GameObject>("Meshes/SK_BaseModel");
Material material = Resources.Load<Material>("Materials/M_BaseMaterial");
_sidekickRuntime = new SidekickRuntime(model, material, null, _dbManager);
// Populate the parts list for easy access.
SidekickRuntime.PopulateToolData(_sidekickRuntime);
_partLibrary = _sidekickRuntime.MappedPartDictionary;
// For this example we are only interested in Upper Body parts, so we filter the list of all parts to only get the ones we want.
List<CharacterPartType> upperBodyParts = PartGroup.UpperBody.GetPartTypes();
foreach (CharacterPartType type in upperBodyParts)
{
_availablePartDictionary.Add(type, _partLibrary[type]);
_partIndexDictionary.Add(type, Random.Range(0, _availablePartDictionary[type].Count - 1));
}
_loadingText.enabled = false;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Torso part.
/// </summary>
public void ForwardTorso()
{
int index = _partIndexDictionary[CharacterPartType.Torso];
index++;
if (index >= _availablePartDictionary[CharacterPartType.Torso].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.Torso] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Torso part.
/// </summary>
public void BackwardTorso()
{
int index = _partIndexDictionary[CharacterPartType.Torso];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.Torso].Count - 1;
}
_partIndexDictionary[CharacterPartType.Torso] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the ArmUpperLeft part.
/// </summary>
public void ForwardUpperArmLeft()
{
int index = _partIndexDictionary[CharacterPartType.ArmUpperLeft];
index++;
if (index >= _availablePartDictionary[CharacterPartType.ArmUpperLeft].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.ArmUpperLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the ArmUpperLeft part.
/// </summary>
public void BackwardUpperArmLeft()
{
int index = _partIndexDictionary[CharacterPartType.ArmUpperLeft];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.ArmUpperLeft].Count - 1;
}
_partIndexDictionary[CharacterPartType.ArmUpperLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the ArmUpperRight part.
/// </summary>
public void ForwardUpperArmRight()
{
int index = _partIndexDictionary[CharacterPartType.ArmUpperRight];
index++;
if (index >= _availablePartDictionary[CharacterPartType.ArmUpperRight].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.ArmUpperRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the ArmUpperRight part.
/// </summary>
public void BackwardUpperArmRight()
{
int index = _partIndexDictionary[CharacterPartType.ArmUpperRight];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.ArmUpperRight].Count - 1;
}
_partIndexDictionary[CharacterPartType.ArmUpperRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the ArmLowerLeft part.
/// </summary>
public void ForwardLowerArmLeft()
{
int index = _partIndexDictionary[CharacterPartType.ArmLowerLeft];
index++;
if (index >= _availablePartDictionary[CharacterPartType.ArmLowerLeft].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.ArmLowerLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the ArmLowerLeft part.
/// </summary>
public void BackwardLowerArmLeft()
{
int index = _partIndexDictionary[CharacterPartType.ArmLowerLeft];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.ArmLowerLeft].Count - 1;
}
_partIndexDictionary[CharacterPartType.ArmLowerLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the ArmLowerRight part.
/// </summary>
public void ForwardLowerArmRight()
{
int index = _partIndexDictionary[CharacterPartType.ArmLowerRight];
index++;
if (index >= _availablePartDictionary[CharacterPartType.ArmLowerRight].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.ArmLowerRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the ArmLowerRight part.
/// </summary>
public void BackwardLowerArmRight()
{
int index = _partIndexDictionary[CharacterPartType.ArmLowerRight];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.ArmLowerRight].Count - 1;
}
_partIndexDictionary[CharacterPartType.ArmLowerRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the HandLeft part.
/// </summary>
public void ForwardHandLeft()
{
int index = _partIndexDictionary[CharacterPartType.HandLeft];
index++;
if (index >= _availablePartDictionary[CharacterPartType.HandLeft].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.HandLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the HandLeft part.
/// </summary>
public void BackwardHandLeft()
{
int index = _partIndexDictionary[CharacterPartType.HandLeft];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.HandLeft].Count - 1;
}
_partIndexDictionary[CharacterPartType.HandLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the HandRight part.
/// </summary>
public void ForwardHandRight()
{
int index = _partIndexDictionary[CharacterPartType.HandRight];
index++;
if (index >= _availablePartDictionary[CharacterPartType.HandRight].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.HandRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the HandRight part.
/// </summary>
public void BackwardHandRight()
{
int index = _partIndexDictionary[CharacterPartType.HandRight];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.HandRight].Count - 1;
}
_partIndexDictionary[CharacterPartType.HandRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the AttachmentBack part.
/// </summary>
public void ForwardBackAttachment()
{
int index = _partIndexDictionary[CharacterPartType.AttachmentBack];
index++;
if (index >= _availablePartDictionary[CharacterPartType.AttachmentBack].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.AttachmentBack] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the AttachmentBack part.
/// </summary>
public void BackwardBackAttachment()
{
int index = _partIndexDictionary[CharacterPartType.AttachmentBack];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.AttachmentBack].Count - 1;
}
_partIndexDictionary[CharacterPartType.AttachmentBack] = index;
UpdateModel();
}
/// <summary>
/// Updates the body size blends based on the slider values.
/// </summary>
/// <param name="slider">The UI slider to get the values from.</param>
public void UpdateBodySize(Slider slider)
{
// If the slider is greater than 0, then we update the Heavy blend and zero the Skinny.
if (slider.value > 0)
{
_sidekickRuntime.BodySizeHeavyBlendValue = slider.value;
_sidekickRuntime.BodySizeSkinnyBlendValue = 0;
}
// If the slider is 0 or below, we zero the Heavy blend, then we update the Skinny blend.
else
{
_sidekickRuntime.BodySizeHeavyBlendValue = 0;
_sidekickRuntime.BodySizeSkinnyBlendValue = -slider.value;
}
UpdateModel();
}
/// <summary>
/// Updates the created character model.
/// </summary>
private void UpdateModel()
{
// Create and populate the list of parts to use from the parts list.
List<SkinnedMeshRenderer> partsToUse = new List<SkinnedMeshRenderer>();
foreach (KeyValuePair<CharacterPartType, Dictionary<string, SidekickPart>> entry in _availablePartDictionary)
{
int index = _partIndexDictionary[entry.Key];
List<SidekickPart> parts = entry.Value.Values.ToList();
GameObject partContainer = null;
if (parts.Count > 0 && index < parts.Count)
{
if (index > parts.Count)
{
index = parts.Count - 1;
}
partContainer = parts[index].GetPartModel();
}
if (partContainer != null)
{
partsToUse.Add(partContainer.GetComponentInChildren<SkinnedMeshRenderer>());
}
}
// 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);
}
}
}
using Synty.SidekickCharacters.API;
using Synty.SidekickCharacters.Database;
using Synty.SidekickCharacters.Database.DTO;
using Synty.SidekickCharacters.Enums;
using Synty.SidekickCharacters.Utils;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
namespace Synty.SidekickCharacters.Demo
{
/// <summary>
/// An example script to show how to interact with the Sidekick API in regards to parts at runtime.
/// </summary>
public class RuntimePartsDemo : MonoBehaviour
{
private readonly string _OUTPUT_MODEL_NAME = "Sidekick Character";
Dictionary<CharacterPartType, int> _partIndexDictionary = new Dictionary<CharacterPartType, int>();
Dictionary<CharacterPartType, Dictionary<string, SidekickPart>> _availablePartDictionary = new Dictionary<CharacterPartType, Dictionary<string, SidekickPart>>();
private DatabaseManager _dbManager;
private SidekickRuntime _sidekickRuntime;
private Dictionary<CharacterPartType, Dictionary<string, SidekickPart>> _partLibrary;
public TextMeshProUGUI _loadingText;
/// <inheritdoc cref="Start"/>
void Start()
{
// Create a new instance of the database manager to access database content.
_dbManager = new DatabaseManager();
// Load the base model and material required to create an instance of the Sidekick Runtime API.
GameObject model = Resources.Load<GameObject>("Meshes/SK_BaseModel");
Material material = Resources.Load<Material>("Materials/M_BaseMaterial");
_sidekickRuntime = new SidekickRuntime(model, material, null, _dbManager);
// Populate the parts list for easy access.
SidekickRuntime.PopulateToolData(_sidekickRuntime);
_partLibrary = _sidekickRuntime.MappedPartDictionary;
// For this example we are only interested in Upper Body parts, so we filter the list of all parts to only get the ones we want.
List<CharacterPartType> upperBodyParts = PartGroup.UpperBody.GetPartTypes();
foreach (CharacterPartType type in upperBodyParts)
{
_availablePartDictionary.Add(type, _partLibrary[type]);
_partIndexDictionary.Add(type, Random.Range(0, _availablePartDictionary[type].Count - 1));
}
_loadingText.enabled = false;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Torso part.
/// </summary>
public void ForwardTorso()
{
int index = _partIndexDictionary[CharacterPartType.Torso];
index++;
if (index >= _availablePartDictionary[CharacterPartType.Torso].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.Torso] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Torso part.
/// </summary>
public void BackwardTorso()
{
int index = _partIndexDictionary[CharacterPartType.Torso];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.Torso].Count - 1;
}
_partIndexDictionary[CharacterPartType.Torso] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the ArmUpperLeft part.
/// </summary>
public void ForwardUpperArmLeft()
{
int index = _partIndexDictionary[CharacterPartType.ArmUpperLeft];
index++;
if (index >= _availablePartDictionary[CharacterPartType.ArmUpperLeft].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.ArmUpperLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the ArmUpperLeft part.
/// </summary>
public void BackwardUpperArmLeft()
{
int index = _partIndexDictionary[CharacterPartType.ArmUpperLeft];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.ArmUpperLeft].Count - 1;
}
_partIndexDictionary[CharacterPartType.ArmUpperLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the ArmUpperRight part.
/// </summary>
public void ForwardUpperArmRight()
{
int index = _partIndexDictionary[CharacterPartType.ArmUpperRight];
index++;
if (index >= _availablePartDictionary[CharacterPartType.ArmUpperRight].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.ArmUpperRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the ArmUpperRight part.
/// </summary>
public void BackwardUpperArmRight()
{
int index = _partIndexDictionary[CharacterPartType.ArmUpperRight];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.ArmUpperRight].Count - 1;
}
_partIndexDictionary[CharacterPartType.ArmUpperRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the ArmLowerLeft part.
/// </summary>
public void ForwardLowerArmLeft()
{
int index = _partIndexDictionary[CharacterPartType.ArmLowerLeft];
index++;
if (index >= _availablePartDictionary[CharacterPartType.ArmLowerLeft].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.ArmLowerLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the ArmLowerLeft part.
/// </summary>
public void BackwardLowerArmLeft()
{
int index = _partIndexDictionary[CharacterPartType.ArmLowerLeft];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.ArmLowerLeft].Count - 1;
}
_partIndexDictionary[CharacterPartType.ArmLowerLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the ArmLowerRight part.
/// </summary>
public void ForwardLowerArmRight()
{
int index = _partIndexDictionary[CharacterPartType.ArmLowerRight];
index++;
if (index >= _availablePartDictionary[CharacterPartType.ArmLowerRight].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.ArmLowerRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the ArmLowerRight part.
/// </summary>
public void BackwardLowerArmRight()
{
int index = _partIndexDictionary[CharacterPartType.ArmLowerRight];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.ArmLowerRight].Count - 1;
}
_partIndexDictionary[CharacterPartType.ArmLowerRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the HandLeft part.
/// </summary>
public void ForwardHandLeft()
{
int index = _partIndexDictionary[CharacterPartType.HandLeft];
index++;
if (index >= _availablePartDictionary[CharacterPartType.HandLeft].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.HandLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the HandLeft part.
/// </summary>
public void BackwardHandLeft()
{
int index = _partIndexDictionary[CharacterPartType.HandLeft];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.HandLeft].Count - 1;
}
_partIndexDictionary[CharacterPartType.HandLeft] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the HandRight part.
/// </summary>
public void ForwardHandRight()
{
int index = _partIndexDictionary[CharacterPartType.HandRight];
index++;
if (index >= _availablePartDictionary[CharacterPartType.HandRight].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.HandRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the HandRight part.
/// </summary>
public void BackwardHandRight()
{
int index = _partIndexDictionary[CharacterPartType.HandRight];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.HandRight].Count - 1;
}
_partIndexDictionary[CharacterPartType.HandRight] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the AttachmentBack part.
/// </summary>
public void ForwardBackAttachment()
{
int index = _partIndexDictionary[CharacterPartType.AttachmentBack];
index++;
if (index >= _availablePartDictionary[CharacterPartType.AttachmentBack].Count)
{
index = 0;
}
_partIndexDictionary[CharacterPartType.AttachmentBack] = index;
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the AttachmentBack part.
/// </summary>
public void BackwardBackAttachment()
{
int index = _partIndexDictionary[CharacterPartType.AttachmentBack];
index--;
if (index < 0)
{
index = _availablePartDictionary[CharacterPartType.AttachmentBack].Count - 1;
}
_partIndexDictionary[CharacterPartType.AttachmentBack] = index;
UpdateModel();
}
/// <summary>
/// Updates the body size blends based on the slider values.
/// </summary>
/// <param name="slider">The UI slider to get the values from.</param>
public void UpdateBodySize(Slider slider)
{
// If the slider is greater than 0, then we update the Heavy blend and zero the Skinny.
if (slider.value > 0)
{
_sidekickRuntime.BodySizeHeavyBlendValue = slider.value;
_sidekickRuntime.BodySizeSkinnyBlendValue = 0;
}
// If the slider is 0 or below, we zero the Heavy blend, then we update the Skinny blend.
else
{
_sidekickRuntime.BodySizeHeavyBlendValue = 0;
_sidekickRuntime.BodySizeSkinnyBlendValue = -slider.value;
}
UpdateModel();
}
/// <summary>
/// Updates the created character model.
/// </summary>
private void UpdateModel()
{
// Create and populate the list of parts to use from the parts list.
List<SkinnedMeshRenderer> partsToUse = new List<SkinnedMeshRenderer>();
foreach (KeyValuePair<CharacterPartType, Dictionary<string, SidekickPart>> entry in _availablePartDictionary)
{
int index = _partIndexDictionary[entry.Key];
List<SidekickPart> parts = entry.Value.Values.ToList();
GameObject partContainer = null;
if (parts.Count > 0 && index < parts.Count)
{
if (index > parts.Count)
{
index = parts.Count - 1;
}
partContainer = parts[index].GetPartModel();
}
if (partContainer != null)
{
partsToUse.Add(partContainer.GetComponentInChildren<SkinnedMeshRenderer>());
}
}
// 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);
}
}
}

View File

View File

@@ -1,325 +1,325 @@
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
{
/// <summary>
/// An example script to show how to interact with the Sidekick API in regards to presets at runtime.
/// </summary>
public class RuntimePresetDemo : MonoBehaviour
{
private readonly string _OUTPUT_MODEL_NAME = "Sidekick Character";
private Dictionary<string, SidekickPartPreset> _availableHeadPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private Dictionary<string, SidekickPartPreset> _availableUpperBodyPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private Dictionary<string, SidekickPartPreset> _availableLowerBodyPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private List<SidekickBodyShapePreset> _availableBodyShapes = new List<SidekickBodyShapePreset>();
private List<SidekickColorPreset> _availableColorPresets = new List<SidekickColorPreset>();
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<CharacterPartType, Dictionary<string, SidekickPart>> _partLibrary;
public TextMeshProUGUI _loadingText;
/// <inheritdoc cref="Start"/>
void Start()
{
_dbManager = new DatabaseManager();
GameObject model = Resources.Load<GameObject>("Meshes/SK_BaseModel");
Material material = Resources.Load<Material>("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<SidekickPartPreset> presets = SidekickPartPreset.GetAllByGroup(_dbManager, partGroup);
List<string> presetNames = new List<string>();
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();
}
/// <summary>
/// Handles the click on the forward button for the Head Preset.
/// </summary>
public void ForwardHeadPreset()
{
_currentHeadPresetIndex++;
if (_currentHeadPresetIndex >= _availableHeadPresetDictionary.Count)
{
_currentHeadPresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Head Preset.
/// </summary>
public void BackwardHeadPreset()
{
_currentHeadPresetIndex--;
if (_currentHeadPresetIndex < 0)
{
_currentHeadPresetIndex = _availableHeadPresetDictionary.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Upper Body Preset.
/// </summary>
public void ForwardUpperBodyPreset()
{
_currentUpperBodyPresetIndex++;
if (_currentUpperBodyPresetIndex >= _availableUpperBodyPresetDictionary.Count)
{
_currentUpperBodyPresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Upper Body Preset.
/// </summary>
public void BackwardUpperBodyPreset()
{
_currentUpperBodyPresetIndex--;
if (_currentUpperBodyPresetIndex < 0)
{
_currentUpperBodyPresetIndex = _availableUpperBodyPresetDictionary.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Lower Body Preset.
/// </summary>
public void ForwardLowerBodyPreset()
{
_currentLowerBodyPresetIndex++;
if (_currentLowerBodyPresetIndex >= _availableLowerBodyPresetDictionary.Count)
{
_currentLowerBodyPresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Lower Body Preset.
/// </summary>
public void BackwardLowerBodyPreset()
{
_currentLowerBodyPresetIndex--;
if (_currentLowerBodyPresetIndex < 0)
{
_currentLowerBodyPresetIndex = _availableLowerBodyPresetDictionary.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Body Shape Preset.
/// </summary>
public void ForwardBodyShapePreset()
{
_currentBodyShapePresetIndex++;
if (_currentBodyShapePresetIndex >= _availableBodyShapes.Count)
{
_currentBodyShapePresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Body Shape Preset.
/// </summary>
public void BackwardBodyShapePreset()
{
_currentBodyShapePresetIndex--;
if (_currentBodyShapePresetIndex < 0)
{
_currentBodyShapePresetIndex = _availableBodyShapes.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Color Preset.
/// </summary>
public void ForwardColorPreset()
{
_currentColorPresetIndex++;
if (_currentColorPresetIndex >= _availableColorPresets.Count)
{
_currentColorPresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Color Preset.
/// </summary>
public void BackwardColorPreset()
{
_currentColorPresetIndex--;
if (_currentColorPresetIndex < 0)
{
_currentColorPresetIndex = _availableColorPresets.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Updates the created character model.
/// </summary>
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<SidekickPartPreset> presets = new List<SidekickPartPreset>()
{
_availableHeadPresetDictionary.Values.ToArray()[_currentHeadPresetIndex],
_availableUpperBodyPresetDictionary.Values.ToArray()[_currentUpperBodyPresetIndex],
_availableLowerBodyPresetDictionary.Values.ToArray()[_currentLowerBodyPresetIndex]
};
List<SkinnedMeshRenderer> partsToUse = new List<SkinnedMeshRenderer>();
foreach (SidekickPartPreset preset in presets)
{
List<SidekickPartPresetRow> rows = SidekickPartPresetRow.GetAllByPreset(_dbManager, preset);
foreach (SidekickPartPresetRow row in rows)
{
if (!string.IsNullOrEmpty(row.PartName))
{
CharacterPartType type = Enum.Parse<CharacterPartType>(CharacterPartTypeUtils.GetTypeNameFromShortcode(row.PartType));
Dictionary<string, SidekickPart> partLocationDictionary = _partLibrary[type];
GameObject selectedPart = partLocationDictionary[row.PartName].GetPartModel();
SkinnedMeshRenderer selectedMesh = selectedPart.GetComponentInChildren<SkinnedMeshRenderer>();
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<SidekickColorPresetRow> 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);
}
/// <summary>
/// Gets a resource path for using with Resources.Load() from a full path.
/// </summary>
/// <param name="fullPath">The full path to get the resource path from.</param>
/// <returns>The resource path.</returns>
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));
}
}
}
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
{
/// <summary>
/// An example script to show how to interact with the Sidekick API in regards to presets at runtime.
/// </summary>
public class RuntimePresetDemo : MonoBehaviour
{
private readonly string _OUTPUT_MODEL_NAME = "Sidekick Character";
private Dictionary<string, SidekickPartPreset> _availableHeadPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private Dictionary<string, SidekickPartPreset> _availableUpperBodyPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private Dictionary<string, SidekickPartPreset> _availableLowerBodyPresetDictionary = new Dictionary<string, SidekickPartPreset>();
private List<SidekickBodyShapePreset> _availableBodyShapes = new List<SidekickBodyShapePreset>();
private List<SidekickColorPreset> _availableColorPresets = new List<SidekickColorPreset>();
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<CharacterPartType, Dictionary<string, SidekickPart>> _partLibrary;
public TextMeshProUGUI _loadingText;
/// <inheritdoc cref="Start"/>
void Start()
{
_dbManager = new DatabaseManager();
GameObject model = Resources.Load<GameObject>("Meshes/SK_BaseModel");
Material material = Resources.Load<Material>("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<SidekickPartPreset> presets = SidekickPartPreset.GetAllByGroup(_dbManager, partGroup);
List<string> presetNames = new List<string>();
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();
}
/// <summary>
/// Handles the click on the forward button for the Head Preset.
/// </summary>
public void ForwardHeadPreset()
{
_currentHeadPresetIndex++;
if (_currentHeadPresetIndex >= _availableHeadPresetDictionary.Count)
{
_currentHeadPresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Head Preset.
/// </summary>
public void BackwardHeadPreset()
{
_currentHeadPresetIndex--;
if (_currentHeadPresetIndex < 0)
{
_currentHeadPresetIndex = _availableHeadPresetDictionary.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Upper Body Preset.
/// </summary>
public void ForwardUpperBodyPreset()
{
_currentUpperBodyPresetIndex++;
if (_currentUpperBodyPresetIndex >= _availableUpperBodyPresetDictionary.Count)
{
_currentUpperBodyPresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Upper Body Preset.
/// </summary>
public void BackwardUpperBodyPreset()
{
_currentUpperBodyPresetIndex--;
if (_currentUpperBodyPresetIndex < 0)
{
_currentUpperBodyPresetIndex = _availableUpperBodyPresetDictionary.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Lower Body Preset.
/// </summary>
public void ForwardLowerBodyPreset()
{
_currentLowerBodyPresetIndex++;
if (_currentLowerBodyPresetIndex >= _availableLowerBodyPresetDictionary.Count)
{
_currentLowerBodyPresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Lower Body Preset.
/// </summary>
public void BackwardLowerBodyPreset()
{
_currentLowerBodyPresetIndex--;
if (_currentLowerBodyPresetIndex < 0)
{
_currentLowerBodyPresetIndex = _availableLowerBodyPresetDictionary.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Body Shape Preset.
/// </summary>
public void ForwardBodyShapePreset()
{
_currentBodyShapePresetIndex++;
if (_currentBodyShapePresetIndex >= _availableBodyShapes.Count)
{
_currentBodyShapePresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Body Shape Preset.
/// </summary>
public void BackwardBodyShapePreset()
{
_currentBodyShapePresetIndex--;
if (_currentBodyShapePresetIndex < 0)
{
_currentBodyShapePresetIndex = _availableBodyShapes.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the forward button for the Color Preset.
/// </summary>
public void ForwardColorPreset()
{
_currentColorPresetIndex++;
if (_currentColorPresetIndex >= _availableColorPresets.Count)
{
_currentColorPresetIndex = 0;
}
UpdateModel();
}
/// <summary>
/// Handles the click on the backward button for the Color Preset.
/// </summary>
public void BackwardColorPreset()
{
_currentColorPresetIndex--;
if (_currentColorPresetIndex < 0)
{
_currentColorPresetIndex = _availableColorPresets.Count - 1;
}
UpdateModel();
}
/// <summary>
/// Updates the created character model.
/// </summary>
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<SidekickPartPreset> presets = new List<SidekickPartPreset>()
{
_availableHeadPresetDictionary.Values.ToArray()[_currentHeadPresetIndex],
_availableUpperBodyPresetDictionary.Values.ToArray()[_currentUpperBodyPresetIndex],
_availableLowerBodyPresetDictionary.Values.ToArray()[_currentLowerBodyPresetIndex]
};
List<SkinnedMeshRenderer> partsToUse = new List<SkinnedMeshRenderer>();
foreach (SidekickPartPreset preset in presets)
{
List<SidekickPartPresetRow> rows = SidekickPartPresetRow.GetAllByPreset(_dbManager, preset);
foreach (SidekickPartPresetRow row in rows)
{
if (!string.IsNullOrEmpty(row.PartName))
{
CharacterPartType type = Enum.Parse<CharacterPartType>(CharacterPartTypeUtils.GetTypeNameFromShortcode(row.PartType));
Dictionary<string, SidekickPart> partLocationDictionary = _partLibrary[type];
GameObject selectedPart = partLocationDictionary[row.PartName].GetPartModel();
SkinnedMeshRenderer selectedMesh = selectedPart.GetComponentInChildren<SkinnedMeshRenderer>();
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<SidekickColorPresetRow> 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);
}
/// <summary>
/// Gets a resource path for using with Resources.Load() from a full path.
/// </summary>
/// <param name="fullPath">The full path to get the resource path from.</param>
/// <returns>The resource path.</returns>
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));
}
}
}

View File