Jump to content
Sign in to follow this  
gagi2

mapstuff serverside

Recommended Posts

hi&hello...

 

we have a multiplayer mission server (koth) with 9 different locations atm

that means we have 9 missionfiles with all the different mapstuff (spawnpoints, objectives, markers, extra buildings etc)

 

everytime we make some changes we need to do it in all of these 9 mission files

which can be very frustrating sometimes...

 

so i thought about to put all this stuff into a serverside sqf file... one file for each location...

so we only need one missionfile... and 9 locationfiles

 

is this possible to achieve?

because with all these sqm-to-sqf porting stuff or the m3e-eden editor which exports all this stuff there are no object names for example

which we need for the weapon and vehicle traders at least

or markers and other stuff...

 

so if anyone has an idea how i can get this done.. please let me know...

Share this post


Link to post
Share on other sites

There's quite endless methods of doing what you want really.    First thing you'd want to look at is repeated code. What do you have in multiple locations that is basically the same thing?  If you've got 9 files all with this:

//File 1:
_object = "myCarClass" createVehicle getMarkerPos "marker1";

//File 2:
_object = "myCarClass" createVehicle getMarkerPos "marker2";

//File 3:
_object = "myOtherCarClass" createVehicle getMarkerPos "marker3";

You can combine all of those into a single function you just feed different input to:

//Function: _objectSpawned = ["myCarClass", "myMarker1"] call gagi_fnc_spawnObjectAtMarker;
gagi_fnc_spawnObjectAtMarker = {
	params ["_className", "_markerName"];
	_object = _className createVehicle getMarkerPos _markerName;
	_object
};

Then you have a single function which can spawn any class object at any marker instead of nine copies of the same code.

 

So maybe take a look at Functions and see if they can help you condense down your code somewhat.

Share this post


Link to post
Share on other sites

i have no repeating code in this 9 missionfiles when it comes to the locations...

every location has 3 different bases and a different objective etc

so the items/stuff is the same... but on different coords on every file

 

 

but what concerns me are the spawnpoints which are playable characters set on the map...

which are listed as slots in the lobby if done by mission.sqm

 

 

but how does this work within a serverside sqf if it works at all... because afaik the sqf isnt loaded when you join the lobby after the server has started?

 

 

my goal was to put all the stuff in the serverside files...

and then load one of these 9 files random (or maybe by selecting through a database or something... which could also give us an option to vote for the next location etc...)

Share this post


Link to post
Share on other sites

i have no repeating code in this 9 missionfiles ... so the items/stuff is the same... but on different coords on every file

 

That sure sounds like a ton of repeated code. :)  No idea what you mean by lobby based spawnpoints, and voting on things is a bit beyond the scope of this demo, but here's a mission showing how to do random mission using the Functions Library to minimize repeated code as much as possible.  You can download the demo mission to follow along.

 

This mission example is pretty basic so lends itself to functions.  In each mission we'll have a marker, a vehicle and a task involving that vehicle.  We'll either steal, destroy or paint the vehicle.  Since each mission has basically everything the same we're able to have a single function handle multiple missions.  

 

We'll start by declaring some basics in the init.sqf.  Here we'll create a variable to keep track of when the missions are in progress, an array of mission options and a trigger to end the mission when we're complete.  Here's that file:

 

init.sqf:

// Set variable to mark when missions are in progress.
missionNamespace setVariable ["gagi_missionInProgress", false, true];

// Array of possible missions, objects, marker name and task details
availableMissions = [
		["steal", "C_Offroad_01_F", "markerStealCar", "Steal the car in town, bring it back here!"],
		["destroy", "C_Offroad_01_repair_F", "markerDestroyCar", "Destroy the car on the road!"],
		["paint", "C_SUV_01_F", "markerPaintCar", "Paint the car in the woods!"]
	];

// End mission trigger to end the mission when out of missions and none in progress.
_endTrigger = createTrigger ["EmptyDetector", [0,0,0]];
_endTrigger setTriggerStatements ["((count availableMissions) < 1) && !(missionNameSpace getVariable 'gagi_missionInProgress')", "['end1'] call BIS_fnc_endMission", ""];	

The real processing will come within our functions.  The next step is to declare the functions.  We'll use the folder method for this example.  That means we'll have a functions folder in our mission and inside that folder will be individual files for each function we need - four in all this time.  These function files will be called fn_functionName.sqf.  The name is important, it must be fn_<nameoffunction>.sqf.  We'll declare our functions in the mission config file.

 

description.ext:

class CfgFunctions
{
	class gagi // Functions tag.  Functions will be called as [] call gagi_fnc_chooseMission
	{
		class functions
		{
			file = "functions"; // Folder where individual function files are stored.
			class chooseMission {};  // File name is functions\fn_chooseMission.sqf
			class spawnObjectAtMarker {};
			class startMission {};
			class missionCleanUp {};
		};
	};
};

So the first class will declare the "tag" we'll use.  The function we created under the file fn_chooseMission.sqf will be called by gagi_fnc_chooseMission based on the tag and the filename.

 

Next up we'll declare our functions, each in their own file.  gagi_fnc_chooseMission function will be our starting point.  It'll check if missions are in progress or no longer available.  If missions are available it will pick a random mission, remove it from the pool of available missions and start the mission.

 

fn_choosemission.sqf:

/*
	Author: kylania

	Description:
	Selects random mission from availableMissions, removes it from the array, starts mission.

	Parameter(s):
	NONE
		
	Returns:
	BOOLEAN - returns true on completion.
	
	Example:
	this addAction ["Request Mission", {[] call gagi_fnc_chooseMission}];
*/
// If a mission is in progress, exit with message.
if (missionNameSpace getVariable "gagi_missionInProgress") exitWith {systemChat "Mission still in progress!"};

// If there are no more missions available, exit with message.
if ((count availableMissions) < 1) exitWith {systemChat "No more missions!"};

// Select random mission from global availableMissions array.
private _currentMissionParams = selectRandom availableMissions;

// Remove the selected mission from the array.
{
	if (_x isEqualTo _currentMissionParams) exitWith 
	{
		availableMissions deleteAt _forEachIndex;
	};
} 
forEach availableMissions;

// Start selected mission.
_currentMission = _currentMissionParams call gagi_fnc_startMission;

The next function is a quick one simply to spawn an object at a marker.

 

fn_spawnObjectAtMarker.sqf:

/*
	Author: kylania

	Description:
	Spawns an object on a marker.

	Parameter(s):
	0: STRING - Classname of the object to spawn.
	1: STRING - Marker name to spawn the object on.
	
	
	Returns:
	OBJECT - returns the spawned object.
	
	Example:
	_objectSpawned = [_className, _markerName] call gagi_fnc_spawnObjectAtMarker;
	_objectSpawned = ["C_Offroad_01_F", "markerStealCar"] call gagi_fnc_spawnObjectAtMarker;
*/
params ["_className", "_markerName"];

// Spawn object on marker.
_object = _className createVehicle getMarkerPos _markerName;

// Name object gagi_missionTarget
missionNamespace setVariable ["gagi_missionTarget",_object, true];

// Return object
_object

The next function is the big one.  This is the function that creates the missions and any special rules we want for each mission, such as triggers to detect when they are complete or addActions to help paint the car for example.

 

fn_startMission.sqf:

/*
	Author: kylania

	Description:
	Starts a mission by spawning a custom object, creating a task, performs and custom code for mission and starts clean up function.

	Parameter(s):
	0: STRING - Misson type, used as taskID.
	1: STRING - Classname of object to spawn.
	2: STRING - Marker name of object spawn location.
	3: STRING - Task description for mission.
	4: ARRAY - empty array for use with trigger statements
	
	Returns:
	BOOLEAN - true upon completion.
	
	Example:
	_currentMission = _currentMissionParams call gagi_fnc_startMission;
	_currentMission = ["steal", "C_Offroad_01_F", "markerStealCar", "Steal the car in town, bring it back here!"] call gagi_fnc_startMission;
*/
params["_type", "_className", "_markerName", "_description", ["_trigger",[]]];

// Mark mission in progress.	
missionNamespace setVariable ["gagi_missionInProgress", true, true];

// Spawn selected object at marker.
_objectSpawned = [_className, _markerName] call gagi_fnc_spawnObjectAtMarker;
	
// Trim first three words from description for task title.	
_sDesc = _description splitString " ";
_sDesc resize 3;
_title = format["%1", _sDesc joinString " "];
	
// Create task
[
	west,
	[_type],
	[_description,_title,_markerName],
	getMarkerPos _markerName,
	true,
	1,
	true
] call BIS_fnc_taskCreate;

// Custom code for each mission.
switch (_type) do {
	// For the steal task we create a marker to return the car to and delete it within the onAct of the trigger statement.
	case "steal": {
		_marker = createMarker ["gagi_extractMarker", getPos player];
		_marker setMarkerShape "RECTANGLE";
		_marker setMarkerSize [10,10];
	
		// Mission is complete when the vehicle is within the return area marker.
		_trigger = ["position gagi_missionTarget inArea 'gagi_extractMarker'", "deleteMarker 'gagi_extractMarker'", ""];
		
	};
	// For the destroy mission we just test for the vehicle to be destroyed.
	case "destroy": {
		_trigger = ["!(alive gagi_missionTarget)", "", ""];
		};
	// For the paint mission we create an addAction on the vehicle which will "paint" the car for us and remove the option upon painting.
	case "paint": {
		//"#(argb,8,8,3)color(0,0,0,0.6)"
		[
			_objectSpawned, 
			[
				"Paint this car!", 
				{
					[
						_this select 0, 
						[0,"#(argb,8,8,3)color(0,0,0,0.6)"]
					] remoteExec ["setObjectTexture", 0, true];
					[
						_this select 0,
						_this select 2
					] remoteExec ["removeAction", 0, true]; 
				}
			]
		] remoteExec ["addAction", 0, true];

		// The trigger looks for the car to be painted.
		_trigger = ["((getObjectTextures gagi_missionTarget) select 0) == '#(argb,8,8,3)color(0,0,0,0.6)'", "", ""];

	};
	default {};
};
	
// Start mission cleanup based on marker, task and trigger statements.
[_markerName, _type, _trigger] call gagi_fnc_missionCleanUp;
true

The final function is called at the end of gagi_fnc_startMission and creates a trigger to detect when each mission is finished and cleans up after the mission succeeds.

 

fn_missionCleanUp.sqf:

/*
	Author: kylania

	Description:
	Cleans up mission by creating a custom condition trigger, succeeds task and deletes mission object and marker.  Marks mission as no longer in progress.

	Parameter(s):
	0: STRING - Marker name of task location.
	1: STRING - Task name to succeed.
	2: ARRAY - Custom triggerStatements

	Returns:
	BOOLEAN - true upon completion.
	
	Example:
	[_markerName, _type, _trigger] call gagi_fnc_missionCleanUp;
	["markerStealCar", "steal", ["position gagi_missionTarget inArea 'gagi_extractMarker'", "deleteMarker 'gagi_extractMarker'", ""]] call gagi_fnc_missionCleanUp;
*/
params["_markerName", "_task", "_triggerCondition"];

_trigger = createTrigger ["EmptyDetector", [0,0,0]];
_trigger setTriggerStatements _triggerCondition;
		
waitUntil {triggerActivated _trigger};
	
[_task, "SUCCEEDED", true] spawn BIS_fnc_taskSetState;
sleep 4;
deleteVehicle gagi_missionTarget;
deleteMarker _markerName;
	
missionNamespace setVariable ["gagi_missionInProgress", false, true];
true

Hopefully you can see how you might take all the common aspects of your mission and turn them into functions to reduce redundant code.

Share this post


Link to post
Share on other sites

No idea what you mean by lobby based spawnpoints,

 

normally you put playable characters on the map (mission.sqm)

when you connect to the server they are listed as roles/playerslots

 

im not sure this works when i try this serverside...

 

in my scenarios everything changes from file to file...

spawnpoints etc too

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  

×