Build variable array: Mutator or Rep. Info?

Discussions about Coding and Scripting
Post Reply
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Build variable array: Mutator or Rep. Info?

Post by ANUBITEK »

I have a struct array that contains variables. I need to write into the struct(s), the functions are already written. The struct array is contained in my player replication info. Would it be a better idea to hold functions that write to the struct array, contained in the player replication info class, in the player replication class itself or to use a mutator? It would do something like this:

Grab player and possessed scripted pawn,
Grab variables from scripted pawn,
Copy variables into struct array,
Back this struct array up into a .ini file. (Mutator should handle this)

I'll be using this for backing up mostly small strings and integers to modify health, damage, and some other stuff. I already have that planned and coded, but I'm not sure where I should throw my functions.
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Build variable array: Mutator or Rep. Info?

Post by Feralidragon »

I think you may be doing that in the wrong way altogether, but I would rather see the struct itself first and see what you're saving and getting from there to what, to do a better assessment.

In the meanwhile, you probably should read a bit about SOLID programming principles (S.O.L.I.D. -> it's an acronym).
Although most of the code that you will find, be it from Epic or modders in general in their mods, stays really far from or even goes directly against SOLID principles, it's in cases like this one where you should abide to them the most, because these principles not only automatically answer those questions in a very succinct manner, they help you to avoid doing some kinds of mistakes.

From there, after you post the struct, and after you maybe read a little bit about them (they are 5 principles, and they aren't very hard to understand), I think the solution you seek will become more clearer.
User avatar
Barbie
Godlike
Posts: 2792
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Build variable array: Mutator or Rep. Info?

Post by Barbie »

I even did not understand what the aim of it could be...

BTW: storing data in arrays means you are limited to a fixed amount. I remember sektor2011 has published some code to read (write?) unlimited amount of array entries from an INI file. Another option is using a single- or double-linked list.
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Build variable array: Mutator or Rep. Info?

Post by sektor2111 »

WARNING !
Trying to read such things with UScript without XCGE will crash any game instantly (let me guess... unchanged in any 451 anyway...).
With XCGE that mutator has no flaws - no new natives are called and no new deps are created and there is a need to a special consideration toward last element from array...
Else I could Not Write such things as UT can do from Preferences Menu (INI can be edited from there)- probably in that menu UT is using pure natives without UScript support.
Dynamic array is not an easy deal due to that "awesome" UE1...

For dealing with ScriptedPawn properties probably a dynamic array should not be a very need. I used some actor in a MonsterReplacer which I did before XCGE's age - that was supposed to get ScriptedPawn's data for replacing it - Now I don't need it - and it was a lagger anyway because... I did not have Cacher mutator which I did months later, and so on...

Now about that SOLID programing...
Perhaps FeraliDragon or how he said later nogarDilareF can explain these coding hints in the topic where Mr. Loathsome has ignited a speech about coding hints, tricks and where I did not see many people speaking useful sentences for low skilled people like me and others...

At this moment I'm saying RESPECT for LannFyre which was learning a lot and even doing new things, he cannot be compared with other sudden new comers self-claimed "coders" spamming forum with crap and having unexistent UCC troubles (troubles were in their heads), he did new stuff... but heavy to figure by those which are not reading forum but they are only on a posting spree... and which convinced me to Not Read this board Daily as I was doing before...
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Build variable array: Mutator or Rep. Info?

Post by Feralidragon »

sektor2111 wrote: Now about that SOLID programing...
Perhaps FeraliDragon or how he said later nogarDilareF can explain these coding hints in the topic where Mr. Loathsome has ignited a speech about coding hints, tricks and where I did not see many people speaking useful sentences for low skilled people like me and others...
I intend to write about it eventually, not only about SOLID, but design patterns, code style and naming conventions and general dos and don'ts in programming (DRY, premature optimization, KISS, encapsulation, stuff like that), and how they can be applied to UScript.

However I was only intending to do so by the time I actually picked up UScript itself and started developing on it again, given that right now I am exclusively focused in developing things in another language, since I need those things first before doing anything in UScript at all, plus any code I did previously (that includes things like NW3 for example) were way before I learned about these and how to structure my own code better, although this learning was entirely by actually reading stuff online hence me advising you guys to do the same.
Adding to this, I intend to create one or more packages, eventually, in order to ease up the creation of mods overall, in such a way that no one breaks anything from anyone else.

But, if anyone is really interested to, I may start a topic today for SOLID principles how they may be applied into UScript, and how they help you figure out the solutions better and quicker, and making good maintainable code.
I don't think Mr. Loathsome's topic is the most appropriate for this, because things like SOLID is more than a few tricks and techniques, it's a lot more broader than that and is something that is bound to generate a lot of discussion.
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Build variable array: Mutator or Rep. Info?

Post by sektor2111 »

Okay, I'm eyes and ears at any coder's posting and if it does include some snippets (negatives and positives) How To / How To Not, I'm reading everything (even 60+ pages if I have to) and also copying any useful info for any future usage.
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Build variable array: Mutator or Rep. Info?

Post by Feralidragon »

Done: viewtopic.php?f=15&t=12753
It's only an introduction and the first principle for now. Once I manage some time, maybe tomorrow, I will write about another one.
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Build variable array: Mutator or Rep. Info?

Post by ANUBITEK »

Instead of just inserting all the actors I have modified as well as their code, I've just taken out the individual variables and functions relevant to what I want to do. Relevant actors:

> PlayerPawn (RPG_Controller or Controller, sends input to Puppet class)
> ScriptedPawn (RPG_Puppet or Puppet, controlled by player),
> Mutator (RPG_GameMutator, or Mut)
> PlayerReplicationInfo (RPG_PlayerReplicationInfo, or PRI).

The following is a brief description of segments of code grabbed along with their intended purpose:

> Pawn has a Strength, Dexterity, and Intelligence stat variable (default 15 on each), as well as a Max Health variable for when their Health is modified via health pack items. These stats are modified by a GlobalLevel Variable that accounts for a level-up count for your party. If one Puppet's level should be modified, then all Puppets' levels are modified (ex: Puppet is level 2, all Puppets are level 2).
Spoiler

Code: Select all

// PUPPET VARIABLES
var string() PMemberName
var travel int MaxHealth;
var int Class1,Class2,StrStat,DexStat,IntStat,
			StrFocus,DexFocus,InFocus;

// PLAYER VARIABLES (arbitrated, uses input to modify Puppet, always-existing pawn for reference)
var travel int	GlobalLevel;
var int		MaxLevel;

// LEVEL MODIFICATION VARIABLES
var int LevelUpTotal;
> I want up to 3 Puppets spawned at a time, capable of being swapped out similar to how the game Earthbound allows you to switch your party member order and up to 2 of the "Puppets" follow the currently controlled Puppet. If the player only wants 1 or 2 Puppets at a time, or to swap them between 5 different Puppets, the Puppet could have their information swapped with information held in a registry. Therefore a registry needs to be made of any Puppets that are on the map when code is called to register them. This is the struct they are registered to:
Spoiler

Code: Select all

struct PMemberInfo
{
    var travel string PMemberName;
	var travel pawn PMember;
    var travel int Class1;
	var travel int Class2;
	var travel int StrStat;
	var travel int DexStat;
	var travel int IntStat;
	var travel int StrFocus;
	var travel int DexFocus;
	var travel int IntFocus;
};
var travel private array<PMemberInfo> PartyInfo;
> The following code assigns variables from a Puppet to the above struct.
RegisterPMemberInfo(): checks if the array can or has been incremented, then executes ModifyPStats() and Register Stats.
ModifyPStats(): Grabs a Puppet's STR/DEX/INT stats, then grabs the GlobalLevel variable, modifies them by adding the current GlobalLevel multiplied by STR/DEX/INTfocus.
RegisterStats(): Assigns a Puppet's stats to a struct, within the array.
GetByActor(): uses a Puppet as a parameter to determine which Array element they are assigned to.
Spoiler

Code: Select all

final function RegisterPMemberInfo(RPG_Puppet P)
{
	local int i;
	
	Num = GetByActor( P);
    if ( Num == -1 ) {
		Num = Array_Size( PartyInfo);
		if ( !Array_Insert( PartyInfo, Num, 1) )
		{
			Log("ERROR: Failed to allocate animation register for "$P.Name);
			return;
		}
	}
	
	if ( P != none ) {
		PartyInfo[Num].PMember = P;
		ModifyPStats(P);
		RegisterStats(P,Num);
	}
}

Code: Select all

final function ModifyPStats(RPG_Puppet P, optional bool bResetToDefaults)
{
	if (bResetToDefaults == true) {
		P.StrStat = P.StrStat.default;
		P.DexStat = P.DexStat.default;
		P.IntStat = P.IntStat.default;
		return;
	}
	P.StrStat = (P.StrFocus*GlobalLevel)+P.StrStat.default;
	P.DexStat = (P.DexFocus*GlobalLevel)+P.DexStat.default;
	P.IntStat = (P.IntFocus*GlobalLevel)+P.IntStat.default;
}

Code: Select all

final function RegisterStats(RPG_Puppet P, int i)
{
	if (P != none) {
		PartyInfo[i].PMemberName = P.PMemberName;
		PartyInfo[i].Class1 = P.Class1;
		PartyInfo[i].Class2 = P.Class2;
		PartyInfo[i].StrStat = P.StrStat;
		PartyInfo[i].DexStat = P.DexStat;
		PartyInfo[i].IntStat = P.IntStat;
		PartyInfo[i].StrFocus = StrFocus;
		PartyInfo[i].DexFocus = DexFocus;
		PartyInfo[i].IntFocus = IntFocus;
	}
}

Code: Select all

final function int GetByActor(RPG_Puppet P)
{
    local int i;

    for ( i=Array_Size(PartyInfo)-1 ; i>=0 ; i-- )
        if ( PartyInfo[i].PMember == P ^^ PartyInfo[i].PMember == none)
            return i;
    return -1;
}
> Here are functions related to applying the variables from the first spoiler to modify relevant variables attached to a Puppet.
AdjustGlobalLevel(): Adds a level-up amount to the current GlobalLevel. If greater than max level, return original value before function call.
ModifyHealth(): Modifies a Puppet's MaxHealth based on their Strength Stat.
Spoiler

Code: Select all

function int AdjustGlobalLevel(int Level, int MaxLevel)
{
	local int i;
	i = Level+LevelUpTotal;
	
	if ( i <= MaxLevel ) {return i;}
	else if ( i > MaxLevel ^^ i <= 0) {return Level;}
}

Code: Select all

function ModifyHealth()
{
	if (Str>0) {HealthMax = default.Health + (Str);}
	else {HealthMax = default.Health;}
}
> Class1, Class2 are values between 0-10. This is used to determine a list of abilities a player can used when they call fire() from a custom weapon. Each class value allows for 5 more abilities, 0 allowing none. Abilities will amount to playing a different sprite animation and spawning a different projectile or actor. No code is written for this, but this code should also modify a Puppet's STR/DEX/INTfocus variables, adding 1 when relevant. This is what I've been thinking of potentially using:
Spoiler

Code: Select all

function ClassCheck() {
	local RPG_Puppet.P;
	if (RPG_Puppet(Owner) != none) P=RPG_Puppet(Owner);
	else return;

	If (P.Class1==0 && P.Class 2==0) {
		P.StrFocus = 1;
		P.DexFocus = 1;
		P.IntFocus = 1;
		// Should limit values that can be passed to Fire()
		// Cannot pass in anything other than Fire(0)
		// The value assigned to Fire() will be set through a HUD-menu
		//	system, which will set a variable in a key function and pass
		//	it to Fire()
		//	exec function HotkeyOne(int i)
		//	i = 1;
		//	fire(i);
	}
	Else If (P.Class1==1 ^^ P.Class 2==1) {
		P.StrFocus += 1;
		P.DexFocus += 1;
		P.IntFocus = 1;
		// Allow values between 1-5 to be passed into Fire()
		// Fire(1-5)
	}
	[...]
	Else If (P.Class1=10 ^^ P.Class2==10)
		// Same as above
		// Fire(45-50)
	}
}
> Defaults
Spoiler

Code: Select all

defaultproperties
{
	Health=15
	MaxHealth=15
	Class1=1
	Class2=0
	StrStat=15
	DexStat=15
	IntStat=15
	StrFocus=1
	DexFocus=1
	IntFocus=1
	GlobalLevel=0
	MaxLevel=10
}
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Build variable array: Mutator or Rep. Info?

Post by Feralidragon »

I assume you didn't compile any of that yet? Asking because you have some syntax errors there, but it gives a rough idea on how you want to implement things, so I guess you mostly wanted to show the general idea first to then get a direction, right? :)
Furthermore I also assume this is exclusively to Unreal, given that you're using a dynamic array there and UT99 doesn't support those (unless you use Higor's XC_Engine, which implements them I believe).

OK, so... answering the original question at hand, I mentioned SOLID and the first principle I wrote about (SRP) addresses exactly this.

Considering that structs are pretty much classes with only properties and no methods, an array of structs makes sense, although it's generally preferable to have objects so you can shift the responsibility and control in maintaining and updating the properties to methods of that object, but structs are fine too here.

Having that said, the question is where to store all of these, and you ask whether it should go to a PRI or a mutator essentially, and SRP's answer to that is: neither.

A PRI is a class only meant to replicate player-only properties to every client which would otherwise be only kept for the client owner or the server, and it should be kept at that.
Extensions to that class to that data should only include further informational data, but nothing in the nature of controlling anything, because that's not the job of that class.

While a mutator is only meant to "mutate" the game in some given way, either that means weapons giving more damage, replacing weapons, show extra stuff in the HUD, changing the level in some way, and so on. It also serves as an entry class to define sub-gametypes of sorts, where the main gametype may still be a CTF but then the overall gametype is defined by the mutator itself (Strangelove, Instagib, etc).
In other words, is not meant for a controller of puppets and such, at most it should only be used to bootstrap them.

Therefore, what you probably really want is a completely new separate type of class instead: a manager.
In other words, I believe you should create a brand new class, extending from Actor, and put all the structs and methods handling those there.
Then you just spawn this manager, and use it.
The role of a mutator here would be at most spawning this manager and do the necessary initialization steps for other actors to use it, but nothing more beyond that, while the PRI could just show some extra data such as those stats alone for the player, never per puppet.
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Build variable array: Mutator or Rep. Info?

Post by ANUBITEK »

Absolutely, I just grabbed code and cut it up until it could be used to explain what I was doing. None of what I've written thus far seems like too much, does it?
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Build variable array: Mutator or Rep. Info?

Post by Feralidragon »

Other than what I have mentioned above, the rest seems fine to me.
Post Reply