====== Compilation d'AS3 en AS3 ====== {{tag>as3}} J'ai découvert il y a quelques temps deja, un petit [[http://eval.hurlant.com/|framework]] contenant une partie du code de [[http://www.mozilla.org/projects/tamarin/|tamarin]], dans ces premiers commits, et qui permet donc de compiler de l'AS3 avec le Flash Player, moyennant quelques adaptations d'écritures, et quelques issues à connaitre. L'idée, c'est que l'application cliente ne dispose que des interfaces des classes, pour qu'en cas de décompilation, les classes critiques ne puissent être obtenues. ===== Applications ===== Imaginons, un serveur socket, binaire ou xml, qui discute avec son application cliente, elle reçoit en AMF3 ou sous forme Hexa, un String compréssé, modifié, et crypté. On reçoit ce String, on le décompresse, on le décrypte, etc, et on en arrive à la compilation proprement dite. On peut aussi imaginer tout un tas d'autre cas d'utilisations : * Dans un framework 3D, préparer et compiler des objets 3D, pour n'avoir ensuite qu'à les instancier, avec déja les propriétés prédefinies. * Faire une fausse IA, qui pourrait avoir des enfants de plus en plus intelligents où ayant des caracteristiques différentes selon certains croisements, * Etc, c'est pas les possibilités d'application possibles qui manquent. Il faut savoir que sur le [[http://eval.hurlant.com/|framework]] en question, les seuls trucs utiles à garder, c'est : * com.hurlant.eval.ByteLoader * com.hurlant.eval.CompiledESC * abc.* Le Compileur en AS3 pur, d'une il marche pas, de deux, il est lent, et de trois, il est tellement mal écrit, qu'il y a 3000 warnings et aucun typage, en gardant que les classes et packages nommés plus haut, il ne devrait plus y avoir de soucis. ===== Utilisation ===== Donc la création et la compilation d'une classe au runtime est assez facile, au niveau de la syntaxe, la seule chose qui change, c'est les import : /* import flash.utils; devient : */ namespace utils = "flash.utils"; use namespace utils; Prenons une classe toute simple : namespace event = "flash.events"; use namespace event; public class MyClass extends EventDispatcher { private static var ID : int = 0; private var _label : String; private var _id : int; public function MyClass () { _id = ID; ID++; } public function get id () : int { return _id; } public function set label (value:String) : void { if (_label != value) { _label = value; dispatchEvent(new Event('labelChanged')); } } public function get label () : String { return _label; } } Imaginons que le code précédent est stocké dans une variable ''maClass'' sous forme de String : var c : CompiledESC = new CompiledESC (); var classDump : ByteArray = c.eval(maClass); var swf : ByteArray = ByteLoader.wrapInSWF([classDump]); /* ici vous pouvez au choix, loader votre classe dans le LoaderContext qui vont convient : */ var l : Loader = new Loader (); var lc : LoaderContext = new LoaderContext (false,ApplicationDomain.currentDomain,null); l.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaderComplete,false,0,true); l.loadBytes(swf,lc); /* et plus loin, dans votre */ private function onLoaderComplete (e:Event) : void { if (ApplicationDomain.currentDomain.hasDefinition('MyClass')) { var c : Class = ApplicationDomain.currentDomain.getDefinition('MyClass') as Class; var instance : * = new c (); trace (instance.id); } } Les quelques problèmes rencontrés, en vrac : * impossibilité de récupérer le ''this'' de l'instance à l'interieur de celle-ci. * assurez-vous d'avoir toutes les classes que la classe que vous voulez compiler utilise dans votre swf principal, sinon, la compilation échouera et ''classDump'' sera ''null''. * Vous ne pouvez importer plusieurs Class en même temps, donc assurez vous de ne pas faire de loadBytes concurrents. * Vous ne pouvez pas non plus importer 2 fois la même classe, car la 1ere version sera gardée. * Vous ne pouvez utiliser ''as'', vous devrez donc caster avec ''MyType(obj)''. Sinon, ça marche plutôt bien, et ça permet de faire des choses assez sympas :), en esperant que Flash 10 ne casse pas tout :) ~~DISCUSSION~~