Jump to content
Sign in to follow this  
daniel-davies

Require help with making script MP-compatible

Recommended Posts

Hello. Bit of a newbie coder here - I'm trying to script a money system for my multiplayer mission whereby the amount of money is SHARED between all players. This means that they have a shared money pool and a transaction would affect all online players. I've got the script working - sort of - in that it will display the correct amount of money to the server host, ie. locally, but I can't seem to make it so that it works completely for all players. JIP players also seem to reset the amount of money the players have accumulated to 0 (the starting value) so if someone could explain to me how to go about fixing my issues that would be extremely appreciated.

Also, I'm really sorry if the scripts below make you want to slam your face into the table - like I said previously, I'm new to SQF scripting.

Here are my scripts:

init.sqf

money = "InitialMoney" call BIS_fnc_getParamValue;
publicVariable "money";

DAN_fnc_initupdateMoney = {
((_this select 0) displayCtrl 1102) ctrlSetText format ["%1", money]
};

DAN_fnc_setMoney = {
_amount = _this select 0; 
money = _amount;
publicVariable "money";

((uiNamespace getVariable "dan_Hud") displayCtrl 1102) ctrlSetText format ["%1", money];
};

DAN_fnc_updateMoney = {
publicVariable "money";

((uiNamespace getVariable "dan_Hud") displayCtrl 1102) ctrlSetText format ["%1", money];
};

DAN_fnc_say2D = {
_source = (_this select 0);
_sound = (_this select 1);

_source say2D _sound;
};

DAN_fnc_addMoney = {
_amount = _this select 0;

if (_amount == nil) then {
_amount = 0
};

money = money + _amount;
publicVariable "money";

((uiNamespace getVariable "dan_Hud") displayCtrl 1102) ctrlSetText format ["%1", money];
//[[player,"cashAdd"],"DAN_fnc_say2D",true] call BIS_fnc_MP;

};

DAN_fnc_removeMoney = {
_amount = _this select 0;

if (_amount == nil) then {
_amount = 0
};

money = money - _amount;
publicVariable "money";

((uiNamespace getVariable "dan_Hud") displayCtrl 1102) ctrlSetText format ["%1", money];
[[player,"cashAdd"],"DAN_fnc_say2D",true] call BIS_fnc_MP;

};

null = [] spawn {

while {true} do {

[[[],"Scripts\callResource.sqf"],"BIS_fnc_execVM",true,true] call BIS_fnc_MP;

[[],"DAN_fnc_updateMoney",true,true] call BIS_fnc_MP;

sleep 30;

};

};

initPlayerLocal.sqf:

/*
@filename: initPlayerLocal.sqf
Author:

Daniel G. Davies

Last modified:

29/05/2015 ArmA 1.32 by DGD

Description:

Client scripts and event handlers.
______________________________________________________*/

//------------------- client executions

[[[],"Scripts\callResource.sqf"],"BIS_fnc_execVM",true,true] call BIS_fnc_MP;

[[],"DAN_fnc_updateMoney",true,true] call BIS_fnc_MP;

callResource.sqf (this is called in the initPlayerLocal.sqf file):

/*
@filename: callResource.sqf
Author:

Daniel G. Davies

Last modified:

29/05/2015 ArmA 1.32 by DGD

Description:

Setup / Initialization for the HUD.
______________________________________________________*/


disableSerialization;

1 cutRsc["dan_Hud", "PLAIN"];

_funds = money;

waitUntil {!isNull (uiNameSpace getVariable "dan_Hud")};
_display = uiNameSpace getVariable "dan_Hud";
_setText = _display displayCtrl 1102;
_setText ctrlSetText (parseText format ["%1",_funds]);

Thanks in advance for any help, it's really appreciated :)

Edited by daniel-davies

Share this post


Link to post
Share on other sites

Bump. If someone could assist me in any way it would be incredibly helpful, I've been here for many hours bashing my head on the table - the solution is eluding me completely :(

Share this post


Link to post
Share on other sites
Hello. Bit of a newbie coder here - I'm trying to script a money system for my multiplayer mission whereby the amount of money is SHARED between all players. This means that they have a shared money pool and a transaction would affect all online players. I've got the script working - sort of - in that it will display the correct amount of money to the server host, ie. locally, but I can't seem to make it so that it works completely for all players. JIP players also seem to reset the amount of money the players have accumulated to 0 (the starting value) so if someone could explain to me how to go about fixing my issues that would be extremely appreciated.

Also, I'm really sorry if the scripts below make you want to slam your face into the table - like I said previously, I'm new to SQF scripting.

Here are my scripts:

init.sqf

money = "InitialMoney" call BIS_fnc_getParamValue;
publicVariable "money";

DAN_fnc_initupdateMoney = {
((_this select 0) displayCtrl 1102) ctrlSetText format ["%1", money]
};

DAN_fnc_setMoney = {
_amount = _this select 0; 
money = _amount;
publicVariable "money";

((uiNamespace getVariable "dan_Hud") displayCtrl 1102) ctrlSetText format ["%1", money];
};

DAN_fnc_updateMoney = {
publicVariable "money";

((uiNamespace getVariable "dan_Hud") displayCtrl 1102) ctrlSetText format ["%1", money];
};

DAN_fnc_say2D = {
_source = (_this select 0);
_sound = (_this select 1);

_source say2D _sound;
};

DAN_fnc_addMoney = {
_amount = _this select 0;

if (_amount == nil) then {
_amount = 0
};

money = money + _amount;
publicVariable "money";

((uiNamespace getVariable "dan_Hud") displayCtrl 1102) ctrlSetText format ["%1", money];
//[[player,"cashAdd"],"DAN_fnc_say2D",true] call BIS_fnc_MP;

};

DAN_fnc_removeMoney = {
_amount = _this select 0;

if (_amount == nil) then {
_amount = 0
};

money = money - _amount;
publicVariable "money";

((uiNamespace getVariable "dan_Hud") displayCtrl 1102) ctrlSetText format ["%1", money];
[[player,"cashAdd"],"DAN_fnc_say2D",true] call BIS_fnc_MP;

};

null = [] spawn {

while {true} do {

[[[],"Scripts\callResource.sqf"],"BIS_fnc_execVM",true,true] call BIS_fnc_MP;

[[],"DAN_fnc_updateMoney",true,true] call BIS_fnc_MP;

sleep 30;

};

};

initPlayerLocal.sqf:

/*
@filename: initPlayerLocal.sqf
Author:

Daniel G. Davies

Last modified:

29/05/2015 ArmA 1.32 by DGD

Description:

Client scripts and event handlers.
______________________________________________________*/

//------------------- client executions

[[[],"Scripts\callResource.sqf"],"BIS_fnc_execVM",true,true] call BIS_fnc_MP;

[[],"DAN_fnc_updateMoney",true,true] call BIS_fnc_MP;

callResource.sqf (this is called in the initPlayerLocal.sqf file):

/*
@filename: callResource.sqf
Author:

Daniel G. Davies

Last modified:

29/05/2015 ArmA 1.32 by DGD

Description:

Setup / Initialization for the HUD.
______________________________________________________*/


disableSerialization;

1 cutRsc["dan_Hud", "PLAIN"];

_funds = money;

waitUntil {!isNull (uiNameSpace getVariable "dan_Hud")};
_display = uiNameSpace getVariable "dan_Hud";
_setText = _display displayCtrl 1102;
_setText ctrlSetText (parseText format ["%1",_funds]);

Thanks in advance for any help, it's really appreciated :)

You need to use publicVariable to update vars across all clients, also JIP players will receive this info once they connect, but you need to put in a check before it sets (i.e check if value is already assigned before assigning default value) the value to zero for them locally, which then inadvertantly gets sent across the network and it resets everybody's value.

by the looks of it your having each client broadcast their new value whenever they do something, which is kinda inefficient but its fine for a starting point, but the only problem lies with the above.

best case scenario have BIS_fnc_MP report things that clients did to server then have server do the money adding then broadcast its new money value out to clients.

Edited by austin_medic

Share this post


Link to post
Share on other sites
Okay, I understand, but I'm not sure where I should go about doing this?

initPlayerLocal.sqf

/*
@filename: initPlayerLocal.sqf
Author:

Daniel G. Davies

Last modified:

29/05/2015 ArmA 1.32 by DGD

Description:

Client scripts and event handlers.
______________________________________________________*/

//------------------- client executions

[b]waitUntil{!isNil "money"};[/b]

[[[],"Scripts\callResource.sqf"],"BIS_fnc_execVM",true,true] call BIS_fnc_MP;

[[],"DAN_fnc_updateMoney",true,true] call BIS_fnc_MP;

try to above, as long as the server defines the money variable (you could try to use initServer.sqf for that), and then sends it out using publicVariable so the clients will be able to move past the waitUntil.

Share this post


Link to post
Share on other sites

When I previously defined the money variable in initServer, when I joined as a player the variable showed as <any> on screen. Am I using public variables in the correct way in the above scripts? I feel like I am calling the HUD to be reset way too many times, and I'm using an infinite loop as well - I feel the code could be a lot better but I don't know how to refine it..

Share this post


Link to post
Share on other sites
When I previously defined the money variable in initServer, when I joined as a player the variable showed as <any> on screen. Am I using public variables in the correct way in the above scripts? I feel like I am calling the HUD to be reset way too many times, and I'm using an infinite loop as well - I feel the code could be a lot better but I don't know how to refine it..

You probably should use a publicVariableEventHandler to make sure clients catch the data that gets sent over.

initPlayerLocal.sqf

"money" addPublicVariableEventHandler {
hint format ["%1 has been updated to: %2",_this select 0,_this select 1];
       money = _this select 1;
};

probably meant to be used with publicVariable even though the page doesn't mention that at all ^^.

also note you need to refire this event handler with publicVariable every time the value changes.

Edited by austin_medic

Share this post


Link to post
Share on other sites

Right I think I see what you mean! So if I wanted to display the current value of the money variable which is defined in the initserver sqf to all clients, then could you please explain how I can achieve this? Right now all I can see I need to change is adding that JIP check and making sure when I change the value of 'money' through my DAN_fnc_addMoney function then it is updated to all clients, which at the moment is not the case.

Share this post


Link to post
Share on other sites
Right I think I see what you mean! So if I wanted to display the current value of the money variable which is defined in the initserver sqf to all clients, then could you please explain how I can achieve this? Right now all I can see I need to change is adding that JIP check and making sure when I change the value of 'money' through my DAN_fnc_addMoney function then it is updated to all clients, which at the moment is not the case.

send the value across with publicVariable then have the clients catch it with the publicVariableEventHandler I just posted above.

Share this post


Link to post
Share on other sites

This variable should be accessible to clients when they connect:

//initServer.sqf
dan_randomVar = 6; publicVariable "dan_randomVar";

//initPlayerLocal.sqf
waitUntil {(player isKindOf "Man")};
hint str dan_randomVar;  // 6

only require an event handler when you want the receiver to run code when the variable changes. If its just reading a variable, that is possible anywhere with publicVariable.

Also your initPlayerLocal looks a bit dodgy, you're using BIS_fnc_MP in the client init, even using the persistence argument. I would suggest trying to make it work with code like this:

//initPlayerLocal.sqf
[] execVM "Scripts\callResource.sqf";
[] call DAN_fnc_updateMoney;                   // ensure this function in your functions library correctly, so the client will compile it prior to this call.

Regarding your issue with displaying the variable, ensure you have converted the variable to string prior to trying to display a string.

example:

myVar = 7;

hint myVar;

hint str myVar;

^ try both of those in console to see what i mean.

Edited by MDCCLXXVI

Share this post


Link to post
Share on other sites

Actually - I lied... when I go run a server with my money-related script running on the mission, it causes everyone on the server to get 100000 desync (tested with 11 players on two different servers)... I don't know why but it's really affecting perfomance, perhaps it's to do with this loop in init.sqf?

null = [] spawn {

while {true} do {

//[[[],"Scripts\callResource.sqf"],"BIS_fnc_execVM",true,true] call BIS_fnc_MP;

[[],"DAN_fnc_updateMoney",true,true] call BIS_fnc_MP;

sleep 10;

};

};

Could someone help?

Share this post


Link to post
Share on other sites

Init.sqf is called on all connected computers (as they connect), so your code there is executed everywhere.

Are you sure you need it executed everywhere as it looks to me like every connected computer is sending an instruction (DAN_fnc_updateMoney) via BIS_fnc_MP to every other connected computer every 10 seconds.

Also, you have flagged the "persistent" param as true so this will be sending lots of data to the mission logic every 10 secs.

I didn't check out DAN_fnc_updateMoney but this might be why your mission is desyncing.

Share this post


Link to post
Share on other sites

//InitPlayerlocal.sqf

//initPlayerLocal.sqf

//wait until the variable money exists
//this will be set on JIP by the last amount publicvariabled
waitUntil { !isNil "money" };

//create hud on a rsc layer
( "Dan_hud" call BIS_fnc_rscLayer ) cutRsc [ "dan_Hud", "PLAIN" ];

//function to update hud
Dan_fnc_updateHud = {
disableSerialization;
waitUntil {!isNull (uiNameSpace getVariable "dan_Hud")};
_display = uiNamespace getVariable "dan_Hud";
_setText = _display displayCtrl 1102;
_setText ctrlSetText ( str money ) ;
};

//initial call to the hud to show PVed amount on start
call Dan_fnc_updateHud;


//when ever money is PVed by the server update hud
"money" addPublicVariableEventHandler {
call Dan_fnc_updateHud;
};


//Function to say something locally
DAN_fnc_say2D = {

player say2D _this;

};

//InitServer.sqf

//initServer.sqf

//get starting money from params
money = "InitialMoney" call BIS_fnc_getParamValue;
//broadcast to all
publicVariable "money";

//function to add money
DAN_fnc_addMoney = {
_amount = _this select 0;

money = money + _amount;
publicVariable "money";

//Update hud if we are a hosted server
if !( isDedicated ) then {
	call Dan_fnc_updateHud;
};

//Say cash add on all clients
[ "cashAdd", "Dan_fnc_say2D", true ] call BIS_fnc_MP;
};

//Function to remove money
DAN_fnc_removeMoney = {   
_amount = _this select 0; 

//money never goes below 0
money = ( money - _amount ) max 0;  
publicVariable "money";

//Update hud if we are a hosted server
if !( isDedicated ) then {
	call Dan_fnc_updateHud;
};

//Say cash remove on all players
[ "cashRemove", "Dan_fnc_say2D", true ] call BIS_fnc_MP;
};

Server takes care of handling any money transactions (add, remove) and broadcasts the value of money to all clients.

On receiving an update to the money variable all clients will update their huds.

Was not sure what the say2D was about so made the server make all clients say something when ever money changes (add or remove).

To use when ever you want to add or remove money call the functions on the server.

[ [ 100 ], "Dan_fnc_addMoney", false ] call BIS_fnc_MP;

OR

[ [ 100 ], "Dan_fnc_removeMoney", false ] call BIS_fnc_MP;

Untested.

Edited by Larrow
corrected mistake in scripts

Share this post


Link to post
Share on other sites
//InitPlayerlocal.sqf

//initPlayerLocal.sqf

//wait until the variable money exists
//this will be set on JIP by the last amount publicvariabled
waitUntil { !isNil "money" };

//create hud on a rsc layer
( "Dan_hud" call BIS_fnc_rscLayer ) cutRsc [ "dan_Hud", "PLAIN" ];

//function to update hud
Dan_fnc_updateHud = {
disableSerialization;
waitUntil {!isNull (uiNameSpace getVariable "dan_Hud")};
_display = uiNamespace getVariable "dan_Hud";
_setText = _display displayCtrl 1102;
_setText ctrlSetText ( str money ) ;
};

//initial call to the hud to show PVed amount on start
call Dan_fnc_updateHud;


//when ever money is PVed by the server update hud
"money" addPublicVariableEventHandler {
call Dan_fnc_updateHud;
};


//Function to say something locally
DAN_fnc_say2D = {

_source = (_this select 0);
_sound = (_this select 1);

_source say2D _sound;

};

//InitServer.sqf

//initServer.sqf

//get starting money from params
money = "InitialMoney" call BIS_fnc_getParamValue;
//broadcast to all
publicVariable "money";

//function to add money
DAN_fnc_addMoney = {
_amount = _this select 0;

money = money + _amount;
publicVariable "money";

//Update hud if we are a hosted server
if !( isDedicated ) then {
	call Dan_fnc_updateHud;
};

//Say cash add on all clients
[ [player,"cashAdd"], "Dan_fnc_say2D", true ] call BIS_fnc_MP;
};

//Function to remove money
DAN_fnc_removeMoney = {   
_amount = _this select 0; 

//money never goes below 0
money = ( money - _amount ) max 0;  
publicVariable "money";

//Update hud if we are a hosted server
if !( isDedicated ) then {
	call Dan_fnc_updateHud;
};

//Say cash remove on all players
[ [player,"cashRemove"], "Dan_fnc_say2D", true ] call BIS_fnc_MP;
};

Server takes care of handling any money transactions (add, remove) and broadcasts the value of money to all clients.

On receiving an update to the money variable all clients will update their huds.

Was not sure what the say2D was about so made the server make all clients say something when ever money changes (add or remove).

To use when ever you want to add or remove money call the functions on the server.

[ [ 100 ], "Dan_fnc_addMoney", false ] call BIS_fnc_MP;

OR

[ [ 100 ], "Dan_fnc_removeMoney", false ] call BIS_fnc_MP;

Untested.

Thank you so much for your time taken to rewrite my scripts! I'll test them tomorrow hopefully with better results (I need to get things working by then as I am using it in a group mission :p )

Also thanks to everyone else for their input, really appreciate everything, I am learning a lot from what you guys have posted - I've virtually never worked with MP scripting before :)

Share this post


Link to post
Share on other sites

With fresh eyes this morning i have corrected a couple of mistakes in my last post. I was sending player from the server in the calls to say2D. Changes in last post.

Share this post


Link to post
Share on other sites

Okay, so your method of displaying the hud via BIS_fnc_RSClayer caused some problems... it meant that when I added money, the initial value of 0 stayed on the screen, and a 100 for example was added on top of it causing them to overlap. I tried replacing it with the previous way of displaying the hud and am now testing it.

Share this post


Link to post
Share on other sites
so your method of displaying the hud via BIS_fnc_RSClayer caused some problems... it meant that when I added money, the initial value of 0 stayed on the screen, and a 100 for example was added on top of it causing them to overlap.
This means there are two huds showing.

The code i supplied was to replace everything shown in your original post including your callResource.sqf. If you have added that back in or left a call to it, or not cleaned out (deleted) what was in the init.sqf, that is why you are getting two displays. Which ever one gets called last resets the UInamespace variable for the display and is the one that gets updated leaving the other still showing 0.

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  

×