Results 1 to 11 of 11
  1. #1
    God King
    Join Date
    Nov 2007
    Location
    Lithuania
    Posts
    4,723

    Default Replication: RagImpactSounds

    I'm not sure if it's at all possible, but I'm trying to change xPawn.RagImpactSounds[] of every pawn in the game without changing the pawn class and also make it work online. There is one issue - RagImpactSounds is a dynamic array, and those generally don't have any idea about replication. However, I was wondering if it would be possible to simulate that, as I just want the clients to hear the changed sounds (not necessarily to bother the server with setting them). Although then I also see how relevance could get in the way, as clients would have to have a way to reset the sounds to the new ones every time another client becomes relevant...

    So, any thoughts on this? Is this even realistically possible?

  2. #2
    Redeemer
    Join Date
    Jan 2004
    Location
    The great Pacific Northwest
    Posts
    1,576

    Default

    You might be able to use a LinkedReplicationInfo subclass for each pawn (hook it to the Player's replication info via a mutator). Have the linked replication info periodically check (via a simulated tick or simulated timer call) if its owner is relevant (owner!=none) and then do some basic logic (maybe manually check the sounds array, or keep track of whether the owner has gone "unrelevant") to see whether or not the ragimpact sound array needs to be updated.
    "What do you mean it doesn't exist clientside?"
    YARM: where player's Lean, Prone, Mantle, Dash, Crouch Jump, 'Parkour' and slide around all with generic realistic weapons!
    Meowcat's Mods for UT2K4:
    Yet Another Real-life Mod: Realistic weapons, unoriginal gameplay, w/ cheap CODMW knockoff mutator
    TD Vehicles: HUMV, MI4Hound, Motorcycle, IFAV Jeep, UH-60, MH-53 & AH-6 Helicopters, Abrams Tank
    Jetpacks for UT2k4!

  3. #3
    God King
    Join Date
    Nov 2007
    Location
    Lithuania
    Posts
    4,723

    Default

    Hmm. I see what you mean with the LinkedReplicationInfo, but I don't follow the checking part. Who is the owner supposed to be? If it's just spawned, it would automatically be the mutator. I assume you mean the PlayerReplicationInfo, or the pawn? I'm also not entirely familiar with how PRIs work... Do you mean that each client executes what is on the LinkedReplicationInfos of other clients, too?

  4. #4
    Redeemer
    Join Date
    Jan 2004
    Location
    The great Pacific Northwest
    Posts
    1,576

    Default

    The "owner" could be the pawn itself (use the Pawn as one of the spawn(class'', ...) parameters when spawned by the mutator), or simply create a pawn variable in your LinkedReplicationInfo (LRI) and assign the pawn to it, called MyPawnOwner for instance, that is in the variable replication block and then check to see whether or not it == none on the client. If it's not 'none' then you can do whatever check you need to do to see if the sounds should be updated.

    You probably already know this, but I'm adding it just for others in the future:

    Controllers: Exist on the server and owning client (for playercontrollers) only, they are never relevant/replicated for non-owning clients

    Pawns: Always exist on the server. The pawns belonging to client are always relevant to them, other bot controlled pawns and other client controlled pawns become relevant and un-relevant depending on visibility checks around the level geometry (getting spawned and destroyed on the client machines), except in some cases where they are always relevant (different default properties for bAlwaysRelevant etc.)

    PlayerReplicationInfo (PRI) always relevant to all clients, and if I recall correctly they are updated roughly once per second (check the default properties to be sure). LinkedReplicationInfos (LRI) assigned to a PRI are also replicated to non-owning clients and are good places to store extra variables needed by other non-owning clients (like location for a Radar that would always work even when pawns lose network relevancy for a given client). LRI can also be given a higher NetUpdateFrequency so that the data will be sent out more frequently (obviously costing some bandwidth).
    "What do you mean it doesn't exist clientside?"
    YARM: where player's Lean, Prone, Mantle, Dash, Crouch Jump, 'Parkour' and slide around all with generic realistic weapons!
    Meowcat's Mods for UT2K4:
    Yet Another Real-life Mod: Realistic weapons, unoriginal gameplay, w/ cheap CODMW knockoff mutator
    TD Vehicles: HUMV, MI4Hound, Motorcycle, IFAV Jeep, UH-60, MH-53 & AH-6 Helicopters, Abrams Tank
    Jetpacks for UT2k4!

  5. #5
    God King
    Join Date
    Nov 2007
    Location
    Lithuania
    Posts
    4,723

    Default

    Aha, that's a lot clearer now, thanks. Although I still wonder, if I have a pawn assigned as the owner, and it becomes irrelevant, then becomes relevant again, how does it still remain the owner of the LRI? Wouldn't the newly relevant pawn be a new pawn that has no clue about any attached LRIs?

    EDIT: Hmm, somehow the LRI doesn't execute PostNetReceive(). I want it to set the timer equal to the network update rate (so that just as new information arrives, I could utilise it), but apparently it doesn't get called... What gives?

  6. #6
    Redeemer
    Join Date
    Jan 2004
    Location
    The great Pacific Northwest
    Posts
    1,576

    Default

    Don't bother trying to synch the 'timer' call with the netupdate frequency because depending on network conditions the net updates may not actually occur at a regular interval (think of the netupdatefrequency and NetPriority as more of desired values...). Make sure 'bNetNotify' is true for the LRI to call the PostNetRecieve function (and that PostNetRecieve is simulated).

    Good question about the pawn going relevant and un-relevant. Although I've tested my mod in network games, I'm not sure I would have picked up on whether that variable was being replicated properly. [EDIT] Now looking through the base actor code again, I don't think that the owner variable would be replicated to non-owning clients at all which means you will probably have to replciate it as another variable (and maybe reassign it once in a while on the server just to make sure that the clients will be updated).

    Here is some sample code where I used an LRI for storing pawn location information (for radars to be used by clients) and to store loadout information. My custom HUDOverlay code does not really care about whether the pawn owner exists or not since on the client it just uses the PawnLocX, PawnLocY values to draw the radar markers (unless the pawn!=none (IE: is net relevant), in which case it uses the pawn's actual locations):
    Code:
    class YarmPawnRepInfo extends LinkedReplicationInfo;
    var string PrimaryWeap, SecondWeap, InventoryOne, InventoryTwo;
    var byte PrimPos, SecPos, Inv1Pos, Inv2Pos, PawnByte;
    
    var int PawnLocX, PawnLocY; // this is to be used by the Radar, so that clients can see other enemies on the radar
    var byte RotByte;//the rotation of this player
    var Pawn myPawn;
    var int CamoIdx, TeamCamoSetIdx;
    var class<ym_CamoDataSet> CamoSetClass; // added 27Apr09 to allow camo set selection without needing another pawn subclass
    var(ym_Camo) enum ECamoMode{  //important - order in decreasing importance
    	CAMO_None,      // Don't apply custom camo skins
        CAMO_Default,	// use the camo assigned to the pawn type
    	CAMO_Team,		// all team members share the same camo
    	CAMO_Custom 	// each player has an individual camo selection
    } CamoMode;
    
    replication
    {
        reliable if(bNetInitial && Role==ROLE_Authority)
    	    CamoSetClass;
    
        reliable if ( bNetDirty && (Role == Role_Authority))
    		PrimPos, SecPos, Inv1Pos, Inv2Pos, PawnByte, CamoIdx, CamoMode, TeamCamoSetIdx;// added team camo stuff here so that the admin can change this on the fly
    
    	reliable if ( bNetDirty && (Role == Role_Authority))
    		PawnLocX, PawnLocY, RotByte, myPawn;
    
        // owning client sends to server
        reliable if (Role < Role_Authority)
    		SetGear, SetGearByte, SetCamoIdx;
    }
    
    event PostBeginPlay()
    {
        if ( Role < ROLE_Authority )
    		return;
    	Timer();
    	SetTimer(2.0 + FRand(), true);  //this helps the replication info from all "popping" and then having to replicate at the same time
    }
    
    simulated function SetGear(string Primary, string Secondary, string Inv1, string Inv2, string PawnName)
    {
         PrimaryWeap=Primary;
         SecondWeap=Secondary;
         InventoryOne=Inv1;
         InventoryTwo=Inv2;
         NetUpdateTime = Level.TimeSeconds - 1;
         //TDPawnClassName=PawnName;
         //bUpdate=true;
    }
    
    simulated function SetGearByte(byte Primary, byte Secondary, byte Inv1, byte Inv2, byte PawnName)
    {
         PrimaryWeap=class'mute_YarmWeapons'.default.Weapon1ClassNames[int(Primary)].path;
         PrimPos=Primary;
         SecondWeap=class'mute_YarmWeapons'.default.Weapon1ClassNames[int(Secondary)].path;
         SecPos=Secondary;
         //InventoryOne=Inventory1[Inv1];
         Inv1Pos=Inv1;
         //InventoryTwo=Inventory2[Inv2];
         Inv2Pos=Inv2;
         //log("TDPCI:TDPawnClassName = "$TDPawnClassName);
         PawnByte=PawnName;
         //bUpdate=true;
         //if(Role < Role_Authority) ServerGearByte(
         NetUpdateTime = Level.TimeSeconds - 1;
    }
    
    simulated function SetCamoIdx(int Idx){
        if(CamoMode == CAMO_Custom) CamoIdx = Idx;
        NetUpdateTime = Level.TimeSeconds - 1;
    }
    
    // oooh so bad for a network
    simulated function string GetGear(int info)
    {
         local string item;
         if (info == 0) item=PrimaryWeap;
         else if (info == 1) item=SecondWeap;
         else if (info == 2) item=InventoryOne;
         else item=InventoryTwo;
         return item;
    }
    
    
    // Prep some information for the client's radar etc.
    function Timer(){
        local yarmPawn cdp;
    
        // update info for the radar
        if ( Owner != None && yarmPawn(controller(Owner).Pawn) !=none ){
             cdp = yarmPawn(controller(Owner).Pawn);
             PawnLocX = cdp.Location.X;
             PawnLocY = cdp.Location.Y;
             RotByte = cdp.rotation.yaw / 256;
             if(myPawn==none) myPawn=cdp;
        }
    	SetTimer(1.5 + FRand(), true);
    }
    
    defaultproperties
    {
    	NetUpdateFrequency=1
    	CamoSetClass=class'ym_CamoDataSet'
    }
    And some code (located in my mutator's 'CheckReplacement' function) for spawning the LRI. NOTE: this code does not check for other LRIs in the LRI chain from the PRI so it could break other mutator's functionality...
    Code:
        local	PlayerReplicationInfo	PRI;
    	local	yarmPawnRepInfo	YPRI;
    ...
            // Add custom player replication info and make it first in the list
        // see this thread-> http://forums.beyondunreal.com/showthread.php?t=168306&highlight=player+replication+info
    	if ( Other == PlayerReplicationInfo(Other) ){
    		PRI = PlayerReplicationInfo(Other);
    		if ( PRI.Owner != None && yarmPawnRepInfo(PRI.CustomReplicationInfo) == none ){ 
    			YPRI = PRI.Spawn(class'yarmPawnRepInfo', PRI.Owner);
    			YPRI.NextReplicationInfo = PRI.CustomReplicationInfo;
    			PRI.CustomReplicationInfo = YPRI;
    			switch( iCamoUniformMode ){
                    case 2:
                        YPRI.CamoMode = CAMO_Custom; break;
                    case 1:
                        YPRI.CamoMode = CAMO_Team; break;
                    Default:
                        YPRI.CamoMode = CAMO_Default; break;
                }
    			if(AIController(PRI.Owner) != None && iCamoUniformMode==2){  //PRI.bBot // This will not show up until after the bots have died at least once since the PlayerReplicationInfo is spawned after the pawn!!!
                    //log("Set Random Camo Skin for bot "$PRI);
                    YPRI.CamoIdx = Rand(YPRI.CamoSetClass.default.CamoDatas.Length);
                    //log("Set Random Camo Skin for bot "$PRI@YPRI.CamoIdx@"from"@YPRI.CamoSetClass.default.CamoDatas.Length@"camos");
    			}else if(iCamoUniformMode==1 && Level.Game.bTeamGame ){  // forced team skins in a team game
    			   if(TeamSkinSet < 0) TeamSkinSet = Rand(YPRI.CamoSetClass.default.CamoTeamDatas.Length);
                   YPRI.TeamCamoSetIdx = TeamSkinSet;
    			}
    		}
    		return true;
    	}
    
    ...
    Last edited by meowcat; 08-02-2012 at 08:45 PM.
    "What do you mean it doesn't exist clientside?"
    YARM: where player's Lean, Prone, Mantle, Dash, Crouch Jump, 'Parkour' and slide around all with generic realistic weapons!
    Meowcat's Mods for UT2K4:
    Yet Another Real-life Mod: Realistic weapons, unoriginal gameplay, w/ cheap CODMW knockoff mutator
    TD Vehicles: HUMV, MI4Hound, Motorcycle, IFAV Jeep, UH-60, MH-53 & AH-6 Helicopters, Abrams Tank
    Jetpacks for UT2k4!

  7. #7
    God King
    Join Date
    Nov 2007
    Location
    Lithuania
    Posts
    4,723

    Default

    Hmm. If that's the case, then newly relevant pawns are going to be a problem. How do I make sure that they are tracked? I don't know of any function (and it must be simulated, at that) that would be executed on a pawn becoming relevant... And the LRI has no way of knowing what the new pawn is (now, for instance, it could go through the controller, but then controllers are irrelevant to other clients, so that wouldn't work).

  8. #8
    Redeemer
    Join Date
    Jan 2004
    Location
    The great Pacific Northwest
    Posts
    1,576

    Default

    As far as I know only the PreBeginPlay/BeginPlay/PostBeginPlay and Destroyed functions are called within pawns on the non-owning client's computer when the pawn's become relevant and un-relevant. I could be wrong about the owner thing though in the LRI, you should still try and experiment with it.

    You could have the LRI (clientside) notify the server when, during it's periodic check, the pawn goes 'un-relevent', via a replicated function, or maybe. The main problem I see is that I don't think the server will continually replicate a 'pawn variable' to the client if it previously sent the same value (so you might not see it change from 'none' to 'somePawn' in the PostNetRecieve function on the client). You should probably test this though...

    Unfortunately your only real option may be to use the "dreaded" ForEach DynamicActors iterator in some custom actor spawned clientside (no need to use LRIs in this case) to periodically to check for pawns (which is what HUDInvasion does for the radar). Its obviously not the most elegant solution, but it does not require any additional communication with the server (replicated function calls asking for a pawn reference that may or may not be relevant) and if its really important to you you could try it out.
    Last edited by meowcat; 08-03-2012 at 08:24 PM.
    "What do you mean it doesn't exist clientside?"
    YARM: where player's Lean, Prone, Mantle, Dash, Crouch Jump, 'Parkour' and slide around all with generic realistic weapons!
    Meowcat's Mods for UT2K4:
    Yet Another Real-life Mod: Realistic weapons, unoriginal gameplay, w/ cheap CODMW knockoff mutator
    TD Vehicles: HUMV, MI4Hound, Motorcycle, IFAV Jeep, UH-60, MH-53 & AH-6 Helicopters, Abrams Tank
    Jetpacks for UT2k4!

  9. #9
    God King
    Join Date
    Nov 2007
    Location
    Lithuania
    Posts
    4,723

    Default

    Well, pawn functions are not going to be helpful here, given that I can't change the pawn class.

    And with that mechanism, I still see a problem. The client loses track of a pawn. It tells the server "hey dude, I lost track of the guy, can you track it for me?". The server can try to track the pawns as much as it likes - from the server's perspective, everything is always relevant, so the pawns always stay the same. So all that the server can do is reply with "No you didn't, the pawn is still there!". The newly relevant pawn would be different than it was to the client, but the same to the server. Even if the server was to send the pawn's instance to the client, would the client be able to identify the newly relevant pawn as being the same as the server just sent, or would it look different? And, most importantly, the server doesn't know when things become relevant to clients. It could send the information all the time, but it would be a waste of bandwidth, especially considering that it would have to send information about every pawn in the game every second to every client.

    Hmm, the foreach mechanism could indeed be a (hacky) option. It would require more resources, but it could work. That said, this is not really that important - the ragdoll sounds are there just for added effects, and probably people wouldn't even notice the difference.

  10. #10
    Redeemer
    Join Date
    Jan 2004
    Location
    The great Pacific Northwest
    Posts
    1,576

    Default

    Quote Originally Posted by GreatEmerald View Post
    Well, pawn functions are not going to be helpful here, given that I can't change the pawn class.
    Yup, I know, I mention it only because not everyone (other forum users) understand that a pawn, like other actors, gets destroyed on the client's machine after a second or two of being 'un-relevant' to that client.

    And with that mechanism, I still see a problem. The client loses track of a pawn. It tells the server "hey dude, I lost track of the guy, can you track it for me?". The server can try to track the pawns as much as it likes - from the server's perspective, everything is always relevant, so the pawns always stay the same. So all that the server can do is reply with "No you didn't, the pawn is still there!". The newly relevant pawn would be different than it was to the client, but the same to the server. Even if the server was to send the pawn's instance to the client, would the client be able to identify the newly relevant pawn as being the same as the server just sent, or would it look different? And, most importantly, the server doesn't know when things become relevant to clients. It could send the information all the time, but it would be a waste of bandwidth, especially considering that it would have to send information about every pawn in the game every second to every client.
    This is what I meant in my third paragraph of my previous post referring to additional communication with the server. And a slight correction, the server knows *exactly* when any replicated actor stops being relevant to a given client (since the server is determining when to send info to the client), unfortunately we don't have access to that "per client" information in UScript.

    Hmm, the foreach mechanism could indeed be a (hacky) option. It would require more resources, but it could work. That said, this is not really that important - the ragdoll sounds are there just for added effects, and probably people wouldn't even notice the difference.
    Make it a "standalone game only" mutator just like the SlowTimeKill mute for UT3 Though you could make it effect the pawns owned by a client using the LRI (so on the client machines only their pawn would get the sounds changed, and on the server every pawn's sounds would get changed).
    "What do you mean it doesn't exist clientside?"
    YARM: where player's Lean, Prone, Mantle, Dash, Crouch Jump, 'Parkour' and slide around all with generic realistic weapons!
    Meowcat's Mods for UT2K4:
    Yet Another Real-life Mod: Realistic weapons, unoriginal gameplay, w/ cheap CODMW knockoff mutator
    TD Vehicles: HUMV, MI4Hound, Motorcycle, IFAV Jeep, UH-60, MH-53 & AH-6 Helicopters, Abrams Tank
    Jetpacks for UT2k4!

  11. #11
    God King
    Join Date
    Nov 2007
    Location
    Lithuania
    Posts
    4,723

    Default

    Quote Originally Posted by meowcat View Post
    And a slight correction, the server knows *exactly* when any replicated actor stops being relevant to a given client (since the server is determining when to send info to the client), unfortunately we don't have access to that "per client" information in UScript.

    Make it a "standalone game only" mutator just like the SlowTimeKill mute for UT3 Though you could make it effect the pawns owned by a client using the LRI (so on the client machines only their pawn would get the sounds changed, and on the server every pawn's sounds would get changed).
    Yea, that's what I meant. After all, the whole idea of things going irrelevant is that the server needs to send less data. But it's useless to mod makers as it's all done natively.

    Well, that mutator adds more than just that. Although good idea for making it work for the owner, that's where things are most noticeable.

    EDIT: So I'm still mystified by that PostNetReceive(). Here's my code:

    Code:
    function RegisterRagdollSoundsClient(xPawn xP)
    {
        local UT2003RagImpactLRI LRI;
        local LinkedReplicationInfo CRI;
        
        log(Self@"RegisterRagdollSoundsClient!");
        if (xP.PlayerReplicationInfo == None //If pawn doesn't have a PRI or if we already got one, you see
            || (xP.PlayerReplicationInfo.CustomReplicationInfo != None && UT2003RagImpactLRI(xP.PlayerReplicationInfo.CustomReplicationInfo) != None) )
            return;
        
        log(Self@"Attempting to spawn a LRI!");
        LRI = Spawn(LRIClass, xP);
        if (LRI != None)
        {
            log(Self@"LRI spawned!");
            if (xP.PlayerReplicationInfo.CustomReplicationInfo == None)
                xP.PlayerReplicationInfo.CustomReplicationInfo = LRI;
            else
            {
                log(Self@"Another LRI exists!");
                for (CRI=xP.PlayerReplicationInfo.CustomReplicationInfo; CRI != None; CRI=CRI.NextReplicationInfo)
                {
                    if (CRI.NextReplicationInfo == None)
                    {
                        CRI.NextReplicationInfo = LRI;
                        break;
                    }
                }
            }
        }
    }
    Code:
    simulated function PostNetReceive()
    {
        local int i;
        
        log(Self@"PostNetReceive!");
        
        if (xPawn(Owner) != None) //GEm: The pawn is relevant!
        {
            log(Self@"Pawn is relevant!");
            for (i=0; i<4; i++)
                xPawn(Owner).RagImpactSounds[i] = Class'MutUT2003Extra'.default.UT2003RagImpactSounds[i];
        }
        Super.PostNetReceive();
    }
    
    defaultproperties
    {
        bNetNotify=true
    }
    In the log, I get "LRI spawned!" on server, and nothing else after that on both the server and the client. No "PostNetReceive".

    EDIT2: On a related note, on the server, xPawn.VoiceClass always equals XGame.JuggMaleVoice (although, for instance, xPawn.SoundGroupClass is correctly set). How come is that, and is there anything that can be done to fix this? I need to access the correct VoiceClass to play the correct voice depending on the voice the player has chosen.


 

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Copyright ©2009-2011 Epic Games, Inc. All Rights Reserved.
Digital Point modules: Sphinx-based search vBulletin skin by CompletevB.com.