Jump to content
m1ndgames

Creating 3D Markers for Multiplayer

Recommended Posts

Hi,

this script works locally (i could create the marker on top of myself before i re-wrote it for online multiplayer), but online nothing is shown.

I thought because i create those markers on the player side initially, i wont have any problems in multiplayer. But i was wrong..

The script gives no error or something, the marker just doesent show up... Hope someone points me in the right direction

from Description.ext

class Params
{
class spotdistance // paramsarray select 3;
{
	title = "Max Range for 3D Player Markers";
	value[] = {250,500,750,1000};
	default = 500;
};
};

class CfgFunctions
{
class WarZones
{
	class Misc_Functions
	{
		class draw3d {
			file = "WarZones_Function_Draw3D.sqf";
		};

	};
};
};

WarZones_Function_Draw3D.sqf

// draw3d Usage
// [] call WarZones_fnc_draw3d;

// Draw3d Loop for allUnits
cfg_spot_distance_team = paramsarray select 3;
{
spot_spotted = _x;
spot_distance = [player, spot_spotted] call BIS_fnc_distance2D;

if (spot_distance < cfg_spot_distance_team) then {
	spot_side_own = side (group player);
	spot_side_spotted = side (group spot_spotted);

	if (spot_side_own == spot_side_spotted) then {

		if (spot_side_own == blufor) then {
			spot_texture_color = [0,0,255,0.4];
		};
		if (spot_side_own == opfor) then {
			spot_texture_color = [255,0,0,0.4];

		} else {
			spot_texture_color = [255,255,255,1.0];
		}

		spot_Pos = getPosATL spot_spotted;
		spot_rank_short = [spot_spotted,"displayNameShort"] call BIS_fnc_rankParams;
		spot_texture = [spot_spotted,"texture"] call BIS_fnc_rankParams;
		spot_string = format["%1 %2", spot_rank_short, name spot_spotted];

		drawIcon3D [
			spot_texture,
			spot_texture_color,
			[spot_Pos select 0,spot_Pos select 1,2.3],
			5,
			5,
			0,
			str spot_string,
			1,
			0.2,
			"PuristaMedium",
			"",
			false
		];
	};
};
} forEach allUnits;

from init.sqf

if (hasInterface) then { // Wait for Server and Player Entities
waitUntil {(getPlayerUID player) != "" && !isNull player && isPlayer player};
_init_client = [] execVM "WarZones_Init_Client.sqf";
waitUntil {isNull _init_client};
};

from WarZones_Init_Client.sqf

// Create Eventhandlers
_handler_mpkilled = player addMPEventHandler ["MPKilled", {Null = _this execVM "WarZones_Handler_MPKilled.sqf";}];
_handler_mphit = player addMPEventHandler ["MPHit", {Null = _this execVM "WarZones_Handler_MPHit.sqf";}];
_handler_respawn = player addEventHandler ["Respawn", {_this exec "WarZones_Handler_MPRespawn.sqf"}];
_handler_draw3d = addMissionEventHandler ["Draw3D",{ [] call WarZones_fnc_draw3d; }];
findDisplay 12 displayCtrl 51 ctrlAddEventHandler ["Draw",{ [] call WarZones_fnc_drawmap; }];

Share this post


Link to post
Share on other sites

Everything looks good at first glance (sadly...) .

My approach to debug such an issue would be to put some systemchats or diag_log at various spots throughout the script chain to see where the messages stop coming in. Use them especially to verify all your condition checks do what you expect them to do.

Makes it much easier to see where things get messed up precisely.

The only thing I find odd is that you use global variables throughout WarZones_function_Draw3d.sqf, but that shouldn't cause it to not work in MP.

Share this post


Link to post
Share on other sites

try using east/west instead of opfor/blufor

there are some unnecessary complexities in your code for development that IMO would be best if used when its functional, and then carefully add complexity one step at at time.

Also your init.sqf looks a little dodgy, hard to say what is running on client or server.

Edited by MDCCLXXVI

Share this post


Link to post
Share on other sites

Thanks for your answers :)

I have only posted the snippets that are used for the markers.

The full init.sqf:

/////////////////////////////////////////////////////////////////////
// Read Mission Parameters and Config Settings
#include "WarZones_Config.hpp"; ["Loading config file"] call WarZones_fnc_debug;

if (isServer) then {
// Create the Sectors
[] call WarZones_fnc_createsectors;
["Sectors created"] call WarZones_fnc_debug;

// Give Tickets to the Teams
["add",blufor,1000] call WarZones_fnc_tickets;
["add",opfor,1000] call WarZones_fnc_tickets;
["add",resistance,250] call WarZones_fnc_tickets;
["Gave tickets to the Teams"] call WarZones_fnc_debug;

// Start Ticket Bleeding for the Player Teams
[[blufor,opfor], 0.5, 3, 5] call BIS_fnc_bleedTickets;
["Ticket Bleeding initialized"] call WarZones_fnc_debug;

// Set Mission Parameters
_param_skill =  ["AISkill",0.6] call BIS_fnc_getParamValue;
{
	_x setSkill _param_skill;
} forEach allUnits;
["AI Skill has been set"] call WarZones_fnc_debug;
};

if (hasInterface) then { // Wait for Server and Player Entities
waitUntil {(getPlayerUID player) != "" && !isNull player && isPlayer player};
_init_client = [] execVM "WarZones_Init_Client.sqf"; ["Loading WarZones_Init_Client.sqf"] call WarZones_fnc_debug;
waitUntil {isNull _init_client};
};

WarZones_Init_Server.sqf

// Load the config file Values
#include WarZones_Config.hpp; ["Loading cfg: WarZones_Config.hpp"] call WarZones_fnc_debug;

// Create Side Centers and Groups
BLUFOR_HQ = createCenter blufor;
BLUFOR_Group = createGroup BLUFOR_HQ;
OPFOR_HQ = createCenter opfor;
OPFOR_Group = createGroup OPFOR_HQ;
INDEPENDENT_HQ = createCenter resistance;
INDEPENDENT_Group = createGroup INDEPENDENT_HQ;
["Created Side Centers and Groups"] call WarZones_fnc_debug;

onPlayerConnected {[_id, _name, _uid] call compile preprocessfilelinenumbers "WarZones_Handler_PlayerConnected.sqf"};

WarZones_Init_Client.sqf

// Create Eventhandlers
_handler_mpkilled = player addMPEventHandler ["MPKilled", {Null = _this execVM "WarZones_Handler_MPKilled.sqf";}]; ["MP Handler Created: MPKilled"] call WarZones_fnc_debug;
_handler_mphit = player addMPEventHandler ["MPHit", {Null = _this execVM "WarZones_Handler_MPHit.sqf";}]; ["MP Handler Created: MPHit"] call WarZones_fnc_debug;
_handler_respawn = player addEventHandler ["Respawn", {_this exec "WarZones_Handler_MPRespawn.sqf"}]; ["Handler Created: Respawn"] call WarZones_fnc_debug;
_handler_draw3d = addMissionEventHandler ["Draw3D",{ [] call WarZones_fnc_draw3d; }]; ["Handler Created: Draw3D"] call WarZones_fnc_debug;
findDisplay 12 displayCtrl 51 ctrlAddEventHandler ["Draw",{ [] call WarZones_fnc_drawmap; }]; ["Handler Created: Draw"] call WarZones_fnc_debug;

// Load Gear
[] call WarZones_fnc_gearcheck;

// Create Diary: Changelog
["about"] call WarZones_fnc_diary;

// Create Diary: Mission Guide
["guide"] call WarZones_fnc_diary;

// Enable 3rd Person View restriction
_view_check = [] execVM "scripts\3rdView.sqf"; ["3rd Person View disabled"] call WarZones_fnc_debug;
waitUntil {isNull _view_check};

The Server Init runs pre-init via Description.ext:

class CfgFunctions
{
class WarZones
{
	class Initialize
	{
		class WarZones_ServerInit
		{
			preInit = 1; // 1 to call the function upon mission start, before objects are initialized. Passed arguments are ["preInit"]
//				postInit = 1; // 1 to call the function upon mission start, after objects are initialized. Passed arguments are ["postInit"]
//				preStart = 1; // 1 to call the function upon game start, before title screen, but after all addons are loaded.
//				recompile = 1; // 1 to recompile the function upon mission start
			file = "WarZones_Init_Server.sqf";
		};
	};
...

I would really like if someone with experience would 'audit' my scripts and teach me best practise...

---------- Post added at 12:41 ---------- Previous post was at 12:31 ----------

there are some unnecessary complexities in your code for development that IMO would be best if used when its functional, and then carefully add complexity one step at at time.

The markers were created in singleplayer and worked, then i adapted for multiplay and now it doesent :(

---------- Post added at 12:51 ---------- Previous post was at 12:41 ----------

The only thing I find odd is that you use global variables throughout WarZones_function_Draw3d.sqf, but that shouldn't cause it to not work in MP.

i had issues with undefined variables, using global fixed this, but i will look into it after markers are actually shown

Edited by m1ndgames

Share this post


Link to post
Share on other sites

Regarding "onplayerconnected": Better get used to use the new StackedEventHandler to avoid potential for mysterious errors. Overall, your code is pretty neat.

Minor thing: I much prefer "waitUntil {scriptDone _view_check};" over "waitUntil {isNull _view_check}; " . It's just clearer to read (as it's unmistakable that you expect a script handle to end), but both approaches do work.

Again, I do not know why your markers don't work. Why don't you do the tests with systemchat etc. to narrow it down? The fact that you are getting "issues with undefined variables" is a clear indicator that something is not going right. It's better to track such issues down right away, before your code turns into a huge mess of barely working scripting. Your fnc_draw3d should not need ANY global variables at all.

Share this post


Link to post
Share on other sites

I checked everything again, my guess is that the functions are not executed remotely. therefore i executed the functions like this:

["","WarZones_fnc_draw3d",true,true ] call BIS_fnc_MP;
["","WarZones_fnc_drawmap",true,true ] call BIS_fnc_MP;

but without success... :(

a point in the right direction would be highly appreciated

Share this post


Link to post
Share on other sites
I mean, if you wanted to you could use the 3d markers script already out

dont mean to like, kill your vibe or anything

Plenty of people like to make their own content so they can learn how to do stuff, as well as having the satisfaction of completing something.

You could probably provide some examples of the scripts your referencing too....

Share this post


Link to post
Share on other sites

Exactly... I use one script snippet to reset the cam, everything else is from me. This Project is ongoing for a while, and i learn sqf with it...

update:

i realized i ran the functions only once, but didnt create a handler remotely, so i wrote this:

if (isNull _handler_draw) then {
_handler_draw ctrlAddEventHandler ["Draw",{ [] call WarZones_fnc_drawmap; }]; ["Handler Created: Draw"] call WarZones_fnc_debug;
};

But i dont get the debug message, neither on client nor server side.

This Init_Server file is executed pre-init via description.ext, but i dont get the called: debug messages either... is it maybe because of the pre-init compilation?

// Load the config file Values
#include WarZones_Config.hpp; ["Loading cfg: WarZones_Config.hpp"] call WarZones_fnc_debug;

// Create Side Centers and Groups
BLUFOR_HQ = createCenter blufor;
BLUFOR_Group = createGroup BLUFOR_HQ;
OPFOR_HQ = createCenter opfor;
OPFOR_Group = createGroup OPFOR_HQ;
INDEPENDENT_HQ = createCenter resistance;
INDEPENDENT_Group = createGroup INDEPENDENT_HQ;
["Created Side Centers and Groups"] call WarZones_fnc_debug;

onPlayerConnected {[_id, _name, _uid] call compile preprocessfilelinenumbers "WarZones_Handler_PlayerConnected.sqf"};

["","WarZones_fnc_draw3d",true,true ] call BIS_fnc_MP; ["Called Draw3D with BIS_fnc_MP"] call WarZones_fnc_debug;
["","WarZones_fnc_drawmap",true,true ] call BIS_fnc_MP; ["Called Drawmap with BIS_fnc_MP"] call WarZones_fnc_debug;

i will now try to call the file and not the function... lets see if that makes a difference...

	["WarZones_Function_Draw3D.sqf","BIS_fnc_execVM",true,true ] call BIS_fnc_MP;
["WarZones_Function_DrawMap.sqf","BIS_fnc_execVM",true,true ] call BIS_fnc_MP;

edit: still nothing. i will call them now from init.sqf in the server launch section...

Edited by m1ndgames

Share this post


Link to post
Share on other sites

I'm pressed for time right now, and I can look a little more closely later, but 1 best practice that I noticed right-off-the-bat: execVM returns a script handle, but I assume you don't care to save the script handle because you're assigning it to the global variable NULL. NULL is not a reserved word in sqf, you are in fact assigning that script handle to a real variable. This could cause undefined behavior, script errors, or difficult-to-debug scripts in the future if you try to use NULL as a test, ie.

if (myVar == NULL) then

There are 2 best practices for saving a script handle you don't care about.

1. simply...not save it. You are not required to actually save any output from the commands

2. Try assigning the script handle to a number. Numbers in sqf are reserved and cannot be re-assigned a different value. Example:

 0 = [] execVM "myScript.sqf";

Method #2 is rather useful when using the 2D editor and running scripts from unit init boxes, where saving the script handle into a variable is required (for some goddamn reason)

Hope that helps for now. I'll look more closely later

Share this post


Link to post
Share on other sites

Thanks! I will look over the code and apply your suggestions

Aaaand... I made progress! :D

VAlWYBj.jpg

the map markers are still not shown, but i have an assumption about the issue, will look into it tomorrow.

the initial error was that the functions were not run remotely. the next issue was that you can not define eventhandlers in scripts that are run pre-init via description.ext.

this is the working code (for 3d markers)

init.sqf

if (isDedicated) then {
["WarZones_Function_Client.sqf","BIS_fnc_execVM",true,true ] call BIS_fnc_MP;
...

WarZones_Function_Client.sqf

_handler_draw3d = addMissionEventHandler ["Draw3D",{ [] call WarZones_fnc_draw3d; }]; ["Handler Created: Draw3D"] call WarZones_fnc_debug;
_handler_drawmap = ((findDisplay 12) displayCtrl 51) ctrlAddEventHandler ["Draw",{ [] call WarZones_fnc_drawmap; }]; ["Handler Created: Draw"] call WarZones_fnc_debug;

and now the handlers are created.

I assume the map markers are not created because the map control is not called correctly

// drawmap Usage
// [] call WarZones_fnc_drawmap;

{
map_draw_spotted = _x;
map_draw_distance = [player, map_draw_spotted] call BIS_fnc_distance2D; // Get Distance from Player to _x

if (map_draw_distance < 10000) then { // Distance < 10000m
	map_draw_side_own = side (group player); // Get own Side

	if (map_draw_side_own == blufor) then { // Paint BLUFOR Blue
		map_draw_color = [0,0,255,1.0];
	};
	if (map_draw_side_own == opfor) then { // Paint OPFOR Red
		map_draw_color = [255,0,0,1.0];

	} else {
		map_draw_color = [255,255,255,1.0]; // Everything else is white
	};

	map_draw_Pos = getPosATL map_draw_spotted; // Get Position
	map_draw_rank_short = [map_draw_spotted,"displayNameShort"] call BIS_fnc_rankParams; // Get Short Rank of _x
	map_draw_string = format["%1 %2", map_draw_rank_short, name map_draw_spotted]; // Build a String of Shortrank + Playername
	disableSerialization; // Needed because of reasons
	((findDisplay 12) displayCtrl 51) drawIcon [ // Find the map ctrl and draw the icon
		'iconMan', // The man!
		map_draw_color, // Team Color
		map_draw_Pos, // Position
		12, // x size
		12, // y size
		getDir player, // Player direction
		map_draw_string, // The Shortname + Playername string
		1, // Shadow
		0.02, // Fontsize
		'TahomaB', // Font
		'right' // Font Align
	];
};
} forEach allUnits; // Do it for all living units

Edited by m1ndgames

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

×