You are never going to believe this, but I am going to tell you anyway because it has completely blown my mind. Executive summary: there is some sort of memory alignment issue in UDK when running the 32-bit executable in a 64-bit environment.
I have been pounding on this bug for several weeks and, in a final act of desperation, I burned everything down and started copying my child classes over line by line trying to identify what could possibly be causing this bug. I eventually narrowed it down to something in my Pawn class (and not in the Controller class, which was quite a surprise) and continue the process of adding one line at a time, recompiling, testing, ad infinitum.
After a few hours I finally narrowed it down to the presence or absence of some floating point variables declared in my Pawn class. I'll repeat that, because it bears repeating: the bug is caused by having too many member variables declared in your class.
I narrowed it down further to the exact byte by declaring a bunch of padding bytes, one at a time, until I got the bug to occur. I could declare a maximum of 3 bytes, and upon adding byte #4 and running my game the previously discussed nav mesh problem would occur. The header portion of my class is included at the end of this post for posterity, though its exact nature probably won't be helpful since the actual manifestation of this bug will depend on what your inheritance chain is, the number and nature of the interfaces you're implementing, etc.
After spending several minutes laughing like crazy person I realized that this was probably the result of running a 32-bit executable on my Windows 7 64-bit installation, and sure enough when I checked the shortcuts I use to run my game they were all pointing at the Win32 directory in my UDK install. Switching these to use the 64-bit version completely solved the bug.
If I may wax poetic for a moment, this is possibly the most amazing debugging effort of my programming career (I'm a professional game programmer in real life too). Managing to track down and debug a memory issue without any of the usual debugging tools is something I never, ever want to do again, but I feel like I can wear it as some sort of freakish medal.
Thank you to everyone here who tried to assist me - there's absolutely no way anybody would have guessed that this was the issue, and I'm grateful for all the very helpful suggestions I received along the way. I still learned a number of things about UDK and UnrealScript in the process of fixing this so I'm going to chalk it up as a learning experience.
The previously mentioned class header is below. The nav mesh failure will occur 100% of the time if the fourth padding byte (PaddingByte3) is uncommented and UDK is run using the 32-bit executable (or,for that matter, if you uncomment the other 3 actually useful floating points).
Code:
class MobaTestPawn extends Pawn implements( MobaTargetableInterface, MobaStatusInterface, MobaHUDInterface );
var() MobaSelectionComponent SelectionComponent;
var DynamicLightEnvironmentComponent LightEnvironment;
/** Slot node used for playing full body anims. */
var AnimNodeSlot FullBodyAnimSlot;
/** Overhead status bar values */
var float OverheadBarWidth;
var float OverheadBarHeight;
var float OverheadBarYOffset;
var float OverheadManaBarHeight;
/**
* Attack and ability related values
*/
var float AutoAttackRangeSqr;
var bool bCanAutoAttack;
var() MobaHomingProjectile AutoAttackTemplate;
/** Will only be valid on AI controller minions */
var MinionReplicationInfo MinionReplicationInfo;
/** How much experience and gold this pawn is worth when killed */
var() int ExperienceValue;
var() int GoldValue;
/** Basic combat values all pawns have - these level up with the pawn (via time, exp, etc.) */
var() float BaseGroundSpeed;
var() int BaseHealth;
var() float BaseArmor;
var() float BaseAttackDamage;
var() float BaseAbilityPower;
var() float BaseResist;
var() float BaseAttackSpeed; // Attacks per second
/** Used for displaying damage, healing, status effects, etc. */
struct DamageDisplayInfo
{
var float LifeTime;
var float StartTime;
var string Text;
var LinearColor Color;
var Vector2D Direction;
var float Distance;
var Controller Instigator;
};
var array<DamageDisplayInfo> DamageDisplays;
struct MobaTakeHitInfo
{
var float Damage;
var class<DamageType> Type;
var Controller Instigator;
var byte UpdateStamp; // Used to force the struct to replicate
};
/** Stores the most recent hit that the player has taken */
//var repnotify MobaTakeHitInfo LastHitInfo;
//var() float HitInfoDisplayLifetime;
//var() float HitInfoDisplayMinAlpha;
//var() float HitInfoDisplayMinDistance;
var() float HitInfoDisplayMaxDistance;
var byte PaddingByte0;
var byte PaddingByte1;
var byte PaddingByte2;
//var byte PaddingByte3;
Bookmarks