remove sfx wav subfix. Update some NRE cases
This commit is contained in:
@@ -15,7 +15,7 @@ MonoBehaviour:
|
||||
m_DefaultGroup: 712e3991f28e549e7a56ee582a977810
|
||||
m_currentHash:
|
||||
serializedVersion: 2
|
||||
Hash: 6df2b5e922d0a8184eba54abd29fafeb
|
||||
Hash: 00000000000000000000000000000000
|
||||
m_OptimizeCatalogSize: 0
|
||||
m_BuildRemoteCatalog: 0
|
||||
m_CatalogRequestsTimeout: 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,8 @@ namespace BrewMonster.Scripts
|
||||
private Dictionary<string, AsyncOperationHandle<TextAsset>> _loadedTextAssets = new();
|
||||
private Dictionary<string, AsyncOperationHandle<AudioClip>> _loadedAudioAssets = new();
|
||||
|
||||
private Dictionary<string, int> _loadedAssetReferenceCount = new();
|
||||
|
||||
/// <summary>
|
||||
/// Whenever we release an asset, we store the timestamp of the release.
|
||||
/// After a certain amount of time, we will release the asset from the cache.
|
||||
@@ -98,6 +100,29 @@ namespace BrewMonster.Scripts
|
||||
_releaseAssetTimestamps.Remove(assetPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void IncreaseReferenceCount(string assetPath)
|
||||
{
|
||||
if (!_loadedAssetReferenceCount.ContainsKey(assetPath))
|
||||
{
|
||||
_loadedAssetReferenceCount[assetPath] = 0;
|
||||
}
|
||||
_loadedAssetReferenceCount[assetPath]++;
|
||||
}
|
||||
|
||||
private void DecreaseReferenceCount(string assetPath)
|
||||
{
|
||||
if (_loadedAssetReferenceCount.TryGetValue(assetPath, out int count))
|
||||
{
|
||||
count--;
|
||||
if (count <= 0)
|
||||
{
|
||||
_loadedAssetReferenceCount.Remove(assetPath);
|
||||
// put into the release asset timestamp dictionary.
|
||||
_releaseAssetTimestamps[assetPath] = Time.realtimeSinceStartup;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region public functions
|
||||
@@ -111,6 +136,13 @@ namespace BrewMonster.Scripts
|
||||
/// <returns></returns>
|
||||
public async Task<TextAsset> LoadTextAssetAsync(string assetPath)
|
||||
{
|
||||
// increase the reference count of the asset.
|
||||
if (!_loadedAssetReferenceCount.ContainsKey(assetPath))
|
||||
{
|
||||
_loadedAssetReferenceCount[assetPath] = 0;
|
||||
}
|
||||
_loadedAssetReferenceCount[assetPath]++;
|
||||
|
||||
// remove the asset from the release timestamp dictionary. So it won't be released.
|
||||
RemoveFromReleaseAssetDictionary(assetPath);
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@ public class FLoatingTextManager : MonoBehaviour
|
||||
|
||||
foreach (string address in candidates)
|
||||
{
|
||||
// TODO: use AddressableManager to load the sprite.
|
||||
var handle = Addressables.LoadAssetAsync<Sprite>(address);
|
||||
handle.WaitForCompletion();
|
||||
|
||||
|
||||
@@ -0,0 +1,843 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using ModelRenderer.Scripts.Common;
|
||||
using PerfectWorld.Scripts.Task;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster.Scripts.Task
|
||||
{
|
||||
public static class TaskCsvExporter
|
||||
{
|
||||
private const string MenuPath = "Tools/Task/Export Tasks To CSV";
|
||||
private const string OutputAssetPath = "Assets/PerfectWorld/Exports/tasks_export.csv";
|
||||
private const string KnownTaskContainerAssetPath = "Assets/PerfectWorld/SO/TaskTemplContainerSO.asset";
|
||||
private const int MaxSerializationDepth = 12;
|
||||
|
||||
private static readonly string[] CustomHeaders =
|
||||
{
|
||||
"TaskId",
|
||||
"ParentId",
|
||||
"PrevSiblingId",
|
||||
"NextSiblingId",
|
||||
"FirstChildId",
|
||||
"Depth",
|
||||
"SubCount",
|
||||
"Name",
|
||||
"Description",
|
||||
"OkText",
|
||||
"NoText",
|
||||
"Tribute",
|
||||
"Signature",
|
||||
"DelvTaskTalkJson",
|
||||
"UnqualifiedTalkJson",
|
||||
"DelvItemTalkJson",
|
||||
"ExeTalkJson",
|
||||
"AwardTalkJson"
|
||||
};
|
||||
|
||||
private static readonly FieldInfo AllTaskTemplatesField = typeof(TaskTemplContainerSO).GetField(
|
||||
"_allTaskTemplates",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
[MenuItem(MenuPath)]
|
||||
public static void ExportTasksToCsv()
|
||||
{
|
||||
TaskTemplContainerSO container = null;
|
||||
bool destroyTemporaryContainer = false;
|
||||
|
||||
try
|
||||
{
|
||||
container = LoadOrBuildTaskContainer(out destroyTemporaryContainer);
|
||||
if (container == null)
|
||||
{
|
||||
Debug.LogError("[TaskCsvExporter] Could not load task data from SO or pack file.");
|
||||
return;
|
||||
}
|
||||
|
||||
container.BuildTaskTemplateMap();
|
||||
|
||||
List<ATaskTempl> allTemplates = GetAllTaskTemplates(container);
|
||||
if (allTemplates.Count == 0)
|
||||
{
|
||||
Debug.LogError("[TaskCsvExporter] No task templates were found to export.");
|
||||
return;
|
||||
}
|
||||
|
||||
PrepareTemplatesForExport(container, allTemplates);
|
||||
|
||||
List<ATaskTempl> orderedTasks = BuildOrderedTaskList(container, allTemplates);
|
||||
List<FieldInfo> fixedDataFields = GetOrderedPublicFields(typeof(ATaskTemplFixedData));
|
||||
List<Dictionary<string, string>> rows = BuildRows(orderedTasks, fixedDataFields);
|
||||
|
||||
ValidateExport(rows, orderedTasks.Count, allTemplates.Count);
|
||||
WriteCsv(rows, fixedDataFields, OutputAssetPath);
|
||||
|
||||
AssetDatabase.ImportAsset(OutputAssetPath, ImportAssetOptions.ForceUpdate);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
int readableNameCount = rows.Count(row =>
|
||||
row.TryGetValue("Name", out string value) && !string.IsNullOrWhiteSpace(value));
|
||||
|
||||
Debug.Log(
|
||||
$"[TaskCsvExporter] Exported {rows.Count} task rows to {OutputAssetPath}. " +
|
||||
$"SourceCount={allTemplates.Count}, NamedRows={readableNameCount}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (destroyTemporaryContainer && container != null)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TaskTemplContainerSO LoadOrBuildTaskContainer(out bool destroyTemporaryContainer)
|
||||
{
|
||||
destroyTemporaryContainer = false;
|
||||
|
||||
TaskTemplContainerSO existing = LoadExistingTaskContainer();
|
||||
if (HasTaskData(existing))
|
||||
{
|
||||
return existing;
|
||||
}
|
||||
|
||||
string taskPackPath = Path.Combine(Application.streamingAssetsPath, "data/tasks.data");
|
||||
if (!File.Exists(taskPackPath))
|
||||
{
|
||||
throw new FileNotFoundException(
|
||||
$"Task pack file not found at '{taskPackPath}'.",
|
||||
taskPackPath);
|
||||
}
|
||||
|
||||
TaskTemplContainerSO temporaryContainer = ScriptableObject.CreateInstance<TaskTemplContainerSO>();
|
||||
temporaryContainer.LoadAllTasksFromPack();
|
||||
destroyTemporaryContainer = true;
|
||||
return temporaryContainer;
|
||||
}
|
||||
|
||||
private static TaskTemplContainerSO LoadExistingTaskContainer()
|
||||
{
|
||||
TaskTemplContainerSO container = AssetDatabase.LoadAssetAtPath<TaskTemplContainerSO>(KnownTaskContainerAssetPath);
|
||||
if (container != null)
|
||||
{
|
||||
return container;
|
||||
}
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets("t:TaskTemplContainerSO");
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
container = AssetDatabase.LoadAssetAtPath<TaskTemplContainerSO>(assetPath);
|
||||
if (container != null)
|
||||
{
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool HasTaskData(TaskTemplContainerSO container)
|
||||
{
|
||||
return container != null && GetAllTaskTemplates(container).Count > 0;
|
||||
}
|
||||
|
||||
private static List<ATaskTempl> GetAllTaskTemplates(TaskTemplContainerSO container)
|
||||
{
|
||||
if (container == null || AllTaskTemplatesField == null)
|
||||
{
|
||||
return new List<ATaskTempl>();
|
||||
}
|
||||
|
||||
List<ATaskTempl> templates = AllTaskTemplatesField.GetValue(container) as List<ATaskTempl>;
|
||||
return templates?.Where(template => template != null).ToList() ?? new List<ATaskTempl>();
|
||||
}
|
||||
|
||||
private static void PrepareTemplatesForExport(TaskTemplContainerSO container, IEnumerable<ATaskTempl> templates)
|
||||
{
|
||||
foreach (ATaskTempl template in templates)
|
||||
{
|
||||
template.FillUnserializableDataWhenPlayGame(container);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ATaskTempl> BuildOrderedTaskList(TaskTemplContainerSO container, IReadOnlyCollection<ATaskTempl> allTemplates)
|
||||
{
|
||||
var ordered = new List<ATaskTempl>(allTemplates.Count);
|
||||
var visitedIds = new HashSet<uint>();
|
||||
|
||||
foreach (ATaskTempl topTask in container.TopTaskTemplates)
|
||||
{
|
||||
TraverseTaskTree(topTask, ordered, visitedIds);
|
||||
}
|
||||
|
||||
foreach (ATaskTempl template in allTemplates.OrderBy(template => template.m_ID))
|
||||
{
|
||||
TraverseTaskTree(template, ordered, visitedIds);
|
||||
}
|
||||
|
||||
return ordered;
|
||||
}
|
||||
|
||||
private static void TraverseTaskTree(ATaskTempl task, ICollection<ATaskTempl> ordered, ISet<uint> visitedIds)
|
||||
{
|
||||
if (task == null || !visitedIds.Add(task.m_ID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ordered.Add(task);
|
||||
|
||||
ATaskTempl child = task.m_pFirstChild;
|
||||
while (child != null)
|
||||
{
|
||||
TraverseTaskTree(child, ordered, visitedIds);
|
||||
child = child.m_pNextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Dictionary<string, string>> BuildRows(IEnumerable<ATaskTempl> tasks, IReadOnlyList<FieldInfo> fixedDataFields)
|
||||
{
|
||||
var rows = new List<Dictionary<string, string>>();
|
||||
|
||||
foreach (ATaskTempl task in tasks)
|
||||
{
|
||||
var row = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["TaskId"] = task.m_ID.ToString(CultureInfo.InvariantCulture),
|
||||
["ParentId"] = task.ParentID.ToString(CultureInfo.InvariantCulture),
|
||||
["PrevSiblingId"] = task.PrevSiblingID.ToString(CultureInfo.InvariantCulture),
|
||||
["NextSiblingId"] = task.NextSiblingID.ToString(CultureInfo.InvariantCulture),
|
||||
["FirstChildId"] = task.FirstChildID.ToString(CultureInfo.InvariantCulture),
|
||||
["Depth"] = task.m_uDepth.ToString(CultureInfo.InvariantCulture),
|
||||
["SubCount"] = task.m_nSubCount.ToString(CultureInfo.InvariantCulture),
|
||||
["Name"] = ByteToStringUtils.UshortArrayToUnicodeString(task.m_FixedData.m_szName),
|
||||
["Description"] = ByteToStringUtils.UshortArrayToUnicodeString(task.m_pwstrDescript),
|
||||
["OkText"] = ByteToStringUtils.UshortArrayToUnicodeString(task.m_pwstrOkText),
|
||||
["NoText"] = ByteToStringUtils.UshortArrayToUnicodeString(task.m_pwstrNoText),
|
||||
["Tribute"] = ByteToStringUtils.UshortArrayToUnicodeString(task.m_pwstrTribute),
|
||||
["Signature"] = ByteToStringUtils.UshortArrayToUnicodeString(task.m_FixedData.m_pszSignature),
|
||||
["DelvTaskTalkJson"] = SerializeJsonValue(task.m_DelvTaskTalk, typeof(talk_proc), "m_DelvTaskTalk", 0),
|
||||
["UnqualifiedTalkJson"] = SerializeJsonValue(task.m_UnqualifiedTalk, typeof(talk_proc), "m_UnqualifiedTalk", 0),
|
||||
["DelvItemTalkJson"] = SerializeJsonValue(task.m_DelvItemTalk, typeof(talk_proc), "m_DelvItemTalk", 0),
|
||||
["ExeTalkJson"] = SerializeJsonValue(task.m_ExeTalk, typeof(talk_proc), "m_ExeTalk", 0),
|
||||
["AwardTalkJson"] = SerializeJsonValue(task.m_AwardTalk, typeof(talk_proc), "m_AwardTalk", 0)
|
||||
};
|
||||
|
||||
object boxedFixedData = task.m_FixedData;
|
||||
foreach (FieldInfo field in fixedDataFields)
|
||||
{
|
||||
object value = field.GetValue(boxedFixedData);
|
||||
row[field.Name] = SerializeColumnValue(value, field.FieldType, field.Name);
|
||||
}
|
||||
|
||||
rows.Add(row);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static void ValidateExport(IReadOnlyCollection<Dictionary<string, string>> rows, int traversedCount, int sourceCount)
|
||||
{
|
||||
if (rows.Count != traversedCount)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"CSV row count mismatch. Rows={rows.Count}, Traversed={traversedCount}.");
|
||||
}
|
||||
|
||||
if (traversedCount != sourceCount)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Task traversal mismatch. Traversed={traversedCount}, Source={sourceCount}.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteCsv(IEnumerable<Dictionary<string, string>> rows, IReadOnlyList<FieldInfo> fixedDataFields, string assetPath)
|
||||
{
|
||||
string absolutePath = GetAbsoluteProjectPath(assetPath);
|
||||
string directory = Path.GetDirectoryName(absolutePath);
|
||||
if (!string.IsNullOrEmpty(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
var headers = new List<string>(CustomHeaders.Length + fixedDataFields.Count);
|
||||
headers.AddRange(CustomHeaders);
|
||||
headers.AddRange(fixedDataFields.Select(field => field.Name));
|
||||
|
||||
var builder = new StringBuilder(1024 * 1024);
|
||||
builder.AppendLine(string.Join(",", headers.Select(CsvEscape)));
|
||||
|
||||
foreach (Dictionary<string, string> row in rows)
|
||||
{
|
||||
string[] values = headers
|
||||
.Select(header => row.TryGetValue(header, out string value) ? value : string.Empty)
|
||||
.Select(CsvEscape)
|
||||
.ToArray();
|
||||
|
||||
builder.AppendLine(string.Join(",", values));
|
||||
}
|
||||
|
||||
File.WriteAllText(absolutePath, builder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: true));
|
||||
}
|
||||
|
||||
private static string GetAbsoluteProjectPath(string assetPath)
|
||||
{
|
||||
string projectRoot = Directory.GetParent(Application.dataPath)?.FullName ?? Directory.GetCurrentDirectory();
|
||||
return Path.Combine(projectRoot, assetPath);
|
||||
}
|
||||
|
||||
private static string CsvEscape(string value)
|
||||
{
|
||||
value ??= string.Empty;
|
||||
|
||||
bool needsQuotes =
|
||||
value.IndexOf(',') >= 0 ||
|
||||
value.IndexOf('"') >= 0 ||
|
||||
value.IndexOf('\n') >= 0 ||
|
||||
value.IndexOf('\r') >= 0;
|
||||
|
||||
if (!needsQuotes)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return "\"" + value.Replace("\"", "\"\"") + "\"";
|
||||
}
|
||||
|
||||
private static string SerializeColumnValue(object value, Type declaredType, string path)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
Type type = Nullable.GetUnderlyingType(declaredType) ?? declaredType;
|
||||
|
||||
if (TrySerializeLeafValue(value, type, path, false, out string leafValue))
|
||||
{
|
||||
return leafValue;
|
||||
}
|
||||
|
||||
if (type.IsArray)
|
||||
{
|
||||
return SerializeJsonValue(value, type, path, 0);
|
||||
}
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(type) && type != typeof(string))
|
||||
{
|
||||
return SerializeEnumerableValue((IEnumerable)value, path, 0);
|
||||
}
|
||||
|
||||
return SerializeJsonValue(value, type, path, 0);
|
||||
}
|
||||
|
||||
private static string SerializeJsonValue(object value, Type declaredType, string path, int depth)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (depth >= MaxSerializationDepth)
|
||||
{
|
||||
return QuoteJson("<max-depth>");
|
||||
}
|
||||
|
||||
Type type = Nullable.GetUnderlyingType(declaredType) ?? declaredType;
|
||||
|
||||
if (TrySerializeLeafValue(value, type, path, true, out string leafValue))
|
||||
{
|
||||
return leafValue;
|
||||
}
|
||||
|
||||
if (type.IsArray)
|
||||
{
|
||||
return SerializeArrayValue((Array)value, path, depth + 1);
|
||||
}
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(type) && type != typeof(string))
|
||||
{
|
||||
return SerializeEnumerableValue((IEnumerable)value, path, depth + 1);
|
||||
}
|
||||
|
||||
return SerializeObjectValue(value, type, path, depth + 1);
|
||||
}
|
||||
|
||||
private static string SerializeObjectValue(object value, Type type, string path, int depth)
|
||||
{
|
||||
List<FieldInfo> fields = GetOrderedPublicFields(type);
|
||||
if (fields.Count == 0)
|
||||
{
|
||||
return QuoteJson(Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty);
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append('{');
|
||||
|
||||
for (int i = 0; i < fields.Count; i++)
|
||||
{
|
||||
FieldInfo field = fields[i];
|
||||
if (i > 0)
|
||||
{
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
object fieldValue = field.GetValue(value);
|
||||
string fieldPath = string.IsNullOrEmpty(path) ? field.Name : path + "." + field.Name;
|
||||
|
||||
builder.Append(QuoteJson(field.Name));
|
||||
builder.Append(':');
|
||||
builder.Append(SerializeJsonValue(fieldValue, field.FieldType, fieldPath, depth));
|
||||
}
|
||||
|
||||
builder.Append('}');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static string SerializeArrayValue(Array array, string path, int depth)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
Type elementType = array.GetType().GetElementType() ?? typeof(object);
|
||||
|
||||
if (array.Rank == 2)
|
||||
{
|
||||
return SerializeMatrixValue(array, elementType, path, depth);
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append('[');
|
||||
|
||||
int index = 0;
|
||||
foreach (object item in array)
|
||||
{
|
||||
if (index++ > 0)
|
||||
{
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
builder.Append(SerializeJsonValue(item, elementType, path + "[]", depth));
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static string SerializeMatrixValue(Array matrix, Type elementType, string path, int depth)
|
||||
{
|
||||
if (elementType == typeof(ushort) && IsTaskCharField(path))
|
||||
{
|
||||
return SerializeUnicodeRowArray(ReadUnicodeRows((ushort[,])matrix));
|
||||
}
|
||||
|
||||
if (elementType == typeof(byte) && IsByteTextField(path))
|
||||
{
|
||||
return SerializeUnicodeRowArray(ReadUnicodeRows((byte[,])matrix));
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append('[');
|
||||
|
||||
int rows = matrix.GetLength(0);
|
||||
int cols = matrix.GetLength(1);
|
||||
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
if (row > 0)
|
||||
{
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
builder.Append('[');
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
if (col > 0)
|
||||
{
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
object elementValue = matrix.GetValue(row, col);
|
||||
builder.Append(SerializeJsonValue(elementValue, elementType, path + "[]", depth));
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static string SerializeEnumerableValue(IEnumerable enumerable, string path, int depth)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append('[');
|
||||
|
||||
bool first = true;
|
||||
foreach (object item in enumerable)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
first = false;
|
||||
Type itemType = item?.GetType() ?? typeof(object);
|
||||
builder.Append(SerializeJsonValue(item, itemType, path + "[]", depth));
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static bool TrySerializeLeafValue(object value, Type type, string path, bool jsonContext, out string serializedValue)
|
||||
{
|
||||
if (type == typeof(string))
|
||||
{
|
||||
serializedValue = jsonContext
|
||||
? QuoteJson((string)value)
|
||||
: (string)value ?? string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
serializedValue = ((bool)value) ? "true" : "false";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsNumericType(type))
|
||||
{
|
||||
serializedValue = Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
string enumValue = $"{Convert.ToUInt64(value, CultureInfo.InvariantCulture)}:{value}";
|
||||
serializedValue = jsonContext ? QuoteJson(enumValue) : enumValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type == typeof(ushort[]))
|
||||
{
|
||||
string text = SerializeUshortArray((ushort[])value, path);
|
||||
serializedValue = jsonContext && LooksLikeJson(text) ? text : (jsonContext ? QuoteJson(text) : text);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type == typeof(byte[]))
|
||||
{
|
||||
string text = SerializeByteArray((byte[])value, path);
|
||||
serializedValue = jsonContext && LooksLikeJson(text) ? text : (jsonContext ? QuoteJson(text) : text);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type == typeof(char))
|
||||
{
|
||||
string charValue = Convert.ToString(value, CultureInfo.InvariantCulture);
|
||||
serializedValue = jsonContext ? QuoteJson(charValue) : charValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
serializedValue = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string SerializeUshortArray(ushort[] values, string path)
|
||||
{
|
||||
if (values == null || values.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (IsTaskCharField(path))
|
||||
{
|
||||
return SerializeUnicodeRowArray(ReadUnicodeRows(values, TaskTemplConstants.TASK_AWARD_MAX_DISPLAY_CHAR_LEN));
|
||||
}
|
||||
|
||||
if (IsLikelyTextField(path))
|
||||
{
|
||||
return ByteToStringUtils.UshortArrayToUnicodeString(values);
|
||||
}
|
||||
|
||||
return SerializePrimitiveArray(values);
|
||||
}
|
||||
|
||||
private static string SerializeByteArray(byte[] values, string path)
|
||||
{
|
||||
if (values == null || values.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (IsByteTextField(path))
|
||||
{
|
||||
return SerializeUnicodeRowArray(ReadUnicodeRows(values, TaskTemplConstants.TASK_AWARD_MAX_DISPLAY_CHAR_LEN));
|
||||
}
|
||||
|
||||
if (IsLikelyTextField(path))
|
||||
{
|
||||
return DecodeByteArrayAsUnicode(values);
|
||||
}
|
||||
|
||||
return SerializePrimitiveArray(values);
|
||||
}
|
||||
|
||||
private static string SerializePrimitiveArray<T>(IEnumerable<T> values)
|
||||
{
|
||||
return "[" + string.Join(",", values.Select(SerializePrimitiveElement)) + "]";
|
||||
}
|
||||
|
||||
private static string SerializePrimitiveElement<T>(T value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
Type type = value.GetType();
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
return ((bool)(object)value) ? "true" : "false";
|
||||
}
|
||||
|
||||
return Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty;
|
||||
}
|
||||
|
||||
private static List<string> ReadUnicodeRows(ushort[] flatValues, int rowWidth)
|
||||
{
|
||||
var rows = new List<string>();
|
||||
if (flatValues == null || flatValues.Length == 0 || rowWidth <= 0)
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
int rowCount = flatValues.Length / rowWidth;
|
||||
for (int row = 0; row < rowCount; row++)
|
||||
{
|
||||
var buffer = new ushort[rowWidth];
|
||||
Array.Copy(flatValues, row * rowWidth, buffer, 0, rowWidth);
|
||||
rows.Add(ByteToStringUtils.UshortArrayToUnicodeString(buffer));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static List<string> ReadUnicodeRows(ushort[,] matrix)
|
||||
{
|
||||
var rows = new List<string>();
|
||||
if (matrix == null)
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
int rowCount = matrix.GetLength(0);
|
||||
int colCount = matrix.GetLength(1);
|
||||
|
||||
for (int row = 0; row < rowCount; row++)
|
||||
{
|
||||
var buffer = new ushort[colCount];
|
||||
for (int col = 0; col < colCount; col++)
|
||||
{
|
||||
buffer[col] = matrix[row, col];
|
||||
}
|
||||
|
||||
rows.Add(ByteToStringUtils.UshortArrayToUnicodeString(buffer));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static List<string> ReadUnicodeRows(byte[] flatValues, int rowWidth)
|
||||
{
|
||||
var rows = new List<string>();
|
||||
if (flatValues == null || flatValues.Length == 0 || rowWidth <= 0)
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
int rowCount = flatValues.Length / rowWidth;
|
||||
for (int row = 0; row < rowCount; row++)
|
||||
{
|
||||
var buffer = new byte[rowWidth];
|
||||
Array.Copy(flatValues, row * rowWidth, buffer, 0, rowWidth);
|
||||
rows.Add(DecodeByteArrayAsUnicode(buffer));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static List<string> ReadUnicodeRows(byte[,] matrix)
|
||||
{
|
||||
var rows = new List<string>();
|
||||
if (matrix == null)
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
int rowCount = matrix.GetLength(0);
|
||||
int colCount = matrix.GetLength(1);
|
||||
|
||||
for (int row = 0; row < rowCount; row++)
|
||||
{
|
||||
var buffer = new byte[colCount];
|
||||
for (int col = 0; col < colCount; col++)
|
||||
{
|
||||
buffer[col] = matrix[row, col];
|
||||
}
|
||||
|
||||
rows.Add(DecodeByteArrayAsUnicode(buffer));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static string DecodeByteArrayAsUnicode(byte[] values)
|
||||
{
|
||||
if (values == null || values.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var widened = new ushort[values.Length];
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
widened[i] = values[i];
|
||||
}
|
||||
|
||||
return ByteToStringUtils.UshortArrayToUnicodeString(widened);
|
||||
}
|
||||
|
||||
private static string SerializeUnicodeRowArray(IEnumerable<string> rows)
|
||||
{
|
||||
return "[" + string.Join(",", rows.Select(QuoteJson)) + "]";
|
||||
}
|
||||
|
||||
private static string QuoteJson(string value)
|
||||
{
|
||||
value ??= string.Empty;
|
||||
|
||||
var builder = new StringBuilder(value.Length + 8);
|
||||
builder.Append('"');
|
||||
foreach (char ch in value)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '\\':
|
||||
builder.Append("\\\\");
|
||||
break;
|
||||
case '"':
|
||||
builder.Append("\\\"");
|
||||
break;
|
||||
case '\n':
|
||||
builder.Append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.Append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
builder.Append("\\t");
|
||||
break;
|
||||
default:
|
||||
builder.Append(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append('"');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static bool LooksLikeJson(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return value[0] == '[' || value[0] == '{' || value == "null";
|
||||
}
|
||||
|
||||
private static bool IsTaskCharField(string path)
|
||||
{
|
||||
return path?.IndexOf("TaskChar", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private static bool IsByteTextField(string path)
|
||||
{
|
||||
return path?.IndexOf("pszExp", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private static bool IsLikelyTextField(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string lastSegment = path;
|
||||
int separatorIndex = path.LastIndexOf('.');
|
||||
if (separatorIndex >= 0 && separatorIndex < path.Length - 1)
|
||||
{
|
||||
lastSegment = path.Substring(separatorIndex + 1);
|
||||
}
|
||||
|
||||
return lastSegment.IndexOf("name", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
|| lastSegment.IndexOf("text", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
|| lastSegment.IndexOf("desc", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
|| lastSegment.IndexOf("sign", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
|| lastSegment.IndexOf("tribute", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
|| lastSegment.IndexOf("str", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
|| lastSegment.IndexOf("psz", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
|| lastSegment.IndexOf("wsz", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private static bool IsNumericType(Type type)
|
||||
{
|
||||
type = Nullable.GetUnderlyingType(type) ?? type;
|
||||
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Byte:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.Decimal:
|
||||
case TypeCode.Double:
|
||||
case TypeCode.Single:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<FieldInfo> GetOrderedPublicFields(Type type)
|
||||
{
|
||||
return type
|
||||
.GetFields(BindingFlags.Instance | BindingFlags.Public)
|
||||
.OrderBy(field => field.MetadataToken)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9da13fdecbdd94102ba2f741916ab5be
|
||||
@@ -161,6 +161,10 @@ namespace BrewMonster.UI
|
||||
}
|
||||
m_pDlgNPC.PopupNPCDialog(pTalk);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For what: This is for QuickBar (Skill + Action + Combo)
|
||||
/// </summary>
|
||||
public CECShortcutSet GetSCSByDlg(int indexPanel)
|
||||
{
|
||||
CECHostPlayer pHost = CECGameRun.Instance.GetHostPlayer();
|
||||
|
||||
@@ -57,10 +57,10 @@ namespace BrewMonster
|
||||
//setting.comboSkill[0].idSkill[0] = -2;
|
||||
/* setting.comboSkill[0].idSkill[1] = -1;
|
||||
setting.comboSkill[0].idSkill[0] = (short)(EC_Game.GetGameRun().GetHostPlayer().GetPositiveSkillByIndex(0).GetSkillID()) ;*/
|
||||
setting.comboSkill[0].idSkill[0] = -2;
|
||||
setting.comboSkill[0].idSkill[1] = -1;
|
||||
setting.comboSkill[0].idSkill[2] = (short)(EC_Game.GetGameRun().GetHostPlayer().GetPositiveSkillByIndex(0).GetSkillID());
|
||||
setting.comboSkill[0].idSkill[3] = -1;
|
||||
// setting.comboSkill[0].idSkill[0] = -2;
|
||||
// setting.comboSkill[0].idSkill[1] = -1;
|
||||
// setting.comboSkill[0].idSkill[2] = (short)(EC_Game.GetGameRun().GetHostPlayer().GetPositiveSkillByIndex(0).GetSkillID());
|
||||
// setting.comboSkill[0].idSkill[3] = -1;
|
||||
|
||||
/* for (i = 0; i < 1; i++)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
@@ -102,7 +103,7 @@ namespace BrewMonster
|
||||
UpdateAddressableAddressesPath("world", _modelPathPrefixToRemove, "");
|
||||
}
|
||||
|
||||
public static void UpdateAddressableAddressesPath(string groupName, string prefixToRemove, string subfix)
|
||||
public static async void UpdateAddressableAddressesPath(string groupName, string prefixToRemove, string subfix)
|
||||
{
|
||||
AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings;
|
||||
if (settings == null)
|
||||
@@ -112,6 +113,7 @@ namespace BrewMonster
|
||||
}
|
||||
|
||||
int updatedCount = 0;
|
||||
int count = 0;
|
||||
foreach (var group in settings.groups)
|
||||
{
|
||||
if (group == null) continue;
|
||||
@@ -120,6 +122,9 @@ namespace BrewMonster
|
||||
if (entries == null) continue;
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
count++;
|
||||
// show editor progress bar
|
||||
EditorUtility.DisplayProgressBar("Update Addressable Addresses Path", $"Updating {groupName} -- {count} / {entries.Count}", count / entries.Count);
|
||||
if (entry == null) continue;
|
||||
var address = entry.address;
|
||||
if (string.IsNullOrEmpty(address)) continue;
|
||||
@@ -154,9 +159,13 @@ namespace BrewMonster
|
||||
entry.SetAddress(newAddress);
|
||||
updatedCount++;
|
||||
}
|
||||
|
||||
await Task.Delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
if (updatedCount > 0)
|
||||
{
|
||||
EditorUtility.SetDirty(settings);
|
||||
|
||||
Reference in New Issue
Block a user