#How to replace SQF CfgFunctions in reforger?

1 messages Β· Page 1 of 1 (latest)

spare field
#

Goal is not to have alternatives but rather to find a replacement for the functionality of CfgFunctions with preInit,... And making it available cross-missions and game world/modes/...

foggy cobalt
#

so a script?

#

with functions inside?

spare field
#

Pretty much
But mostly the entry points of CfgFunctions specialized modes

foggy cobalt
#

I have limited experience modding in arma 3 but from the wiki it looks like a library of functions - you can have your own library (or libraries) of functions and distribute them as a mod to be used as a dependency in other projects

#

however it looks like cfgfunctions is loading them from files (dynamically?), which I don't think is possible in script

spare field
#

The former is correct but not really what is the key point I try to replicate

It is the preInit, preStart, postInit which interests me

foggy cobalt
#

ah I get you, preInit = mission start before initialization, postInit = after initialization, preStart = after load but before mission start?

spare field
#

Want to find replacement for documenting it

foggy cobalt
#

I think that this exact model is not present in the game, instead you'd have to rely on things like having init happen in a component of your game mode, for example

#

or inside your own entity if it is present in the world being loaded

#

additionally, nothing in addons can be executed before the game is loading into a world - mod scripts are compiled at that stage, not before (ie. cannot make a mod that does anything before you join a server/start game)

keen lagoon
spare field
spare field
#

So a very basic sample for postInit/preInit (those two are pretty much just would be the following (using sqf functions to ease the sample, just imagine the functions would be implemented):

private _roads = [] call X39_fnc_getRoads;
{
  if ([] call X39_fnc_iedChance) then {
    [_x] call X39_fnc_createIed;
  };
} forEach _roads;

Or one that probably better explains why adding this to every game mode is a chore:

("X39_HudLayer" call BIS_fnc_rscLayer) cutRsc ["X39Hud", "PLAIN"];
[] spawn {
  while {true} do {
    sleep 1; // Update every second only
    [] call X39_fnc_updateHud;
  };
};

There is even more things in desperate need of proper "how to entry-point" explaination, but for now the most basic once will do (see https://community.bistudio.com/wiki/Event_Scripts for more entry points about sqf mission eg.)

spare field
#

bumping for relevance

keen lagoon
#

ooo my bad, i've gotten busy with the end of the semester. I'll try to get these soon

spare field
#

πŸ˜™

spare field
#

@meager hollow see this πŸ™‚

meager hollow
#

I do not think I really get what you want here

#

can you explain it in a verbose way without SQF samples?

#

Basically explain what, when and how you want to do things in an abstract way at least

#

@spare field

#

There are ways for scripters to introduce similar features that you have in SQF to Enscript, like in here for example

#

Read the thread for context

spare field
#

Willco in 20 Minutes
Basic goal to me is to allow transitioning from sqf to enscript by finding ways to archive the same.
But as said, will write something proper down later

meager hollow
#

So, do you want to find direct replacement even if they are extremely wrong (Like the hacky stuff I did in that linked reply) or be guided through the proper ways of doing them but differently of course?

#

I am fine with both as long as you know the wrong ones are wrong, but tbh these hacky things are nice as they help you understand what can be done as well

#

But i would advise against using those

spare field
#

For starters, the whole thread actually started here: #enfusion_scripting message

Basically, there is 2 questions left in limbo to me right now:

  1. How can i make classes/... recognized by the game without having to add them to every game mode explicitly
  2. How can i make a function run at the start of eg. game mode being loaded (again: without adding it to the game mode explicitly)

For both, a relevant sample of Arma 3 would be eg. https://steamcommunity.com/sharedfiles/filedetails/?id=1638341685

Simply said:
I want to write a biki article on how to transform a modification which applies to the game as a whole (aka: No setup required besides loading the mod) from arma 3 to reforger.

meager hollow
#

I will provide you some samples in a bit with explanations

#

Just a note

#

preStart behavior is just not possible, and if it happens to be through some hack then it should be patched

spare field
#

?

meager hollow
# spare field ?

Hey sorry, I fell sick so I have not got around to do this yet

spare field
#

Sorry, hope you get well soon

spare field
warm flare
#

Essentially, the way you can externally access events of entities and components is through ScriptInvoker getters and then insert your function there.

warm flare
spare field
#

Examples mostly serve the purpose of providing an idea of what might be done for this posting and are not relevant for my long term goals.
First thing to tackle is to provide arma 3 modders (including myself) a way to cope around the new stuff, allowing to have a grounded idea of how to do things when coming from arma 3

warm flare
#

Yeah, lack of documentation makes it difficult to switch, but after some time I have the feeling that I got the hang of it and I miss SQF, CfgFunctions not one bit πŸ˜…

#

So far I mostly add my functionalities by adding components to the game mode. It offers me two entry points: OnPostInit and EOnInit. Sometimes I don't even need these, since the SCR_BaseGameModeComponentClass is really versatile and offers several events I can hook to like when player dies or disconnects and so on.

#

For instance, this component checks whether a player is far away from the initial respawn point and then deletes it:
https://github.com/Kexanone/EscapeGameMode_AR/blob/main/scripts/Game/GameMode/Components/EM_InitialSpawnPointDeleterComponent.c
And another example that doesn't need EOnInit that makes sure there's only one corpse per player:
https://github.com/Kexanone/EscapeGameMode_AR/blob/main/scripts/Game/GameMode/Components/EM_PlayerCorpseComponent.c

GitHub

Escape game mode for Arma Reforger inspired by "Escape from Malden" from Arma 3. - EscapeGameMode_AR/EM_InitialSpawnPointDeleterComponent.c at main Β· Kexanone/EscapeGameMode_AR

GitHub

Escape game mode for Arma Reforger inspired by "Escape from Malden" from Arma 3. - EscapeGameMode_AR/EM_PlayerCorpseComponent.c at main Β· Kexanone/EscapeGameMode_AR

#

So you simply add these components to the game mode entity, configure the attributes and that's it.

spare field
#

Neat
Will check that stuff tomorrow in depth

warm flare
#

Np, feel free to ask if you need more explanations for some parts πŸ˜‰

spare field
#

Those two files are requiring components to be placed if i am seeing this correct
however, i am looking for a way to have something apply to every game mode automatically without having to alter the world itself

warm flare
#

You can apply it to every game mode by overriding the game mode prefab

#

no need to modify the world

#

Oh wait that's the wrong one πŸ˜…

#

You have to mod GameMode_Base.et

#

Then when you place your prefab in the world, you can modify the prefab rather than the instance in the world by changing the object you edit

spare field
#

Given i understood you correctly here, this still requires placement in the world in some way
The goal i have however is to archive the same by just having a mod loaded, no interaction required

warm flare
spare field
#

Will toy around with that on the weekend (hopefully ... work is killing me right now) and probably ask a few more questions πŸ˜„

warm flare
#

The escape game mode was a bad example on hindsight, since I created a new prefab for that, but I got an example for modding a prefab too: https://github.com/Kexanone/SkipNighttime
In this case I override TimeAndWeatherManager.et in order to add my SCR_SkipNighttimeComponent component to it.

GitHub

This Arma Reforger mod automatically skips nighttime. - GitHub - Kexanone/SkipNighttime: This Arma Reforger mod automatically skips nighttime.

#

This was one of my first mods, so it doesn't follow the proper tag convention yet. You should use your own prefix instead of SCR

ornate portal
#

The prefab is placed inside the world (Every world that has a game mode, which is basically every)

So if you mod the prefab by adding a component to it.
The component is also added to all prefabs that inherit from it (other game modes), so now its in all game mode prefabs.

And because every world has some game mode placed, you'll end up with your component in every world

meager hollow
#

@warm flare @spare field You should stop doing a component every time you want to add a script, a component per every time you want to introduce scripted behavior is not optimal and is not the intended usage of components.

If everyone does this then we end up with entities with hundred or more componennts on them, further slowing FindComponent methods and such. Not to mention huge increases of memory usage if used in certain prefabs.

#

Use component when it makes sense and when using modded classes is not an option

#

@spare field In your case, you want to mod a specific class. In this case it is ArmaReforgerScripted

so that you can do the following

modded class ArmaReforgerScripted
{
  override event bool OnGameStart()
  {
    bool returnVal = super.OnGameStart();

    // Your logic equivalent to postInit here!.
    
    return returnVal;
  }
}
#

That will add that logic to that game event from the Game (ArmaReforgerScripted imp) class directly from scripts

#

No need to mess with world editor, no need to create useless components for this case, no messing with entities, etc

#

In this case, you essentially updated the impl of the OnGameStart() of ArmaReforgerScripted so this will be available everywhere as it's now part of the class itself

keen lagoon
#

Thats super clean actually. I can use this approach in a few places

meager hollow
#

I think this is not explained in the BIKI if I recall

#

I will make some tutorials on this

warm flare
#

Thanks for the recommendation. I wasn't aware of the severe impact of components. It's a bummer. I really liked the modular nature they offered.

keen lagoon
#

When does OnGameStart get called, when the game is launched? Or when a world has all entities loaded? Something else?

#

Is this where the gamemode is found and initialized?

warm flare
#

Equivalent to post init would mean when the entity and its components have been initialized

keen lagoon
#

So if you mod this script it mods all entities?

warm flare
#

yes, all entities that are based on this class and classes that inherit from it

keen lagoon
#

Gotcha

spare field
#

In hopes that this yields a way to emplace CfgFunctions, I am happy to try out whatever is available

ornate portal
#

There you got a preInit

#

that's basically all you need from CfgFunctions

warm flare
#

No entity gets modded

#

Tbh. I'm not entirely happy with this approach. I hardly think it can be the idea to put all the nicely grouped features I had in components in one huge modded ArmaReforgerScripted. I also entirely lose the ability to have configurable attributes.

ornate portal
#

You don't need to put it into one huge modded class

#

you can still have many classes, that one there is just the initialization start point

#

You can put configuration into config file if you want a moddable config

warm flare
#

Well, I'll give it a try and we'll see what MarioE has to complain about it again πŸ˜…

spare field
ornate portal
#

You're asking a bad question

#

you say "replace CfgFunctions"
which doesn't really make sense.
There are no functions like that in Enforce Script

#

You meant how to get a init/preInit handler

spare field
#

It does make a lot of sense from the point I try to reason from.

My goal is to provide proper and qualified ways to utilize enscript, replacing sqf.
This means that I do not have any goal but the one which BI should provide in the biki, but does not (yet).

That is where I want to apply my spare time to solve an issue at. However, this includes to naively ask questions in relation to solving problems, from a sqf perspective

#

Plus, the whole thread only attempts to deal with the question to literally replace CfgFunctions

ornate portal
#

Wiki has a guide for sqf to enscript, but it doesn't show eventhandler probably

spare field
#

Because I attempt to go the naive way

warm flare
#

It's a very relevant question you posed, which I tried to solve with components, but that's apparently not a good apporach. So discussing the best practice is very important.

meager hollow
#

@spare field That is not convenient or proper in my opinion, they are two different engines and what was good in RV is not good in enfusion

spare field
meager hollow
#

It's better to do things in enfusion the enfusion way instead of the RV way

#

I would say that it's better to spend the time understanding the new concepts, architecture, etc instead of trying to patch RV's in here

#

OnGameStart here is the same as postInit

spare field
#

The part I try to figure out here is not even a complex part

meager hollow
#

lIke how i am doing with you right now πŸ™‚

#

You should start a new journey for understanding this engine properly

#

trying to do RV to Enfusion will just make you do so many wrong assumptions

spare field
#

In particular, it is about transforming information from A to B

meager hollow
#

If you have questions, then just ask and we will answer

#

Do not worry about taking it upon yourself

#

We are working on improving the information i nwiki

ornate portal
#

Transforming CfgFunctions doesn't really make sense, because nothing of it applies anymore
The transform is rather "forget everything you knew and start from scratch"

meager hollow
#

Provide how tos, tutorials, etc

spare field
meager hollow
#

So that people can get started on enfusion nicely at some point

#

We plan on properly introducing proper concepts and workflows, do not worry about that πŸ™‚

#

Your life would be easier if you just start from scratch here

#

The entry learning curve for enfusion is so much easier than RV

#

So do not worry about it and if you have any questions then just ask in the channels or ask me directly

warm flare
#

I get your point that you shouldn't try to translate SQF to Enscript directly, but on a fundamental level CfgFunctions contains concepts that are in Enfusion too, like how to define and override functions and entry points.

spare field
#

As said, I attempt to be naive on purpose for that

#

Which is why the depth I get into enscript involves "does it work out of the box or not"

#

So I can dive in depth once that question is answered

#

My personal goal is writing a medical mod for the game

#

Prior, it is to write guides

meager hollow
#

So it's misleading to do CfgFunctions to Enfusion enscript

warm flare
#

fair enough

ornate portal
#

The qeustion now is, now that you know that, what is your next question

spare field
#

(obviously provoking)

#

There is a way to Archive the same
If not, that is an issue to be raised

ornate portal
#

What is your definition of "the same"

spare field
#

If there is a way, that is to be revealed here

ornate portal
#

You keep saying CfgFunctions, but CfgFunctions is alot of things.
One thing (init event) you have been shown.

if that is not what you were looking for, what other feature is it?

warm flare
#

You can do everything you did with CfgFunctions in Enfusion too I would argue, except there's no entry point yet when the game starts πŸ˜…

ornate portal
spare field
#

The same, in this case, as told many times in the lifetime of this thread, is an alternative way to archive the same (that is: a way to intercept regardless of placement akin to CfgFunctions preInit and postinit)

ornate portal
#

What, the fuck, is "the same" to you

meager hollow
#

But as modder you have no access to it because of the lock on main menubefore mods are loaded

ornate portal
#

a way to intercept regardless of placement akin to CfgFunctions preInit and postinit
You want a postInit handler that you can put anywhere, instead of having to put it into a specific place.
That doesn't exist. Ok, next question?

spare field
#

As said, I am in a (on purpose) extremely naive position. Because many modders with brief knowledge are in that position

The whole discussion is a philosophical by now btw. Because I did not try the ways offered yet (due to personal time constraints, right now at a local circus eg. But I ain't being paid or anything... So that is pretty much fine from my personal perspective)

Once I did, I will come back with additional questions

The main point of this thread tho, is to solve the features CfgFunctions offers

#

So the naive question is:
How to replace CfgFunctions

#

And yes, this is frustrating... But that is on purpose. Because people coming from sqf are asking those questions

meager hollow
#

Trying to do connections is not healthy for your learning process for this

ornate portal
#

"Question"
"Answer"
"No I refuse, I don't accept that answer"
"Question"

Do you really want to keep repeating that circle, I don't get the reasoning.

People from SQF will ask the same question indeed, but they will accept the answer they've been given

meager hollow
#

as you have seen, you have been stuck on this

#

while new modders are experienced already

#

and other arma modders that did not do this have progressed a lot

spare field
#

That is not how learning goes tho. The relation to arma 3 for functions is CfgFunctions
So I need to offer, for my biki article, alternate ways

meager hollow
#

I know it's hard to get rid of old ways and there is rejection on that but once you get past that, it's just easier and you realize how bad it was before

spare field
#

That is why I am so reluctant on this issue

ornate portal
#

That is exactly how learning works though.
"Hey I used to open that door with this key, but now it doesn't work anymore and I've been given this plastic card"
"You don't use the key anymore, just hold the plastic card up to this box"
"But no, I want to know how to use my key"

That's what you're doing right now

spare field
#

I have no issue to find replacements
Thought of replacing the rulings with nodded xlasses
But want an naive approach to write the proper article

#

As said, I did not try those ways as of now
If you have better ways to replace the features, go ahead.

Otherwise, I will try them and continue asking questions then

ornate portal
#

To write the article.
I would say "CfgFunctions doesn't exist anymore, but there are different ways to do the things that CfgFunctions used to do"

  • Adding a postInit eventhandler is now done like so:
  • X ...
#

Now if you have a specific question about a specific part of CfgFunctions that you want to know the new way to, you can ask that, and people can help you with that.
But you keep "no I want it all" "but that doesn't make sense" "but I want it all" then we won't get far

spare field
#

Feel free to write "transitioning from sqf to enscript" articles yourself tho
Will gladly take those solution over spending my own time for obvious reasons

spare field
ornate portal
#

Ok so we are actually done here then for now.
It seemed as if you didn't get an answer yet and still wanted one

spare field
#

And again, would gladly take any tutorial provided by BI, writing eg. Dui squad radar any point in time over my own

warm flare
#

Let's first experiment with the solutions that were proposed by MarioE and Dedmen before dragging this out over nothing^^

warm flare
#

So with the modding ArmaReforgerScripted approach, what would be the appropriate way to ensure you only execute the code on the server?

#

My first approach would have been to get the RplComponent of the game mode entity and check whether the machine is the authority

#

Nvm, there's Replication.IsServer()

spare field
#

IsServer is another question on its own πŸ€ͺ

warm flare
#

Funny how modded over component almost sounds like the opposite of composition over inheritance

meager hollow
#

and you can break composition with components as well

#

What happens is up to the developer, nothing makes it safe for one or the other

meager hollow
#

but not the game itself

warm flare
#

So I came up with an approach to introduce modular scripts to SCR_BaseGameMode without the need of components:

modded class SCR_BaseGameMode : BaseGameMode
{
    [Attribute("", UIWidgets.Auto, "", category: "Game Mode")]
    protected ref array<ref KEX_GameModeScript> m_KEX_GameModeScripts;
    
    override void EOnInit(IEntity owner)
    {
        super.EOnInit(owner);
        
        foreach (KEX_GameModeScript script : m_KEX_GameModeScripts)
        {
            script.OnInit(this);
        };
    };
};

[BaseContainerProps()]
class KEX_GameModeScript
{
    void OnInit(SCR_BaseGameMode owner) {};
};

[BaseContainerProps()]
class KEX_MySpecificScript : KEX_GameModeScript
{
    [Attribute("0", UIWidgets.EditBox)]
    protected float m_fMyVariable;
    
    override void OnInit(SCR_BaseGameMode owner)
    {
        owner.GetOnPlayerDisconnected().Insert(OnPlayerDisconnected);
        
        // Do stuff
    };
    
    void OnPlayerDisconnected(int playerID)
    {
        // Do stuff
    };
};
meager hollow
#

For example:

#
// mod A
modded class SCR_BaseGameMode
{
    override void EOnInit(IEntity owner)
    {
        super.EOnInit(owner);
        
        Print("Hello!, I have been called because of mod A.");
    };
};

// mod B
modded class SCR_BaseGameMode
{
    override void EOnInit(IEntity owner)
    {
        super.EOnInit(owner);
        
        Print("Hello!, I have been called because of mod B.");
    };
};

// mod C
modded class SCR_BaseGameMode
{
    override void EOnInit(IEntity owner)
    {
        super.EOnInit(owner);
        
        Print("Hello!, I have been called because of mod C.");
    };
};

When SCR_BaseGameMode::EOnInit gets called it would do all of them so you would get this in the script log

Hello!, I have been called because of mod A.
Hello!, I have been called because of mod B.
Hello!, I have been called because of mod C.
#

You can add new things to the class with modded

#

like in this case

#
// mod A
modded class SCR_BaseGameMode
{
    override void EOnInit(IEntity owner)
    {
        super.EOnInit(owner);
        
        Print("Hello!, I have been called because of mod A.");
    };
};

// mod B
modded class SCR_BaseGameMode
{
    override void EOnInit(IEntity owner)
    {
        super.EOnInit(owner);
        
        Print("Hello!, I have been called because of mod B.");
        CustomPrint("Hello!, I have been called because of mod B.");
    };
    
    void CustomPrint(string content)
    {
        Print("CustomPrint: " + content);
    }
};

// mod C
modded class SCR_BaseGameMode
{
    override void EOnInit(IEntity owner)
    {
        super.EOnInit(owner);
        
       CustomPrint("Hello!, I have been called because of mod C.");
    };
};

When SCR_BaseGameMode::EOnInit gets called it would do all of them so you would get this in the script log

Hello!, I have been called because of mod A.
Hello!, I have been called because of mod B.
CustomPrint: Hello!, I have been called because of mod B.
CustomPrint: Hello!, I have been called because of mod C.
#

same for defining new member variables

#

and changing constants or static values

warm flare
#

Thanks, doing it this way is a good approach when a mod has a singular purpose and hard-coding the changes makes sense, like SkipNighttime. However, what about a case where you might not want that? Let's say you have an utility mod that provides a collection of features you can use to build scenarios like an initial spawn deleter, AI stalking players script and so on. Depending on the type of scenario, you might only need some of them. I don't see how what you suggested offers that flexibility, unless I break the utility mod into a bunch of separate mods for every tiny optional feature.

warm flare
#

I see your point that doing components in every case introduces an unnecessary overhead, but isn't it the right tool when I want some optionality and if it isn't what would it be instead?

meager hollow
#

Not everything has to be mashed together in the modded class and you can take away features added by other mods as well

#

It does not work exactly like inheritance

#

idk exactly what you want to create so I can't really give you hints/tips

#

If you explain further what you want (As result, not how you want it to work behind the scenes) then I will happily help to possibly find the best route

#

There is not a single true methodology to make something moddable, it highly depends on your system, feature, etc

#

It's almost the same as making some system scalable, the way to go depends on many things

warm flare
#

So currently I have a bunch of game mode components for the various features for an escape game mode: https://github.com/Kexanone/EscapeGameMode_AR/tree/main/scripts/Game/GameMode/Components
Now I want to create a PvE CTI game mode instead as a new mod. I would like to reuse some of the features I implemented in the escape game mode, for instance, EM_RespawnTimerComponent (Allows modifying respawn timer in mission header) and EM_StalkerComponent (Handles AI that stalk players), but ofc there are some features I don't want in CTI like VictoryBorderComponent (ends game in victory when leaving a polygon area) and EM_SpawnTicketsComponent (introduces global spawn tickets and disables all spawns when no tickets are left).

GitHub

Escape game mode for Arma Reforger inspired by "Escape from Malden" from Arma 3. - EscapeGameMode_AR/scripts/Game/GameMode/Components at main Β· Kexanone/EscapeGameMode_AR

#

So my original plan was to create an utility mod that contains all the components I have and I can add the ones that I need to each game mode.

#

Ofc I'm open to alternative suggestions how to structure my code if components aren't the right choice for what I'm trying to achieve

meager hollow