UE1 - UT Setting bools clientside

  • 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.

playsax

New Member
Feb 20, 2008
44
0
0
Here's another problem which has been bothering me for years, really. Let me first describe the scenario: I want players to be able to type "mutate enable". This in turn should set a boolean value to True on their client, and their client only.

Here is some code to illustrate:

Code:
var bool bEnabled;

function Mutate( string Str, PlayerPawn Sender )
{
	if ( Str ~= "enable" )
        bEnabled=true;
}

simulated function CheckBool()
{
if(bEnabled) // do something
}

Obviously this won't work, since bEnabled isn't replicated to the clients. However, if this value were replicated, it would affect the boolean value for ALL clients. So if one player was to type "mutate enable", the bool bEnabled would be True for everyone.

The question is: how can I make it so bEnabled is only set True for the client that issued the Mutate request?
More specifically: how do I set it on their client (since bEnabled is used in a simulated function)?
 

meowcat

take a chance
Jun 7, 2001
803
3
18
1. I believe this was true for UT, mutators only exist on the server, unless you change their default properties. So you have to change this first (RemoteRole=ROLE_SimulatedProxy, bAlwaysRelevant=true).

2. Here is one way you might do this without having to subclass the PlayerPawn class (there is probably a simpler way...). In the mutator class you might try to store an array of structs that contain playerReplicationInfo (PRI) references and a bool or two. Anytime mutate is called (with "Enable" as the string argument), add the Sender's PRI to the array and set the bool to true. This array can keep track of which player's have called "mutate enable" recently (in case multiple client's mutate calls are received in the same tick) by adding the call to the next available element (or wrapping around to the end). I suppose you could also just save a reference to the playerPawn also, on clients those elements would evavluate to none if the player was not relevant.

Have a replicated struct with a playerReplicationInfo reference (call it ClientPRIEnable for instance) and bool. Each tick, iterate to the next element in the tracking array, give ClientPRIEnable's info that element, set the bool to false, then update a position counter (basically replicate a different element each tick).

In the same tick function you can have a client only section (if(Role==ROLE_SimulatedProxy)....) that checks to see if the replicated ClientPRIEnable.PRI is equal to their PlayerPawn's PRI, and if it is, and ClientPRIEnable.bEnable is true, go ahead and toggle their local non-replicated copy of the bEnable variable. Now you may wonder how to get a reference to the local playerPawn...keep a playerPawn reference variable in your mutator class, iterate through all actors in a simulated version of PostBeginPlay (or perhaps perform everytime in the client portion of Tick, if it ==none), then check to see if ViewPort(playerPawnRef.Player)!=none (<-- This will not work exactly as written, the UT99 checks will be a bit different).

There are probably cleaner way of doing this (also possibly faster ways for replication purposes, but this method should limit the amount of clientside checking that needs to be done as opposed to iterating through an entire replicated array to see if the server picked up a client's "mutate enable" function call).

What exactly are you trying to do this for? The only thing I can immediately think of is creating a HUDMutator with features that each client could turn on and off....
 
Last edited:

playsax

New Member
Feb 20, 2008
44
0
0
What exactly are you trying to do this for? The only thing I can immediately think of is creating a HUDMutator with features that each client could turn on and off....

That's correct ;)

Thanks for that big reply. I currently use a list of players that have typed "mutate enable". If someone types that, their playername is added to the list. This list is replicated to the client and the client cycles through the list to see if its own playername is on there. If it is, then bEnabled=True, if it isn't, then it isn't (heh...) This works well, but it's a messy way of doing things. But then again your method sounds even more complicated, so I think I'll stick with this.

Thanks a lot.
 
Last edited:

Zur

surrealistic mad cow
Jul 8, 2002
11,708
8
38
48
Hmm, it's not really essential to use replication for something like this although it does simplify things when a player enters or leaves a server. As for keeping track of players, it's a better idea to store a reference to their playerpawn as that is unique.

There is one thing that I don't understand though. Why have a client type mutate enable to add the playername to a list and then have the client cycle through the list again. It sounds like double the work for the same result.
 

playsax

New Member
Feb 20, 2008
44
0
0
There is one thing that I don't understand though. Why have a client type mutate enable to add the playername to a list and then have the client cycle through the list again. It sounds like double the work for the same result.

"mutate enable" is an optional command that players can type. So only those who do should be taken care of. The list is constructed serverside (since mutate commands are handled by the server) and through this way it's able to keep track of each player's "preference" (enabled yes/no).

But then a problem arises.. how do we communicate this to the specific player? The server knows he typed "mutate enable", but his client does not. So that's where the list enters the picture... since it contains his name, the client now knows the player typed the mutate command.

I hope this makes sense.

--

You are right about the playernames. For uniqueness sake I've now based it on the PlayerID.
 
Last edited:

Zur

surrealistic mad cow
Jul 8, 2002
11,708
8
38
48
You want to set an attribute clientside but haven't said for what purpose. If it's simply to keep track of an on/off setting with nothing specific happening clientside (for example a hud being displayed or a weapon changing aspect) then this can be done serverside no problem.

Code:
struct PPrefs
{
       var Pawn PawnLink;
       var bool Enable;
};

PPrefs[32]; //UT1 has a 32 player limit. The maximum player limit is higher on UT2004 and UT3.

function Mutate(string MutateString, PlayerPawn PLink)
{
	Super.Mutate(MutateString, PLink);

	if( PLink != none ) // not really necessary but an empty PLink will throw up accessed nones further on
	{

		if ( Caps(MutateString) == "ENABLE" )
		{
			PPrefs[PLink.PlayerReplicationInfo.PlayerID].PawnLink = PLink;
			PPrefs[PLink.PlayerReplicationInfo.PlayerID].Enable = true;

			PLink.ClientMessage("Option is activated.");
		}

		if ( Caps(MutateString) == "DISABLE" )
		{
			PPrefs[PLink.PlayerReplicationInfo.PlayerID].PawnLink = PLink;
			PPrefs[PLink.PlayerReplicationInfo.PlayerID].Enable = false;

			PLink.ClientMessage("Option is deactivated.");
		}
	}
}

You could default Enable to false (I'm not sure if a bool will work in a struct btw) and use the reference to Pawn to make sure the setting corresponds with a player. The player will get a message each time he uses the correct mutate commands. Note that I'm not sure if PlayerID should be used in this way. I know it increments with each new player but I don't know if it continues doing so or if it resets to ID 0. If it doesn't then it would be a better idea to create a custom Object with next/previous links that you can instantiate only when needed.
 
Last edited:

playsax

New Member
Feb 20, 2008
44
0
0
That's nice code, Azura.

The thing is PPreferences[PLink.PlayerReplicationInfo.PlayerID].Enable needs to be read from within a simulated function on the client (to draw something on the HUD, so that's what bEnabled is for). Your code does indeed save the preference for each player on the server, but it doesn't tell (replicate to) the client which preference it has.

As far as I know the PlayerID can only increase.. it's a standard INT value and I've seen no code that resets it. I've wondered that myself though and reconnected well over 32 times (what I figured would be likely be the limit) and it seemed to keep on increasing indefinitely.

All in all there've been great responses and I'm very grateful for your input. :)
 

Zur

surrealistic mad cow
Jul 8, 2002
11,708
8
38
48
That's nice code, Azura.

The thing is PPreferences[PLink.PlayerReplicationInfo.PlayerID].Enable needs to be read from within a simulated function on the client (to draw something on the HUD, so that's what bEnabled is for). Your code does indeed save the preference for each player on the server, but it doesn't tell (replicate to) the client which preference it has.

Right, I get you. So, if I've understood correctly, the server's role is to police the preferences of players. Ideally you'd have a list serverside for all players and the relevant bool replicated clientside. I'd follow Meowcat's suggestion.

As far as I know the PlayerID can only increase.. it's a standard INT value and I've seen no code that resets it. I've wondered that myself though and reconnected well over 32 times (what I figured would be likely be the limit) and it seemed to keep on increasing indefinitely.

I suspected as much and Anthrax hinted that it isn't a good idea to use PlayerIDs in this way. Pawn seems to be the only reliable piece of information that can be used. I suppose some sort of correspondance with the array could be done by cycling through the pawn list but this would be a pain to manage because players come and go. The object approach is probably the best.

That's exactly where replicated attributes can make things simpler since PRI disappears along with it's associated Pawn. It's also easier to get at information using linked lists (Next.Blah). However, some mod authors use PRI just to store information as a sort of substitute for dynamic arrays in cases where replication isn't needed at all. It's a waste of ressources and that's why I was asking what you intend to do.
 
Last edited: