1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Two Factor Authentication is now available on BeyondUnreal Forums. To configure it, visit your Profile and look for the "Two Step Verification" option on the left side. We can send codes via email (may be slower) or you can set up any TOTP Authenticator app on your phone (Authy, Google Authenticator, etc) to deliver codes. It is highly recommended that you configure this to keep your account safe.

Replication Issue on Melee Weapons

Discussion in 'Programming' started by jb, Sep 16, 2003.

  1. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    Folks,

    me again with YAI (yet another issue) that I have not been able to wrap my arms fully around to and could use a kick in the right direction. It involves melee combat and on-line games. What we did is something a bit different. We got away from using the trace X units in front of a player and went to an animation driven system. We created a dozen or so custom attack animations for the pawn class( one handed swings, two handed, jabs/pokes, ect). We look at your movement and the base the attack animation on the movement. The key is the weapon and how its attached. We use one standard bone in the model to attach to your hand. Then we placed 2 bones in the model of the weapon. We place one of them at the tip of the blade and the other in the hilt of a sword (for example). Then we the player "fires" the weapon, we start tracing between these two points. As soon something breaks that trace we look at the hit detection to see if it was a "wall", a player or another weapon (ie a block) then handle that hit. The system works pretty well off-line. However on-line its a different story and I am sure its how I set up the replication of the weapons. Instead of using a started weapon attachment I used this:

    Code:
    //==================================================================
    //  The active weapon file
    //==================================================================
    
    class swordAttachmentb extends MeleeWeapon placeable;
    
    var ShieldSparks Sparks;
    var(Health) float Health;
    
    var() int MomentumTransfer;
    var() float damMomentum; // changed type to float from int -jm
    var() int Damage;
    var() int DamageRadius;
    var() int DamageType;
    var swipetrail SweepTrail;
    var() float HeadShotDamageMult;
    var() float HeadShotRadius;
    var name ActionAttack;
    var array<Actor> HitActors[16]; // this array will keep our list of hit actors.
    // Sounds vars
    var(MeleeSounds) array<Sound> BlockSound;
    var(MeleeSounds) array<Sound> Melee_HitFlesh;
    var(MeleeSounds) array<Sound> Melee_HitArmor;
    var(MeleeSounds) array<Sound> Head_Shot;
    var Sound HitWallSound;
    
    
    //=============================================================================
    // PostBeginPlay
    // Set up the swipe effects
    //=============================================================================
    simulated function PostBeginPlay()
    {
        local actor W;
        W = self;
       // log("I am here " @location);
        //Log("My instigator is " @instigator.controller.Playerreplicationinfo.PlayerName);
        if ( Level.NetMode != NM_DedicatedServer)
        {
            if (!Level.bDropDetail && (Level.DetailMode != DM_Low) )
                SweepTrail = Spawn(class 'swipetrail', self);
            if ( SweepTrail != None )
            {
                W.AttachToBone(SweepTrail, 'sweepjoint3');
                SweepTrail.mRegen =false;
            }
        }
    }
    
    
    //=============================================================================
    // ThirdPersonEffects
    // Blank out any current 3rd person effects
    //=============================================================================
    simulated event ThirdPersonEffects()
    {
    }
    
    
    //=============================================================================
    // Explode
    // Blows up with an effect?
    // Jb: Why? for like a shattered sword???? Hmm Come back and remove later?
    //=============================================================================
    simulated function Explode(vector HitLocation, vector HitNormal)
    {                               // is this used? - JM
        if (Role == ROLE_Authority)
        {
            // HurtRadius(Damage, DamageRadius, class'ketoweapons.DamTypesever',
            // MomentumTransfer, HitLocation );
        }
        if (EffectIsRelevant(Location, false))
            Spawn(class 'ImpactDust',,, Location);  // ,rotator(Velocity));
    }
    
    
    //=============================================================================
    // Destroyed
    // Remove the swipe/sparks effect
    //=============================================================================
    simulated function Destroyed()
    {
        if (SweepTrail != None)
            sweeptrail.Destroy();
        if (Sparks != None)
            Sparks.Destroy();
        Super.Destroyed();
    }
    
    
    //=============================================================================
    // CheckHit
    // Remove the swipe/sparks effect
    //=============================================================================
    function bool CheckHit(Actor A)
    {
     local int i;
    
     // Check if this actor is valid to be struck
     if(A == Owner || A.Owner == Owner || A == self)
     {
      return false;
     }
          // Check this actor against the HitCount array
     for(i = 0; i < 16; i++)
     {
      if(HitActors[i]== A)
      { // Found this actor in the list
       return false;
      }
     }
     // The actor wasn't in the list, so add it
     for(i = 0; i < 16; i++)
     {
      if(HitActors[i] == None)
      {
       HitActors[i]= A;
       return true;
      }
     }
     return(false);
    }
    
    
    //=============================================================================
    // ClearHitActors
    // Resets the array of actors we hit
    //=============================================================================
    function ClearHitActors()
    {
     local int i;
     for(i = 0; i < 16; i++)
      HitActors[i] = None;
    
    }
    
    
    //=============================================================================
    // Timer
    // This function checks to see if any object passes between the sweep joints of
    // the weapon.
    //
    //  Jb: AdHOCK (or is that AdHACK...hehheh get it...hahaha)  fix was to move it to a timer and have the
    //       fire class controlls when the timer as active and not active....hey its a bit better...
    //=============================================================================
    Function Timer()
    {
        local vector newpos1;
        local vector newpos2;
        local coords newcoords1;
        local coords newcoords2;
        local Vector End, HitLocation, HitNormal, Start;
        local actor Other;
        local actor W;
        // local xWeaponAttachment WeaponAttachment;
        local Weapon Weapon;
        local Controller C;
    
          if (SweepTrail != None)
                SweepTrail.mRegen = true;
    
          W = self;               // say my name...
          newcoords1 = W.GetBoneCoords('sweepjoint1');    // get the location of the sword blade start
          newcoords2 = W.GetBoneCoords('sweepjoint2');    // get the location of the sword blade end
          newpos1 = newcoords1.Origin;
          newpos2 = newcoords2.Origin;
          log("sweep joints are at " @newpos1 @newpos2);
          MeleePawn(Instigator).pt1 = newcoords1.Origin;
          MeleePawn(Instigator).pt2 = newcoords2.Origin; // copy for async trace drawing
    
            Start = newpos1;
            End = newpos2;
            Other = Trace(HitLocation, HitNormal, End, Start, true);    // see if the sword 'line' hits anything
            C = Instigator.Controller;
            Weapon = Instigator.Weapon;
    
            if (Other != None && Other != W )
            {
                if (Other.IsA('MeleeWeapon'))
                {
                    PlaySound(BlockSound[Rand(BlockSound.Length)], SLOT_Interact);
                    if (CheckHit(Other))
                    {
                       // Hit a new object here..spawn effect
                        Spawn(class 'WallSparks',,, HitLocation);
                    }
    
                    // We also should stop our swing...as we are not swining amy more.
                    // Cad do this by setting the bfire tag to false, then play another
                    // animation to stop
    
                    // Jb: Stop their fire
                    if (C != none)
                    {
                       C.bFire = 0;
                  Weapon.StopFire(0);  // now we need to stop the player from holding the firebutton down
                    }
                    // Reset thier animation
                    ActionAttack = '2hstance';
                    MeleePawn(Instigator).SetAnimAction(ActionAttack);
                    SwordFire(Weapon.FireMode[0]).GotoState('');  // Stop the swing!
                    // moved gotostate to the end, in case it was jumpin early. -jm
                }
                else if (Other.bWorldGeometry)
                {
                    // weve struck map stuff
                    PlaySound(HItWallSound, SLOT_Interact);
                    if (CheckHit(Other))
                    {
    
                       Spawn(class'HitEffect'.static.GetHitEffect(Other, Other.Location,HitNormal)
                                   ,,, HitLocation, Rotator(HitNormal));
    
                    }
                    if (C != none)
                    {
                       C.bFire = 0;
                     Weapon.StopFire(0);  // now we need to stop the player from holding the firebutton down
                    }
                    // Reset their animation
                    ActionAttack = '2hstance';
                    MeleePawn(Instigator).SetAnimAction(ActionAttack);
                    // on the surface type (like rune did)
                    SwordFire(Weapon.FireMode[0]).GotoState('');  // Stop the swing!
                }
                else if (Other.IsA('Projectile'))
                {
                   // Maybe play a custom sound for projectiles here??
                   // call that projeciles ProcessTouch to see if it can be refelected
                   Projectile(Other).ProcessTouch(Instigator, HitLocation);
                }
                else if (!Other.bWorldGeometry && Other != Instigator && Other != Owner && Other.IsA('Pawn'))
                {
                    // we hit paydirt! err, it hit the other pawn in the flesh, time to do some damage.
                    // Jb: Maybe put a check for a team mate and if so stop the swing or damage?
    
                    //Play sounds here
                    if (Pawn(Other).ShieldStrength != 0.0)
                          PlaySound(Melee_HitArmor[Rand(Melee_HitArmor.Length)], SLOT_Interact);   // implies hit a target with shield/armor
                    else
                          PlaySound(Melee_HitFlesh[Rand(Melee_HitFlesh.Length)], SLOT_Interact);  // implies hit a target with w/o shield/armor
                    // give them damage :)
                   ProcessTouch(Other, HitLocation);
                }
    
            }
    
       // else
       // {
            if (SweepTrail != None)
                SweepTrail.mRegen = false;
       // }
    }
    
    
    //=============================================================================
    // ProcessTouch
    // Call when we hit another actor to see if we should hand out damage.
    //=============================================================================
    simulated function ProcessTouch(Actor Other, Vector hitLocation)
    {
        local Vector X, moe;
        local float dist;
        local class<DamageType> swordDamageType;
    
        if (Other == Instigator)
            return;
        if (Other == Owner)
            return;
        if (Other == self)
            return;
    
         Damage = Default.Damage + (5*Sword(Instigator.Weapon).CurrentStance);
    
         // if the current pawn is in berserk mode, increase their damage by 20%
         if ( Instigator.IsA('xPawn') && xPawn(Instigator).CurrentCombo != none && xPawn(Instigator).CurrentCombo.IsA('ComboBerserk'))
           Damage += Damage * 0.20;
    
         if (Other != None && Other.IsA('xPawn') )
         {
               X = Normal(Other.Location-Instigator.location);
               moe = (X+vect(0,0,0.5))*damMomentum;
               // collect damagetype from custom weapons
               if ( Instigator.Weapon.IsA( 'Sword' ) )
                   swordDamageType = class 'DamTypeSword';
               else if ( Instigator.Weapon.IsA( 'Axe' ) )
                    swordDamageType = class 'DamTypeAxe';
               else
                    swordDamageType = class 'DamTypeDoubleAxe';
    
               if (Pawn(Other) != None)
               {
                    if (Other.GetClosestBone(HitLocation, X, dist, 'head', HeadShotRadius) == 'head')
                    {
                         PlaySound(Head_Shot[Rand(Head_Shot.Length)], SLOT_Interact);
                         Other.TakeDamage(Damage * HeadShotDamageMult,Instigator, HitLocation, moe, class 'Melee.DamTypeseverHead ');
                    }
                    else
                    {
                         Other.TakeDamage(Damage, Instigator, HitLocation, moe, swordDamageType );
                    }
               }
          }
          else if (Other != None && Other.bProjTarget)
          {
               Other.TakeDamage(Damage, Instigator, HitLocation, moe, swordDamageType );
               // Need a sound for a reflect/projectile hit?? Or No solid hits?
               PlaySound(HitWallSound, SLOT_Misc);
          }
    }
    
    
    
    defaultproperties
    {
        Health=500;
        MomentumTransfer=30000;
        damMomentum=25000f;        
        HeadShotDamageMult=2.000000;
        HeadShotRadius=8.000000;
        Damage=15;
        DamageRadius=45;
        DrawType=DT_Mesh;
        // Temp add by Jb
        Mesh=SkeletalMesh'Chaos_melee1.OldBastardSword'
        DrawScale=0.425
        // end temp
        SurfaceType=EST_Metal;
        SoundRadius=100.000000;
        SoundVolume=255;
        TransientSoundVolume=1.200000;
        TransientSoundRadius=400.000000;
        bCollideActors=True;
        bCollideWorld=True;
        bBlockActors=True;
        bBlockPlayers=True;
        // added in these to better model the sword
        CollisionRadius=6;
        CollisionHeight=41;
        BlockSound(0)=Sound'MeleeSounds.Melee.sword_blockmelee1'
        BlockSound(1)=Sound'MeleeSounds.Melee.sword_blockmelee2'
        BlockSound(2)=Sound'MeleeSounds.Melee.sword_blockmelee3'
        BlockSound(3)=Sound'MeleeSounds.Melee.sword_blockmelee4'
        BlockSound(4)=Sound'MeleeSounds.Melee.sword_blockmelee6'
        BlockSound(5)=Sound'MeleeSounds.Melee.sword_blockmelee5'
        HitWallSound=Sound'MeleeSounds.Melee.sword_wall1'
        Melee_HitFlesh(0)=Sound'MeleeSounds.Melee.melee_hitflesh1'
        Melee_HitFlesh(1)=Sound'MeleeSounds.Melee.melee_hitflesh2'
        Melee_HitFlesh(2)=Sound'MeleeSounds.Melee.melee_hitflesh3'
        Melee_HitFlesh(3)=Sound'MeleeSounds.Melee.melee_hitflesh4'
        Melee_HitFlesh(4)=Sound'MeleeSounds.Melee.melee_hitflesh5'
        Melee_HitFlesh(5)=Sound'MeleeSounds.Melee.melee_hitflesh6'
        Melee_HitFlesh(6)=Sound'MeleeSounds.Melee.melee_hitflesh7'
        Melee_HitFlesh(7)=Sound'MeleeSounds.Melee.melee_hitflesh8'
        Melee_HitArmor(0)=Sound'MeleeSounds.Melee.melee_hitarmor1'
        Melee_HitArmor(1)=Sound'MeleeSounds.Melee.melee_hitarmor2'
        Melee_HitArmor(2)=Sound'MeleeSounds.Melee.melee_hitarmor3'
        Melee_HitArmor(3)=Sound'MeleeSounds.Melee.melee_hitarmor4'
        Melee_HitArmor(4)=Sound'MeleeSounds.Melee.melee_hitarmor5'
        Melee_HitArmor(5)=Sound'MeleeSounds.Melee.melee_hitarmor6'
        Head_Shot(0)=Sound'MeleeSounds.Melee.melee_headshot1'
        Head_Shot(1)=Sound'MeleeSounds.Melee.melee_headshot2'
        Head_Shot(2)=Sound'MeleeSounds.Melee.melee_headshot3'
        Head_Shot(3)=Sound'MeleeSounds.Melee.melee_headshot4'
        Head_Shot(4)=Sound'MeleeSounds.Melee.melee_headshot5'
    }
    
    and its partent:
    
    [code]
    //============================================================
    // base class for the weapon "attachments"
    //============================================================
    class MeleeWeapon extends Actor;
    
    defaultproperties
    {
    
        bCollideActors=True;
        bCollideWorld=True;
        bBlockActors=True;
        bBlockPlayers = true;
        bPathColliding = False;
    
        //Replication stuff
        bGameRelevant=True;
        bAlwaysRelevant=True
       //bReplicateMovement=false
    }
    

    No real reason why I chose to make this a parent of Actor. What should I have used for the parent of the MeleeWeapon Class? So in on-line games it does not do any damage. And some time the sword will attach it self to the players hands. It depends on the bReplicateMovement var. If I leave it in as false, then my sword attachment spawns but its is never attached to my hand. Thus I walk around with out a weapon. If I remove it (so its set to true via the Actor class setting) then my weapon gets attached. However when I log the location of the trace joints they never move. So I can not hit anything. Now with some work I was able to play on-line with the bots. I noticed that when the swords did not attach (ie bReplicateMovement=false) I would see these swords lying at their spawns. If I walked up to a bots sword and that bot swung, then I DID TAKE damage. So the method will work. Once I can figure out what I did wrong. I guess I don't understand how it can attach the weapon and yet not have the sword joints be updated. Any thoughts???
     
    Last edited: Sep 16, 2003
  2. Daid303

    Daid303 MSPA

    Joined:
    Aug 7, 2002
    Messages:
    246
    Likes Received:
    0
    Why not use InventoryAttachment as base class?
     
  3. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    Daid303,

    ok that makes a lot of senses. I made that change but I still do not get any updates to the postion of the sword when I log its location:

    Code:
          log("my postion is " @self.location);
          log("sweep joints are at " @newpos1 @newpos2);
    
    These never change in value even though the sword is in my hand and moving. Now in an off-line game these change. Any ideas what I did wrong?
     
  4. RegularX

    RegularX Master of Dagoth Lies

    Joined:
    Feb 2, 2000
    Messages:
    1,215
    Likes Received:
    0
    What if you keep InventoryAttachment as the parent but change "bFastAttachmentReplication" to be false? It might be setting the Actor mostly correct, but I wonder if that var isn't telling the native replication to not worry about sending the location/rotation over the wire.
     
  5. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    RegX,

    thanks for the reply. Last night I tried a few things and one of them was as you suggested as well as the bOnlyDirtyReplication. Still no luck. At this point i have no idea why I can see the sword in the hands of my players yet logs show it never moves eventhough I go through the level hopping like a bunny. I would expect if the log is showing it not moving then it would not be attached. Confusing :(
     
  6. RegularX

    RegularX Master of Dagoth Lies

    Joined:
    Feb 2, 2000
    Messages:
    1,215
    Likes Received:
    0
    self.location doesn't change, but it's also not 0,0,0 ?
     
  7. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    Yeap its set to some non-zero value that I am almost sure its the spawn point of my player (or close to it).

    I tried a rather nasty hack of settibg its location every tick to my instigators location. Well I got the logs to show that it moved. However it detached from my hand. I did not figure on a way to reattach it so dropped that idea. Thanks again!
     
  8. RegularX

    RegularX Master of Dagoth Lies

    Joined:
    Feb 2, 2000
    Messages:
    1,215
    Likes Received:
    0
    This is totally a side note - but is it me, or are semicolons suddenly OK in default props? didn't that use to hose the whole section?
     
  9. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    Well I am lazy and will remove them all. Normally spaces are bad in the default section unless you use a semicolon :)
     
  10. RegularX

    RegularX Master of Dagoth Lies

    Joined:
    Feb 2, 2000
    Messages:
    1,215
    Likes Received:
    0
    Doing a bit reading, it seems like Role_DumbProxy would be a better choice unless the Owner is acting like a base. ROLE_SimulatedProxy (in inventory attachment) won't replication location if there's no base.

    If it is the base, try keeping SimulatedProxy and setting bUpdateSimulatedPosition=True ... (at this point I'm just trying to decipher Actor's replication rules for location)
     
  11. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    Thanks I will try that as well as do some more reading on this as well.
     
  12. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    Reg,

    thanks again but still the same results no mater what I try to set its role too....
     
  13. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    Update:

    Erik from Epic replied with this:

    For me I logged the bone postion of the right hand. That showed up and had real data on server. It also moved. So now that I know I can use the location of the righthand on the server, it should be a simple matter of calculating those sweep joints with some vector math.
     
  14. DannyMeister

    DannyMeister UT3 Jailbreak Coder

    Joined:
    Dec 11, 2002
    Messages:
    1,270
    Likes Received:
    0
    Wrap long lines of code, pretty please!

    :)
     
  15. jb

    jb New Member

    Joined:
    May 22, 2000
    Messages:
    278
    Likes Received:
    0
    Found a hint burried in the UTMod List.

    Basically what I had to do was get the bone cord of the players hands. Move the Attachment class to that location. Set the rotation of the attachment class to that of the right hand. Then reattach. Just 6 lines of code is all it took :)
     
    Last edited: Oct 6, 2003

Share This Page