Jump to content
Sign in to follow this  
dreadedentity

Having trouble understanding publicVariableClient/Server and addPublicVariableEventHa

Recommended Posts

Hello all,

I'm trying to create a mission kind of like a "Life" server. I want everything to be persistent, however, so database interactions are necessary. But the database will be stored on the server machine so I need a way to broadcast the variables across the network. Fortunately, a solution for this already exists in arma. Unfortunately, I don't understand how it works at all. Basically, when a player joins my game, the server should retrieve his stats, then the server will publicVariableClient to the client that just connected and sync his stats (if they exist). My problem is that I'm getting an undefined variable error in the little script I wrote. Here's what I've got so far:

init.sqf

"stats" addPublicVariableEventHandler
{
money = _this select 1;
};

if (isDedicated) then
{
call compile preProcessFile "\inidbi\init.sqf"; //using @iniDB for read/write
["connect", "onPlayerConnected", {
	missionNamespace setVariable ["stats", ["PLAYERINFO", _uid, "MONEY", "STRING"] call iniDB_read];
	_id publicVariableClient "stats";
}] call BIS_fnc_addStackedEventHandler;
};

if (!isServer) then
{
sleep 2;
hintSilent format["%1", money];
};

Like I said above, the error I'm getting is "Undefined variable in expression: money". So I guess I'm having trouble getting the variable saved on the client machine. Can anybody help me shed some light on this?

Share this post


Link to post
Share on other sites

I'm not sure if I understand you logic correctly. Please correct me if I'm wrong. So the PVEH for "stats" should be clientside, just as the "if(!isServer)" statement, right? And the code in between is serverside? So, right away, I could tell you this:

Firstly, telling from your stats array, it should be "money = _this select 2;".

Secondly, you should place your hintSilent statement behind a while loop:

while {isNil "money"} do
{
 sleep 1;
};

hintSilent format ["%1", money];

I'm not sure though about this "missionNamespace setVariable" thing as I don't know if that's necessary when using "publicVariable" commands, but I think it isn't.

Anyway, try that and please let us know the result.

Regards,

waltenberg aka Johnny

Edited by waltenberg

Share this post


Link to post
Share on other sites

Well the database part is irrelevant, I'm just trying to understand how to pass a variable from server to client. That's not an array, it's just a variable. iniDB_read takes 4 parameters and returns one.

I could replace that line with:

stats = ["PLAYERINFO", _uid, "MONEY", "STRING"] call iniDB_read]; 

and it does the same thing.

To explain a little more about how iniDB handles things, the first parameter is the filename. So if I opened up PLAYERINFO.ini, it would look like this:

["MYPLAYERID"] //second argument
MONEY="3000" //third argument //fourth argument is variable type you want to return

I have every reason to believe I've coded the database interaction correctly, I'm just not sure how to use publicVariable.

Share this post


Link to post
Share on other sites

publicVariableClient requires the owner id of the player object so it knows who to send the data to, you can get it by doing: (owner playerobject). On your own client that would simply be (owner player). On the server you either have to find the desired player object by scripts or have the client send somekind of loadrequest that contains the clients player object, or you could use the mission.sqm defined name for the player slot the player is occupying.

publicvariable broadcasts a variable and it's value across the network, a defined publicvariableeventhandler for that variable is triggered across all clients (and server), but not on the client/server that broadcasted it.

So essentially publicvariable sends variable to everyone, publicvariableclient sends variable from server to a specific client, publicvariableserver sends variable from client to server only.

Share this post


Link to post
Share on other sites

Is this just a typo in your post? "\inidbi\init.sqf" should be "\inidb\init.sqf"

Where are you testing this? At the moment you have it set for dedicated usage only.

I prefer to do this the other way round. As in the player once he is initialized asks for his stats, just saves any timing issues with initialization, if the player is asking for his stats then he is definitely going to be initialized.

//isServer so will also work for hosted server
if (isServer) then {

//Init iniDB
call compile preprocessFile "\inidb\init.sqf";

//server function for sending stats to client
fnc_getStats = {
	_who = objectFromNetId (_this select 0);
	_uid = _this select 1
	stats = ["PLAYERINFO", _uid, "MONEY", "STRING"] call iniDB_read;
	(owner _who) publicVariableClient "stats";
};

};

//client - including hosted client
if (!isDedicated) then {

//waituntil the player exists
waitUntil {!isNull player};

//set up a PVEH for retrieving stats
"stats" addPublicVariableEventHandler {
	money = _this select 1;
	hintSilent money;
};

//Ask server for stats
[ [netId player, getPlayerUID player], "fnc_getStats", false] call BIS_fnc_MP;

};

untested code just for examples sake, although i have used iniDB set up this way.

The netID stuff is not really needed but atleast i know i am sending a reference to a unique object and is not going to be interpreted wrong.

I realize your end goal is a dedicated with iniDB but for testing purposes having Hosted available could save some hassle.

Share this post


Link to post
Share on other sites

Larrow I think iniDB updated and changed the @modname, confirming @inidbi in my computer.

It was a long road with many problems, but I was somehow able to use my second pc to run the dedi from, that's my test enviornment.

I came to a similar conclusion as you, and made the client ask the server for his info, so the server will get the client's session ID (there really needs to be a better way to do this btw). Rewrote my init.sqf to look like this

"stats" addPublicVariableEventHandler
{
money = _this select 1;
};

if (isDedicated) then
{
call compile preProcessFile "\inidbi\init.sqf";

"PV_ClientID" addPublicVariableEventHandler
{
	stats = ["PLAYERINFO", _uid, "MONEY", "STRING"] call iniDB_read;
	(_this select 1) publicVariableClient "stats";
};


//	["connect", "onPlayerConnected", {
//		missionNamespace setVariable ["stats", ["PLAYERINFO", _uid, "MONEY", "STRING"] call iniDB_read];
//		_id publicVariableClient "stats";
//	}] call BIS_fnc_addStackedEventHandler;
};
if (!isServer) then
{
PV_ClientID = owner player;
publicVariableServer "PV_ClientID";
sleep 5;
hintSilent format ["%1", money];
};

It's pretty messy and I'm still getting the "Undefined variable in expression: money" script error. I'll look over your code, but the secret to publicVariable is just eluding me for some reason.

Share this post


Link to post
Share on other sites

Thats not going to work DE.

Several problems:-

You never send a UID, _uid in the server PVEH is undefined.

owner player on a client will be a crap result 0, owner only works from the server.

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  

×