Trying to create a simple command-line application in Haxe which has a ticking Timer, but it does not seem to work out; the Timer never actually starts 'ticking'.
package;
import haxe.Timer;
class TimerCallback {
private static inline var CHAR_SPACE : Int = 32;
public static function main() : Void {
var myME = new TimerTicker();
while (Sys.getChar(false) != CHAR_SPACE) {
//loop until [space] detected, do nothing here
}
}
}
class TimerTicker {
private var myTimer : Timer = null;
public function new() {
myTimer = new Timer(20);
myTimer.run = timer_OnTick;
}
private function timer_OnTick() : Void {
Sys.println ("foobar");
}
/* destructor?! */
}
And this is the build command:
>haxe.exe -lib nme -main TimerCallback -cpp .\bin
If I am not adding -lib nme, the code does not compile (based on API doc it's OK as Timer is not supported for cpp, so only static functions are available)
If I am adding this, however, the code is compiled -as nme supports cpp Timers-, and the exe is created (win), but timer_OnTick() is never called. So exe starts, nothing happens, one press SPACE and app. quits.Additional info:
- The imported Timer.hx file is this one: haxe\lib\nme\5,1,8\haxe. And if I am right, this should be OK & working.
- Using haxe 3.1.3, nme 5.1.8, hxcpp 3.1.39 (and haxelib 3.1.0-rc.4 if matters)Any help would be much appreciated.
Okay, I've got help from the Haxe Community (mailing list). Here are the solutions if anyone happen to need them:PSEUDO CODE (not tested)
class RunLoop {
static var queue = new Deque<Void->Void>();
static var keepAlives:Int; = 1;
static public function release()
enque(function () keepAlives--);
static public function retain()
enque(function () keepAlives++);
static public function enque(task:Void->Void)
queue.add(task);
static function main() {
enque(entryPoint);
release();
}
static function entryPoint() {
//code goes here
}
static function run()
while (keepAlives:Int > 0)
queue.pop()();
}
//Now you can go an implement a timer like so:
class Timer {
var active:Bool = true;
public function new(msecs:Int) {
RunLoop.retain();
Thread.create(function () while(active) {
Sys.sleep(msecs / 1000);
if (active)
RunLoop.enque(this.run);
});
}
public dynamic function run() {}
public function stop() {
active = false;
RunLoop.release();
}
}
//And a helper for blocking code:
class Task {
var task:Void->T;
var onDone:T->Void;
public function new(task:Void->T, onDone:T->Void) {
RunLoop.retain();
Thread.create(function () {
var result = task();
RunLoop.enque(onDone.bind(result));
});
}
}
//So then the code you want would look roughly like this:
static function entryPoint() {
var timer = new Timer();
timer.run = function () trace('foobar');
function waitForSpace() {
while (Sys.getChar(false) != CHAR_SPACE) {
//loop until [space] detected, do nothing here
}
return true;
}
new Task(
waitForSpace,
function (_) timer.stop() //stop the timer so that the run loop can exit
);
} (solution provided by back2dos)
/*
1. Neko : works
2. C++: works, However, incrementing count in the if statement instead ( if( count++ == 0 ) { ... ) fails to increment count! Fixed on Git?
3. Flash : works
4. Java : fails using Haxe 3.1.3
*/
### build.hxml ###
-main Main
-swf main.swf
-swf-version 12
--next
-main Main
-neko main.n
--next
-main Main
-cpp cpp
-cmd cp cpp/Main ./main
--next
-main Main
-java java
-cmd cp java/Main.jar ./main-jar
### Main.hx ###
class Main {
public static function main() {
#if sys
var count = 0;
while( true ) {
if( count == 0 ) {
Timer.delay(function() trace("doThing1"), 3000);
Timer.delay(function() trace("doThing2"), 1000);
count++;
}
}
#else
Timer.delay(function() trace("doThing1"), 3000);
Timer.delay(function() trace("doThing2"), 1000);
#end
}
}
### Timer.hx ###
#if neko
import neko.vm.Deque;
import neko.vm.Thread;
import neko.vm.Mutex;
import neko.vm.Lock;
#elseif cpp
import cpp.vm.Deque;
import cpp.vm.Thread;
import cpp.vm.Mutex;
import cpp.vm.Lock;
#elseif java
import java.vm.Deque;
import java.vm.Thread;
import java.vm.Mutex;
import java.vm.Lock;
#end
class Timer {
#if sys
static var timerThread : TimerThread;
#else
static var timers : Array;
#end
static function __init__() {
#if sys
timerThread = new TimerThread();
#else
timers = [];
#end
}
public static function stop() {
#if sys
timerThread.quit();
#else
for( t in timers )
t.stop();
#end
}
public static function delay( func : Void -> Void, delayMillis : Int ) {
#if sys
timerThread.addTimer(delayMillis/1000, func);
#else
timers.push( haxe.Timer.delay(func, delayMillis) );
#end
}
}
#if sys
typedef TTimerData = {
time : Float,
func : Void -> Void
}
class TimerThread {
var mutex : Mutex;
var queueLock : Lock;
var queue : Array;
var running : Bool;
public function new() {
queue = [];
queueLock = new Lock();
mutex = new Mutex();
running = true;
Thread.create( mainLoop );
}
public function addTimer( delaySec : Float, cb : Void -> Void ) {
mutex.acquire();
var time = haxe.Timer.stamp() + delaySec;
var index = 0;
while( index < queue.length && time >= queue[index].time )
index++;
queue.insert(index, { time : time, func : cb });
mutex.release();
queueLock.release();
}
public function quit( ?cb : Void -> Void ) {
var me = this;
addTimer( 0, function() {
me.running = false;
if( cb != null )
cb();
} );
}
function mainLoop() {
while( running ) {
var wake : Null = null;
var now = haxe.Timer.stamp();
var ready = new Array();
mutex.acquire();
while( queue.length > 0 )
if( queue[0].time <= now )
ready.push(queue.shift());
else {
wake = queue[0].time;
break;
}
mutex.release();
for( d in ready ) {
d.func();
if( !running )
break;
}
if( !running )
break;
if( wake == null )
queueLock.wait();
else {
var delay = wake - haxe.Timer.stamp();
if( delay > 0 )
queueLock.wait(delay);
}
}
}
}
#end
(Solution provided by Zjnue, modified code of Hugh)
Related
I want to use functions as keys in a Map like this:
var timers : Map<Void->Void, snow.api.Timer>;
But Haxe won't compile:
Abstract Map has no #:to function that accepts IMap<Void -> Void, snow.api.Timer>
Is there a way to do this ?
It's easy to write a custom implementation:
import haxe.Constraints;
class FunctionMap<K:Function,V> implements IMap<K,V> {
private var _keys : Array<K>;
private var _values : Array<V>;
public function new () {
_keys = [];
_values = [];
}
public function get(k:K):Null<V> {
var keyIndex = index(k);
if (keyIndex < 0) {
return null;
} else {
return _values[keyIndex];
}
}
public function set(k:K, v:V):Void {
var keyIndex = index(k);
if (keyIndex < 0) {
_keys.push(k);
_values.push(v);
} else {
_values[keyIndex] = v;
}
}
public function exists(k:K):Bool {
return index(k) >= 0;
}
public function remove(k:K):Bool {
var keyIndex = index(k);
if (keyIndex < 0) {
return false;
} else {
_keys.splice(keyIndex, 1);
_values.splice(keyIndex, 1);
return true;
}
}
public function keys():Iterator<K> {
return _keys.iterator();
}
public function iterator():Iterator<V> {
return _values
.iterator();
}
public function toString():String {
var s = new StringBuf();
s.add("{");
for( i in 0..._keys.length ) {
s.add('<function>');
s.add(" => ");
s.add(Std.string(_values[i]));
if( i < _keys.length - 1 )
s.add(", ");
}
s.add("}");
return s.toString();
}
private function index(key:K) : Int {
for (i in 0..._keys.length) {
if (Reflect.compareMethods(key, _keys[i])) {
return i;
}
}
return -1;
}}
http://try.haxe.org/#DdF31
I just tried this in try.haxe.org, and the compiler doesn't seem to like it, so I'm guessing the answer is "no."
You could get around this with some cleverness:
class Test {
static function main() {
var map:Map<VoidVoid,String>;
map = new Map<VoidVoid,String>();
var thing = {func:foo};
map.set(thing,"bar");
trace(map.get({func:foo})); //fails
trace(map.get(thing)); //succeeds;
}
static function foo():Void
{
}
}
typedef VoidVoid = {
var func:Void->Void;
}
But that's not an ideal solution because wrapping it in a typedef like that will make it fail if it's not the exact same instance, even if the value inside is the same.
I also tried making a Map<Dynamic,String> since you can stuff function references in those, but that didn't work either.
At this point I should ask, what problem are you trying to solve this way? Perhaps it could be better solved some other way.
Adobe security setting popups
I am using flash player for audio recording purpose. I want 1st popup but may program showing 2nd popup. How get I get first popup
My Action Script Code is given below.
package
{
import fr.kikko.lab.ShineMP3Encoder;
import flash.events.ErrorEvent;
import flash.events.ProgressEvent;
import flash.events.StatusEvent;
import flash.display.Sprite;
import flash.media.Microphone;
import flash.system.Security;
import org.bytearray.micrecorder.*;
import org.bytearray.micrecorder.events.RecordingEvent;
import org.bytearray.micrecorder.encoder.WaveEncoder;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.events.ActivityEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import flash.display.LoaderInfo;
import flash.external.ExternalInterface;
import flash.media.Sound;
import org.as3wavsound.WavSound;
import org.as3wavsound.WavSoundChannel;
public class Main extends Sprite
{
// private var recBar:RecBar = new RecBar();
private var mic:Microphone;
private var waveEncoder:WaveEncoder = new WaveEncoder();
private var recorder:MicRecorder = new MicRecorder(waveEncoder);
private var maxTime:Number = 30; // default time to record in seconds
private var tts:WavSound;
private var playingChannel:WavSoundChannel;
private var mp3Encoder:ShineMP3Encoder;
private var mp3done:Boolean = false; // if we done converting to mp3
private var wasRecorded:Boolean = false; // if we done recording
private var isPreviewing:Boolean = false; // if we are in previewing state now?
private var isConverting:Boolean = false; // if we are in converting state now?
public function Main():void
{
mic = Microphone.getMicrophone();
mic.setSilenceLevel(mic.activityLevel);
mic.gain = 50;
mic.setLoopBack(false);
mic.setUseEchoSuppression(true);
recorder.addEventListener(RecordingEvent.RECORDING, recording);
addCommands();
}
public function jStartRecording(max_time:Number):void
{
if (mic != null) {
mp3done = false;
wasRecorded = false;
maxTime = max_time;
recorder.record();
// recorder.microphone.addEventListener(StatusEvent.STATUS, onMicStatus);
ExternalInterface.call("justrec.recordingStarted");
}
else
{
ExternalInterface.call("justrec.recordingError");
}
}
public function jStopRecording():void
{
recorder.stop();
wasRecorded = true;
mic.setLoopBack(false);
ExternalInterface.call("justrec.recordingStopped");
}
public function jPreview():void
{
if(wasRecorded) {
previewRecording();
}
}
public function jStopPreview():void
{
if(isPreviewing) {
stopPreviewRecording();
}
}
// convert WAV to MP3
public function jConvert2MP3():void
{
if(wasRecorded) {
convert2mp3();
}
}
public function jSendFileToServer():void
{
// do nothing if we have not converted our record
if(mp3done) {
sendRecording();
}
else {
ExternalInterface.call("justrec.mp3ConvertingError");
}
}
/* ************ */
/* Private area */
/* ************ */
private function recording(e:RecordingEvent):void
{
var currentTime:int = Math.floor(e.time / 1000);
ExternalInterface.call("justrec.recordingActivity", String(currentTime), mic.activityLevel);
if(currentTime >= maxTime )
{
// force stop recording
jStopRecording();
}
}
private function previewRecording():void
{
if(isConverting) {
return;
}
if(isPreviewing) {
stopPreviewRecording();
}
isPreviewing = true; // force into previewing mode
tts = new WavSound(recorder.output);
playingChannel = tts.play();
// ?? ExternalInterface.call("justrec.previewStarted");
}
private function stopPreviewRecording():void
{
playingChannel.stop();
isPreviewing = false;
// ?? ExternalInterface.call("justrec.previewStopped");
}
// convert to mp3 using ShineMP3Encoder
private function convert2mp3():void {
if(isConverting) {
return;
}
if(isPreviewing) {
stopPreviewRecording();
}
// set position of ByteArray with WAV data to 0
// either converting sticks if previewing is done
recorder.output.position = 0;
isConverting = true;
mp3Encoder = new ShineMP3Encoder(recorder.output);
mp3Encoder.addEventListener(Event.COMPLETE, mp3EncodeComplete);
mp3Encoder.addEventListener(ProgressEvent.PROGRESS, mp3EncodeProgress);
mp3Encoder.addEventListener(ErrorEvent.ERROR, mp3EncodeError);
mp3Encoder.start();
}
private function mp3EncodeProgress(event: ProgressEvent) : void {
var percent:int = Math.round(event.bytesLoaded / event.bytesTotal * 100);
ExternalInterface.call("justrec.mp3Converting", String(percent));
}
private function mp3EncodeError(event: ErrorEvent) : void {
isConverting = false;
ExternalInterface.call("justrec.mp3ConvertingError");
}
private function mp3EncodeComplete(event: Event) : void {
mp3done = true; // converting flag
isConverting = false;
ExternalInterface.call("justrec.mp3Converted");
}
// send data to server
private function sendRecording():void
{
var _var1:String = '';
var globalParam:Object = LoaderInfo(this.root.loaderInfo).parameters;
for (var element:String in globalParam) {
if (element == 'host'){
_var1 = globalParam[element];
}
}
if(_var1 != '') {
var req:URLRequest = new URLRequest(_var1);
req.contentType = 'application/octet-stream';
req.method = URLRequestMethod.POST;
// req.data = recorder.output; -- for WAV data
req.data = mp3Encoder.mp3Data; // for MP3 data
var loader:URLLoader = new URLLoader(req);
loader.addEventListener(Event.COMPLETE, sendComplete);
loader.addEventListener(ProgressEvent.PROGRESS, sendProgress);
}
}
private function sendProgress(event: ProgressEvent) : void {
var percent:int = Math.round(event.bytesLoaded / event.bytesTotal * 100);
ExternalInterface.call("justrec.sendingProgress", String(percent));
}
// done sending record
private function sendComplete(event: Event) : void {
ExternalInterface.call("justrec.sendingFinished");
}
/* ***************** */
// helper functions //
/* *************** */
private function addCommands():void
{
ExternalInterface.addCallback("jStartRecording", jStartRecording);
ExternalInterface.addCallback("jStopRecording", jStopRecording);
ExternalInterface.addCallback("jPreview", jPreview);
ExternalInterface.addCallback("jStopPreview", jStopPreview);
ExternalInterface.addCallback("jConvert2MP3", jConvert2MP3);
ExternalInterface.addCallback("jSendFileToServer", jSendFileToServer);
}
// dispatches on allowing/denying access to Camera/Microphone
/*
private function onMicStatus(event:StatusEvent):void
{
ExternalInterface.call("justrec.micStatus");
if (event.code == "Microphone.Muted")
{
ExternalInterface.call("justrec.recordingError");
// trace("Microphone access was denied.");
}
}
*/
} // class Main
} // package
I am trying to make a sound play with the timer goes to 3, 2, 1.
My timer starts at ten and has a three second delay. If I use the following code:
if (tl.myCoolTimer == 10)
{
print("Play Sound");
myAudioSource.Play();
}
It plays the Beep over and over again until the game starts and the counter goes below 10.
If I use the code:
if (tl.myCoolTimer == 3)
{
print("Play Sound");
myAudioSource.Play();
}
It doesn't play the sound at all. It doesn't even print the print statement.
I literally only changed the number. I am not sure why this isn't working.
I have also tried setting it to 3f to see if it is a float issue.
Timer Scripts
This is the starting Timer. it counts down to 3 (then the game starts)
public Text startGameTimerText;
public float startGameTimer = 3;
public void Start ()
{
startGameTimerText = GetComponent<Text> ();
}
public void Update ()
{
startGameTimer -= Time.deltaTime;
startGameTimerText.text = startGameTimer.ToString ("f1");
if (startGameTimer < 0) {
GameObject.Find ("GameStartTimer").SetActive (false);
}
}
This is the Game Timer It starts at 10 and counts down to 0.
public StartGameTimer gt; //this is the script the other timer is on
public Text timerText;
public float myCoolTimer = 10;
public void Start ()
{
timerText = GetComponent<Text> ();
}
public void Update ()
{
if (gt.startGameTimer > 0) {
myCoolTimer = 10;
} else {
myCoolTimer -= Time.deltaTime;
timerText.text = myCoolTimer.ToString ("f1");
}
}
Thanks Joe for the help. Here was my final answer. I know it is hacked, but I haven't figured out the Invoke thing yet. When I set the into it kept playing the entire time it was at "3", so i need to make it play only once.
private AudioSource myAudioSource;
public bool isSoundPlayed;
void Start()
{
myAudioSource = GetComponent<AudioSource>();
isSoundPlayed = false;
}
void Update()
{
if((int)tl.myCoolTimer == 3)
{
if (isSoundPlayed == false)
{
myAudioSource.Play();
isSoundPlayed = true;
}
return;
}
if ((int)tl.myCoolTimer == 2)
{
if (isSoundPlayed == true)
{
myAudioSource.Play();
isSoundPlayed = false;
}
return;
}
if ((int)tl.myCoolTimer == 1)
{
if (isSoundPlayed == false)
{
myAudioSource.Play();
isSoundPlayed = true;
}
return;
}
}
I want to write a chat server.
Using the programming language D. (Dlang)
It is desirable to use OOP.
My example.(Not working)
import std.stdio;
import std.concurrency;
import core.thread;
import std.conv;
import std.socket;
synchronized class DataInfo{
shared this()
{
}
public shared Socket[] sockList;
shared void AddSocket(shared Socket scket)
{
sockList ~= scket;
}
shared(Socket[]) getSockList()
{
return to!(shared Socket[])(sockList);
}
}
void UserLoop(shared DataInfo data,shared(int) id)
{
Socket client;
synchronized(data)
{
client = cast(Socket)(data.sockList[id]);
}
while(true)
{
char[1024] buffer;
int sockCount = 0;
client.receive(buffer);
synchronized(data)
{
sockCount = data.sockList.length;
}
for(int i =0 ; i < sockCount; i++)
{
synchronized(data)
{
auto sk = cast( Socket)(data.sockList[i]);
sk.send("Hello world");
}
}
}
}
int main()
{
ushort port;
port = 4444;
auto listener = new TcpSocket();
assert(listener.isAlive);
listener.blocking = false;
listener.bind(new InternetAddress(port));
listener.listen(10);
writefln("Listening on port %d.", port);
shared(DataInfo) data = new shared(DataInfo);
while(true)
{
int len = 0;
auto client = cast(shared Socket)listener.accept();
synchronized(data)
{
data.AddSocket(client);
len = data.sockList.length;
}
spawn(&UserLoop,data,cast(shared int)len);
}
return 0;
}
How? How to fix the bug?
Can I get an example of correct chat servers? (Only Dlang)
Also, can you give an example of the correct client.
import vibe.d;
import vibe.utils.array;
shared static this()
{
Chat m_chat=new Chat();
ushort port=5555;
listenTCP(port,&m_chat.connHandler,"127.0.0.1");
}
class Chat{
private:
TCPConnection[] connz;
public:
void connHandler(TCPConnection conn){
sendMessage(conn,"Hello!\n");
connz~=conn;
while(conn.connected){
while(conn.waitForData(dur!"seconds"(1L))){
ubyte[1] c;
string inMessage;
while(conn.dataAvailableForRead){
conn.read(c);
inMessage~=c;
}
foreach(TCPConnection _con; connz){
if(_con!=conn)
sendMessage(_con,"Someone says: "~inMessage);
}
}
}
connz.removeFromArray(conn);
}
void sendMessage(TCPConnection conn, string message){
conn.write(cast(ubyte[])message);
}
}
Solution suggested by Lord_Evil
I'm trying to handle thread pool in a class.
below is my code.
#include <Windows.h>
class ClassA
{
public : // user API
ClassA()
{
}
~ClassA()
{
}
public : //my muiti-thread func
void init()
{
//*************************************
// multithread Initialization
//*************************************
pool = NULL;
cleanupgroup = NULL;
rollback = 0;
bool bRet = false;
pool = CreateThreadpool(NULL);
if(NULL == pool)
{
goto cleanPool;
}
rollback = 1;
SetThreadpoolThreadMaximum(pool, 5);
bRet = SetThreadpoolThreadMinimum(pool, 10);
if (FALSE == bRet) {
goto cleanPool;
}
cleanupgroup = CreateThreadpoolCleanupGroup();
if (NULL == cleanupgroup) {
goto cleanPool;
}
rollback = 2;
SetThreadpoolCallbackPool(&CallBackEnviron, pool);
SetThreadpoolCallbackCleanupGroup(&CallBackEnviron,
cleanupgroup,
NULL);
return ;
cleanPool:
switch (rollback)
{
case 2:
// Clean up the cleanup group.
CloseThreadpoolCleanupGroup(cleanupgroup);
case 1:
// Clean up the pool.
CloseThreadpool(pool);
default:
break;
}
return ;
}
void foo()
{
PTP_WORK work = NULL;
work = CreateThreadpoolWork(ClassA::_delegate,
NULL,
&CallBackEnviron);
}
static void __stdcall _delegate(PTP_CALLBACK_INSTANCE Instance, PVOID Parameter, PTP_WORK Work)
{
//some code
}
PTP_POOL pool;
UINT rollback;
TP_CALLBACK_ENVIRON CallBackEnviron;
PTP_CLEANUP_GROUP cleanupgroup;
};
int main()
{
ClassA a;
a.init();
a.foo();
}
If you make a project and execute this code, it gets unhandled execption...
I have no clue why...
I think the exception is caused by an uninitialized structure CallBackEnviron. The documentation states that this structure must be initialized by InitializeThreadpoolEnvironment