У ничего не подозревающей игры один из типов, наследников MonoBehaviour переезжает в другую сборку. В оригинальной остаётся ссылка, с пометкой ExportedType. Этот грязный хак используется для её модификации.
Начинается процесс загрузки скриптов. Дело доходит до нашего типа.
Помимо родительских полей он содержит в себе:
public string GroupName = string.Empty;
public HelpDetail2 Help2;
Первое поле успешно десериализуется. Всё, на этом процесс обрывается.
В логах видим:
A script behaviour (probably ButtonGroupState?) has a different serialization layout when loading. (Read 64 bytes but expected 68 bytes)
Did you #ifdef UNITY_EDITOR a section of your serialized properties in any of your scripts?
Тип HelpTetail2 помечен аттрибутом [Serializable], на который движок плюет с высокой колокольни. Object is null.
Стоит отнаследовать его от UnityEngine.Object или MonoBehaviour - случается чудо, объект десериализуется! Правда, не слишком успешно, что логично, но тем не менее.
Вопрос - как этот демонский движок определяет - какие объекты, помеченные Serializable, ему нужно десериализовать, а какие нет?
Схожий вопрос касается методов Awake, OnLoad и т.д. - движок не будет вызывать те методы, которые отсутствовали в сборке в момент компиляции.
Где хранится эта информация? Кого нужно отревёрсить и распотрошить?
---Update:
Пока удалось найти только интефейс ISerializationCallbackReceiver. Он предоставляет два метода - BeforeSerialization и AfterDeserialization. Не вижу явных вызовов. Возможно, дёргается из нативного кода? К сожалению, не позволяет переопределить механизмы десериализации и не предоставляет доступа потоку данных. Сам вызов летит из нативного кода:
at System.Environment.get_StackTrace()
at ButtonGroupState.OnAfterDeserialize()
---Конец стека---
---Update 2:
Нашёл такой код:
Синтаксис:
Используется csharp
internal static class ClassLibraryInitializer
{
private static void Init()
{
UnityLogWriter.Init();
if (!Application.platform.ToString().Contains("WebPlayer"))
return;
BinaryFormatter.set_DefaultSurrogateSelector((ISurrogateSelector) new UnitySurrogateSelector());
}
}
{
private static void Init()
{
UnityLogWriter.Init();
if (!Application.platform.ToString().Contains("WebPlayer"))
return;
BinaryFormatter.set_DefaultSurrogateSelector((ISurrogateSelector) new UnitySurrogateSelector());
}
}
Смущает то, что справедливо только для WebPlayer'а.
Эх, не хотелось лезть в UnityEngine/mscorlib.
---Update 3:
Нет, увы, если бы всё было так просто. Подмена форматтера ни к чему не привела - он просто не вызывается.