Contents

UE4 TextAssetFormat

需求:常常多人修改一个资源如何做到不锁资源多人协作。

  1. 方向1. 能够进行类似文本不同资源的diff合并
  2. 方向2,将资源解耦,将常常需要修改的部分单独作为一个资源。

方案一:使用TextAssetFormat方案

  1. 我们在 Editor preference 中搜索 Text Asset Format​。可打开配置

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527155331.png

  1. 然后在资产右键​ Asset Action 可以 export to text format 保存成 utxt 格式的文件。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527155401.png

  1. 在资产被引用时,如果对应 uasset 后缀名不存在,则会去搜索 utxt 后缀名并加载。如果不被引用是不会加载的。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527155523.png

我们一个Uasset在内存中是一个UPackage的数据结构,其结构如上。对于大部分数据来讲。其明文存储的东西其实是它的File Summary和它的结构数据。但是所有走序列化的数据都是在一个数据块中,例如如下一个Montage:

  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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
{
	"Exports": {
		"AM_Dunan_ComboXFinish02:ActAnimNotify_AutoTrace_2": {
			"__Class": "Class /Script/X21.ActAnimNotify_AutoTrace",
			"__Outer": "AnimMontage /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02",
			"__ObjectFlags": 8,
			"__bNotAlwaysLoadedForEditorGame": true,
			"__Value": {
				"Properties": {}
			}
		},
		"AM_Dunan_ComboXFinish02:ActAnimNotify_ComponentFrameFire_0": {
			"__Class": "Class /Script/X21.ActAnimNotify_ComponentFrameFire",
			"__Outer": "AnimMontage /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02",
			"__ObjectFlags": 8,
			"__bNotAlwaysLoadedForEditorGame": true,
			"__Value": {
				"Properties": {
					"BoneName": {
						"__Type": "NameProperty",
						"__Value": "RightWeapon_socket"
					},
					"TraceActor": {
						"__Type": "ObjectProperty",
						"__Value": "Object:/Script/Engine.BlueprintGeneratedClass /Game/X21/Weapon/TestWeapons/DunanSword/BP_TraceActor_Dunan.BP_TraceActor_Dunan_C"
					},
					"EffectGroupIdxs": {
						"__Type": "ArrayProperty",
						"__InnerType": "IntProperty",
						"__Value": [
							0
						]
					},
					"EffectCompIdxs": {
						"__Type": "ArrayProperty",
						"__InnerType": "IntProperty",
						"__Value": [
							1
						]
					}
				}
			}
		},
		"AM_Dunan_ComboXFinish02": {
			"__Class": "Class /Script/Engine.AnimMontage",
			"__ObjectFlags": 11,
			"__bNotAlwaysLoadedForEditorGame": true,
			"__bIsAsset": true,
			"__Value": {
				"BaseClassAutoGen": {
					"Data": {
						"Digest": "2d478bb32399147bf00315965feee61b69992d7e",
						"Base64": [
							"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"
						]
					},
					"Objects": [
						"Object:/Script/Engine.AnimMontage /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02",
						"Object:/Script/Engine.AnimSequence /Game/X21/Char/Dunan/Animation/AM_pc01_01a_w_attack_finish03.AM_pc01_01a_w_attack_finish03",
						null,
						"Object:/Script/X21.ActAnimNotify_AutoTrace /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02:ActAnimNotify_AutoTrace_2",
						"Object:/Script/X21.ActAnimNotify_ComponentFrameFire /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02:ActAnimNotify_ComponentFrameFire_0",
						"Object:/Script/Engine.AnimNotify_PlayParticleEffect /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02:AnimNotify_PlayParticleEffect_0",
						"Object:/Script/Engine.Skeleton /Game/X21/Char/Dunan/SK_Dunan.SK_Dunan",
						"Object:/Script/UnrealEd.SceneThumbnailInfo /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02:SceneThumbnailInfo_0"
					],
					"Names": [
						"CompositeSections",
						"ArrayProperty",
						"StructProperty",
						"CompositeSection",
						"SectionName",
						"NameProperty",
						"Default",
						"NextSectionName",
						"None",
						"MetaData",
						"ObjectProperty",
						"LinkedMontage",
						"SlotIndex",
						"IntProperty",
						"SegmentIndex",
						"LinkMethod",
						"ByteProperty",
						"EAnimLinkMethod",
						"EAnimLinkMethod::Absolute",
						"CachedLinkMethod",
						"SegmentBeginTime",
						"FloatProperty",
						"SegmentLength",
						"LinkValue",
						"LinkedSequence",
						"SlotAnimTracks",
						"SlotAnimationTrack",
						"SlotName",
						"FullAttack",
						"AnimTrack",
						"AnimSegments",
						"AnimSegment",
						"AnimReference",
						"StartPos",
						"AnimStartTime",
						"AnimEndTime",
						"AnimPlayRate",
						"LoopingCount",
						"BranchingPointMarkers",
						"BranchingPointMarker",
						"NotifyIndex",
						"TriggerTime",
						"NotifyEventType",
						"EAnimNotifyEventType",
						"EAnimNotifyEventType::Begin",
						"EAnimNotifyEventType::End",
						"BranchingPointStateNotifyIndices",
						"Notifies",
						"AnimNotifyEvent",
						"TriggerTimeOffset",
						"EndTriggerTimeOffset",
						"TriggerWeightThreshold",
						"NotifyName",
						"ActAutoTrace",
						"Notify",
						"NotifyStateClass",
						"Duration",
						"EndLink",
						"AnimLinkableElement",
						"bConvertedFromBranchingPoint",
						"BoolProperty",
						"MontageTickType",
						"EMontageNotifyTickType",
						"EMontageNotifyTickType::Queued",
						"NotifyTriggerChance",
						"NotifyFilterType",
						"ENotifyFilterType",
						"ENotifyFilterType::NoFiltering",
						"NotifyFilterLOD",
						"bTriggerOnDedicatedServer",
						"bTriggerOnFollower",
						"NotifyColor",
						"Color",
						"Guid",
						"TrackIndex",
						"ActComponentFrameFire",
						"PlayParticleEffect",
						"SequenceLength",
						"AnimNotifyTracks",
						"AnimNotifyTrack",
						"TrackName",
						"1",
						"TrackColor",
						"LinearColor",
						"VFX",
						"2",
						"Skeleton",
						"ThumbnailInfo"
					]
				}
			}
		},
		"AM_Dunan_ComboXFinish02:AnimNotify_PlayParticleEffect_0": {
			"__Class": "Class /Script/Engine.AnimNotify_PlayParticleEffect",
			"__Outer": "AnimMontage /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02",
			"__ObjectFlags": 8,
			"__bNotAlwaysLoadedForEditorGame": true,
			"__Value": {
				"Properties": {
					"PSTemplate": {
						"__Type": "ObjectProperty",
						"__Value": "Object:/Script/Engine.ParticleSystem /Game/X21/Effect/Temp/Common/P_Com/PS_BD_SwordTrack_04.PS_BD_SwordTrack_04"
					},
					"SocketName": {
						"__Type": "NameProperty",
						"__Value": "fx_Combox_Finish_02"
					}
				}
			}
		},
		"PackageMetaData": {
			"__Class": "Class /Script/CoreUObject.MetaData",
			"__ObjectFlags": 2,
			"__bNotForClient": true,
			"__bNotForServer": true,
			"__Value": {
				"Properties": {},
				"ObjectMetaDataMap": [],
				"RootMetaDataMap": [
					[
						"PackageLocalizationNamespace",
						"6D0324674F6561EB03570CA4927073F3"
					]
				]
			}
		},
		"AM_Dunan_ComboXFinish02:SceneThumbnailInfo_0": {
			"__Class": "Class /Script/UnrealEd.SceneThumbnailInfo",
			"__Outer": "AnimMontage /Game/X21/Char/Dunan/Montage/AM_Dunan_ComboXFinish02.AM_Dunan_ComboXFinish02",
			"__ObjectFlags": 8,
			"__bNotAlwaysLoadedForEditorGame": true,
			"__Value": {
				"BaseClassAutoGen": {
					"Data": "Base64:AAAAAAAAAAA=",
					"Names": [
						"None"
					]
				}
			}
		}
	},
	"Summary": {
		"Tag": -1641380927,
		"LegacyFileVersion": -7,
		"LegacyUE3Version": 864,
		"FileVersionUE4": 518,
		"FileVersionLicenseeUE4": 0,
		"CustomVersions": [
			{
				"Key": "29E575DDE0A346279D10D276232CDCEA",
				"Version": 17
			},
			{
				"Key": "601D1886AC644F84AA16D3DE0DEAC7D6",
				"Version": 31
			},
			{
				"Key": "AF43A65D7FD3494798733E8ED9C1BB05",
				"Version": 7
			},
			{
				"Key": "CFFC743F43B04480939114DF171D2073",
				"Version": 37
			},
			{
				"Key": "E4B068EDF49442E9A231DA0B2E46BB41",
				"Version": 38
			}
		],
		"TotalHeaderSize": 0,
		"FolderName": "None",
		"PackageFlags": 0,
		"NameCount": 0,
		"NameOffset": 0,
		"LocalizationId": "6D0324674F6561EB03570CA4927073F3",
		"GatherableTextDataCount": 0,
		"GatherableTextDataOffset": 0,
		"ExportCount": 6,
		"ExportOffset": 0,
		"ImportCount": 18,
		"ImportOffset": 0,
		"DependsOffset": 0,
		"SoftPackageReferencesCount": 0,
		"SoftPackageReferencesOffset": 0,
		"SearchableNamesOffset": 0,
		"ThumbnailTableOffset": 0,
		"Guid": "6678B9B649FE690D9B0882AF68E7EE66",
		"PersistentGuid": "00000000000000000000000000000000",
		"OwnerPersistentGuid": "00000000000000000000000000000000",
		"GenerationCount": 1,
		"Generations": [
			{
				"ExportCount": 6,
				"NameCount": 0
			}
		],
		"SavedByEngineVersion": "0.0.0-0",
		"CompatibleWithEngineVersion": "0.0.0-0",
		"CompressionFlags": 0,
		"CompressedChunks": [],
		"PackageSource": 401305165,
		"AdditionalPackagesToCook": [],
		"AssetRegistryDataOffset": 0,
		"BulkDataStartOffset": 0,
		"WorldTileInfoDataOffset": 0,
		"ChunkIDs": [],
		"PreloadDependencyCount": -1,
		"PreloadDependencyOffset": 0
	}
}

我们删减去缩略图的数据可以看出,其所有的数据都在Exports里面,也就是它包含的所有的UObject。而Object里面的数据,其实是通过序列化进行的编码格式,我们在文本中是没有办法合并的。下图是我们只改变了norify 的时间轴的时间。所引发的结果。因此使用这种方案无法进行合并。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527160212.png

结论:序列化数据的存储不是明文的,结构和数量是无法确定的。无法完成需求。

方案二:将常修改数据资源化

所有我们想第二个方案,将常常需要修改的数据资源化到另一个Package中。例如我们的AnimNotify_PlayParticleEffect,其表示为我们在蒙太奇中播放一个特效,外部特效的修改其实并不会影响这个Package的数据。也就是美术在修改特效本身的表现时并不会影响到montage。

因此,如果我们把常用的数据分出去,如果有人修改AnimNotify_PlayParticleEffect的内容,将不会影响到montage资源。

但是这会有很多问题。

  1. 涉及到Montage本身的数据(存储在montage身上,而不是它的成员变量Object身上的数据)是无法修改的。例如AnimNotify时间触发点这个数据其实是存储在montage本身,我们如果想要做到这个分离的话需要做一个例如MontageSetting的资源。
  2. 会极大的增多Packae的资源数量,零散内存的使用
  3. 操作上其实并不简单,会更加的繁琐。
  4. 无法复用方案,每个数据必须精心筛选和单独制作。
  5. 老资源的兼容问题,序列化的数据常常修改会有资源报废的风险。

结论:坑太多,无法完成需求。

方案三:使用高效的编辑器资源管理方案

如同堡垒之夜这么庞大人数,多地域多时区的大型协作类项目其实也是用Lock 的方案。

我们的痛点其实并不是lock本身,而是我们对Lock的不及时,或者是知道别人是否lock不及时。

也就是说,你在修改这个资源的时候,不知道这个资源是否被lock了或者是被谁lock了。

而UE4内置的编辑器资源版本管理工具就可以解决这个问题!

我们只需要在编辑器中进行配置: https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527162832.png

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527163037.png

填充好信息 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527163155.png

解决的问题

我们可以在编辑器中选择设置

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527163521.png

  1. 资源修改时是否自动锁(Automatically Checkout on Asset Modification)选中后,它将自动迁出任何已修改的资源。也就是说,如果我们在编辑器中修改了这个资源,我们将可以选择是否需要锁住。
  2. 包修改锁提示(Prompt for Checkout on Package Modification)选中后,当您对源码管理包进行更改时,将出现一条提示,询问您是否希望(锁定)该资源。

当你配置好后,你可以在编辑器中看到资源的状态 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527163429.png

如果有人锁了,你将看到是谁锁的,那么你就无法修改这个资源了,这个时候你是可以看到是谁锁的,你可以在popo上通知这个人。非常的方便!

https://docs.unrealengine.com/4.26/zh-CN/Basics/UI/SourceControl/

案例

现在我修改保存一个蓝图。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527164439.png

它会在保存的时候提示是否Check out,如果我们选择Check out,我们将会锁住这个资源。

https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527164552.png

别人就没有办法修改了 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527164610.png

所有人的编辑器中都会显示是我锁住的。 https://papalqiblog.oss-cn-beijing.aliyuncs.com/blog/picture20210527164629.png

当我们SVN提交的时候,我们会解锁就可以了。如果我们需要其他的功能也可以根据这个再开发