Scalability and Asserts I’m Not Yet Fixing

I’ve been a bit quiet because I’ve been working on (hopefully) completely invisible stuff involving backend server scalability.  What does that mean, you ask?  In practical player-facing terms, it means I’m trying to get the lobby and registration system robust enough to first invite the rest of the waiting list in,1 and then to open the beta up completely, allowing people to hear about the game, visit the site, pay their money, and get into the beta instantly.  Between 10 and 500 people sign up a day, depending on how much press the game is getting at the time, and I’m very curious to find out how many of those will join the beta if it’s available immediately, and they aren’t told they have to wait.

I’m currently working on the text-mode robot client.  I’ve got it logging into the lobby and pretending it’s a full SpyParty client, and it can chat, and invite people to games.  I posted on facebook and twitter asking for suggestions of what the robots should say to each other as they’re hanging out in the lobby.

Next up, I’m going to get the robots playing fake matches and games and reporting the game results to the lobby, and logging in and out a bunch.  Then, I’m going to hack up the bees with machineguns load testing app to launch a bunch of EC2 micro instances with multiple robots running on each, and aim them all at my test server.  I expect chaos.

Once I’ve got the obvious stuff fixed, and have figured out how many clients my system can host at a given machine size, I’ll do some tests with beefier machines to make sure it scales linearly.  There are four basic machine resources: CPU, memory, network, and disk…I assume I’ll run out of memory first, but I don’t know for sure.  I was originally going to try to get the entire backend infrastructure running in the cloud, but I think for the near term I’m going to just make sure I get a machine that can accept way more clients signing up and playing than I think I’m going to get when I open up the beta, and hope it holds up.  If it dies due to too much traffic, well, I guess that’s a good problem to have, at least!  I did this same kind of thing with when I started taking beta signups, and I stress tested and optimized it well enough that it didn’t even break a sweat, so hopefully the beta launch itself will go as smoothly. If not, then if Blizzard can do it, so can I! Yikes.

Then, once I’ve got the backend scalable for the robots, I’ll start inviting much larger groups into the beta to loadtest with live players.  There are some features I’m going to need to add to make this work, like chat rooms and colored chat text, and it’s going to be pretty raw to start with, but it should work okay.  The beta testers have been very forgiving of my incredibly primitive lobby so far, so hopefully that attitude will continue!

After everybody’s in, I’ll shut off the signups and let it stew for a few days, and if it’s working, I’ll open it up!  I hesitate to give time estimates on this stuff, because I’ve never hit a date, but most of this will be happening over the next few weeks.

Asserts!

Programming is complicated, and handling errors makes it even more complicated.  Oftentimes, it’s good programming practice to not handle some types of errors gracefully, but simply assert that you aren’t in a state you shouldn’t be in, and if the assertion fails, you exit with an error.

assert(1 + 1 == 2);  // integer arithmetic better work or we're hosed

Of course, during development, the impossible is not only possible, but likely, and so your asserts fire.  And, often in complicated code, you’ll assert things that should be true, but aren’t catastrophic if they’re not true, and so you usually pop up a dialog that gives you the choice to break into the debugger, abort the program, or ignore the assert (just this once, or forever).  The problem is, once you let yourself have that ignore option, you can get lazy, and start using asserts as popup reminders of things to fix.  This tends to be really bad on a large team, because the game is asserting every 2 seconds, and you’re just hitting ignore all the time to other people’s asserts, and it becomes a habit.  However, on an indie sized team, which in my case means exactly one programmer, one can use asserts this way and they can still be useful.  I can get a feel for how often certain types of things are going wrong while I’m testing, and I can remember what I was doing when a specific assert fired most of the time…it goes from a purely quantitative tool to a qualitative tool.

I also can leave the asserts on in beta builds, but in a way that fires silently once and then auto-ignores-forever, and then have them shipped off over the network to the server, so I can see what kinds of things are going wrong on player machines, and how frequently they go wrong.

I tend to be pretty liberal with asserts in my code, and so they fire a lot, and in turn the server logs a lot of them.  About 30000 of them so far in the beta.  Here they are, sorted by frequency:

4918 internalMcostTest(sx, sy)
object_system\subsystems\pathing\pathing.cpp
2237 holding
object_system\subsystems\animation\animation.cpp
2237 ad
object_system\subsystems\animation\animation.cpp
2145 am && (right || left)
object_system\subsystems\animation\animation.cpp
1780 am->playing.blend_out == am->queue.front().blend_in
object_system\subsystems\animation\animation.cpp
1485 am && (boneId != -1) && ad
object_system\subsystems\animation\animation.cpp
1415 cd->object_of_interest
character.cpp
1350 d->NearBookcaseID
situations\bookcase\bookcase.cpp
1114 (err = glGetError()) == GL_NO_ERROR, “code: 0x00000501”
spyparty.cpp
1105 cd->object_of_interest && (cd->object_of_interest == BriefcaseID)
situations\briefcase\briefcase.cpp
994 StatueAD && (StatueAD->Object->Type == object_types::STATUE) && (object_system::GetObject(StatueAD->ParentID)->Type == object_types::PEDESTAL)
situations\pedestal\pedestal.cpp
952 am && (am->playing.type == &core_talks)
situations\conversation\conversation.cpp
813 BriefcaseAD && HoldingBriefcase && d->PlayingCycle
situations\briefcase\briefcase.cpp
801 !d->PlayingCycle
situations\drinks\drinks.cpp
628 verify( pathing::pathGetCharacterValue(x, y) == BriefcasePathValue )
situations\briefcase\briefcase.cpp
539 verify( animation::HandleDetach(am, am->Events[i].event->boneId, cd->holding_right, cd->holding_left, &OnRight) && OnRight )
situations\briefcase\briefcase.cpp
478 cd->object_of_interest == BriefcaseID
situations\briefcase\briefcase.cpp
469 !PoppedYesNoQuestioner
spyparty.cpp
413 d->GoalPedestalID == d->NearPedestalID
situations\pedestal\pedestal.cpp
278 HoldingBriefcase && BriefcaseAD
situations\briefcase\briefcase.cpp
252 verify( HandleDetach(am, am->Events[i].event->boneId, cd->holding_right, cd->holding_left, &OnRight) && OnRight )
situations\pedestal\pedestal.cpp
236 IK.Bone && IK.Target && IK.MeshHardpoint
object_system\subsystems\animation\animation.cpp
229 am->queue.empty()
object_system\subsystems\animation\animation.cpp
216 x == p->ex && y == p->ey
object_system\subsystems\pathing\pathing.cpp
193 0, “unknown packet type: 9”
spy_server.cpp
188 !”stuck!”
character.cpp
172 cd->disposable_left
situations\pedestal\pedestal.cpp
160 verify( pathing::pathGetCharacterValue(x, y) == pathing::PATH_VALUE_INFINITE )
situations\briefcase\briefcase.cpp
151 !cd->holding_right || (cd->holding_right == d->BookID)
situations\bookcase\bookcase.cpp
139 (cd->holding_left == d->BookID) && (!cd->holding_right || (cd->holding_right == d->BookID))
situations\bookcase\bookcase.cpp
110 e.MatchTimestamp > RoundTimeline[LastMarkSuspectIdx].MatchTimestamp
round_events.cpp
97 verify( GetConnectionNames(Us, sizeof(Us), Them, sizeof(Them)) )
spyparty.cpp
78 0, “unknown packet type: 15”
spy_server.cpp
77 0, “unknown packet type: 9”
sniper_client.cpp
74 Distance2(cd->Object->Position, ps_sci->Object->Position) <= MaxHandoffDistance2
situations\briefcase\briefcase.cpp
70 !gd->ForceGoToPedestalID
situations\steal_statue\steal_statue.cpp
66 am->playing.type == &core_briefcase_pickups
situations\briefcase\briefcase.cpp
59 !”spy stuck!”
spy_server.cpp
59 0, “unknown packet type: 9”
spyparty.cpp
55 pathTestOpen(sx, sy)
object_system\subsystems\pathing\pathing.cpp
50 0, “unknown packet type: 7”
spy_server.cpp
48 d->BookBookcaseID && cd->IsGoalOwner(this)
situations\bookcase\bookcase.cpp
43 !”what do to here?”
examples\lobby\lobbyclient.cpp
40 verify( animation::GetPlayingAnimationInfo(am, &time, &duration) )
situations\conversation\conversation.cpp
40 HoldingBriefcase
situations\briefcase\briefcase.cpp
40 am->playing.animid == -1
situations\pedestal\pedestal.cpp
35 n
spyparty.cpp
32 e.MatchTimestamp > RoundTimeline[LastMarkBookIdx].MatchTimestamp
round_events.cpp
26 verify( animation::HandleDetach(am, am->Events[i].event->boneId, cd->holding_right, cd->holding_left, &OnRight) && !OnRight )
situations\bookcase\bookcase.cpp
26 object_system::GetObject(cd->holding_left) && (object_system::GetObject(cd->holding_left)->Type == FNV1(“BOOK”))
situations\bookcase\bookcase.cpp
26 it != am->AnimHandleMap.end()
network.cpp
26 IsTypingString
spyparty.cpp
26 0, “unknown packet type: 8”
spyparty.cpp
25 DefaultCharacterStatePacket && (ndata == CharacterStatePacketSizeBytes)
sniper_client.cpp
25 cd->object_of_interest == d->BookID
situations\bookcase\bookcase.cpp
24 !p2pauth_con && (p2pauthn_state == WAITING_AUTHN)
examples\lobby\lobbyclient.cpp
24 !IsSpy && d->TargetBookcaseID
situations\bookcase\bookcase.cpp
24 HoldingDrink
situations\drinks\drinks.cpp
23 obj->Rotation.IsIdentity()
character.cpp
23 HoldingBook
situations\bookcase\bookcase.cpp
23 !err, “krb5_rd_priv err: -1765328342”
examples\lobby\lobbyclient.cpp
22 (w >= 0) && (w <= 1)
object_system\subsystems\animation\animation_cal3dutils.cpp
22 d_cust && (d_cust->State == drinks_data::INVALID)
situations\serving\serving.cpp
21 !”somehow in a valid state but !HoldingDrink?!”
situations\drinks\drinks.cpp
20 propid && ( (Spy->holding_right == propid) || (Spy->holding_left == propid))
situations\steal_statue\steal_statue.cpp
20 !HoldingDrink
situations\drinks\drinks.cpp
18 !”somehow didn’t get statue”
situations\pedestal\pedestal.cpp
18 ad && (ad->Object->Type == object_types::STATUE)
situations\pedestal\pedestal.cpp
16 o && !(o->Flags & object::UNMANAGED)
object_system\object_manager.cpp
16 am->queue.empty()
situations\drinks\drinks.cpp
13 !”something went wrong picking up briefcase!”
situations\briefcase\briefcase.cpp
12 !”should have detached”
situations\bookcase\bookcase.cpp
11 !”should not get here”
situations\conversation\conversation.cpp
11 0, “unknown packet type: 11”
spyparty.cpp
10 (w >= 0) && (w <= 1) && (u >= 0) && (u <= 1) && (v >= 0) && (v <= 1)
checkerlib\misc\geomutils.cpp
10 verify( network::SendPacket(&gs, sizeof(gs), true) )
spy_server.cpp
10 (rem >= 0.0f) && (rem < 1.0f)
spyparty.cpp
10 Pedestal
situations\pedestal\pedestal.cpp
10 (err = glGetError()) == GL_NO_ERROR, “code: 0x00000505”
spyparty.cpp
9 Statue && (Statue->Type == object_types::STATUE)
object_utils.cpp
9 Level
network.cpp
9 !err
examples\lobby\async_krb5_wrapper.cpp
9 0, “unknown packet type: 1”
sniper_client.cpp
8 SpyCheck == player_control::state::TESTING
situations\check_watch\check_watch.cpp
8 ObjectIDToByte.empty() || nettest_mode
network.cpp
8 !IsSpy && cd->object_of_interest
situations\pedestal\pedestal.cpp
8 ByteToObjectID.empty() || nettest_mode
network.cpp
8 0, “unknown packet type: 20”
sniper_client.cpp
8 0, “unknown packet type: 13”
spy_server.cpp
8 0, “unknown packet type: 13”
spyparty.cpp
7 ObjectIDToByte.empty() && ByteToObjectID.empty()
network.cpp
7 (CameraMode == SNIPER_CAMERA) && Level
round_events.cpp
7 0, “unknown packet type: 24”
spy_server.cpp
6 SwapStatueID && ( (Spy->holding_right == SwapStatueID) || (Spy->holding_left == SwapStatueID))
situations\steal_statue\steal_statue.cpp
6 RoundTimeline.size() < round_events_packet::MAX_NUM_EVENTS
round_events.cpp
6 o
network.cpp
6 mc && (mc->Object->Type == object_types::STATUE) && (StatueMeshIndex < mc->Meshes.size())
object_utils.cpp
6 IsChatAllowed()
spyparty.cpp
6 ad
object_utils.cpp
6 0, “unknown packet type: 21”
sniper_client.cpp
5 !”shouldn’t get here”
situations\steal_statue\steal_statue.cpp
5 mark_value <= 1.0f
spyparty.cpp
5 client && client->OtherClientID
spyparty_lobby.cpp
5 0, “unknown packet type: 25”
spy_server.cpp
4 !”shouldn’t get here, must have moved while holding book”
situations\book_transfer\book_transfer.cpp
4 object_system::GetObject(History.States[i].ID)
network.cpp
4 Level
sniper_client.cpp
4 Level->ActiveGameTypeIndex < Level->GameTypes.size()
sniper_client.cpp
4 !err
examples\lobby\lobbyclient.cpp
4 am
network.cpp
4 0, “unknown packet type: 10”
spyparty.cpp
3 SpyCheck == player_control::state::TESTING
situations\seduction\seduction.cpp
3 !”shouldn’t get here”
examples\lobby\lobbyclient.cpp
3 i_ind == i_dep+1
character.cpp
3 !Focus
player_control.cpp
3 Control->GetSpyTriggeredResult(this) == player_control::state::TESTING
situations\double_agent\double_agent.cpp
3 !(ChooserCurrentCharacter->Object->Flags & object_system::object::UNMANAGED)
ui.cpp
3 am->Events[i].animation->getCoreAnimation()
situations\drinks\drinks.cpp
3 0, “unknown packet type: 16”
spyparty.cpp
3 0, “unknown packet type: 15”
spyparty.cpp
2 verify( network::SendPacket(&p, sizeof(p), true) )
network.cpp
2 verify( network::SendPacket(&gs, sizeof(gs), true) )
spyparty.cpp
2 verify( ConfirmGameIDToLobby(CurrentPlayID, CurrentGameID) )
spy_server.cpp
2 verify( animation::GetPlayingAnimationInfo(am, &time, &duration) )
situations\book_transfer\book_transfer.cpp
2 t >= 0
round_events.cpp
2 State.CurrentNode->Parent->StringSoFar == State.CurrentLeaf->StringSoFar
spyparty.cpp
2 s
checkerlib\misc\glutils.cpp
2 mc
situations\steal_statue\steal_statue.cpp
2 glMultiTexCoord2f_ && glActiveTexture_
spy_server.cpp
2 GameIDs.find(PacketPlayID) == GameIDs.end()
examples\lobby\lobbyclient.cpp
2 !err && p2pauth_con && krbtgt.data && (krbtgt.length < KRBTGT_LIMIT)
examples\lobby\lobbyclient.cpp
2 (err = glGetError()) == GL_NO_ERROR, “code: 0x00000506”
spyparty.cpp
2 !decoder.underflowed() && decoder.on_last_byte()
examples\lobby\lobbyclient.cpp
2 CurrentNetworkObjectID
network.cpp
2 !ChooserScrollDrag
ui.cpp
2 (cd->object_of_interest == d->BookID) || (ps->status != pathing::PATH_success)
situations\bookcase\bookcase.cpp
2 cd->object_of_interest && (cd->object_of_interest == d->BookID)
situations\bookcase\bookcase.cpp
2 ATPCachedDescription
player_control.cpp
2 Array && Num
checkerlib\misc\utils.h
2 am->playing.type == core_book_hidefilm_okay
situations\book_transfer\book_transfer.cpp
2 0, “unknown packet type: 8”
sniper_client.cpp
2 0, “unknown packet type: 2”
spy_server.cpp
2 0, “unknown packet type: 22”
sniper_client.cpp
1 verify( network::SendPacket(DefaultCharacterStatePacket, CharacterStatePacketSizeBytes, true) )
spy_server.cpp
1 verify( network::SendPacket(CommandsPacketBuffer, SizeBytes, true) )
network.cpp
1 verify( Camera.Project(vector_3(0, 0,0), &origin) )
spyparty.cpp
1 StatueAD && (StatueAD->Object->Type == object_types::STATUE)
situations\pedestal\pedestal.cpp
1 !”somehow didn’t get book”
situations\bookcase\bookcase.cpp
1 ScreamSound
spy_server.cpp
1 network::IsConnected()
spy_server.cpp
1 it != NetTestByteMap.end()
network.cpp
1 fabs(1-Length2(Axis)) < 1e-5
checkerlib\misc\math4d.h
1 (err = glGetError()) == GL_NO_ERROR, “code: 0x00000502”
spyparty.cpp
1 DefaultCharacterStatePacket && (ndata == sizeof(*DefaultCharacterStatePacket) + DefaultCharacterStatePacket->NumCharacters*sizeof(DefaultCharacterStatePacket->States[0]))
sniper_client.cpp
1 !decoder.underflowed()
network.cpp
1 !decoder.underflowed() && decoder.on_last_byte()
network.cpp
1 (d >= 0) && (d <= 1)
c:\users\checker\dev\spyparty\project\spyparty\code\network.h
1 CharacterStatePacket && (CharacterStatePacket->NumCharacters <= MaxNumCharacters)
network.cpp
1 ByteToObjectID.find(CurrentNetworkObjectID) == ByteToObjectID.end()
network.cpp
1 0, “unknown packet type: 8”
spy_server.cpp
1 0, “unknown packet type: 6”
spy_server.cpp
1 0, “unknown packet type: 6”
sniper_client.cpp
1 0, “unknown packet type: 4”
sniper_client.cpp
1 0, “unknown packet type: 2”
sniper_client.cpp
1 0, “unknown packet type: 25”
sniper_client.cpp
1 0, “unknown packet type: 19”
spyparty.cpp
1 0, “unknown packet type: 18”
spyparty.cpp
1 0, “got new play id with existing: 0xca98 “
sniper_client.cpp
1 0, “got new play id with existing: 0x57a5 “
sniper_client.cpp
1 0, “got new play id with existing: 0x5267 “
sniper_client.cpp
1 0, “got new play id with existing: 0x3e15 “
sniper_client.cpp
1 0, “got new play id with existing: 0x33fc “
sniper_client.cpp
1 0, “got new play id (0xabeb) with existing (0xcdb6) “
sniper_client.cpp
1 0, “got new play id (0x6f9f) when already playing with existing (0xfb2e) “
sniper_client.cpp
  1. currently at 16681 people as of this post []

SpyParty at Evo 2012 pics!

I’m back from Evo, and finally mostly rested.  It was a lot of fun!  I had no idea what to expect and so I went in with no expectations, and that’s good, because it turned out to be quite different from previous playtests. The show floor was a small part of the overall event, and the main focus was obviously on the competition, so attendees were able to enjoy the Indie Showcase titles without the long lines that always happen at PAX. For SpyParty, this meant people could play for longer, come back more often, and explore more of the game’s depth. I had the same booth setup as PAX West 2011, with the three stations, and it worked out pretty well. People seemed to enjoy the game and the stations were almost always full, and as our voices gave out,1 we had attendees train other attendees, which I particularly like because it starts to get to some of my future goals for mentoring modes.

I have to admit, I was slightly worried we’d get beat up or something, but actually my first experience with the Fighting Game Community was really positive, and they really seemed to appreciate the depth of the game and what I’m going for.

I want to thank Tom and Tony Cannon, and Seth Killian for making this possible, it was a really great time.

Below are a ton of pics. Continue reading ‘SpyParty at Evo 2012 pics!’ »

  1. The show floor hours were 8am to 12am!!! Holy cow that’s exhausting…PAX hours are like 10am to 6pm! []

Competitive Gaming: Come Play SpyParty at Evo in Vegas, July 6th & 7th

I give a lot of lectures on games.  In these lectures, I often talk about games as an art form, and how games are different from the other popular and important art and entertainment forms.  Even though we often get compared to film, I think when games finally fulfill their potential, they will be as deeply different from film in the ways they affect people emotionally as film is from music or painting.1

I don’t think anyone knows exactly what these differences will feel like in 50 or 100 years, but I think we can get whiffs of them in current games, and for me, the scent is especially strong in competitive player-skill games.  There is something about a competitive player-skill game that gets to the essence of interactivity, the thing that makes games different from the other art and entertainment forms.  The players, interacting with the game systems and each other, using their physical and mental skills to achieve a clearly defined win-state…it can be magic.  Although there are many different-yet-amazing competitive player-skill games, like my old flame Counter-Strike, but also obviously Starcraft, and DOTA/League of Legends,2 I think the magic I’m talking about is most clearly captured in this famous clip of a Street Fighter tournament:

There have been articles written about these seconds of gameplay, it has become internet-famous, and I have used it in several of the aforementioned lectures.

This magical thing happened at a fighting game tournament called The Evolution Championship Series, or more commonly, Evo.

It’s always been one of my design goals for SpyParty to be regarded as a competition-worthy player-skill game, to try to attain the depth of a game like Counter-Strike or Street Fighter, but by emphasizing a very different set of player-skills from the current crop of competition games.  However, to be included in that pantheon your game has to be able to stand up to thousands of hours of play, and designing a game like that turns out to be very hard.  Luckily, I’m patient, but I’m expecting it to take years for SpyParty to get to that level, if it ever does. Eventually, once the game was balanced and tuned and deep enough, I hoped people would start running tournaments, and maybe those tournaments would grow, and then, who knows.  But I’m getting way ahead of myself…

The Email

This is all by way of saying I’ve been fascinated by Evo for a while, but hadn’t spent much time thinking about how it relates to me and my game right here and now.  And then my friend Seth Killian emailed me, “Would you be interested to bring SpyParty to Evo this summer?”

Whoa.

He went on, “Obviously your game isn’t a fighter, but what’s interesting about these guys is that they aren’t just good at fighters–they’re good at games, and breaking down systems, period. They like games that involve psychology, competition, or are just insanely difficult.”

Now you’re talking.

The Show

So, after I said “YES” as fast as I could, Seth introduced me to Tom Cannon, and it’s happening, and I’m nervous but very excited!  Did I mention the nervous part?  The fighting game community is well-known for their, um, honest feedback, and I’m hoping they like SpyParty, but if they don’t, I’m hoping they’ll tell me why, and not just beat me up or something.

In fact, to this end, I offered to invite a bunch of Evo attendees into the beta before the show, so they could read the manual, practice, and play some games online with the current beta testers to increase the level of play once we get there.  Tom put a signup form on the announcement and got over twice as many signups from registered Evo attendees as we planned, so he had to shut it down.  I was originally going to invite 50, but I may try to invite even more of them this week.  I expect some of them will be pretty good by the time the show starts if they practice.  I’m going to do a similar setup to last year’s PAX booth, so three 1v1 stations, but this time I’m also going to try to get two of them on the internet so people in the beta lobby can play people at Evo.  I hope some of the expert players will hang around the lobby to give hands-on demonstrations of SpyParty‘s current player-skill depth!

Even better, it turns out Tom and Seth wanted to have a bunch of player-skill competitive indie games at the show, so they’ve got a great lineup for their Indie Showcase, including AztezBaraBariBall, DIVEKICK, Nidhogg, Super Comboman, and Super Time Force!

But, the coolest thing of all is that I found out the Evo expo is open to the public and free on July 6th and 7th!  So, if you’re in the Las Vegas area, or within driving distance, come by and play SpyParty and all these indie games!  Oh, and I’m sure there’ll be a couple fighting games around somewhere to play if you look hard enough.

Postscript

I have my work cut out for me trying to make SpyParty deep enough to be a competitive gaming title, of course.  There have been a few different articles about the game’s upcoming appearance at Evo, with comments ranging from “awesome!” to “wtf?!”, but my favorite comment was on the Kotaku piece:

LuppyLuptonium Tue 26 Jun 2012 8:26 PM
This is like Bingo being played at an NBA basketball game…. Nothing necessarily wrong with it but strange.
  1. This is why I wish people would stop wasting their time making big movie-wannabe games with big movie-wannabe linear stories the player has to fight/shoot/drive/fly their way through, and instead play our unique strengths. []
  2. or non-digitally, Go and Poker, or even sports like basketball []

Release notes v0.1.2056.0 – THE MEGABUILD

A dispatch from the private beta forums regarding the “megabuild”

Author Message
checker
Post subject: Release notes v0.1.2056.0 – THE MEGABUILD
Posted: 2012/06/22 23:25 
Online
Joined: 2011/06/22 17:00
Posts: 724

I didn’t get to everything I wanted to before I start spectation, so there will be a Daughter of Megabuild at some point soon.

  • add crlf to whole chat log ctrl-c copy so notepad.exe works
  • strip x says: or x whispers: if it’s at the beginning of a single line ctrl-c copy, yay urls!
  • add gameid confirm message to avoid junking game bug due to canceled starts
  • swap statue bad test – wait until action test is over, flicker longer
  • swap statue good test – don’t timeout during pending, go to OT, closest available npc comes over, statue swaps instantly when they bring it to looking idle
  • swap statue preview modes for these changes
  • prevent npcs and spy from picking up ghost statues
  • in practice: ctrl-m resets missions, shift-m adds time, ctrl-shift-m does both
  • fix multiple characters picking up statues at the same time
  • stop keyboard beep on alt keys
  • change add time to 45 seconds
  • treat book holding as one handed when not reading
  • handle case where ambassador/scientist picks something up while handing briefcase over
  • retry briefcase putdown on path failure as well
  • don’t crash on non-text data in clipboard
  • try to get unstuck if we’re failing to path because our start point is blocked
  • don’t read a book you’re not holding if you’re failing to get to the bookshelf
  • don’t freeze if you can’t put the briefcase down, just move a bit to a new spot
  • wait before picking up the statue
  • add /win x y w h maximized borderless command
  • oh man, actually tick situations in scored order, yikes! will this change things?
  • display highlit and lowlit characters on results screen
  • display waiting text on waiting for results screen
  • separate y invert setting for mouse and gamepad
  • handle case where sniper shoots too late given the time sync
  • write game result to log
  • don’t show mouse cursor when waiting for results
  • don’t sample keyboard when chat is up in results screen
  • don’t let mouse down state affect spy camera movement
  • /ping command for testing peer-to-peer network connection – hopefully will help with “greeting” and “sniper accept” bugs
  • more handling of briefcase put down and then started moving
  • sample spy keys async instead of doing up/down processing to avoid losing ups on focus change
  • more explicit duplicate login prompt
  • allow briefcase pickup with just right hand
  • fixing spy walking away with briefcase while putting down
  • better phrasing of game results everywhere
  • disable attachment lerp on detach so statues don’t erroneously end up on the floor
  • prevent focus changing mouse presses from interacting with game
  • fix drinks.cpp crash, animation was getting freed out from under the events
  • more play id checking to avoid issues with old packets coming in when starting games
  • don’t pick up briefcase for a while if you’ve given up
  • initialize the statues before game start
  • use ConnectTime to register player since LoginTime not available yet, fixing beta homepage display
  • listen pauses
  • don’t prompt to escape from practice menu
  • fix problem with shift key not working after sniping somebody with gamepad
  • tells for bailing on banana bread okay and bad action test
  • fake banana bread available when mission selected but not enabled
  • add escape confirmation to results screen
  • remove escape confirmation from practice screen
  • don’t hide mouse cursor on sniper game start waiting screens so you can adjust your window
  • wait a bit after disposing of book as well
  • log some more connection info
  • pause at bookshelf before picking up book…enough time to seduce?
  • add CancelInteraction everwhere there’s an action test and it’s bailed on
  • be clear that the first whisper was delivered
  • better newline handling in lobbyclient assert logs
  • verify overtime on sniper machine before beeping
  • flash window when in background and beeps happen
  • fix spy missions in practice sniper
  • think I fixed the levitating characters by the briefcase bug
  • add SpyWatchID to holding_right to block animations (especially bug) while checking watch
  • expiring actions to avoid accidental banana bread triggers
  • ctrl/shoulder slam all the way to highlight/lowlight
  • single level highlight and lowlight
  • new inspect statues with inspecting neighboring statues
  • pedestal works with disposable holding, drinks, briefcase, like bookshelves
  • play clank sound when teleporting statue back
  • add layer attribute for hittest ignore and don’t hittest muntin bars with laser
  • hittest columns with laser on both spy and sniper view
  • wait a bit after putting book away
  • make briefcase non-infinite and fix spiral search to deal with max open value
  • make pathTestOpen take rectangle for anisotropic queries and fix bookcase pileup
  • don’t crash or delete krb5 files on duplicate login
  • gl and cpuid info to log and journal
  • sometimes interrupted people finish talking completely

I really should not have shoved so much stuff into a single build, but it feels pretty good. I’m sure there are some bugs, as well, but I think this build is a subtle but significant step forward in continuing to increase the depth of the game.

Chris

The First 999 Beta Tester Usernames

There are now 999 people registered in the Early-Access Beta.1 Here are their usernames:

aaboyles aaerox abettega ablemonkey aca15 acbgardner aces acron actionpotential adam adman aerox2 aethyr agent agentmidnight agradula ahalay ahnimal aisugirl akuda alessandro ali alkapwn almostpeaceful74 amagineer amar amassingham amonjura ancillas andrew andy angellion01 angryamish angryjaffa angrywombat ankhwatcher annoyedguy anotheruselesspwn antoine antonio applemint apreche arbaard arbiter ardonite aresbece arthol ashenke astroblack astrognat attackslug atticusfinch austin authoralden avian avianflame awakewise awayman awesome awesomex awkwardhero azazoth azeltir bambu85 bassguitarbill bater bbrocker bc5389 bclose bdgolfer81 beanopolis beavens beckett007 beffy belak beljerd ben benny bepedos berbank beric berndie90 berryalice bespectacledgent betabetamax billiechar binarychimp biodork bishop bizzkaj bjorngylling bkyoops bl00dw0lf blabber blackheart blacklamb blaine blargnblarg blimeycow blind blindcicero blindprophet blinkity bluenator bluewins bnetter12 bobbesmcgee bobo bogger bom351 boner bracken brackhar brawnyfanta braytek brettbot bronn browncoat768 bslinger bubonulus bucksexington bukit1 bull bungeeman bunnyfoofoo bureaucromancer burgly burguois buxx cafebagels caincc calitar callguinness camgoeswild camperbob canadianbacon candafilm caphector capnlee captainduh captainquincy captgadianton carrington casey castor cathlin causeofdeath15 caustic cba123 chan charliechan charliehuge checker chris chris2c2 chrisbell chrisfranklin christianwins chuckgriff chvyvele cian cigumo ciminator ckarinja clarkson101 click cliff cloversquirrel clovest clownbaby clownzilla clubley2 codarl codyme1 cogbyrn cokelogic colemip coleopteran coleslawesome colinnorthway collinc colourmeindigo commandercup commandersven communistbloc compositeredfox congodave cornpalace corvon coubs38 cpsabotage crackilator cramill creasy cru31ty cskilbeck cube cukydoh curieous cyberpirate cyclpsrock d1a2r3k d4rkfr4g dacool561 daddykingkong daeke daenrr daethwing188 dagstur daheadhunter dak722 damatman dan danblanchard dandyshlonglegs danger dangerskew danicia danielben danigold dariusk darkcephas darkernukes darkswordmaster darktrooper darrentorpey darthbutternutz dash daveycraney david2crazy dbfclark dbltnk dead deadbolt deadjoe deep9x defendership deftmunky dekuplatformer desdewd develin devp dexan dfan diamondae dieffenbachj dienekes00 diffusion digikrynary dinozzo dios dippyt dirk dizzyduke dj2scoop dla26 doc docace doctorwhy docyahoo doddzy39 doenan domofizz doneval dookie dorkus1218 dotreptile doug drdos dredgman drmuncie drqqq dukrous dumbitdown duncank dungeonduck dutchsanta duwilli dvorak eddie edgeblend eggs eight einhandr eirabben eklyptz ekombokom elcarlito elendira eljenso ellbent elpicante emanon emil emmick4 emuspawn emwurst engagequadlaser enragedviol ento ephargy erariga escapecharacter esperento esuark06 etran1 etsd eversoslightly evolved exayden ezithau fain faithbleed falcon9xr falconred fancyfrog fapsauss faryn fatheroctopus favocado feenox fenir fetthesten finners fischl flamingarms flanjygo foo forspareparts fortninety foxblock fredthedeadhead french fringe frondo furay fuzzyspo0n fweez fyre gabriel gabrielsp gabumon2 gahd gamersdg garythellama geekgrrl geekynerd geibys geiko generalchaos gerardi getaway geveeso gimmefiction ging girricane gkyl gmandm goat6star6of6astaroth goblineat2 godfatherbrak godfire godzchozenson goinbananas golds golzernurf goodboy goofus gordon gordonfremen gouda graywolf greger grempkin griffinmcelroy grifta67 grimwtf grinspork gryphus1 grythean gummikana guncannon gunner1905 gunslingernz guylum haganehylian hajav halcyon hansoneg harrisonthefan harrylee hasmarth hatebobbarker havochq hawk haze hdfisise headbuddy hehateme henningdc hermituk hernismall herrdoctor hinges hobbes2424 hollygolightly holodoc homeless hop3less hothmonster hulkmaster hunter4hire hutty211 iamcarneiro iax ibis idrisguitar iiatlas ikubiakius ilzxc imaginarydinosaur immortalwombat imthedude ineffable ininja132 inker intero iocat iou1username ironhive isamu itsatrap itsmyyard itt0 j0be jacksonaces jake james1221 jaqenhghar jason jasonbourne jcmoore jedexodus jedimasta jeffatrad jeffnosanov jello jennylynn jentaro jeremiahbritt jetlizard jguzikowski jjb273 jleet82 joakim joeaverage joeprunz johnnemann johnnyr jonmm1776 jonoabbo jorispz joset305 jrmtz85 ju34u julian justin justinliew jvnane kai kalei50 kami kapit karabinerkarl karaidon karibou kate katya kb0m kbd keith kelemvor kellywallick kennyal kevin keysosaurus kidko kifil killercow kkriller klinefelter0 kmonarq7 kmuncie knifeninja kobolt kramff krow007 krpiper kujiun kunstbanause kwhiggs8 kyarourin kyoun lackey lagarathan lala lameduck lamzor lancelake larakin launchbay07 lavinashfield lawiin lawlercaust lazz leaveittoreaver leichelle lemming liamh101 lightishred linkz lioninacoma liquidindian liquience ln3000 loddy logomorph loki lopert lordking loshon lovick lrrr ltfragbox ludusvan lusomai m0r7if3r maarch macintoth mackinder maddragon maedas malbios malfunktionv2 maniacalv mantis marcham93 marciantobay marcnotmark markfnd markrestart markus marlowe mathewcrichton matt mattseligman maverick21xx maxemoe mazazon mbrewski mcc meanbrian megadestructo megapixel23 mehall merc mercuryn mercy metaregress metronome49 mevica michael michibuenkosai micole miggins mike mikecruz mikegbrown mikejmika mikella mikey minecraftboy3437 mistadad misterfix misterpanky mizzrie mmcdhoward mmorier mmustapic mogri moo moof moomanibe morfran morganic mosse motorcrash mrbanana519 mrcompletely mrhoten mrmember mrpants mrphatjared mrprice33 mrpropellerhead mrssaurbaum msarge mtb mukow murray mvandevander mylene namelesssniper nara nateventure nayon7 nayrev naysayer nazzerac nefiorim nelsormensch nemesiscw nemo nerdmancer neuman nexai nicemissmayonnaise nickmac863 nicktheflanders nicta nille niteowl noc noclip noethis nogon noise noisia noonan noonchild norskov northernlion nosferatastic notbengilbert notch nuhuhnoway nukednova nunix nyo odeyin odie ohsickkbro okibi olninyo omar omgmyface omnomonsouls onik onyxmoron opticalshadow or1g1nal1ty orahpajo ossy otakushi overlordror ozzyj88 paarre palm partario pastorpeej patrick patyrick pauzle pawng pax217 pbobzebuilder penumbra peter phaazoid phase phatjax pheranova phobon phokal pickard12 pigo pikes piratepwnsninja pixelfenix pixeltitan pixistick pnomoth pobblepop poison5htp pokeadot polycube popabawa porousnapkin postgoodism powerlanguage pparks76 prall prelone prios proverbialbones psponge psytog pubtongue puppet purplevanes pylons qq qualityjeverage quanimal queenkid1 quickfics quirken rachel rachet20 radchek rage ragegoblin rager ragtag21 rainault raphaelo rapscallion ravi ravie77 raypaik rebeleleven redbeardedowl redivy redrocket redrum remy remzo rennix resdog reusablebox revdancatt reverendanthony rex rick rift rinzai ripply rj rnw159 robinaire robotpants rockliao rocky rodomont roel1976 rogermoore rook rorrim ross rowdynun ruhmann rullerr rune ryan rym sabones sachiarias sagemichael samuel samuelcole sarahnorthway sardiax sarge sargonas sarrick saucepain saurbaum sawchuk1 sb00ya scnigey scopesofter scottish scotto6uk screwjack scud seansf seeking segolectrick seiromem senisan sentry sepherimorth sequel seregrail7 sgtfury shakewell shatter1313 sheepofheight shurp sigmatheta simon2776 simonbob sirblastalot sirlaitier sk82712 skapig skrymir skuchachii skuzeeii slack slats sleepyendymion slyvr smacktubby snakeaes sneakypeaky89 snoken snowmaneater soda solidplasma someguy sonicblastoise sonicboom soolseem spencerrohan spikerama spinnermaster spinyeti spliter splodeybaloney splodn spouwny spy spychao999 squirtle srjenkins starkiller2000 stdizzie steakeatsbabies stents sterling steve stockdogfactory storm stu stuart superdraw swenson sylver symlink syrinx t3kk taco taker talensis tam tantfarbror taquelli tautology teddydief telephis tembac tenebrous tenjouutena tenochtitlan terrytate testing texanfromin thealmightydan thebogdan thechicken thecze thedirt thedoctor52 thedoomsmith thegeckoj thegerf theharribokid theinfamousnolan thejoshfox thelaughingman themantis themightyyeti themosb thename thenew110 theotheralex ther thesocialsolipsist thief thirdordeal thornsten thoseposers thsandman tiefooz tigerseye85 tigershark tilton time5 tlabresh tobybot tokion tomeng1997 tomqbui toomuchpete tpwt tralan trauts travis treadd tree treythalomew trickery triplelex trouserdemon tubybuny tulse twie twinbolt twistamafoo twoflower tylerthedesigner undeadnub undisclosed uneddy vadid37 valir valuedrug vanlo varanas venom veturi vidvandre vincentdpc vinnyboombatz vorrik vortexmortinghan voxhumano vs vutdevuk wantedbob warlock watertower webjr weebee886 weeble wesley weteor whatthegeek whispous whitewolf whizkid wiggy wikzo willdude william wilson2k4 wiltwin wirapuru wish wkerslake woodensplint woof woomstick woseseltops wubang3r wubby wyrmling x13ucketheadx x1pyvr84 xav xemu xenoacid xlom3000 xspjigo xtreyu xzalander yanndos yazzflute yegg yobani yokelbloke yorudy yourdad zacaj zachwlewis zafo999 zaktilu zapdsl zen zerooneinfinity zerosyphon zerotka zerozshadow zgilly zhiwiller zoink2000 zoneghost zynux

  1. Updated numbers to be clear: There are 13788 people signed up as of right now, 1081 registered (I invited more in after this post), 2430 invites total sent, for a 44% registration rate…I’m still inviting people in slowly until I get the lobby scalable. []