This is a read-only archive of the old Scratch 1.x Forums.
Try searching the current Scratch discussion forums.

#1 2011-04-03 04:57:09

FlySoftiii
New Scratcher
Registered: 2011-04-03
Posts: 3

Scratch Player on WP7

Hey Guys,
I am currently working (or better: want to start working) on a Scratch Player for the new WP7. But the only Project-File-Format-Specification I can find is for the V01 of the project-file format. Is there any newer specification? And can you get the Java-source the Scratch Applet?

Would be very glad if you could tell me  smile
Thank you,

FlySoft

Offline

 

#2 2011-04-03 09:40:24

wcfs96
New Scratcher
Registered: 2011-03-10
Posts: 37

Re: Scratch Player on WP7

I don't think there is a newer specification, I could try and look at the source and figure it out. And to get the Java source from the applet, download the .jar and get a decompiler for Java to view the source.

Offline

 

#3 2011-04-03 12:59:21

FlySoftiii
New Scratcher
Registered: 2011-04-03
Posts: 3

Re: Scratch Player on WP7

I already did, now I am reading the source, but I think it'll take some time. The documentation isn't very exact, so I have no chance but reading the source  hmm

Offline

 

#4 2011-04-03 17:28:44

MathWizz
Scratcher
Registered: 2009-08-31
Posts: 1000+

Re: Scratch Player on WP7

Here is the base of a player I starter in JavaScript but never finished:

(I hope this post isn't too big.  yikes )

Reader file:

Code:

var class_id = new Array();
class_id[1] = "UndefinedObject";class_id[2] = "True";class_id[3] = "False";class_id[4] = "SmallInteger";
class_id[5] = "SmallInteger16";class_id[6] = "LargePositiveInteger";class_id[7] = "LargeNegativeInteger";
class_id[8] = "Float";class_id[9] = "String";class_id[10] = "Symbol";class_id[11] = "ByteArray";
class_id[12] = "SoundBuffer";class_id[13] = "Bitmap";class_id[14] = "UTF8";class_id[20] = "Array";
class_id[21] = "OrderedCollection";class_id[22] = "Set";
class_id[23] = "IdentitySet";class_id[24] = "Dictionary";class_id[25] = "IdentityDictionary";class_id[30] = "Color";
class_id[31] = "TranslucentColor";class_id[32] = "Point";class_id[33] = "Rectangle";class_id[34] = "Form";class_id[35] = "ColorForm";
class_id[99] = "ObjectRef";class_id[100] = "Morph";class_id[101] = "BorderedMorph";class_id[102] = "RectangleMorph";
class_id[103] = "EllipseMorph";class_id[104] = "AlignmentMorph";class_id[105] = "StringMorph";class_id[106] = "UpdatingStringMorph";
class_id[107] = "SimpleSliderMorph";
class_id[108] = "SimpleButtonMorph";class_id[109] = "SampledSound";class_id[110] = "ImageMorph";class_id[111] = "SketchMorph";
class_id[123] = "SensorBoardMorph";class_id[124] = "ScratchSpriteMorph";
class_id[125] = "ScratchStageMorph";class_id[140] = "ChoiceArgMorph";class_id[141] = "ColorArgMorph";
class_id[142] = "ExpressionArgMorph";class_id[145] = "SpriteArgMorph";class_id[147] = "BlockMorph";
class_id[148] = "CommandBlockMorph";class_id[149] = "CBlockMorph";
class_id[151] = "HatBlockMorph";class_id[153] = "ScratchScriptsMorph";class_id[154] = "ScratchSliderMorph";
class_id[155] = "WatcherMorph";class_id[157] = "SetterBlockMorph";class_id[158] = "EventHatMorph";class_id[160] = "VariableBlockMorph";
class_id[162] = "ImageMedia";class_id[163] = "MovieMedia";class_id[164] = "SoundMedia";class_id[165] = "KeyEventHatMorph";
class_id[166] = "BooleanArgMorph";class_id[167] = "EventTitleMorph";class_id[168] = "MouseClickEventHatMorph";
class_id[169] = "ExpressionArgMorphWithMenu";class_id[170] = "ReporterBlockMorph";class_id[171] = "MultilineStringMorph";
class_id[172] = "ToggleButton";class_id[173] = "WatcherReadoutFrameMorph";class_id[174] = "WatcherSliderMorph";
class_id[175] = "ScratchListMorph";class_id[176] = "ScrollingStringMorph";
//var file = [];
var info;
var object;
var index = 0;
var file;
var fields;
var image;

function read(file)
{
    //file = this.file;
    if (read_header())
    {
        if (next_string(2) == 0)
        {
            println("This project is too old!");
        }
        else
        {
            println("This file is a Scratch file!");
            next_uint(4);
            info = read_object();
            var notes = info.at("comment");
            setNotes(notes);
            setHistory(info.at("history"));

            object = read_object();
        }
    }
    else
    {
        println("This file is not a Scratch file!");
    }
}

function next_byte()
{
    var b = file[index];
    index++;
    return b;
}

function next_length(length)
{
    bytes = [];
    if (length > file.length - index)
    {
        throw "Trying to read " + length + " bytes. It is longer than the file itself. Index: " + index;
        if(!confirm("Warning, this may be an error: The viewer wants to read " + length + " bytes of data. Do you wish to continue?")){return;}
    }
    for (var i = 0; i < length; i++)
    {
        bytes[i] = next_byte();
    }
    return bytes;
}

function read_header()
{
    next = next_string(8);
    println(next);
    return next == "ScratchV";
}

function next_string(length)
{
    string = "";
    for (var i = 0; i < length; i++)
    {
        string += String.fromCharCode(next_byte());
    }
    return string;
}

function next_uint(length)
{
    num = 0;
    j = 1;
    bytes = next_length(length).reverse();
    for (var i = 0; i < bytes.length; i++)
    {
        var b = bytes[i];
        num += (b * j);
        j *= 256;
    }
    return num;
}

function next_int(length)
{
    num = 0;
    j = 1;
    bytes = next_length(length);
    for (var i = 0; i < bytes.length; i++)
    {
        var b = bytes[i];
        num += (b * j);
        j *= 256;
    }
    return num;
}

function read_obj_header()
{
    return next_string(4) == "ObjS" && next_byte() == 1 && next_string(4) == "Stch" && next_byte() == 1;
}

function read_object()
{
    if (read_obj_header())
    {
        objectSize = next_uint(4);
        println("Object size: " + objectSize)

        fields = [];
        for (var fieldNum = 0; fieldNum < objectSize; fieldNum++)
        {
            field = read_field();
            fields[fieldNum] = field;
        }
        return fields[0].fix().fixClass();
    }
    else
    {
        println("Not an Object!");
    }
}

function read_field()
{
    return new FieldObject().read();
}

function FieldObject()
{
    var id;
    var name;
    var userDefined;
    var variables;
    var fixed = false;
    var fixedClass = false;
    var version;
    this.read = function()
    {
        id = next_byte();
        name = class_id[id];
        userDefined = false;
        variables = [];
        println("Reading: " + name + " id: " + id + " index: " + index);
        switch (name)
        {
            case "ObjectRef":
                variables = [next_uint(3)];
                break;
            case "UndefinedObject":
                variables = new Array();
                break;
            case "True":
                variables = new Array();
                break;
            case "False":
                variables = new Array();
                break;
            case "SmallInteger":
                variables = [next_uint(4)];
                break;
            case "SmallInteger16":
                variables = [next_uint(2)];
                break;
            case "Float":
                variables = [next_uint(4), next_uint(4)];
                break;
            case "String":
                variables = [next_string(next_uint(4))];
                break;
            case "Symbol":
                variables = [next_string(next_uint(4))];
                break;
            case "ByteArray":
                variables = next_length(next_uint(4));
                break;
            case "SoundBuffer":
                variables = next_length(next_uint(4)*2);
                break;
            case "Bitmap":
                size = next_uint(4);
                variables = new Array();
                for (i = 0; i < size; i++)
                {
                    variables[i] = next_uint(4);
                }
                break;
            case "UTF8":
                variables = [next_string(next_uint(4))];
                break;
            case "Array":
                size = next_uint(4);
                variables = new Array();
                for (i = 0; i < size; i++)
                {
                    variables[i] = read_field();
                }
                break;
            case "OrderedCollection":
                size = next_uint(4);
                variables = new Array();
                for (i = 0; i < size; i++)
                {
                    variables[i] = read_field();
                }
                break;
            case "Dictionary":
                size = next_uint(4);
                variables = new Array();
                for (i = 0; i < size; i++)
                {
                    key = read_field();
                    value = read_field();
                    variables[i] = [key, value];
                }
                break;
            case "Color":
                var color = next_uint(4);
                variables = [color >> 22 & 0xFF, color >> 12 & 0xFF, color >> 2 & 0xFF];
                break;
            case "TranslucentColor":
                var color = next_uint(4);
                variables = [color >> 22 & 0xFF, color >> 12 & 0xFF, color >> 2 & 0xFF, next_byte()];
                break;
            case "Point":
                variables = [read_field(), read_field()];
                break;
            case "Rectangle":
                variables = [read_field(), read_field(), read_field(), read_field()];
                break;
            case "Form":
                width = read_field();
                height = read_field();
                depth = read_field();
                offset = read_field();
                bits = read_field();
                variables = [width, height, depth, offset, bits];
                break;
            case "ColorForm":
                width = read_field();
                height = read_field();
                depth = read_field();
                offset = read_field();
                bits = read_field();
                colors = read_field();
                variables = [width, height, depth, offset, bits, colors];
                break;
            default:
                if(id >= 100 && id <= 176)
                {
                    version = next_byte();
                    size = next_byte();
                    variables = new Array();
                    for (i = 0; i < size; i++)
                    {
                        value = read_field();
                        variables[i] = value;
                    }
                    userDefined = true;
                }
                else
                {
                    throw "Unknown class: " + id;
                }
        }
        return this;
    };
    this.fix = function()
    {
        println("Fixing: " + name);
        if(!fixed)
        {
            fixed = true;
            switch (name)
            {
                case "ObjectRef":
                    return fields[variables[0] - 1].fix();
                    break;
                case "Array":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i] = variables[i].fix();
                    }
                    break;
                case "OrderedCollection":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i] = variables[i].fix();
                    }
                    break;
                case "Dictionary":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i][0] = variables[i][0].fix();
                        variables[i][1] = variables[i][1].fix();
                    }
                    break;
                case "Form":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i] = variables[i].fix();
                    }
                    break;
                case "ColorForm":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i] = variables[i].fix();
                    }
                    break;
                default:
                    if(userDefined)
                    {
                        for (var i = 0; i < variables.length; i++)
                        {
                            variables[i] = variables[i].fix();
                        }
                    }
            }
        }
        return this;
    };
    this.fixClass = function()
    {
        println("Fixing class: " + name);
        if(!fixedClass)
        {
            fixedClass = true;
            switch (name)
            {
                case "Array":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i] = variables[i].fixClass();
                    }
                    break;
                case "OrderedCollection":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i] = variables[i].fixClass();
                    }
                    break;
                case "Dictionary":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i][0] = variables[i][0].fixClass();
                        variables[i][1] = variables[i][1].fixClass();
                    }
                    break;
                case "Form":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i] = variables[i].fixClass();
                    }
                    break;
                case "ColorForm":
                    for (var i = 0; i < variables.length; i++)
                    {
                        variables[i] = variables[i].fixClass();
                    }
                    break;
                case "Point":
                    variables[0] = variables[0].fixClass();
                    variables[1] = variables[1].fixClass();
                    break;
                case "Rectangle":
                    variables[0] = variables[0].fixClass();
                    variables[1] = variables[1].fixClass();
                    variables[2] = variables[2].fixClass();
                    variables[3] = variables[3].fixClass();
                    break;
                default:
                    if(userDefined)
                    {
                        for (var i = 0; i < variables.length; i++)
                        {
                            variables[i] = variables[i].fixClass();
                        }
                    }
            }
        }
        return classFor(this);
    }
    this.toString = function()
    {
        switch (name)
        {
            case "ObjectRef":
                return "ObjectRef: " + variables[0];
                break;
            case "String":
                return "String: " + variables[0];
                break;
            case "UTF8":
                return "UTF8: " + variables[0];
                break;
            case "Array":
                return "Dictionary ln: " + variables.length;
                break;
            case "OrderedCollection":
                return "Dictionary ln: " + variables.length;
                break;
            case "Dictionary":
                return "Dictionary ln: " + variables.length;
                break;
            case "Form":
                return "Form";
                break;
            case "ColorForm":
                return "ColorForm ln: " + variables.length;
                break;
            default:
                return name + " ln: " + variables.length;
        }
    }
    this.getName = function() {return name};
    this.getVariables = function() {return variables};
    this.getFixed = function() {return fixed};
    this.getFixedClass = function() {return fixedClass};
    this.getId = function() {return id};
    this.getVersion = function() {return version};
    this.getUserDefined = function() {return userDefined};
}

Classes:

Code:

function classFor(obj)
{
    var objName = obj.getName();
    switch(objName)
    {
        case "String":
            return obj.getVariables()[0];
            break;
        case "UTF8":
            return obj.getVariables()[0];
            break;
        case "Symbol":
            return obj.getVariables()[0];
            break;
        case "UndefinedObject":
            return null;
            break;
        case "True":
            return true;
            break;
        case "False":
            return false;
            break;
        case "SmallInteger":
            return obj.getVariables()[0];
            break;
        case "SmallInteger16":
            return obj.getVariables()[0];
            break;
        case "Float":
            return obj.getVariables()[0];
            break;
        case "Array":
            return obj.getVariables();
            break;
        case "OrderedCollection":
            return obj.getVariables();
            break;
        case "ByteArray":
            return obj.getVariables();
            break;
        case "Dictionary":
            var result = new Dictionary();
            for (var i = 0; i < obj.getVariables().length; i++)
            {
                result.keys.push(obj.getVariables()[i][0]);
                result.values.push(obj.getVariables()[i][1]);
            }
            return result;
            break;
        case "Color":
            var result = new Color();
            result.r = obj.getVariables()[0];
            result.g = obj.getVariables()[1];
            result.b = obj.getVariables()[2];
            return result;
            break;
        case "TranslucentColor":
            var result = new TranslucentColor();
            result.r = obj.getVariables()[0];
            result.g = obj.getVariables()[1];
            result.b = obj.getVariables()[2];
            result.a = obj.getVariables()[3];
            return result;
            break;
        case "Point":
            var result = new Point();
            result.x = obj.getVariables()[0];
            result.y = obj.getVariables()[1];
            return result;
            break;
        case "Rectangle":
            var result = new Rectangle();
            result.x = obj.getVariables()[0];
            result.y = obj.getVariables()[1];
            result.cornerX = obj.getVariables()[2];
            result.cornerY = obj.getVariables()[3];
            return result;
            break;
        case "Form":
            var result = new Form();
            result.width = obj.getVariables()[0];
            result.height = obj.getVariables()[1];
            result.depth = obj.getVariables()[2];
            result.offset = obj.getVariables()[3];
            result.bits = obj.getVariables()[4];
            return result;
            break;
        case "ColorForm":
            var result = new ColorForm();
            result.width = obj.getVariables()[0];
            result.height = obj.getVariables()[1];
            result.depth = obj.getVariables()[2];
            result.offset = obj.getVariables()[3];
            result.bits = obj.getVariables()[4];
            result.colors = obj.getVariables()[5];
            return result;
            break;
        case "Bitmap":
            return obj.getVariables();
            break;
        case "SoundBuffer":
            return obj.getVariables();
            break;
        default:
            if(obj.getUserDefined())
            {
                if(false)//obj.getName() == "ScratchStageMorph")
                {
                    var result = new ScratchStageMorph();
                    result.init(obj.getVariables());
                }
                else
                {
                    var result = new Morph();
                    result.version = obj.getVersion();
                    result.variables = obj.getVariables();
                }
                return result;
            }
    }
    throw "Unknown class: " + obj.getId();
}

function Dictionary()
{
    this.keys = [];
    this.values = [];

    this.at = function(key)
    {
        for(var i = 0; i < this.keys.length; i++)
        {
            if(key == this.keys[i])
            {
                return this.values[i];
            }
        }
        return null;
    }
}

function Morph()
{
    this.version = 0;
    this.variables = [];
}

function ScratchStageMorph()
{
    this.init = function(vars)
    {
        this.bounds = vars[0];
        this.owner = vars[1];
        this.submorphs = vars[2];
        this.color = vars[3];
        this.flags = vars[4];
        this.objName = vars[5];
        this.vars = vars[6];
        this.blocksBin = vars[7];
        this.isClone = vars[8];
        this.media = vars[9];
        this.costume = vars[10];

        this.zoom = vars[11];
        this.hPan = vars[12];
        this.vPan = vars[13];
        this.obsoleteSavedState = vars[14];
        this.sprites = vars[15];
        this.volume = vars[16];
        this.tempoBPM = vars[17];
        this.sceneStates = vars[18];
        this.lists = vars[19];
    }
}

function Color()
{
    this.r = 0;
    this.g = 0;
    this.b = 0;
}

function TranslucentColor()
{
    this.r = 0;
    this.g = 0;
    this.b = 0;
    this.a = 0;
}

function Point()
{
    this.x = 0;
    this.y = 0;
}

function Rectangle()
{
    this.x = 0;
    this.y = 0;
    this.cornerX = 0;
    this.cornerY = 0;
}

function Form()
{
    this.width = 0;
    this.height = 0;
    this.depth = 0;
    this.offset = 0;
    this.bits = [];
}

function ColorForm()
{
    this.width = 0;
    this.height = 0;
    this.depth = 0;
    this.offset = 0;
    this.bits = [];
    this.colors = [];
}

Last edited by MathWizz (2011-04-03 17:30:18)


http://block.site90.net/scratch.mit/text.php?size=30&amp;text=%20A%20signature!&amp;color=333333

Offline

 

#5 2011-04-04 11:06:23

FlySoftiii
New Scratcher
Registered: 2011-04-03
Posts: 3

Re: Scratch Player on WP7

I dicedet to make my own project format, with a more or less comfortable editor ;-)

Thank you all anyway!

Offline

 

Board footer