Compare commits
No commits in common. '2b18d39744830a0666a863910029341e2bb6494b' and 'ae8f8f12164f6cef18687e13c3f2cff5dfac6ee7' have entirely different histories.
2b18d39744
...
ae8f8f1216
21 changed files with 93 additions and 462 deletions
@ -1,9 +0,0 @@ |
|||||||
using Unity.Profiling; |
|
||||||
|
|
||||||
namespace Tools |
|
||||||
{ |
|
||||||
public static class ProfilerUtil |
|
||||||
{ |
|
||||||
public static readonly ProfilerMarker MyMarker = new ProfilerMarker("MyCustomCode"); |
|
||||||
} |
|
||||||
} |
|
@ -1,3 +0,0 @@ |
|||||||
fileFormatVersion: 2 |
|
||||||
guid: ab28fc99e92b409aadd67ec27519c3cc |
|
||||||
timeCreated: 1737917311 |
|
@ -1,118 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.Reflection; |
|
||||||
using OfficeOpenXml; |
|
||||||
using Sirenix.OdinInspector; |
|
||||||
using UnityEditor; |
|
||||||
using UnityEngine; |
|
||||||
|
|
||||||
namespace Tools.ExcelResolver.Editor |
|
||||||
{ |
|
||||||
public sealed partial class ExcelResolverEditorWindow |
|
||||||
{ |
|
||||||
[FoldoutGroup("Hide Setting")] |
|
||||||
[ShowInInspector] private Dictionary<ExcelWorksheet, ClassCodeData> classCodeDataDict = new(); |
|
||||||
|
|
||||||
private void WriteDataSO() |
|
||||||
{ |
|
||||||
foreach (var classCodeDataDictPair in classCodeDataDict) |
|
||||||
{ |
|
||||||
var worksheet = classCodeDataDictPair.Key; |
|
||||||
var classCodeData = classCodeDataDictPair.Value; |
|
||||||
|
|
||||||
var dataName = $"{classCodeData.className}"; |
|
||||||
var path = $"{excelResolverConfig.SOPathRoot}/{classCodeData.className}/"; |
|
||||||
|
|
||||||
string[] assetGuids = AssetDatabase.FindAssets($"t:{dataName}", new[] { path }); |
|
||||||
Dictionary<string, ScriptableObject> originAssets = new(); |
|
||||||
for (int i = 0; i < assetGuids.Length; i++) |
|
||||||
{ |
|
||||||
string assetPath = AssetDatabase.GUIDToAssetPath(assetGuids[i]); |
|
||||||
ScriptableObject scriptableObject = AssetDatabase.LoadAssetAtPath<ScriptableObject>(assetPath); |
|
||||||
originAssets.Add(scriptableObject.name, scriptableObject); |
|
||||||
} |
|
||||||
|
|
||||||
var result = new List<ScriptableObject>(); |
|
||||||
|
|
||||||
for (int row = 1; row <= worksheet.Dimension.End.Row; row++) |
|
||||||
{ |
|
||||||
// 跳过注释行 |
|
||||||
if (worksheet.Cells[row, 1].Text.StartsWith("##")) continue; |
|
||||||
|
|
||||||
var assetName = getAssetName(worksheet, row, classCodeData); |
|
||||||
var fullPath = $"{path}{assetName}.asset"; |
|
||||||
|
|
||||||
if (originAssets.ContainsKey(assetName)) |
|
||||||
{ |
|
||||||
set(originAssets[assetName], worksheet, row, classCodeData); |
|
||||||
EditorUtility.SetDirty(originAssets[assetName]); |
|
||||||
Debug.Log($"刷新:{assetName}", originAssets[assetName]); |
|
||||||
result.Add(originAssets[assetName]); |
|
||||||
originAssets.Remove(assetName); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
ScriptableObject instance = ScriptableObject.CreateInstance(dataName); |
|
||||||
set(instance, worksheet, row, classCodeData); |
|
||||||
AssetDatabase.CreateAsset(instance, fullPath); |
|
||||||
Debug.Log($"创建:{assetName}", instance); |
|
||||||
result.Add(instance); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
foreach (var value in originAssets.Values) |
|
||||||
{ |
|
||||||
Debug.LogError($"删除:{value.name}", value); |
|
||||||
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(value)); |
|
||||||
} |
|
||||||
|
|
||||||
WriteUtilSO(path, result, classCodeData); |
|
||||||
} |
|
||||||
|
|
||||||
AssetDatabase.SaveAssets(); |
|
||||||
GC.Collect(); |
|
||||||
GC.WaitForPendingFinalizers(); |
|
||||||
|
|
||||||
void set(ScriptableObject instance, ExcelWorksheet worksheet, int row, ClassCodeData classCodeData) |
|
||||||
{ |
|
||||||
foreach (var pair in classCodeData.fields) |
|
||||||
{ |
|
||||||
var col = pair.Key; |
|
||||||
var fieldData = pair.Value; |
|
||||||
|
|
||||||
var cell = worksheet.Cells[row, col]; |
|
||||||
object convertedValue = ExcelResolverUtil.ConvertCellValue(cell, fieldData.type, classCodeData.className); |
|
||||||
FieldInfo fieldInfo = instance.GetType().GetField(fieldData.varName); |
|
||||||
if (fieldInfo == null) throw new Exception($"{classCodeData.className}中不存在字段:{fieldData.varName}"); |
|
||||||
fieldInfo.SetValue(instance, convertedValue); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
string getAssetName(ExcelWorksheet worksheet, int row, ClassCodeData classCodeData) |
|
||||||
{ |
|
||||||
switch (classCodeData.tableType) |
|
||||||
{ |
|
||||||
case TableType.SingleKeyTable: |
|
||||||
var keyColIndex = classCodeData.keyField[0].colIndex; |
|
||||||
var key = worksheet.Cells[row, keyColIndex].Text; |
|
||||||
if (!string.IsNullOrEmpty(key)) |
|
||||||
return $"{classCodeData.className}_{key}"; |
|
||||||
break; |
|
||||||
// case TableType.UnionMultiKeyTable: |
|
||||||
// return $"{classCodeData.className}_{classCodeData.keyField[0].varName}"; |
|
||||||
// case TableType.MultiKeyTable: |
|
||||||
// return $"{classCodeData.className}_{classCodeData.keyField[0].varName}"; |
|
||||||
// case TableType.NotKetTable: |
|
||||||
// return classCodeData.className; |
|
||||||
// case TableType.ColumnTable: |
|
||||||
// return $"{classCodeData.className}_{classCodeData.fields[2].Value.varName}"; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
throw new Exception($"无法定义资产名称 " + |
|
||||||
$"className: '<color=cyan>{classCodeData.className}</color>' " + |
|
||||||
$"FullAddress: <color=cyan>{row}</color> "); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,80 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.IO; |
||||||
|
using System.Reflection; |
||||||
|
using OfficeOpenXml; |
||||||
|
using Sirenix.OdinInspector; |
||||||
|
using UnityEditor; |
||||||
|
using UnityEngine; |
||||||
|
|
||||||
|
namespace Tools.ExcelResolver.Editor |
||||||
|
{ |
||||||
|
public sealed partial class ExcelResolverEditorWindow |
||||||
|
{ |
||||||
|
[FoldoutGroup("Hide Setting")] |
||||||
|
[ShowInInspector] private Dictionary<ExcelWorksheet, ClassCodeData> classCodeDataDict = new(); |
||||||
|
|
||||||
|
private void WriteSOData() |
||||||
|
{ |
||||||
|
foreach (var classCodeDataDictPair in classCodeDataDict) |
||||||
|
{ |
||||||
|
var worksheet = classCodeDataDictPair.Key; |
||||||
|
var classCodeData = classCodeDataDictPair.Value; |
||||||
|
|
||||||
|
Type soType = ExcelResolverUtil.GetOrCacheTypeByName(classCodeData.className); |
||||||
|
|
||||||
|
if (soType == null) |
||||||
|
{ |
||||||
|
Debug.LogError($"Class '{classCodeData.className}SO' not found. Please generate classes first (or check namespace)."); |
||||||
|
return; |
||||||
|
} |
||||||
|
var path = $"{excelResolverConfig.SOPathRoot}/{classCodeData.className}/"; |
||||||
|
|
||||||
|
for (int row = 1; row <= worksheet.Dimension.End.Row; row++) |
||||||
|
{ |
||||||
|
var assetName = $"{classCodeData.className}_{row}"; |
||||||
|
var fullPath = $"{path}{assetName}.asset"; |
||||||
|
// 跳过注释行 |
||||||
|
if (worksheet.Cells[row, 1].Text.StartsWith("##")) |
||||||
|
{ |
||||||
|
if (File.Exists(fullPath)) |
||||||
|
{ |
||||||
|
AssetDatabase.DeleteAsset(fullPath); |
||||||
|
Debug.LogError($"删除:{assetName}"); |
||||||
|
} |
||||||
|
continue; |
||||||
|
} |
||||||
|
ScriptableObject instance; |
||||||
|
if (File.Exists(fullPath)) |
||||||
|
{ |
||||||
|
instance = AssetDatabase.LoadAssetAtPath<ScriptableObject>(fullPath); |
||||||
|
Debug.Log($"刷新:{assetName}", instance); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
instance = ScriptableObject.CreateInstance(soType); |
||||||
|
AssetDatabase.CreateAsset(instance, fullPath); |
||||||
|
AssetDatabase.SaveAssets(); |
||||||
|
Debug.Log($"创建:{assetName}", instance); |
||||||
|
} |
||||||
|
|
||||||
|
foreach (var pair in classCodeData.fields) |
||||||
|
{ |
||||||
|
var col = pair.Key; |
||||||
|
var fieldData = pair.Value; |
||||||
|
|
||||||
|
var cell = worksheet.Cells[row, col]; |
||||||
|
object convertedValue = ExcelResolverUtil.ConvertCellValue(cell, fieldData.type, classCodeData.className); |
||||||
|
FieldInfo fieldInfo = soType.GetField(fieldData.varName); |
||||||
|
if (fieldInfo == null) throw new Exception($"目标类中不存在字段:{fieldData.varName}"); |
||||||
|
fieldInfo.SetValue(instance, convertedValue); |
||||||
|
} |
||||||
|
EditorUtility.SetDirty(instance); |
||||||
|
} |
||||||
|
AssetDatabase.SaveAssets(); |
||||||
|
} |
||||||
|
GC.Collect(); |
||||||
|
GC.WaitForPendingFinalizers(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,48 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Collections; |
|
||||||
using System.Collections.Generic; |
|
||||||
using UnityEditor; |
|
||||||
using UnityEngine; |
|
||||||
|
|
||||||
namespace Tools.ExcelResolver.Editor |
|
||||||
{ |
|
||||||
public sealed partial class ExcelResolverEditorWindow |
|
||||||
{ |
|
||||||
private void WriteUtilSO(string path, List<ScriptableObject> assets, ClassCodeData classCodeData) |
|
||||||
{ |
|
||||||
var utilName = $"{classCodeData.className}Util"; |
|
||||||
var utilPath = $"{path}/_{utilName}.asset"; |
|
||||||
|
|
||||||
var instance = AssetDatabase.LoadAssetAtPath<ScriptableObject>(utilPath); |
|
||||||
if (instance == null) |
|
||||||
{ |
|
||||||
instance = ScriptableObject.CreateInstance(utilName); |
|
||||||
AssetDatabase.CreateAsset(instance, utilPath); |
|
||||||
} |
|
||||||
|
|
||||||
switch (classCodeData.tableType) |
|
||||||
{ |
|
||||||
case TableType.SingleKeyTable: |
|
||||||
var keyField = classCodeData.keyField[0]; |
|
||||||
var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(keyField.type.RealType, assets[0].GetType())); |
|
||||||
|
|
||||||
foreach (var asset in assets) |
|
||||||
{ |
|
||||||
var key = asset.GetType().GetField(keyField.varName).GetValue(asset); |
|
||||||
dict[key] = asset; |
|
||||||
} |
|
||||||
instance.GetType().GetField("Data").SetValue(instance, dict); |
|
||||||
break; |
|
||||||
case TableType.UnionMultiKeyTable: |
|
||||||
break; |
|
||||||
case TableType.MultiKeyTable: |
|
||||||
break; |
|
||||||
case TableType.NotKetTable: |
|
||||||
break; |
|
||||||
case TableType.ColumnTable: |
|
||||||
break; |
|
||||||
} |
|
||||||
EditorUtility.SetDirty(instance); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,3 +0,0 @@ |
|||||||
fileFormatVersion: 2 |
|
||||||
guid: 3b78262c18a44a04af02c750d7628d02 |
|
||||||
timeCreated: 1737914896 |
|
Binary file not shown.
@ -1,132 +0,0 @@ |
|||||||
%YAML 1.1 |
|
||||||
%TAG !u! tag:unity3d.com,2011: |
|
||||||
--- !u!114 &11400000 |
|
||||||
MonoBehaviour: |
|
||||||
m_ObjectHideFlags: 0 |
|
||||||
m_CorrespondingSourceObject: {fileID: 0} |
|
||||||
m_PrefabInstance: {fileID: 0} |
|
||||||
m_PrefabAsset: {fileID: 0} |
|
||||||
m_GameObject: {fileID: 0} |
|
||||||
m_Enabled: 1 |
|
||||||
m_EditorHideFlags: 0 |
|
||||||
m_Script: {fileID: 11500000, guid: e8aa3c1560079b84cafbabe4bc0d2c8d, type: 3} |
|
||||||
m_Name: Hero_4 |
|
||||||
m_EditorClassIdentifier: |
|
||||||
serializationData: |
|
||||||
SerializedFormat: 2 |
|
||||||
SerializedBytes: |
|
||||||
ReferencedUnityObjects: [] |
|
||||||
SerializedBytesString: |
|
||||||
Prefab: {fileID: 0} |
|
||||||
PrefabModificationsReferencedUnityObjects: [] |
|
||||||
PrefabModifications: [] |
|
||||||
SerializationNodes: |
|
||||||
- Name: nihao |
|
||||||
Entry: 7 |
|
||||||
Data: 0|System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.Single, |
|
||||||
mscorlib]], mscorlib |
|
||||||
- Name: comparer |
|
||||||
Entry: 7 |
|
||||||
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.Int32, |
|
||||||
mscorlib]], mscorlib |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 12 |
|
||||||
Data: 2 |
|
||||||
- Name: |
|
||||||
Entry: 7 |
|
||||||
Data: |
|
||||||
- Name: $k |
|
||||||
Entry: 3 |
|
||||||
Data: 2 |
|
||||||
- Name: $v |
|
||||||
Entry: 4 |
|
||||||
Data: 2.3 |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 7 |
|
||||||
Data: |
|
||||||
- Name: $k |
|
||||||
Entry: 3 |
|
||||||
Data: 5 |
|
||||||
- Name: $v |
|
||||||
Entry: 4 |
|
||||||
Data: 4.6 |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 13 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: attribute |
|
||||||
Entry: 7 |
|
||||||
Data: 2|System.Collections.Generic.Dictionary`2[[Tools.ExcelResolver.Attribute, |
|
||||||
Assembly-CSharp],[System.Int32, mscorlib]], mscorlib |
|
||||||
- Name: comparer |
|
||||||
Entry: 7 |
|
||||||
Data: 3|System.Collections.Generic.EnumEqualityComparer`1[[Tools.ExcelResolver.Attribute, |
|
||||||
Assembly-CSharp]], mscorlib |
|
||||||
- Name: |
|
||||||
Entry: 12 |
|
||||||
Data: 0 |
|
||||||
- Name: |
|
||||||
Entry: 13 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 12 |
|
||||||
Data: 2 |
|
||||||
- Name: |
|
||||||
Entry: 7 |
|
||||||
Data: |
|
||||||
- Name: $k |
|
||||||
Entry: 3 |
|
||||||
Data: 0 |
|
||||||
- Name: $v |
|
||||||
Entry: 3 |
|
||||||
Data: 500 |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 7 |
|
||||||
Data: |
|
||||||
- Name: $k |
|
||||||
Entry: 3 |
|
||||||
Data: 1 |
|
||||||
- Name: $v |
|
||||||
Entry: 3 |
|
||||||
Data: 300 |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 13 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
id: 4 |
|
||||||
name: "\u9053\u58EB" |
|
||||||
icon: hero_1 |
|
||||||
has: 1 |
|
||||||
hp: 100 |
|
||||||
atk: 20 |
|
||||||
speed: 1.2 |
|
||||||
pos: {x: 0, y: 1, z: 9} |
|
||||||
ches: {x: 0, y: 1} |
|
||||||
attack_target: |
|
||||||
- {x: 1, y: 2} |
|
||||||
- {x: 1, y: 2} |
|
||||||
- {x: 1, y: 2} |
|
||||||
- {x: 1, y: 2} |
|
||||||
color: 1 |
|
@ -1,8 +0,0 @@ |
|||||||
fileFormatVersion: 2 |
|
||||||
guid: 4f9da86093404c6449ad6f21e1207cb0 |
|
||||||
NativeFormatImporter: |
|
||||||
externalObjects: {} |
|
||||||
mainObjectFileID: 11400000 |
|
||||||
userData: |
|
||||||
assetBundleName: |
|
||||||
assetBundleVariant: |
|
@ -1,5 +1,5 @@ |
|||||||
fileFormatVersion: 2 |
fileFormatVersion: 2 |
||||||
guid: 3b98756cd197195498b14b5e67935cbe |
guid: 031f6bc6b7884a54da49033ea61073a7 |
||||||
NativeFormatImporter: |
NativeFormatImporter: |
||||||
externalObjects: {} |
externalObjects: {} |
||||||
mainObjectFileID: 11400000 |
mainObjectFileID: 11400000 |
@ -1,5 +1,5 @@ |
|||||||
fileFormatVersion: 2 |
fileFormatVersion: 2 |
||||||
guid: cdde19489f16dce429041c1d6e207864 |
guid: f68d13699cf81a14a8e10092094b0f8d |
||||||
NativeFormatImporter: |
NativeFormatImporter: |
||||||
externalObjects: {} |
externalObjects: {} |
||||||
mainObjectFileID: 11400000 |
mainObjectFileID: 11400000 |
@ -1,5 +1,5 @@ |
|||||||
fileFormatVersion: 2 |
fileFormatVersion: 2 |
||||||
guid: 934bc10c06f0592419baf474987cc0a7 |
guid: acae57c5032fca54685e664fb60872d6 |
||||||
NativeFormatImporter: |
NativeFormatImporter: |
||||||
externalObjects: {} |
externalObjects: {} |
||||||
mainObjectFileID: 11400000 |
mainObjectFileID: 11400000 |
@ -1,95 +0,0 @@ |
|||||||
%YAML 1.1 |
|
||||||
%TAG !u! tag:unity3d.com,2011: |
|
||||||
--- !u!114 &11400000 |
|
||||||
MonoBehaviour: |
|
||||||
m_ObjectHideFlags: 0 |
|
||||||
m_CorrespondingSourceObject: {fileID: 0} |
|
||||||
m_PrefabInstance: {fileID: 0} |
|
||||||
m_PrefabAsset: {fileID: 0} |
|
||||||
m_GameObject: {fileID: 0} |
|
||||||
m_Enabled: 1 |
|
||||||
m_EditorHideFlags: 0 |
|
||||||
m_Script: {fileID: 11500000, guid: 0b8ec7437f31db141b138472f0c2a3aa, type: 3} |
|
||||||
m_Name: _HeroUtil |
|
||||||
m_EditorClassIdentifier: |
|
||||||
serializationData: |
|
||||||
SerializedFormat: 2 |
|
||||||
SerializedBytes: |
|
||||||
ReferencedUnityObjects: |
|
||||||
- {fileID: 11400000, guid: 3b98756cd197195498b14b5e67935cbe, type: 2} |
|
||||||
- {fileID: 11400000, guid: cdde19489f16dce429041c1d6e207864, type: 2} |
|
||||||
- {fileID: 11400000, guid: 934bc10c06f0592419baf474987cc0a7, type: 2} |
|
||||||
- {fileID: 11400000, guid: 4f9da86093404c6449ad6f21e1207cb0, type: 2} |
|
||||||
SerializedBytesString: |
|
||||||
Prefab: {fileID: 0} |
|
||||||
PrefabModificationsReferencedUnityObjects: [] |
|
||||||
PrefabModifications: [] |
|
||||||
SerializationNodes: |
|
||||||
- Name: Data |
|
||||||
Entry: 7 |
|
||||||
Data: 0|System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[Tools.ExcelResolver.Hero, |
|
||||||
Assembly-CSharp]], mscorlib |
|
||||||
- Name: comparer |
|
||||||
Entry: 7 |
|
||||||
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.Int32, |
|
||||||
mscorlib]], mscorlib |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 12 |
|
||||||
Data: 4 |
|
||||||
- Name: |
|
||||||
Entry: 7 |
|
||||||
Data: |
|
||||||
- Name: $k |
|
||||||
Entry: 3 |
|
||||||
Data: 1 |
|
||||||
- Name: $v |
|
||||||
Entry: 10 |
|
||||||
Data: 0 |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 7 |
|
||||||
Data: |
|
||||||
- Name: $k |
|
||||||
Entry: 3 |
|
||||||
Data: 2 |
|
||||||
- Name: $v |
|
||||||
Entry: 10 |
|
||||||
Data: 1 |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 7 |
|
||||||
Data: |
|
||||||
- Name: $k |
|
||||||
Entry: 3 |
|
||||||
Data: 3 |
|
||||||
- Name: $v |
|
||||||
Entry: 10 |
|
||||||
Data: 2 |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 7 |
|
||||||
Data: |
|
||||||
- Name: $k |
|
||||||
Entry: 3 |
|
||||||
Data: 4 |
|
||||||
- Name: $v |
|
||||||
Entry: 10 |
|
||||||
Data: 3 |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 13 |
|
||||||
Data: |
|
||||||
- Name: |
|
||||||
Entry: 8 |
|
||||||
Data: |
|
Loading…
Reference in new issue