I'm trying to implement a tick event, and have a little test below that demonstrates that it doesn't work. I'd appreciate insight as to why it doesn't work.
gameloop :: TChan UAC ->
IO ()
gameloop commandChannel = do
(tickHandler, tickSink) <- newAddHandler
networkDescr <- compile $ makeNetworkDescription commandChannel tickHandler
actuate networkDescr
forkIO $ forever $ (timer 10) >>= tickSink
return ()
makeNetworkDescription :: forall t . Frameworks t =>
TChan UAC ->
AddHandler () ->
Moment t ()
makeNetworkDescription commandChannel tickHandler = do
eTick <- fromAddHandler tickHandler
bCChannel <- fromPoll $ grabCommands commandChannel
-- test fromPoll
test <- initial bCChannel
liftIO $ appendFile "testPoll.txt" $ show test
-- end fromPoll test
let eCChannel = bCChannel <@ eTick
liftIO $ print "hi there\n"
reactimate $ (\n -> appendFile "Commands.txt" (show n)) <$> eCChannel
grabCommands :: TChan UAC -> IO [UAC]
grabCommands unval = do
result <- (atomically $ readTChan unval) `untilM` (atomically $ isEmptyTChan unval)
liftIO $ print $ show result
return result
timer :: TimeOut -> IO ()
timer ms = do
threadDelay ms
Here's some test data.
main :: IO ()
main = do
commandChan <- atomically $ newTChan :: IO (TChan UAC)
forkIO $ gameloop commandChan
liftIO $ print "back from fork\n"
atomically $ populateCC commandChan playerCommands
return ()
populateCC :: TChan UAC -> [UAC] -> STM ()
populateCC pChannel pCommands = mapM_ (writeTChan pChannel) pCommands
playerCommands =
[UAC (PlayerCommand (CommandData (T.pack "1" :: AID) Look) (T.pack "1")),
UAC (PlayerCommand (CommandData (T.pack "2" :: AID) (Move Mongo)) (T.pack "2"))
]
when I execute the above Main
I get this output.
"back from fork\n"
"[UAC (PlayerCommand (CommandData \"1\" Look) \"1\"),UAC (PlayerCommand (CommandData \"2\" (Move Mongo)) \"2\")]"
"hi there\n"
The file Commands.txt
never comes into existence. I attribute this problem to a faulty tick event.
I got my idea for the timer implementation from this, but wonder if I'm thinking about this the wrong way. Any ideas?
Edit: I wanted some assurance fromPoll
was doing the right thing. I added the test above, and it is.
It appears to me that the problem is not with the tick event, but with the fact that you model the player commands as a Behavior
.
If you think denotationally and imagine that a behavior is a time-varying value Behavior a = Time -> a
, does it make sense to model player commands in this way? What is the player command in, say, the time frame between 3s
and 4s
? Does the argument you give to fromPoll
respect these semantics?
The thing is that grabCommands
has a serious side effect: calling it removes the commands from the channel, so it is not even idempotent. Also, it blocks when there is no command available. I think that this is ultimately the reason why the tick event doesn't work: the network is blocked trying to execute the fromPoll
action. However, the underlying problem is more profound: the right way to model player commands is to use an Event
, not a Behavior
.