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,8 @@
fileFormatVersion: 2
guid: 5a363afb0c737a847945e160da4911ae
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,894 @@
// 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.Blendshapes;
using Synty.SidekickCharacters.Database;
using Synty.SidekickCharacters.Database.DTO;
using Synty.SidekickCharacters.Enums;
using Synty.SidekickCharacters.SkinnedMesh;
using Synty.SidekickCharacters.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Synty.SidekickCharacters.API
{
public class SidekickRuntime
{
private const string _BLEND_GENDER_NAME = "masculineFeminine";
private const string _BLEND_MUSCLE_NAME = "defaultBuff";
private const string _BLEND_SHAPE_HEAVY_NAME = "defaultHeavy";
private const string _BLEND_SHAPE_SKINNY_NAME = "defaultSkinny";
private const string _TEXTURE_COLOR_NAME = "ColorMap.png";
private const string _TEXTURE_METALLIC_NAME = "MetallicMap.png";
private const string _TEXTURE_SMOOTHNESS_NAME = "SmoothnessMap.png";
private const string _TEXTURE_REFLECTION_NAME = "ReflectionMap.png";
private const string _TEXTURE_EMISSION_NAME = "EmissionMap.png";
private const string _TEXTURE_OPACITY_NAME = "OpacityMap.png";
private const string _TEXTURE_PREFIX = "T_";
private static readonly int _COLOR_MAP = Shader.PropertyToID("_ColorMap");
private static readonly int _METALLIC_MAP = Shader.PropertyToID("_MetallicMap");
private static readonly int _SMOOTHNESS_MAP = Shader.PropertyToID("_SmoothnessMap");
private static readonly int _REFLECTION_MAP = Shader.PropertyToID("_ReflectionMap");
private static readonly int _EMISSION_MAP = Shader.PropertyToID("_EmissionMap");
private static readonly int _OPACITY_MAP = Shader.PropertyToID("_OpacityMap");
private DatabaseManager _dbManager;
private GameObject _baseModel;
private Material _currentMaterial;
private RuntimeAnimatorController _currentAnimationController;
private List<Vector2> _currentUVList;
private Dictionary<ColorPartType, List<Vector2>> _currentUVDictionary;
private Dictionary<string, Vector3> _blendShapeRigMovement;
private Dictionary<string, Quaternion> _blendShapeRigRotation;
private Dictionary<CharacterPartType, Dictionary<string, string>> _partLibrary;
private Dictionary<CharacterPartType, List<SidekickPart>> _allPartsLibrary;
private Dictionary<string, List<string>> _partOutfitMap;
private Dictionary<string, bool> _partOutfitToggleMap;
private Dictionary<string, Dictionary<SidekickSpecies, Dictionary<CharacterPartType, List<string>>>> _filterPartDictionary;
private Dictionary<CharacterPartType, Dictionary<string, SidekickPart>> _mappedPartDictionary;
private Dictionary<CharacterPartType, List<string>> _mappedPartList;
private Dictionary<SidekickSpecies, Dictionary<CharacterPartType, List<string>>> _mappedBasePartDictionary;
private Dictionary<string, SidekickSpecies> _speciesDictionary;
private Dictionary<string, List<SidekickPartPreset>> _mappedPresetFilterDictionary;
private Dictionary<SidekickSpecies, List<SidekickPartPreset>> _mappedBasePresetDictionary;
private int _partCount;
private SidekickSpecies _currentSpecies;
private float _bodyTypeBlendValue;
private float _bodySizeSkinnyBlendValue;
private float _bodySizeHeavyBlendValue;
private float _musclesBlendValue;
public DatabaseManager DBManager
{
get => _dbManager;
set => _dbManager = value;
}
public GameObject BaseModel
{
get => _baseModel;
set => _baseModel = value;
}
public Material CurrentMaterial
{
get => _currentMaterial;
set => _currentMaterial = value;
}
public RuntimeAnimatorController CurrentAnimationController
{
get => _currentAnimationController;
set => _currentAnimationController = value;
}
public List<Vector2> CurrentUVList
{
get => _currentUVList;
set => _currentUVList = value;
}
public Dictionary<ColorPartType, List<Vector2>> CurrentUVDictionary
{
get => _currentUVDictionary;
set => _currentUVDictionary = value;
}
public Dictionary<CharacterPartType, Dictionary<string, string>> PartLibrary
{
get => _partLibrary;
set => _partLibrary = value;
}
public int PartCount
{
get => _partCount;
private set => _partCount = value;
}
public Dictionary<string, List<string>> PartOutfitMap
{
get => _partOutfitMap;
set => _partOutfitMap = value;
}
public Dictionary<string, bool> PartOutfitToggleMap
{
get => _partOutfitToggleMap;
set => _partOutfitToggleMap = value;
}
public float BodyTypeBlendValue
{
get => _bodyTypeBlendValue;
set => _bodyTypeBlendValue = value;
}
public float BodySizeSkinnyBlendValue
{
get => _bodySizeSkinnyBlendValue;
set => _bodySizeSkinnyBlendValue = value;
}
public float BodySizeHeavyBlendValue
{
get => _bodySizeHeavyBlendValue;
set => _bodySizeHeavyBlendValue = value;
}
public float MusclesBlendValue
{
get => _musclesBlendValue;
set => _musclesBlendValue = value;
}
public SidekickSpecies CurrentSpecies
{
get => _currentSpecies;
set => _currentSpecies = value;
}
public Dictionary<string, Dictionary<SidekickSpecies, Dictionary<CharacterPartType, List<string>>>> FilterPartDictionary
{
get => _filterPartDictionary;
private set => _filterPartDictionary = value;
}
public Dictionary<CharacterPartType, Dictionary<string, SidekickPart>> MappedPartDictionary
{
get => _mappedPartDictionary;
private set => _mappedPartDictionary = value;
}
public Dictionary<SidekickSpecies, Dictionary<CharacterPartType, List<string>>> MappedBasePartDictionary
{
get => _mappedBasePartDictionary;
private set => _mappedBasePartDictionary = value;
}
public Dictionary<CharacterPartType, List<string>> MappedPartList
{
get => _mappedPartList;
private set => _mappedPartList = value;
}
public Dictionary<CharacterPartType, List<SidekickPart>> AllPartsLibrary
{
get => _allPartsLibrary;
private set => _allPartsLibrary = value;
}
public Dictionary<string, List<SidekickPartPreset>> MappedPresetFilterDictionary
{
get => _mappedPresetFilterDictionary;
private set => _mappedPresetFilterDictionary = value;
}
public Dictionary<SidekickSpecies, List<SidekickPartPreset>> MappedBasePresetDictionary
{
get => _mappedBasePresetDictionary;
private set => _mappedBasePresetDictionary = value;
}
/// <summary>
/// Creates and instance of the SidekickRuntime with the given parameters.
/// </summary>
/// <param name="model">The base donor model to use. This is used to provide a base rig that parts can be added and removed from.</param>
/// <param name="material">The base material that will be applied to all parts that are added or removed from the character.</param>
/// <param name="animationController">The animation controller to apply to the created model.</param>
/// <param name="dbManager">The Database Manager to use, if not provided a new connection will be created.</param>
public SidekickRuntime(GameObject model, Material material, RuntimeAnimatorController animationController = null, DatabaseManager dbManager = null)
{
_dbManager = dbManager ?? new DatabaseManager();
if (_dbManager.GetCurrentDbConnection() == null)
{
_dbManager.GetDbConnection(true);
}
_baseModel = model;
_currentMaterial = material;
_currentAnimationController = animationController;
}
public static async Task PopulateToolData(SidekickRuntime runtime)
{
await runtime.LoadPartLibrary();
await runtime.PopulatePresetLibrary();
}
/// <summary>
/// Takes all the parts selected in the window, and combines them into a single model in the scene.
/// </summary>
/// <param name="modelName">What to call the parent GameObject of the created character.</param>;
/// <param name="toCombine">The list of SkinnedMeshes to combine to create the character.</param>
/// <param name="combineMesh">When true the character mesh will be combined into a single mesh.</param>
/// <param name="processBoneMovement">When true the bones will be moved to match the blend shape settings.</param>
/// <returns>A new character object.</returns>
public GameObject CreateCharacter(
string modelName,
List<SkinnedMeshRenderer> toCombine,
bool combineMesh,
bool processBoneMovement,
GameObject existingModel = null
)
{
PopulateUVDictionary(toCombine);
GameObject newSpawn;
if (combineMesh)
{
newSpawn = Combiner.CreateCombinedSkinnedMesh(toCombine, _baseModel, _currentMaterial);
}
else
{
newSpawn = CreateModelFromParts(toCombine, modelName, existingModel);
}
newSpawn.name = modelName;
Renderer renderer = newSpawn.GetComponentInChildren<Renderer>();
if (renderer != null)
{
renderer.sharedMaterial = _currentMaterial;
}
if (newSpawn.GetComponent<Animator>() == null)
{
if (existingModel == null)
{
Animator newModelAnimator = newSpawn.AddComponent<Animator>();
Animator baseModelAnimator = _baseModel.GetComponentInChildren<Animator>();
newModelAnimator.avatar = baseModelAnimator.avatar;
newModelAnimator.Rebind();
if (_currentAnimationController != null)
{
newModelAnimator.runtimeAnimatorController = _currentAnimationController;
}
}
else
{
Animator newModelAnimator = newSpawn.AddComponent<Animator>();
Animator baseModelAnimator = existingModel.GetComponentInChildren<Animator>();
newModelAnimator.avatar = baseModelAnimator.avatar;
newModelAnimator.Rebind();
}
}
UpdateBlendShapes(newSpawn);
if (processBoneMovement)
{
ProcessRigMovementOnBlendShapeChange(SidekickBlendShapeRigMovement.GetAllForProcessing(_dbManager));
ProcessBoneMovement(newSpawn);
}
return newSpawn;
}
/// <summary>
/// Creates the model but with all parts as separate meshes.
/// </summary>
/// <param name="parts">The parts to build into the character.</param>
/// <param name="outputModelName">What to call the parent GameObject of the created character.</param>
/// <returns>A new game object with all the part meshes and a single rig.</returns>
public GameObject CreateModelFromParts(
List<SkinnedMeshRenderer> parts,
string outputModelName,
GameObject existingModel = null
)
{
List<CharacterPartType> allTypes = Enum.GetValues(typeof(CharacterPartType)).Cast<CharacterPartType>().ToList();
GameObject partsModel = existingModel == null ? new GameObject(outputModelName) : existingModel;
Transform modelRootBone = _baseModel.GetComponentInChildren<SkinnedMeshRenderer>().rootBone;
GameObject newRootBone;
if (existingModel != null)
{
GameObject oldRootBone = existingModel.transform.Find("root").gameObject;
#if UNITY_EDITOR
GameObject.DestroyImmediate(oldRootBone);
#else
GameObject.Destroy(oldRootBone);
#endif
}
newRootBone = Object.Instantiate(modelRootBone.gameObject, partsModel.transform, true);
newRootBone.name = modelRootBone.name;
Hashtable boneNameMap = Combiner.CreateBoneNameMap(newRootBone);
Transform[] bones = new Transform[boneNameMap.Count];
if (existingModel != null)
{
boneNameMap.Values.CopyTo(bones, 0);
}
Transform[] additionalBones = Combiner.FindAdditionalBones(boneNameMap, new List<SkinnedMeshRenderer>(parts));
if (additionalBones.Length > 0)
{
Combiner.JoinAdditionalBonesToBoneArray(bones, additionalBones, boneNameMap);
// Need to redo the name map now that we have updated the bone array.
boneNameMap = Combiner.CreateBoneNameMap(newRootBone);
}
for (int i = 0; i < parts.Count; i++)
{
SkinnedMeshRenderer part = parts[i];
allTypes.Remove(ExtractPartType(part.name));
if (existingModel != null && partsModel != null)
{
SkinnedMeshRenderer existingPart = partsModel.GetComponentsInChildren<SkinnedMeshRenderer>()
.FirstOrDefault(go => go.name.Contains(ExtractPartTypeString(part.name)));
if (existingPart != null)
{
#if UNITY_EDITOR
GameObject.DestroyImmediate(existingPart.gameObject);
#else
GameObject.Destroy(existingModel.gameObject);
#endif
}
}
GameObject newPart = new GameObject(part.name);
newPart.transform.parent = partsModel.transform;
SkinnedMeshRenderer renderer = newPart.AddComponent<SkinnedMeshRenderer>();
renderer.updateWhenOffscreen = true;
Transform[] oldBones = part.bones;
Transform[] newBones = new Transform[part.bones.Length];
for (int j = 0; j < oldBones.Length; j++)
{
newBones[j] = (Transform) boneNameMap[oldBones[j].name];
}
renderer.sharedMesh = MeshUtils.CopyMesh(part.sharedMesh);
renderer.rootBone = (Transform) boneNameMap[part.rootBone.name];
Combiner.MergeAndGetAllBlendShapeDataOfSkinnedMeshRenderers(
new[]
{
part
},
renderer.sharedMesh,
renderer
);
renderer.bones = newBones;
renderer.sharedMaterial = _currentMaterial;
}
foreach (CharacterPartType type in allTypes)
{
SkinnedMeshRenderer existingPart = partsModel.GetComponentsInChildren<SkinnedMeshRenderer>()
.FirstOrDefault(go => go.name.Contains(CharacterPartTypeUtils.GetPartTypeString(type)));
if (existingPart != null)
{
#if UNITY_EDITOR
GameObject.DestroyImmediate(existingPart.gameObject);
#else
GameObject.Destroy(existingModel.gameObject);
#endif
}
}
return partsModel;
}
/// <summary>
/// Populates the list of current UVs and UV part dictionary.
/// </summary>
public void PopulateUVDictionary(List<SkinnedMeshRenderer> usedParts)
{
_currentUVList = new List<Vector2>();
_currentUVDictionary = new Dictionary<ColorPartType, List<Vector2>>();
foreach (ColorPartType type in Enum.GetValues(typeof(ColorPartType)))
{
_currentUVDictionary.Add(type, new List<Vector2>());
}
foreach (SkinnedMeshRenderer skinnedMesh in usedParts)
{
ColorPartType type = Enum.Parse<ColorPartType>(ExtractPartType(skinnedMesh.name).ToString());
List<Vector2> partUVs = _currentUVDictionary[type];
foreach (Vector2 uv in skinnedMesh.sharedMesh.uv)
{
int scaledU = (int) Math.Floor(uv.x * 16);
int scaledV = (int) Math.Floor(uv.y * 16);
if (scaledU == 16)
{
scaledU = 15;
}
if (scaledV == 16)
{
scaledV = 15;
}
Vector2 scaledUV = new Vector2(scaledU, scaledV);
// For the global UV list, we don't want any duplicates on a global level
if (!_currentUVList.Contains(scaledUV))
{
_currentUVList.Add(scaledUV);
}
// For the part specific UV list we may have UVs that are in the global list already, we don't want to exclude these, so check
// them separately to the global list
if (!partUVs.Contains(scaledUV))
{
partUVs.Add(scaledUV);
}
}
_currentUVDictionary[type] = partUVs;
}
}
/// <summary>
/// Updates the blend shape values of the combined model.
/// </summary>
public void UpdateBlendShapes(GameObject model)
{
if (model == null)
{
return;
}
List<SkinnedMeshRenderer> allMeshes = model.GetComponentsInChildren<SkinnedMeshRenderer>().ToList();
foreach (SkinnedMeshRenderer skinnedMesh in allMeshes)
{
Mesh sharedMesh = skinnedMesh.sharedMesh;
for (int i = 0; i < sharedMesh.blendShapeCount; i++)
{
string blendName = sharedMesh.GetBlendShapeName(i);
if (blendName.Contains(_BLEND_GENDER_NAME))
{
skinnedMesh.SetBlendShapeWeight(i, (_bodyTypeBlendValue + 100) / 2);
}
else if (blendName.Contains(_BLEND_SHAPE_SKINNY_NAME))
{
skinnedMesh.SetBlendShapeWeight(i, _bodySizeSkinnyBlendValue);
}
else if (blendName.Contains(_BLEND_SHAPE_HEAVY_NAME))
{
skinnedMesh.SetBlendShapeWeight(i, _bodySizeHeavyBlendValue);
}
else if (blendName.Contains(_BLEND_MUSCLE_NAME))
{
skinnedMesh.SetBlendShapeWeight(i, (_musclesBlendValue + 100) / 2);
}
}
}
}
/// <summary>
/// Populates the internal library of parts based on the files in the project.
/// </summary>
public Dictionary<CharacterPartType, Dictionary<string, string>> PopulatePartLibrary()
{
_partLibrary = new Dictionary<CharacterPartType, Dictionary<string, string>>();
_partOutfitMap = new Dictionary<string, List<string>>();
_partOutfitToggleMap = new Dictionary<string, bool>();
_partCount = 0;
List<string> files = Directory.GetFiles("Assets", "SK_*_*_*_*_*.fbx", SearchOption.AllDirectories).ToList();
foreach (CharacterPartType partType in Enum.GetValues(typeof(CharacterPartType)))
{
Dictionary<string, string> partLocationDictionary = new Dictionary<string, string>();
foreach (string file in files)
{
FileInfo fileInfo = new FileInfo(file);
string partName = fileInfo.Name;
partName = partName.Substring(0, partName.IndexOf(".fbx", StringComparison.Ordinal));
CharacterPartType characterPartType = ExtractPartType(partName);
if (characterPartType > 0 && characterPartType == partType && !partLocationDictionary.ContainsKey(partName))
{
partLocationDictionary.Add(partName, file);
_partCount++;
// TODO: populate with actual outfit data when we have proper information about part outfits
string tempPartOutfit = GetOutfitNameFromPartName(partName);
List<string> partNameList;
if (_partOutfitMap.TryGetValue(tempPartOutfit, out List<string> value))
{
partNameList = value;
partNameList.Add(partName);
_partOutfitMap[tempPartOutfit] = partNameList;
}
else
{
partNameList = new List<string>();
partNameList.Add(partName);
_partOutfitMap.Add(tempPartOutfit, partNameList);
_partOutfitToggleMap.Add(tempPartOutfit, true);
}
}
}
_partLibrary.Add(partType, partLocationDictionary);
}
return _partLibrary;
}
/// <summary>
/// Populates the internal library of Presets into libraries based on filters and base parts.
/// </summary>
public Task PopulatePresetLibrary()
{
HashSet<SidekickPartPreset> uniqueList = new HashSet<SidekickPartPreset>();
_mappedPresetFilterDictionary = new Dictionary<string, List<SidekickPartPreset>>();
_mappedBasePresetDictionary = new Dictionary<SidekickSpecies, List<SidekickPartPreset>>();
foreach (SidekickPresetFilter filter in SidekickPresetFilter.GetAll(_dbManager))
{
List<SidekickPartPreset> presets = filter.GetAllPresetsForFilter(_dbManager, true, true);
_mappedPresetFilterDictionary[filter.Term] = presets;
uniqueList.UnionWith(presets);
}
// Check for and add BASE only presets
List<SidekickPartPreset> allPresets = SidekickPartPreset.GetAll(_dbManager);
List<SidekickPartPreset> presetsNotInFilters = allPresets.Where(preset => !uniqueList.Contains(preset)).ToList();
foreach (SidekickPartPreset preset in presetsNotInFilters)
{
if (preset.HasOnlyBasePartsAndAllAvailable(_dbManager))
{
if (_mappedBasePresetDictionary.TryGetValue(preset.Species, out List<SidekickPartPreset> mappedPresets))
{
mappedPresets.Add(preset);
_mappedBasePresetDictionary[preset.Species] = mappedPresets;
}
else
{
List<SidekickPartPreset> presets = new List<SidekickPartPreset>
{
preset
};
_mappedBasePresetDictionary.Add(preset.Species, presets);
}
}
}
return Task.CompletedTask;
}
/// <summary>
/// Populates the internal library of parts based on the files in the project.
/// </summary>
public Task LoadPartLibrary()
{
_allPartsLibrary = new Dictionary<CharacterPartType, List<SidekickPart>>();
_mappedPartList = new Dictionary<CharacterPartType, List<string>>();
_mappedPartDictionary = new Dictionary<CharacterPartType, Dictionary<string, SidekickPart>>();
_mappedBasePartDictionary = new Dictionary<SidekickSpecies, Dictionary<CharacterPartType, List<string>>>();
_speciesDictionary = new Dictionary<string, SidekickSpecies>();
_partCount = 0;
List<string> files = Directory.GetFiles("Assets", "SK_*_*_*_*_*.fbx", SearchOption.AllDirectories).ToList();
Dictionary<string, string> filesOnDisk = new Dictionary<string, string>();
foreach (string file in files)
{
FileInfo fileInfo = new FileInfo(file);
string partName = fileInfo.Name;
partName = partName.Substring(0, partName.IndexOf(".fbx", StringComparison.Ordinal));
filesOnDisk.TryAdd(partName, file);
}
foreach (CharacterPartType type in Enum.GetValues(typeof(CharacterPartType)))
{
_allPartsLibrary[type] = new List<SidekickPart>();
_mappedPartDictionary[type] = new Dictionary<string, SidekickPart>();
_mappedPartList[type] = new List<string>();
}
SidekickSpecies unrestrictedSpecies = null;
foreach (SidekickSpecies species in SidekickSpecies.GetAll(_dbManager, false))
{
_speciesDictionary[species.Name] = species;
_mappedBasePartDictionary[species] = new Dictionary<CharacterPartType, List<string>>();
if (species.Name == "Unrestricted")
{
unrestrictedSpecies = species;
}
}
List<SidekickPart> allParts = SidekickPart.GetAll(_dbManager);
foreach (SidekickPart part in allParts)
{
if (filesOnDisk.ContainsKey(part.Name))
{
_partCount++;
part.FileExists = true;
List<SidekickPart> parts = _allPartsLibrary.TryGetValue(part.Type, out List<SidekickPart> value)
? value
: new List<SidekickPart>();
parts.Add(part);
_allPartsLibrary[part.Type] = parts;
Dictionary<string, SidekickPart> partMap = _mappedPartDictionary[part.Type];
partMap[part.Name] = part;
_mappedPartDictionary[part.Type] = partMap;
List<string> currentList = _mappedPartList[part.Type];
currentList.Add(part.Name);
_mappedPartList[part.Type] = currentList;
if (part.Name.Contains("_BASE_"))
{
if (!_mappedBasePartDictionary.ContainsKey(part.Species))
{
continue;
}
Dictionary<CharacterPartType, List<string>> basePartMap = _mappedBasePartDictionary[part.Species];
List<string> partList = basePartMap.TryGetValue(part.Type, out List<string> existingList) ? existingList : new List<string>();
partList.Add(part.Name);
basePartMap[part.Type] = partList;
_mappedBasePartDictionary[part.Species] = basePartMap;
if (unrestrictedSpecies != null)
{
Dictionary<CharacterPartType, List<string>> unrestrictedBasePartMap = _mappedBasePartDictionary[unrestrictedSpecies];
List<string> unrestrictedPartList = unrestrictedBasePartMap.TryGetValue(part.Type, out List<string> unrestrictedList) ? unrestrictedList : new List<string>();
unrestrictedPartList.Add(part.Name);
unrestrictedBasePartMap[part.Type] = unrestrictedPartList;
_mappedBasePartDictionary[unrestrictedSpecies] = unrestrictedBasePartMap;
}
}
}
else
{
part.FileExists = false;
}
}
SidekickPart.UpdateAll(_dbManager, allParts);
return Task.CompletedTask;
}
/// <summary>
/// Gets the "outfit" name from the part name.
/// TODO: This will be replaced once parts and outfits have a proper relationship.
/// </summary>
/// <param name="partName">The part name to parse the "outfit" name from.</param>
/// <returns>The "outfit" name.</returns>
public string GetOutfitNameFromPartName(string partName)
{
if (string.IsNullOrEmpty(partName))
{
return "None";
}
return string.Join('_', partName.Substring(3).Split('_').Take(2));
}
/// <summary>
/// Determines the part type from the part name. This will work as long as the naming format is correct.
/// </summary>
/// <param name="partName">The name of the part.</param>
/// <returns>The part type.</returns>
public CharacterPartType ExtractPartType(string partName)
{
string partTypeString = ExtractPartTypeString(partName);
string partIndexString = "0";
if (partTypeString.Length > 2)
{
partIndexString = partTypeString.Substring(0, 2);
}
bool valueParsed = int.TryParse(partIndexString, out int index);
return valueParsed ? (CharacterPartType) index : 0;
}
/// <summary>
/// Extracts the part type string from the file name.
/// </summary>
/// <param name="partName">The name of the part.</param>
/// <returns>The part type string</returns>
public string ExtractPartTypeString(string partName)
{
return partName.Split('_').Reverse().ElementAt(1);
}
/// <summary>
/// Processes the movement of rig joints based on blend shape changes.
/// </summary>
public void ProcessRigMovementOnBlendShapeChange(Dictionary<CharacterPartType, Dictionary<BlendShapeType, SidekickBlendShapeRigMovement>> offsetLibrary)
{
Transform modelRootBone = _baseModel.transform.Find("root");
Hashtable boneNameMap = Combiner.CreateBoneNameMap(modelRootBone.gameObject);
_blendShapeRigMovement = new Dictionary<string, Vector3>();
_blendShapeRigRotation = new Dictionary<string, Quaternion>();
foreach (KeyValuePair<CharacterPartType, string> entry in BlendshapeJointAdjustment.PART_TYPE_JOINT_MAP)
{
Transform bone = (Transform) boneNameMap[entry.Value];
float feminineBlendValue = (_bodyTypeBlendValue + 100) / 2 / 100;
Vector3 allMovement = bone.localPosition;
Quaternion allRotation = bone.localRotation;
if (offsetLibrary.TryGetValue(entry.Key, out Dictionary<BlendShapeType, SidekickBlendShapeRigMovement> blendOffsetLibrary))
{
foreach (BlendShapeType blendType in Enum.GetValues(typeof(BlendShapeType)))
{
if (blendOffsetLibrary.TryGetValue(blendType, out SidekickBlendShapeRigMovement rigMovement))
{
if (rigMovement == null)
{
continue;
}
switch (blendType)
{
case BlendShapeType.Feminine:
allMovement += rigMovement.GetBlendedOffsetValue(feminineBlendValue);
allRotation *= rigMovement.GetBlendedRotationValue(feminineBlendValue);
break;
case BlendShapeType.Heavy:
allMovement += rigMovement.GetBlendedOffsetValue(_bodySizeHeavyBlendValue / 100);
allRotation *= rigMovement.GetBlendedRotationValue(_bodySizeHeavyBlendValue / 100);
break;
case BlendShapeType.Skinny:
allMovement += rigMovement.GetBlendedOffsetValue(_bodySizeSkinnyBlendValue / 100);
allRotation *= rigMovement.GetBlendedRotationValue(_bodySizeSkinnyBlendValue / 100);
break;
case BlendShapeType.Bulk:
allMovement += rigMovement.GetBlendedOffsetValue((_musclesBlendValue + 100) / 2 / 100);
allRotation *= rigMovement.GetBlendedRotationValue((_musclesBlendValue + 100) / 2 / 100);
break;
}
}
}
}
_blendShapeRigMovement[entry.Value] = allMovement;
_blendShapeRigRotation[entry.Value] = allRotation;
}
}
/// <summary>
/// Processes the movement of the rig with regards to the current blend shape settings.
/// </summary>
/// <param name="model">The model to process the movement on.</param>
public void ProcessBoneMovement(GameObject model)
{
if (model == null)
{
return;
}
Transform modelRootBone = model.transform.Find("root");
Hashtable boneNameMap = Combiner.CreateBoneNameMap(modelRootBone.gameObject);
Combiner.ProcessBoneMovement(boneNameMap, _blendShapeRigMovement, _blendShapeRigRotation);
}
/// <summary>
/// Updates the texture on the given color row for the specified color type.
/// </summary>
/// <param name="colorType">The color type to update.</param>
/// <param name="colorRow">The color row to get the updated color from.</param>
public void UpdateColor(ColorType colorType, SidekickColorRow colorRow)
{
if (colorRow == null)
{
return;
}
if (_currentMaterial == null)
{
return;
}
switch (colorType)
{
case ColorType.Metallic:
Texture2D metallic = (Texture2D) _currentMaterial.GetTexture(_METALLIC_MAP);
UpdateTexture(metallic, colorRow.NiceMetallic, colorRow.ColorProperty.U, colorRow.ColorProperty.V);
_currentMaterial.SetTexture(_METALLIC_MAP, metallic);
break;
case ColorType.Smoothness:
Texture2D smoothness = (Texture2D) _currentMaterial.GetTexture(_SMOOTHNESS_MAP);
UpdateTexture(smoothness, colorRow.NiceSmoothness, colorRow.ColorProperty.U, colorRow.ColorProperty.V);
_currentMaterial.SetTexture(_SMOOTHNESS_MAP, smoothness);
break;
case ColorType.Reflection:
Texture2D reflection = (Texture2D) _currentMaterial.GetTexture(_REFLECTION_MAP);
UpdateTexture(reflection, colorRow.NiceReflection, colorRow.ColorProperty.U, colorRow.ColorProperty.V);
_currentMaterial.SetTexture(_REFLECTION_MAP, reflection);
break;
case ColorType.Emission:
Texture2D emission = (Texture2D) _currentMaterial.GetTexture(_EMISSION_MAP);
UpdateTexture(emission, colorRow.NiceEmission, colorRow.ColorProperty.U, colorRow.ColorProperty.V);
_currentMaterial.SetTexture(_EMISSION_MAP, emission);
break;
case ColorType.Opacity:
Texture2D opacity = (Texture2D) _currentMaterial.GetTexture(_OPACITY_MAP);
UpdateTexture(opacity, colorRow.NiceOpacity, colorRow.ColorProperty.U, colorRow.ColorProperty.V);
_currentMaterial.SetTexture(_OPACITY_MAP, opacity);
break;
case ColorType.MainColor:
default:
Texture2D color = (Texture2D) _currentMaterial.GetTexture(_COLOR_MAP);
UpdateTexture(color, colorRow.NiceColor, colorRow.ColorProperty.U, colorRow.ColorProperty.V);
_currentMaterial.SetTexture(_COLOR_MAP, color);
break;
}
}
/// <summary>
/// Updates the color on the texture with the given new color.
/// </summary>
/// <param name="texture">The texture to update.</param>
/// <param name="newColor">The color to assign to the texture.</param>
/// <param name="u">The u positioning on the texture to update.</param>
/// <param name="v">The v positioning on the texture to update.</param>
public void UpdateTexture(Texture2D texture, Color newColor, int u, int v)
{
int scaledU = u * 2;
int scaledV = v * 2;
texture.SetPixel(scaledU, scaledV, newColor);
texture.SetPixel(scaledU + 1, scaledV, newColor);
texture.SetPixel(scaledU, scaledV + 1, newColor);
texture.SetPixel(scaledU + 1, scaledV + 1, newColor);
texture.Apply();
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 665c362b672a816439cb81f6fc40eed8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,185 @@
// 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.Database.DTO;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
using UnityEngine;
namespace Synty.SidekickCharacters.Blendshapes
{
public static class BlendshapeJointAdjustment
{
// Feminine_Offset Values
private static readonly Vector3 FEMININE_OFFSET_HIP_ATTACH_BACK = new Vector3(0.0f, 0.00095f, 0.00072f);
private static readonly Vector3 FEMININE_OFFSET_HIP_ATTACH_L = new Vector3(-0.0031f, -0.00241f, 0.00727f);
private static readonly Vector3 FEMININE_OFFSET_HIP_ATTACH_FRONT = new Vector3(0.0f, 0.00138f, -0.01824f);
private static readonly Vector3 FEMININE_OFFSET_KNEE_ATTACH_L = new Vector3(-0.00064f, -0.00106f, -0.001f);
private static readonly Vector3 FEMININE_OFFSET_KNEE_ATTACH_R = new Vector3(-0.00064f, -0.00106f, -0.001f);
private static readonly Vector3 FEMININE_OFFSET_HIP_ATTACH_R = new Vector3(0.0031f, -0.00241f, 0.00727f);
private static readonly Vector3 FEMININE_OFFSET_ELBOW_ATTACH_R = new Vector3(0.00125f, -0.00021f, 0.0093f);
private static readonly Vector3 FEMININE_OFFSET_SHOULDER_ATTACH_R = new Vector3(-0.01559f, -0.00467f, 0.00124f);
private static readonly Vector3 FEMININE_OFFSET_BACK_ATTACH = new Vector3(0.0f, 0.00137f, 0.01903f);
private static readonly Vector3 FEMININE_OFFSET_SHOULDER_ATTACH_L = new Vector3(-0.01559f, -0.00467f, -0.00124f);
private static readonly Vector3 FEMININE_OFFSET_ELBOW_ATTACH_L = new Vector3(-0.00125f, -0.00021f, 0.0093f);
// Heavy_Offset Values
private static readonly Vector3 HEAVY_OFFSET_HIP_ATTACH_BACK = new Vector3(0.0f, -0.02628f, -0.15593f);
private static readonly Vector3 HEAVY_OFFSET_HIP_ATTACH_L = new Vector3(-0.14163f, 0.00034f, 0.00718f);
private static readonly Vector3 HEAVY_OFFSET_HIP_ATTACH_FRONT = new Vector3(0.0f, -0.06413f, 0.14101f);
private static readonly Vector3 HEAVY_OFFSET_KNEE_ATTACH_L = new Vector3(0.00331f, -0.00084f, 0.02737f);
private static readonly Vector3 HEAVY_OFFSET_KNEE_ATTACH_R = new Vector3(0.00331f, -0.00084f, 0.02737f);
private static readonly Vector3 HEAVY_OFFSET_HIP_ATTACH_R = new Vector3(0.14163f, 0.00034f, 0.00718f);
private static readonly Vector3 HEAVY_OFFSET_ELBOW_ATTACH_R = new Vector3(0.0f, 0.00138f, -0.02725f);
private static readonly Vector3 HEAVY_OFFSET_SHOULDER_ATTACH_R = new Vector3(-0.00707f, 0.03154f, 0.00351f);
private static readonly Vector3 HEAVY_OFFSET_BACK_ATTACH = new Vector3(0.0f, 0.02174f, -0.07185f);
private static readonly Vector3 HEAVY_OFFSET_SHOULDER_ATTACH_L = new Vector3(-0.00707f, 0.03154f, -0.00351f);
private static readonly Vector3 HEAVY_OFFSET_ELBOW_ATTACH_L = new Vector3(0.0f, 0.00138f, -0.02725f);
// Skinny_Offset Values
private static readonly Vector3 SKINNY_OFFSET_HIP_ATTACH_BACK = new Vector3(0.0f, -0.0042f, 0.00849f);
private static readonly Vector3 SKINNY_OFFSET_HIP_ATTACH_L = new Vector3(0.01571f, -0.00161f, -0.00123f);
private static readonly Vector3 SKINNY_OFFSET_HIP_ATTACH_FRONT = new Vector3(0.0f, 0.00159f, -0.01787f);
private static readonly Vector3 SKINNY_OFFSET_KNEE_ATTACH_L = new Vector3(0.00167f, 0.00145f, -0.00388f);
private static readonly Vector3 SKINNY_OFFSET_KNEE_ATTACH_R = new Vector3(0.00167f, 0.00145f, -0.00388f);
private static readonly Vector3 SKINNY_OFFSET_HIP_ATTACH_R = new Vector3(-0.01571f, -0.00161f, -0.00123f);
private static readonly Vector3 SKINNY_OFFSET_ELBOW_ATTACH_R = new Vector3(0.00128f, -0.00342f, 0.01043f);
private static readonly Vector3 SKINNY_OFFSET_SHOULDER_ATTACH_R = new Vector3(0.0003f, -0.00818f, 0.00089f);
private static readonly Vector3 SKINNY_OFFSET_BACK_ATTACH = new Vector3(-0.00001f, -0.00079f, 0.00938f);
private static readonly Vector3 SKINNY_OFFSET_SHOULDER_ATTACH_L = new Vector3(0.0003f, -0.00818f, -0.00089f);
private static readonly Vector3 SKINNY_OFFSET_ELBOW_ATTACH_L = new Vector3(-0.00128f, -0.00342f, 0.01043f);
// Bulk_Offset Values
private static readonly Vector3 BULK_OFFSET_HIP_ATTACH_BACK = new Vector3(0.0f, 0.00093f, -0.01182f);
private static readonly Vector3 BULK_OFFSET_HIP_ATTACH_L = new Vector3(0.00115f, 0.00139f, 0.00299f);
private static readonly Vector3 BULK_OFFSET_HIP_ATTACH_FRONT = new Vector3(0.0f, 0.00132f, 0.00489f);
private static readonly Vector3 BULK_OFFSET_KNEE_ATTACH_L = new Vector3(0.00041f, 0.00005f, 0.00033f);
private static readonly Vector3 BULK_OFFSET_KNEE_ATTACH_R = new Vector3(0.00041f, 0.00005f, 0.00033f);
private static readonly Vector3 BULK_OFFSET_HIP_ATTACH_R = new Vector3(-0.00115f, 0.00139f, 0.00299f);
private static readonly Vector3 BULK_OFFSET_ELBOW_ATTACH_R = new Vector3(0.00609f, 0.01381f, -0.06119f);
private static readonly Vector3 BULK_OFFSET_SHOULDER_ATTACH_R = new Vector3(0.02127f, 0.04615f, -0.00861f);
private static readonly Vector3 BULK_OFFSET_BACK_ATTACH = new Vector3(0.0f, 0.00465f, -0.03104f);
private static readonly Vector3 BULK_OFFSET_SHOULDER_ATTACH_L = new Vector3(0.02127f, 0.04615f, 0.00861f);
private static readonly Vector3 BULK_OFFSET_ELBOW_ATTACH_L = new Vector3(-0.00609f, 0.01381f, -0.06119f);
public static readonly Dictionary<CharacterPartType, string> PART_TYPE_JOINT_MAP = new Dictionary<CharacterPartType, string>
{
[CharacterPartType.AttachmentBack] = "backAttach",
[CharacterPartType.AttachmentHipsFront] = "hipAttachFront",
[CharacterPartType.AttachmentHipsBack] = "hipAttachBack",
[CharacterPartType.AttachmentHipsLeft] = "hipAttach_l",
[CharacterPartType.AttachmentHipsRight] = "hipAttach_r",
[CharacterPartType.AttachmentShoulderLeft] = "shoulderAttach_l",
[CharacterPartType.AttachmentShoulderRight] = "shoulderAttach_r",
[CharacterPartType.AttachmentElbowLeft] = "elbowAttach_l",
[CharacterPartType.AttachmentElbowRight] = "elbowAttach_r",
[CharacterPartType.AttachmentKneeLeft] = "kneeAttach_l",
[CharacterPartType.AttachmentKneeRight] = "kneeAttach_r"
};
/// <summary>
/// Gets the combined offset value for the current blend shape settings.
/// </summary>
/// <param name="blendValueFeminine">The feminine blend shape value.</param>
/// <param name="blendValueSize">The body size blend shape value.</param>
/// <param name="blendValueMuscle">The muscle blend shape value.</param>
/// <param name="currentPosition">The current position of the rig.</param>
/// <param name="partType">The current part type.</param>
/// <returns>The combined blend shape offset.</returns>
public static Vector3 GetCombinedOffsetValue(
float blendValueFeminine,
float blendValueSize,
float blendValueMuscle,
Vector3 currentPosition,
CharacterPartType partType
)
{
switch (partType)
{
case CharacterPartType.AttachmentBack:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_BACK_ATTACH, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_BACK_ATTACH, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_BACK_ATTACH, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_BACK_ATTACH, -blendValueSize));
case CharacterPartType.AttachmentHipsFront:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_HIP_ATTACH_FRONT, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_HIP_ATTACH_FRONT, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_HIP_ATTACH_FRONT, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_HIP_ATTACH_FRONT, -blendValueSize));
case CharacterPartType.AttachmentHipsBack:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_HIP_ATTACH_BACK, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_HIP_ATTACH_BACK, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_HIP_ATTACH_BACK, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_HIP_ATTACH_BACK, -blendValueSize));
case CharacterPartType.AttachmentHipsLeft:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_HIP_ATTACH_L, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_HIP_ATTACH_L, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_HIP_ATTACH_L, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_HIP_ATTACH_L, -blendValueSize));
case CharacterPartType.AttachmentHipsRight:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_HIP_ATTACH_R, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_HIP_ATTACH_R, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_HIP_ATTACH_R, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_HIP_ATTACH_R, -blendValueSize));
case CharacterPartType.AttachmentShoulderLeft:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_SHOULDER_ATTACH_L, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_SHOULDER_ATTACH_L, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_SHOULDER_ATTACH_L, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_SHOULDER_ATTACH_L, -blendValueSize));
case CharacterPartType.AttachmentShoulderRight:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_SHOULDER_ATTACH_R, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_SHOULDER_ATTACH_R, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_SHOULDER_ATTACH_R, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_SHOULDER_ATTACH_R, -blendValueSize));
case CharacterPartType.AttachmentElbowLeft:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_ELBOW_ATTACH_L, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_ELBOW_ATTACH_L, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_ELBOW_ATTACH_L, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_ELBOW_ATTACH_L, -blendValueSize));
case CharacterPartType.AttachmentElbowRight:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_ELBOW_ATTACH_R, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_ELBOW_ATTACH_R, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_ELBOW_ATTACH_R, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_ELBOW_ATTACH_R, -blendValueSize));
case CharacterPartType.AttachmentKneeLeft:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_KNEE_ATTACH_L, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_KNEE_ATTACH_L, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_KNEE_ATTACH_L, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_KNEE_ATTACH_L, -blendValueSize));
case CharacterPartType.AttachmentKneeRight:
return currentPosition
+ Vector3.Lerp(Vector3.zero, FEMININE_OFFSET_KNEE_ATTACH_R, blendValueFeminine)
+ Vector3.Lerp(Vector3.zero, BULK_OFFSET_KNEE_ATTACH_R, blendValueMuscle)
+ (blendValueSize > 0
? Vector3.Lerp(Vector3.zero, HEAVY_OFFSET_KNEE_ATTACH_R, blendValueSize)
: Vector3.Lerp(Vector3.zero, SKINNY_OFFSET_KNEE_ATTACH_R, -blendValueSize));
}
return Vector3.zero;
}
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1c0e68460b4d826459957d3ba3c8bfd2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2888e51f917533c4cb2ce72685d11db3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,203 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_blend_shape_rig_movement")]
public class SidekickBlendShapeRigMovement
{
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("part_type")]
public CharacterPartType PartType { get; set; }
[Column("blend_type")]
public BlendShapeType BlendType { get; set; }
[Column("max_offset_x")]
public float MaxOffsetX { get; set; }
[Column("max_offset_y")]
public float MaxOffsetY { get; set; }
[Column("max_offset_z")]
public float MaxOffsetZ { get; set; }
[Column("max_rotation_x")]
public float MaxRotationX { get; set; }
[Column("max_rotation_y")]
public float MaxRotationY { get; set; }
[Column("max_rotation_z")]
public float MaxRotationZ { get; set; }
[Column("max_scale_x")]
public float MaxScaleX { get; set; }
[Column("max_scale_y")]
public float MaxScaleY { get; set; }
[Column("max_scale_z")]
public float MaxScaleZ { get; set; }
[Ignore]
public Vector3 MaxOffset
{
get => new Vector3(MaxOffsetX, MaxOffsetY, MaxOffsetZ);
set
{
MaxOffsetX = value.x;
MaxOffsetY = value.y;
MaxOffsetZ = value.z;
}
}
[Ignore]
public Quaternion MaxRotation
{
get => Quaternion.Euler(new Vector3(MaxRotationX, MaxRotationY, MaxRotationZ));
set
{
Vector3 rot = value.eulerAngles;
MaxRotationX = rot.x;
MaxRotationY = rot.y;
MaxRotationZ = rot.z;
}
}
[Ignore]
public Vector3 MaxScale
{
get => new Vector3(MaxScaleX, MaxScaleY, MaxScaleZ);
set
{
MaxScaleX = value.x;
MaxScaleY = value.y;
MaxScaleZ = value.z;
}
}
public static readonly Dictionary<CharacterPartType, string> PART_TYPE_JOINT_MAP = new Dictionary<CharacterPartType, string>
{
[CharacterPartType.AttachmentBack] = "backAttach",
[CharacterPartType.AttachmentHipsFront] = "hipAttachFront",
[CharacterPartType.AttachmentHipsBack] = "hipAttachBack",
[CharacterPartType.AttachmentHipsLeft] = "hipAttach_l",
[CharacterPartType.AttachmentHipsRight] = "hipAttach_r",
[CharacterPartType.AttachmentShoulderLeft] = "shoulderAttach_l",
[CharacterPartType.AttachmentShoulderRight] = "shoulderAttach_r",
[CharacterPartType.AttachmentElbowLeft] = "elbowAttach_l",
[CharacterPartType.AttachmentElbowRight] = "elbowAttach_r",
[CharacterPartType.AttachmentKneeLeft] = "kneeAttach_l",
[CharacterPartType.AttachmentKneeRight] = "kneeAttach_r"
};
public SidekickBlendShapeRigMovement()
{
// Empty constructor required for SQLite
}
private SidekickBlendShapeRigMovement(CharacterPartType partType, BlendShapeType blendType)
{
ID = -1;
PartType = partType;
BlendType = blendType;
}
/// <summary>
/// Gets a list of all the parts in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all blend shape rig movements in the database.</returns>
public static List<SidekickBlendShapeRigMovement> GetAll(DatabaseManager dbManager)
{
return dbManager.GetCurrentDbConnection().Table<SidekickBlendShapeRigMovement>().ToList();
}
/// <summary>
/// Gets all the blend shape rig movements from the database, sorted into dictionaries for easy processing.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
/// <returns>All the blend shape rig movements from the database, sorted into dictionaries for easy processing.</returns>
public static Dictionary<CharacterPartType, Dictionary<BlendShapeType, SidekickBlendShapeRigMovement>> GetAllForProcessing(
DatabaseManager dbManager
)
{
Dictionary<CharacterPartType, Dictionary<BlendShapeType, SidekickBlendShapeRigMovement>> offsetLibrary =
new Dictionary<CharacterPartType, Dictionary<BlendShapeType, SidekickBlendShapeRigMovement>>();
List<SidekickBlendShapeRigMovement> allRigMovements = GetAll(dbManager);
foreach (CharacterPartType type in PART_TYPE_JOINT_MAP.Keys)
{
List<SidekickBlendShapeRigMovement> typeMovements = allRigMovements.Where(rm => rm.PartType == type).ToList();
Dictionary<BlendShapeType, SidekickBlendShapeRigMovement> typeMovementDictionary =
new Dictionary<BlendShapeType, SidekickBlendShapeRigMovement>();
foreach (BlendShapeType blendType in Enum.GetValues(typeof(BlendShapeType)))
{
SidekickBlendShapeRigMovement movement = typeMovements.FirstOrDefault(tm => tm.BlendType == blendType);
typeMovementDictionary[blendType] = movement;
}
offsetLibrary[type] = typeMovementDictionary;
}
return offsetLibrary;
}
/// <summary>
/// Gets a specific blend shape rig movement by its part type and blend shape type.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partType">The part type to filter by.</param>
/// <param name="blendType">The blend shape to filter by.</param>
/// <returns>The blend shape rig movement if it exists; otherwise null.</returns>
public static SidekickBlendShapeRigMovement GetByPartTypeAndBlendType(DatabaseManager dbManager, CharacterPartType partType, BlendShapeType blendType)
{
SidekickBlendShapeRigMovement rigMovement = dbManager.GetCurrentDbConnection().Table<SidekickBlendShapeRigMovement>().FirstOrDefault(rm
=> rm.BlendType == blendType && rm.PartType == partType);
return rigMovement ?? new SidekickBlendShapeRigMovement(partType, blendType);
}
public Vector3 GetBlendedOffsetValue(float blendValue)
{
return Vector3.Lerp(Vector3.zero, MaxOffset, blendValue);
}
public Quaternion GetBlendedRotationValue(float blendValue)
{
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), MaxRotation, blendValue);
}
public Vector3 GetBlendedScaleValue(float blendValue)
{
return Vector3.Lerp(Vector3.zero, MaxScale, blendValue);
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID < 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickBlendShapeRigMovement>(ID);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a4448e0059304113aa6a54e83bd2d846
timeCreated: 1732662833

View File

@@ -0,0 +1,75 @@
// 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 SQLite;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_body_shape_preset")]
public class SidekickBodyShapePreset
{
[PrimaryKey]
[AutoIncrement]
[Column("id")]
public int ID { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("body_type")]
public int BodyType { get; set; }
[Column("body_size")]
public int BodySize { get; set; }
[Column("musculature")]
public int Musculature { get; set; }
/// <summary>
/// Gets a list of all the Preset Body Shape in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all Preset Body Shapes in the database.</returns>
public static List<SidekickBodyShapePreset> GetAll(DatabaseManager dbManager)
{
return dbManager.GetCurrentDbConnection().Table<SidekickBodyShapePreset>().ToList();
}
/// <summary>
/// Gets a specific Preset Body Shape by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset Body Shape.</param>
/// <returns>The specific Preset Body Shape if it exists; otherwise null.</returns>
public static SidekickBodyShapePreset GetByID(DatabaseManager dbManager, int id)
{
return dbManager.GetCurrentDbConnection().Get<SidekickBodyShapePreset>(id);
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID < 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickBodyShapePreset>(ID);
}
}
}

View File

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

View File

@@ -0,0 +1,115 @@
// 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 SQLite;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_body_shape_preset_image")]
public class SidekickBodyShapePresetImage
{
private SidekickBodyShapePreset _bodyShapePreset;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_body_shape_preset")]
public int PtrPreset { get; set; }
[Column("img_data")]
public byte[] ImageData { get; set; }
[Column("img_width")]
public int Width { get; set; }
[Column("img_height")]
public int Height { get; set; }
[Ignore]
public SidekickBodyShapePreset BodyShapePreset
{
get => _bodyShapePreset;
set
{
_bodyShapePreset = value;
PtrPreset = value.ID;
}
}
/// <summary>
/// Gets a specific Preset Part by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset Part.</param>
/// <returns>The specific Preset Part if it exists; otherwise null.</returns>
public static SidekickBodyShapePresetImage GetByID(DatabaseManager dbManager, int id)
{
SidekickBodyShapePresetImage bodyShapePresetImage = dbManager.GetCurrentDbConnection().Find<SidekickBodyShapePresetImage>(id);
Decorate(dbManager, bodyShapePresetImage);
return bodyShapePresetImage;
}
/// <summary>
/// Gets a list of all the Preset Parts in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all preset parts in the database.</returns>
public static List<SidekickBodyShapePresetImage> GetAll(DatabaseManager dbManager)
{
List<SidekickBodyShapePresetImage> bodyShapePresetImages = dbManager.GetCurrentDbConnection().Table<SidekickBodyShapePresetImage>().ToList();
foreach (SidekickBodyShapePresetImage bodyShapePresetImage in bodyShapePresetImages)
{
Decorate(dbManager, bodyShapePresetImage);
}
return bodyShapePresetImages;
}
/// <summary>
/// Gets a list of all the Preset Part Images in the database that have the matching Part Preset.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="bodyShapePreset">The preset to get all the preset part images for.</param>
/// <returns>A list of all preset part images in the database for the given preset.</returns>
public static SidekickBodyShapePresetImage GetByPreset(DatabaseManager dbManager, SidekickBodyShapePreset bodyShapePreset)
{
SidekickBodyShapePresetImage bodyShapePresetImage = dbManager.GetCurrentDbConnection().Table<SidekickBodyShapePresetImage>()
.FirstOrDefault(bodyShapePresetImage => bodyShapePresetImage.PtrPreset == bodyShapePreset.ID);
if (bodyShapePresetImage != null)
{
Decorate(dbManager, bodyShapePresetImage);
}
return bodyShapePresetImage;
}
/// <summary>
/// Ensures that the given preset has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="bodyShapePresetImage">The color preset to decorate</param>
/// <returns>A color set with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickBodyShapePresetImage bodyShapePresetImage)
{
bodyShapePresetImage.BodyShapePreset ??= SidekickBodyShapePreset.GetByID(dbManager, bodyShapePresetImage.PtrPreset);
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
}
}
}

View File

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

View File

@@ -0,0 +1,44 @@
// 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 SQLite;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_color_filter")]
public class SidekickColorFilter
{
[PrimaryKey, Column("id")]
public int ID { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("display_name")]
public string DisplayName { get; set; }
/// <summary>
/// Gets a list of all the Color Filters in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all Color Filters in the database.</returns>
public static List<SidekickColorFilter> GetAll(DatabaseManager dbManager)
{
return dbManager.GetCurrentDbConnection().Table<SidekickColorFilter>().ToList();
}
/// <summary>
/// Gets a specific Color Filter by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Color Filter.</param>
/// <returns>The specific Color Filter if it exists; otherwise null.</returns>
public static SidekickColorFilter GetByID(DatabaseManager dbManager, int id)
{
return dbManager.GetCurrentDbConnection().Get<SidekickColorFilter>(id);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2e524419640c4fcdb41c8bdb5c26cb0c
timeCreated: 1711075931

View File

@@ -0,0 +1,204 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_color_preset")]
public class SidekickColorPreset
{
private SidekickSpecies _species;
[PrimaryKey]
[AutoIncrement]
[Column("id")]
public int ID { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("color_group")]
public ColorGroup ColorGroup { get; set; }
[Column("ptr_species")]
public int PtrSpecies { get; set; }
[Ignore]
public SidekickSpecies Species
{
get => _species;
set
{
_species = value;
PtrSpecies = value.ID;
}
}
/// <summary>
/// Gets a list of all the Color Presets in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all color presets in the database.</returns>
public static List<SidekickColorPreset> GetAll(DatabaseManager dbManager)
{
List<SidekickColorPreset> presets = dbManager.GetCurrentDbConnection().Table<SidekickColorPreset>().ToList();
foreach (SidekickColorPreset preset in presets)
{
Decorate(dbManager, preset);
}
return presets;
}
/// <summary>
/// Gets a list of all the Color Presets in the database that have the matching species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The species to get all the color presets for.</param>
/// <returns>A list of all color presets in the database for the given species.</returns>
public static List<SidekickColorPreset> GetAllBySpecies(DatabaseManager dbManager, SidekickSpecies species)
{
List<SidekickColorPreset> presets = dbManager.GetCurrentDbConnection().Table<SidekickColorPreset>()
.Where(set => set.PtrSpecies == species.ID)
.ToList();
foreach (SidekickColorPreset preset in presets)
{
preset.Species = species;
}
return presets;
}
/// <summary>
/// Gets a Color Presets in the database with the matching name if one exists.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="name">The name of the preset to retrieve.</param>
/// <returns>Returns a Color Presets in the database with the matching name if one exists; otherwise null.</returns>
public static SidekickColorPreset GetByName(DatabaseManager dbManager, string name)
{
SidekickColorPreset colorPreset = dbManager.GetCurrentDbConnection()
.Table<SidekickColorPreset>()
.FirstOrDefault(colorPreset => colorPreset.Name == name);
if (colorPreset != null)
{
Decorate(dbManager, colorPreset);
}
return colorPreset;
}
/// <summary>
/// Gets a list of all the Color Presets in the database that have the matching species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="colorGroup">The color group to get all the color presets for.</param>
/// <returns>A list of all color presets in the database for the given color group.</returns>
public static List<SidekickColorPreset> GetAllByColorGroup(DatabaseManager dbManager, ColorGroup colorGroup)
{
List<SidekickColorPreset> presets = dbManager.GetCurrentDbConnection().Table<SidekickColorPreset>()
.Where(preset => preset.ColorGroup == colorGroup)
.ToList();
foreach (SidekickColorPreset preset in presets)
{
Decorate(dbManager, preset);
}
return presets;
}
/// <summary>
/// Gets a list of all the Color Presets in the database that have the matching species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="colorGroup">The color group to get all the color presets for.</param>
/// <param name="species">The species to get the color presets for.</param>
/// <returns>A list of all color presets in the database for the given color group and species.</returns>
public static List<SidekickColorPreset> GetAllByColorGroupAndSpecies(
DatabaseManager dbManager,
ColorGroup colorGroup,
SidekickSpecies species
)
{
List<SidekickColorPreset> presets = dbManager.GetCurrentDbConnection()
.Table<SidekickColorPreset>()
.Where(preset => preset.ColorGroup == colorGroup && preset.PtrSpecies == species.ID)
.ToList();
foreach (SidekickColorPreset preset in presets)
{
preset.Species = species;
}
return presets;
}
/// <summary>
/// Gets a specific Color Preset by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Color Preset.</param>
/// <returns>The specific Color Preset if it exists; otherwise null.</returns>
public static SidekickColorPreset GetByID(DatabaseManager dbManager, int id)
{
SidekickColorPreset preset = dbManager.GetCurrentDbConnection().Find<SidekickColorPreset>(id);
Decorate(dbManager, preset);
return preset;
}
/// <summary>
/// Ensures that the given preset has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="preset">The color preset to decorate</param>
/// <returns>A color set with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickColorPreset preset)
{
if (preset.Species == null && preset.PtrSpecies >= 0)
{
preset.Species = SidekickSpecies.GetByID(dbManager, preset.PtrSpecies);
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID < 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
foreach (SidekickColorPresetRow row in SidekickColorPresetRow.GetAllByPreset(dbManager, this))
{
row.Delete(dbManager);
}
SidekickColorPresetImage image = SidekickColorPresetImage.GetByPresetAndColorGroup(dbManager, this, ColorGroup);
image?.Delete(dbManager);
dbManager.GetCurrentDbConnection().Delete<SidekickColorPreset>(ID);
}
}
}

View File

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

View File

@@ -0,0 +1,158 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_color_preset_image")]
public class SidekickColorPresetImage
{
private SidekickColorPreset _colorPreset;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_color_preset")]
public int PtrPreset { get; set; }
[Column("color_group")]
public ColorGroup ColorGroup { get; set; }
[Column("img_data")]
public byte[] ImageData { get; set; }
[Column("img_width")]
public int Width { get; set; }
[Column("img_height")]
public int Height { get; set; }
[Ignore]
public SidekickColorPreset ColorPreset
{
get => _colorPreset;
set
{
_colorPreset = value;
PtrPreset = value.ID;
}
}
/// <summary>
/// Gets a specific Preset Part by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset Part.</param>
/// <returns>The specific Preset Part if it exists; otherwise null.</returns>
public static SidekickColorPresetImage GetByID(DatabaseManager dbManager, int id)
{
SidekickColorPresetImage partPresetImage = dbManager.GetCurrentDbConnection().Find<SidekickColorPresetImage>(id);
Decorate(dbManager, partPresetImage);
return partPresetImage;
}
/// <summary>
/// Gets a list of all the Preset Parts in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all preset parts in the database.</returns>
public static List<SidekickColorPresetImage> GetAll(DatabaseManager dbManager)
{
List<SidekickColorPresetImage> partPresetImages = dbManager.GetCurrentDbConnection().Table<SidekickColorPresetImage>().ToList();
foreach (SidekickColorPresetImage partPresetImage in partPresetImages)
{
Decorate(dbManager, partPresetImage);
}
return partPresetImages;
}
/// <summary>
/// Gets a list of all the Preset Part Images in the database that have the matching Part Preset.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPreset">The preset to get all the preset part images for.</param>
/// <returns>A list of all preset part images in the database for the given preset.</returns>
public static List<SidekickColorPresetImage> GetAllByPreset(DatabaseManager dbManager, SidekickPartPreset partPreset)
{
List<SidekickColorPresetImage> partPresetImages = dbManager.GetCurrentDbConnection().Table<SidekickColorPresetImage>()
.Where(presetPart => presetPart.PtrPreset == partPreset.ID)
.ToList();
foreach (SidekickColorPresetImage partPresetImage in partPresetImages)
{
Decorate(dbManager, partPresetImage);
}
return partPresetImages;
}
/// <summary>
/// Gets the Preset Part Image in the database that have the matching Part Preset and Part Group.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPreset">The preset to get the preset part image for.</param>
/// <param name="partGroup">The part group to filter the results by.</param>
/// <returns>The preset part image in the database for the given preset and part group.</returns>
public static SidekickColorPresetImage GetByPresetAndColorGroup(
DatabaseManager dbManager,
SidekickColorPreset partPreset,
ColorGroup partGroup
)
{
SidekickColorPresetImage partPresetImage = dbManager.GetCurrentDbConnection().Table<SidekickColorPresetImage>()
.FirstOrDefault(presetPart => presetPart.PtrPreset == partPreset.ID && presetPart.ColorGroup == partGroup);
if (partPresetImage != null)
{
Decorate(dbManager, partPresetImage);
}
return partPresetImage;
}
/// <summary>
/// Ensures that the given preset has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPresetImage">The color preset to decorate</param>
/// <returns>A color set with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickColorPresetImage partPresetImage)
{
if (partPresetImage != null)
{
if (partPresetImage.ColorPreset == null && partPresetImage.PtrPreset >= 0)
{
partPresetImage.ColorPreset = SidekickColorPreset.GetByID(dbManager, partPresetImage.PtrPreset);
}
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickColorPresetImage>(ID);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7586d1ff5aab4e6a972345f299975238
timeCreated: 1730241515

View File

@@ -0,0 +1,288 @@
// 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 SQLite;
using System.Collections.Generic;
using UnityEngine;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_color_preset_row")]
public class SidekickColorPresetRow
{
private SidekickColorPreset _colorPreset;
private SidekickColorProperty _colorProperty;
private Color? _niceColor;
private Color? _niceMetallic;
private Color? _niceSmoothness;
private Color? _niceReflection;
private Color? _niceEmission;
private Color? _niceOpacity;
[PrimaryKey]
[AutoIncrement]
[Column("id")]
public int ID { get; set; }
[Column("ptr_color_preset")]
public int PtrColorPreset { get; set; }
[Column("ptr_color_property")]
public int PtrColorProperty { get; set; }
[Column("color")]
public string MainColor { get; set; }
[Column("metallic")]
public string Metallic { get; set; }
[Column("smoothness")]
public string Smoothness { get; set; }
[Column("reflection")]
public string Reflection { get; set; }
[Column("emission")]
public string Emission { get; set; }
[Column("opacity")]
public string Opacity { get; set; }
[Ignore]
public SidekickColorPreset ColorPreset
{
get => _colorPreset;
set
{
_colorPreset = value;
PtrColorPreset = value.ID;
}
}
[Ignore]
public SidekickColorProperty ColorProperty
{
get => _colorProperty;
set
{
_colorProperty = value;
PtrColorProperty = value.ID;
}
}
[Ignore]
public Color NiceColor
{
get
{
_niceColor ??= ColorUtility.TryParseHtmlString("#" + MainColor, out Color color) ? color : Color.white;
return (Color) _niceColor;
}
set
{
_niceColor = value;
MainColor = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceMetallic
{
get
{
_niceMetallic ??= ColorUtility.TryParseHtmlString("#" + Metallic, out Color color) ? color : Color.white;
return (Color) _niceMetallic;
}
set
{
_niceMetallic = value;
Metallic = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceSmoothness
{
get
{
_niceSmoothness ??= ColorUtility.TryParseHtmlString("#" + Smoothness, out Color color) ? color : Color.white;
return (Color) _niceSmoothness;
}
set
{
_niceSmoothness = value;
Smoothness = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceReflection
{
get
{
_niceReflection ??= ColorUtility.TryParseHtmlString("#" + Reflection, out Color color) ? color : Color.white;
return (Color) _niceReflection;
}
set
{
_niceReflection = value;
Reflection = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceEmission
{
get
{
_niceEmission ??= ColorUtility.TryParseHtmlString("#" + Emission, out Color color) ? color : Color.white;
return (Color) _niceEmission;
}
set
{
_niceEmission = value;
Emission = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceOpacity
{
get
{
_niceOpacity ??= ColorUtility.TryParseHtmlString("#" + Opacity, out Color color) ? color : Color.white;
return (Color) _niceOpacity;
}
set
{
_niceOpacity = value;
Opacity = ColorUtility.ToHtmlStringRGB(value);
}
}
/// <summary>
/// Gets a list of all the Color Preset Rows in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all Color Preset Rows in the database.</returns>
public static List<SidekickColorPresetRow> GetAll(DatabaseManager dbManager)
{
List<SidekickColorPresetRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickColorPresetRow>().ToList();
foreach (SidekickColorPresetRow row in rows)
{
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Gets a specific Color Preset Row by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Color Preset Row.</param>
/// <returns>The specific Color Preset Row if it exists; otherwise null.</returns>
public static SidekickColorPresetRow GetByID(DatabaseManager dbManager, int id)
{
SidekickColorPresetRow row = dbManager.GetCurrentDbConnection().Find<SidekickColorPresetRow>(id);
Decorate(dbManager, row);
return row;
}
/// <summary>
/// Gets a list of all the Color Preset Rows in the database that have the matching Property.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="property">The property to get all the color preset rows for.</param>
/// <returns>A list of all color preset rows in the database for the given property.</returns>
public static List<SidekickColorPresetRow> GetAllByProperty(DatabaseManager dbManager, SidekickColorProperty property)
{
List<SidekickColorPresetRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickColorPresetRow>()
.Where(row => row.PtrColorProperty == property.ID)
.ToList();
foreach (SidekickColorPresetRow row in rows)
{
row.ColorProperty = property;
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Gets a list of all the Color Preset Rows in the database that have the matching Set and Property.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="preset">The color preset to get the color preset rows for.</param>
/// <param name="property">The property to get all the color preset rows for.</param>
/// <returns>A list of all color preset rows in the database for the given set and property.</returns>
public static List<SidekickColorPresetRow> GetAllByPresetAndProperty(
DatabaseManager dbManager,
SidekickColorPreset preset,
SidekickColorProperty property
)
{
List<SidekickColorPresetRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickColorPresetRow>()
.Where(row => row.PtrColorPreset == preset.ID && row.PtrColorProperty == property.ID)
.ToList();
foreach (SidekickColorPresetRow row in rows)
{
row.ColorProperty = property;
row.ColorPreset = preset;
}
return rows;
}
/// <summary>
/// Gets a list of all the Color Preset Rows in the database that have the matching Set.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="preset">The color preset to get the color preset rows for.</param>
/// <returns>A list of all color preset rows in the database for the given set.</returns>
public static List<SidekickColorPresetRow> GetAllByPreset(DatabaseManager dbManager, SidekickColorPreset preset)
{
List<SidekickColorPresetRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickColorPresetRow>()
.Where(row => row.PtrColorPreset == preset.ID)
.ToList();
foreach (SidekickColorPresetRow row in rows)
{
row.ColorPreset = preset;
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Ensures that the given row has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="row">The color preset row to decorate</param>
/// <returns>A color preset row with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickColorPresetRow row)
{
// don't need PtrColorProperty check as should always be >= 0; if it's not, we have bad data and want the error
row.ColorProperty ??= SidekickColorProperty.GetByID(dbManager, row.PtrColorProperty);
row.ColorPreset ??= SidekickColorPreset.GetByID(dbManager, row.PtrColorPreset);
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID < 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickColorPresetRow>(ID);
}
}
}

View File

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

View File

@@ -0,0 +1,83 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
using UnityEngine;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_color_property")]
public class SidekickColorProperty
{
[PrimaryKey, Column("id")]
public int ID { get; set; }
// NOTE : automatically converts to the integer mapping of the enum
[Column("color_group")]
public ColorGroup Group { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("u")]
public int U { get; set; }
[Column("v")]
public int V { get; set; }
/// <summary>
/// Gets a list of all the Color Properties in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all Color Properties in the database.</returns>
public static List<SidekickColorProperty> GetAll(DatabaseManager dbManager)
{
return dbManager.GetCurrentDbConnection().Table<SidekickColorProperty>().ToList();
}
/// <summary>
/// Gets a list of all the Color Properties in the database that have the matching group.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="group">The color group to get all the color properties for.</param>
/// <returns>A list of all color groups in the database for the given group.</returns>
public static List<SidekickColorProperty> GetAllByGroup(DatabaseManager dbManager, ColorGroup group)
{
return dbManager.GetCurrentDbConnection().Table<SidekickColorProperty>().Where(prop => prop.Group == group).ToList();
}
/// <summary>
/// Gets a specific Color Property by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Color Property.</param>
/// <returns>The specific Color Property if it exists; otherwise null.</returns>
public static SidekickColorProperty GetByID(DatabaseManager dbManager, int id)
{
return dbManager.GetCurrentDbConnection().Find<SidekickColorProperty>(id);
}
/// <summary>
/// Gets a list of properties that match any of the UVs from the given list.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="uVs">The list of UVs to get the properties for.</param>
/// <returns>A list of properties that match any of the UVs from the given list.</returns>
public static List<SidekickColorProperty> GetByUVs(DatabaseManager dbManager, List<Vector2> uVs)
{
List<SidekickColorProperty> properties = new List<SidekickColorProperty>();
foreach (Vector2 uv in uVs)
{
properties.AddRange(
dbManager.GetCurrentDbConnection().Table<SidekickColorProperty>()
.Where(prop => prop.U == uv.x && prop.V == uv.y)
.ToList()
);
}
return properties;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 111a0f92d48c4b54bfc31c7845f94085
timeCreated: 1711070621

View File

@@ -0,0 +1,347 @@
// 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 SQLite;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_color_row")]
public class SidekickColorRow
{
private SidekickColorSet _colorSet;
private SidekickColorProperty _colorProperty;
private Color? _niceColor;
private Color? _niceMetallic;
private Color? _niceSmoothness;
private Color? _niceReflection;
private Color? _niceEmission;
private Color? _niceOpacity;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_color_set")]
public int PtrColorSet { get; set; }
[Column("ptr_color_property")]
public int PtrColorProperty { get; set; }
[Column("color")]
public string MainColor { get; set; }
[Column("metallic")]
public string Metallic { get; set; }
[Column("smoothness")]
public string Smoothness { get; set; }
[Column("reflection")]
public string Reflection { get; set; }
[Column("emission")]
public string Emission { get; set; }
[Column("opacity")]
public string Opacity { get; set; }
[Ignore]
public SidekickColorSet ColorSet
{
get => _colorSet;
set
{
_colorSet = value;
PtrColorSet = value.ID;
}
}
[Ignore]
public SidekickColorProperty ColorProperty
{
get => _colorProperty;
set
{
_colorProperty = value;
PtrColorProperty = value.ID;
}
}
[Ignore]
public Color NiceColor
{
get
{
_niceColor ??= ColorUtility.TryParseHtmlString("#" + MainColor, out Color color) ? color : Color.white;
return (Color) _niceColor;
}
set
{
_niceColor = value;
MainColor = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceMetallic
{
get
{
_niceMetallic ??= ColorUtility.TryParseHtmlString("#" + Metallic, out Color color) ? color : Color.white;
return (Color) _niceMetallic;
}
set
{
_niceMetallic = value;
Metallic = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceSmoothness
{
get
{
_niceSmoothness ??= ColorUtility.TryParseHtmlString("#" + Smoothness, out Color color) ? color : Color.white;
return (Color) _niceSmoothness;
}
set
{
_niceSmoothness = value;
Smoothness = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceReflection
{
get
{
_niceReflection ??= ColorUtility.TryParseHtmlString("#" + Reflection, out Color color) ? color : Color.white;
return (Color) _niceReflection;
}
set
{
_niceReflection = value;
Reflection = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceEmission
{
get
{
_niceEmission ??= ColorUtility.TryParseHtmlString("#" + Emission, out Color color) ? color : Color.white;
return (Color) _niceEmission;
}
set
{
_niceEmission = value;
Emission = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public Color NiceOpacity
{
get
{
_niceOpacity ??= ColorUtility.TryParseHtmlString("#" + Opacity, out Color color) ? color : Color.white;
return (Color) _niceOpacity;
}
set
{
_niceOpacity = value;
Opacity = ColorUtility.ToHtmlStringRGB(value);
}
}
[Ignore]
public bool IsLocked { get; set; }
[Ignore]
public Image ButtonImage { get; set; }
/// <summary>
/// Gets a list of all the Color Rows in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all Color Rows in the database.</returns>
public static List<SidekickColorRow> GetAll(DatabaseManager dbManager)
{
List<SidekickColorRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickColorRow>().ToList();
foreach (SidekickColorRow row in rows)
{
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Gets a specific Color Row by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Color Row.</param>
/// <returns>The specific Color Row if it exists; otherwise null.</returns>
public static SidekickColorRow GetByID(DatabaseManager dbManager, int id)
{
SidekickColorRow row = dbManager.GetCurrentDbConnection().Find<SidekickColorRow>(id);
Decorate(dbManager, row);
return row;
}
/// <summary>
/// Gets a list of all the Color Rows in the database that have the matching Property.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="property">The property to get all the color rows for.</param>
/// <returns>A list of all color rows in the database for the given property.</returns>
public static List<SidekickColorRow> GetAllByProperty(DatabaseManager dbManager, SidekickColorProperty property)
{
List<SidekickColorRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickColorRow>()
.Where(row => row.PtrColorProperty == property.ID)
.ToList();
foreach (SidekickColorRow row in rows)
{
row.ColorProperty = property;
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Gets a list of all the Color Rows in the database that have the matching Set and Property.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="set">The color set to get the color rows for.</param>
/// <param name="property">The property to get all the color rows for.</param>
/// <returns>A list of all color rows in the database for the given set and property.</returns>
public static List<SidekickColorRow> GetAllBySetAndProperty(DatabaseManager dbManager, SidekickColorSet set, SidekickColorProperty property)
{
List<SidekickColorRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickColorRow>()
.Where(row => row.PtrColorSet == set.ID && row.PtrColorProperty == property.ID)
.ToList();
foreach (SidekickColorRow row in rows)
{
row.ColorSet = set;
row.ColorProperty = property;
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Gets a list of all the Color Rows in the database that have the matching Set.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="set">The color set to get the color rows for.</param>
/// <returns>A list of all color rows in the database for the given set.</returns>
public static List<SidekickColorRow> GetAllBySet(DatabaseManager dbManager, SidekickColorSet set)
{
List<SidekickColorRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickColorRow>()
.Where(row => row.PtrColorSet == set.ID)
.ToList();
foreach (SidekickColorRow row in rows)
{
row.ColorSet = set;
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Creates a SidekickColorRow from a SidekickColorPresetRow.
/// </summary>
/// <param name="row">The SidekickColorPresetRow to convert.</param>
/// <returns>A SidekickColorRow created from a SidekickColorPresetRow.</returns>
public static SidekickColorRow CreateFromPresetColorRow(SidekickColorPresetRow row)
{
SidekickColorRow newRow = new SidekickColorRow()
{
MainColor = row.MainColor,
Emission = row.Emission,
Metallic = row.Metallic,
Opacity = row.Opacity,
Reflection = row.Reflection,
Smoothness = row.Smoothness,
ColorProperty = row.ColorProperty
};
return newRow;
}
/// <summary>
/// Ensures that the given row has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="row">The color row to decorate</param>
/// <returns>A color row with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickColorRow row)
{
// don't need PtrColorProperty check as should always be >= 0; if it's not, we have bad data and want the error
row.ColorProperty ??= SidekickColorProperty.GetByID(dbManager, row.PtrColorProperty);
if (row.ColorSet == null && row.PtrColorSet >= 0)
{
row.ColorSet = SidekickColorSet.GetByID(dbManager, row.PtrColorSet);
}
}
/// <summary>
/// Delete this color row from the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
int deletedCount = dbManager.GetCurrentDbConnection().Delete<SidekickColorRow>(ID);
if (deletedCount == 0)
{
throw new Exception($"Could not delete color set with ID '{ID}'");
}
}
/// <summary>
/// Inserts, or updates the values in the database, depending on this object has been saved before or not.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
public void Save(DatabaseManager dbManager)
{
if (ID < 0)
{
SaveToDB(dbManager);
}
else
{
UpdateDB(dbManager);
}
}
/// <summary>
/// Saves this Color Set to the database with the current values.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
private void SaveToDB(DatabaseManager dbManager)
{
SQLiteConnection connection = dbManager.GetCurrentDbConnection();
int insertCount = connection.Insert(this);
if (insertCount == 0)
{
throw new Exception("Unable to save current color row");
}
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(connection.Handle);
}
/// <summary>
/// Updates this Color Set in the database with the current values.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
private void UpdateDB(DatabaseManager dbManager)
{
int updatedCount = dbManager.GetCurrentDbConnection().Update(this);
if (updatedCount == 0)
{
throw new Exception($"Could not update color row with ID '{ID}'");
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7364093cfc524536bef3f864a7991e75
timeCreated: 1711501683

View File

@@ -0,0 +1,222 @@
// 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 SQLite;
using System;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_color_set")]
public class SidekickColorSet
{
private SidekickSpecies _species;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
// NOTE : cannot make private as the ORM requires it to be visible when calling Save()
// NOTE : not possible to encapsulate setting _species without a dbManager reference, so always set via Species instead
[Column("ptr_species")]
public int PtrSpecies { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("src_color")]
public string SourceColorPath { get; set; }
[Column("src_metallic")]
public string SourceMetallicPath { get; set; }
[Column("src_smoothness")]
public string SourceSmoothnessPath { get; set; }
[Column("src_reflection")]
public string SourceReflectionPath { get; set; }
[Column("src_emission")]
public string SourceEmissionPath { get; set; }
[Column("src_opacity")]
public string SourceOpacityPath { get; set; }
[Ignore]
public SidekickSpecies Species
{
get => _species;
set
{
_species = value;
PtrSpecies = value.ID;
}
}
/// <summary>
/// Gets a list of all the Color Sets in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all color sets in the database.</returns>
public static List<SidekickColorSet> GetAll(DatabaseManager dbManager)
{
List<SidekickColorSet> sets = dbManager.GetCurrentDbConnection().Table<SidekickColorSet>().ToList();
foreach (SidekickColorSet set in sets)
{
Decorate(dbManager, set);
}
return sets;
}
/// <summary>
/// Gets a list of all the Color Sets in the database that have the matching species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The species to get all the color sets for.</param>
/// <returns>A list of all color sets in the database for the given species.</returns>
public static List<SidekickColorSet> GetAllBySpecies(DatabaseManager dbManager, SidekickSpecies species)
{
List<SidekickColorSet> sets = dbManager.GetCurrentDbConnection().Table<SidekickColorSet>()
.Where(set => set.PtrSpecies == species.ID)
.ToList();
foreach (SidekickColorSet set in sets)
{
set.Species = species;
Decorate(dbManager, set);
}
return sets;
}
/// <summary>
/// Gets the default Color Set in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>The default Color Set in the database.</returns>
public static SidekickColorSet GetDefault(DatabaseManager dbManager)
{
SidekickColorSet set = dbManager.GetCurrentDbConnection().Get<SidekickColorSet>(set => set.PtrSpecies == -1);
Decorate(dbManager, set);
return set;
}
/// <summary>
/// Gets count of all the Color Sets in the database that have the matching species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The species to get the color set count for.</param>
/// <returns>The count of all color sets in the database for the given species.</returns>
public static int GetCountBySpecies(DatabaseManager dbManager, SidekickSpecies species)
{
return dbManager.GetCurrentDbConnection().Table<SidekickColorSet>().Count(set => set.PtrSpecies == species.ID);
}
/// <summary>
/// Gets a specific Color Set by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Color Set.</param>
/// <returns>The specific Color Set if it exists; otherwise null.</returns>
public static SidekickColorSet GetByID(DatabaseManager dbManager, int id)
{
SidekickColorSet set = dbManager.GetCurrentDbConnection().Find<SidekickColorSet>(id);
Decorate(dbManager, set);
return set;
}
/// <summary>
/// Gets a specific Color Set by its database name.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="name">The name of the required Color Set.</param>
/// <returns>The specific Color Set if it exists; otherwise null.</returns>
public static SidekickColorSet GetByName(DatabaseManager dbManager, string name)
{
SidekickColorSet set = dbManager.GetCurrentDbConnection().Table<SidekickColorSet>().FirstOrDefault(set => set.Name == name);
Decorate(dbManager, set);
return set;
}
/// <summary>
/// Checks if the given color set name exists in the database or not.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="name">The name to check for.</param>
/// <returns>True if the name exists in the database; otherwise False.</returns>
public static bool DoesNameExist(DatabaseManager dbManager, string name)
{
return dbManager.GetCurrentDbConnection().Table<SidekickColorSet>().Count(set => set.Name == name) > 0;
}
/// <summary>
/// Ensures that the given set has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="set">The color set to decorate</param>
/// <returns>A color set with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickColorSet set)
{
if (set.Species == null && set.PtrSpecies >= 0)
{
set.Species = SidekickSpecies.GetByID(dbManager, set.PtrSpecies);
}
}
/// <summary>
/// Delete this color set from the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
int deletedCount = dbManager.GetCurrentDbConnection().Delete<SidekickColorSet>(ID);
if (deletedCount == 0)
{
throw new Exception($"Could not delete color set with ID '{ID}'");
}
}
/// <summary>
/// Inserts, or updates the values in the database, depending on this object has been saved before or not.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
public void Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
SaveToDB(dbManager);
}
else
{
UpdateDB(dbManager);
}
}
/// <summary>
/// Saves this Color Set to the database with the current values.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
private void SaveToDB(DatabaseManager dbManager)
{
SQLiteConnection connection = dbManager.GetCurrentDbConnection();
int insertCount = connection.Insert(this);
if (insertCount == 0)
{
throw new Exception("Unable to save current color set");
}
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(connection.Handle);
}
/// <summary>
/// Updates this Color Set in the database with the current values.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
private void UpdateDB(DatabaseManager dbManager)
{
int updatedCount = dbManager.GetCurrentDbConnection().Update(this);
if (updatedCount == 0)
{
throw new Exception($"Could not update color set with ID '{ID}'");
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 68d1d4b9f3c2474d99f37b7b600c2305
timeCreated: 1711058031

View File

@@ -0,0 +1,39 @@
// 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 SQLite;
using System;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_vdata")]
public class SidekickDBVersion
{
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("semantic_version")]
public string SemanticVersion { get; set; }
[Column("update_time")]
public DateTime LastUpdated { get; set; }
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5ee48c6f79044f06b72466f41d770727
timeCreated: 1716368689

View File

@@ -0,0 +1,346 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_part")]
public class SidekickPart
{
private SidekickSpecies _species;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_species")]
public int PtrSpecies { get; set; }
[Column("type")]
public CharacterPartType Type { get; set; }
[Column("part_group")]
public PartGroup PartGroup { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("part_file_name")]
public string FileName { get; set; }
[Column("part_location")]
public string Location { get; set; }
[Column("uses_wrap")]
public bool UsesWrap { get; set; }
[Column("file_exists")]
public bool FileExists { get; set; }
[Ignore]
public SidekickSpecies Species
{
get => _species;
set
{
_species = value;
PtrSpecies = value.ID;
}
}
/// <summary>
/// Gets a specific Preset Part by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset Part.</param>
/// <returns>The specific Preset Part if it exists; otherwise null.</returns>
public static SidekickPart GetByID(DatabaseManager dbManager, int id)
{
SidekickPart part = dbManager.GetCurrentDbConnection().Find<SidekickPart>(id);
Decorate(dbManager, part);
return part;
}
/// <summary>
/// Gets a list of all the parts in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all parts in the database.</returns>
public static List<SidekickPart> GetAll(DatabaseManager dbManager)
{
List<SidekickPart> parts = dbManager.GetCurrentDbConnection().Table<SidekickPart>().ToList();
foreach (SidekickPart part in parts)
{
Decorate(dbManager, part);
}
return parts;
}
/// <summary>
/// Gets a list of all the parts in the database for a given Character Part Type.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partType">The Character Part Type to get all the parts for.</param>
/// <returns>A list of all parts for the given Character Part Type in the database.</returns>
public static List<SidekickPart> GetAllForPartType(DatabaseManager dbManager, CharacterPartType partType)
{
List<SidekickPart> parts = dbManager.GetCurrentDbConnection().Table<SidekickPart>().Where(part => part.Type == partType).ToList();
foreach (SidekickPart part in parts)
{
Decorate(dbManager, part);
}
return parts;
}
/// <summary>
/// Gets a list of all the parts in the database for a given Character Part Type.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The Character Part Type to get all the parts for.</param>
/// <param name="onlyPartsWithFile">Whether to include parts that have a file in the project or not.</param>
/// <returns>A list of all parts for the given Character Part Type in the database.</returns>
public static List<SidekickPart> GetAllForSpecies(DatabaseManager dbManager, SidekickSpecies species, bool onlyPartsWithFile = true)
{
List<SidekickPart> parts = new List<SidekickPart>();
if (onlyPartsWithFile)
{
parts = dbManager.GetCurrentDbConnection().Table<SidekickPart>().Where(part => part.PtrSpecies == species.ID && part.FileExists == onlyPartsWithFile).ToList();
}
else
{
parts = dbManager.GetCurrentDbConnection().Table<SidekickPart>().Where(part => part.PtrSpecies == species.ID).ToList();
}
foreach (SidekickPart part in parts)
{
Decorate(dbManager, part);
}
return parts;
}
/// <summary>
/// Get the part in the database for the given part file name.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="fileName">The file name to get the part for.</param>
/// <returns>A part in the database for the given part file name if it exists; otherwise null</returns>
public static SidekickPart GetByPartFileName(DatabaseManager dbManager, string fileName)
{
SidekickPart part = dbManager.GetCurrentDbConnection().Table<SidekickPart>().FirstOrDefault(part => part.FileName == fileName);
Decorate(dbManager, part);
return part;
}
/// <summary>
/// Gets all the base parts from the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all the base parts from the database.</returns>
public static List<SidekickPart> GetBaseParts(DatabaseManager dbManager)
{
List<SidekickPart> parts = dbManager.GetCurrentDbConnection().Table<SidekickPart>().Where(part => part.FileName.Contains("_BASE_")).ToList();
foreach (SidekickPart part in parts)
{
Decorate(dbManager, part);
}
return parts;
}
/// <summary>
/// Search for a part in the database where the part name or filename match the given term.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partName">The term to search for the part with.</param>
/// <returns>A part in the database for that matches the search term if it exists; otherwise null</returns>
public static SidekickPart SearchForByName(DatabaseManager dbManager, string partName)
{
SidekickPart part = dbManager.GetCurrentDbConnection().Table<SidekickPart>().FirstOrDefault(part => part.Name == partName || part
.FileName.Contains(partName));
Decorate(dbManager, part);
return part;
}
/// <summary>
/// Checks to see if the provided part name is unique.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partName">The part name to check and see if it is unique.</param>
/// <returns>True if no part exists in the database with given name; otherwise false.</returns>
public static bool IsPartNameUnique(DatabaseManager dbManager, string partName)
{
SidekickPart part = dbManager.GetCurrentDbConnection().Table<SidekickPart>().FirstOrDefault(part => part.Name == partName);
return part == null;
}
/// <summary>
/// Gets the species for a specific part.
/// TODO: get from the DB when data is populated.
/// </summary>
/// <param name="allSpecies">The list of all species to return a populated species object from.</param>
/// <param name="partName">The name of the part to get the species for.</param>
/// <returns>The species the part belongs to.</returns>
public static SidekickSpecies GetSpeciesForPart(List<SidekickSpecies> allSpecies, string partName)
{
string shortcode = partName.Split('_').Last().Substring(0, 2);
SidekickSpecies selectedSpecies = allSpecies[0];
foreach (SidekickSpecies species in allSpecies)
{
if (string.Equals(shortcode, species.Code, StringComparison.CurrentCultureIgnoreCase))
{
selectedSpecies = species;
}
}
return selectedSpecies;
}
/// <summary>
/// Updates all of the given parts in the DB. This is an Update only, and will not insert new objects.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
/// <param name="parts">The parts to update</param>
public static void UpdateAll(DatabaseManager dbManager, List<SidekickPart> parts)
{
dbManager.GetCurrentDbConnection().UpdateAll(parts, false);
}
/// <summary>
/// Ensures that the given part has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="part">The part to decorate</param>
private static void Decorate(DatabaseManager dbManager, SidekickPart part)
{
if (part != null)
{
if (part.Species == null && part.PtrSpecies >= 0)
{
part.Species = SidekickSpecies.GetByID(dbManager, part.PtrSpecies);
}
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Gets the image associated with this part.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
/// <returns>The image associated with this part.</returns>
public SidekickPartImage GetImageForPart(DatabaseManager dbManager)
{
return SidekickPartImage.GetByPart(dbManager, this);
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
foreach (SidekickPartFilterRow row in SidekickPartFilterRow.GetAllForPart(dbManager, this))
{
row.Delete(dbManager);
}
foreach (SidekickPartPresetRow row in SidekickPartPresetRow.GetAllByPart(dbManager, this))
{
row.Delete(dbManager);
}
foreach (SidekickPartSpeciesLink link in SidekickPartSpeciesLink.GetAllForPart(dbManager, this))
{
link.Delete(dbManager);
}
SidekickPartImage image = SidekickPartImage.GetByPart(dbManager, this);
image?.Delete(dbManager);
dbManager.GetCurrentDbConnection().Delete<SidekickPart>(ID);
}
/// <summary>
/// Gets the GameObject model of this part.
/// </summary>
/// <returns>A GameObject with the part model</returns>
public GameObject GetPartModel()
{
string resource = GetResourcePath(Location);
return Resources.Load<GameObject>(resource);
}
/// <summary>
/// Checks if the file for this part exists.
/// </summary>
/// <returns>True if the file is available; otherwise false</returns>
public bool IsFileAvailable()
{
FileExists = File.Exists(Location);
return FileExists;
}
/// <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)
{
int startIndex = fullPath.IndexOf("Resources", StringComparison.Ordinal) + 10;
string resourcePath = fullPath.Substring(startIndex, fullPath.Length - startIndex);
return Path.Combine(Path.GetDirectoryName(resourcePath)?? "", Path.GetFileNameWithoutExtension(resourcePath));
}
/// <inheritdoc cref="Equals"/>
public override bool Equals(object obj)
{
SidekickPart part = (SidekickPart) obj;
if (ID > 0 && part?.ID > 0)
{
return ID == part?.ID;
}
return Name.Equals(part?.Name);
}
/// <inheritdoc cref="GetHashCode"/>
public override int GetHashCode()
{
HashCode hashCode = new HashCode();
hashCode.Add(_species);
hashCode.Add(ID);
hashCode.Add(PtrSpecies);
hashCode.Add((int) Type);
hashCode.Add((int) PartGroup);
hashCode.Add(Name);
hashCode.Add(FileName);
hashCode.Add(Location);
hashCode.Add(UsesWrap);
hashCode.Add(FileExists);
return hashCode.ToHashCode();
}
}
}

View File

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

View File

@@ -0,0 +1,125 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
using System.Linq;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_part_filter")]
public class SidekickPartFilter
{
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("filter_type")]
public FilterType Type { get; set; }
[Column("filter_term")]
public string Term { get; set; }
/// <summary>
/// Gets a specific Part Filter by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Part Filter.</param>
/// <returns>The specific Part Filter if it exists; otherwise null.</returns>
public static SidekickPartFilter GetByID(DatabaseManager dbManager, int id)
{
SidekickPartFilter filter = dbManager.GetCurrentDbConnection().Find<SidekickPartFilter>(id);
return filter;
}
/// <summary>
/// Gets a list of all the part filters in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all part filters in the database.</returns>
public static List<SidekickPartFilter> GetAll(DatabaseManager dbManager)
{
List<SidekickPartFilter> filters = dbManager.GetCurrentDbConnection().Table<SidekickPartFilter>().ToList();
return filters;
}
/// <summary>
/// Gets a list of all the filters in the database for a given Character Part Type.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filterType">The Character Part Type to get all the filters for.</param>
/// <param name="excludeFiltersWithNoParts">Whether to exclude filters that have no parts associated</param>
/// <returns>A list of all filters for the given Character Part Type in the database.</returns>
public static List<SidekickPartFilter> GetAllForFilterType(DatabaseManager dbManager, FilterType filterType, bool
excludeFiltersWithNoParts = true)
{
List<SidekickPartFilter> filters = dbManager.GetCurrentDbConnection().Table<SidekickPartFilter>().Where(filter => filter.Type == filterType).ToList();
if (excludeFiltersWithNoParts)
{
List<SidekickPartFilter> toRemove = new List<SidekickPartFilter>();
foreach (SidekickPartFilter filter in filters)
{
List<SidekickPartFilterRow> rows = SidekickPartFilterRow.GetAllForFilter(dbManager, filter);
rows = rows.Where(row => !row.Part.FileName.Contains("_BASE_")).ToList();
if (rows.Count < 1)
{
toRemove.Add(filter);
}
}
filters.RemoveAll(filter => toRemove.Contains(filter));
}
return filters;
}
/// <summary>
/// Searches for a filter in the database with the given term and filter type.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filterTerm">The term to search for.</param>
/// <param name="filterType">The Character Part Type to search for.</param>
/// <returns>The filter with the given term and given Character Part Type in the database if it exist; otherwise null.</returns>
public static SidekickPartFilter GetByTermAndFilterType(DatabaseManager dbManager, string filterTerm, FilterType filterType)
{
SidekickPartFilter filter = dbManager.GetCurrentDbConnection().Table<SidekickPartFilter>()
.FirstOrDefault(filter => filter.Term == filterTerm && filter.Type == filterType);
return filter;
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
foreach (SidekickPartFilterRow row in SidekickPartFilterRow.GetAllForFilter(dbManager, this))
{
row.Delete(dbManager);
}
dbManager.GetCurrentDbConnection().Delete<SidekickPartFilter>(ID);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0150aa2dd4f647b5992f3db3fe96b562
timeCreated: 1740023330

View File

@@ -0,0 +1,219 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
using System.Linq;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_part_filter_row")]
public class SidekickPartFilterRow
{
private SidekickPartFilter _filter;
private SidekickPart _part;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_filter")]
public int PtrFilter { get; set; }
[Column("ptr_part")]
public int PtrPart { get; set; }
[Ignore]
public SidekickPartFilter Filter
{
get => _filter;
set
{
_filter = value;
PtrFilter = value.ID;
}
}
[Ignore]
public SidekickPart Part
{
get => _part;
set
{
_part = value;
PtrPart = value.ID;
}
}
/// <summary>
/// Gets a specific Part Filter by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Part Filter.</param>
/// <returns>The specific Part Filter if it exists; otherwise null.</returns>
public static SidekickPartFilterRow GetByID(DatabaseManager dbManager, int id)
{
SidekickPartFilterRow filterRow = dbManager.GetCurrentDbConnection().Find<SidekickPartFilterRow>(id);
Decorate(dbManager, filterRow);
return filterRow;
}
/// <summary>
/// Gets a list of all the part filters in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all part filters in the database.</returns>
public static List<SidekickPartFilterRow> GetAll(DatabaseManager dbManager)
{
List<SidekickPartFilterRow> filterRows = dbManager.GetCurrentDbConnection().Table<SidekickPartFilterRow>().ToList();
foreach (SidekickPartFilterRow row in filterRows)
{
Decorate(dbManager, row);
}
return filterRows;
}
/// <summary>
/// Gets a list of all the part filter rows in the database for a given part filter.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filter">The Part Filter to get all the part filter rows for.</param>
/// <returns>A list of all part filter rows for the given Part Filter in the database.</returns>
public static List<SidekickPartFilterRow> GetAllForFilter(DatabaseManager dbManager, SidekickPartFilter filter, bool excludeMissingParts = true)
{
List<SidekickPartFilterRow> filterRows = dbManager.GetCurrentDbConnection().Table<SidekickPartFilterRow>().Where(filterRow => filterRow
.PtrFilter == filter.ID).ToList();
List<SidekickPartFilterRow> toRemove = new List<SidekickPartFilterRow>();
foreach (SidekickPartFilterRow row in filterRows)
{
Decorate(dbManager, row);
if (row.Part == null)
{
toRemove.Add(row);
}
}
if (excludeMissingParts)
{
foreach (SidekickPartFilterRow row in filterRows)
{
if (!row.Part.FileExists)
{
toRemove.Add(row);
}
}
}
filterRows.RemoveAll(row => toRemove.Contains(row));
return filterRows;
}
/// <summary>
/// Gets a list of all the part names in the database for a given part filter, species and part type.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filter">The Part Filter to get all the part names for.</param>
/// <param name="species">The Species to get all the part names for.</param>
/// <param name="type">The Part Type to get all the part names for.</param>
/// <returns>A list of all the part names in the database for a given part filter, species and part type.</returns>
public static List<string> GetAllPartNamesForFilterSpeciesAndType(DatabaseManager dbManager,
SidekickPartFilter filter,
SidekickSpecies species,
CharacterPartType type)
{
List<string> filterRows = dbManager.GetCurrentDbConnection().Query<SidekickPart>("SELECT p.* FROM sk_part_filter_row AS pfw JOIN "
+ "sk_part AS p ON pfw.ptr_part = p.id JOIN sk_part_species_link AS s ON p.id = s.ptr_part WHERE pfw.ptr_filter = " + filter.ID
+ " AND s.ptr_species = " + species.ID + " AND p.type = " + (int)type + " AND p.file_exists = 1").ToList().Select(part => part.Name)
.ToList();
return filterRows;
}
/// <summary>
/// Gets a part filter row in the database for a given part filter and part.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filter">The Part Filter to get all the part filter row for.</param>
/// <param name="part">The part to get the row for.</param>
/// <returns>The part filter row for the given Part Filter and Part in the database.</returns>
public static SidekickPartFilterRow GetForFilterAndPart(DatabaseManager dbManager, SidekickPartFilter filter, SidekickPart part)
{
SidekickPartFilterRow row = dbManager.GetCurrentDbConnection().Table<SidekickPartFilterRow>().FirstOrDefault(filterRow => filterRow
.PtrFilter == filter.ID && filterRow.PtrPart == part.ID
);
Decorate(dbManager, row);
return row;
}
/// <summary>
/// Gets a list of all the part filter rows in the database for a given part.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="part">The part to get the rows for.</param>
/// <returns>The part filter rows for the given Part in the database.</returns>
public static List<SidekickPartFilterRow> GetAllForPart(DatabaseManager dbManager, SidekickPart part)
{
List<SidekickPartFilterRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickPartFilterRow>().Where(filterRow => filterRow.PtrPart == part.ID).ToList();
foreach (SidekickPartFilterRow row in rows)
{
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Ensures that the given part filter row has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filterRow">The part filter row to decorate</param>
private static void Decorate(DatabaseManager dbManager, SidekickPartFilterRow filterRow)
{
SidekickPart part = SidekickPart.GetByID(dbManager, filterRow.PtrPart);
if (part == null)
{
filterRow.Delete(dbManager);
}
else
{
filterRow.Filter ??= SidekickPartFilter.GetByID(dbManager, filterRow.PtrFilter);
filterRow.Part ??= part;
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickPartFilterRow>(ID);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 81f100234a4e4bedb2b3cdd3ea26edb1
timeCreated: 1740429753

View File

@@ -0,0 +1,124 @@
// 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 SQLite;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_part_image")]
public class SidekickPartImage
{
private SidekickPart _part;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_part")]
public int PtrPart { get; set; }
[Column("img_data")]
public byte[] ImageData { get; set; }
[Column("img_width")]
public int Width { get; set; }
[Column("img_height")]
public int Height { get; set; }
[Ignore]
public SidekickPart Part
{
get => _part;
set
{
_part = value;
PtrPart = value.ID;
}
}
/// <summary>
/// Gets a specific Part Image by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Part Image.</param>
/// <returns>The specific Part Image if it exists; otherwise null.</returns>
public static SidekickPartImage GetByID(DatabaseManager dbManager, int id)
{
SidekickPartImage partImage = dbManager.GetCurrentDbConnection().Find<SidekickPartImage>(id);
Decorate(dbManager, partImage);
return partImage;
}
/// <summary>
/// Gets a specific Part Image for a specific part.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="part">The Part to get the image for.</param>
/// <returns>The specific Part Image for a specific part if it exists; otherwise null.</returns>
public static SidekickPartImage GetByPart(DatabaseManager dbManager, SidekickPart part)
{
SidekickPartImage partImage = dbManager.GetCurrentDbConnection().Table<SidekickPartImage>()
.FirstOrDefault(pi => pi.PtrPart == part.ID);
Decorate(dbManager, partImage);
return partImage;
}
/// <summary>
/// Gets a list of all the Part Images in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all part images in the database.</returns>
public static List<SidekickPartImage> GetAll(DatabaseManager dbManager)
{
List<SidekickPartImage> partImages = dbManager.GetCurrentDbConnection().Table<SidekickPartImage>().ToList();
foreach (SidekickPartImage partImage in partImages)
{
Decorate(dbManager, partImage);
}
return partImages;
}
/// <summary>
/// Ensures that the given preset has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partImage">The part image to decorate</param>
private static void Decorate(DatabaseManager dbManager, SidekickPartImage partImage)
{
if (partImage != null)
{
if (partImage.Part == null && partImage.PtrPart >= 0)
{
partImage.Part ??= SidekickPart.GetByID(dbManager, partImage.PtrPart);
}
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickPartImage>(ID);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 77cb14daf5fc40d7854189c730575b4c
timeCreated: 1739227504

View File

@@ -0,0 +1,48 @@
// 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 SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_pmdata")]
public class SidekickPartMetaData
{
[PrimaryKey, Column("id")]
public int ID { get; set; }
[Column("part_guid")]
public string PartGuid { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("value")]
public string Value { get; set; }
[Column("type")]
public string Type { get; set; }
[Column("value_type")]
public string ValueType { get; set; }
[Column("last_updated")]
public DateTime LastUpdated { get; set; }
/// <summary>
/// Gets a list of part guids from the meta data based on the passed in type and value.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="type">The type of metadata to search for.</param>
/// <param name="value">The value of the metadata to search for.</param>
/// <returns>A list of part guids that match the given criteria.</returns>
public static List<string> GetPartGuidsByMetaDataValue(DatabaseManager dbManager, string type, string value)
{
return dbManager.GetCurrentDbConnection().Table<SidekickPartMetaData>()
.Where(meta => meta.Type == type && meta.Value == value)
.Select(meta => meta.PartGuid)
.ToList();
}
}
}

View File

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

View File

@@ -0,0 +1,285 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using Synty.SidekickCharacters.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_part_preset")]
public class SidekickPartPreset
{
private SidekickSpecies _species;
[PrimaryKey]
[AutoIncrement]
[Column("id")]
public int ID { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("part_group")]
public PartGroup PartGroup { get; set; }
[Column("ptr_species")]
public int PtrSpecies { get; set; }
[Column("outfit")]
public string Outfit { get; set; }
[Ignore]
public SidekickSpecies Species
{
get => _species;
set
{
_species = value;
PtrSpecies = value.ID;
}
}
/// <summary>
/// Gets a specific Preset by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset.</param>
/// <returns>The specific Preset if it exists; otherwise null.</returns>
public static SidekickPartPreset GetByID(DatabaseManager dbManager, int id)
{
SidekickPartPreset partPreset = dbManager.GetCurrentDbConnection().Find<SidekickPartPreset>(id);
Decorate(dbManager, partPreset);
return partPreset;
}
/// <summary>
/// Gets a list of all the Presets in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all presets in the database.</returns>
public static List<SidekickPartPreset> GetAll(DatabaseManager dbManager)
{
List<SidekickPartPreset> partPresets = dbManager.GetCurrentDbConnection().Table<SidekickPartPreset>().ToList();
foreach (SidekickPartPreset partPreset in partPresets)
{
Decorate(dbManager, partPreset);
}
return partPresets;
}
/// <summary>
/// Gets a list of all the Part Presets in the database that have the matching species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The species to get all the part presets for.</param>
/// <returns>A list of all part presets in the database for the given species.</returns>
public static List<SidekickPartPreset> GetAllBySpecies(DatabaseManager dbManager, SidekickSpecies species)
{
List<SidekickPartPreset> partPresets = dbManager.GetCurrentDbConnection().Table<SidekickPartPreset>()
.Where(partPreset => partPreset.PtrSpecies == species.ID)
.ToList();
foreach (SidekickPartPreset partPreset in partPresets)
{
partPreset.Species = species;
}
return partPresets;
}
/// <summary>
/// Gets a Part Presets in the database with the matching name if one exists.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="name">The name of the preset to retrieve.</param>
/// <returns>Returns a Part Presets in the database with the matching name if one exists; otherwise null.</returns>
public static SidekickPartPreset GetByName(DatabaseManager dbManager, string name)
{
SidekickPartPreset partPreset = dbManager.GetCurrentDbConnection()
.Table<SidekickPartPreset>()
.FirstOrDefault(partPreset => partPreset.Name == name);
if (partPreset != null)
{
Decorate(dbManager, partPreset);
}
return partPreset;
}
/// <summary>
/// Gets a list of all the Part Presets in the database that have the matching species and part group.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partGroup">The part group to filter search by.</param>
/// <returns>A list of all part presets in the database for the given species and part group.</returns>
public static List<SidekickPartPreset> GetAllByGroup(DatabaseManager dbManager, PartGroup partGroup, bool excludeMissingParts = true)
{
List<SidekickPartPreset> partPresets = dbManager.GetCurrentDbConnection().Table<SidekickPartPreset>()
.Where(partPreset => partPreset.PartGroup == partGroup)
.ToList();
foreach (SidekickPartPreset partPreset in partPresets)
{
Decorate(dbManager, partPreset);
}
if (excludeMissingParts)
{
List<SidekickPartPreset> toRemove = new List<SidekickPartPreset>();
foreach (SidekickPartPreset partPreset in partPresets)
{
if (!partPreset.HasAllPartsAvailable(dbManager))
{
toRemove.Add(partPreset);
}
}
partPresets.RemoveAll(preset => toRemove.Contains(preset));
}
return partPresets;
}
/// <summary>
/// Gets a list of all the Part Presets in the database that have the matching species and part group.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The species to get all the part presets for.</param>
/// <param name="partGroup">The part group to filter search by.</param>
/// <returns>A list of all part presets in the database for the given species and part group.</returns>
public static List<SidekickPartPreset> GetAllBySpeciesAndGroup(DatabaseManager dbManager, SidekickSpecies species, PartGroup partGroup)
{
List<SidekickPartPreset> partPresets = dbManager.GetCurrentDbConnection().Table<SidekickPartPreset>()
.Where(partPreset => partPreset.PtrSpecies == species.ID && partPreset.PartGroup == partGroup)
.ToList();
foreach (SidekickPartPreset partPreset in partPresets)
{
partPreset.Species = species;
}
return partPresets;
}
/// <summary>
/// Ensures that the given set has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPreset">The color set to decorate</param>
/// <returns>A color set with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickPartPreset partPreset)
{
if (partPreset.Species == null && partPreset.PtrSpecies >= 0)
{
partPreset.Species = SidekickSpecies.GetByID(dbManager, partPreset.PtrSpecies);
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID < 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
foreach (SidekickPartPresetRow row in SidekickPartPresetRow.GetAllByPreset(dbManager, this))
{
row.Delete(dbManager);
}
foreach (SidekickPresetFilterRow row in SidekickPresetFilterRow.GetAllForPreset(dbManager, this))
{
row.Delete(dbManager);
}
SidekickPartPresetImage image = SidekickPartPresetImage.GetByPresetAndPartGroup(dbManager, this, PartGroup);
image?.Delete(dbManager);
dbManager.GetCurrentDbConnection().Delete<SidekickPartPreset>(ID);
}
/// <summary>
/// Determines if all the parts associated with this preset are valid (has a file in the project).
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
/// <returns>True if all parts are valid; otherwise False.</returns>
public bool HasAllPartsAvailable(DatabaseManager dbManager)
{
List<SidekickPartPresetRow> allRows = SidekickPartPresetRow.GetAllByPreset(dbManager, this);
return allRows.Count > 0 && allRows.All(row => row.HasValidPart());
}
/// <summary>
/// Determines if all the parts associated with this preset are valid (has a file in the project).
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
/// <returns>True if all parts are valid; otherwise False.</returns>
public bool HasOnlyBasePartsAndAllAvailable(DatabaseManager dbManager)
{
List<SidekickPartPresetRow> allRows = SidekickPartPresetRow.GetAllByPreset(dbManager, this);
return allRows.Count > 0 && allRows.All(row => row.HasValidPart() && (row.Part == null || PartUtils.IsBaseSpeciesPart(row.PartName)));
}
/// <summary>
/// Checks the equality of this preset to the given preset.
/// </summary>
/// <param name="other">The preset to check equality with.</param>
/// <returns>True if the presets are equal, otherwise false.</returns>
protected bool Equals(SidekickPartPreset other)
{
return ID == other.ID
&& Name == other.Name
&& PartGroup == other.PartGroup
&& PtrSpecies == other.PtrSpecies;
}
/// <inheritdoc cref="Equals"/>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((SidekickPartPreset) obj);
}
/// <inheritdoc cref="GetHashCode"/>
public override int GetHashCode()
{
return HashCode.Combine(ID, Name, (int) PartGroup, PtrSpecies);
}
}
}

View File

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

View File

@@ -0,0 +1,158 @@
// 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 SQLite;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_part_preset_image")]
public class SidekickPartPresetImage
{
private SidekickPartPreset _partPreset;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_part_preset")]
public int PtrPreset { get; set; }
[Column("part_group")]
public PartGroup PartGroup { get; set; }
[Column("img_data")]
public byte[] ImageData { get; set; }
[Column("img_width")]
public int Width { get; set; }
[Column("img_height")]
public int Height { get; set; }
[Ignore]
public SidekickPartPreset PartPreset
{
get => _partPreset;
set
{
_partPreset = value;
PtrPreset = value.ID;
}
}
/// <summary>
/// Gets a specific Preset Part by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset Part.</param>
/// <returns>The specific Preset Part if it exists; otherwise null.</returns>
public static SidekickPartPresetImage GetByID(DatabaseManager dbManager, int id)
{
SidekickPartPresetImage partPresetImage = dbManager.GetCurrentDbConnection().Find<SidekickPartPresetImage>(id);
Decorate(dbManager, partPresetImage);
return partPresetImage;
}
/// <summary>
/// Gets a list of all the Preset Parts in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all preset parts in the database.</returns>
public static List<SidekickPartPresetImage> GetAll(DatabaseManager dbManager)
{
List<SidekickPartPresetImage> partPresetImages = dbManager.GetCurrentDbConnection().Table<SidekickPartPresetImage>().ToList();
foreach (SidekickPartPresetImage partPresetImage in partPresetImages)
{
Decorate(dbManager, partPresetImage);
}
return partPresetImages;
}
/// <summary>
/// Gets a list of all the Preset Part Images in the database that have the matching Part Preset.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPreset">The preset to get all the preset part images for.</param>
/// <returns>A list of all preset part images in the database for the given preset.</returns>
public static List<SidekickPartPresetImage> GetAllByPreset(DatabaseManager dbManager, SidekickPartPreset partPreset)
{
List<SidekickPartPresetImage> partPresetImages = dbManager.GetCurrentDbConnection().Table<SidekickPartPresetImage>()
.Where(presetPart => presetPart.PtrPreset == partPreset.ID)
.ToList();
foreach (SidekickPartPresetImage partPresetImage in partPresetImages)
{
Decorate(dbManager, partPresetImage);
}
return partPresetImages;
}
/// <summary>
/// Gets the Preset Part Image in the database that have the matching Part Preset and Part Group.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPreset">The preset to get the preset part image for.</param>
/// <param name="partGroup">The part group to filter the results by.</param>
/// <returns>The preset part image in the database for the given preset and part group.</returns>
public static SidekickPartPresetImage GetByPresetAndPartGroup(
DatabaseManager dbManager,
SidekickPartPreset partPreset,
PartGroup partGroup
)
{
SidekickPartPresetImage partPresetImage = dbManager.GetCurrentDbConnection().Table<SidekickPartPresetImage>()
.FirstOrDefault(presetPart => presetPart.PtrPreset == partPreset.ID && presetPart.PartGroup == partGroup);
if (partPresetImage != null)
{
Decorate(dbManager, partPresetImage);
}
return partPresetImage;
}
/// <summary>
/// Ensures that the given preset has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPresetImage">The color preset to decorate</param>
/// <returns>A color set with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickPartPresetImage partPresetImage)
{
if (partPresetImage != null)
{
if (partPresetImage.PartPreset == null && partPresetImage.PtrPreset >= 0)
{
partPresetImage.PartPreset = SidekickPartPreset.GetByID(dbManager, partPresetImage.PtrPreset);
}
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickPartPresetImage>(ID);
}
}
}

View File

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

View File

@@ -0,0 +1,190 @@
// 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 SQLite;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_part_preset_row")]
public class SidekickPartPresetRow
{
private SidekickPartPreset _partPreset;
private SidekickPart _part;
[PrimaryKey]
[AutoIncrement]
[Column("id")]
public int ID { get; set; }
[Column("part_name")]
public string PartName { get; set; }
[Column("ptr_part_preset")]
public int PtrPreset { get; set; }
[Column("ptr_part")]
public int PtrPart { get; set; } = -1;
[Column("part_type")]
public string PartType { get; set; }
[Ignore]
public SidekickPartPreset PartPreset
{
get => _partPreset;
set
{
_partPreset = value;
PtrPreset = value.ID;
}
}
[Ignore]
public SidekickPart Part
{
get => _part;
set
{
_part = value;
PtrPart = value.ID;
}
}
/// <summary>
/// Gets a specific Preset Part by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset Part.</param>
/// <returns>The specific Preset Part if it exists; otherwise null.</returns>
public static SidekickPartPresetRow GetByID(DatabaseManager dbManager, int id)
{
SidekickPartPresetRow partPreset = dbManager.GetCurrentDbConnection().Find<SidekickPartPresetRow>(id);
Decorate(dbManager, partPreset);
return partPreset;
}
/// <summary>
/// Gets a list of all the Preset Parts in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all preset parts in the database.</returns>
public static List<SidekickPartPresetRow> GetAll(DatabaseManager dbManager)
{
List<SidekickPartPresetRow> presetParts = dbManager.GetCurrentDbConnection().Table<SidekickPartPresetRow>().ToList();
foreach (SidekickPartPresetRow preset in presetParts)
{
Decorate(dbManager, preset);
}
return presetParts;
}
/// <summary>
/// Gets a list of all the Preset Part rows in the database that have the matching species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPreset">The preset to get all the preset part rows for.</param>
/// <returns>A list of all preset part rows in the database for the given preset.</returns>
public static List<SidekickPartPresetRow> GetAllByPreset(DatabaseManager dbManager, SidekickPartPreset partPreset)
{
List<SidekickPartPresetRow> presetParts = dbManager.GetCurrentDbConnection().Table<SidekickPartPresetRow>()
.Where(presetPart => presetPart.PtrPreset == partPreset.ID)
.ToList();
foreach (SidekickPartPresetRow presetPart in presetParts)
{
Decorate(dbManager, presetPart);
}
return presetParts;
}
/// <summary>
/// Gets a list of all the Preset Part rows in the database that have the matching part.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="part">The part to get all the preset part rows for.</param>
/// <returns>A list of all preset part rows in the database for the given part.</returns>
public static List<SidekickPartPresetRow> GetAllByPart(DatabaseManager dbManager, SidekickPart part)
{
List<SidekickPartPresetRow> presetParts = dbManager.GetCurrentDbConnection().Table<SidekickPartPresetRow>()
.Where(presetPart => presetPart.PtrPart == part.ID)
.ToList();
foreach (SidekickPartPresetRow presetPart in presetParts)
{
Decorate(dbManager, presetPart);
}
return presetParts;
}
/// <summary>
/// Ensures that the given preset has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partPreset">The color preset to decorate</param>
/// <returns>A color set with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickPartPresetRow partPreset)
{
if (partPreset != null)
{
if (partPreset.PartPreset == null && partPreset.PtrPreset >= 0)
{
partPreset.PartPreset = SidekickPartPreset.GetByID(dbManager, partPreset.PtrPreset);
}
if (partPreset.Part == null && partPreset.PtrPart >= 0)
{
partPreset.Part = SidekickPart.GetByID(dbManager, partPreset.PtrPart);
}
else if (partPreset.Part == null && partPreset.PtrPart < 0)
{
SidekickPart part = SidekickPart.SearchForByName(dbManager, partPreset.PartName);
if (part != null)
{
partPreset.Part = part;
}
}
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID < 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickPartPresetRow>(ID);
}
/// <summary>
/// Checks whether the associated part has a file that exists in the project.
/// </summary>
/// <returns>True if the part has a file in the project; otherwise False.</returns>
public bool HasValidPart()
{
return Part == null || Part.FileExists;
}
}
}

View File

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

View File

@@ -0,0 +1,181 @@
// 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 SQLite;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_part_species_link")]
public class SidekickPartSpeciesLink
{
private SidekickSpecies _species;
private SidekickPart _part;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_species")]
public int PtrSpecies { get; set; }
[Column("ptr_part")]
public int PtrPart { get; set; }
[Ignore]
public SidekickSpecies Species
{
get => _species;
set
{
_species = value;
PtrSpecies = value.ID;
}
}
[Ignore]
public SidekickPart Part
{
get => _part;
set
{
_part = value;
PtrPart = value.ID;
}
}
/// <summary>
/// Gets a specific Part Species Link by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Part Species Link.</param>
/// <returns>The specific Part Species Link if it exists; otherwise null.</returns>
public static SidekickPartSpeciesLink GetByID(DatabaseManager dbManager, int id)
{
SidekickPartSpeciesLink part = dbManager.GetCurrentDbConnection().Find<SidekickPartSpeciesLink>(id);
Decorate(dbManager, part);
return part;
}
/// <summary>
/// Gets a list of all the Part Species Links in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all Part Species Links in the database.</returns>
public static List<SidekickPartSpeciesLink> GetAll(DatabaseManager dbManager)
{
List<SidekickPartSpeciesLink> partSpeciesLinks = dbManager.GetCurrentDbConnection().Table<SidekickPartSpeciesLink>().ToList();
foreach (SidekickPartSpeciesLink partSpeciesLink in partSpeciesLinks)
{
Decorate(dbManager, partSpeciesLink);
}
return partSpeciesLinks;
}
/// <summary>
/// Gets a list of all the Part Species Links in the database for the specific species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The species to search for all parts species links for.</param>
/// <returns>A list of all Part Species Links in the database for the specified species.</returns>
public static List<SidekickPartSpeciesLink> GetAllForSpecies(DatabaseManager dbManager, SidekickSpecies species)
{
List<SidekickPartSpeciesLink> partSpeciesLinks = dbManager.GetCurrentDbConnection().Table<SidekickPartSpeciesLink>()
.Where(psl => psl.PtrSpecies == species.ID)
.ToList();
foreach (SidekickPartSpeciesLink partSpeciesLink in partSpeciesLinks)
{
Decorate(dbManager, partSpeciesLink);
}
return partSpeciesLinks;
}
/// <summary>
/// Gets a list of all the Part Species Links in the database for the specific part.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="part">The part to search for all parts species links for.</param>
/// <returns>A list of all Part Species Links in the database for the specified part.</returns>
public static List<SidekickPartSpeciesLink> GetAllForPart(DatabaseManager dbManager, SidekickPart part)
{
List<SidekickPartSpeciesLink> partSpeciesLinks = dbManager.GetCurrentDbConnection().Table<SidekickPartSpeciesLink>()
.Where(psl => psl.PtrPart == part.ID)
.ToList();
foreach (SidekickPartSpeciesLink partSpeciesLink in partSpeciesLinks)
{
Decorate(dbManager, partSpeciesLink);
}
return partSpeciesLinks;
}
/// <summary>
/// Gets a list of all the Part Species Links in the database for the specific part.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The species to search for all parts species links for.</param>
/// <param name="part">The part to search for all parts species links for.</param>
/// <returns>A list of all Part Species Links in the database for the specified part.</returns>
public static SidekickPartSpeciesLink GetForSpeciesAndPart(DatabaseManager dbManager, SidekickSpecies species, SidekickPart part)
{
SidekickPartSpeciesLink partSpeciesLink = dbManager.GetCurrentDbConnection().Table<SidekickPartSpeciesLink>()
.FirstOrDefault(psl => psl.PtrSpecies == species.ID && psl.PtrPart == part.ID);
Decorate(dbManager, partSpeciesLink);
return partSpeciesLink;
}
/// <summary>
/// Ensures that the given part has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="partSpeciesLink">The part to decorate</param>
private static void Decorate(DatabaseManager dbManager, SidekickPartSpeciesLink partSpeciesLink)
{
if (partSpeciesLink != null)
{
if (partSpeciesLink.Species == null && partSpeciesLink.PtrSpecies >= 0)
{
partSpeciesLink.Species = SidekickSpecies.GetByID(dbManager, partSpeciesLink.PtrSpecies);
}
if (partSpeciesLink.Part == null && partSpeciesLink.PtrPart >= 0)
{
partSpeciesLink.Part = SidekickPart.GetByID(dbManager, partSpeciesLink.PtrPart);
}
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickPartSpeciesLink>(ID);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b31bc1fc8ff44c3c9c0629ebaf7d69c2
timeCreated: 1745892314

View File

@@ -0,0 +1,163 @@
// 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 SQLite;
using System.Collections.Generic;
using System.Linq;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_preset_filter")]
public class SidekickPresetFilter
{
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("filter_term")]
public string Term { get; set; }
private List<SidekickPartPreset> _allPresets = new List<SidekickPartPreset>();
/// <summary>
/// Gets a specific Preset Filter by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset Filter.</param>
/// <returns>The specific Preset Filter if it exists; otherwise null.</returns>
public static SidekickPresetFilter GetByID(DatabaseManager dbManager, int id)
{
SidekickPresetFilter filter = dbManager.GetCurrentDbConnection().Find<SidekickPresetFilter>(id);
return filter;
}
/// <summary>
/// Gets a list of all the Preset filters in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="excludeFiltersWithNoParts">Whether to exclude filters without any parts from the list or not.</param>
/// <returns>A list of all Preset filters in the database.</returns>
public static List<SidekickPresetFilter> GetAll(DatabaseManager dbManager, bool excludeFiltersWithNoParts = true)
{
List<SidekickPresetFilter> filters = dbManager.GetCurrentDbConnection().Table<SidekickPresetFilter>().ToList();
if (excludeFiltersWithNoParts)
{
List<SidekickPresetFilter> toRemove = new List<SidekickPresetFilter>();
foreach (SidekickPresetFilter filter in filters)
{
if (filter.GetAllPresetsForFilter(dbManager).Count < 1)
{
toRemove.Add(filter);
}
}
filters.RemoveAll(filter => toRemove.Contains(filter));
}
return filters;
}
/// <summary>
/// Searches for a filter in the database with the given term and filter type.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filterTerm">The term to search for.</param>
/// <returns>The filter with the given term in the database if it exist; otherwise null.</returns>
public static SidekickPresetFilter GetByTerm(DatabaseManager dbManager, string filterTerm)
{
SidekickPresetFilter filter = dbManager.GetCurrentDbConnection().Table<SidekickPresetFilter>()
.FirstOrDefault(filter => filter.Term == filterTerm);
return filter;
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
foreach (SidekickPresetFilterRow row in SidekickPresetFilterRow.GetAllForFilter(dbManager, this))
{
row.Delete(dbManager);
}
dbManager.GetCurrentDbConnection().Delete<SidekickPresetFilter>(ID);
}
/// <summary>
/// Gets all of the presets for this filter.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
/// <param name="excludeMissingParts">Exclude presets where parts are missing or not.</param>
/// <param name="refreshList">Whether to refresh the list from the database or not.</param>
/// <returns>All of the presets for this filter.</returns>
public List<SidekickPartPreset> GetAllPresetsForFilter(DatabaseManager dbManager, bool excludeMissingParts = true, bool refreshList = false)
{
if (refreshList || _allPresets.Count < 1)
{
List<SidekickPresetFilterRow> filterRows = SidekickPresetFilterRow.GetAllForFilter(dbManager, this, excludeMissingParts);
_allPresets = filterRows.Select(row => row.Preset).ToList();
}
return _allPresets;
}
/// <summary>
/// Checks if this filter and the given filter are the same filter.
/// </summary>
/// <param name="other">The filter to check.</param>
/// <returns>True, if they are the same filter (IDs match); otherwise false.</returns>
protected bool Equals(SidekickPresetFilter other)
{
return ID == other.ID;
}
/// <inheritdoc cref="Equals"/>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((SidekickPresetFilter) obj);
}
/// <inheritdoc cref="GetHashCode"/>
public override int GetHashCode()
{
return ID;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9c5720e7c54f49fcb6b353ab3fdc8d47
timeCreated: 1744592126

View File

@@ -0,0 +1,197 @@
// 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 SQLite;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_preset_filter_row")]
public class SidekickPresetFilterRow
{
private SidekickPresetFilter _filter;
private SidekickPartPreset _preset;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_filter")]
public int PtrFilter { get; set; }
[Column("ptr_preset")]
public int PtrPreset { get; set; }
[Ignore]
public SidekickPresetFilter Filter
{
get => _filter;
set
{
_filter = value;
PtrFilter = value.ID;
}
}
[Ignore]
public SidekickPartPreset Preset
{
get => _preset;
set
{
_preset = value;
PtrPreset = value.ID;
}
}
/// <summary>
/// Gets a specific Preset Filter by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Preset Filter.</param>
/// <returns>The specific Preset Filter if it exists; otherwise null.</returns>
public static SidekickPresetFilterRow GetByID(DatabaseManager dbManager, int id)
{
SidekickPresetFilterRow filterRow = dbManager.GetCurrentDbConnection().Find<SidekickPresetFilterRow>(id);
Decorate(dbManager, filterRow);
return filterRow;
}
/// <summary>
/// Gets a list of all the preset filters in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all preset filters in the database.</returns>
public static List<SidekickPresetFilterRow> GetAll(DatabaseManager dbManager)
{
List<SidekickPresetFilterRow> filterRows = dbManager.GetCurrentDbConnection().Table<SidekickPresetFilterRow>().ToList();
foreach (SidekickPresetFilterRow row in filterRows)
{
Decorate(dbManager, row);
}
return filterRows;
}
/// <summary>
/// Gets a list of all the preset filter rows in the database for a given preset filter.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filter">The Preset Filter to get all the preset filter rows for.</param>
/// <returns>A list of all preset filter rows for the given Preset Filter in the database.</returns>
public static List<SidekickPresetFilterRow> GetAllForFilter(DatabaseManager dbManager, SidekickPresetFilter filter, bool excludeMissingParts = true)
{
List<SidekickPresetFilterRow> filterRows = dbManager.GetCurrentDbConnection().Table<SidekickPresetFilterRow>().Where(filterRow => filterRow
.PtrFilter == filter.ID).ToList();
List<SidekickPresetFilterRow> toRemove = new List<SidekickPresetFilterRow>();
foreach (SidekickPresetFilterRow row in filterRows)
{
Decorate(dbManager, row);
if (row.Preset == null)
{
toRemove.Add(row);
}
}
if (excludeMissingParts)
{
foreach (SidekickPresetFilterRow row in filterRows)
{
if (!row.Preset.HasAllPartsAvailable(dbManager))
{
toRemove.Add(row);
}
}
}
filterRows.RemoveAll(row => toRemove.Contains(row));
return filterRows;
}
/// <summary>
/// Gets a preset filter row in the database for a given preset filter and preset.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filter">The Preset Filter to get all the preset filter row for.</param>
/// <param name="preset">The preset to get the row for.</param>
/// <returns>The preset filter row for the given Preset Filter and Preset in the database.</returns>
public static SidekickPresetFilterRow GetForFilterAndPreset(DatabaseManager dbManager, SidekickPresetFilter filter, SidekickPartPreset preset)
{
SidekickPresetFilterRow row = dbManager.GetCurrentDbConnection().Table<SidekickPresetFilterRow>().FirstOrDefault(filterRow => filterRow
.PtrFilter == filter.ID && filterRow.PtrPreset == preset.ID
);
Decorate(dbManager, row);
return row;
}
/// <summary>
/// Gets a list of all the preset filter rows in the database for a given part.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="preset">The preset to get the rows for.</param>
/// <returns>The preset filter rows for the given Preset in the database.</returns>
public static List<SidekickPresetFilterRow> GetAllForPreset(DatabaseManager dbManager, SidekickPartPreset preset)
{
List<SidekickPresetFilterRow> rows = dbManager.GetCurrentDbConnection().Table<SidekickPresetFilterRow>()
.Where(filterRow => filterRow.PtrPreset == preset.ID).ToList();
foreach (SidekickPresetFilterRow row in rows)
{
Decorate(dbManager, row);
}
return rows;
}
/// <summary>
/// Ensures that the given preset filter row has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="filterRow">The preset filter row to decorate</param>
private static void Decorate(DatabaseManager dbManager, SidekickPresetFilterRow filterRow)
{
SidekickPartPreset preset = SidekickPartPreset.GetByID(dbManager, filterRow.PtrPreset);
if (preset == null)
{
filterRow.Delete(dbManager);
}
else
{
filterRow.Filter ??= SidekickPresetFilter.GetByID(dbManager, filterRow.PtrFilter);
filterRow.Preset ??= preset;
}
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickPresetFilterRow>(ID);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c29bd46d22b54dee81faf768f30ec75e
timeCreated: 1747794537

View File

@@ -0,0 +1,116 @@
// 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 SQLite;
using System;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_species")]
public class SidekickSpecies
{
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("code")]
public string Code { get; set; }
/// <summary>
/// Gets a list of all the Species in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="excludeSpeciesWithNoParts">Whether to excludes species that have no active parts</param>
/// <returns>A list of all species in the database.</returns>
public static List<SidekickSpecies> GetAll(DatabaseManager dbManager, bool excludeSpeciesWithNoParts = true)
{
List<SidekickSpecies> allSpecies = dbManager.GetCurrentDbConnection().Table<SidekickSpecies>().ToList();
List<SidekickSpecies> filteredSpecies = allSpecies;
if (excludeSpeciesWithNoParts)
{
filteredSpecies = new List<SidekickSpecies>();
foreach (SidekickSpecies species in allSpecies)
{
List<SidekickPart> allParts = SidekickPart.GetAllForSpecies(dbManager, species);
if (allParts.Count > 0 || species.Name.Equals("Unrestricted", StringComparison.OrdinalIgnoreCase))
{
filteredSpecies.Add(species);
}
}
}
return filteredSpecies;
}
/// <summary>
/// Gets a specific Species by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Species.</param>
/// <returns>The specific Species if it exists; otherwise null.</returns>
public static SidekickSpecies GetByID(DatabaseManager dbManager, int id)
{
return dbManager.GetCurrentDbConnection().Get<SidekickSpecies>(id);
}
/// <summary>
/// Gets a specific Species by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="name">The name of the required Species.</param>
/// <returns>The specific Species if it exists; otherwise null.</returns>
public static SidekickSpecies GetByName(DatabaseManager dbManager, string name)
{
return dbManager.GetCurrentDbConnection().Table<SidekickSpecies>().FirstOrDefault(species => species.Name.ToLower() == name.ToLower());
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public int Save(DatabaseManager dbManager)
{
if (ID < 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
return ID;
}
/// <summary>
/// Deletes this item from the database
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Delete(DatabaseManager dbManager)
{
dbManager.GetCurrentDbConnection().Delete<SidekickSpecies>(ID);
}
/// <inheritdoc cref="Equals"/>
public override bool Equals(object obj)
{
SidekickSpecies species = (SidekickSpecies) obj;
if (ID > 0 && species?.ID > 0)
{
return ID == species?.ID;
}
return Name.Equals(species?.Name);
}
/// <inheritdoc cref="GetHashCode"/>
public override int GetHashCode()
{
return HashCode.Combine(ID, Name, Code);
}
}
}

View File

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

View File

@@ -0,0 +1,115 @@
// 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 SQLite;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Database.DTO
{
[Table("sk_species_image")]
public class SidekickSpeciesImage
{
private SidekickSpecies _species;
[PrimaryKey, AutoIncrement, Column("id")]
public int ID { get; set; }
[Column("ptr_species")]
public int PtrSpecies { get; set; }
[Column("img_data")]
public byte[] ImageData { get; set; }
[Column("img_width")]
public int Width { get; set; }
[Column("img_height")]
public int Height { get; set; }
[Ignore]
public SidekickSpecies Species
{
get => _species;
set
{
_species = value;
PtrSpecies = value.ID;
}
}
/// <summary>
/// Gets a specific Species Image by its database ID.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="id">The id of the required Species Image.</param>
/// <returns>The specific Species Image if it exists; otherwise null.</returns>
public static SidekickSpeciesImage GetByID(DatabaseManager dbManager, int id)
{
SidekickSpeciesImage speciesImage = dbManager.GetCurrentDbConnection().Find<SidekickSpeciesImage>(id);
Decorate(dbManager, speciesImage);
return speciesImage;
}
/// <summary>
/// Gets a list of all the Species Image in the database.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <returns>A list of all species images in the database.</returns>
public static List<SidekickSpeciesImage> GetAll(DatabaseManager dbManager)
{
List<SidekickSpeciesImage> speciesImages = dbManager.GetCurrentDbConnection().Table<SidekickSpeciesImage>().ToList();
foreach (SidekickSpeciesImage speciesImage in speciesImages)
{
Decorate(dbManager, speciesImage);
}
return speciesImages;
}
/// <summary>
/// Gets the Species Image in the database that has the matching Species.
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="species">The species to get the species image for.</param>
/// <returns>The species image in the database for the given species.</returns>
public static SidekickSpeciesImage GetBySpecies(DatabaseManager dbManager, SidekickSpecies species)
{
SidekickSpeciesImage partPresetImage = dbManager.GetCurrentDbConnection().Table<SidekickSpeciesImage>()
.FirstOrDefault(presetPart => presetPart.PtrSpecies == species.ID);
if (partPresetImage != null)
{
Decorate(dbManager, partPresetImage);
}
return partPresetImage;
}
/// <summary>
/// Ensures that the given preset has its nice DTO class properties set
/// </summary>
/// <param name="dbManager">The Database Manager to use.</param>
/// <param name="bodyShapePresetImage">The color preset to decorate</param>
/// <returns>A color set with all DTO class properties set</returns>
private static void Decorate(DatabaseManager dbManager, SidekickSpeciesImage bodyShapePresetImage)
{
bodyShapePresetImage.Species ??= SidekickSpecies.GetByID(dbManager, bodyShapePresetImage.PtrSpecies);
}
/// <summary>
/// Updates or Inserts this item in the Database.
/// </summary>
/// <param name="dbManager">The database manager to use.</param>
public void Save(DatabaseManager dbManager)
{
if (ID <= 0)
{
dbManager.GetCurrentDbConnection().Insert(this);
// in theory this could return a different ID, but in practice it's highly unlikely
ID = (int) SQLite3.LastInsertRowid(dbManager.GetCurrentDbConnection().Handle);
}
dbManager.GetCurrentDbConnection().Update(this);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5c33e8e2dcf84666a0261253f096d61c
timeCreated: 1730347087

View File

@@ -0,0 +1,210 @@
// 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 SqlCipher4Unity3D;
// using SqlCipher4Unity3D;
using SQLite;
using Synty.SidekickCharacters.Database.DTO;
using System;
using System.Linq;
namespace Synty.SidekickCharacters.Database
{
/// <summary>
/// Manages connecting to, initializing and validating a local Sidekick SQLite database
/// </summary>
public class DatabaseManager
{
private static readonly string _DATABASE_PATH = "Assets/Synty/SidekickCharacters/Database/Side_Kick_Data.db";
private readonly string _CURRENT_VERSION = "1.0.2";
private static SQLiteConnection _connection;
private static int _connectionHash;
/// <summary>
/// Gets the DB connection with the given connection details.
/// If the current connection is not for the given details, the connection is replaced with the correct connection.
/// </summary>
/// <param name="databasePath">The path to the DB.</param>
/// <param name="connectionKey">The connection key for the DB.</param>
/// <param name="checkDbOnLoad">Whether or not to valiate the structure of the DB after connecting to it.</param>
/// <returns>A connection to a DB with the given connection details.</returns>
public SQLiteConnection GetDbConnection(bool checkDbOnLoad = false)
{
if (_connection == null)
{
_connection = new SQLiteConnection(_DATABASE_PATH, true);
}
else
{
return _connection;
}
if (checkDbOnLoad)
{
bool createTables = !IsDatabaseConfigured();
InitialiseDatabase(createTables);
}
return _connection;
}
/// <summary>
/// Returns whatever the current DB connection is, regardless of state.
/// </summary>
/// <returns>The current DB connection.</returns>
public SQLiteConnection GetCurrentDbConnection()
{
return _connection;
}
/// <summary>
/// Closes the current DB connection.
/// </summary>
public void CloseConnection()
{
if (_connection == null)
{
return;
}
// NOTE: Previously, if we didn't clear the pool in the connection, it resulted in a file lock on the database,
// which in some cases could cause problems when trying to update the DB to a new version.
// Our SQLCipher library doesn't use pool clearing unless using SQLiteAsyncConnection.
_connection.Dispose();
// Our SQLCipher library doesn't surface checking connection state; disposed connections need their reference removed
_connection = null;
}
/// <summary>
/// Initialises the Sidekicks database with required data, if they don't already exist.
/// </summary>
/// <param name="createTables">Whether to update the database and create the needed tables or not.</param>
private void InitialiseDatabase(bool createTables = false)
{
// ensure we have a default color set (a bunch of other code relies on this, not safe to remove yet)
try
{
SidekickColorSet.GetDefault(this);
}
catch (Exception)
{
SidekickColorSet newSet = new SidekickColorSet
{
Species = new SidekickSpecies { ID = -1, Name = "None" },
Name = "Default",
SourceColorPath = "Assets/Synty/Tools/SidekickCharacters/Resources/Textures/T_ColorMap.png",
SourceMetallicPath = "Assets/Synty/Tools/SidekickCharacters/Resources/Textures/T_MetallicMap.png",
SourceSmoothnessPath = "Assets/Synty/Tools/SidekickCharacters/Resources/Textures/T_SmoothnessMap.png",
SourceReflectionPath = "Assets/Synty/Tools/SidekickCharacters/Resources/Textures/T_ReflectionMap.png",
SourceEmissionPath = "Assets/Synty/Tools/SidekickCharacters/Resources/Textures/T_EmissionMap.png",
SourceOpacityPath = "Assets/Synty/Tools/SidekickCharacters/Resources/Textures/T_OpacityMap.png",
};
newSet.Save(this);
}
if (createTables)
{
GetCurrentDbConnection().CreateTable<SidekickDBVersion>();
SidekickDBVersion version;
if (GetCurrentDbConnection().Table<SidekickDBVersion>().Any())
{
version = GetCurrentDbConnection().Table<SidekickDBVersion>().FirstOrDefault();
version.SemanticVersion = _CURRENT_VERSION;
version.LastUpdated = DateTime.Now;
}
else
{
version = new SidekickDBVersion()
{
ID = -1,
SemanticVersion = _CURRENT_VERSION,
LastUpdated = DateTime.Now
};
}
version.Save(this);
GetCurrentDbConnection().CreateTable<SidekickPart>();
GetCurrentDbConnection().CreateTable<SidekickPartImage>();
GetCurrentDbConnection().CreateTable<SidekickPartFilter>();
GetCurrentDbConnection().CreateTable<SidekickPartFilterRow>();
GetCurrentDbConnection().CreateTable<SidekickPartPresetRow>();
GetCurrentDbConnection().CreateTable<SidekickPartSpeciesLink>();
GetCurrentDbConnection().CreateTable<SidekickPresetFilter>();
GetCurrentDbConnection().CreateTable<SidekickPresetFilterRow>();
}
}
/// <summary>
/// Checks to see if the current database has the required tables.
/// TODO: Check DB version, not just if table is present.
/// </summary>
/// <returns>True if the tables are present; otherwise false.</returns>
private bool IsDatabaseConfigured()
{
bool configured = !(GetCurrentDbConnection().GetTableInfo("sk_vdata").Count < 1);
if (GetCurrentDbConnection().GetTableInfo("sk_part").Count < 9)
{
configured = false;
}
if (GetCurrentDbConnection().GetTableInfo("sk_part_image").Count < 1)
{
configured = false;
}
if (GetCurrentDbConnection().GetTableInfo("sk_part_filter").Count < 1)
{
configured = false;
}
if (GetCurrentDbConnection().GetTableInfo("sk_part_filter_row").Count < 1)
{
configured = false;
}
if (GetCurrentDbConnection().GetTableInfo("sk_part_preset_row").Count < 5)
{
configured = false;
}
if (GetCurrentDbConnection().GetTableInfo("sk_part_species_link").Count < 3)
{
configured = false;
}
if (GetCurrentDbConnection().GetTableInfo("sk_preset_filter").Count < 1)
{
configured = false;
}
if (GetCurrentDbConnection().GetTableInfo("sk_preset_filter_row").Count < 1)
{
configured = false;
}
return configured;
}
/// <summary>
/// Retrieves the current database version.
/// </summary>
/// <returns>Semantic version (major.minor.patch).</returns>
public Version GetDatabaseVersion()
{
return new Version(GetCurrentDbConnection()?.Table<SidekickDBVersion>().FirstOrDefault().SemanticVersion ?? "0.0.1ea");
}
}
}

View File

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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 43d3882c5cf34fe897d4303f9fe147cf
timeCreated: 1712129971

View File

@@ -0,0 +1,17 @@
// 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.
namespace Synty.SidekickCharacters.Enums
{
public enum BlendShapeType
{
Feminine,
Heavy,
Skinny,
Bulk
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 67eaa8575d444e26a1989c7e375a0089
timeCreated: 1732673290

View File

@@ -0,0 +1,57 @@
// 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.
namespace Synty.SidekickCharacters.Enums
{
/// <summary>
/// The type of part that a SidekickPart represents.
/// </summary>
public enum CharacterPartType
{
// Specify the starting value as 1 to ensure values match server side values.
Head = 1,
Hair,
EyebrowLeft,
EyebrowRight,
EyeLeft,
EyeRight,
EarLeft,
EarRight,
FacialHair,
Torso,
ArmUpperLeft,
ArmUpperRight,
ArmLowerLeft,
ArmLowerRight,
HandLeft,
HandRight,
Hips,
LegLeft,
LegRight,
FootLeft,
FootRight,
AttachmentHead,
AttachmentFace,
AttachmentBack,
AttachmentHipsFront,
AttachmentHipsBack,
AttachmentHipsLeft,
AttachmentHipsRight,
AttachmentShoulderLeft,
AttachmentShoulderRight,
AttachmentElbowLeft,
AttachmentElbowRight,
AttachmentKneeLeft,
AttachmentKneeRight,
Nose,
Teeth,
Tongue,
Wrap,
// AttachmentHandLeft,
// AttachmentHandRight,
}
}

View File

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

View File

@@ -0,0 +1,18 @@
// 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.
namespace Synty.SidekickCharacters.Enums
{
public enum ColorGroup
{
Species = 1,
Outfits,
Attachments,
Materials,
Elements
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 65a90e4f6d8f4050be3c2adbfb20cecd
timeCreated: 1712532015

View File

@@ -0,0 +1,62 @@
// 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.
namespace Synty.SidekickCharacters.Enums
{
public enum ColorPartType
{
AllParts,
Species,
Outfit,
Attachments,
Materials,
Elements,
CharacterHead,
CharacterUpperBody,
CharacterLowerBody,
Head,
Hair,
EyebrowLeft,
EyebrowRight,
EyeLeft,
EyeRight,
EarLeft,
EarRight,
FacialHair,
Torso,
ArmUpperLeft,
ArmUpperRight,
ArmLowerLeft,
ArmLowerRight,
HandLeft,
HandRight,
Hips,
LegLeft,
LegRight,
FootLeft,
FootRight,
AttachmentHead,
AttachmentFace,
AttachmentBack,
AttachmentHipsFront,
AttachmentHipsBack,
AttachmentHipsLeft,
AttachmentHipsRight,
AttachmentShoulderLeft,
AttachmentShoulderRight,
AttachmentElbowLeft,
AttachmentElbowRight,
AttachmentKneeLeft,
AttachmentKneeRight,
Nose,
Teeth,
Tongue,
Wrap,
// AttachmentHandLeft,
// AttachmentHandRight,
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8fc699cf45ef478ca0a51a9b463dbb91
timeCreated: 1712553714

View File

@@ -0,0 +1,19 @@
// 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.
namespace Synty.SidekickCharacters.Enums
{
public enum ColorType
{
MainColor,
Metallic,
Smoothness,
Reflection,
Emission,
Opacity
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 39bd8b4b73e04c038a78c0e762cfde1c
timeCreated: 1712268358

View File

@@ -0,0 +1,16 @@
// 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.
namespace Synty.SidekickCharacters.Enums
{
public enum FilterCombineType
{
And,
Or,
Not
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 47dd50ec62a341f9aa9570a95f8d8a85
timeCreated: 1740432327

View File

@@ -0,0 +1,16 @@
// 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.
namespace Synty.SidekickCharacters.Enums
{
public enum FilterType
{
Species,
Outfit,
PartType
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 336dc01d315d41ada8d58bfa7d8c7444
timeCreated: 1740344361

View File

@@ -0,0 +1,16 @@
// 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.
namespace Synty.SidekickCharacters.Enums
{
public enum PartGroup
{
Head = 1,
UpperBody,
LowerBody
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 990ef0c4596a0ba42bebd7fd9868d9b3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,204 @@
// 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.API;
using Synty.SidekickCharacters.Database;
using Synty.SidekickCharacters.Database.DTO;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Synty.SidekickCharacters.Filters
{
public class FilterGroup
{
public SidekickRuntime Runtime;
public FilterCombineType CombineType;
private Dictionary<CharacterPartType, List<string>> _filteredParts;
private List<FilterItem> _filterItems = new List<FilterItem>();
private List<FilterGroup> _subGroups = new List<FilterGroup>();
/// <summary>
/// Adds a sub group of filters to this group.
/// </summary>
/// <param name="subGroup">The group to add as a sub group.</param>
public void AddFilterSubGroup(FilterGroup subGroup)
{
if (_subGroups.Count < 1 || _subGroups[0].CombineType == subGroup.CombineType)
{
_subGroups.Add(subGroup);
}
else
{
Debug.LogWarning("Unable to add sub group as sub groups cannot have different combine types.");
}
}
/// <summary>
/// Adds a filter item to this group.
/// </summary>
/// <param name="filterItem">The filter item to add.</param>
public void AddFilterItem(FilterItem filterItem)
{
if (_filterItems.Count < 1 || _filterItems[0].CombineType == filterItem.CombineType)
{
_filterItems.Add(filterItem);
}
else
{
Debug.LogWarning("Unable to add filter as filters cannot have different combine types.");
}
}
/// <summary>
/// Removes the given filter item from this group, if it exists.
/// </summary>
/// <param name="filterItem">The filter item to remove.</param>
public void RemoveFilterItem(FilterItem filterItem)
{
_filterItems.RemoveAll(fi => fi.Filter == filterItem.Filter);
}
/// <summary>
/// Resets the part dictionaries for all filter items.
/// </summary>
public void ResetFiltersForSpeciesChange()
{
foreach (FilterItem item in _filterItems)
{
item.ResetPartsForSpeciesChange();
}
}
/// <summary>
/// Gets a list of all parts that the filters within this group evaluate to.
/// </summary>
/// <returns>The list of all filtered parts</returns>
public Dictionary<CharacterPartType, List<string>> GetFilteredParts()
{
_filteredParts = new Dictionary<CharacterPartType, List<string>>();
// If there are no filter items, it means that we aren't filtering any parts out. Return all parts.
if (_filterItems.Count < 1)
{
return Runtime.MappedBasePartDictionary[Runtime.CurrentSpecies];
}
if (_filterItems.Count > 1)
{
FilterCombineType filterCombineType = _filterItems[1].CombineType;
if (_filterItems[0].CombineType != FilterCombineType.Or)
{
_filteredParts = Runtime.MappedPartList;
}
foreach (FilterItem item in _filterItems)
{
Dictionary<CharacterPartType, List<string>> newFilteredParts = item.GetFilteredParts();
List<string> toRemove = new List<string>();
foreach (KeyValuePair<CharacterPartType, List<string>> entry in newFilteredParts)
{
switch (filterCombineType)
{
case FilterCombineType.And:
toRemove = new List<string>();
foreach (string part in _filteredParts[entry.Key])
{
if (!entry.Value.Contains(part))
{
toRemove.Add(part);
}
}
_filteredParts[entry.Key].RemoveAll(part => toRemove.Contains(part));
break;
case FilterCombineType.Or:
HashSet<string> uniqueList = entry.Value.ToHashSet();
HashSet<string> existingList = _filteredParts.TryGetValue(entry.Key, out List<string> filteredList) ? filteredList.ToHashSet() : new HashSet<string>();
existingList.UnionWith(uniqueList);
_filteredParts[entry.Key] = existingList.ToList();
break;
case FilterCombineType.Not:
toRemove = new List<string>();
foreach (string part in _filteredParts[entry.Key])
{
if (entry.Value.Contains(part))
{
toRemove.Add(part);
}
}
_filteredParts[entry.Key].RemoveAll(part => toRemove.Contains(part));
break;
}
}
}
}
else
{
_filteredParts = _filterItems[0].GetFilteredParts();
}
foreach (FilterGroup group in _subGroups)
{
FilterCombineType filterCombineType = group.CombineType;
Dictionary<CharacterPartType, List<string>> newFilteredParts = group.GetFilteredParts();
List<string> toRemove = new List<string>();
foreach (KeyValuePair<CharacterPartType, List<string>> entry in newFilteredParts)
{
switch (filterCombineType)
{
case FilterCombineType.And:
toRemove = new List<string>();
foreach (string part in _filteredParts[entry.Key])
{
if (!entry.Value.Contains(part))
{
toRemove.Add(part);
}
}
_filteredParts[entry.Key].RemoveAll(part => toRemove.Contains(part));
break;
case FilterCombineType.Or:
HashSet<string> uniqueList = entry.Value.ToHashSet();
HashSet<string> existingList = _filteredParts[entry.Key].ToHashSet();
existingList.UnionWith(uniqueList);
_filteredParts[entry.Key] = existingList.ToList();
break;
case FilterCombineType.Not:
toRemove = new List<string>();
foreach (string part in _filteredParts[entry.Key])
{
if (entry.Value.Contains(part))
{
toRemove.Add(part);
}
}
_filteredParts[entry.Key].RemoveAll(part => toRemove.Contains(part));
break;
}
}
}
return _filteredParts;
}
}
}

View File

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

View File

@@ -0,0 +1,59 @@
// 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.API;
using Synty.SidekickCharacters.Database.DTO;
using Synty.SidekickCharacters.Enums;
using System;
using System.Collections.Generic;
namespace Synty.SidekickCharacters.Filters
{
public class FilterItem
{
public SidekickRuntime Runtime;
public SidekickPartFilter Filter;
public FilterCombineType CombineType;
private Dictionary<CharacterPartType, List<string>> _filteredParts = new Dictionary<CharacterPartType, List<string>>();
public FilterItem(SidekickRuntime runtime, SidekickPartFilter filter, FilterCombineType combineType)
{
Runtime = runtime;
Filter = filter;
CombineType = combineType;
}
/// <summary>
/// Resets the part dictionary when the species is changed.
/// </summary>
public void ResetPartsForSpeciesChange()
{
_filteredParts = new Dictionary<CharacterPartType, List<string>>();
}
/// <summary>
/// Gets a list of all the parts for this filter item.
/// </summary>
/// <returns>A list of all parts for this filter item.</returns>
public Dictionary<CharacterPartType, List<string>> GetFilteredParts()
{
if (_filteredParts == null || _filteredParts.Count < 1)
{
_filteredParts = new Dictionary<CharacterPartType, List<string>>();
foreach (CharacterPartType type in Enum.GetValues(typeof(CharacterPartType)))
{
List<string> parts = SidekickPartFilterRow.GetAllPartNamesForFilterSpeciesAndType(Runtime.DBManager, Filter, Runtime.CurrentSpecies, type);
_filteredParts[type] = parts;
}
}
return _filteredParts;
}
}
}

View File

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

View File

@@ -0,0 +1,36 @@
// 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.Database;
using Synty.SidekickCharacters.Database.DTO;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Synty.SidekickCharacters.Filters
{
public class ParsedPart
{
public string Species;
public string Outfit1;
public string Outfit2;
public string PartArea;
public string Filename;
public string Name;
public ParsedPart(string partName, string name)
{
Species = partName.Substring(partName.LastIndexOf('_') + 1, 2);
Outfit1 = partName.Substring(3, 4);
Outfit2 = partName.Substring(8, 4);
PartArea = partName.Substring(18, 4);
Filename = partName;
Name = name;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 88015ac5c0e044149a859e8143155d4d
timeCreated: 1741050319

View File

@@ -0,0 +1,45 @@
// 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.Database;
using Synty.SidekickCharacters.Database.DTO;
using Synty.SidekickCharacters.Enums;
using System.Collections.Generic;
using System.Linq;
namespace Synty.SidekickCharacters.Filters
{
public class PresetFilterItem
{
public DatabaseManager DbManager;
public SidekickPresetFilter Filter;
public FilterCombineType CombineType;
private List<SidekickPartPreset> _filteredPresets;
public PresetFilterItem(DatabaseManager dbManager, SidekickPresetFilter filter, FilterCombineType combineType)
{
DbManager = dbManager;
Filter = filter;
CombineType = combineType;
}
/// <summary>
/// Gets a list of all the presets for this filter item.
/// </summary>
/// <returns>A list of all presets for this filter item.</returns>
public List<SidekickPartPreset> GetFilteredPresets()
{
if (_filteredPresets == null || _filteredPresets.Count < 1)
{
_filteredPresets = SidekickPresetFilterRow.GetAllForFilter(DbManager, Filter).Select(row => row.Preset).ToList();
}
return _filteredPresets;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b852b386e6bc4e6eab4140b0d792d22e
timeCreated: 1747794343

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5e54ff5aadff4098a8ebbe8af53c67d6
timeCreated: 1748989523

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 70aaed080c064050876e02c5a9faede3
timeCreated: 1748989560

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7ffda9b8cf088e548ac0848af560c64c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// 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;
namespace Synty.SidekickCharacters.Serialization
{
[Serializable]
public class SerializedBlendShapeValues
{
public float BodyTypeValue { get; set; } = 50;
public float BodySizeValue { get; set; } = 0;
public float MuscleValue { get; set; } = 50;
public SerializedBlendShapeValues()
{
}
}
}

View File

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

View File

@@ -0,0 +1,27 @@
// 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.Collections.Generic;
namespace Synty.SidekickCharacters.Serialization
{
[Serializable]
public class SerializedCharacter
{
public string Name { get; set; }
public int Species { get; set; }
public List<SerializedPart> Parts { get; set; }
public SerializedColorSet ColorSet { get; set; }
public List<SerializedColorRow> ColorRows { get; set; }
public SerializedBlendShapeValues BlendShapes { get; set; } = new SerializedBlendShapeValues();
public SerializedCharacter()
{
}
}
}

View File

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

View File

@@ -0,0 +1,59 @@
// 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.Database;
using Synty.SidekickCharacters.Database.DTO;
using System;
namespace Synty.SidekickCharacters.Serialization
{
[Serializable]
public class SerializedColorRow
{
public int ColorProperty { get; set; }
public string MainColor { get; set; }
public string Metallic { get; set; }
public string Smoothness { get; set; }
public string Reflection { get; set; }
public string Emission { get; set; }
public string Opacity { get; set; }
// Empty constructor for serialization purposes.
public SerializedColorRow()
{
}
public SerializedColorRow(SidekickColorRow row)
{
ColorProperty = row.PtrColorProperty;
MainColor = row.MainColor;
Metallic = row.Metallic;
Smoothness = row.Smoothness;
Reflection = row.Reflection;
Emission = row.Emission;
Opacity = row.Opacity;
}
public SidekickColorRow CreateSidekickColorRow(DatabaseManager db, SidekickColorSet set)
{
SidekickColorProperty property = SidekickColorProperty.GetByID(db, ColorProperty);
return new SidekickColorRow
{
ID = -1,
ColorSet = set,
ColorProperty = property,
MainColor = MainColor,
Metallic = Metallic,
Smoothness = Smoothness,
Reflection = Reflection,
Emission = Emission,
Opacity = Opacity
};
}
}
}

View File

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

View File

@@ -0,0 +1,59 @@
// 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.Database;
using Synty.SidekickCharacters.Database.DTO;
using System;
namespace Synty.SidekickCharacters.Serialization
{
[Serializable]
public class SerializedColorSet
{
public int Species { get; set; }
public string Name { get; set; }
public string SourceColorPath { get; set; }
public string SourceMetallicPath { get; set; }
public string SourceSmoothnessPath { get; set; }
public string SourceReflectionPath { get; set; }
public string SourceEmissionPath { get; set; }
public string SourceOpacityPath { get; set; }
public SerializedColorSet()
{
}
public void PopulateFromSidekickColorSet(SidekickColorSet colorSet, SidekickSpecies defaultSpecies)
{
Species = colorSet.Species?.ID ?? defaultSpecies.ID;
Name = colorSet.Name;
SourceColorPath = colorSet.SourceColorPath;
SourceMetallicPath = colorSet.SourceMetallicPath;
SourceSmoothnessPath = colorSet.SourceSmoothnessPath;
SourceReflectionPath = colorSet.SourceReflectionPath;
SourceEmissionPath = colorSet.SourceEmissionPath;
SourceOpacityPath = colorSet.SourceOpacityPath;
}
public SidekickColorSet CreateSidekickColorSet(DatabaseManager db)
{
SidekickSpecies species = SidekickSpecies.GetByID(db, Species);
return new SidekickColorSet
{
ID = -1,
Species = species,
Name = Name,
SourceColorPath = SourceColorPath,
SourceMetallicPath = SourceMetallicPath,
SourceSmoothnessPath = SourceSmoothnessPath,
SourceReflectionPath = SourceReflectionPath,
SourceEmissionPath = SourceEmissionPath,
SourceOpacityPath = SourceOpacityPath
};
}
}
}

View File

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

View File

@@ -0,0 +1,32 @@
// 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.Serialization
{
[Serializable]
public class SerializedPart
{
public string Name { get; set; }
public CharacterPartType PartType { get; set; }
public string PartVersion { get; set; }
public SerializedPart()
{
}
public SerializedPart(string name, CharacterPartType partType, string partVersion)
{
Name = name;
PartType = partType;
PartVersion = partVersion;
}
}
}

View File

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

Some files were not shown because too many files have changed in this diff Show More