LoCo Day 8

Long polling is working! I now have a very basic real-time web-based chat room implemented. JavaScript on the browser regularly polls for updates on the server, and adds them to the chat window if it finds any. The server thread handling the request blocks for a short while if no messages are available. It’s simple, but the messaging subsystem will be the foundation of client-server communications when the actual game is implemented.

The only problem with my implementation (other than the design limitations I mentioned in the previous post) is that sometimes the server returns a 500 error to the client’s long-poll request instead of a 200 or 204 based on whether any messages are available. The error seems to be getting spit out by Happstack itself, since the specific error message (“server error: thread killed”) isn’t anything I’ve written. My best guess at the moment is that Happstack imposes its own timeout on request handlers, and when it sees it hasn’t finished after a while, assumes that the handler has gotten hung and kills it. If this is the case, the solution would be to either shorting the long-poll timeout in my code, or see if there’s a way to adjust Happstack’s timeout.

I think that after fixing that issue, I’ll migrate the chat room code into a more general “room” abstraction that’ll be amenable to building the game on top of. (The chat room code is a bit hackish at the moment.) I’ll then probably make it so you can have more than just one room in existence, which could make the main server logic a bit neater too, and give some more realistic URLs too.

Comments Off

LoCo Day 7

I think I have long-polling for chat messages mostly implemented. The one missing piece is retrieving messages on the server side. The client side can send and (try to) receive messages, and the server accepts new messages.

One obvious flaw in the current implementation is that the chat room queues messages for clients based on session ID, so if someone opened the page in two separate tabs in their browser, messages would only appear in one tab or the other, since the server wouldn’t be able to distinguish the two — each tab’s requests would be carrying the same session ID. When my implementation gets more sophisticated, I’ll either need to add another ID for a particular instance of having the page loaded, or just block attempts to have the same chat room (or game or whatever) opened multiple times by the same session.

Comments Off

LoCo Day 6

Some actual progress, now that I’ve abandoned trying to get Heist to do what I want it to and switched to Blaze for HTML generation.

Then I implemented site-wide CSRF prevention. Whenver the server receives a POST request, it checks that the csrfToken parameter matches the one stored in the session for that request. If not, it stops processing the request and spits out an error. Unfortunately, if the browser has cookies disabled, that’ll also trigger the error message, since the server won’t be able to associate the request with an existing session. Either that’ll need to be fixed somehow, or I’ll at least need to detail that cause in the error message. After all, if there really is a CSRF attack taking place, no one will actually be reading the page that gets returned anyway.

After that, I implemented a multicast messaging system that will serve as the innermost component for letting browsers poll efficiently for game-related events. Internally it’s built around transactional channels, with my code dealing with creating and destroying TChans as players enter or leave the game, and with retrieving all queued messages without blocking. It’s that last bit that requires using TChan instead of the slightly simpler Chan; the latter doesn’t have a reliable way to check whether the channel still has anything left in it.

Finally, I started working on a basic chat room mechanism, to operationally test the messaging system and to serve as a starting point for the JavaScript code that’ll run in the user’s browser. I haven’t had a chance to get very far with this piece yet, but it ought to be fairly straightforward.

It feels good to be making actual progress once again.

Comments Off

LoCo Day 5

Yet another day with little-to-no direct progress, but I think I did finally get to the heart of the problem I’ve been wrestling with. I’ve asked on Stack Overflow if there’s a way around it, in case I’m still missing something, but I don’t think I am.

The basic problem I ran into is this: In Heist, page templates can only run Haskell code by invoking splices, which are defined in the context of the program’s application stack. As a result, splices can’t see anything that doesn’t directly originate in that monad. However, when using web-routes for type-safe URLs, parameters passed via the URL path itself, instead of the query string, are inaccessible from the application monad; instead, they are accessed by pattern-matching against the type-safe URL. Likewise, the session object created before invoking the web-routes part of the code lives outside of the application monad. As a result, splices can’t get at URL path parameters or the session object, and there doesn’t seem to be a way around this inherent design limitation.

The problem doesn’t seem to arise when using Snap instead of Happstack, since Snap’s routing mechanism extracts URL path parameters, gives them names, and treats them as though they were other query string parameters, in which case they can be accessed via a Snap-based monad. I imagine something similar happens when working with sessions. Since Heist arose out of the Snap project, it’s not surprising its splices are limited to getting things out of the application monad, since in Snap that’s less of a limitation than it is in Happstack. No wonder that all the examples of Heist I’ve come across hand-wave getting request parameters by assuming there’s something in the application monad to do that.

I think that means I should give up on Heist (barring an answer to the aforementioned question that points out a way around this issue entirely) and use Blaze to generate HTML instead, at least for now. Although I’m stuck with Blaze’s quasi-monadic syntax instead of something that looks like actual HTML, at least I get some extra type-safety guarantees by having the HTML templates be Haskell code instead of standalone files loaded at runtime.

I did effectively lose a couple days wrestling with this, but at least I’m coming out of it with a better understanding of what these libraries can and can’t do.

LoCo Day 4

Another horrifically unproductive day, mostly spent searching for and reading documentation and tutorials for the libraries I’m trying to use, in the hopes of figuring out the right way to use them together.

I think the mistake I’ve been making is the assumption that I want to be using a MonadReader to expose session and request information to the Heist templates I’ll be using to piece together web pages. All of the Heist tutorials and blog posts I’ve seen hand-wave the issue of accessing request-specific data in templates and splices by supposing an application monad exists that provides an operation to get at that information. I had originally taken that to mean that I should use a ReaderT to package up that sort of information and add it to the monad stack I’ve pieced together out of Happstack, web-routes, and Heist. However, sticking a ReaderT into the stack throws the compiler into a fit, since it winds up hiding some of the monad typeclasses below it in the stack. For instance, Happstack doesn’t provide the plumbing for ReaderT to lift ServerMonad operations up, and I don’t know whether that’s a deliberate design decision or an oversight. There doesn’t seem to be a feasible place to stick the ReaderT into the stack that doesn’t cause problems somewhere.

So, what I think I’ll try to do is give up on ReaderT entirely for this, and instead pass the Session object and any other resource handles I need to worry about as function arguments (possibly encapsulated in some Context object so I have only one thing to pass around instead of a bunch) until they get to the actual request routing function. In there, I’ll create splices out of the session information for the templates to use, passing them to Heist at the same time I tell it which template I want to render. This is slightly complicated by the fact that the happstack-heist module, which provides the plumbing between Happstack and Heist, doesn’t provide a wrapper for the Heist function that lets you invoke a template with extra splices. Fortunately, it doesn’t look like it’d be difficult to reimplement that bit of plumbing myself. I’m still not certain this is the “correct” way to do things, but there’s a chance it will work, which is better than my approach so far.

I had also considered giving up on Heist and using some other mechanism for generating web pages. Blaze would have the advantage of better type safety since the HTML-generating code would be part of the program, but then I’d be stuck using Blaze functions to construct the pages instead of writing something that actually looks like HTML. HSP would in theory solve this by letting you write XML directly in the program and use preprocessing magic to translate it into Haskell code at compile time. However, HSP has the crippling flaw of being effectively undocumented, other than a bit of API documentation and pointers to a ten-year-old thesis written about it. Other templating engines seem to be merely string-based, which makes me concerned about the possibility of accidental cross-site scripting attacks.

It’d be great if there were some well-documented, simple-but-not-trivial example out there of something using Happstack, Heist, and web-routes together, but I haven’t managed to come across it yet. I guess I’ll keep stumbling along tomorrow.

LoCo Day 3

Most of today was spent wrestling with figuring out how to use Happstack, Heist, and web-routes to play nicely together. All of the tutorials I could find focus only on Happstack and Heist, or Happstack and web-routes, but it’s not immediately obvious (to me, at least) how they should be put together in the monad stack, especially when you also want to throw in a ReaderT to carry session information and a couple handles to shared resources. Hopefully if I go slowly, one step at a time, I’ll be able to figure out the “correct” solution which will no doubt be obvious once I see it.

I just wish I had more to show for the hours I’ve already sunk into this….

Comments Off

LoCo Day 2

Progress is still slower than I’d like, but it’s there. Basic session tracking is working. Now when the server gets a request, it looks for a session cookie and either loads the session from the database or starts a new session. At the moment the sessions don’t do anything more than exist, but the rest of the functionality will need them to associate different requests by the same user.

It took longer than I was expecting to get to this point. I think part of it’s because I’m having to frequently consult the documentation for the different libraries I’m using, and part of it is that it’s early enough along that I’m still having to set up basic scaffolding along the way. Hopefully that means as time goes on my rate of progress will increase.

The next order of business is to start serving a real page, implement CSRF protection, and implement multicast message queues. Before getting to the actual game, I’ll construct a basic chat room sort of thing, which will exercise the messaging system. Besides, once there’s an actual game there, it can still be used to let players talk with one another.

Comments Off

LoCo Day 1

Today’s progress was underwhelming, unfortunately. But first things first.

I’m building my webapp atop the Happstack framework. I’ve identified a couple short-term goals for implementing basic functionality:

  • Session tracking, which unfortunately isn’t provided by anything in Happstack itself. (Maybe the happstack-authenticate package will provide this, but there haven’t been any releases of that library on Hackage yet.)
  • Multicast communication channels to use as the core message forwarding mechanism during a game. The server would use this to queue messages for each player in a game, which the player’s browser would fetch via long polling.

All I managed to accomplish so far is to get a minimal webserver running and to define the type to use as a session ID. I started on test cases for the session database, but wasn’t able to progress beyond that. Bleh. Hopefully I’ll be able to knock out the rest of the basic session stuff tomorrow and start on the multicast channels.

Too loco for NaNo

Having won NaNoWriMo the past three years (and another time several years before those), I think it’s safe to say that I’m capable of writing the first draft of a 50,000-word novel in the span of 30 days. The next time I write a work of fiction of that length, I’d like to release it after having a chance to give it some polish, instead of immediately posting the first thing to fall onto my keyboard.

So this November, I’m going to try to kick things up a notch.

I am going to try to create, from scratch, a fully-functional web-based multiplayer game during the month of November. By the end of November 30, I hope to have something that works and that I wouldn’t mind running on a closed network populated by trusted users. After all, just as a NaNoWriMo novel isn’t going to be in publishable quality at the end of November, I’m not expecting my program to be of high enough quality to be able to be run securely on the real Internet.

And, of course, by “from scratch”, I mean not having written any code for it yet. I’m still going to be using libraries and whatnot. It’s not like I’m going to be writing raw assembly directly to an executable or anything. That’d be crazy. And annoying. But then, it’s not as though you’re first inventing your own language when you do NaNoWriMo anyway.

Since this is something I’ll be doing on my own, it’s much more local than it is national. And I’ll be writing code instead of a novel. So it’s really a LoCoWriMo, which sounds about right.

Obviously, I won’t be posting playable demos every day, but I will be coming up with some sort of status update to post here each day. I haven’t quite figured out what will be interesting or make sense in terms of metrics. Shooting for a 50,000-line program is even more absurd than shooting for a 50,000-word novel. I’ll come up with something, I’m sure.

I wonder how long it’ll take before I start regretting this….

Comments Off

Book List – September and October 2011

Am I late, or am I early? Do they cancel out? Does it matter?

The Zen of Zombie: Better Living Through the Undead, by Scott Kenemore, © 2007. Finished September 25.

A self-help book crossed with zombies. The premise wears thin long before the end, since there’s really only so many ways you can go with the idea. The book could’ve had potential as a satire of the self-help genre, but it’s not played nearly straight enough for that to work.

Pay Me, Bug!, by Christopher Wright, © 2011. Finished October 19.

A starship captain pulls off an impossible heist against a heavily fortified facility, but before he and his crew can enjoy the spoils, they are blackmailed into performing an even more impossible caper against an even harder target. But with an assassin on their tail, will Grif Vindh and his crew survive long enough to try to make lightning strike twice? From the man who often brings you Help Desk and occasionally Kernel Panic comes Pay Me, Bug!

Seriously, though, it’s worth the price of admission just for the fight scene in Chapter 31 alone. But since the entire thing is posted online, I guess the price of admission is zero. But that just means you have no excuse.

Comments Off

Book List – August 2011

Even later than before!

Moving Pictures, by Terry Pratchett, © 1990. Finished August 31.

The tenth Discworld novel, and the first in the series where Cut-Me-Own-Throat Dibbler plays a prominent role in the plot. I thought for sure that elephants were going to play some important part in the climax, given the recurring imagery of them earlier on, but I was mistaken. I also totally missed one of the (fairly obvious) Hollywood references being made repeatedly until near the ending.

Comments Off

Legend of Zelda

I recently played through The Legend of Zelda, and to my surprise I found it to be a much better game than I remember it being from having played it many years ago. It certainly has its rough edges, and A Link to the Past improved on the gameplay in almost every way, but there’s still a lot to like about the original.

In no particular order, here’s a bunch of random things that struck me while playing.

There is a lot more freedom than in modern Zelda games. Right from the start, you can go pretty much wherever you want in Hyrule, including most of the dungeons. Want to go right to Ganon’s lair in Level 9? No problem! Granted, you won’t get past the Old Man in the second room without the Triforce, but you can still go inside. But if you know where Level 8 is, you can buy a Blue Candle, burn down the entrance, and see how far you can get. Heck, in the Second Quest, I cleared Level 8 before I found Level 7 at all.

Modern Zelda games have more of a tendency to keep you on a particular path, forcing you through a tutorial-ish segment at the start and blocking access to the next dungeon in the predetermined sequence until you complete its predecessor. You have some freedom to explore the world in between, but it always feels like you’re straying from the intended path, instead of freely exploring at your leisure. The otherwise fantastic Ocarina of Time took this to an extreme, with Navi frequently shouting her irritating “Hey! Listen!” if for whatever reason you hadn’t reached the next plot point yet.

Speaking of which….

Dungeons aren’t built around their treasure. In the original game, a lot of the treasures aren’t at all necessary to complete the game. In fact, a lot of players deliberately avoid getting the Book of Magic since it arguably weakens the Magical Rod‘s attack, which itself isn’t actually needed for anything. With the exception of a few critical items, if you fail to thoroughly explore each dungeon and miss something as a result, you’re free to keep on going anyway.

Contrast that with Ocarina of Time and later games, where each dungeon’s treasure is invariably necessary to reach the end, and is typically key for defeating the boss guarding whichever plot coupon you’re collecting. And once that’s done, the treasure will be needed to reach the next dungeon. Every time.

Puzzle solving is surprisingly lacking. The original game’s dungeons are much more fighting-oriented, with puzzles generally restricted to finding hidden passages between rooms and pushing the occasional block to reveal a staircase. This is definitely something that the later games improved on, striking a better balance between fighting and puzzle solving.

The real puzzle solving is in finding where some of the dungeons are in the first place. In the First Quest the entrances are out in the open up until Level 7, but in the Second Quest they start hiding them as soon as Level 2, with nary a clue as to where each one can be found. The Second Quest is actually a bit unreasonable about this, expecting you to find which tree Level 7 is hidden under armed only with a somewhat inaccurate clue and the Blue Candle (the superior, not-limited-to-one-use-per-screen Red Candle being hidden within Level 7 itself!). I’ll admit to resorting to look online to find out where Level 7 was, which was a good move, since it would’ve taken hours and hours of repetitive and time-consuming play to eventually come across it.

That said, however….

The Second Quest is pretty nifty, and adds a lot of replay value by upping the difficulty considerably. I thought the placement of the first few levels was well-done. Level 1 is in the same place in both locations, letting you get started in a superficially familiar environment. But where Level 2 would be in the First Quest, you find a fairyless pond. Of course you immediately suspect there’s a dungeon hidden below the water (and there is — Level 3), but you need the Whistle to reveal it, and the Whistle is hidden in Level 2. So where is Level 2? Where the hidden shop selling the game-critical Food was in the First Quest. A player familiar with the First Quest would have little trouble finding the first three dungeons in the Second Quest just based on his or her knowledge of where important locations where in the First Quest. But after that, however, the training wheels come off and the dungeons are hidden in much less obvious locations. Sometimes, excessively so. [glares at Level 7]

The dungeons themselves also have some nifty tricks to them. I was particularly amused by how Level 4 has a decoy treasure! The Book of Magic is fairly easy to find, but completely worthless since the Magical Rod isn’t found until a later dungeon. The real treasure, the Raft needed to reach Level 5, is only accessible through a series of rooms reachable from a hidden passage in the Triforce room! Pretty sneaky, but fair, since the Map of the dungeon makes it clear there’s a few rooms that are otherwise inaccessible, so you’re given a chance to realize something’s up.

Not many Zelda games reused the idea of a Second Quest, though. The only one I’m aware of is Ocarina of Time, which had a “Master Quest” version on Gamecube that significantly changed the dungeons. Granted, it’s more work to do that sort of thing in 3D than it is in 2D, but it’s still an idea worth revisiting.

The real villains are the Old Men. Think about it. Sure, Moblins will shoot arrows at you, but they’re just doing their job. They can’t help it that the Hyrule economy is in a slump and Ganon is the only person… er, pig thing… hiring. But when you catch them off-duty, chilling at home, they’ll immediately offer to pay you off to keep that little secret between the two of you.

But the Old Men are jerks through and through. Come into their home, and they’ll fine you for breaking down their door.

… OK, maybe that’s fair. Do you know how long it takes a tree to regrow after being burned down? But that’s no excuse for them giving you incomprehensible “clues”…

10TH ENEMY HAS THE BOMB

… or running illicit gambling operations …

LET'S PLAY MONEY MAKING GAME

… or making surprisingly stereotypically thuggish threats …

LEAVE YOUR LIFE OR MONEY

… is it no wonder that so many live in dungeons that are otherwise filled with monsters? Clearly, they are monsters too. If nothing else, they’re evolved from Cuccos — why else would they be impossible to kill yet relentlessly fight back if you attack?

Also, come to think of it….

If Zelda had the Silver Arrows, she could have defeated Ganon herself. The game’s intro text clearly states that she is the one who broke up the Triforce of Wisdom and hid its pieces in the eight dungeons, so somehow she managed to fight her way through all the same areas that Link does. So how did Ganon manage to capture her, if she’s just as tough as Link? Because she didn’t have the Silver Arrows, Ganon’s one weakness, which for some reason he keeps hidden in his own lair. If she had them, she could have used them, too — notice how in Wind Waker and Twilight Princess, she fires Light Arrows at Ganon while Link engages with his sword.

That’s a lot more impressive than Peach, certainly, who gets kidnapped by Bowser so frequently that she has to schedule board game nights and kart-racing tournaments around Bowser’s weekly invasions of the Mushroom Kingdom.

I survived another earthquake

This time it was a 5.8-5.9. That’s a bit more impressive than that that dinky little 3.6 from a year ago. Figures that Maryland decides that earthquakes are fun times after I’ve become a property owner. Also, hurricanes, maybe.

Comments Off

Book List – July 2011

Late? I don’t know what you’re talking about.

The Adventures of Sherlock Holmes, by Arthur Conan Doyle, © 1892. Audiobook. Finished July 25.

Unsurprisingly, a collection of Sherlock Holmes short stories. Less unsurprisingly, a couple of the stories seemed vaguely familiar — I’m not sure whether I’ve read them before a long time ago, or if (being in the public domain and all), the core of the plots of some of them got transplanted into other works. Surprisingly, Holmes doesn’t manage to win in all of them. More surprisingly, in one of the stories Holmes goes up against the KKK.

The Picture of Dorian Gray, by Oscar Wilde, © 1890. Audiobook. Finished July 25.

I came away from this one somewhat disappointed. A lot of the dialogue felt a bit contrived to fit in a bunch of witticisms, and there’s hardly a likable character to be found. OK sure, the reprehensibility of the titular character is sort of the point, but still.

Comments Off

Book List – June 2011

Here’s what I read this past month:

Machine of Death, edited by Ryan North, Matthew Bennardo, and David Malki !, © 2010. Finished June 18.

An anthology of short stories all based on the premise of a machine that, given a small blood sample, can predict with 100% accuracy how a person will die. You might think there’d be a lot of similarity between the stories given that unifying concept, but there’s a huge variety in how each of the authors build on that premise to create interesting and compelling stories. Thankfully, the only thing you’ll be hard-pressed to find is the obvious twist-ending-where-the-prediction-was-being-interpreted-incorrectly. Besides, any book that can enrage Glenn Beck has got to be worth something!

Them: Adventures with Extremists, by Jon Ronson, © 2002. Finished June 30.

A description of Jon Ronson’s experiences shadowing various fringe conspiracy theorists and trying to track down the truth, if any, underlying their beliefs. Despite the variety of groups he spends time with, from Islamic extremists to KKK leaders, he finds them unwittingly unified by the common belief that somewhere there’s a small cabal of wealthy Western businessmen secretly pulling the strings to control the world (and, to a lesser extent, the belief that many other conspiracy theorists are puppets of that cabal, trying to discredit them). He finds that it’s difficult to keep track of what’s real and what’s not once you go down that rabbit hole, when it becomes uncertain what is really a code word for what, or when you find yourself being tailed after trying to infiltrate a suspected Bilderberg meeting. The book reminded me of Michael Shermer‘s book Why People Believe Weird Things, in that once you get past the people who are just flat out crazy and/or evil, a lot of the conspiracy theorists fixated on a particular theory, and then became adept at finding ways to interpret any facts encountered after that as supporting their theory. This is particularly evident in the climax of the book, where Ronson and a couple conspiracy-theory radio hosts sneak into Bohemian Grove and come away with vastly different interpretations of what they saw.