Build variable array: Mutator or Rep. Info?
-
- Adept
- Posts: 261
- Joined: Sun Dec 28, 2014 1:10 am
- Location: Anubitek
Build variable array: Mutator or Rep. Info?
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.
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.
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
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
-
- Godlike
- Posts: 5486
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Build variable array: Mutator or Rep. Info?
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.
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.
-
- Godlike
- Posts: 2644
- Joined: Fri Sep 25, 2015 9:01 pm
- Location: moved without proper hashing
Re: Build variable array: Mutator or Rep. Info?
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.
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
-
- Godlike
- Posts: 6313
- Joined: Sun May 09, 2010 6:15 pm
- Location: On the roof.
Re: Build variable array: Mutator or Rep. Info?
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...
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...
-
- Godlike
- Posts: 5486
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Build variable array: Mutator or Rep. Info?
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.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...
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.
-
- Godlike
- Posts: 6313
- Joined: Sun May 09, 2010 6:15 pm
- Location: On the roof.
Re: Build variable array: Mutator or Rep. Info?
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.
-
- Godlike
- Posts: 5486
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Build variable array: Mutator or Rep. Info?
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.
It's only an introduction and the first principle for now. Once I manage some time, maybe tomorrow, I will write about another one.
-
- Adept
- Posts: 261
- Joined: Sun Dec 28, 2014 1:10 am
- Location: Anubitek
Re: Build variable array: Mutator or Rep. Info?
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).
> 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:
> 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.
> 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.
> 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:
> Defaults
> 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;
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;
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;
}
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;}
}
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)
}
}
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
}
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
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
-
- Godlike
- Posts: 5486
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Build variable array: Mutator or Rep. Info?
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.

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.
-
- Adept
- Posts: 261
- Joined: Sun Dec 28, 2014 1:10 am
- Location: Anubitek
Re: Build variable array: Mutator or Rep. Info?
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?
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
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
-
- Godlike
- Posts: 5486
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Build variable array: Mutator or Rep. Info?
Other than what I have mentioned above, the rest seems fine to me.