private static TextMeshProUGUI GetTMProText(ReplaceUnit updatedReference, TextInformation textInfo, GameObject root) { TextMeshProUGUI newText; GameObject textParent = FabulousExtensions .GetGameObjectAtAddress(root, updatedReference.TextAddress); Text oldText = textParent.GetComponent <Text>(); if (oldText != null) { UnityEngine.Object.DestroyImmediate(oldText, true); newText = textParent.AddComponent <TextMeshProUGUI>(); } else { newText = FabulousExtensions .GetGameObjectAtAddress(root, updatedReference.TextAddress) .GetComponent <TextMeshProUGUI>(); } if (newText == null) { Debug.LogError($"TMPro text component is null"); } return(newText); }
// // ─── TEXT COMPONENT REPLACEMENT ────────────────────────────────── // #region TEXT COMPONENT REPLACEMENT private void ReplaceTextComponent(ReplaceUnit updatedReference) { TextInformation textInfo = updatedReference.textInformation; // * Don't even think of performing below operations on previously saved prefabs loaded into the memory // * They are like lost souls that want to trap your innocent code // * Whatever you execute on them gets lost in a limbo and flushed down along the garbage collection // * If you want to edit a prefab, make sure you just loaded it and you work on a fresh, crunchy instance using (var editScope = new EditPrefabAssetScope(updatedReference.prefabPath)) { GameObject root = editScope.prefabRoot; TextMeshProUGUI tmProText = GetTMProText(updatedReference, textInfo, root); textInfo.StyleTMProText(tmProText, _fontAssetMap); if (updatedReference.isReferenced) { TMProAdapter tmProAdapter = GetTextAdapter(updatedReference, root, tmProText); if (tmProAdapter == null) { return; } AssignTMProReference(updatedReference, tmProAdapter, root); } } }
private static object GetFieldOwner(ReplaceUnit replaceUnit, GameObject root) { object fieldOwner = null; FieldInformation fieldInformation = replaceUnit.fieldInformation; Type monoType = fieldInformation.FieldOwnerType; Component mono = FabulousExtensions .GetGameObjectAtAddress(root, replaceUnit.MonoAddress) .GetComponent(monoType); if (mono == null) { throw new NullReferenceException($"Failed to find mono {monoType} for field {fieldInformation.FieldName} and type {fieldInformation.FieldType} by its address for prefab: {root} at path {replaceUnit.prefabPath} and address {string.Join(",", replaceUnit.MonoAddress.ToArray())}"); } if (fieldInformation.FieldType.HasOneOfTheFlags(FieldType.Nested | FieldType.External)) { ExternallyOwnedFieldInformation eofi = fieldInformation.GetFieldInformationParamter <ExternallyOwnedFieldInformation>(); FieldInfo externalObjectFieldInfo = monoType.GetField(eofi.ExternalOwnerFieldName, ReferenceFinder.GENEROUS_NONSTATIC_FIELD_SEARCH_FLAGS); if (eofi.fieldInformation.FieldType.HasOneOfTheFlags(FieldType.Arrayed | FieldType.Listed)) { var efi = eofi.fieldInformation.GetFieldInformationParamter <EnumerableFieldInformation>(); IEnumerable enumberableOwner = (IEnumerable)externalObjectFieldInfo.GetValue(mono); int index = 0; foreach (var item in enumberableOwner) { if (index == efi.index) { fieldOwner = item; } index++; } } else { fieldOwner = externalObjectFieldInfo.GetValue(mono); } } else { fieldOwner = mono; } return(fieldOwner); }
// // ─── SCRIPT REPLACEMENT ────────────────────────────────────────── // #region SCRIPT REPLACEMENT private void GatherFieldsToUpdate(ReplaceUnit reference) { if (reference.isReferenced) { Type declaringType = reference.fieldInformation.FieldDeclaringType; FieldInformation fieldInformation = reference.fieldInformation; if (!_fieldsToUpdateByFieldOwnerType.ContainsKey(declaringType)) { _fieldsToUpdateByFieldOwnerType[declaringType] = new List <FieldInformation>(); } _fieldsToUpdateByFieldOwnerType[declaringType].Add(fieldInformation); } }
private void SaveTextReferences(string sourcePrefabPath, GameObject prefabParent, Text textComponent) { //* 1. Separately add each text component as unreferenced version of replace unit // ? This is quite a dirty trick, I'm sorry, more about it in ReplaceUnit ReplaceUnit unreferencedTextComponent = new ReplaceUnit(prefabParent, textComponent); UpdatedReferenceAddressBook[sourcePrefabPath].Add(unreferencedTextComponent); //* 2. Add all referenced versions of replace unit var updatedReferences = CheckTextAgainstFoundMonobehaviours(textComponent, prefabParent); foreach (ReplaceUnit updatedReference in updatedReferences) { UpdatedReferenceAddressBook[sourcePrefabPath].Add(updatedReference); } }
private static void SetAdapterAndTMProFieldValues(TMProAdapter tmProAdapter, ReplaceUnit replaceUnit, object fieldOwner, FieldInfo adapterFieldInfo, FieldInfo tmProFieldInfo) { FieldInformation fieldInformation = replaceUnit.fieldInformation; FieldType fieldType = fieldInformation.FieldType; if (fieldType.HasOneOfTheFlags(FieldType.Listed | FieldType.Arrayed)) { var adpaterField = adapterFieldInfo.GetValue(fieldOwner); var tmProField = tmProFieldInfo.GetValue(fieldOwner); EnumerableFieldInformation efi = fieldInformation.GetFieldInformationParamter <EnumerableFieldInformation>(); if (adpaterField != null && tmProField != null) { if (adpaterField is List <TMProAdapter> adapterList) { adapterList[efi.index] = tmProAdapter; (tmProField as List <TextMeshProUGUI>).Add(tmProAdapter.TMProText); } else if (adpaterField is TMProAdapter[] adapterArray) { adapterArray[efi.index] = tmProAdapter; //* We don't need to do the same with above adapterArray since it already has the correct size as it //* replaced the old array of text components TextMeshProUGUI[] tmproFieldArray = tmProField as TextMeshProUGUI[]; TextMeshProUGUI[] newTMProFieldArray = new TextMeshProUGUI[tmproFieldArray.Length + 1]; tmproFieldArray.CopyTo(newTMProFieldArray, 0); newTMProFieldArray[tmproFieldArray.Length] = tmProAdapter.TMProText; tmProFieldInfo.SetValue(fieldOwner, newTMProFieldArray); } else { Debug.LogError($"Huh? Thats weird"); } } else { Debug.LogError($"Either adapter field: {adpaterField} or tmpro field: {tmProField} is null."); } } else { adapterFieldInfo.SetValue(fieldOwner, tmProAdapter); tmProFieldInfo.SetValue(fieldOwner, tmProAdapter.TMProText); } }
private static TMProAdapter GetOrCreateAdapter(ReplaceUnit updatedReference, TextMeshProUGUI newTextComponent, GameObject adaptersParent) { TMProAdapter adapter; string fieldName = GetAdapterGameObjectName(updatedReference.fieldInformation); string adapterName = String.Format(ADAPTER_GAMEOBJECT_NAME, fieldName); Transform adapterTransform = adaptersParent.transform.Find(adapterName); if (adapterTransform == null) { adapter = CreateNewAdapter(newTextComponent, adaptersParent, fieldName, adapterName); } else { adapter = adaptersParent.GetComponent <TMProAdapterParent>()[fieldName]; } return(adapter); }
private static TMProAdapter GetTextAdapter(ReplaceUnit updatedReference, GameObject root, TextMeshProUGUI newTextComponent) { TMProAdapter adapter = null; try { string fieldOwnerName = updatedReference.fieldInformation.FieldOwnerType.Name; string adapterParentName = String.Format(ADAPTER_PARENT_NAME, fieldOwnerName); GameObject adaptersParent = GetAdaptersParent(root, adapterParentName); adapter = GetOrCreateAdapter(updatedReference, newTextComponent, adaptersParent); } catch (Exception ex) { Debug.LogError($"Exception occured for {updatedReference.rootPrefab} at path {updatedReference.prefabPath}, message: {ex.Message}"); } return(adapter); }
private void AssignTMProReference(ReplaceUnit reference, TMProAdapter tmProAdapter, GameObject root) { try { if (tmProAdapter == null) { Debug.LogError($"Adapter is null for {reference.prefabPath} field {reference.fieldInformation.FieldName}"); } object fieldOwner = GetFieldOwner(reference, root); GetAdapterAndTmproFieldInfos( reference.fieldInformation, out FieldInfo adapterFieldInfo, out FieldInfo tmProFieldInfo); SetAdapterAndTMProFieldValues(tmProAdapter, reference, fieldOwner, adapterFieldInfo, tmProFieldInfo); } catch (Exception ex) { Debug.LogError($"Exception occured for {reference.rootPrefab} at path {reference.prefabPath}, message: {ex.Message}"); } }