Feat: 프랍 브라우저 및 웹 업로드 시스템 추가
- PropBrowserWindow: Unity 에디터용 프랍 브라우저 - 개별 프리펩 단위로 표시 (폴더별 묶음 X) - 씬 조명 기반 썸네일 생성 - 앞쪽에서 촬영하도록 카메라 각도 수정 - WebsitePropExporter: 웹 API 업로드 기능 - 개별 프리펩별 썸네일 URL 지원 - PropSyncSettings: API 및 Git URL 설정 - PropData: 프랍 데이터 구조체 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f2cd9878cb
commit
35f50ba25b
8
Assets/Scripts/Streamingle/StreamingleControl/Prop.meta
Normal file
8
Assets/Scripts/Streamingle/StreamingleControl/Prop.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef5f7eb69221f2b498b9a1cc56a4d794
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69ed6044e4ba275409c5c0a75325bf03
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57624d2ef1d480c48bd4af170df78730
|
||||
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Streamingle.Prop.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 프랍 동기화 설정을 저장하는 ScriptableObject
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "PropSyncSettings", menuName = "Streamingle/Prop Sync Settings")]
|
||||
public class PropSyncSettings : ScriptableObject
|
||||
{
|
||||
[Header("웹사이트 API 설정")]
|
||||
[Tooltip("프랍 API 엔드포인트 URL (예: https://minglestudio.co.kr/api/props)")]
|
||||
public string apiEndpoint = "https://minglestudio.co.kr/api/props";
|
||||
|
||||
[Tooltip("API 인증 키 (선택사항)")]
|
||||
public string apiKey = "";
|
||||
|
||||
[Header("Git 설정 (썸네일 URL용)")]
|
||||
[Tooltip("Git 서버 URL (예: https://kindnick-git.duckdns.org)")]
|
||||
public string gitServerUrl = "https://kindnick-git.duckdns.org";
|
||||
|
||||
[Tooltip("Git 리포지토리 경로 (예: kindnick/Streamingle_URP)")]
|
||||
public string gitRepoPath = "kindnick/Streamingle_URP";
|
||||
|
||||
[Tooltip("Git 브랜치 (예: main)")]
|
||||
public string gitBranch = "main";
|
||||
|
||||
[Header("웹사이트 설정")]
|
||||
[Tooltip("프랍 페이지 URL (브라우저에서 열기용)")]
|
||||
public string websiteUrl = "https://minglestudio.co.kr/props";
|
||||
|
||||
/// <summary>
|
||||
/// Git Media 파일 URL 생성 (Gitea 형식)
|
||||
/// </summary>
|
||||
public string GetGitRawUrl(string assetPath)
|
||||
{
|
||||
// Assets/ResourcesData/Prop/... 형식의 경로를 Git Media URL로 변환
|
||||
string relativePath = assetPath.Replace("\\", "/");
|
||||
|
||||
// 경로의 각 세그먼트를 URL 인코딩 (슬래시는 유지)
|
||||
string[] segments = relativePath.Split('/');
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
segments[i] = Uri.EscapeDataString(segments[i]);
|
||||
}
|
||||
string encodedPath = string.Join("/", segments);
|
||||
|
||||
return $"{gitServerUrl}/{gitRepoPath}/media/branch/{gitBranch}/{encodedPath}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API 설정이 유효한지 확인
|
||||
/// </summary>
|
||||
public bool IsValid()
|
||||
{
|
||||
return !string.IsNullOrEmpty(apiEndpoint) &&
|
||||
!string.IsNullOrEmpty(gitServerUrl) &&
|
||||
!string.IsNullOrEmpty(gitRepoPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98eaf226422c2a746ab5e281d74c76e8
|
||||
@ -0,0 +1,409 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Streamingle.Prop.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 프랍 데이터를 웹사이트 API로 업로드
|
||||
/// 썸네일은 Git URL을 사용
|
||||
/// </summary>
|
||||
public class WebsitePropExporter : EditorWindow
|
||||
{
|
||||
private PropSyncSettings _settings;
|
||||
private PropDatabase _database;
|
||||
private string _statusMessage = "";
|
||||
private MessageType _statusType = MessageType.Info;
|
||||
private bool _isExporting;
|
||||
private UnityWebRequestAsyncOperation _currentRequest;
|
||||
|
||||
private const string SETTINGS_PATH = "Assets/Resources/Settings/PropSyncSettings.asset";
|
||||
private const string DATABASE_PATH = "Assets/Resources/Settings/PropDatabase.asset";
|
||||
|
||||
[MenuItem("Streamingle/Upload Props to Website")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<WebsitePropExporter>("프랍 업로드");
|
||||
window.minSize = new Vector2(450, 400);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
private void LoadSettings()
|
||||
{
|
||||
_settings = AssetDatabase.LoadAssetAtPath<PropSyncSettings>(SETTINGS_PATH);
|
||||
_database = AssetDatabase.LoadAssetAtPath<PropDatabase>(DATABASE_PATH);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
EditorGUILayout.Space(10);
|
||||
EditorGUILayout.LabelField("프랍 웹사이트 업로드", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
// 설정 확인
|
||||
if (_settings == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("PropSyncSettings을 찾을 수 없습니다.\nAssets/Resources/Settings/PropSyncSettings.asset 을 생성해주세요.", MessageType.Warning);
|
||||
|
||||
if (GUILayout.Button("설정 파일 생성"))
|
||||
{
|
||||
CreateSettingsAsset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_database == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("PropDatabase를 찾을 수 없습니다.\n프랍 브라우저에서 새로고침을 눌러주세요.", MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// API 설정
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
EditorGUILayout.LabelField("API 설정", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
_settings.apiEndpoint = EditorGUILayout.TextField("API 엔드포인트", _settings.apiEndpoint);
|
||||
_settings.apiKey = EditorGUILayout.TextField("API 키 (선택)", _settings.apiKey);
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("Git 설정 (썸네일 URL용)", EditorStyles.boldLabel);
|
||||
_settings.gitServerUrl = EditorGUILayout.TextField("Git Server URL", _settings.gitServerUrl);
|
||||
_settings.gitRepoPath = EditorGUILayout.TextField("Repo Path", _settings.gitRepoPath);
|
||||
_settings.gitBranch = EditorGUILayout.TextField("Branch", _settings.gitBranch);
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
_settings.websiteUrl = EditorGUILayout.TextField("웹사이트 URL", _settings.websiteUrl);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorUtility.SetDirty(_settings);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
// 설정 유효성 검사
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
if (!_settings.IsValid())
|
||||
{
|
||||
EditorGUILayout.HelpBox("API 엔드포인트와 Git 설정을 입력해주세요.", MessageType.Warning);
|
||||
}
|
||||
|
||||
// 썸네일 URL 예시
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("썸네일 URL 예시:", EditorStyles.boldLabel);
|
||||
string exampleUrl = _settings.GetGitRawUrl("Assets/ResourcesData/Prop/예시/Thumbnail/예시_thumbnail.png");
|
||||
EditorGUILayout.SelectableLabel(exampleUrl, EditorStyles.miniLabel, GUILayout.Height(20));
|
||||
|
||||
// 데이터베이스 정보
|
||||
EditorGUILayout.Space(10);
|
||||
EditorGUILayout.LabelField($"프랍 수: {_database.props.Count}개", EditorStyles.miniLabel);
|
||||
|
||||
// 업로드 버튼
|
||||
EditorGUILayout.Space(20);
|
||||
|
||||
GUI.enabled = _settings.IsValid() && !_isExporting;
|
||||
|
||||
if (GUILayout.Button("웹사이트에 업로드", GUILayout.Height(35)))
|
||||
{
|
||||
UploadToWebsite();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
if (GUILayout.Button("업로드 후 브라우저에서 열기", GUILayout.Height(30)))
|
||||
{
|
||||
UploadToWebsite(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_settings.websiteUrl))
|
||||
{
|
||||
Application.OpenURL(_settings.websiteUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
if (GUILayout.Button("API 연결 테스트", GUILayout.Height(25)))
|
||||
{
|
||||
TestApiConnection();
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
|
||||
// 상태 메시지
|
||||
if (!string.IsNullOrEmpty(_statusMessage))
|
||||
{
|
||||
EditorGUILayout.Space(10);
|
||||
EditorGUILayout.HelpBox(_statusMessage, _statusType);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateSettingsAsset()
|
||||
{
|
||||
// Settings 폴더 확인
|
||||
if (!AssetDatabase.IsValidFolder("Assets/Resources"))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets", "Resources");
|
||||
}
|
||||
if (!AssetDatabase.IsValidFolder("Assets/Resources/Settings"))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets/Resources", "Settings");
|
||||
}
|
||||
|
||||
// 새 설정 파일 생성
|
||||
var settings = CreateInstance<PropSyncSettings>();
|
||||
AssetDatabase.CreateAsset(settings, SETTINGS_PATH);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
_settings = settings;
|
||||
UnityEngine.Debug.Log("[WebsitePropExporter] PropSyncSettings 생성됨");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 웹사이트에 프랍 데이터 업로드 (개별 프리펩 단위)
|
||||
/// </summary>
|
||||
public void UploadToWebsite(Action onSuccess = null)
|
||||
{
|
||||
_isExporting = true;
|
||||
_statusMessage = "업로드 준비 중...";
|
||||
_statusType = MessageType.Info;
|
||||
|
||||
try
|
||||
{
|
||||
// JSON 데이터 생성 - 개별 프리펩 단위로 내보내기
|
||||
var exportData = new WebsitePropData
|
||||
{
|
||||
lastUpdated = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||
props = new List<WebsitePropItem>()
|
||||
};
|
||||
|
||||
foreach (var propInfo in _database.props)
|
||||
{
|
||||
// 폴더에 프리펩이 있으면 각 프리펩을 개별 항목으로 추가
|
||||
if (propInfo.prefabPaths.Count > 0)
|
||||
{
|
||||
foreach (var prefabPath in propInfo.prefabPaths)
|
||||
{
|
||||
string prefabName = System.IO.Path.GetFileNameWithoutExtension(prefabPath);
|
||||
|
||||
// 개별 프리펩 썸네일 경로 찾기
|
||||
string prefabThumbnailPath = $"{propInfo.folderPath}/Thumbnail/{prefabName}_thumbnail.png";
|
||||
string prefabThumbnailFullPath = prefabThumbnailPath.Replace("Assets/", Application.dataPath + "/");
|
||||
|
||||
// 개별 썸네일이 있으면 사용, 없으면 폴더 썸네일 사용
|
||||
string thumbnailPath = System.IO.File.Exists(prefabThumbnailFullPath)
|
||||
? prefabThumbnailPath
|
||||
: propInfo.thumbnailPath;
|
||||
|
||||
var item = new WebsitePropItem
|
||||
{
|
||||
name = prefabName, // 프리펩 파일 이름 사용
|
||||
folderPath = propInfo.folderPath,
|
||||
folderName = propInfo.propName, // 원래 폴더 이름도 유지
|
||||
prefabPath = prefabPath,
|
||||
prefabCount = 1,
|
||||
modelCount = propInfo.modelPaths.Count,
|
||||
textureCount = propInfo.textureCount,
|
||||
materialCount = propInfo.materialCount,
|
||||
thumbnailUrl = !string.IsNullOrEmpty(thumbnailPath)
|
||||
? _settings.GetGitRawUrl(thumbnailPath)
|
||||
: null
|
||||
};
|
||||
|
||||
exportData.props.Add(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 프리펩이 없는 경우 폴더명으로 추가
|
||||
var item = new WebsitePropItem
|
||||
{
|
||||
name = propInfo.propName,
|
||||
folderPath = propInfo.folderPath,
|
||||
folderName = propInfo.propName,
|
||||
prefabPath = null,
|
||||
prefabCount = 0,
|
||||
modelCount = propInfo.modelPaths.Count,
|
||||
textureCount = propInfo.textureCount,
|
||||
materialCount = propInfo.materialCount,
|
||||
thumbnailUrl = !string.IsNullOrEmpty(propInfo.thumbnailPath)
|
||||
? _settings.GetGitRawUrl(propInfo.thumbnailPath)
|
||||
: null
|
||||
};
|
||||
|
||||
exportData.props.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// JSON 문자열 생성
|
||||
string json = JsonConvert.SerializeObject(exportData, Formatting.Indented);
|
||||
|
||||
// HTTP POST 요청
|
||||
SendPostRequest(json, onSuccess);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_statusMessage = $"데이터 준비 실패: {ex.Message}";
|
||||
_statusType = MessageType.Error;
|
||||
_isExporting = false;
|
||||
UnityEngine.Debug.LogError($"[WebsitePropExporter] 데이터 준비 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void SendPostRequest(string jsonData, Action onSuccess)
|
||||
{
|
||||
_statusMessage = "서버에 업로드 중...";
|
||||
|
||||
var request = new UnityWebRequest(_settings.apiEndpoint, "POST");
|
||||
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonData);
|
||||
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
|
||||
if (!string.IsNullOrEmpty(_settings.apiKey))
|
||||
{
|
||||
request.SetRequestHeader("X-API-Key", _settings.apiKey);
|
||||
}
|
||||
|
||||
_currentRequest = request.SendWebRequest();
|
||||
_currentRequest.completed += operation =>
|
||||
{
|
||||
HandleUploadResponse(request, onSuccess);
|
||||
};
|
||||
|
||||
// 진행 상황 업데이트를 위한 에디터 갱신
|
||||
EditorApplication.update += UpdateProgress;
|
||||
}
|
||||
|
||||
private void UpdateProgress()
|
||||
{
|
||||
if (_currentRequest != null && !_currentRequest.isDone)
|
||||
{
|
||||
_statusMessage = $"업로드 중... {(_currentRequest.progress * 100):F0}%";
|
||||
Repaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorApplication.update -= UpdateProgress;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleUploadResponse(UnityWebRequest request, Action onSuccess)
|
||||
{
|
||||
_isExporting = false;
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = JsonConvert.DeserializeObject<PropApiResponse>(request.downloadHandler.text);
|
||||
if (response.success)
|
||||
{
|
||||
_statusMessage = $"업로드 완료!\n{response.message}\n업데이트: {response.lastUpdated}";
|
||||
_statusType = MessageType.Info;
|
||||
UnityEngine.Debug.Log($"[WebsitePropExporter] 업로드 성공: {response.message}");
|
||||
onSuccess?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
_statusMessage = $"서버 오류: {response.error}";
|
||||
_statusType = MessageType.Error;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_statusMessage = $"응답 파싱 실패: {ex.Message}\n응답: {request.downloadHandler.text}";
|
||||
_statusType = MessageType.Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_statusMessage = $"업로드 실패!\n{request.error}\n상태코드: {request.responseCode}";
|
||||
_statusType = MessageType.Error;
|
||||
UnityEngine.Debug.LogError($"[WebsitePropExporter] 업로드 실패: {request.error}");
|
||||
}
|
||||
|
||||
request.Dispose();
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void TestApiConnection()
|
||||
{
|
||||
_statusMessage = "API 연결 테스트 중...";
|
||||
_statusType = MessageType.Info;
|
||||
|
||||
var request = UnityWebRequest.Get(_settings.apiEndpoint);
|
||||
var operation = request.SendWebRequest();
|
||||
|
||||
operation.completed += op =>
|
||||
{
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
_statusMessage = $"API 연결 성공!\n응답: {request.downloadHandler.text.Substring(0, Math.Min(200, request.downloadHandler.text.Length))}...";
|
||||
_statusType = MessageType.Info;
|
||||
}
|
||||
else
|
||||
{
|
||||
_statusMessage = $"API 연결 실패!\n{request.error}\n상태코드: {request.responseCode}";
|
||||
_statusType = MessageType.Error;
|
||||
}
|
||||
|
||||
request.Dispose();
|
||||
Repaint();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API 응답 구조
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PropApiResponse
|
||||
{
|
||||
public bool success;
|
||||
public string message;
|
||||
public string error;
|
||||
public string lastUpdated;
|
||||
public int count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 웹사이트용 프랍 데이터 구조
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class WebsitePropData
|
||||
{
|
||||
public string lastUpdated;
|
||||
public List<WebsitePropItem> props;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 웹사이트용 개별 프랍 항목 (프리펩 단위)
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class WebsitePropItem
|
||||
{
|
||||
public string name; // 프리펩 이름
|
||||
public string folderPath; // 폴더 경로
|
||||
public string folderName; // 원래 폴더 이름
|
||||
public string prefabPath; // 프리펩 경로
|
||||
public int prefabCount;
|
||||
public int modelCount;
|
||||
public int textureCount;
|
||||
public int materialCount;
|
||||
public string thumbnailUrl;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7f64cb7ac7294a41a80919b89f3d527
|
||||
@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Streamingle.Prop
|
||||
{
|
||||
/// <summary>
|
||||
/// 프랍 정보를 담는 데이터 클래스
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PropInfo
|
||||
{
|
||||
public string propName; // 프랍 이름
|
||||
public string folderPath; // 프랍 폴더 경로 (Assets/...)
|
||||
public string thumbnailPath; // 썸네일 이미지 경로
|
||||
public Texture2D thumbnail; // 로드된 썸네일 (런타임용)
|
||||
public List<string> prefabPaths = new List<string>(); // 프리펩 경로들
|
||||
public List<string> modelPaths = new List<string>(); // 모델 파일 경로들
|
||||
public int textureCount; // 텍스처 파일 수
|
||||
public int materialCount; // 머티리얼 파일 수
|
||||
|
||||
public string DisplayName => propName;
|
||||
|
||||
/// <summary>
|
||||
/// 대표 프리펩 경로 (첫 번째)
|
||||
/// </summary>
|
||||
public string MainPrefabPath => prefabPaths.Count > 0 ? prefabPaths[0] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 프랍 데이터를 저장하는 ScriptableObject
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "PropDatabase", menuName = "Streamingle/Prop Database")]
|
||||
public class PropDatabase : ScriptableObject
|
||||
{
|
||||
public List<PropInfo> props = new List<PropInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// 프랍 이름으로 검색
|
||||
/// </summary>
|
||||
public PropInfo FindByName(string propName)
|
||||
{
|
||||
return props.Find(p => p.propName == propName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 폴더 경로로 검색
|
||||
/// </summary>
|
||||
public PropInfo FindByPath(string folderPath)
|
||||
{
|
||||
return props.Find(p => p.folderPath == folderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e148686fc073a10478d6beb39b4cd8d8
|
||||
Loading…
x
Reference in New Issue
Block a user