Reading DWORD incorrectly with AS3? - actionscript-3

In this question I got an answer on how to use this information to read BLB files. So I followed the instructions, and it appears that I'm reading the header properly.
However, when I try to read the file IDs, I get an end of file runtime error:
[Fault] exception, information=Error: Error #2030: End of file was encountered.
Here's my code.
Base class:
package
{
import flash.display.Sprite;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;
import flash.utils.IDataInput;
import flash.filesystem.FileMode;
public class BLBDecompress extends Sprite
{
private var _file:File;
private var _stream:FileStream;
private var _blbBytes:ByteArray;
private var _header:Header;
private var _fileIDs:Array;
public function BLBDecompress()
{
decompress();
}
private function decompress():void
{
_file = File.applicationDirectory.resolvePath("testfiles/t.blb");
_blbBytes = new ByteArray();
_stream = new FileStream();
_stream.open(_file, FileMode.READ);
_stream.readBytes(_blbBytes);
_stream.close();
_header = readHeader(_blbBytes);
_fileIDs = new Array();
for (var i:int = 0; i < _header.dwNumber; i++)
{
_fileIDs.push(readFileID(_blbBytes));
}
}
private function readHeader(input:IDataInput):Header
{
var header:Header = new Header();
header.szID = new ByteArray();
input.readBytes(header.szID, 0, 4);
header.bID = input.readUnsignedByte();
header.bUnknown = input.readUnsignedByte();
header.wDataSize = input.readUnsignedShort();
header.dwFileSize = input.readUnsignedInt();
header.dwNumber = input.readUnsignedInt();
return header;
}
private function readFileID(input:IDataInput):uint
{
var fileID:uint = input.readUnsignedInt();
return fileID;
}
}
}
Header class:
package
{
import flash.utils.ByteArray;
public class Header
{
public var szID:ByteArray;
public var bID:uint;
public var bUnknown:uint;
public var wDataSize:uint;
public var dwFileSize:uint;
public var dwNumber:uint;
public function Header()
{
}
}
}
The thing is that _header.dwNumber returns/traces as 1090650112 (41020000 in base 16), so I can imagine that would reach the end of the file. So am I reading it wrong, using it wrong, or doing something else wrong? The rest of the
If it helps, this is an AIR application, and I'm using FlashDevelop with the Flex 4 SDK.

That look like a simple Big/Little endian problem, the 4 bytes that make up the DWORD are in the file in a different order to that used by your processor.
You need to reverse the order of the bytes in the DWORD to get 00000241, and any other multibyte number

Related

Unable to clone vector with deep copy of objects

This is my vector that I want to fully clone (meaning that if I change the cloned vector it doesn't affect the original vector).
var vector:Vector.<Path_Tiles> = new Vector.<Path_Tiles>();
vector = path_finder.Find_Path(Gird.TILE_SET, start, end, R_G_B, SCAREDNESS);// return a vector of path_tiles in order
and I'm trying to put it into this vector
var vector2:Vector.<Path_Tiles> = clone(vector);
and clone method is this (which I found this method on a website so I do not fully understand it)
public function clone(source:Object):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
But I'm getting this error: "[Fault] exception, information=TypeError: Error #1034: Type Coercion failed: cannot convert AS3.vec::Vector.#85973d1 to AS3.vec.Vector.."
How do I convert Path_Tiles into an object?
Assure your Path_Tiles class has been registered:
flash.net.registerClassAlias("tld.domain.package.Path_Tiles", Path_Tiles);
Then, you may copy by serializing the data to a ByteArray:
var tiles:Vector.<Path_Tiles>;
var tilesCloned:Vector.<Path_Tiles>;
var byteArray = new ByteArray();
byteArray.writeObject(tiles);
byteArray.position = 0;
tilesCloned = byteArray.readObject() as Vector.<Path_Tiles>;
Cast the readObject() deserialization to Vector.<Path_Tiles> using the as keyword.
Constructors for objects serialized must accept default parameters.
To put this all together, say this was your Path_Tiles class:
Path_Tiles.as
package
{
public class Path_Tiles
{
public function Path_Tiles(property1:String=null, property2:int=undefined) {
this.property1 = property1;
this.property2 = property2;
}
public var property1:String;
public var property2:int;
}
}
Here is your main class, showing an example of deep cloning the Path_Tiles collection:
Main.as
package
{
import flash.display.Sprite;
import flash.net.registerClassAlias;
import flash.utils.ByteArray;
public class Main extends Sprite
{
public function Main() {
super();
var source:Vector.<Path_Tiles> = new <Path_Tiles>[
new Path_Tiles("Hello", 1),
new Path_Tiles("World", 2)
];
var cloned:Vector.<Path_Tiles> = clone(source);
}
public function clone(source:Vector.<Path_Tiles>):Vector.<Path_Tiles> {
flash.net.registerClassAlias("Path_Tiles", Path_Tiles);
var byteArray = new ByteArray();
byteArray.writeObject(source);
byteArray.position = 0;
return byteArray.readObject() as Vector.<Path_Tiles>;
}
}
}
Finally, we can see the object was deep copied; confirmed by memory address:

What is the proper way to add a SharedObject to a .AS file?

Having trouble adding a SharedObject to a .AS file, I am trying to add the users name to the .flv file in red 5 like "username_myfile" I am not sure I am adding the code thats saves the name in the correct part of the class. is there a proper way to add a SharedObject to a .AS file?
--
added:
import flash.net.SharedObject;
package app
{
import flash.display.BitmapData;
import flash.display.Stage;
import flash.external.ExternalInterface;
**import flash.net.SharedObject;**
public class DataHolder
{
private static var dataHolder:DataHolder;
public var savedstuff:SharedObject = SharedObject.getLocal("myStuff2","/");
if (savedstuff.size > 0)
{
public var username = savedstuff.data.username;
}
public var filename:String = (String(username) + "_myfile");
public var rtmpPath:String = "rtmp://numbershere.compute-1.amazonaws.com/oflaDemo/";
public var recorder:Recorder;
public var navigation:Navigation;
public var cameraFPS:Number = 30;
public var cameraWidth:Number = 640;
public var cameraHeight:Number = 480;
public var cameraQuality:Number = 88;// camera quality
public var timelimit:Number = 25;// limit count of seconds
public var stage:Stage;
public function DataHolder()
{
if (dataHolder)
{
throw new Error("Only one DataHolder instance should be instantiated");
}
}
public static function getInstance():DataHolder
{
if (dataHolder == null)
{
dataHolder = new DataHolder();
}
return dataHolder;
}
}
}
Remove the conditional declaration of your shared object and declare as usual, ie:
private var savedStuff:SharedObject;
Then, in your constructor:
try {
savedStuff = SharedObject.getLocal("savedData");
} catch (error) {
cookiesActive = false;
};
Then check cookiesActive==true to save data to the SharedObject, eg:
if (cookiesActive) {
savedStuff.data.levelsFinished = 1;
}

Better way to send voice over a socket in AS3

I made an AIR application that sends voice between two computers, this is the code:
package
{
import fl.controls.List;
import flash.events.ProgressEvent;
import flash.events.SampleDataEvent;
import flash.events.ServerSocketConnectEvent;
import flash.media.Microphone;
import flash.media.Sound;
import flash.net.ServerSocket;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.system.System;
public class VoiceCommunication
{
private var soundBytes:ByteArray;
private var mic:Microphone;
private var voiceReceiver:ServerSocket;
private var voiceSender:Socket;
private var mLocalIP:String;
private var mRemoteIP:String;
private var mPort:uint;
private var sound:Sound;
private var sample:Number;
public function VoiceCommunication(localIP:String, port:uint)
{
mLocalIP = localIP;
mPort = port;
}
public function startSendingVoice(remoteIP:String = null):void
{
mic = Microphone.getMicrophone();//2-null
mic.gain = 100;
mic.rate = 44;
voiceSender = new Socket();//3-null
mRemoteIP = remoteIP;//5-null
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler);//1-remove eventlistener
}
protected function micSampleDataHandler(event:SampleDataEvent):void
{
if(mRemoteIP != null)
{
voiceSender.connect(mRemoteIP, mPort);
while(event.data.bytesAvailable)
{
sample = event.data.readFloat();
voiceSender.writeFloat(sample);
}
voiceSender.flush();
}
}
public function startReceivingVoice():void
{
voiceReceiver = new ServerSocket;//2
voiceReceiver.bind(mPort, mLocalIP);
voiceReceiver.addEventListener(ServerSocketConnectEvent.CONNECT, handleConnection);//1
voiceReceiver.listen();
}
protected function handleConnection(event:ServerSocketConnectEvent):void
{
var s:Socket = event.socket as Socket;
s.addEventListener(ProgressEvent.SOCKET_DATA, handleData);
}
protected function handleData(event:ProgressEvent):void
{
event.target.removeEventListener(ProgressEvent.SOCKET_DATA, handleData);
var s:Socket = event.target as Socket;
soundBytes = null;
soundBytes = new ByteArray();//3
s.readBytes(soundBytes);
playSound();
s = null;
}
private function playSound():void
{
soundBytes.position = 0;
sound = null;
sound = new Sound();//5
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler, false, 0, true);//4
sound.play();
}
protected function playbackSampleHandler(event:SampleDataEvent):void
{
sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler);
for (var i:int = 0; i < 8192 && soundBytes.bytesAvailable > 0; i++)
{
sample = soundBytes.readFloat();
event.data.writeFloat(sample);
event.data.writeFloat(sample);
}
System.gc();
}
public function destroySender():void
{
mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler);
mic = null;
voiceSender = null;
mRemoteIP = null;
System.gc();
}
public function destroyReceiver():void
{
voiceReceiver.removeEventListener(ServerSocketConnectEvent.CONNECT, handleConnection);//1
voiceReceiver = null;
soundBytes = null;
sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler);
sound = null;
System.gc();
}
}
}
This works fine and when I tried it, it did send the voice, but the problem is that sending the voice is too slow and gets split. So is there a better way to do it?
I rewrote it using datagram socket but that didn't work at all, the code:
package
{
import fl.controls.List;
import flash.events.DatagramSocketDataEvent;
import flash.events.ProgressEvent;
import flash.events.SampleDataEvent;
import flash.events.ServerSocketConnectEvent;
import flash.media.Microphone;
import flash.media.Sound;
import flash.net.DatagramSocket;
import flash.net.ServerSocket;
import flash.net.Socket;
import flash.system.System;
import flash.utils.ByteArray;
public class VoiceComm
{
private var soundBytes:ByteArray;
private var mic:Microphone;
private var socket:DatagramSocket
private var mList:List;
private var mLocalIP:String;
private var mRemoteIP:String;
private var mPort:uint;
private var sound:Sound;
private var sample:Number;
private var bytesToBeSent:ByteArray;
public function VoiceComm(localIP:String, port:uint)
{
socket = new DatagramSocket();
mLocalIP = localIP;
mPort = port;
}
public function startSendingVoice(remoteIP:String = null):void
{
mic = Microphone.getMicrophone();
mic.gain = 100;
mic.rate = 44;
mRemoteIP = remoteIP;
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler);
}
protected function micSampleDataHandler(event:SampleDataEvent):void
{
var sample:Number;
if(mRemoteIP != null)
{
while(event.data.bytesAvailable)
{
sample = event.data.readFloat();
bytesToBeSent = null;
bytesToBeSent = new ByteArray();
bytesToBeSent.writeFloat(sample);
socket.send(bytesToBeSent, 0, 0, mRemoteIP, mPort);
}
}
}
public function startReceivingVoice():void
{
socket.bind(mPort, mLocalIP);
socket.addEventListener(DatagramSocketDataEvent.DATA, handleData);
socket.receive();
}
protected function handleData(event:DatagramSocketDataEvent):void
{
trace("Data inthere!");
soundBytes = null;
soundBytes = new ByteArray();//3
event.data.readBytes(soundBytes);
playSound();
}
private function playSound():void
{
soundBytes.position = 0;
sound = null;
sound = new Sound();//5
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler, false, 0, true);//4
sound.play();
}
protected function playbackSampleHandler(event:SampleDataEvent):void
{
sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler);
for (var i:int = 0; i < 8192 && soundBytes.bytesAvailable > 0; i++)
{
sample = soundBytes.readFloat();
event.data.writeFloat(sample);
event.data.writeFloat(sample);
}
System.gc();
}
public function destroySender():void
{
mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler);
mic = null;
mList = null;
mRemoteIP = null;
System.gc();
}
public function destroyReceiver():void
{
soundBytes = null;
sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler);
sound = null;
System.gc();
}
}
}
**Update:
The code after modification:
package
{
import fl.controls.List;
import flash.events.DatagramSocketDataEvent;
import flash.events.SampleDataEvent;
import flash.media.Microphone;
import flash.media.Sound;
import flash.net.DatagramSocket;
import flash.net.Socket;
import flash.system.System;
import flash.utils.ByteArray;
public class VoiceComm
{
private var mic:Microphone;
private var soundBytes:ByteArray;
private var sample:Number;
private var sound:Sound;
private var socket:DatagramSocket;
private var mLocalIP:String;
private var mPort:uint;
private var mRemoteIP:String;
private var receivedBytes:ByteArray;
public function VoiceComm(localIP:String, port:uint)
{
socket = new DatagramSocket();
mLocalIP = localIP;
mPort = port;
}
//destroyers:
public function destroySender():void
{
mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, sampleData);
mic = null;
soundBytes = null;
System.gc();
}
public function destroyReceiver():void
{
socket.removeEventListener(DatagramSocketDataEvent.DATA, playSound);
receivedBytes = null;
System.gc();
}
//sending part
public function startSendingVoice(ip:String = null):void
{
mRemoteIP = ip;
mic = Microphone.getMicrophone();
mic.rate = 44;
mic.gain = 100;
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, sampleData);
}
protected function sampleData(event:SampleDataEvent):void
{
soundBytes = new ByteArray();
while(event.data.bytesAvailable)
{
var sample:Number = event.data.readFloat();
soundBytes.writeFloat(sample);
}
if(mRemoteIP != null)
{
event.data.position = 0;
socket.send(soundBytes, 0, event.data.length, mRemoteIP, mPort);
}
}
//receiving part
public function startReceivingVoice():void
{
socket.bind(mPort, mLocalIP);
socket.addEventListener(DatagramSocketDataEvent.DATA, playSound);
socket.receive();
}
protected function playSound(event:DatagramSocketDataEvent):void
{
trace("got data!");
receivedBytes = new ByteArray();
event.data.readBytes(receivedBytes);
receivedBytes.position = 0;
var sound:Sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler, false, 0, true);
sound.play();
}
protected function playbackSampleHandler(event:SampleDataEvent):void
{
trace("Playing Sound...");
for (var i:int = 0; i < 8192 && receivedBytes.bytesAvailable > 0; i++)
{
var sample:Number = receivedBytes.readFloat();
event.data.writeFloat(sample);
event.data.writeFloat(sample);
System.gc();
}
}
}
}
This is most likely the source of the issue: http://forums.adobe.com/message/3111816. The TCP Nagle Algorithm. What this basically does is, when you're writing a bunch of small chunks of data to the socket, instead of sending them all out individually it will hold them back and pool them together in order to send a single "full" packet rather than tons of small ones (which leads to a greater, constant load on the network).
If possible, re-write using Datagram sockets instead. To my knowledge there is currently no way to disable the Nagle algorithm in Flash.
Update
A couple things after looking at your code in depth: The first is that you're writing each byte one at a time to the TCP socket. Don't do that, write the entire bytearray and flush it.
if(mRemoteIP != null)
{
voiceSender.connect(mRemoteIP, mPort);
voiceSender.writeBytes(event.data, 0, event.data.length);
voiceSender.flush();
}
That may solve the issues you're having. If not, the reason why your UDP version is for two reasons. The first is that again, you're writing one byte at a time and sending but more important, you're telling it not to write the data to the socket at all. This line is the culprit:
socket.send(bytesToBeSent, 0, 0, mRemoteIP, mPort);
Note the third paramter, "0". That parameter is the amount of data from the supplied bytearray that should be written to the socket. So you're essentially saying, don't send anything. Change the code like so:
if(isConnected == true)
{
event.data.position = 0;
localSendingSocket.send(event.data, 0, event.data.length, remoteIP, remotePort);
}
Let me know if this works out for you. In the meantime I'm re-writing your code based on these suspicions so if I manage to get a project compiled and working before you, I'll post the project files here.
Where not use Adobe Cirrus (formerly Stratus to create a peer2peer application instead of the socket?
use the (OS) Red5 server.
http://www.red5.org/
the blurb:
"Red5 Media Server 1.0 delivers a powerful video streaming and multi-user solution to the ©Adobe ©Flash Player and other exciting client technologies. Based on Java and some of the most powerful open source frameworks, Red5 stands as a solid solution for business of all sizes including the enterprise.
Red5 includes support for the latest multi-user API’s including NetConnection, NetStream and SharedObject’s while providing a powerful RTMP / Servlet implementation. In addition to support for the RTMP protocol, the application server has an embedded Tomcat Servlet container for Java EE Web Applications. Application development draws additional benefits from the Spring Framework and Scope based event driven services.
By using the Open Source Red5 Media Server, you are developing with a truly open and extensible platform that can be used in Video Conferences, Multi-User Gaming and Enterprise Application Software.
Happy Coding and enjoy our powerful free community server"

Error #1034, with a MouseEvent

I am making a basic point n' click game and I came upon this error:
TypeError: Error #1034: Type Coercion failed: cannot convert 3 to cem.mouvement.
Here's my script:
package cem {
import flash.events.Event;
import flash.display.MovieClip;
import cem.microjeux.events.InfoJeuEvent;
import cem.mouvement;
import flash.events.MouseEvent;
public class monterJeu extends MovieClip
{
private static var pType:String = "type";
private static var pNom:String = "testNom";
private static var pCourriel:String = "test#hotmail.com";
private static var pDifficulte:int = 0;
private static var pLangue:int = 0;
private static var pTitre:String = "Veuillez sortir";
private static var pVersion:String = "1.5";
private static var pCoordonnees:Number;
private var environnementJeu:environnement = new environnement();
private var personnageJeu:personnage = new personnage();
public function monterJeu():void
{
jouer(pNom,pDifficulte,pLangue);
dispatchEvent(new InfoJeuEvent(pType,pNom,pCourriel,pTitre,pVersion));
stage.addEventListener(MouseEvent.CLICK, test);
}
public function jouer(PNom:String,PDifficulte:int,PLangue:int):void
{
addChild(environnementJeu);
addChild(personnageJeu);
}
function test(e:MouseEvent){
pCoordonnees = stage.mouseX;
trace(pCoordonnees);
mouvement(3);
}
}
}
And on mouvement();
package cem
{
public class mouvement {
public function mouvement(blabla) {
trace(blabla);
}
}
}
I searched everywhere I could, and didn't find anything. I have no instances on the stage. Everything is imported on the first frame. I am kind of a beginner (let's say i'm no good at programming), so you can notify at the same time if you something that needs to be corrected. (BTW, the strange words are in french ;D)
Thanks!
The error is due to you trying to cast 3 to mouvement.
I think what you want is something like
function test(e:MouseEvent){
pCoordonnees = stage.mouseX;
trace(pCoordonnees);
var mouve:mouvement = new mouvement(3);
}
Notice that you have to have new in order to create a new instance of a class.
On another note, you should capitilize classes so they stand out better. So I would name the class Mouvement.
You are trying to cast 3 to the class mouvement into the test function:
function test(e:MouseEvent){
pCoordonnees = stage.mouseX;
trace(pCoordonnees);
new mouvement().mouvement(3); // <-- here your error
}
If you have only a function into your class you don't need to create a class but you can put on the function alone:
package cem
{
public function mouvement(blabla):void {
trace(blabla);
}
}
and now you can call the mpuvement function normally into you test function:
function test(e:MouseEvent){
pCoordonnees = stage.mouseX;
trace(pCoordonnees);
mouvement(3);
}

The right way to send variables with as3 to asp?

Im trying to make an swf send a phone-number to a specific asp-fil on the press of a button.
But since I'm an as3 rookie I have no idea where this code is going wrong (PLEASE HELP):
import flash.events.IOErrorEvent;
import flash.display.*;
import flash.events.MouseEvent;
import flash.net.*;
import flash.events.Event;
public class action extends MovieClip
{
private var swf_front_mc:swf_front = new swf_front ;
var request:URLRequest = new URLRequest("succes.html");
var request2:URLRequest = new URLRequest("http://www.example.com");
public var mobilNr:Number = new Number(swf_front_mc.mobilInput.text);
public var varsToSend:URLVariables = new URLVariables();
public function action()
{
addChild(swf_front_mc);
swf_front_mc.name = "swf_front_mc";
swf_front_mc.x = 0;
swf_front_mc.y = 0;
makeInteraction();
}
private function makeInteraction():void
{
swf_front_mc.submit_mc.addEventListener(MouseEvent.CLICK, submitForm);
}
function submitForm(e:MouseEvent):void
{
//trace("hello");
varsToSend.RecipientMobileNumber = mobilNr;
// Create URL Request, set to POST, and attach data
var formRequest:URLRequest = new URLRequest("webform_input.asp");
formRequest.method = URLRequestMethod.GET;
formRequest.data = varsToSend;
// Create URL Loader, attach listeners, and load URL Request
var varLoader:URLLoader = new URLLoader ;
varLoader.addEventListener(Event.COMPLETE, onLoaded);
varLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
varLoader.load(formRequest);
}
function onLoaded(e:Event):void
{
navigateToURL(request,"blank");
}
function ioErrorHandler(e:IOErrorEvent):void
{
navigateToURL(request2,"blank");
}
}
Thanks for the tips and hints guys...
Meanwhile i got the perfect solution from a friend. It's much shorter and more simple then I thought possible. Here it is:
package app.form
{
import flash.net.*;
import flash.display.*;
import flash.events.*;
public class container extends MovieClip
{
public function container()
{
sendBtn.addEventListener(MouseEvent.CLICK, sendBtnClick);
}
public function SendToURLExample(_navn:String, _tlf:String) {
var url:String = "http://www.yourdomain.com/file.asp";
var variables:URLVariables = new URLVariables();
variables.name = _name;
variables.phone = _phone;
var request:URLRequest = new URLRequest(url);
request.data = variables;
trace("sendToURL: " + request.url + "?" + request.data);
try {
sendToURL(request);
}
catch (e:Error) {
// handle error here
}
}
// two text-example-fields on stage called input_text_name/input_text_mobil
private function sendBtnClick(e:MouseEvent):void {
SendToURLExample(input_text_name.text, input_text_mobil.text);
}
}
}
Hope this will solve the something for someone out there :)
try this one example
http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/net/URLVariables.html#includeExamplesSummary
or you can try to encode your vat into GET URL like new URLRequest("localhost/?number="+numberField.text);
but first one try navigatetourl method from previous sample.
p.s. look at this too: http://blog.flexexamples.com/2007/08/16/using-httpservice-tag-to-sendreceive-variables-to-a-server-side-script/