chore: Assets 디렉토리 구조 정리 및 네이밍 컨벤션 적용

- Assets/_Game/ 하위로 게임 에셋 통합
- External/ 패키지 벤더별 분류 (Synty, Animations, UI)
- 에셋 네이밍 컨벤션 확립 및 적용
  (Data_Skill_, Data_SkillEffect_, Prefab_, Anim_, Model_, BT_ 등)
- pre-commit hook으로 네이밍 컨벤션 자동 검사 추가
- RESTRUCTURE_CHECKLIST.md 작성

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 19:08:27 +09:00
parent 309bf5f48b
commit c265f980db
17251 changed files with 2630777 additions and 206 deletions

View File

@@ -0,0 +1,189 @@
// Copyright (c) 2024 Synty Studios Limited. All rights reserved.
//
// Use of this software is subject to the terms and conditions of the Synty Studios End User Licence Agreement (EULA)
// available at: https://syntystore.com/pages/end-user-licence-agreement
//
// For additional details, see the LICENSE.MD file bundled with this software.
using Synty.SidekickCharacters.SkinnedMesh;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Synty.SidekickCharacters.Utils
{
public static class BlendShapeUtils
{
/// <summary>
/// Collects all of the blend shape data from a given skinnedMesh and Mesh, and stores them as blend shape data.
/// </summary>
/// <param name="mesh">The mesh to get the blend shape data from.</param>
/// <param name="skinnedMesh">The skinned mesh to get the blend shape data from.</param>
/// <param name="excludedBlendNames">The blend shape names, or partial names to exclude from the data.</param>
/// <param name="verticesCountStartIndex">The start position for the delta vertices index.</param>
/// <param name="allBlendShapeData">Passed in blendshape data used </param>
/// <returns>A list of BlendShapeData from all blend shape data on the mesh and skinned mesh.</returns>
public static List<BlendShapeData> GetBlendShapeData(
Mesh mesh,
SkinnedMeshRenderer skinnedMesh,
string[] excludedBlendNames,
int verticesCountStartIndex,
List<BlendShapeData> allBlendShapeData
)
{
// Debug.Log("Blend count in getter: " + allBlendShapeData.Count);
int totalVerticesVerifiedAtHereForBlendShapes = verticesCountStartIndex;
string[] blendShapes = new string[skinnedMesh.sharedMesh.blendShapeCount];
for (int i = 0; i < skinnedMesh.sharedMesh.blendShapeCount; i++)
{
string blendShapeName = skinnedMesh.sharedMesh.GetBlendShapeName(i);
if (excludedBlendNames.All(ebn => !blendShapeName.Contains(ebn)))
{
blendShapes[i] = blendShapeName;
}
}
for (int i = 0; i < blendShapes.Length; i++)
{
if (blendShapes[i] == null)
{
continue;
}
string bsn = blendShapes[i];
int index = bsn.IndexOf('.') + 1;
bsn = "MESHBlends." + bsn.Substring(index, bsn.Length - index);
int blendIndex = skinnedMesh.sharedMesh.GetBlendShapeIndex(blendShapes[i]);
BlendShapeData blendShapeData = new BlendShapeData
{
blendShapeFrameName = bsn,
blendShapeFrameIndex = blendIndex
};
if (allBlendShapeData.Count > 0 && allBlendShapeData.Contains(blendShapeData))
{
BlendShapeData existingData = allBlendShapeData.Find(data => data.Equals(blendShapeData));
if (existingData != null)
{
blendShapeData = existingData;
allBlendShapeData.Remove(blendShapeData);
}
}
blendShapeData.blendShapeCurrentValue = skinnedMesh.GetBlendShapeWeight(blendIndex);
Mesh sharedMesh = skinnedMesh.sharedMesh;
int framesCount = sharedMesh.GetBlendShapeFrameCount(blendIndex);
Vector3[] originalDeltaVertices = new Vector3[sharedMesh.vertexCount];
Vector3[] originalDeltaNormals = new Vector3[sharedMesh.vertexCount];
Vector3[] originalDeltaTangents = new Vector3[sharedMesh.vertexCount];
Vector3[] finalDeltaVertices = new Vector3[mesh.vertexCount];
Vector3[] finalDeltaNormals = new Vector3[mesh.vertexCount];
Vector3[] finalDeltaTangents = new Vector3[mesh.vertexCount];
if (blendShapeData.startDeltaVertices.Count < 1)
{
blendShapeData.startDeltaVertices.AddRange(finalDeltaVertices);
blendShapeData.startDeltaNormals.AddRange(finalDeltaNormals);
blendShapeData.startDeltaTangents.AddRange(finalDeltaTangents);
blendShapeData.finalDeltaVertices.AddRange(finalDeltaVertices);
blendShapeData.finalDeltaNormals.AddRange(finalDeltaNormals);
blendShapeData.finalDeltaTangents.AddRange(finalDeltaTangents);
}
if (skinnedMesh.sharedMesh.GetBlendShapeIndex(blendShapes[i]) != -1)
{
skinnedMesh.sharedMesh.GetBlendShapeFrameVertices(
blendIndex,
framesCount - 1,
originalDeltaVertices,
originalDeltaNormals,
originalDeltaTangents
);
}
for (int x = 0; x < originalDeltaVertices.Length; x++)
{
blendShapeData.finalDeltaVertices[x + totalVerticesVerifiedAtHereForBlendShapes] = originalDeltaVertices[x];
}
for (int x = 0; x < originalDeltaNormals.Length; x++)
{
blendShapeData.finalDeltaNormals[x + totalVerticesVerifiedAtHereForBlendShapes] = originalDeltaNormals[x];
}
for (int x = 0; x < originalDeltaTangents.Length; x++)
{
blendShapeData.finalDeltaTangents[x + totalVerticesVerifiedAtHereForBlendShapes] = originalDeltaTangents[x];
}
allBlendShapeData.Add(blendShapeData);
}
return allBlendShapeData;
}
/// <summary>
/// Restores the given blend shape data to the given mesh and skinned mesh.
/// </summary>
/// <param name="blendData">The blend shape data to restore.</param>
/// <param name="meshToRestoreTo">The mesh to restore the blend shape data to.</param>
/// <param name="meshRenderer">The mesh renderer that the mesh belongs to.</param>
public static void RestoreBlendShapeData(List<BlendShapeData> blendData, Mesh meshToRestoreTo, SkinnedMeshRenderer meshRenderer)
{
Dictionary<string, int> alreadyAddedBlendShapesNames = new Dictionary<string, int>();
foreach (BlendShapeData blendShape in blendData)
{
string blendShapeName = blendShape.blendShapeFrameName;
if (alreadyAddedBlendShapesNames.TryGetValue(blendShape.blendShapeFrameName, out int name))
{
blendShapeName += " (" + name + ")";
}
meshToRestoreTo.AddBlendShapeFrame(
blendShapeName,
0.0f,
blendShape.startDeltaVertices.ToArray(),
blendShape.startDeltaNormals.ToArray(),
blendShape.startDeltaTangents.ToArray()
);
meshToRestoreTo.AddBlendShapeFrame(
blendShapeName,
100.0f,
blendShape.finalDeltaVertices.ToArray(),
blendShape.finalDeltaNormals.ToArray(),
blendShape.finalDeltaTangents.ToArray()
);
blendShape.blendShapeNameOnCombinedMesh = blendShapeName;
if (alreadyAddedBlendShapesNames.ContainsKey(blendShape.blendShapeFrameName))
{
alreadyAddedBlendShapesNames[blendShape.blendShapeFrameName] += 1;
}
else
{
alreadyAddedBlendShapesNames.Add(blendShape.blendShapeFrameName, 0);
}
}
foreach (BlendShapeData blendShape in blendData)
{
meshRenderer.SetBlendShapeWeight(
meshToRestoreTo.GetBlendShapeIndex(blendShape.blendShapeFrameName),
blendShape.blendShapeCurrentValue
);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1381ccc320f2c774e9230410f19ae2ed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,376 @@
// Copyright (c) 2024 Synty Studios Limited. All rights reserved.
//
// Use of this software is subject to the terms and conditions of the Synty Studios End User Licence Agreement (EULA)
// available at: https://syntystore.com/pages/end-user-licence-agreement
//
// For additional details, see the LICENSE.MD file bundled with this software.
using Synty.SidekickCharacters.Enums;
using System;
namespace Synty.SidekickCharacters.Utils
{
/// <summary>
/// A collection of utility methods related to operations on CharacterPartType enum values.
/// </summary>
public static class CharacterPartTypeUtils
{
/// <summary>
/// Get the part group that the given part type belongs to
/// </summary>
/// <param name="basePartType">The part type to get the group of</param>
/// <returns>The PartGroup the part type belongs to</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown if the part type is unrecognised</exception>
public static PartGroup GetPartGroup(this CharacterPartType basePartType)
{
switch (basePartType)
{
case CharacterPartType.Head:
case CharacterPartType.Hair:
case CharacterPartType.EyebrowLeft:
case CharacterPartType.EyebrowRight:
case CharacterPartType.EyeLeft:
case CharacterPartType.EyeRight:
case CharacterPartType.EarLeft:
case CharacterPartType.EarRight:
case CharacterPartType.FacialHair:
case CharacterPartType.AttachmentHead:
case CharacterPartType.AttachmentFace:
case CharacterPartType.Nose:
case CharacterPartType.Teeth:
case CharacterPartType.Tongue:
return PartGroup.Head;
case CharacterPartType.Torso:
case CharacterPartType.ArmUpperLeft:
case CharacterPartType.ArmUpperRight:
case CharacterPartType.ArmLowerLeft:
case CharacterPartType.ArmLowerRight:
case CharacterPartType.HandLeft:
case CharacterPartType.HandRight:
case CharacterPartType.AttachmentBack:
case CharacterPartType.AttachmentShoulderLeft:
case CharacterPartType.AttachmentShoulderRight:
case CharacterPartType.AttachmentElbowLeft:
case CharacterPartType.AttachmentElbowRight:
case CharacterPartType.Wrap:
return PartGroup.UpperBody;
case CharacterPartType.Hips:
case CharacterPartType.LegLeft:
case CharacterPartType.LegRight:
case CharacterPartType.FootLeft:
case CharacterPartType.FootRight:
case CharacterPartType.AttachmentHipsFront:
case CharacterPartType.AttachmentHipsBack:
case CharacterPartType.AttachmentHipsLeft:
case CharacterPartType.AttachmentHipsRight:
case CharacterPartType.AttachmentKneeLeft:
case CharacterPartType.AttachmentKneeRight:
return PartGroup.LowerBody;
default:
throw new ArgumentOutOfRangeException(nameof(basePartType), basePartType, null);
}
}
/// <summary>
/// Checks if the given part type is a species specific part or not.
/// </summary>
/// <param name="partType">The part type to check.</param>
/// <returns>True if a species specific part type; otherwise false.</returns>
public static bool IsSpeciesSpecificPartType(this CharacterPartType partType)
{
switch (partType)
{
case CharacterPartType.Head:
case CharacterPartType.Hair:
case CharacterPartType.EyebrowLeft:
case CharacterPartType.EyebrowRight:
case CharacterPartType.EyeLeft:
case CharacterPartType.EyeRight:
case CharacterPartType.EarLeft:
case CharacterPartType.EarRight:
case CharacterPartType.FacialHair:
case CharacterPartType.Nose:
case CharacterPartType.Teeth:
case CharacterPartType.Tongue:
return true;
default:
return false;
}
}
/// <summary>
/// Gets the string value of the part type from a part short code.
/// </summary>
/// <param name="shortCode">The short code to get the part type name for.</param>
/// <returns>The part type name for the given short code.</returns>
public static string GetTypeNameFromShortcode(string shortCode)
{
switch (shortCode)
{
case "01HEAD":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.Head);
case "02HAIR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.Hair);
case "03EBRL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.EyebrowLeft);
case "04EBRR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.EyebrowRight);
case "05EYEL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.EyeLeft);
case "06EYER":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.EyeRight);
case "07EARL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.EarLeft);
case "08EARR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.EarRight);
case "09FCHR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.FacialHair);
case "10TORS":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.Torso);
case "11AUPL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.ArmUpperLeft);
case "12AUPR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.ArmUpperRight);
case "13ALWL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.ArmLowerLeft);
case "14ALWR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.ArmLowerRight);
case "15HNDL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.HandLeft);
case "16HNDR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.HandRight);
case "17HIPS":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.Hips);
case "18LEGL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.LegLeft);
case "19LEGR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.LegRight);
case "20FOTL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.FootLeft);
case "21FOTR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.FootRight);
case "22AHED":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentHead);
case "23AFAC":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentFace);
case "24ABAC":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentBack);
case "25AHPF":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentHipsFront);
case "26AHPB":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentHipsBack);
case "27AHPL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentHipsLeft);
case "28AHPR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentHipsRight);
case "29ASHL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentShoulderLeft);
case "30ASHR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentShoulderRight);
case "31AEBL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentElbowLeft);
case "32AEBR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentElbowRight);
case "33AKNL":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentKneeLeft);
case "34AKNR":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.AttachmentKneeRight);
case "35NOSE":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.Nose);
case "36TETH":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.Teeth);
case "37TONG":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.Tongue);
case "38WRAP":
return Enum.GetName(typeof(CharacterPartType), CharacterPartType.Wrap);
default:
return shortCode;
}
}
/// <summary>
/// Returns the part type string based onm the CharacterPartType
/// </summary>
/// <param name="type">The CharacterPartType to get the part type string from</param>
/// <returns>The part type string</returns>
public static string GetPartTypeString(CharacterPartType type)
{
switch (type)
{
case CharacterPartType.Head:
return "01HEAD";
case CharacterPartType.Hair:
return "02HAIR";
case CharacterPartType.EyebrowLeft:
return "03EBRL";
case CharacterPartType.EyebrowRight:
return "04EBRR";
case CharacterPartType.EyeLeft:
return "05EYEL";
case CharacterPartType.EyeRight:
return "06EYER";
case CharacterPartType.EarLeft:
return "07EARL";
case CharacterPartType.EarRight:
return "08EARR";
case CharacterPartType.FacialHair:
return "09FCHR";
case CharacterPartType.Torso:
return "10TORS";
case CharacterPartType.ArmUpperLeft:
return "11AUPL";
case CharacterPartType.ArmUpperRight:
return "12AUPR";
case CharacterPartType.ArmLowerLeft:
return "13ALWL";
case CharacterPartType.ArmLowerRight:
return "14ALWR";
case CharacterPartType.HandLeft:
return "15HNDL";
case CharacterPartType.HandRight:
return "16HNDR";
case CharacterPartType.Hips:
return "17HIPS";
case CharacterPartType.LegLeft:
return "18LEGL";
case CharacterPartType.LegRight:
return "19LEGR";
case CharacterPartType.FootLeft:
return "20FOTL";
case CharacterPartType.FootRight:
return "21FOTR";
case CharacterPartType.AttachmentHead:
return "22AHED";
case CharacterPartType.AttachmentFace:
return "23AFAC";
case CharacterPartType.AttachmentBack:
return "24ABAC";
case CharacterPartType.AttachmentHipsFront:
return "25AHPF";
case CharacterPartType.AttachmentHipsBack:
return "26AHPB";
case CharacterPartType.AttachmentHipsLeft:
return "27AHPL";
case CharacterPartType.AttachmentHipsRight:
return "28AHPR";
case CharacterPartType.AttachmentShoulderLeft:
return "29ASHL";
case CharacterPartType.AttachmentShoulderRight:
return "30ASHR";
case CharacterPartType.AttachmentElbowLeft:
return "31AEBL";
case CharacterPartType.AttachmentElbowRight:
return "32AEBR";
case CharacterPartType.AttachmentKneeLeft:
return "33AKNL";
case CharacterPartType.AttachmentKneeRight:
return "34AKNR";
case CharacterPartType.Nose:
return "35NOSE";
case CharacterPartType.Teeth:
return "36TETH";
case CharacterPartType.Tongue:
return "37TONG";
case CharacterPartType.Wrap:
return "38WRAP";
default:
return null;
}
}
/// <summary>
/// Returns the tool tip text for the given character part type.
/// </summary>
/// <param name="partType">The character part type to get the tooltip for.</param>
/// <returns>The tooltip text for the given character part type.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown if an invalid character part type is provided.</exception>
public static string GetTooltipForPartType(this CharacterPartType partType)
{
switch (partType)
{
case CharacterPartType.Head:
return "A character part that makes up the base of the head area";
case CharacterPartType.Hair:
return "A character part makes up hair on the top of a character's head";
case CharacterPartType.EyebrowLeft:
return "A character part that is above the eyes as an eyebrows";
case CharacterPartType.EyebrowRight:
return "A character part that is above the eyes as an eyebrows";
case CharacterPartType.EyeLeft:
return "A character part that acts as an eye for the character";
case CharacterPartType.EyeRight:
return "A character part that acts as an eye for the character";
case CharacterPartType.EarLeft:
return "A character part that is attached to the side of the head as an ear";
case CharacterPartType.EarRight:
return "A character part that is attached to the side of the head as an ear";
case CharacterPartType.FacialHair:
return "A character part that is on the face as facial hair";
case CharacterPartType.Torso:
return "A character part that sits at the center of the character as the torso";
case CharacterPartType.ArmUpperLeft:
return "A character part that is attached to the torso as the upper arm";
case CharacterPartType.ArmUpperRight:
return "A character part that is attached to the torso as the upper arm";
case CharacterPartType.ArmLowerLeft:
return "A character part that is attached to the upper arm as the lower arm";
case CharacterPartType.ArmLowerRight:
return "A character part that is attached to the upper arm as the lower arm";
case CharacterPartType.HandLeft:
return "A character part that is attached to the lower arm as a hand";
case CharacterPartType.HandRight:
return "A character part that is attached to the lower arm as a hand";
case CharacterPartType.Hips:
return "A character part that sits below the torso as the hips of the character";
case CharacterPartType.LegLeft:
return "A character part that is attached to the hips as a left leg of the character";
case CharacterPartType.LegRight:
return "A character part that is attached to the hips as a right leg of the character";
case CharacterPartType.FootLeft:
return "A character part that is attached to the lower leg as a left foot of the character";
case CharacterPartType.FootRight:
return "A character part that is attached to the lower leg as a right foot of the character";
case CharacterPartType.AttachmentHead:
return "The head attachment is a part that covers the head (for example - hat, helmet, mask etc)";
case CharacterPartType.AttachmentFace:
return "The face attachment is a part that covers the face but doesnt cover the full head like a head attachment (for example - glasses, VRheadset, eye patch etc)";
case CharacterPartType.AttachmentBack:
return "A character part that is attached to the back of the torso";
case CharacterPartType.AttachmentHipsFront:
return "A character part that sit at the front of the hips as a front hip attachment";
case CharacterPartType.AttachmentHipsBack:
return "A character part that sit at the back of the hips as a back hip attachment";
case CharacterPartType.AttachmentHipsLeft:
return "A character part that sit on the left side of the hips as a left hip attachment";
case CharacterPartType.AttachmentHipsRight:
return "A character part that sit on the right side of the hips as a right hip attachment";
case CharacterPartType.AttachmentShoulderLeft:
return "A character part that is attached to the left shoulder of the character";
case CharacterPartType.AttachmentShoulderRight:
return "A character part that is attached to the right shoulder of the character";
case CharacterPartType.AttachmentElbowLeft:
return "A character part that is attached to the left elbow of the character";
case CharacterPartType.AttachmentElbowRight:
return "A character part that is attached to the right elbow of the character";
case CharacterPartType.AttachmentKneeLeft:
return "A character part that is attached to the left knee of the character";
case CharacterPartType.AttachmentKneeRight:
return "A character part that is attached to the right knee of the character";
case CharacterPartType.Nose:
return "A character part that sits in the middle of the face as a nose";
case CharacterPartType.Teeth:
return "A character part that sits in the mouth area of a character as teeth";
case CharacterPartType.Tongue:
return "A character part that sits in the mouth area as a tongue";
case CharacterPartType.Wrap:
return "A character part that that covers the chest of feminine characters. Only shown when required.";
default:
throw new ArgumentOutOfRangeException(nameof(partType), partType, "Invalid part type provided");
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aa1b2eb3cd54589479e6ef52083b6d9d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,137 @@
// Copyright (c) 2024 Synty Studios Limited. All rights reserved.
//
// Use of this software is subject to the terms and conditions of the Synty Studios End User Licence Agreement (EULA)
// available at: https://syntystore.com/pages/end-user-licence-agreement
//
// For additional details, see the LICENSE.MD file bundled with this software.
using Synty.SidekickCharacters.Enums;
using System;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Utils
{
/// <summary>
/// A collection of utility methods related to operations on ColorPartType enum values.
/// </summary>
public static class ColorPartTypeUtils
{
/// <summary>
/// Get the part types that the given color part type represents
/// </summary>
/// <param name="basePartType">The part type to get the associated types of</param>
/// <returns>A List of part types that belongs to this ColorPartType</returns>
public static List<ColorPartType> GetPartTypes(this ColorPartType basePartType)
{
switch (basePartType)
{
case ColorPartType.AllParts:
return new List<ColorPartType>
{
ColorPartType.Head,
ColorPartType.Hair,
ColorPartType.EyebrowLeft,
ColorPartType.EyebrowRight,
ColorPartType.EyeLeft,
ColorPartType.EyeRight,
ColorPartType.EarLeft,
ColorPartType.EarRight,
ColorPartType.FacialHair,
ColorPartType.Torso,
ColorPartType.ArmUpperLeft,
ColorPartType.ArmUpperRight,
ColorPartType.ArmLowerLeft,
ColorPartType.ArmLowerRight,
ColorPartType.HandLeft,
ColorPartType.HandRight,
ColorPartType.Hips,
ColorPartType.LegLeft,
ColorPartType.LegRight,
ColorPartType.FootLeft,
ColorPartType.FootRight,
ColorPartType.AttachmentHead,
ColorPartType.AttachmentFace,
ColorPartType.AttachmentBack,
ColorPartType.AttachmentHipsFront,
ColorPartType.AttachmentHipsBack,
ColorPartType.AttachmentHipsLeft,
ColorPartType.AttachmentHipsRight,
ColorPartType.AttachmentShoulderLeft,
ColorPartType.AttachmentShoulderRight,
ColorPartType.AttachmentElbowLeft,
ColorPartType.AttachmentElbowRight,
ColorPartType.AttachmentKneeLeft,
ColorPartType.AttachmentKneeRight,
ColorPartType.Nose,
ColorPartType.Teeth,
ColorPartType.Tongue,
// ColorPartType.Wrap,
// ColorPartType.AttachmentHandLeft,
// ColorPartType.AttachmentHandRight,
};
case ColorPartType.CharacterHead:
return new List<ColorPartType>
{
ColorPartType.Head,
ColorPartType.Hair,
ColorPartType.EyebrowLeft,
ColorPartType.EyebrowRight,
ColorPartType.EyeLeft,
ColorPartType.EyeRight,
ColorPartType.EarLeft,
ColorPartType.EarRight,
ColorPartType.FacialHair,
ColorPartType.AttachmentHead,
ColorPartType.AttachmentFace,
ColorPartType.Nose,
ColorPartType.Teeth,
ColorPartType.Tongue,
};
case ColorPartType.CharacterUpperBody:
return new List<ColorPartType>
{
ColorPartType.Torso,
// ColorPartType.Wrap,
ColorPartType.ArmUpperLeft,
ColorPartType.ArmUpperRight,
ColorPartType.ArmLowerLeft,
ColorPartType.ArmLowerRight,
ColorPartType.HandLeft,
ColorPartType.HandRight,
ColorPartType.AttachmentBack,
ColorPartType.AttachmentShoulderLeft,
ColorPartType.AttachmentShoulderRight,
ColorPartType.AttachmentElbowLeft,
ColorPartType.AttachmentElbowRight,
// ColorPartType.AttachmentHandLeft,
// ColorPartType.AttachmentHandRight,
};
case ColorPartType.CharacterLowerBody:
return new List<ColorPartType>
{
ColorPartType.Hips,
ColorPartType.LegLeft,
ColorPartType.LegRight,
ColorPartType.FootLeft,
ColorPartType.FootRight,
ColorPartType.AttachmentHipsFront,
ColorPartType.AttachmentHipsBack,
ColorPartType.AttachmentHipsLeft,
ColorPartType.AttachmentHipsRight,
ColorPartType.AttachmentKneeLeft,
ColorPartType.AttachmentKneeRight,
};
default:
// if it's not a group, then it only represents itself, so only return itself
return new List<ColorPartType>
{
basePartType,
};
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f5f03d5acc7447ec89651c5ca2b96d98
timeCreated: 1724379445

View File

@@ -0,0 +1,46 @@
// Copyright (c) 2024 Synty Studios Limited. All rights reserved.
//
// Use of this software is subject to the terms and conditions of the Synty Studios End User Licence Agreement (EULA)
// available at: https://syntystore.com/pages/end-user-licence-agreement
//
// For additional details, see the LICENSE.MD file bundled with this software.
using UnityEngine;
namespace Synty.SidekickCharacters.Utils
{
/// <summary>
/// A collection of utility methods related to operations on Meshes.
/// </summary>
public class MeshUtils
{
/// <summary>
/// Creates and returns a copy of the passed in Mesh.
/// </summary>
/// <param name="mesh">The mesh to copy.</param>
/// <returns>A copy of the passed in Mesh.</returns>
public static Mesh CopyMesh(Mesh mesh)
{
Mesh newMesh = new Mesh
{
name = mesh.name,
vertices = mesh.vertices,
triangles = mesh.triangles,
uv = mesh.uv,
uv2 = mesh.uv2,
uv3 = mesh.uv3,
uv4 = mesh.uv4,
uv5 = mesh.uv5,
uv6 = mesh.uv6,
uv7 = mesh.uv7,
uv8 = mesh.uv8,
normals = mesh.normals,
colors = mesh.colors,
tangents = mesh.tangents,
boneWeights = mesh.boneWeights,
bindposes = mesh.bindposes
};
return newMesh;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e6a4d27caa9a9874a8d0669c7f8579ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
// Copyright (c) 2024 Synty Studios Limited. All rights reserved.
//
// Use of this software is subject to the terms and conditions of the Synty Studios End User Licence Agreement (EULA)
// available at: https://syntystore.com/pages/end-user-licence-agreement
//
// For additional details, see the LICENSE.MD file bundled with this software.
using Synty.SidekickCharacters.Enums;
using System;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Utils
{
/// <summary>
/// A collection of utility methods related to operations on PartGroup enum values.
/// </summary>
public static class PartGroupUtils
{
/// <summary>
/// Get the part types that the given part group contains
/// </summary>
/// <param name="basePartGroup">The part group to get the types of</param>
/// <returns>A List of part types that belongs to this PartGroup</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown if the part group is unrecognised</exception>
public static List<CharacterPartType> GetPartTypes(this PartGroup basePartGroup)
{
switch (basePartGroup)
{
case PartGroup.Head:
return new List<CharacterPartType>
{
CharacterPartType.Head,
CharacterPartType.Hair,
CharacterPartType.EyebrowLeft,
CharacterPartType.EyebrowRight,
CharacterPartType.EyeLeft,
CharacterPartType.EyeRight,
CharacterPartType.EarLeft,
CharacterPartType.EarRight,
CharacterPartType.FacialHair,
CharacterPartType.AttachmentHead,
CharacterPartType.AttachmentFace,
CharacterPartType.Nose,
CharacterPartType.Teeth,
CharacterPartType.Tongue,
};
case PartGroup.UpperBody:
return new List<CharacterPartType>
{
CharacterPartType.Torso,
CharacterPartType.ArmUpperLeft,
CharacterPartType.ArmUpperRight,
CharacterPartType.ArmLowerLeft,
CharacterPartType.ArmLowerRight,
CharacterPartType.HandLeft,
CharacterPartType.HandRight,
CharacterPartType.AttachmentBack,
CharacterPartType.AttachmentShoulderLeft,
CharacterPartType.AttachmentShoulderRight,
CharacterPartType.AttachmentElbowLeft,
CharacterPartType.AttachmentElbowRight,
CharacterPartType.Wrap,
// CharacterPartType.AttachmentHandLeft,
// CharacterPartType.AttachmentHandRight,
};
case PartGroup.LowerBody:
return new List<CharacterPartType>
{
CharacterPartType.Hips,
CharacterPartType.LegLeft,
CharacterPartType.LegRight,
CharacterPartType.FootLeft,
CharacterPartType.FootRight,
CharacterPartType.AttachmentHipsFront,
CharacterPartType.AttachmentHipsBack,
CharacterPartType.AttachmentHipsLeft,
CharacterPartType.AttachmentHipsRight,
CharacterPartType.AttachmentKneeLeft,
CharacterPartType.AttachmentKneeRight,
};
default:
throw new ArgumentOutOfRangeException(nameof(basePartGroup), basePartGroup, null);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cb79594c641d4f68ba6440f336be721f
timeCreated: 1724039825

View File

@@ -0,0 +1,24 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Synty.SidekickCharacters.Utils
{
public static class PartUtils
{
/// <summary>
/// Checks if a given part is a base part or not.
/// </summary>
/// <param name="partName">The name of the part to check.</param>
/// <returns>true if it is a base part; otherwise false</returns>
public static bool IsBaseSpeciesPart(string partName)
{
if (string.IsNullOrEmpty(partName))
{
return false;
}
return partName.Contains("_BASE_");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 96a13b71844a1b1408a7818b6092b843
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
// Copyright (c) 2025 Synty Studios Limited. All rights reserved.
//
// Use of this software is subject to the terms and conditions of the End User Licence Agreement (EULA)
// of the store at which you purchased this asset.
//
// Synty assets are available at:
// https://www.syntystore.com
// https://assetstore.unity.com/publishers/5217
// https://www.fab.com/sellers/Synty%20Studios
//
// Sample scripts are included only as examples and are not intended as production-ready.
using UnityEngine;
using UnityEngine.EventSystems;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
// compile errors?
using UnityEngine.InputSystem.UI;
// compile errors?
// if you are getting a compile error here you likely need to import the Input System package (com.unity.inputsystem) in the package manager or change the input setting in player settings back to 'Input Manager (Old)'
#endif
namespace Synty.SidekickCharacters.Utils
{
/// <summary>
/// Sample script that helps automatically select the correct input event module depending on your project's settings.
/// </summary>
[ExecuteAlways]
[RequireComponent(typeof(EventSystem))]
public class SampleAutoInputModule : MonoBehaviour
{
void OnEnable()
{
UpdateInputModule();
}
void UpdateInputModule()
{
#if ENABLE_INPUT_SYSTEM
// New Input System only
if (GetComponent<InputSystemUIInputModule>() == null)
{
// Remove any existing modules
foreach (var module in GetComponents<BaseInputModule>())
{
DestroyImmediate(module);
}
gameObject.AddComponent<InputSystemUIInputModule>();
if(!Application.isPlaying) Debug.Log("Added InputSystemUIInputModule (new input system)");
}
#elif ENABLE_LEGACY_INPUT_MANAGER
// Old Input Manager only
if (GetComponent<StandaloneInputModule>() == null)
{
// Remove any existing modules
foreach (var module in GetComponents<BaseInputModule>())
{
DestroyImmediate(module);
}
gameObject.AddComponent<StandaloneInputModule>();
if(!Application.isPlaying) Debug.Log("Added StandaloneInputModule (old input manager)");
}
#else
Debug.LogWarning("No input system enabled in project settings.");
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a76f00e69f738b1419aa1865415e886e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
// Copyright (c) 2024 Synty Studios Limited. All rights reserved.
//
// Use of this software is subject to the terms and conditions of the Synty Studios End User Licence Agreement (EULA)
// available at: https://syntystore.com/pages/end-user-licence-agreement
//
// For additional details, see the LICENSE.MD file bundled with this software.
using System;
using System.Linq;
namespace Synty.SidekickCharacters.Utils
{
public static class StringUtils
{
public static string AddSpacesBeforeCapitalLetters(string baseString)
{
return string.Concat(baseString.Select(c => Char.IsUpper(c) ? " " + c : c.ToString())).TrimStart(' ');
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3569486c37e832344b3be8547d9e0f2e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: