Jump to content
Sign in to follow this  
sorophx

script call in object's init field executed every time a player connects. workaround?

Recommended Posts

sorry for bringing this up again, I do remember reading threads about this issue before but Google fails me.

anyway, there's this problem: I have a script that creates some objects. and it's being called from another object's init field (I can't do it from init.sqf for certain reasons). every time somebody connects to the dedicated server, this script is being run, creating these objects again. and again. and again.

how do I stop it?

I tried placing a precondition inside the script, checking for a true/false variable. but that didn't work (probably a problem with my script's logic). tried using diag_tickTime to cut off the script after a few seconds have passed since mission start. didn't work (still can't figure out how many ticks there are in one second). tried deleting the object with the respective line in its init field after the script finished executing for the first time - this broke the whole script for some reason (locality?)

so does anyone know of a simple solution? if not I'll post the script and explain what I'm trying to do with it, maybe somebody can tell me a better way of doing it :j:

Share this post


Link to post
Share on other sites

Maybe run it from a trigger:

[any faction] [not present] [not repeatable]

Condition: this && isServer

It'll fire once when the mission starts, and that's it.

Share this post


Link to post
Share on other sites

can't, unfortunately. I'd have to create the trigger somehow first with a script, I guess I could create a trigger first via the object's init field, run the script via that trigger's init field and hope the game doesn't create these triggers every time somebody connects...

but first I'll wait and see, maybe someone has a more elegant solution

Share this post


Link to post
Share on other sites
can't, unfortunately. I'd have to create the trigger somehow first with a script...

Ah, I suppose the "call from object init" is significant here. Make sure you are doing a server check in the script itself. Shouldn't be a problem then.

Share this post


Link to post
Share on other sites

if you mean the "isServer" command, then it doesn't do me any good inside the script, objects are being created regardless.

Share this post


Link to post
Share on other sites
if you mean the "isServer" command, then it doesn't do me any good inside the script, objects are being created regardless.

Can you post your code?

Share this post


Link to post
Share on other sites
private [
"_ammo",
"_back",
"_backpacks",
"_crate",
"_crates",
       "_markerstr",
"_module",
"_units",
"_unitsArray",
"_ruckArray",
"_crateArray"
];

_units = _this select 0;
_module = _this select 1;
_ammo = _this select 2;

_module setVariable ["defineUnits", _units, true];
_unitsArray = _module getVariable "defineUnits";

_backpacks = [];
_crates = [];
for "_i" from 1 to (count _unitsArray) do {
       _back = createVehicle ["Misc_Backpackheap_EP1", getPos _module, [], 0, "NONE"];
       _backpacks = _backpacks + [_back];
       if (_ammo == 1) then {
           _crate = createVehicle ["USBasicAmmunitionBox_EP1", getPos _module, [], 0, "NONE"];
           _crates = _crates + [_crate];
       };
};

_module setVariable ["defineRP", _backpacks, true];
_ruckArray = _module getVariable "defineRP";

_module setVariable ["defineCrates", _crates, true];
_crateArray = _module getVariable "defineCrates";

if ((str player) in _unitsArray) then {
null = [[("<t color=""#FF0000"">" + ("Set rally point") + "</t>"), "rally.sqf"]] call CBA_fnc_addPlayerAction;
};

_markerstr = createMarker ["respawn_west", getPos _module];
_markerstr setMarkerShape "Empty";
"respawn_west" setMarkerType "Empty";

null = player addMPEventHandler [
"mprespawn", {
	_this execVM "rally_a.sqf"
}
];

Share this post


Link to post
Share on other sites

(isServer) wouldn't work for me before, but now I tried it again, and it doesn't seem to break anything. I'll test it on a dedi now

edit: nope, doesn't work. script isn't being ran at all if I add "if (isServer)"

Edited by sorophx

Share this post


Link to post
Share on other sites

How about a public variable to check if the script was run once?

if (isNil "myScriptWasRunOnce") then
{
   myScriptWasRunOnce = true;
   publicVariable "myScriptWasRunOnce";

   // Call your sqf-file or execute your code here
};

This approach has the risk of getting into a race condition but it's worth a try :>

Share this post


Link to post
Share on other sites

Well, i don't know what you want to achieve. If you want to execute a script only on the server calling it by the object init, that's the way. If you want to execute the script on the client, you have to change your approach or adding a variable like this (rude way and i don't think it will work 100%):

if (isNil "your_var") then {[] execVM "blablabla.sqf";};

"blablabla.sqf"

your_var = true;
//rest of the script

Share this post


Link to post
Share on other sites
How about a public variable to check if the script was run once?

that was the first thing I tried, and it didn't do anything for me. I will try again, though, just to be sure.

Well, i don't know what you want to achieve. If you want to execute a script only on the server calling it by the object init, that's the way.

no, that's not what I want to do. but I guess that's what I should want to do. you have to forgive me, locality is so confusing, sometimes I'm not sure what's going on and how to fix it.

I'm trying to achieve the following. when the game starts the script creates a number of objects, depending on the parameters passed to the script. that's what it does currently. but on a dedi it creates these objects for every player that connects to the server. so, say, I need 4 objects and 4 players connect, it will create 20 objects instead. first 16 will be unusable copies and the last 4 will be the ones I need. say, now a 5th player connects, it will again create 5 objects, rendering the previous 4 useless and replacing them with these new 4.

I could live with that if only it wouldn't keep spamming the server by creating these objects every time a player connects.

I could only come up with 2 solutions: (a) stop the script from executing so many times or (b) not create these objects for every player. I can't achieve (a) without breaking something in the script, which leads me to believe my whole approach is inherently wrong and I have to rewrite everything, (b) is tricky, like I said "isServer" checks somehow stop the objects from being created, and "!isServer" doesn't do much either.

Share this post


Link to post
Share on other sites

I think you have to change approach.

I don't really get what you want to do but i could suggest this:

I think you need to create 4 objects and then give to the players an action linked to these 4 objects, right?

I hope :p

Then you have to create the objectives on the server with the command isServer, give to these 4 objects a name (use setVehicleVarName).

In the init.sqf then you could give the action to the players using the name you gave to the objectives.

I hope it helps you ;)

Share this post


Link to post
Share on other sites

yeah, the reason why I can't name these objects is because their number is never known. like I said, how many objects are created is dependent on parameters passed to the script. I could maybe try running a loop and concatenating two strings like ("name" + "_i") for every object ...

Share this post


Link to post
Share on other sites

Well, use the publicVariable passing the array ;)

Server:

Array_objs = [obj_1,obj_2];publicVariable "Array_objs";

Client:

{} foreach Array_objs;

Share this post


Link to post
Share on other sites

if ((str player) in _unitsArray) then {
   null = [[("<t color=""#FF0000"">" + ("Set rally point") + "</t>"), "rally.sqf"]] call CBA_fnc_addPlayerAction;
};

You cannot use "player" to reference a unit on a dedicated server. A dedicated server by definition has no player, thus player will always be null.

Share this post


Link to post
Share on other sites
(isServer) wouldn't work for me before, but now I tried it again, and it doesn't seem to break anything. I'll test it on a dedi now

edit: nope, doesn't work. script isn't being ran at all if I add "if (isServer)"

This means you are running script on clients and of course every new client will run your script. You either have to rethink your approach and run it on the server with isServer from init.sqf or check that the objects you are creating don't exist.

Share this post


Link to post
Share on other sites
if ((str player) in _unitsArray) then {
   null = [[("<t color=""#FF0000"">" + ("Set rally point") + "</t>"), "rally.sqf"]] call CBA_fnc_addPlayerAction;
};

You cannot use "player" to reference a unit on a dedicated server. A dedicated server by definition has no player, thus player will always be null.

hmmm, that particular check works fine, I mean it adds the action to needed units without fail and works for JIP players (that's why I probably shouldn't try to stop this script from running every time players connect to the server)

This means you are running script on clients and of course every new client will run your script. You either have to rethink your approach and run it on the server with isServer from init.sqf or check that the objects you are creating don't exist.

not sure what you mean by "check that the objects you are creating don't exist", but I think what I'll try to do is delete all objects that are created for clients, thus leaving only objects created for the server

so, yeah, a different approach is needed, I can see that trying to stop the script from executing is a dead end

Share this post


Link to post
Share on other sites

you can create local object with createvehiclelocal that would be client only. if you use createvehicle, object exists everywhere. so before you run this command again you can check if there object was already created perhaps by other client. you can use proximity check, like if there is a object of this type already at the position. however this is not the best practice. better to run it on the server once.

Share this post


Link to post
Share on other sites

hah, figured out why (isServer) breaks my script. turns out this condition stops variables from being defined. testing on a dedi shows that

if (isServer) then {
myVar = true;
};

returns ANY as myVar's value.

so, while I can use (isServer) in my loops to create objects for the server only, any other variables will be overwritten when a player joins the server. so now I have to find a way to store these objects created for the server in a variable without overwriting that variable...

the fight goes on

Share this post


Link to post
Share on other sites

is there a difference between isDedicated and isServer on a dedicated server? doesn't work, of course. but still curious

How about a public variable to check if the script was run once?

if (isNil "myScriptWasRunOnce") then
{
   myScriptWasRunOnce = true;
   publicVariable "myScriptWasRunOnce";

   // Call your sqf-file or execute your code here
};

This approach has the risk of getting into a race condition but it's worth a try :>

got around to trying this again but this time parsing the results. and oh boy...

on a dedicated server "myScriptWasRunOnce" will return true as soon as the mission starts (before the code is even ran for any players), meaning that the part inside the condition will never be executed. this is so confusing...

hm, makes me wonder if the problem is with local variables not being recognized by the server. it's not

in this code:

if (isNil "myScriptWasRunOnce") then
{
   myScriptWasRunOnce = true;
   publicVariable "myScriptWasRunOnce";
   _array = [];
};

on my machine values are <ANY ANY> for myScriptWasRunOnce and _array before the execution, they are <TRUE []> after the execution; on the dedicated server they are <TRUE ANY> before *and* after the execution.

Edited by sorophx
it's not the local variables...

Share this post


Link to post
Share on other sites

The difference is the client could be also server dedicated is for dedicated server environment, so if (!isDedicated) means it is 100% client in dedicated environment. Pretty useful command.

now with your example I'm confused in the whole structure. could you explain what scripts you run from where and in what order?

Share this post


Link to post
Share on other sites

I only run one script from an object's init field. I pass certain parameters to that script. based on these parameters my script creates a certain number of objects, which are stored in a global array for accessing during the mission.

simplified example: [2] execVM "script.sqf"; <- in the init field will ask the script to create two objects and stick them into an array, which will be stored on this object (via setVariable).

I keep running into trouble with locality, because I can't predict how the script will function on a dedi. originally I didn't bother with checking for server/not server entities, which caused multiple copies of said objects to be created (instead of 2 it would create 2+2n for n connected players).

using (isServer) on the whole script breaks it. so I tried using it only for creating these objects. this created a different problem - my array would still get overwritten (it's defined each time as an empty array, so even though it was created and filled once already, when someone connects it is redefined again as an empty array but doesn't get filled because that only happens for the server).

I tried experimenting with various ways to stop it from happening (how to store my initial array with objects and keep it from being overwritten), running into trouble at every step.

my latest attempt was to use setVariable inside if (isServer) condition, so connecting players wouldn't have any effect on it. and it actually seems to work.

Edited by sorophx

Share this post


Link to post
Share on other sites

ok , where and what is this object you run script from? how is this object initialised?

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×