Well, there’s not much I really want to say here outside of a bit of an observation.

Since I stopped playing Alganon two weeks ago, they have sent me two emails.

  • The first was to advertise that they were giving away free mounts to all beta testers who wanted one. I did not log in to claim mine :P
  • The second arrived last night and advertised that they really are completely intent on launching in ONE week.

They released a state-of-the-game article monday night to address a lot of their problems. To summarize it all as succinctly (and as snarkily) as possible:

Yeah, there are bugs, lots of bugs, but we’re actually actively patching things that should have been resolved before we declared open beta. We like crunch mode. Sleep is for mortals who plan ahead. We plan on “hitting” a magical launchable degree of quality before December, somehow.

We’ve finally fixed our billing system, so we can charge forners. Downloading the client works again.

We’re still in denial about our rip of WoW being a bad thing. We’re gamers writing a game for gamers, so clearly since we enjoy a bad copy of a polished product, all other “gamers” should too. We’re trying to copy as many features as humanly possible, regardless of the quality or ethics involved. People don’t complain about bugs, they complain about the “similarities” to “other games” they play. We’re not trying to reinvent the wheel or even compete with anything vaguely shaped like a wheel.

Our players who use the forums have drunk the kool-aid. We believe that they will brainwash others, but we don’t want to “steal” players from other games, honest. We’re not in it for the money. We’re all about the ART, man. Clearly we’re not rushing to market to start recouping some of our development costs.

We are totally the first “real” fantasy MMO to launch in two years. Warhammer and Conan don’t count. Runes of Magic and Aion don’t count either. Neither does anything else imported from Asia…

We love you, please don’t hate us for being derivative.

I wish Alganon well, the crazy fools. Really, I do. I just don’t envy the worker drones who’re tasked with making this pig up at the last minute. Surely the insanity isn’t rampant throughout the entire company… just the public facing elements, right? Right? Oh well.

p.s. This week’s report on Ether Saga Online is 2/3 finished. I’ll try to publish it before end of day.

So… wow. Bartle‘s been getting a lot of press and/or flak for his stance against a quest in WoW that the creators coyly titled “The Art of Persuasion”. Basically, the quest NPC is too impatient to interrogate a prisoner but doesn’t want to dirty his hands with torture – it is against his organization’s rules of operation – so he gives you a cattle prod to fry him with a few times while he looks the other way (all of 3 feet away).

The fact that the quest exists isn’t wrong. The fact that you don’t really have much of a choice in the matter is. You can’t tell the quest-giver “no”. You either have to torture the prisoner or you have to bypass the remainder of the quest chain (which is fairly important if you want anything to do with the Kirin Tor mages).

I did the quest once – on my warlock, the character whose job it is to be a little dynamo of concentrated evil – and I remember standing there for 5 minutes debating before I finally decided to actually zap the guy. I’m not planning on doing the quest chain again on any other characters. Normally, my criteria for adding a quest to my blacklist is that it is boring or a terrible waste of time vs the reward. This is the first quest I’ve ever had to swear off on moral grounds.

So why has this particular quest been singled out? Why wait until now? By every definition in the book, we (players of WoW and numerous other MMORPG’s) have clearly been engaged in innumerable unsavory activities – including torture – for years now.

This is hardly the first time a quest in WoW expects you to use violence to extract information. There are quite a few quests that expect you to beat on people until they talk. There are several quests that ask you to kill couriers for information they are carrying. There are quests where you poison people and quests where you perform horrible experiments on people and quests where you don’t actually have to beat on the source of the information, you just have to prove that you’re willing to do so. It is, after all, a game whose fundamental action is killing.

We play a game where we are asked to role-play as soulless mercenaries who’ll kill anyone/anything for a few bucks – or more likely a shirt that we’re just going to turn around and pawn because it breaks our set bonus. We’ll dig through pig droppings and harvest organs and collect on debts owed to thieves and steal apples if we accept every job offer that comes our way.

The circumstances behind this particular quest, however, are much more obvious. This particular quest NPC says:

You see, the Kirin Tor code of conduct frowns upon our taking certain ‘extreme’ measures – even in desperate times such as these.

You, however, as an outsider, are not bound by such restrictions and could take any steps necessary in the retrieval of information.

He then hands you a “Neural Needler”, which “Inflicts incredible pain to target, but does no permanent damage.” You then have to walk 3 feet to a man chained into a chair and use the needler on him five times. The ‘conversation’ goes something like this:

  1. Pathetic fool! A servant of Malygos would sooner die than aid an emeny…
  2. Aargh! Do your worst, {class}! I’ll tell you NOTHING!
  3. Aahhhh! Release me! I am of no use to you. I swear it!
  4. Stop! I beg you, pleae stop. Please….
  5. Alright! I am beaten. {information you wanted goes here} Your mission is folly!

But you can keep zapping him a few times before turning in the quest…

  1. I’ve given you the information, {race}! You’re wasting your time….
  2. Noooo! This tortue is inhumane! You have what you want… why don’t you just kill me?

Even “better”… you can apparently get a fresh needler (I have not confirmed this) and continue frying the guy, just for fun…

  1. What more can you possibly want, {race}?
  2. Stop! Please…
  3. How can you possibly bring me lower?
  4. What more can you take away from me?
  5. You aren’t even asking me questions…
  6. Are you trying to meet the real me?
  7. You’ve got a darkness in you, {race}.

So, whether this is some kind of weird statement on current events or not, several people at Blizzard apparently think that torture can be useful and want to spread that opinion to their audience of millions. I mean, c’mon, it’s not like children play this game, right? …

Regardless of why the quest was written, why it was included in the game, and why it’s standing out above all of the other heinous things players have been asked to do in the game… it was a mistake and needs to be revised to avoid railroading players into a choice between being evil sadists and quitting the game. Everyone involved should be ashamed of themselves.

Back in the lead-up to Wrath, I’d suggested that one of the Hunter class’s biggest problems was the stable system. In my experiences over the last few days with Al, I hold this opinion more firmly than ever.

Every class has the option of carrying a second set of equipment around for different circumstances in instances. A cat druid might carry healing eq for certain boss fights where the extra hot is needed, any warrior worth two beans is going to have a shield somewhere on his person, etc…

Hunters and warlocks are both already heavily penalized in the inventory department, though to be fair they really don’t have much need to switch gear between fights. Hunters permanently sacrifice a bag slot to ammunition, and warlocks need to carry lots of shards – for which they can optionally choose to employ custom bags.

After spending only 17 points in demonology, a warlock can cycle through 3 different pets in ~6 seconds. They can adapt for different fights as necessary. To them, changing pets is roughly as difficult as changing weapons. A warlock’s pet (or often their lack thereof) is simply a buff like that granted by another class’s stances and auras.

If a hunter wants to switch pets, they have to run to the nearest town. No switching gear or rebuffing between fights for them.

Aspects aren’t big enough to warrant this discrepancy. They are essentially:

  1. I am shooting things
  2. I am out of mana because I was shooting things
  3. I am corpse running after my group just wiped
  4. I am fighting a boss that does nature damage
  5. I am not running out of melee range for some bizarre reason

So in normal practice, a hunter has two states – killing and in-combat downtime. Aspect of the viper is a complete joke since 3.0. Requiring players to alternate between the two is a big design flaw, IMO.

So if aspects aren’t a hunter’s “stances”, pets are the big candidate for the role.

Just like a paladin can strap on his shield to tank or put on a dress to heal, a hunter can use a gorilla to tank or a chimera to crowd control or a dinosaur to eat things… as long as he returns to town first.

Please, Blizzard. Just put hunter pets in the spellbook already.

Of course, my nefarious reasoning behind ALL of this is just so I can carry a set of 5 pets into a boss fight and resummon a new one when the old ones melt under his AoE aura – allowing me to actually have a pet out for the entire fight and waiting until after the fight to rez them ;)

As of version 5.0, PHP has had the ability to dynamically include required classes as needed - without requiring the developer to manually include all possible dependencies beforehand. This means that in cases where your code execution never touches 39 of the 40 classes in the project, it loads, parses, and runs that much faster.

There is a performance hit for actually having to call the __autoload() method, but if you're in a situation where the hit for executing a few extra comparison calls is unacceptable... you probably aren't developing in PHP in the first place ;)

Almost all of the php I've written in the last 2-3 years uses autoloading, and it has probably saved me hundreds of hours of aggravation.

In most of my projects, the first line of any script or class usually looks something like this:

require_once "/var/www/common/lib.php";

Then lib.php usually reads something like this:

<?
function __autoload( $class ) {
    include_once( "$class.php" );
}
?>

And that is all that is strictly required to make the magic happen. It is fast, it is easy to understand, it is easy to use. You can use require_once() or include_once() and there is very little meaningful difference.

I've looked around the net and found several other attempts at improving on this simple mechanism. But they invariably overcomplicate things. They attempt to recurse source directories, cache filename->class differences to the filesystem, and otherwise turn what should be a simple filesystem operation that the php environment supports natively into a mess of exception handling and wheel reinvention.

There are obviously theoretical instances where you might want to have more than the one require_once/include_once line... but I've honestly never encountered one myself.

I mean, you could try to throw an exception if the file didn't exist or otherwise failed to load... but nothing will happen. Failure to instantiate a nonexistant class is a fatal error in PHP, and will be handled as such with or without you - preempting any attempt at throwing an exception.

The only thing you can add is a bit of extra diagnostics or maybe logging to a separate location.

Assume that we have a file 'test.php':

<?
require_once "autoload.php";
$frog = new Frog();
?>

If autoload.php contains a simple simple autoload function that uses require_once(), and Frog.php doesn't exist anywhere in your include path, the results will look something like this:

ammon@kif:~$ php test.php

Warning: require_once(Frog.php): failed to open stream: No such file or directory in /home/ammon/autoload.php on line 3

Fatal error: require_once(): Failed opening required 'Frog.php' (include_path='.:/usr/share/php:/usr/share/pear') in /home/ammon/autoload.php on line 3

If we had used an include_once() call, the output is similar, but slightly more informative:

ammon@kif:~$ php test.php

Warning: include_once(Frog.php): failed to open stream: No such file or directory in /home/ammon/autoload.php on line 3

Warning: include_once(): Failed opening 'Frog.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /home/ammon/autoload.php on line 3

Fatal error: Class 'Frog' not found in /home/ammon/test.php on line 4

So that's probably a bit more useful in tracking down the error. Require calls don't return anything - they throw a fatal error on failure. Include calls, however, return FALSE on failure and TRUE if the file is (or, in the case of include_once, has already been) successfully included. So you can include_once() and write to a separate logfile (or to the output stream...) if you need more information than the fatal error already provides you.

<rant>

To those who insist on giving your classes and their containing files different names... umm. Wow.

If I have a class called DatabaseConnection, I'm going to put it in a file called DatabaseConnection.php. If I'm working with strange people who somehow don't think that is explicit enough, I might call it DatabaseConnection.class.php and tweak the autoload method ever so slightly to compensate. There's no good reason to put it in a file called projx-database_connection.incl or something. No. There isn't.

If you want to organize your classes into a meaningful directory structure... good for you. Use PHP's built-in include_path ini option. Don't waste time trying to cascade down a directory structure searching for the classes - just make sure your includes are all in a set of reliable locations. You don't actually have to edit the php.ini file and bounce Apache or your php-cgi processes, just define the additional include paths in the same file where you define your autoloader:

set_include_path(
    get_include_path() . PATH_SEPARATOR .
    "/var/www/includes" . PATH_SEPARATOR .
    "/var/www/includes/apple" . PATH_SEPARATOR .
    "/var/www/includes/banana"
);

Naturally, you could turn that into some function calls to dynamically register and unregister directories, etc... but at that point, you're probably hurting yourself again. If your codebase is being reorganized enough to make maintenance of the list of include dirs onerous without full time intervention, something else has probably already gone very wrong. At best, the code probably doesn't work anyway, so any brief delay in updating the list can't hurt any more than whatever else is happening.

</rant>

But seriously. __autoload() is your friend. It will help clean up your code if you let it. It can help enforce naming conventions. It can even improve performance... so long as you refrain from using it to shoot yourself in the foot. ;)

So... I am not happy with Adobe right now. With the push of Flash Player 9,0,115,0 "moviestar", which included such awesome features as H.264 and AAC codec support and improvements to fullscreen mode, they kind of ambushed me with some sweeping changes to their security policy.

I'd been running pre-release nightly builds of the player since 9,0,60,x... and had noticed some strange warnings. Mysterious "Socket Security Error #2048" exceptions that were being thrown at random - even though I was serving an appropriate (for the time) crossdomain.xml file, unexplained timeouts attempting to talk to an xml socket server when I was very clearly not attempting to do any such thing, etc... My regularly repeated attempts to find documentation on what the warnings actually meant proved fruitless. I believe that is because the appropriate document was not actually released to the public until 9,0,115,0 was released.

Now, the bit where they improved the format for crossdomain.xml files doesn't really affect me one way or the other. I approve of the improvements but could really care less in this case. They don't really affect anything I'm doing.

The part that really chaps my hide is the fact that they've completely redone the way that socket security policies are handled. The important parts:

  • A SWF file may no longer make a socket connection to its own domain without a socket policy file. Prior to version 9,0,115,0, a SWF file was permitted to make socket connections to ports 1024 or greater in its own domain without a policy file.
  • HTTP policy files may no longer be used to authorize socket connections. Prior to version 9,0,115,0, an HTTP policy file, served from the master location of /crossdomain.xml on port 80, could be used to authorize a socket connection to any port 1024 or greater on the same host.

That's right. Your socket policy data can't live in the sitewide crossdomain.xml file that Apache serves any more.

Flash Player 9,0,115,0 introduces a concept of socket master policy files, which are served from the fixed TCP port number 843.

Socket policy files may be obtained from the same port as a main connection (the socket connection being made by ActionScript, which is authorized by a socket policy file), or from a different port, separate from the main connection. If you opt to serve a socket policy file from the same port as a main connection, the server listening on that port must understand socket policy file requests (which are indicated by a transmission of from Flash Player), and must respond differently for policy file requests and main connection requests.

  • When a SWF file attempts to make a socket connection, even to its own domain, Flash Player will first attempt to contact port 843 to see if the host is serving a socket master policy file.

So... regardless of whether you're even using a custom port 843 client, the Flash Player is going to try to hit it. What if your firewall doesn't allow/route traffic to sub-1024 ports w/o special configuration? What if you don't have the access to bind to a sub-1024 port and can't rewrite your other server process to serve the policy data on its port?

  • Socket meta-policies can only be declared in a socket master policy file. The syntax is the same as for declaring a meta-policy in an URL master policy file, using the <site-control> tag. Socket meta-policies cannot be declared in HTTP response headers, as HTTP is not involved.

This implies that you can't even tell apache to listen to port 843 and serve up the data. You HAVE to either maintain a separate server process specifically for the purpose of serving this policy data, or you have to edit the process that SWF's are connecting to and make them serve the data..

As of the time of this writing (10 days after moviestar's release), they have yet to release promised help on how to deploy a solution to these new changes. Granted, the one article they did release explains what needs to be done in high level terms. It was sufficient to help me out. I wrote a server that simply listens on port 843 and spews the required xml. But... I'd have really appreciated specific examples, and I suspect plenty of people would appreciate drop-in solutions to the issue.

A 5-minute skeleton implementation (not recommended for production use by any means) written as a PHP cli script might look something like this:

#!/usr/bin/php
<?
/**
 * Ugly Flash socket policy file service. This script must be run as root from
 * the command line. It binds to port 843 on all interfaces and waits
 * indefinitely for connections. When a connection is detected, the script spits
 * out a chunk of xml and disconnects. It can only serve one request at a time,
 * but that shouldn't be much of a problem.
 *
 * One potential problem with this script is that you can easily lock port 843
 * up for an indeterminate amount of time if the script doesn't exit cleanly.
 * The OS should clear the port up for you eventually, but you could be stuck
 * playing the waiting game.
 *
 * This particular version of the script has only been tested very lightly.
 * Deploy at your own peril ;) YMMV.
 *
 * - Ammon Lauritzen [12/13/07]
 */

// define the xml policy "file"
$policy_file =
    '<'.'?xml version="1.0" encoding="UTF-8"?'.'>'.
    '<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd">'.
        '<allow-access-from domain="*" to-ports="*" secure="false" />'.
        '<site-control permitted-cross-domain-policies="master-only" />'.
    '</cross-domain-policy>';

// make sure everything launches correctly
if( posix_getuid() != 0 )
    die( "You must run this script as root.\\\n" );

$sock = @socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
if( !$sock )
    die( "Unable to create socket.\\\n" );

$succ = @socket_bind( $sock, "0.0.0.0", 843 );
if( !$succ )
    die( "Unable to bind to port 843.\\\n" );

$succ = @socket_listen( $sock );
if( !$succ )
    die( "Unable to start listening.\\\n" );

// start serving policies
while( true ) {
    $r = $w = $e = array( $sock );
    if( @socket_select( $r, $w, $e, null ) !== false ) {
        $conn = @socket_accept( $sock );
        if( $conn !== false ) {
            // somebody connected, just dump the xml and close
            socket_write( $conn, $policy_file );
            socket_close( $conn );
        } else {
            echo "socket_accept() failed?\\\n";
            break;
        }
    } else {
        echo "socket_select() failed?\\\n";
        break;
    }
}// end: listen forever

// clean up
socket_close( $sock );
?>

I'll try to make my production version of this a bit more suitable for public consumption and release it as soon as I can.

The random #2048 security errors continue, despite having deployed my port 843 policy xml server. Granted, they happen less than before... but they still happen. And even when my policy server isn't running, the errors aren't thrown 100% of the time. This just baffles me. If they were consistent, that would be one thing. But when you get a security error 1 time in 20... that's not security, that's not even a lame deterrent. It's just incentive to hammer the same port over and over again until something finally gives.

Now, I admit that I could be wrong here... but I've re-re-read the documentation on these policies a few times now, and cannot find any reason for the behaviors I'm seeing.

update

On April 22nd, 2008, I released a much better, much more reliable version of this daemon. Head over there for more details and source code.

Today I swiped the office's spare monitor, grabbed a cheap PCI video card, and am now seated at a desk with something just shy of five million pixels of doom (1600x1200 + 1600x1050 + 1280x1024). It's a lot of space, and after having used it for about an hour now, I'm wondering if it really IS a bit excessive. Oh well, I'll see how I like it a few weeks from now.

As part of testing out my new monitor layout, I decided that my 3rd screen currently gets to hold my email as I work like normal on the remaining two. The only new message in my inbox intrigued me (kind of) - it was a survey from ADV, an fine company who's done a lot to bring some of the better anime out there (and some of the worst :P ) to this country. I figured that the survey couldn't hurt, and they promised it wouldn't take more than five minutes.

Well, they lied. Most of the questions were innocuous inough. Which demographic categories can we file you under? Which genres do you like? Do you read Newtype? etc... But one question...

Q: Would you buy anime for download?

A: After looking at their selection of initial offerings, and at their FAQ page, I clicked No.

They then offered a box for me to explain my answer. I don't know if their database will have been configureded to deal with a response of the length I provided. :)

Crippled files with DRM are an abomination. They break digital standards and mandate my choice of player software and even operating system if I want to watch them. At least with a physical DVD purchase, I can watch it on any computer I want AND on my dvd player/playstation/father-in-law's 50" tv/whatever... At $5/episode, it's just not worth the inconvenience.

Especially since you're using inferior WMV files that lack such 5-year-old features as multiple audio tracks and optional subtitles. Are all of your files dubbed? Yuck. If I'm gonna be cheap about my shows, I'll just wait until they're in the discount bin or buy them used or support my local comic shop and rent them or something.

Besides, DRM doesn't work. People are ALWAYS going to find ways around copy protection on digital media. There are countless pirates out there with nothing better to do with their time than bypass the latest audio/video/whatever protection scheme.

I'd wanted to go on, but as it is, they're probably not gonna get the whole rant, much less read any of it. Oh well. Maybe one day they'll realize that they can make money by selling whole files, not broken ones.

If it was $5 for dual-audio ogg or mkv files that I could play in VLC or if they offered PDA-sized AVI's that I could carry with me and that wouldn't necessitate that I use Windows Media Player? I'd have bought a few episodes on the spot. In stead, I have little confidence in this part of the industry getting any better for a very long time.