How To Know That Your Flash Content Requires a Premium Feature License

Posted on March 29, 2012 | 9 comments

A license is needed for your SWF if it uses premium features. The current premium feature that requires a license is a SWF that makes use of Stage3D and ApplicationDomain.domainMemory APIs at the same time. If only one is used without the other a license is not required.

Still not sure if your application requires the license? Well there is a way to find out with using a debug version of Flash Player. Starting with Flash Player 11.2 you will get a message that is rendered on top of your SWF if you require a license. Here is what it looks like:

Premium Features Watermark

And here is the code to force the watermark:

package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
import flash.utils.Endian;

[SWF(width="320",height="160",backgroundColor="0x333333")]
public class PremiumFeatureCheck extends Sprite
{
    public function PremiumFeatureCheck()
    {
        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
    }
   
    protected function addedToStageHandler(event:Event):void
    {
        trace("Stage3Ds Lenght: " + stage.stage3Ds.length + "");
        stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, initStage3D );
        stage.stage3Ds[0].requestContext3D();
       
        var testData:ByteArray = new ByteArray();
        testData.endian = Endian.LITTLE_ENDIAN;
        testData.length=0xffff*4; //4bytes
       
        ApplicationDomain.currentDomain.domainMemory=testData;
        var testValue:int=123;
        ApplicationDomain.currentDomain.domainMemory[0] = testValue;
        var readValue:int = ApplicationDomain.currentDomain.domainMemory[0];
        trace(readValue+"");//should print 123  
       
    }
    protected function initStage3D(e:Event):void
    {
        var context3D:Object = stage.stage3Ds[0].context3D;
    }
}
}

If you comment out “stage.stage3Ds[0].requestContext3D(); ” or remove the domainMemory lines of code you will not see this watermark.

NOTE: If you get a context3D error you need to make sure you have swf-version=13 and wmode=”direct” set up properly to run Stage3D content.


It’s also important to note that the watermark doesn’t show up until the features are used in your code. Take this code example:

package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
import flash.utils.Endian;

[SWF(width="400",height="160",backgroundColor="0x333333")]
public class PremiumFeatureCheck extends Sprite
{
    public function PremiumFeatureCheck()
    {
        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
    }
   
    protected function addedToStageHandler(event:Event):void
    {
        trace("Stage3Ds Lenght: " + stage.stage3Ds.length + "");
        stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, initStage3D );
        stage.stage3Ds[0].requestContext3D();
       
        stage.addEventListener(MouseEvent.CLICK, useDomainMemory);
    }
    protected function initStage3D(e:Event):void
    {
        var context3D:Object = stage.stage3Ds[0].context3D;
    }
    protected function useDomainMemory(event:Event):void
    {
       
        var testData:ByteArray = new ByteArray();
        testData.endian = Endian.LITTLE_ENDIAN;
        testData.length=0xffff*4; //4bytes
       
        ApplicationDomain.currentDomain.domainMemory=testData;
        var testValue:int=123;
        ApplicationDomain.currentDomain.domainMemory[0] = testValue;
        var readValue:int = ApplicationDomain.currentDomain.domainMemory[0];
        trace(readValue+"");//should print 123  
    }
}
}

The watermark will only show up once the domainMemory chunk of code is ran after clicking on the stage.

Here is another scenario, SWFMain.swf loads both SWFStage3DAPI.swf and SWFDomainMemory.swf, do you need a license? Yes you do, the water shows up and stays (even if you try and unload) after you have run API calls for Stage3D or ApplicationDomain.domainMemory regardless if they are from the main SWF or loaded SWFs. If you want to try it out yourself here is the source code:

SWFMain.as

package
{
import flash.display.DisplayObjectContainer;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFormat;

public class SWFMain extends Sprite
{
    public function SWFMain()
    {
        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        format = new TextFormat();
        format.size = 24;
        format.color = 0xffffff;
    }
   
    public var loaderStage3D:Loader;
    public var loaderDomainMemory:Loader;
    public var format:TextFormat;
   
    protected function addedToStageHandler(event:Event):void
    {
        // Create buttons
        var s:Sprite = createButton("Load Stage3D SWF");
        s.x = 10;
        s.y = 10;
        s = createButton("Load DomainMemory SWF");
        s.x = 10;
        s.y = 60;
    }
   
    protected function createButton(label:String):Sprite
    {
        var text:TextField = new TextField();
        text.defaultTextFormat = format;
        text.text = label;
        text.width = 200;
       
        var s:Sprite = new Sprite();
        s.graphics.beginFill(0x222222, 0.8);
        s.graphics.lineStyle(2,0x000000);
        s.graphics.drawRect(0, 0, 240, 40);
        s.graphics.endFill();
        s.addEventListener(MouseEvent.CLICK, clickHandler);
       
        s.addChild(text);
        text.x = 10;
        text.y = 8;
       
        addChild(s);
        return s;
    }
   
    protected function clickHandler(event:MouseEvent):void
    {
        var t:String = "";
        if (event.currentTarget is Sprite)
            t = ((event.currentTarget as DisplayObjectContainer).getChildAt(0) as TextField).text;
       
        trace("Click handler:" + t);
        if (t == "Load Stage3D SWF")
        {
            if (loaderStage3D)
            {
                loaderStage3D.unloadAndStop(true);
                loaderStage3D = null;
            }
            else
            {
                loaderStage3D = new Loader();
                loaderStage3D.load(new URLRequest("SWFStage3DAPI.swf"));
                loaderStage3D.x = 40;
                loaderStage3D.y = 160;
                addChild(loaderStage3D);
            }
           
        }
        if (t == "Load DomainMemory SWF")
        {
            if (loaderDomainMemory)
            {
                loaderDomainMemory.unloadAndStop(true);
                loaderDomainMemory = null;
            }
            else
            {
                loaderDomainMemory = new Loader();
                loaderDomainMemory.load(new URLRequest("SWFDomainMemory.swf"));
                loaderDomainMemory.x = 40;
                loaderDomainMemory.y = 200;
                addChild(loaderDomainMemory);
            }
        }
    }
}
}

Here is the SWFStage3DAPI.as

package
{
import flash.display.Sprite;
import flash.events.Event;

public class SWFStage3DAPI extends Sprite
{
    public function SWFStage3DAPI()
    {
        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
    }
   
    protected function addedToStageHandler(event:Event):void
    {
        graphics.beginFill(0x0000ff);
        graphics.drawRect(0, 0, 10, 10);
        graphics.endFill();
       
        trace("SWFStage3DAPI - Stage3Ds Lenght: " + stage.stage3Ds.length + "");
        stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, initStage3D );
        stage.stage3Ds[0].requestContext3D();
    }
   
    protected function initStage3D(e:Event):void
    {
        if (stage)
            var context3D:Object = stage.stage3Ds[0].context3D;
    }
}
}

Here is the SWFDomainMemory.as

package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
import flash.utils.Endian;

public class SWFDomainMemory extends Sprite
{
    public function SWFDomainMemory()
    {
        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
    }
   
    protected function addedToStageHandler(event:Event):void
    {
        graphics.beginFill(0xff0000);
        graphics.drawRect(0, 0, 10, 10);
        graphics.endFill();
       
        var testData:ByteArray = new ByteArray();
        testData.endian = Endian.LITTLE_ENDIAN;
        testData.length=0xffff*4; //4bytes
       
        ApplicationDomain.currentDomain.domainMemory=testData;
        var testValue:int=123;
        ApplicationDomain.currentDomain.domainMemory[0] = testValue;
        var readValue:int = ApplicationDomain.currentDomain.domainMemory[0];
        trace("SWFDomainMemroy " + readValue);//should print 123
    }
}
}
  • Rob Rusher

    Thanks for the demonstration Renaun. So, although the license is required if both are used, you are not subject to royalties unless you are reporting a specific game’s revenue to Adobe that is higher than $50k. Correct?

    • Anonymous

      Yes, this just says you have go get the license. But you don’t pay royalties until the >$50k net revenue is met.

      • http://twitter.com/mihnescu Mihnea Ilicevici

        OK, but how can Adobe know how much money your game did?
        And what is exactly “money made by the game”? Do ads count? Do in-game purchases count?
        How can that be properly tracked without a system such as Apple’s app-store?

        What if there are in-game transactions that are done through normal HTML and the game is played in Flash?
        What if the flash web-game is a component of a bigger game or collection of games that share same revenue? What if there is a [paid] subscription game that can be played both from the web (flash player) and desktop (AiR) (I understand that for AiR games premium features licences does not apply), using the same subscription, how can Adobe track the amount of revenue produced by the web version and not by the desktop one?

        There are many many what ifs? So does Adobe only takes it into account the honesty of game developers that declare to Adobe the exact revenue they made with that particular web-based game?

        I am just saying this is still a bit unclear.

        Thanks!

  • Pingback: leebrimelow.com » An unofficial premium feature FAQ

  • JR

    Hi,
    I am working on a site that uses Away3D 4 but without ApplicationDomain.currentDomain.domainMemory. The watermark is still showing up. Pretty sure Away3D doesn’t use the domainMemory (right?). Are there other ways to address the domainMemory?

    • Anonymous

      Away3D uses domainMemory in their physics I believe, best answer will come from Away3D though.

    • ringodotnl

      Away3D isn’t using domainmemory.

      Away Physics is using Alchemy (so domainmemory), an alternative for the Away Physics would be Jiglibflash physics (http://www.jiglibflash.com).

      So if you aren’t using Away physic you shouldn’t see the watermark.

      • Anonymous

        Thanks for the clarification

  • Dan Carter

    How To Know That Your Flash Content Requires a Premium Feature License…..

    Does it today? No.
    Will it in 6 months time? As long as Adobe can find some tenuous reason then YES.