-
Notifications
You must be signed in to change notification settings - Fork 7
/
base.util.registry.bmx
780 lines (599 loc) · 21.3 KB
/
base.util.registry.bmx
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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
Rem
====================================================================
Class managing assets, configs, ...
====================================================================
The registry Type is a Getter/Setter managing multiple assets and
resources of an app.
There exist helper functions to allow lazy/threaded loading of
assets.
This file includes loaders only requiring the same "imports"
as the Registry/XML-Loader itself.
Recognized types:
-> <data> OR <myname type="data">
-> <file> OR <myname type="file">
====================================================================
If not otherwise stated, the following code is available under the
following licence:
LICENCE: zlib/libpng
Copyright (C) 2002-2019 Ronny Otto, digidea.de
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held liable
for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it
and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
====================================================================
EndRem
SuperStrict
Import BRL.Map
?Threaded
Import Brl.threads
?
Import "base.util.data.bmx"
Import "base.util.event.bmx"
Import "base.util.xmlhelper.bmx"
Import "base.util.logger.bmx"
Type TRegistry
'holding the data in the registry
Field data:TMap = CreateMap()
'holding default objects in case something does not exist
Field defaults:TMap = CreateMap()
?Threaded
Field _dataMutex:TMutex = CreateMutex()
?
Global _instance:TRegistry
Function GetInstance:TRegistry()
If Not _instance Then _instance = New TRegistry
Return _instance
End Function
Method Init:TRegistry()
data.Clear()
End Method
'set a data with the given key
Method Set(key:Object, obj:Object)
?Threaded
LockMutex(_dataMutex)
?
Local ls:TLowerString = TLowerString(key)
If Not ls Then ls = TLowerString.Create(String(key))
data.insert(ls, obj)
?Threaded
UnlockMutex(_dataMutex)
?
End Method
'set a default object for a data type
Method GetDefault:Object(key:Object)
Local ls:TLowerString = TLowerString(key)
If Not ls Then ls = TLowerString.Create(String(key))
Return defaults.ValueForKey(ls)
End Method
'set a default object for a data type
Method SetDefault(key:Object, obj:Object)
?Threaded
LockMutex(_dataMutex)
?
Local ls:TLowerString = TLowerString(key)
If Not ls Then ls = TLowerString.Create(String(key))
defaults.insert(ls, obj)
?Threaded
UnlockMutex(_dataMutex)
?
End Method
Method Get:Object(key:Object, defaultObject:Object=Null, defaultType:Object=Null)
Local ls:TLowerString = TLowerString(key)
If Not ls Then ls = TLowerString.Create(String(key))
Local res:Object = data.ValueForKey(ls)
'try to get the default object
If Not res
If TLowerString(defaultObject)
res = data.ValueForKey(TLowerString(defaultObject))
ElseIf String(defaultObject)
res = data.ValueForKey(TLowerString.Create(String(defaultObject)) )
Else
res = defaultObject
EndIf
EndIf
'still no res (none by key, no defaultObject)
'try to find defaultType
If Not res And defaultType
Local defaultTypeLS:TLowerString = TLowerString(defaultType)
If Not defaultTypeLS Then defaultTypeLS = TLowerString.Create(String(defaultType))
'does a default object exist in defaults list?
res = defaults.ValueForKey(defaultTypeLS)
If res Then Return res
EndIf
Return res
End Method
Method ToString:String()
Local elementCount:Int = 0
For Local k:String = EachIn data.Keys()
elementCount :+ 1
Next
Return "TRegistry: " + elementCount + " data elements."
End Method
End Type
'===== CONVENIENCE REGISTRY ACCESSORS =====
Function GetRegistry:TRegistry()
Return TRegistry.GetInstance()
End Function
Function GetDataFromRegistry:TData(key:Object, defaultNameOrObject:Object = Null)
Return TData( GetRegistry().Get(key, defaultNameOrObject, "data") )
End Function
Function GetStringFromRegistry:String(key:Object, defaultNameOrObject:Object = Null)
Return String( GetRegistry().Get(key, defaultNameOrObject, "string") )
End Function
'==== LOADER TO FILL REGISTRY FROM FILES ====
Type TRegistryLoader
'base url prepended to all given paths in a config-file
Field baseURI:String = ""
Field xmlHelper:TXmlHelper
'holding descendants of TRegistryResourceLoader which handle
'certain types.
'map-key is TYPENAME in uppercase
Global resourceLoaders:TMap = CreateMap()
Global _defaultsCreated:Int = False
Global eventKey_onLoadResourceFromXML:TEventKey = EventManager.GetEventKey("RegistryLoader.onLoadResourceFromXML", True)
Global eventKey_onLoadXmlFromFinished:TEventKey = EventManager.GetEventKey("RegistryLoader.onLoadXmlFromFinished", True)
Global eventKey_onBeginLoadResource:TEventKey = GetEventKey("RegistryLoader.onBeginLoadResource", True)
Global eventKey_onLoadresource:TEventKey = GetEventKey("RegistryLoader.onLoadResource", True)
Method New()
If Not _defaultsCreated
'give loaders a chance to create default resources
TRegistryLoader.CreateRegistryDefaults()
_defaultsCreated = True
EndIf
End Method
Function RegisterResourceLoader:Int(resourceLoader:TRegistryBaseLoader, resourceNames:String="")
If resourceNames = "" Then resourceNames = resourceLoader.resourceNames
For Local resourceName:String = EachIn resourceNames.Split("|")
resourceLoaders.insert(resourceName.ToUpper(), resourceLoader)
Next
End Function
Function CreateRegistryDefaults:Int()
'give loaders a chance to create a default resources
'but: call in order of creation, not sorted by name
'so dependencies are solved
Local resList:TList = CreateList()
For Local loader:TRegistryBaseLoader = EachIn resourceLoaders.Values()
resList.AddLast(loader)
Next
SortList(resList)
For Local loader:TRegistryBaseLoader = EachIn resList
loader.CreateDefaultResource()
Next
End Function
Function GetResourceLoader:TRegistryBaseLoader(resourceName:String)
Return TRegistryBaseLoader(resourceLoaders.ValueForKey(resourceName.ToUpper()))
End Function
Method SetBaseURI:TRegistryLoader(baseURI:String)
Self.baseURI = baseURI
Return Self
End Method
'appends a given uri to the current base uri
Method GetUri:String(uri:String="")
?android
'try to prepend "sdl::" if the file seems to be within the
'APK
If FileSize(uri) <= 0 And uri.Find("sdl::") <> 0
uri = "sdl::"+uri
EndIf
?
Return baseURI + uri
End Method
Method LoadFromXML:Int(file:String, forceDirectLoad:Int=False)
file = GetUri(file)
xmlHelper = TXmlHelper.Create(file, "", False)
If Not xmlHelper.xmlDoc
TLogger.Log("TRegistryLoader.LoadFromXML", "file '" + file + "' not found or invalid.", LOG_LOADING)
Return False
EndIf
LoadResourcesFromXML(xmlHelper.GetRootNode(), file, forceDirectLoad)
'load everything until everything from that file was loaded
If forceDirectLoad
Local instance:TRegistryUnloadedResourceCollection = TRegistryUnloadedResourceCollection.GetInstance()
Repeat
instance.Update()
Until instance.FinishedLoading()
EndIf
TriggerBaseEvent(eventKey_onLoadXmlFromFinished, New TData.AddString("uri", file) )
Return True
End Method
Method LoadResourcesFromXML:Int(node:TxmlNode, source:Object, forceDirectLoad:Int=False)
For Local resourceNode:TxmlNode = EachIn TXmlHelper.GetNodeChildElements(node)
LoadSingleResourceFromXML(resourceNode, source, forceDirectLoad)
Next
End Method
Method LoadSingleResourceFromXML:Int(node:TxmlNode, source:Object, forceDirectLoad:Int=False, extras:TData = Null)
'get the name defined in:
'- type (<bla type="identifier" />) or
'- tagname ( <identifier x="1" />)
Local resourceName:String = TXmlHelper.FindValue(node, "type", node.getName())
'we handle "resource" on our own
If resourceName.ToUpper() = "RESOURCES"
Local directLoad:Int = TXmlHelper.findValueBool(node, "directload", forceDirectLoad)
LoadResourcesFromXML(node, source, directLoad)
Else
Local loader:TRegistryBaseLoader = GetResourceLoader(resourceName)
If loader
'load config from XML
Local conf:TData = loader.GetConfigFromXML(Self, node)
'do nothing without a configuration (maybe it is a virtual group handled
'directly by the loader -> eg. "fonts" which only groups "font")
If conf
conf.Add("_xmlSource", source)
'merge in the extras (eg. overwrite "names")
If extras Then conf.Append(extras)
Local lazyLoad:Int = Not (loader.directLoading Or forceDirectLoad)
'directly load the objects or defer to a helper
If Not lazyLoad
'if direct loading failed ... load it later
If Not loader.LoadFromConfig(conf, resourceName)
lazyLoad = True
EndIf
EndIf
If lazyLoad
'try to get a name for the resource:
'a) from TData "extras"
'b) from the config read from xml
Local name:String = conf.GetString("name")
If name = "" Then name = loader.GetNameFromConfig(conf)
AddLazyLoadedResource(name, resourceName, conf)
EndIf
EndIf
EndIf
EndIf
'inform others about the to-load-element
'sender: self (the loader)
'target: resourceName in uppercases ("SPRITE") -> so listeners can filter on it
'print "RegistryLoader.onLoadResourceFromXML: self + "+ resourceName.ToUpper()
TriggerBaseEvent(eventKey_onLoadResourceFromXML, New TData.AddString("resourceName", resourceName).Add("xmlNode", node), Self, resourceName.ToUpper())
End Method
Function AddLazyLoadedResource(name:String, resourceName:String, data:TData)
'add to "ToLoad"-list
TRegistryUnloadedResourceCollection.GetInstance().Add(..
New TRegistryUnloadedResource.Init(name, resourceName, data)..
)
End Function
End Type
'collection handling multiple resourcecontainers (unloaded resources)
Type TRegistryUnloadedResourceCollection
'simple counters for a 1of10-display
Field toLoadCount:Int = 0
Field loadedCount:Int = 0
'list files containing names of loaded resources
Field loadedLog:TList = CreateList()
Field failedLog:TList = CreateList()
'list files containing objects to get loaded
Field unloadedResources:TList = CreateList()
Field failedResources:TList = CreateList()
'indicator if something failed when the last list got processed
Field failedResourceLoaded:Int = False
'indicator (cache) whether there is still something to load
Field _finishedLoading:Int = True
?Threaded
Field _loadedMutex:TMutex = CreateMutex()
Field _failedMutex:TMutex = CreateMutex()
Field _unloadedMutex:TMutex = CreateMutex()
Field _loaderThread:TThread
?
Global _instance:TRegistryUnloadedResourceCollection
Function GetInstance:TRegistryUnloadedResourceCollection()
If Not _instance Then _instance = New TRegistryUnloadedResourceCollection
Return _instance
End Function
Method Add(resource:TRegistryUnloadedResource)
?Threaded
'wait for the listMutex to be unlocked (nobody modifying the list)
LockMutex(_unloadedMutex)
?
unloadedResources.AddLast(resource)
toLoadCount :+ 1
?Threaded
UnlockMutex(_unloadedMutex)
?
_finishedLoading = False
End Method
Method AddFailed(resource:TRegistryUnloadedResource)
?Threaded
'wait for the listMutex to be unlocked (nobody modifying the list)
LockMutex(_failedMutex)
?
failedResources.AddLast(resource)
failedLog.AddLast(resource.name)
?Threaded
UnlockMutex(_failedMutex)
?
End Method
Method GetUnloadedCount:Int()
?Threaded
'wait for the listMutex to be unlocked (nobody modifying the list)
LockMutex(_unloadedMutex)
Local c:Int = unloadedResources.Count()
UnlockMutex(_unloadedMutex)
Return c
?Not Threaded
Return unloadedResources.Count()
?
End Method
Method GetFailedCount:Int()
?Threaded
'wait for the listMutex to be unlocked (nobody modifying the list)
LockMutex(_failedMutex)
Local c:Int = failedResources.Count()
UnlockMutex(_failedMutex)
Return c
?Not Threaded
Return failedResources.Count()
?
End Method
'removes and returns the first element of the unloaded list
Method PopFirstUnloadedResource:TRegistryUnloadedResource()
?Threaded
'wait for the listMutex to be unlocked (nobody modifying the list)
LockMutex(_unloadedMutex)
?
Local res:TRegistryUnloadedResource = TRegistryUnloadedResource(unloadedResources.RemoveFirst())
?Threaded
UnlockMutex(_unloadedMutex)
?
Return res
End Method
Method AddToLoadedLog:Int(value:String)
?Threaded
'wait for the listMutex to be unlocked (nobody modifying the list)
LockMutex(_loadedMutex)
?
loadedLog.AddLast(value)
loadedCount :+ 1
?Threaded
UnlockMutex(_loadedMutex)
?
End Method
Method FinishedLoading:Int()
'if already calculated, just return true (gets "FALSE" on add of
'a new resource)
If _finishedLoading Then Return True
'finished as soon as nothing to load and last cycle no
'previously failed resource was loaded
_finishedLoading = (GetUnloadedCount() = 0 And Not failedResourceLoaded)
Return _finishedLoading
End Method
Method Update:Int()
If FinishedLoading() Then Return True
'threaded binary: kick off a loader thread
'unthreaded: load the next one
?Threaded
If Not _loaderThread Or Not ThreadRunning(_loaderThread)
_loaderThread = CreateThread(RunLoaderThread, Null)
EndIf
'helper function
Function RunLoaderThread:Object(Input:Object)
'this thread runs as long as there is something to load
'-> it gets auto-recreated if no longer running but there is
'something to load
Repeat
'try to load the next item
TRegistryUnloadedResourceCollection.GetInstance().LoadNext()
Delay(1)
Until TRegistryUnloadedResourceCollection.GetInstance().FinishedLoading()
End Function
?Not Threaded
LoadNext()
?
End Method
Method LoadNext:Int()
'refresh unloaded list with former failed resources
'maybe they are now loadable (dependencies)
If GetUnloadedCount() = 0
'nothing to load
If GetFailedCount() = 0 Then Return True
'try failed again ?!
unloadedResources = failedResources
If failedResources
failedResources.Clear()
Else
failedResources = CreateList()
EndIf
failedResourceLoaded = False
EndIf
Local toLoad:TRegistryUnloadedResource = PopFirstUnloadedResource()
If Not toLoad Then Return True
'try to load the resource
'Print "loading: " + toLoad.name
If toLoad.Load()
AddToLoadedLog(toLoad.name)
'mark the fact that a previously failed resource was now
'correctly loaded - indicator to loop through the failed again
If toLoad.loadAttempts > 0 Then failedResourceLoaded = True
'Print "... done loading " + toLoad.name
Return True
EndIf
'loading failed
toLoad.loadAttempts :+1
'Print " loading failed : "+ toLoad.name + " | "+ toLoad.loadAttempts
'add to the list of failed resources
AddFailed(toLoad)
Return False
End Method
End Type
'object containing information about an not yet loaded element
Type TRegistryUnloadedResource
Field config:TData
Field resourceName:String 'eg. "IMAGE"
Field name:String 'eg. "my background" or "gfx/office/background.png"
Field id:Int = 0
Field loadAttempts:Int = 0 'times engine tried to load this resource
Global LastID:Int = 0
Method New()
LastID :+ 1
id = LastID
End Method
Method Init:TRegistryUnloadedResource(name:String, resourceName:String, config:TData)
Self.name = name
Self.resourceName = resourceName.ToLower()
Self.config = config
Return Self
End Method
Method Load:Int()
TriggerBaseEvent(TRegistryLoader.eventKey_onBeginLoadresource, New TData.AddString("name", name).AddString("resourceName", resourceName))
'try to find a loader for the objects resource type
Local loader:TRegistryBaseLoader = TRegistryLoader.GetResourceLoader(resourceName)
If Not loader Then Return False
'try to load an object with the given config and resourceType-name
If loader.LoadFromConfig(config, resourceName)
'inform others: we loaded something
TriggerBaseEvent(TRegistryLoader.eventKey_onLoadResource, New TData.AddString("name", name).AddString("resourceName", resourceName))
Return True
Else
Return False
EndIf
End Method
'sort by ID
Method Compare:Int(Other:Object)
Local otherResource:TRegistryUnloadedResource = TRegistryUnloadedResource(Other)
If otherResource
If otherResource.id > id Then Return -1
If otherResource.id < id Then Return 1
EndIf
Return Super.Compare(Other)
End Method
End Type
'==== RESOURCE LOADER HANDLING SPECIFIC TYPES ====
'register basic loaders
New TRegistryFileLoader.Init()
New TRegistryDataLoader.Init()
'base loader
Type TRegistryBaseLoader
Field name:String = "Base"
Field resourceNames:String = "nothing"
Field registered:Int = False
Field directLoading:Int = False
Field id:Int = 0
Global LastID:Int = 0
Global keyNameLS:TLowerString = New TLowerString.Create("name")
Method New()
LastID :+ 1
id = LastID
End Method
'call to initialize a loader, set names etc
Method Init:Int() Abstract
'called with the corresponding xmlNode containing the
'element which the loader registered for
'loads all recognized values of the node into a tdata-object
Method GetConfigFromXML:TData(loader:TRegistryLoader, node:TxmlNode) Abstract
'return a printable identifier of this resource (url, spritename, ...)
Method GetNameFromConfig:String(data:TData) Abstract
'loading the objects contained in the data
Method LoadFromConfig:Object(data:TData, resourceName:String) Abstract
Method CreateDefaultResource:Int()
'
End Method
'sort loaders according creation date
Method Compare:Int(other:Object)
Local otherLoader:TRegistryBaseLoader = TRegistryBaseLoader(other)
'no weighting
If Not otherLoader Then Return 0
If otherLoader = Self Then Return 0
'below me
If otherLoader.id < id Then Return 1
'on top of me
Return -1
End Method
'register loader in registry
Method Register:Int()
TRegistryLoader.RegisterResourceLoader(Self)
registered = True
End Method
Method ToString:String()
Return "TRegistry"+name.ToUpper()+"Loader"
End Method
End Type
'loader caring about "<file>"-types
Type TRegistryFileLoader Extends TRegistryBaseLoader
Method Init:Int()
resourceNames = "file"
name = "File"
'xml files can get loaded directly
directLoading = True
If Not registered Then Register()
End Method
Method GetNameFromConfig:String(data:TData)
Local res:String = data.GetString("baseURI","")
If res<>"" Then res :+ "/"
res :+ data.GetString("url")
Return res
End Method
'load url of the xml file (information about file)
Method GetConfigFromXML:TData(loader:TRegistryLoader, node:TxmlNode)
Local _url:String = TXmlHelper.FindValue(node, "url", "")
If _url = "" Then Return Null
Local data:TData = New TData
data.addString("url", _url)
data.addString("baseURI", loader.baseURI)
Return data
End Method
'load the xml file (content of file)
Method LoadFromConfig:Object(data:TData, resourceName:String)
Local newLoader:TRegistryLoader = New TRegistryLoader
'take over baseURI
newLoader.baseURI = data.GetString("baseURI")
newLoader.LoadFromXML(data.GetString("url"))
'indicate that the loading was successful (else return null)
Return Self
End Method
End Type
'loader caring about "<data>"-types
'data blocks are merged with existing ones (except "merge" is set to
'false in the xml-node)
Type TRegistryDataLoader Extends TRegistryBaseLoader
Method Init:Int()
resourceNames = "data"
name = "Data"
If Not registered Then Register()
End Method
Method GetConfigFromXML:TData(loader:TRegistryLoader, node:TxmlNode)
Local name:String = TXmlHelper.FindValue(node, "name", node.GetName())
'skip unnamed data (no name="x" or <namee type="data">)
If name = "" Or name.ToUpper() = "DATA"
TLogger.Log("TRegistryDataLoader.LoadFromXML", "Node ~q<"+node.GetName()+">~q contained no or invalid name field. Skipped.", LOG_WARNING)
Return Null
EndIf
Local data:TData = New TData
data.AddString("name", name)
data.AddNumber("merge", TXmlHelper.FindValueBool(node, "merge", True))
Local values:TData = New TData
For Local child:TxmlNode = EachIn TXmlHelper.GetNodeChildElements(node)
Local childName:String = TXmlHelper.FindValue(child, "name", child.getName())
If childName = "" Then Continue
Local childValue:String = TXmlHelper.FindValue(child, "value", child.getcontent())
values.Add(childName, childValue)
Next
data.Add("values", values)
Return data
End Method
Method GetNameFromConfig:String(data:TData)
Return data.GetString("name","unknown data block")
End Method
'load the xml file (content of file)
Method LoadFromConfig:Object(data:TData, resourceName:String)
Local merge:Int = data.GetInt("merge", False)
Local name:String = GetNameFromConfig(data)
Local values:TData = New TData
'if merging - we load the previously stored data (if there is some)
If merge Then values = TData(GetRegistry().Get(name, New TData))
'merge in the new values (to an empty - or the old tdata)
values.Append(TData(data.Get("values")))
'add to registry
GetRegistry().Set(name, values)
'indicate that the loading was successful
Return values
End Method
End Type