• 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 [Question] Using FileWriter

so spreading the mutator isn't a problem as it'll be done when each client logs on the server. But i fear this will mean that I won't be able to produce a separate log file on each players sprinting conditions across 5rounds. Having a separate file for each round would be nice, though not important.

If I can't have a separate log for each character I'll need a way to log which player each log function relates to. I don't intend to use the web-admin as I'll have a dedicated server computer that won't be playing.

And I found two copies of the mutator and after removing one, the message ceased to show.
 
Upvote 0
What you will need to do is make a client side instance. An easy way to do this is by sub-classing ROPlayerController and move the logging code to that sub-class. Then you have per client direct access to all settings and your code will run on both client and server.

I looked at your mutators code again and I do not see a call to the LogSprintTransition function. You need to call it from somewhere or else it won't work for sure. Also does that code sit in a class instance of which only one will be present on the server. This means that the same bPreviousIsSprinting variable will be used by all players. Your logging will contain none consistent data and will rather be useless. If you move that function to a sub-class of ROPlayerController. Then you are good to go, because that class has an instance for each connected player.
 
Upvote 0
So would this be to create a new .uc file with the

Code:
class sprintCaller Extends ROPlayerController...
'include (sprintMutator.uc)
 
function LogSprintTransition....

As far as I understand that would mean the mutator would just create a file to log in. Though since you said sub-class I believe I've got this wrong, so would it be: 'include ROPlayerController instead?
 
Upvote 0
So would this be to create a new .uc file with the

Code:
class sprintCaller Extends ROPlayerController...
'include (sprintMutator.uc)
 
function LogSprintTransition....
As far as I understand that would mean the mutator would just create a file to log in. Though since you said sub-class I believe I've got this wrong, so would it be: 'include ROPlayerController instead?

Nope. You can't include a class within an other class. You must make 2 classes. One derived from ROMutator and one derived from ROPlayerController. The ROMutator sub-class will only exist to tell the UE to use your ROPlayerController sub-class and not the stock RO2 ROPlayerController class.
Both class files (the .uc files) must sit in the Src\sprintMutator\Classes folder.

SMPlayerController.uc:
Code:
class SMPlayerController extends ROPlayerController;

var FileWriter writer;
var bool bPreviousIsSprinting;

// Overload of ROPlayerController::PostBeginPlay
// Called at both server and client side
simulated function PostBeginPlay()
{
    local string PlayerName;

    super.PostBeginPlay();

    if (self.Role < ROLE_Authority) // Only do this on client side
    {
        // This will only be executed at client-side
        self.writer = self.Spawn(class'FileWriter');
        self.writer.OpenFile("SprintLogFile", FWFT_Log, ".txt", true, true);
    }
}

// This function is an overload of PlayerController::PlayerTick.
// It is only called at client side and by that won't delay the server.
event PlayerTick(float DeltaTime)
{
    super.PlayerTick(DeltaTime);

    self.LogSprintTransition(self.Pawn);
}

function LogSprintTransition(Pawn Other)
{
    local ROPawn  MyPawn;

    MyPawn = ROPawn(Other);

    if(self.bPreviousIsSprinting != MyPawn.bIsSprinting)
    {
        if(MyPawn.bIsSprinting)
        {
            self.writer.Logf("Player Started Sprinting"$TimeStamp());
        }
        else
        {
            self.writer.Logf("Player Stopped"$TimeStamp());
        }

        self.bPreviousIsSprinting = MyPawn.bIsSprinting;
    }
}

// Overload of ROPlayerController::Destroyed.
// Called at both client and server side.
simulated event Destroyed()
{
    super.Destroyed();

    if (self.writer != None)
    {
        self.writer.CloseFile();
    }
}

defaultproperties
{
    writer=None
    bPreviousIsSprinting=False
 }
sprintMutator.uc:
Code:
class sprintMutator extends ROMutator;

// Overload of ROMutator::InitMutator.
// Called at server side only
function InitMutator(string Options, out string ErrorMessage)
{
    local string  password;

    super.InitMutator(Options, ErrorMessage);

    if (ROGameInfo(self.WorldInfo.Game) != None)
    {
        // This is the magic that tells UE to use your SMPlayerController class
        ROGameInfo(self.WorldInfo.Game).PlayerControllerClass = class'sprintMutator.SMPlayerController';
    }
}

defaultproperties
{
    GroupNames=("SprintMutator")
}
Code hasn't been compiled. You might stumble in a few errors/warning here and there.

I strongly advice you to read the online UE3 documentation or else you will stumble into problems with about every step you make. Also lookup example mutators on the beyond unreal wiki. Those are really helpful. That is how we all started.
 
Last edited:
Upvote 0
Thanks Ducky, when compiled I get two warnings which are:

SteamDIR\Development\Src\sprintMutator\Classes\ROSprintController.uc(9): Warning, 'PlayerName : unreferenced local variable

Same DIR as above\sprintMutator.uc(6)... 'Password' :unref

I assume that PlayerName will be used when a client logs in, with password linking to the servers password so will be referenced once with the server files?

Though just to make sure I know what I've got be looking at now, in order to get this running for testing I'll need to have the server loading the .u file and then use replication to get the clients to download and use it in game?
 
Upvote 0
Thanks Ducky, when compiled I get two warnings which are:

SteamDIR\Development\Src\sprintMutator\Classes\ROSprintController.uc(9): Warning, 'PlayerName : unreferenced local variable

Same DIR as above\sprintMutator.uc(6)... 'Password' :unref

I assume that PlayerName will be used when a client logs in, with password linking to the servers password so will be referenced once with the server files?

Nope, it was a left over from a copy-paste action from an other mutator. You can remove that 'local string PlayerName;'

Though just to make sure I know what I've got be looking at now, in order to get this running for testing I'll need to have the server loading the .u file and then use replication to get the clients to download and use it in game?

You are trying to drive a car without knowing the location of the steering wheel.

Don't feel offended, but you need to put some time in studying the basics of UE3. If you look at the mutator code, and your setup, then none has been written by you. This is not the way how you should develop a mutator. Asking is OK, but you can't expect that things will be delivered on a presentation plate. You will still need to put your own effort into your project. Your questions are all basic UE3 knowledge related. And all the answers can be found in the UE3 online documentation. It won't hurt to read that documentation. Nor will it bite you.
 
Upvote 0
No offense taken Ducky, I'm a student studing Music and coding is fairly new. Is there any tutorial videos on UE script from Epic? I found a massive collection on how to start developing levels using UDK and kismet, but nothing on uc.

I know it may have been a pain the last couple of days, but thank you for all your help.
 
Upvote 0
If you have no coding experience at all, then UE3 isn't the easiest language to start with. In UE3 you always have to be aware that some code will run at server side only. Some at client side only and some at both sides. And that split over more than one client. You don't have to worry about something like that if you for instance write a C# desktop application.

The UE3 documentation is a bit split up. I mostly use google to find what I need. Here are two starting points:

The beyond unreal wiki does contain a few examples of simple mutators.
 
Upvote 0
Well I've been poking around the web for most of the day looking at home to get the mutator to load with the server, which I found a few things though couldn't find much in-depth detail of each option so an explanation would be great if its not too much trouble.

So what I found mentioned the most was adding the line ?mutator=MyMutator after the map and gametype, which I'm more than likely wrong in assuming this is to go in the server.bat file so it loads with the serverpackages? Which then searching for serverpackages lead me to a mention of the array in an ini file that I haven't been able to find.

I also saw something I thought was very promising being the DynamicLoadObject() which I believe will only load the packages on the local machine, so to get it to each client I'd have to go round and load it.

I also saw something about needing to compile into a different file format to put into the PCCookedServer, though couldn't find any other particular mention of it elsewhere. I guess for this its to do with a different compiler, so make a shortcut of the ROGame.exe in the server files with make on the end and run that instead.

Does some of this sound right or am I currently staring down the exhaust thinking that must be the steering wheel to continue with the good car analogy?
 
Upvote 0
It's not that hard. This is an example of a ROServer.bat file:
Code:
start .\Binaries\win32\ROGame TE-Apartments?MinPlayers=0?MaxPlayers=32?Mutator=sprintMutator.sprintMutator -seekfreeloadingserver

That's really all. It will start your server and load the mutator. The mutator will be automatically uploaded to the clients as soon as they connect.

You can find some RO2 mutator projects here:

 
Upvote 0