-
-
Save SChinchi/7dd6b321807e9166b65705e6aec96634 to your computer and use it in GitHub Desktop.
Label game object children as `currentIndex / total`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Awake of your mod | |
RoR2Application.onLoad += Thing; | |
private static bool IsNetworkBaseType(Type type) | |
{ | |
return type.BaseType != null && type.BaseType == typeof(UnityEngine.Networking.NetworkBehaviour); | |
} | |
private static bool HasValidBaseType(Type type) | |
{ | |
return type.BaseType != null | |
&& type.BaseType != typeof(UnityEngine.Object) | |
&& type.BaseType != typeof(UnityEngine.Component); | |
} | |
private static List<FieldInfo> GetOrderedFields(Type type) | |
{ | |
var results = type.GetFields((BindingFlags)(-1)).ToList(); | |
if (IsNetworkBaseType(type)) | |
{ | |
// Skip NetworkBehaviour because it's mostly noise | |
results.InsertRange(0, GetOrderedFields(type.BaseType.BaseType)); | |
} | |
else if (HasValidBaseType(type)) | |
{ | |
results.InsertRange(0, GetOrderedFields(type.BaseType)); | |
} | |
return results; | |
} | |
private static List<PropertyInfo> GetOrderedProperties(Type type) | |
{ | |
var results = type.GetProperties((BindingFlags)(-1)).ToList(); | |
if (IsNetworkBaseType(type)) | |
{ | |
// Skip NetworkBehaviour because it's mostly noise | |
results.InsertRange(0, GetOrderedProperties(type.BaseType.BaseType)); | |
} | |
else if (HasValidBaseType(type)) | |
{ | |
results.InsertRange(0, GetOrderedProperties(type.BaseType)); | |
} | |
return results; | |
} | |
public static void OutputComponents(StringBuilder sb, Component[] components, string delimi) | |
{ | |
foreach (Component component in components) | |
{ | |
OutputUnityObject(sb, component, delimi); | |
} | |
} | |
public static void OutputUnityObject(StringBuilder sb, UnityEngine.Object unityObject, string delimi) | |
{ | |
string ParsePoolEntries(DccsPool.PoolEntry[] entries) | |
{ | |
return "[" + string.Join(", ", entries.Select(x => $"({x.dccs.name}, {x.weight})")) + "]"; | |
} | |
string ParseConditionalPoolEntries(DccsPool.ConditionalPoolEntry[] entries) | |
{ | |
return "[" + string.Join(", ", entries.Select(x => $"({x.dccs.name}, {x.weight}, [{string.Join(", ", x.requiredExpansions.Select(x => x.name))}])")) + "]"; | |
} | |
sb.Append($"\n{delimi} "); | |
if (unityObject is RectTransform rectTransform) | |
{ | |
var transformOutput = $"RectTransform = p: {rectTransform.localPosition} r: {rectTransform.eulerAngles} s: {rectTransform.localScale}"; | |
transformOutput += $"\n{delimi}v anchored3D: {rectTransform.anchoredPosition3D} pivot: {rectTransform.pivot} offsetMin: {rectTransform.offsetMin} offsetMax: {rectTransform.offsetMax}"; | |
sb.AppendLine(transformOutput); | |
} | |
else if (unityObject is Transform transform) | |
{ | |
var transformOutput = $"Transform = p: {transform.localPosition} r: {transform.eulerAngles} s: {transform.localScale}"; | |
sb.AppendLine(transformOutput); | |
} | |
else if (unityObject is EntityStateConfiguration esc) | |
{ | |
sb.AppendLine("EntityStateConfiguration: " + esc.targetType.LookupType().Name); | |
if (!esc.serializedFieldsCollection.serializedFields.Any()) | |
{ | |
sb.AppendLine($"{delimi} <Empty>"); | |
} | |
else | |
{ | |
foreach (var field in esc.serializedFieldsCollection.serializedFields) | |
{ | |
try | |
{ | |
var fieldOutput = $"{delimi}v {field.fieldName} = {(field.fieldValue.objectValue ? field.fieldValue.objectValue : field.fieldValue.stringValue)}"; | |
sb.AppendLine(fieldOutput); | |
} | |
catch (Exception e) | |
{ | |
//R2API.LogError(e); | |
} | |
} | |
} | |
} | |
else | |
{ | |
Type type = unityObject.GetType(); | |
sb.AppendLine(type.FullName); | |
foreach (FieldInfo fieldInfo in GetOrderedFields(type)) | |
{ | |
if (fieldInfo.Name.Contains("k__BackingField")) | |
{ | |
continue; | |
} | |
try | |
{ | |
string fieldOutput; | |
if (unityObject is not RoR2.Navigation.NodeGraph && typeof(System.Collections.ICollection).IsAssignableFrom(fieldInfo.FieldType)) | |
{ //Nodegraphs are too meaninglessly large to expand,consider finding some method of visualisation if you wish to analyze them. | |
fieldOutput = $"{delimi}v {fieldInfo.Name} = "; | |
var collection = fieldInfo.GetValue(unityObject); | |
if (collection != null) | |
{ | |
fieldOutput = $"{delimi}v {fieldInfo.Name} = {{ "; | |
foreach (var value in collection as System.Collections.IEnumerable) | |
{ | |
if (value is DccsPool.Category dpCategory) | |
{ | |
fieldOutput += $"{{name: {dpCategory.name}, weight: {dpCategory.categoryWeight}, always: {ParsePoolEntries(dpCategory.alwaysIncluded)}, if: {ParseConditionalPoolEntries(dpCategory.includedIfConditionsMet)}, ifno: {ParsePoolEntries(dpCategory.includedIfNoConditionsMet)}}}"; | |
fieldOutput += "\n"; | |
} | |
else if (value is DirectorCardCategorySelection.Category category) | |
{ | |
fieldOutput += $"{{name: {category.name}, weight: {category.selectionWeight}, cards: [{string.Join(", ", category.cards.Select(card => $"({card.spawnCard.name}, {card.selectionWeight})"))}]}}"; | |
fieldOutput += "\n"; | |
} | |
else if (value is RangeFloat range) | |
{ | |
fieldOutput += $"{{min: {range.min}, max: {range.max}}}"; | |
fieldOutput += ", "; | |
} | |
else if (value is RoR2.Skills.SkillFamily.Variant variant) | |
{ | |
fieldOutput += $"{variant.skillDef}"; | |
fieldOutput += ", "; | |
} | |
else | |
{ | |
fieldOutput += value; | |
fieldOutput += ", "; | |
} | |
} | |
fieldOutput = fieldOutput.TrimEnd(' ', ',', '\n'); | |
fieldOutput += " }"; | |
} | |
} | |
else if (fieldInfo.FieldType == typeof(EntityStates.SerializableEntityStateType)) | |
{ | |
var stateType = (EntityStates.SerializableEntityStateType)fieldInfo.GetValue(unityObject); | |
fieldOutput = $"{delimi}v {fieldInfo.Name} = {stateType.stateType}"; | |
} | |
else if (fieldInfo.FieldType.IsSubclassOf(typeof(BaseConVar))) | |
{ | |
fieldOutput = $"{delimi}v {fieldInfo.Name} = {((BaseConVar)fieldInfo.GetValue(unityObject)).GetString()}"; | |
} | |
else | |
{ | |
fieldOutput = $"{delimi}v {fieldInfo.Name} = {fieldInfo.GetValue(unityObject)}"; | |
} | |
sb.AppendLine(fieldOutput); | |
} | |
catch (Exception e) | |
{ | |
//R2API.Logger.LogError(e); | |
} | |
} | |
foreach (PropertyInfo propertyInfo in GetOrderedProperties(type)) | |
{ | |
if (propertyInfo.Name == "renderingDisplaySize" && unityObject is Canvas) | |
{ //Crash-preventation | |
continue; | |
} | |
try | |
{ | |
if (propertyInfo.GetAccessors() != null && propertyInfo.GetAccessors().Length > 0) | |
{ | |
var fieldOutput = $"{delimi}v {propertyInfo.Name} = {propertyInfo.GetValue(unityObject)}"; | |
sb.AppendLine(fieldOutput); | |
} | |
} | |
catch (Exception e) | |
{ | |
if (e.InnerException != null) | |
{ | |
if (e.InnerException is NullReferenceException || e.InnerException is ArgumentNullException) | |
{ | |
// Lots of properties internally refer to a field that is instantiated on Awake | |
sb.AppendLine($"{delimi}v {propertyInfo.Name} = "); | |
continue; | |
} | |
else if (e.InnerException is NotImplementedException) | |
{ | |
// Ignore the error for some ScriptableObjects' name property | |
continue; | |
} | |
} | |
//R2API.Logger.LogError(e); | |
} | |
} | |
} | |
} | |
public static void GetChildren(StringBuilder sb, Transform transform, string delimi) | |
{ | |
for (var i = 0; i < transform.childCount; i++) | |
{ | |
GameObject gameObject = transform.GetChild(i).gameObject; | |
var childGameObjectHeader = $"\n{delimi}GameObject Child {i}/{transform.childCount}: {gameObject.name}"; | |
sb.AppendLine(childGameObjectHeader); | |
Component[] components = gameObject.GetComponents<Component>(); | |
OutputComponents(sb, components, delimi + ">"); | |
GetChildren(sb, transform.GetChild(i), delimi + ">"); | |
} | |
} | |
private static void Thing() | |
{ | |
UnityEngine.Object assetlazy = Addressables.LoadAssetAsync<UnityEngine.Object>("RoR2/Base/Huntress/Skins.Huntress.Alt1.asset").WaitForCompletion(); | |
R2API.Logger.LogWarning(assetlazy); | |
var i = 0; | |
foreach (UnityEngine.AddressableAssets.ResourceLocators.IResourceLocator item in Addressables.ResourceLocators) | |
{ | |
foreach (var key in item.Keys) | |
{ | |
try | |
{ | |
i++; | |
if (key.ToString().Contains("bundle")) | |
{ | |
continue; | |
} | |
if (!key.ToString().Contains(".")) | |
{ | |
} | |
else | |
{ | |
var digitCount = 0; | |
foreach (var c in key.ToString()) | |
{ | |
if (char.IsDigit(c)) | |
{ | |
digitCount++; | |
if (digitCount > 5) | |
{ | |
break; | |
} | |
} | |
} | |
if (digitCount > 5) | |
{ | |
continue; | |
} | |
R2API.Logger.LogWarning(i + " | " + key.ToString()); | |
UnityEngine.Object asset = Addressables.LoadAssetAsync<UnityEngine.Object>(key).WaitForCompletion(); | |
if (asset) | |
{ | |
var sb = new StringBuilder(); | |
sb.AppendLine("Key Path : " + key.ToString() + " | UnityObject Type : " + asset.GetType() + " | UnityObject Name : " + asset.name); | |
if (asset is GameObject go) | |
{ | |
Component[] components = go.GetComponents<Component>(); | |
OutputComponents(sb, components, ">"); | |
GetChildren(sb, go.transform, ">"); | |
DumpToFile(key, sb); | |
} | |
else if (asset is UnityEngine.Object unityObject) | |
{ | |
OutputUnityObject(sb, unityObject, ">"); | |
DumpToFile(key, sb); | |
} | |
} | |
} | |
} | |
catch (Exception e) | |
{ | |
R2API.Logger.LogError(e); | |
} | |
} | |
} | |
} | |
private static void DumpToFile(object key, StringBuilder sb) | |
{ | |
const string dumpFolder = @"folder_path"; | |
var relativeFilePathTxt = System.IO.Path.ChangeExtension(key.ToString(), ".txt"); | |
var fullFilePath = System.IO.Path.Combine(dumpFolder, relativeFilePathTxt); | |
var directoryPath = System.IO.Path.GetDirectoryName(fullFilePath); | |
Directory.CreateDirectory(directoryPath); | |
File.WriteAllText(fullFilePath, sb.ToString()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment