• Please make sure you are familiar with the forum rules. You can find them here: https://forums.tripwireinteractive.com/index.php?threads/forum-rules.2334636/

Code [Help] Replication problem

forrestmark9

Grizzled Veteran
Nov 29, 2011
1,110
42
I'm trying to make a system where certain players can change there name to have color tags without affecting there original name but sadly a replication problem happens that is confusing me greatly, it appears that the string is "" on both client and server and if I can get it to not be "" on the client then it's "" on the server and other players can't see the change only the owner

Here is the code
ForrestPRI.uc
Code:
class ForrestPRI extends KF_StoryPRI;

var string AltPlayerName;
var bool bGotVIPValues;

replication
{
    reliable if( bNetDirty && (Role == Role_Authority) )
        AltPlayerName;
}

function Tick(float DT)
{
    if( !bGotVIPValues )
    {
        bGotVIPValues = true;
        if( FMXPlayerController(Owner) != none )
            FMXPlayerController(Owner).InitVIPInfo();
    }
    Super.Tick(DT);
}

defaultproperties
{
}
FMXPlayerController.uc
Code:
var() globalconfig string AltPlayerName;

replication
{
    reliable if( Role == ROLE_Authority )
        SetupPlayerName;
}

exec function SetName(coerce string S) 
{
    local ForrestPRI FPlayerRepInfo;
    local string OldName, NewName, Gender;
    
    if( PlayerReplicationInfo == none )
        return;
        
    FPlayerRepInfo = ForrestPRI(PlayerReplicationInfo);
    
    if( !FPlayerRepInfo.bSuperVIP )
        return;
        
    if( NameChanged > 4 && !bNameCoolDown )
    {
        bNameCoolDown = true;
        NameChangeCoolDown = Level.TimeSeconds;
    }
    
    if( bNameCoolDown )
    {
        ClientMessage("Name changed too many times, please wait 10 seconds");
        return;
    }
        
    if( S == "" )
    {
        AltPlayerName = S;
        FPlayerRepInfo.AltPlayerName = S;
        SaveConfig();
        return;
    }   
    
    if( FPlayerRepInfo.AltPlayerName == "" )
        OldName = PlayerReplicationInfo.PlayerName;
    else
        OldName = FPlayerRepInfo.AltPlayerName;
        
    NewName = S;
    
    ReplaceText(NewName, " ", "_");
    ReplaceText(NewName, "\"", "");
    
    Gender = eval(PlayerReplicationInfo.bIsFemale, "her", "his");

    AltPlayerName = NewName;
    SetupPlayerName(FPlayerRepInfo);
    SaveConfig();
        
    if( Mut.StripColorTags(NewName) == Mut.StripColorTags(OldName) )
        return;
        
    BroadcastMessage(Mut.ParseColorTags(OldName)@Mut.ColorString("has changed"@Gender@"name to", 255, 255, 255)@Mut.ParseColorTags(NewName), true);
    NameChanged++;
}

function InitVIPInfo()
{
    local int i;
    local ForrestPRI FPlayerRepInfo;
    local string SteamID;
    local bool bLoggedName;
    
    if( PlayerReplicationInfo == none )
        return;

    FPlayerRepInfo = ForrestPRI(PlayerReplicationInfo);
    SteamID = GetPlayerIDHash();
    
    for(i=0;i<class'FMXBaseMut'.default.Mut.SteamIDs.Length;i++)
    {
        if( class'FMXBaseMut'.default.Mut.SteamIDs[i].ID == SteamID )
        {
            FPlayerRepInfo.bSuperVIP = True;
            FPlayerRepInfo.MedalMaterial = Material(DynamicLoadObject(class'FMXBaseMut'.default.Mut.SteamIDs[i].MedalMaterial, class'Material', true));
            FPlayerRepInfo.PlayerNameColor = class'FMXBaseMut'.default.Mut.SteamIDs[i].VIPColor;
        }
    }

    SetupPlayerName(FPlayerRepInfo);
    
    if( !bLoggedName )
    {
        bLoggedName = true;
        if( Mut != none && AltPlayerName != "" && Mut.StripColorTags(AltPlayerName) != PlayerReplicationInfo.PlayerName )
            log(Mut.StripColorTags(AltPlayerName)$"'s old name was"@PlayerReplicationInfo.PlayerName);
    }
}

simulated function SetupPlayerName( ForrestPRI FPlayerRepInfo )
{   
    if( Level.NetMode == NM_DedicatedServer )
        return;
    if( AltPlayerName != "" )
        FPlayerRepInfo.AltPlayerName = AltPlayerName;
}
 
Last edited:
I'm thinking I made need to use PostNetRecieve but I have no idea what I'd need to do cause PostNetRecieve is already used by the PRI and I wouldn't know exactly how to do it in PlayerController. I'm unsure if I should change the AltPlayerName var directly from the PlayerController in PostNetRecieve or call the function SetupPlayerName
 
Last edited:
Upvote 0
Code:
replication
{
    reliable if( Role [COLOR=Lime]<[/COLOR] ROLE_Authority )
        SetupPlayerName;
}
You need to replicate function call from client to server ^

I tried that but it seemed that when doing so not even the client could see the change

Edit: Wait nevermind it seems to work but sadly it does not get set initially when you join the game which is what is suppose to happen in InitVIPInfo, it seems to only update when calling SetName
 
Last edited:
Upvote 0
I tried that but it seemed that when doing so not even the client could see the change

Edit: Wait nevermind it seems to work but sadly it does not get set initially when you join the game which is what is suppose to happen in InitVIPInfo, it seems to only update when calling SetName
You might be able to fix that by adding a first time run part to PostNetRecieve?
 
Upvote 0
Hmm I'd probably need to pass a bool onto NeedNetNotify() that way PostNetRecieve is only called when that bool is changed
Well, when the client first joins, their game will say "yo, my value is true".
Code:
simulated function PostNetReceive()
{
     if(bJustJoined)
     {
          DoMuhUpdatePls();
          bJustJoined = False;
     }
}
[...]
defaultproperties
{
     bJustJoined = True
}
I'm pretty sure PostNetReceive is called whenever any replicated var is received. Wouldn't it get triggered from when the player is joining and does PRI stuff?
 
Upvote 0
Well, when the client first joins, their game will say "yo, my value is true".
Code:
simulated function PostNetReceive()
{
     if(bJustJoined)
     {
          DoMuhUpdatePls();
          bJustJoined = False;
     }
}
[...]
defaultproperties
{
     bJustJoined = True
}
I'm pretty sure PostNetReceive is called whenever any replicated var is received. Wouldn't it get triggered from when the player is joining and does PRI stuff?

bNetNotify is set by NeedNetNotify() and PostNetRecieve is only ever called when this is true

Code:
simulated function bool NeedNetNotify()
{
    return Super.NeedNetNotify() || bWaitingForPRI || (bVoiceChatEnabled && bWaitingForVRI);
}
 
Upvote 0
You are trying to pass PRI to SetupPlayerName(), i.e. pointer to PRI object. Client already has changed PRI.AltPlayerName, while server has an empty string. That's why it doesn't work. You should pass player name (string value) instead (code may contain errors, because I didn't tried to compile it):

Code:
var() globalconfig string AltPlayerName;

replication
{
    reliable if( Role [COLOR="lime"]<[/COLOR] ROLE_Authority )
        SetupPlayerName;
}

[COLOR="Lime"]simulated function PostNetBeginPlay()
{
    super.PostNetBeginPlay();
    
    // try send local player's name to server --PooSH
    if ( Viewport(Player) != None ) {
        SetupPlayerName(AltPlayerName);
    }
}[/COLOR]

// executing on owner's side
exec function SetName(coerce string S) 
{
    local ForrestPRI FPlayerRepInfo;
    local string OldName, NewName, Gender;
    
    if( PlayerReplicationInfo == none )
        return;
        
    FPlayerRepInfo = ForrestPRI(PlayerReplicationInfo);
    
    if( !FPlayerRepInfo.bSuperVIP )
        return;
        
    if( NameChanged > 4 && !bNameCoolDown )
    {
        bNameCoolDown = true;
        NameChangeCoolDown = Level.TimeSeconds;
    }
    
    if( bNameCoolDown )
    {
        ClientMessage("Name changed too many times, please wait 10 seconds");
        return;
    }
        
    if( S == "" )
    {
        AltPlayerName = S;
        FPlayerRepInfo.AltPlayerName = S;
        SaveConfig();
        return;
    }   
    
    if( FPlayerRepInfo.AltPlayerName == "" )
        OldName = PlayerReplicationInfo.PlayerName;
    else
        OldName = FPlayerRepInfo.AltPlayerName;
        
    NewName = S;
    
    ReplaceText(NewName, " ", "_");
    //ReplaceText(NewName, "\"", "");
    
    Gender = eval(PlayerReplicationInfo.bIsFemale, "her", "his");

    AltPlayerName = NewName;
    SetupPlayerName(AltPlayerName);
    SaveConfig();
        
    if( Mut.StripColorTags(NewName) == Mut.StripColorTags(OldName) )
        return;
        
    BroadcastMessage(Mut.ParseColorTags(OldName)@Mut.ColorString("has changed"@Gender@"name to", 255, 255, 255)@Mut.ParseColorTags(NewName), true);
    NameChanged++;
}

function InitVIPInfo()
{
    local int i;
    local ForrestPRI FPlayerRepInfo;
    local string SteamID;
    local bool bLoggedName;
    
    if( PlayerReplicationInfo == none )
        return;

    FPlayerRepInfo = ForrestPRI(PlayerReplicationInfo);
    SteamID = GetPlayerIDHash();
    
    for(i=0;i<class'FMXBaseMut'.default.Mut.SteamIDs.Length;i++)
    {
        if( class'FMXBaseMut'.default.Mut.SteamIDs[i].ID == SteamID )
        {
            FPlayerRepInfo.bSuperVIP = True;
            FPlayerRepInfo.MedalMaterial = Material(DynamicLoadObject(class'FMXBaseMut'.default.Mut.SteamIDs[i].MedalMaterial, class'Material', true));
            FPlayerRepInfo.PlayerNameColor = class'FMXBaseMut'.default.Mut.SteamIDs[i].VIPColor;
        }
    }

    if( !bLoggedName && AltPlayerName != "")
    {
        bLoggedName = true;
        if( Mut != none && Mut.StripColorTags(AltPlayerName) != PlayerReplicationInfo.PlayerName )
            log(Mut.StripColorTags(AltPlayerName)$"'s old name was"@PlayerReplicationInfo.PlayerName);
    }
}

// server-side only
function SetupPlayerName( [COLOR="lime"]string NewPlayerName[/COLOR] )
{   
    local ForrestPRI FPlayerRepInfo;
    
    if( NewPlayerName == AltPlayerName )
        return; //nothing changed
    
    FPlayerRepInfo = ForrestPRI(PlayerReplicationInfo);
    if( FPlayerRepInfo == none || !FPlayerRepInfo.bSuperVIP )
        return;
        
    AltPlayerName = NewPlayerName;
    FPlayerRepInfo.AltPlayerName = NewPlayerName;
    [COLOR="lime"]InitVIPInfo();[/COLOR]
}

InitVIPInfo() is called from SetupPlayerName(). No need to do a check in PRI.Tick().
 
Last edited:
Upvote 0
This will not work as GetPlayerIDHash will return the players UT2004 CD-Key hash, InitVIPInfo was specifically called in Tick of the PRI as Tick is called after PostLogin which is where GetPlayerIDHash will actually return the persons SteamID

So InitVIPInfo shouldn't be called from SetupPlayerName, so I shall leave it in Tick

Edit: After doing further checks the return if !bSuperVIP won't work as it's set to true after PostNetBeginPlay
 
Last edited:
Upvote 0
Haven't taken a look at your code but, bNetNotify=true set? Because I've had many problems before without that in defprops

bNetNotify only needs to be true when calling the function PostNetRecieve

Poosh's code is in PostNetBeginPlay which doesn't work

Edit: Found the problem, if ( Viewport(Player) != None ) that was returning none
 
Last edited:
Upvote 0
Would this maybe work?

Code:
simulated function PostNetReceive()
{
    if ( Level.NetMode == NM_Client && Viewport(Player) != none )
        SetupPlayerName(AltPlayerName);
        
    Super.PostNetReceive();
}

simulated function bool NeedNetNotify()
{
    return Super.NeedNetNotify() || (Viewport(Player) == none && !bGotPlayerName);
}
 
Upvote 0