Konoko Payne - august 2009 release

August 28th, 2009

Here is another Konoko Payne release. The last one before moving back to Switzerland! The main change is that pathfinding is now performed via the Recast & Detour library. It’s just the initial implementation, so you may expect some troubles.

Changelist:

  • added achievement stack, to make sure 2 achievements can happen at the same time
  • added “friendly fire” achievement (make a sniper kill a NPC)
  • “devil kick” achievement now unlocked when performed on 3 enemies
  • disabled target lock on thrown characters
  • Barabas: “stronger & stronger” sound is now interrupted if Barabas gets thrown
  • it should now be possible to select the arrow keys for motion
  • removed a lot of duplicate textures on characters
  • disabled raycasts on invisible “cubes” around characters
  • added trail on “COMCOMPunchHeavy” anim
  • used new textures from Severed (there’s an option in the menu)
  • the BV when in crouch but with a firearm should be a bit bigger, to avoid going completely through barriers => we now automatically switch off the weapon
  • some transitions are now banned when in “locked crouch”, e.g. inside a ventilation duct
  • added support for “multiple surface sounds” per texture
  • added “ONI” sprites with shadows on title page
  • weapon is now dropped from correct height in crouch mode
  • added “dash” à la ONI
  • implemented Skybox culling
  • “steady cam” is now the default/preferred camera model
  • the jumping gravity should look more like ONI’s now
  • fixed camera rots for NPCs in jump anims
  • fixed crash when selecting “End game”
  • added ESC menu
  • fixed bug when enabling inventory while there’s an impending intercom
  • walljump is now possible a tiny bit longer against a wall
  • added “land hard” anim for side wall jumps
  • if killed while platform sound is on, it doesn’t stop when restarting from checkpoint <== should now be fixed
  • optimized file loading (binary state machine files, music streaming, better file management, etc)
  • some attacks from Elite Striker should have a fixed rotation => done
  • running and jumping constantly should work better now
  • added message from Shinatama when helipad platform goes down
  • added two new combos
  • there is now an option to disable “attack buffering”
  • switched from PathEngine to Recast. The prototype and the game level should now have better navigation meshes. On the other hand pathfinding against dynamic obstacles may not work anymore.

Quick notes about the ICE “kernel”

August 22nd, 2009

Some time ago I mentioned the ICE kernel and somebody asked me about the source code. Well sorry, I’m not going to release this just yet. It’s not secret or anything, it’s just extremely ugly-looking source code. You have to realize: this is the first part of the engine I wrote, somewhere around 2000. I won’t release this without a serious cleaning / refactoring pass first.

However I can briefly describe what it does. It’s nothing special, really. To be perfectly honest I was just experimenting with random ideas, to see if they would work, etc. I never imagined I would still be using this stuff almost 10 years later. Also, even if I’m still using this at home, it doesn’t mean I would ever want to replicate this in a “real” engine at work, or on a console.

So anyway it all started as a reaction to the vanilla reference counting that we’d been using before, in “Irion“. In that engine we had manual, explicit “IncRef” and “DecRef” calls. You couldn’t delete an object directly (private dtor), instead you DecRef, and if the counter reaches 0 the object deletes itself. Standard stuff. But we had a lot of issues with that, people forgot to call “IncRef” or “DecRef”, unused objects that should have been deleted were found in memory alive and well, or quite simply we got many crashes from dangling pointers. Typical BS.

After the death of Irion I started my engine from scratch at home, and I really didn’t want to end up with the same mess (*). So I was looking for a solution to this, that’s the context. At the time the information about engine architecture on the Internet was scarce, or maybe I didn’t look well enough, in any case I don’t remember finding anything very useful online. So I started to build something, probably more out of boredom and curiosity than necessity.

First of all, it only works for objects inheriting a base class. For historical reasons, this base class is called “Cell” (why this is so is another, completely different story). Cell objects register themselves to the “kernel” in their ctor. They unregister themselves from the kernel in their dtor. The kernel is a singleton, for better or for worse (it was almost 10 years ago, I didn’t care about multiple threads).

Now when you create a “reference”, you still have an explicit function to call: “AddRef”. As the same suggests, it does not increase a simple reference counter (as “IncRef” was doing), it keeps track of the “owning object”, or simply owner, and the “referenced object”, or simply reference. Those couples of (owner, reference) are stored inside the kernel, in something called “reference tracker”.

If there is any intelligence in the system, it might be in the reference tracker. This is a somewhat creative data structure designed to keep track of those pairs efficiently, both in terms of speed and memory. A  (owner, reference) pair is simply a DWORD, made of two 16-bit IDs. The number of objects is limited to 64K, yes. The pairs are simply stored in a contiguous amount of memory, like a vector of DWORDs. Given an input Cell, the structure otherwise provides O(1) access to:

  • its number of owners, and the set of owners
  • its number of references, and the set of references

So, in a standard system you would get a Cell object and you could only do something like “GetRefCount”. It would return “3″, and you would know that this Cell is referenced by 3 other Cells somewhere. In ICE, you can easily ask for the “ref counter” (= the number of owners), but also who the owners are. That’s the first building block.

The second step is to investigate what happens when you actually delete an object. As we saw before, on deletion a Cell unregisters itself from the Kernel. The Kernel in turns tells the Reference Tracker about this deleted Cell. And since the Reference tracker knows what other Cells are still referencing the deleted one, well, from this point it’s easy to call the owners for notification. That function is called “OnInvalidReference”, IIRC.

So, for example:

  • you have a Material, 3DS-MAX style
  • it has a Reference to a Diffuse texture
  • if you delete the texture (and I mean really, a savage “delete ptr” anywhere), the system calls Material::OnInvalidReference(), with the deleted Cell (the texture) as a parameter. From here, the Material can fix its dangling pointer (at least it was the original idea, but it evolved a lot afterwards)

There are a bunch of technical issues here with circular references and how to implement all this efficiently, but those are details “beyond the scope of the discussion”. The question was about containers, remember? Well it should be obvious what the next part was: of course I made a Cell-based container. Completely customized object, STL-Vector-style, that can hold Cell pointers, nothing else. The benefit, as you already guessed from the previous post and previous paragraph, is that if I ever carelessly delete a Cell object stored anywhere else in one of those containers, the kernel will know, it will call the container’s “OnInvalidReference”, and the container will remove the bad pointer from itself, automatically. Done!

This, unfortunately, was only the beginning of my weird architecture experiments.

Not long after that, I tried to fix the other main pain in the butt that had plagued Irion since the beginning: serialization. Oh man how I hated writing serialization code in Irion. In ICE, I really wanted to have an automatic mechanism to do that for me. IIRC the idea came from the Half-Life SDK: they had this great “offset of” macro that would give the offset of a member within a class. It’s pretty standard and well-known those days, but at the time, and for me, it was a mini revolution. The serialization code in Irion had to be written manually and painfully. Thanks to this single macro, suddenly it was possible to automate a large part of it. I’ll spare you the details as I’m sure you’re all aware of this stuff now, it’s used and over-used for serialization, meta-data, scripting, etc. The point to take home here is that the kernel suddenly knew about Cell classes’ members… and in particular, about other Cell pointers stored within Cell classes. Which opened a whole brand new Pandora’s box.

Remember, I was only toying at home. This was not production stuff. The ICE engine has never been used commercially or anything. No harm done.

Let’s face it: what’s the point of calling “OnInvalidReference” for a given Cell to clean its dangling pointers… if you can do it yourself? “If you want something done correctly, do it yourself”. Right. So that’s basically what I did. Provided you declared members with the correct serialization macros, the kernel does not call objects anymore to tell them to clean an invalid pointer. The kernel cleans the invalid pointer all by itself. It knows where it is! So it just clears it. Zero it. Nullify it.

That’s usually the point where type-safety zealots and other fans of “clean C++” (talk about an oxymoron) give up and start throwing rotten tomatoes at my indecent lack of concern for “proper OO ways”. (But then again, if “Boost” is the “proper” infant of the OO way, I’ll more than gladly remain a non-believing maverick. Boost! What a joke!)

But wait! I’m not done! I still have to tell you how discovering handle-based “weak pointers” changed the picture over again! And how the kernel can “remap” itself and move objects in memory under the hood to reduce fragmentation!

Come back! It’s fun!

Hello …?

(*) I failed :)

Wanted - Araña

August 22nd, 2009

While doing backups I found this picture of Araña, one of the characters in “Wanted - weapons of fate“. It has a special meaning for me. I see it both as a proof that the Barcelona office did have talented artists, and that “the management” (or whoever was behind the important decisions, it was never all that clear) was just living on another planet.

To me this is one of the most, if not the most awesome render ever created by our artists during the whole project. I think it is very obvious why it has potential. Why it would be a good idea to polish this secondary character, and give it some more screen time. Why it would draw hordes of nerds to the game. Why it would please all the fans (what do you mean you did not expect them to be disappointed when discovering that Angelina is not in the game?!). At the very least, if nothing else, put it somewhere on the box. Create posters. Send it to IGN and Gamespot, I don’t know. Something.

Instead… well, did you see that picture anywhere? Exactly my point.

They saved it for a mindbogglingly weird promotional stunt in a male magazine that should remain nameless. Of all the crappy decisions made during this project, this one has to take the cake. As if the readers of [Censored] were interested in buying video games !? I don’t know, maybe they got lifetime subscriptions out of that deal or something.

Damn it, this one still makes my blood boil!

More Recast notes

August 21st, 2009

Played a bit more with Recast. It rocks so far.

I wonder if I could use the Recast nav-mesh with PathEngine?? Sounds like best of both worlds if Detour has some limitations. For example I don’t know yet if it handles dynamic obstacles very well.

The world is cut into several regions connected by portals. I think I will end up generating one nav-mesh per region. Then if a pathfinding query goes from point Pa in region Ra to point Pb in region Pb, I can always split the query into several sub-queries: first from Pa to the portal connecting Ra and Rb, then from the portal to Pb. Or maybe Recast’s “tiled” mode can do the trick directly.

Not sure how to handle moving platforms yet.

Sparkling ice cubes

August 20th, 2009

That’s what happens when you try to make ice cubes with sparkling water…

EDIT: wonder what happens if I try sparkling water in the coffee machine… too bad it’s already packed :)

Recast on ONI Level 10

August 20th, 2009

I tried Recast on ONI’s level 10. Seems to Just Work! This was all generated by clicking a button.

I guess it’s time to try “Detour” to actually do some pathfinding queries on those meshes.

EDIT: first successful pathfinding queries done with “Detour”. Just Worked. Yay!

Recast Redux

August 20th, 2009

Some more Recast notes:

My characters use capsules with radius = 4.0 and total height = 15.0. After some tweakings I got the best results with those build parameters.

The cable holes on the ground are gone. But they did not disappear when changing the “walkable climb” value. They disappeared when changing the “cell height” from 0.2 to 0.7.

EDIT: the next paragraph is BS, see the comments.

On the other hand I still have troubles with cable holes in the small “command center”, somewhere else in that level. The nav mesh here would look very reasonable without that big hole in the middle. I didn’t manage to get rid of it. Admittedly the UI does not expose all parameters yet (like “max edge length”) and maybe playing with that one will do the trick.

I see troubles with the “walkable radius” otherwise. Even though I use the actual radius from my character’s capsule, the nav mesh misses some connections, areas that can definitely be crossed by the player. Reducing the “walkable radius” helps a bit but not much, since it’s quantized to an integer value internally. So I decrease the value a bit in the UI, nothing changes, repeat that a few times, until suddenly a big change happens because the internal code clamped the float to the next integer. Would be cool to be able to fine-tune this better.

Admittedly that mesh is not very friendly with all those narrow passages. But hey, real-world meshes tend to be painful to library developers - tell me about it!

To be continued, I will post more results after exposing the last build params to the UI.

EDIT: done! Tweaking the remaining params did not significantly change the results.

“Recast” pathfinding library

August 19th, 2009

John Ratcliff told me about a new pathfinding library named “Recast“. It’s open source and it looks pretty good. I am currently using PathEngine in Konoko Payne. That’s a powerful library but it has one big problem for me: navigation meshes have to be created by artists. Since I am the only “artist” in this project, it has always been a huge pain in the butt to open MAX and manually, painfully, create the nav meshes. I more or less did it in KP’s prototype, but never even started for the “real” level (especially since the level is “under construction”. No way I’ll spend time creating a nav mesh for a level which might change the next day).

So the biggest appeal for “Recast”, to me, is that it automatically builds nav meshes. I have no idea about the runtime performance or memory requirements yet, but for me this single feature makes it worth checking.

So, I did.

Pretty simple API, seems to work as advertised. Didn’t test it much yet but seems to work, and it’s fast.

  • This picture is what I get on KP’s “Depot” level. That’s what you get out of the box, without much parameter tweaking. Pretty good.
  • Only problem I see is that some cables on the ground end up creating big holes in the nav mesh, for some reason. I don’t know why yet. I don’t know if it can be easily solved by tweaking the build parameters a bit more. In any case this is a non-issue, I can simply filter those triangles out of the building process.
  • Here are the build parameters I used. You can open this from KP’s console and build everything while the game is running. So far, so good. This is one big step towards releasing KP’s source code. I couldn’t do it before since PathEngine’s license prevented it, but now everything’s possible! (I just have to replace the physics engine, duh!)

(to be continued)

Zurück nach Zürich

August 19th, 2009

I guess I should make it official now that I signed the contract. I am now a proud NVIDIA employee, and I will be working with my old NovodeX mates in Zürich - yep, good old Technopark. In a way it feels like moving backwards, going back to my past rather than exploring new cities, new countries, and trying new things. On the other hand, it feels curiously good to “go home”. Granted, it’s not really my home. But it feels familiar. Friendly. Safe. Secure. Just like a home should be. After 2 years in Spain it may also just feel good to go back to a place where things Just Work. No “caldera” exploding in the middle of the night, no brainless Internet provider forgetting my files on a desk for 2 months, no bad surprise when going for shopping. Of course the weather will not exactly be as gorgeous as Barcelona’s, but hey, that’s a bonus: no more sunburns.

This has been a crazy month of July. Packed with interviews, trips, phone calls. I got so many job offers it’s not even funny. While most people suffer from the financial crisis, lose their job, struggle, I got some 19 offers in the two first weeks, and they kept coming. Some of those were insanely appealing. You have no idea how hard it has been to decline all of them but one. For a while I felt like Paul Atreides, having visions of all the possible futures in all those cool places and cool countries. They really all felt good. It was an impossible task to select just one. I wish I could have worked for all of them. I wish I will, some day.

It’s been a long time since I last wrote a scrolltext but I feel like writing greetings again. In no particular order : Kenneth, Cortney, Simon, Greg, Andrew, David, Oliver, Paco, Martin, Sys, Tatiana, Christer, Christophe, Candace, Jay, Vik, Robert, Francesco, Marie-Therese, Sandra, Alexis, Joachim, Pascal, Vangelis, David. You know who you are. Thank you!!

Fecking hell, I’ll miss the craic !

Your raycast-vs-sphere code is broken

August 17th, 2009

Check your codebase if you don’t believe me. I posted this months ago on GDA but never found the time to make a proper note. And you know what? I still don’t have the time. Check the GDA archives for more information.

In short: the code solving the quadratic equation suffers from limited FPU accuracy and returns “no intersection” while there definitely is one. “Best” fix is to move the ray origin closer to the target sphere. See this small repro case for details.

It’s not a theoretical problem only, it happened in Konoko Payne when sniping a far away enemy with a Mercury Bow.

So, there. Off my TODO list, stupid item!

 

shopfr.org cialis