Progress progress progress. Never enough, but more than before. Time for an update.
Less Is More
In my last post, I bemoaned the amount of programmer’s debt in the A&A code. So, how bad was it? In the networking code, there was over 70 different types of packets. Gratuitous editing has taken this down to 9. There was a large number of packets used in the client/server model that were no longer needed. Many functions were just hanging around in the hope of being used again, but I find this was just distracting and making the core concepts even harder to identify. They had to go and I’ve proceeded to pluck them out one by one. Removing one packet would then lead to a section of code that handles the packet and even more dead subsystems (such as the file transfer routines that are no longer used, or the mechanics for handling a server side store).
I can hear the question from the audience, “But won’t you need that sometime.” And the answer is, “Maybe.” Yes, I admit some of these features will be needed again, but they are not needed now. And, I still have copies of the original code with those features. But for now, its about getting back to the core.
The Magic Number
And getting to the core has allowed me to fix some of the problems plaguing the join/start system. But I got tripped up with a crazy bug that totally eluded me for the longest time. Here are a few details.
One of the goals I set out for this new networking is to allow players from DOSBox and Windows play games with each other. Someone with a Linux or Mac could use the DOSBox version and link up with another with a Windows player. It seemed like a neat idea and since DOSBox’s code was available for doing IPX networking, I decided to pull it out and set it up in the A&A Server program I wrote (you can use the DOSBox server as well, the A&A Server is just a self standing version). Upon making the A&A Server, I found that it worked — or so I thought. Before all of my networking changes, two DOSBox instances could use the A&A Server and talk to each other. Cool.
Then I added the Windows port and setup the networking code. I then proceeded to test two Windows instances on the A&A Server and that worked. Cool also.
However, when I mixed Windows and DOS programs, I found that Windows instances could see DOSBox output, out DOSBox instances could never see Windows instance output. What? Makes you want to sit down and make a logic puzzle or diagram out of it.
At first, I thought it was a problem with the A&A game code. Perhaps the code was compiling differently between DOS and Windows. Nope.
Finally, I pulled out Wireshark — the best tool for debugging networks. I wish we had this tool back in 1995. It would have saved me a ton of time. Looking very closely at the packets coming from DOSBox and Windows, I finally found the problem — the Magic Number. Well, that’s not its real name. The real name is IPX socket number.
The IPX network is a different networking system than TCP/IP. Novell’s Netware system was a contender (more or less) to the networking world way back, but it never did scale up like TCP/IP did on big networks, so it fell by the wayside. But it had a similar concept called a socket number … usually known as a port number. There are plenty of details here I’ll skim over (such as a source and destination port number and how they’re assigned), but let’s just call it a magic number. The problem is that when I created the Windows software, I accepted all IPX packets regardless of their destination port number. DOSBox does too. So, where is the problem?
When creating A&A, I setup a system where a different networking driver can be loaded before the A&A program is run. There were three versions: One for serial, one for modem, and one for IPX. We use the serial port one for single player mode too, but it doesn’t talk out the port. Anyway, when I went to start adding debug code to the IPX driver version, I found it — the magic number. That IPX driver would filter packets that didn’t have a port destination of … drum roll please … 0x869C (34460). The IPX Driver is only used by the DOSBox version. And only incoming packets were filter. The windows version was using the TCP/IP port number (213) instead of the magic number (0x869C). Thus, the DOSBox version would not talk to any packets coming from a Windows instance, but Windows would not filter and accept anything that came from the rest of the computers.
Changing 213 to 0x869C fixes the problem and now everyone can talk to everyone. Problem solved.
Three Up
With these changes, I can now have 3 players start a game, see each other in the 3D world, and affect it. Too bad I’m still having instability problems and a few other known issues. But I was excited to see the players finally on a map. They also seem to move smoothly. That’s nice!
Then I noticed all the graphical errors when a player attacks and how players slide instead of walk. Sigh.
But my goal is simple: Setup a server where many players can meet (community server or personal server), join up in groups up to 4, and play through the original levels. And I want it all stable.
Slowly but surely, we’ll get there.
Almost forgot the music of the day: Collide’s song Razor Sharp: http://open.spotify.com/track/5w4HTOiiKmNBhCs50eJ4jk
I’m finding I’m liking the group Collide more and more, but you have to tune your ear to listening to them.
Oh, and a teaser … work on an editor is coming along too…..
Ooh! I am excited for this. What are your thoughts for mission management? It would be awesome if it were as easy as “drop archive into folder, choose which to play from mission folder on game startup.” I imagine that some authors may want to include their quest with the original campaign, while others might want to create a new campaign independent of the original missions.
I’ve been debating how to approach additional maps to the game. In it’s current incarnation, you could just add another set of maps on top of the game as long as you have a unique 16-bit number for your map. I suspect people would be better served with a ‘campaign’ selector that allows users to choose a set of maps and possibly additional unique items/creatures/etc. Campaigns would not mix with other campaigns (but you certainly could steal). Unfortunately, this means characters created on one campaign can not be ported to another.
Oh, hey, didn’t notice you had updated a bunch recently. Sorry to hear about what happened. I hope everything’s going okay.
On the subject of characters, campaigns, and mods, I had some musings:
You could separate character storage and campaign storage into different files. Each character would get its own save directory, and then in the save directory, you store the main character file (e.g. “AA\char\char0000\char.dat”), which contains your character’s independent data, then you also have one file for each campaign the character is currently involved in (e.g. “AA\char\char0000\campaign\funtimes.cpn”). These files would store the progress-related data for that campaign, so that if you hop back and forth between two different campaigns, you can keep your progress in both. Essentially, from the user’s point of view, you’d create your character like now, then you’d get a list of campaigns to choose from. At any point, you could select a different campaign to play in, similar to how quests currently work in AA, but since a campaign would be a collection of quests, it would be one level above that. Alternatively, campaigns could work at the same level as a quest, meaning that all the quests currently in AA would each be separate campaigns. There’s nothing really wrong with that approach, but I think it’s more interesting the other way.
In order to allow characters to be compatible with multiple campaigns with different item, enemy, spell, etc definitions, these should be required to be stored in a separate modpack file (e.g. “AA\mods\ExtendedWeapons.mod”). A campaign would specify its mod dependencies (and could be easily packaged with its dependencies for distribution), and when a character plays in that campaign, the character would also inherit those dependencies. From there on out, the character would always read from the inherited mod dependencies so that extended properties on the character could be interpreted properly in any campaign. It may also be possible for a player to remove dependencies from a character, as well, and this would destroy any extended properties reliant on them.
Note that in order to prevent conflicts with common definition IDs in a modpack (e.g. two different people naming a new item ‘BlackSword’), a unique identifier system should probably be implemented. Internally, any definition ID used in a campaign could have the campaign’s name prepended to it. So, while a modpack named “ExtendedWeapons” might define an item named “BlackSword”, internally the game would see it as “ExtendedWeapons*BlackSword”, where the asterisk is any special character that modders cannot use in definition IDs. This also provides a convenient reference for which modpack defines which extended properties on a character. The only potential name conflict after that is two different modders having a modpack with the same name, but that isn’t a major problem; it’s relatively easy to predict, recognize, and fix. In the event that two different mods alter the same property (e.g. changing the mana regeneration scale for a mage), you’d have to figure out some method of resolving the disparity (seniority preference?), or just erroring out.
Of course, none of this is really necessary; you could only allow characters to be engaged in one campaign at a time or only one campaign ever, and conflicting mod dependencies would result in an automatic failure. I think players tend to value their characters a lot, though, so letting them keep the same character around as long as possible is generally a plus. I know I still cart out some of my old characters in AA just to play around.
Your do make some good points. I’m working on the next developer post about the Community Edition. Some of what you talk about is to be covered (although lightly).
Pingback: Party of Four? Your Windows Game is Ready, Wix is Evil, and a Three Pronged Plan for the Community Edition | Amulets & Armor Developer