chaos.clone: Functions Types Modinfo Source  

Module for cloning, saving and loading user defined Types. All objects that have to be saved have to be tagged with {Save}. Using {NoSave} prevents an object from being loaded or saved.

Chaos.Clone

 
Hi!
This module is donationware. Feel free to use it as you like and to share it with others. If you like this module please consider using the links in the moduleinfo section and give me a little donation for my efforts.
Also I would ask you to mention me/ the module in the credits of your app. If you share this module please do NOT change the archive - copy it as is.
If there are any questions regarding the module you can contact me: bladerunner@chaosinteractive.de - www.chaosinteractive.de

Usage:

Chaos.Clone is a module which allows nearly universal loading, saving, cloning and combining of user defined objects in BMax. It does so by giving multiple ways to store object data. Because reflection in BMax is not perfect there are some little hacks needed in order to get everything stored. This manual will show the different ways to use the module.
Chaos.Clone contains a type called TChaosClone. With this type (which is a Singleton) all processes are steered. It offers the following functions:

 obj = CloneObject(obj)

 This clones an object. BMax usualy uses references for objects. This leads to severe sideeffects as changing one copy of an type instance will change all other copies to. Cloning a type instance creates a totally independent instance. You can control the copy/clone process with some vars that are within TChaosClone. Those vars can be set with KeepMode(). The controlling vars and the metadata of your object will determine what gets copied.
{Example:
Type TTest field bla:Tanothertype {clone}'
    field blub:int
    field blobber:Tthirdone {noclone}'
    field blubber:Tquad
end type
bla will be cloned.
blub gets copied, it's not an object.
blobber will be ignored.
blubber will be reference-copied.}




obj = CombineObject(source,target)

This combines two objects. The combining behaviour is controlled by KeepMode(). If a field gets marked with {keep} the targets info will be preserved, otherwise the sources field gets copied to the target.
{Example:
Type Ttest
    field bla:Tanothertype {clone}'
    field blub:int {keep}'
end type
erg:ttest=TTest(combine(source,target))


bla gets created as a new clone from the source object field.
blub stays target's field.}




Combine has two special cases: If two Strings get combined they get merged as if they were added. If two arrays get combined - and they are of the same dimensions except the first one- then the arrays are merged as source-target. So, Combine([1,2,3],[4,5,6,7,]) would result in [1,2,3,4,5,6,7].
If the dimensions (except the first) are different, combine will return 'Null'.


SaveUDObject(url,obj) / obj=LoadUDObject(url,[new]obj)

Saves/loads an object to/from the given URL, which can be a String or a Stream. The controller Vars are useful here, too, but the functions you will need are: SetSaveTags() and SetSaveMethodTags(). The first one specifies the fields that are to be saved: {save}, {nosave} and {wholesave}. Save will save the fields content, nosave won't, and wholesave will save all of the fields objects fields and all subobjects.
SetSaveMethodTags() delivers alternate methods for saving and loading, as reflection can't get byte ptr and array of array ([][]) fields. Those tags can specify external methods to do the job.
-{savemethod} declares that the type has a load and a save method that will be used to load the types content. Those method must take one argument, an url-object. The actual stream will be passed to the methods and they can do what is needed. The object should be manipulatet itself, so load does not return anything.
{Example:
type Ttest {savemethod}'
    field path:string
    field obj:object
    method save(url:object)
        local s:TStream = WriteFile(url)
        'do save stuff
        s.close()
    end method


    method load(url:object)
        local s:TStream = ReadFile(url)
        'do load stuff
        s.close()
    endmethod
end type}


-{init} declares that the type has an init()-method which will be invoked (without arguments) after the rest of the type has been loaded.
{Example:
type Ttest {init}'
    field path:string{nosave}'
    field obj:object{save}'
    method init()
        print "ho, I'm gettin' Initialized."
        print obj.tostring()
    end method
end type}


-{loadurl} also declares a load()-method. This will read from an external file, the path is in a type field whose name is declared after the loadurl-tag. Order is crucial, so the path-field has to be loaded before the loadurl-tag gets parsed.
{Example:
type Ttest
    field path:string{save}'
    field sound:TSound{loadurlpath}'
end type}
 
This example also shows the one exception integrated here: 'cause of the internal structure of the TSound object this tag will internaly call the TSound.load function. User defined Types MUST have a method to invoke.
The Save- and LoadUDObject-functions also have an automagic handling for bmax-internal type classes: TList, TMap, TBank, TImage, TPixmap. They will be included automaticaly. Repeating references will be recognized and replaced to minimize the filesize.
The KeepMode: The parameter keep which can be set with Keepmode() specifies if the object goven to the loadudobject function will be kept (as with CombineObject). Standard is false. This feature allows for prototyping types where a prefilled prototype gets finalized by the loaded content.
The ResetMode: Chaos.Clone uses an internal map to recognize repeating references in load and save operations. It gets cleared after each op. If ResetMode() ist true, the map will be kept, which can be from use if templates are to be loaded and saved in a specified order. Standard is also false.


Enjoy.



 
Hi!
Dieses Modul ist Donationware. Benutz es wie Du willst, gib es auch gerne an andere weiter. Wenn Du das Modul gelungen findest und es gern oder regelmäßig verwendest möchte ich Dich bitten mir eine kleine Spende als Anerkennung zukommen zu lassen.
Den Link zur Spendeseite findest Du in der module-info. Desweiteren bitte ich Dich meinen Namen oder den des Modules in den Credits deiner App einzutragen. Wenn Du das Modul weiterreichst verändere es bitte NICHT - gebe es weiter wie es ist.
Wenn Du Fragen betreffend des Modules hast, kontaktiere mich: bladerunner@chaosinteractive.de - www.chaosinteractive.de

Verwendungszweck:

Chaos.Clone ist ein Modul zum universellen Laden, Speichern, Klonen und Kombinieren von Objekten in Bmax. Dabei stellt es verschiedene Methoden zur Verfügung um ein optimales Ergebnis zu erreichen. Da die Reflektion unter BMax nicht universell ist müssen leider einige Kunstgriffe angewendet werden um wirklich alle Daten der zu speichernden Objekte zu erfassen. Im Folgenden werde ich die verschiedenen Methoden erläutern.
Chaos.Clone enthält einen Type: TChaosClone. Mit ihm werden alle Vorgänge gesteuert. Er hat folgende Funktionen:

obj=CloneObject(obj)

CloneObject erstellt eine exakte Kopie von einem Objekt. Üblicherweise werden in Bmax Referenzen übergeben. Dies hat unter Umständen den Nachteil dass die Manipulation eines Objektes sämtliche referenzierten Instanzen ändert. Ein mittels CloneObject erstelltes Objekt ist eine eigenständige Kopie, keine Referenz, daher sind solche instanzübergreifenden Effekte nicht zu erwarten. Zum Steuern des Kopiervorganges existieren in TChaosClone mehrere Steuervariablen welche sich mittels KeepMode() setzen lassen. Bei einem Kopiervorgang wird anhand dieser Steuervariablen und der in den MetaDaten des Objektes festgelegten Anweisungen verfahren:
{Beispiel:
Type Ttest
    field bla:Tanothertype {clone}'
    field blub:int
    field blobber:Tthirdone {noclone}'
    field blubber:Tquad
end type
bla wird als neuer Clone mit angelegt.
blub wird kopiert, da es kein Objekt ist.
blobber wird bei der Kopie ignoriert.
blubber wird als Referenz kopiert, da keine Anweisung vorliegt.}

obj=Combine(source,target)

CombineObject kombiniert zwei Objektinstanzen. Auch hier wird mit KeepMode() das Verhalten der Funktion gesteuert. Wird ein Feld mit {keep} markiert wird das Feld des Targetobjektes erhalten, ansonsten wird das Field von Source übernommen.
{Beispiel:
Type Ttest
    field bla:Tanothertype {clone}'
    field blub:int {keep}'
 end type
erg:ttest=TTest(combine(source,target))
bla wird als neuer Clone von Source mit angelegt.
blub wird behalten, da es mit keep markiert ist.}

Bei Combine gibt es noch zwei Besonderheiten: Sind die beiden Objekte Strings werden sie addiert. Sind es Arrays, werden sie – sofern sie in ihren Dimensionen (außer der ersten) identisch sind – kombiniert, wobei Target an Source angehängt wird. Aus Combine([1,2,3],[4,5,6,7]) würde also [1,2,3,4,5,6,7] folgen.
Sind die Dimensionen (außer der ersten) nicht identisch, liefert Combine 'Null' zurück.

SaveUDObject(url,obj) / obj=LoadUDObject(url,[new] obj)

Speichert ein Objekt in die angegebene URL. Dies kann ein String aber auch ein Stream sein. Auch hier greifen wieder die internen Steuervariablen- allerdings sind folgende Funktionen ausschlaggebend: SetSaveTags() und SetSaveMethodTags(). Erstere legt fest welche Felder eines Types gespeichert werden: {save},{nosave} und {wholesave}. Save speichert das Feld, nosave speichert es nicht, wholesave speichert das Objekt im Typefield inklusive aller Subobjekte.
SetSaveMethodTags() hingegen bietet eine alternative Methode, da nicht alle Felder eines Objektes von Reflection erfasst werden (Byte Ptr und Arrays von Arrays zB. [][]). hier lassen sich die Tags setzen die das Modul auf diverse Lade- und Speichermethoden in den Types aufmerksam machen.
-{savemethod} deklariert dass der Type eine load- und eine save-Methode besitzt. Die Methoden müssen als Argument ein url-Objekt annehmen und alle Felder des Types manipulieren. Die Methode wird dann it dem aktuellen Stream aufgerufen und liest/ schreibt daher im aktuellen File.
{Beispiel:
type Ttest {savemethod}'
    field path:string
    field obj:object
    method save(url:object)
        local s:TStream = WriteFile(url)
        'do save stuff
        s.close()
    end method
    method load(url:object)
        local s:TStream = ReadFile(url)
        'do load stuff
        s.close()
    end method
end type}

-{init} deklariert dass der Type eine Init-Methode hat. Sie wird (parameterfrei) aufgerufen nachdem der restliche Ladevorgang abgeschlossen ist.
{Beispiel:
type Ttest {init}'
    field path:string{nosave}'
    field obj:object{save}'
    method init()
        print "ho, I'm gettin' Initialized."
        print obj.tostring()
    end method
end type}

-{loadurl} deklariert ebenfalls eine loadmethode, allerdings wird hier aus einem externen File gelesen, welches aus einem Feld, dessen Name im Tag spezifiziert wird gespeichert ist. Die Reihenfolge ist hier entscheidend, d.h. das Namensfeld muss vor dem loadurl-Tag geladen sein.
{Beispiel:
type Ttest
    field path:string{save}'
    field sound:TSound{loadurlpath}'
end type}
 
Dieses Beispiel markiert auch die einzige Ausnahme die hier integriert ist: aufgrund der internen Struktur eines TSound-objektes wird hier intern die load-Funktion aufgerufen – bei selbst definierten Types MUSS es eine Methode sein.
Die Save- und LoadUDobject-Funktionen besitzen auch ein automatisches Handling für folgende Bmax-Internen Typklassen: TList, TMap, TBank, TImage, TPixmap. Sie werden automatisch eingebunden. Wiederholende Referenzen werden automatisch erkannt und ersetzt, um die Dateigröße zu minimieren.
Der KeepMode: Der mit Keepmode() zu setzende Parameter Keep bestimmt ob auch beim Laden eines Objektes die übergebene Instanz beibehalten werden soll. Standard ist false. Mittels dieses Features ist es möglich ein Prototyping zu betreiben, also Protoobjekte mit neuen Daten zu kombinieren.
Der ResetMode: Chaos.Clone legt intern eine Map an welche bekannte Referenzen beim aktuellen Lade-/ Speichervorgang speichert. Diese wird nach jedem Aufruf geleert. Ist der ResetMode() jedoch gesetzt wird diese Map beibehalten – was sinnvoll sein kann wenn man in einer festgelegten Reihenfolge Vorlagen speichert und wieder einlädt. Standard ist auch hier false.
Viel Spaß mit dem Modul!

Functions Summary

CloneObject Clones an object and returns the clone. Any fields that reference an object only get the reference copied unless MetaData contains {Clone}
CombineObject Combines two objects (from source-> target). Fields marked with 'keep' will keep what target has in them. Fields marked with 'clone' will get a clone instead of a copie.
LoadUDObject This loads a previously saved object from a file or stream.
LoadUserDefinedObject Loads an Object from the given stream. Any fields that reference an object (strings and arrays are objects, too!) only get loaded if MetaData contains {Save}. {NoSave} prevents the field from being saved/loaded.
SaveUDObject This saves an object to a file or stream. Using metadata it can be specified which fields get saved. All objects (and strings are objects, too!) need to be marked seperately.
SaveUserDefinedObject Saves an Object to the given stream. Any fields that reference an object (strings and arrays are objects, too!) only get saved if MetaData contains {Save}. {NoSave} prevents the field from being saved.

Types Summary

TChaosClone  

Functions

Function CloneObject:Object(obj:Object)
DescriptionClones an object and returns the clone. Any fields that reference an object only get the reference copied unless MetaData contains {Clone}
Example
SuperStrict
Import Chaos.clone

Type TMyTest
	Field a:Int
	Field b:TMyTest 	{clone}		'if you clone ist it will be a new instance. Otherwise you get the reference copied.		
	Field c:String				
	Field id:Int		{noclone}	'fields that should not get copied at all have to be marked.
	
	Global idcount:Int			'Globals don't need to get cloned ;)
	
	Method New() 
		a = Rand(6) 
		c = "Hello World!"
		id = idcount
		idcount:+ 1
	End Method	
End Type

Local instance:TMyTest = New TMyTest
instance.b = New TmyTest
Local clone:TMyTest = TMyTest(TChaosClone.CloneObject(instance) )	'no alternative metadata defined, as it is not needed.
															'I'm using the TChaosClone method, the wrapped function works the same.
instance.c = "Hello Clone!"
DebugStop	'now, take a loog at the debugger and see the result. Try it again without the {clone}-Metadata

Function CombineObject:Object(source:Object , target:Object)
DescriptionCombines two objects (from source-> target). Fields marked with 'keep' will keep what target has in them. Fields marked with 'clone' will get a clone instead of a copie.
Example
SuperStrict

Import Chaos.clone

Type TMyTest
	
	Field _a:String {keep}		'this field will be kept in the target.
	Field _b:String
	Field _obj:TMyTest {clone}	'this field will be cloned to the target
	
	Method Set(a:String , b:String) 
		_a = a
		_b = b
	End Method
End Type

Local source:TMyTest = New TMyTest
source.Set("Hello" , "World") 

Local target:TMyTest = New TMyTest
target.Set("Goodbye" , "Moon") 
source._obj = target	'Warning: setting source._obj to source would be cyclic as every new instance would clone itself into itself.
					'But: You could add source as source._obj if you didn't {clone} it.

Local result:TMyTest = TMyTest(CombineObject(source , target)) 
DebugStop	'now look at the result

Function LoadUDObject:Object(url:Object,obj:Object)
DescriptionThis loads a previously saved object from a file or stream.

Function LoadUserDefinedObject:Object(Stream:TStream,obj:Object,loadtype:Int=False,load:String="save",noload:String="nosave",wholeload:String="wholesave",nullinst:Int = False,map:TMap=Null)
DescriptionLoads an Object from the given stream. Any fields that reference an object (strings and arrays are objects, too!) only get loaded if MetaData contains {Save}. {NoSave} prevents the field from being saved/loaded.
InformationUsage: bla:object = LoadObject(stream,bla). returns: the loaded object.

Function SaveUDObject(url:Object , obj:Object)
DescriptionThis saves an object to a file or stream. Using metadata it can be specified which fields get saved. All objects (and strings are objects, too!) need to be marked seperately.

Function SaveUserDefinedObject:Object(Stream:TStream,obj:Object,SaveType:Int = False,save:String="save",nosave:String="nosave",wholesave:String="wholesave",map:TMap=Null)
Returnsthe stored object.
DescriptionSaves an Object to the given stream. Any fields that reference an object (strings and arrays are objects, too!) only get saved if MetaData contains {Save}. {NoSave} prevents the field from being saved.

Types

Type TChaosClone
Functions Summary
CloneObject Clones an object and returns the clone. Any fields that reference an object only get the reference copied unless MetaData contains {Clone}
Combine Combines two objects (from source-> target). Fields marked with 'keep' will keep what target has in them. Fields marked with 'clone' will get a clone instead of a copie.
KeepMode Sets the overwriting on load and the adjuvant metatags.
LoadUDObject This loads a previously saved object from a file or stream.
Reset This resets The internal storage.
ResetMode Sets wether the internal storage will be automatically reset or not.
SaveUDObject This saves an object to a file or stream. Using metadata it can be specified which fields get saved. All objects (and strings are objects, too!) need to be marked seperately.
SetSaveMethodTags Sets the tags that manage the automatic method calling.
Function CloneObject:Object(obj:Object)
DescriptionClones an object and returns the clone. Any fields that reference an object only get the reference copied unless MetaData contains {Clone}
Example
SuperStrict
Import Chaos.clone

Type TMyTest
	Field a:Int
	Field b:TMyTest 	{clone}		'if you clone ist it will be a new instance. Otherwise you get the reference copied.		
	Field c:String				
	Field id:Int		{noclone}	'fields that should not get copied at all have to be marked.
	
	Global idcount:Int			'Globals don't need to get cloned ;)
	
	Method New() 
		a = Rand(6) 
		c = "Hello World!"
		id = idcount
		idcount:+ 1
	End Method	
End Type

Local instance:TMyTest = New TMyTest
instance.b = New TmyTest
Local clone:TMyTest = TMyTest(TChaosClone.CloneObject(instance) )	'no alternative metadata defined, as it is not needed.
															'I'm using the TChaosClone method, the wrapped function works the same.
instance.c = "Hello Clone!"
DebugStop	'now, take a loog at the debugger and see the result. Try it again without the {clone}-Metadata
Function Combine:Object(source:Object , target:Object)
DescriptionCombines two objects (from source-> target). Fields marked with 'keep' will keep what target has in them. Fields marked with 'clone' will get a clone instead of a copie.
Function KeepMode(mode:Int = False,keep:String="keep",clone:String="clone",noclone:String = "noclone")
DescriptionSets the overwriting on load and the adjuvant metatags.
Function LoadUDObject:Object(url:Object,obj:Object)
DescriptionThis loads a previously saved object from a file or stream.
Function Reset()
DescriptionThis resets The internal storage.
Function ResetMode(mode:Int = True)
DescriptionSets wether the internal storage will be automatically reset or not.
Function SaveUDObject:Object(url:Object , obj:Object)
DescriptionThis saves an object to a file or stream. Using metadata it can be specified which fields get saved. All objects (and strings are objects, too!) need to be marked seperately.
Function SetSaveMethodTags(save:String = "savemethod" , loadurl:String = "loadurl" , init:String = "init")
DescriptionSets the tags that manage the automatic method calling.

Module Information

AboutClone and storage functions for objects
LicenseDonationware. Feel free to contact me @ www.blitzforum.de. Credits are welcome.
Donatehttps://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=LX2X9TLEHGPKU - Thank you.
Spendenhttps://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=LAWKKVVJTERHG - Herzlichen Dank.
AuthorAndreas 'BladeRunner' Brennecke
Version1.50, 07.02.10 - Minor changes in interface. Documentation added. Savemethods etc. First release.
Version1.30, 02.02.10 - Multidimensional Arrays supported. Arrays in Arrays supported. Combining of Objects added.
Version1.20, 01.02.10 - Packed into TChaosClone. Added support for TImage, TMap, TList, TBank. Bugfixing.
Version1.10, 30.01.10 - added SaveUserDefinedObject and LoadUserDefinedObject.
Version1.00, 27.03.09
WebsiteVisit www.chaosinteractive.de