forked from allista/AT_Utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSerializableFiledsPartModule.cs
136 lines (129 loc) · 4.06 KB
/
SerializableFiledsPartModule.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SerializableFiledsPartModule.cs
//
// Author:
// Allis Tauri <allista@gmail.com>
//
// Copyright (c) 2016 Allis Tauri
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using KSP.IO;
using System.Text;
namespace AT_Utils
{
public abstract class SerializableFiledsPartModule : PartModule, ISerializationCallbackReceiver
{
static readonly string cnode_name = typeof(IConfigNode).Name;
List<FieldInfo> _serializable_fields;
List<FieldInfo> serializable_fields
{
get
{
if(_serializable_fields == null)
{
_serializable_fields = new List<FieldInfo>();
var fields = GetType().GetFields(BindingFlags.FlattenHierarchy|BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Instance);
for(int i = 0, len = fields.Length; i < len; i++)
{
var fi = fields[i];
if(fi.GetCustomAttributes(typeof(SerializeField), true).Length == 0) continue;
if(typeof(ConfigNode).IsAssignableFrom(fi.FieldType) ||
fi.FieldType.GetInterface(cnode_name) != null ||
fi.FieldType.GetCustomAttributes(typeof(SerializableAttribute), true).Length > 0)
_serializable_fields.Add(fi);
}
// if(_serializable_fields.Count > 0) //debug
// Utils.Log("{}.serializable_fields: {}", GetType().Name, _serializable_fields);
}
return _serializable_fields;
}
}
[SerializeField] byte[] _serialized_fields;
[SerializeField] List<int> _offsets = new List<int>();
[SerializeField] List<int> _fields = new List<int>();
public virtual void OnBeforeSerialize()
{
_serialized_fields = null;
_offsets.Clear(); _fields.Clear();
var count = serializable_fields.Count;
if(count == 0) return;
var offset = 0;
var fields_data = new List<byte[]>(count);
for(int i = 0; i < count; i++)
{
var fi = serializable_fields[i];
var val = fi.GetValue(this);
// Utils.Log("{}.{}.value = {}", this, fi.Name, val);//debug
if(val != null)
{
byte[] data = null;
if(val is ConfigNode)
data = Encoding.UTF8.GetBytes(((ConfigNode)val).ToString());
else if(val is IConfigNode)
{
var node = new ConfigNode(fi.Name);
((IConfigNode)val).Save(node);
data = Encoding.UTF8.GetBytes(node.ToString());
}
else data = IOUtils.SerializeToBinary(val);
if(data != null && data.Length > 0)
{
fields_data.Add(data);
offset += data.Length;
_offsets.Add(offset);
_fields.Add(i);
}
}
}
if(fields_data.Count == 0) return;
if(fields_data.Count == 1) _serialized_fields = fields_data[0];
else
{
var start = 0;
_serialized_fields = new byte[offset];
foreach(var data in fields_data)
{
Array.Copy(data, 0, _serialized_fields, start, data.Length);
start += data.Length;
}
}
}
public virtual void OnAfterDeserialize()
{
if(_serialized_fields == null || _serialized_fields.Length == 0) return;
// Utils.Log("_fields: {}\n_offsets: {}", _fields, _offsets);//debug
var start = 0;
for(int i = 0, count = _fields.Count; i < count; i++)
{
var offset = _offsets[i];
var len = offset-start;
var data = new byte[len];
var fi = serializable_fields[_fields[i]];
Array.Copy(_serialized_fields, start, data, 0, len);
if(typeof(ConfigNode).IsAssignableFrom(fi.FieldType))
fi.SetValue(this, ConfigNode.Parse(Encoding.UTF8.GetString(data)).nodes[0]);
else if(fi.FieldType.GetInterface(cnode_name) != null)
{
var node = ConfigNode.Parse(Encoding.UTF8.GetString(data)).nodes[0];
// Utils.Log("{}.{}.node: {}", this, fi.Name, node);//debug
var f = fi.GetValue(this) as IConfigNode;
if(f == null)
{
var constructor = fi.FieldType.GetConstructor(Type.EmptyTypes);
if(constructor != null)
f = constructor.Invoke(null) as IConfigNode;
}
if(f != null)
{
f.Load(node);
fi.SetValue(this, f);
}
}
else fi.SetValue(this, IOUtils.DeserializeFromBinary(data));
// Utils.Log("{}.{}.value = {}", this, fi.Name, fi.GetValue(this));//debug
start = offset;
}
}
}
}