View Issue Details

IDProjectCategoryView StatusLast Update
0003079FSSCPSEXPspublic2014-08-05 17:17
ReporterParias Assigned Tom_m  
PrioritynormalSeverityfeatureReproducibilityN/A
Status resolvedResolutionfixed 
Product Version3.7.1 
Summary0003079: Add multi-eval to list of available SEXPs (.patch included)
DescriptionI'm working on a co-op campaign where I'm basically using scripts and a bit of creative FRED-ing to emulate command briefings in a multiplayer co-op setting. While reviewing options for doing this, I came across this thread from karajorma:

http://www.hard-light.net/forums/index.php?topic=86422

The concept of having scripts that can execute client-side looked to be EXACTLY what I needed. However, I could find no signs of this ever actually making it's way into the main FSO branch, and from the description (and Karajorma's other helpful tutorial resources - i.e. here: http://diaspora.fs2downloads.com/FREDDocs/multiplayer_walkthrough.html ) it sounds like this is currently Diaspora-only.

Not knowing in the slightest what the heck I was doing but being badly in need of this SEXP for my project to have a chance of moving forward, I figured out how to grab the source code, dusted off my copy of Visual Studio, and had at 'er to see if I could solve my own problem =) It took a bit of alignment work, but I was able to compile my own 3.7.1 build with multi-eval fully operational based on karajorma's code example. It seems stable and works great for all connected clients in my testlab so far. ....So far.

I badly want to avoid having to include my own separate branch of the code just for my campaign to work - is there any chance this could be reviewed for integration into the primary FSO codebase at some point?

I've even taken the liberty of creating a new .patch based on my own work - full credit should still go to Karajorma as my understanding is he did all the original labor in creating this, I've just dusted it off and aligned it for easier merging into the current 3.7.1 code. Hopefully my efforts here make this a comparatively trivial request to implement, but I don't know if there would be additional implications to just arbitrarily throwing this code in.

From thread comments it also sounded like there were some decisions remaining as to if this code was the best way to proceed in lieu of something else. I don't know if this was perhaps put on hold for that reason or if there was some other issue that stopped this from going in, so I'm curious what kind of feedback my request will get.
Additional InformationHere's what I've accomplished so far using a relatively simple script and some creative FRED-ing, only possible thanks to multi-eval:

https://www.youtube.com/watch?v=kuiWgYjnh0M
(This was all taken from a connecting client system)
TagsNo tags attached.

Activities

Parias

2014-07-25 04:31

developer  

multi-eval-3_7_1.patch (6,131 bytes)   
Index: FS2Source-multieval/code/parse/sexp.cpp
===================================================================
--- FS2Source-multieval/code/parse/sexp.cpp	(revision 10927)
+++ FS2Source-multieval/code/parse/sexp.cpp	(working copy)
@@ -681,6 +681,7 @@
 	{ "damaged-escort-priority",		OP_DAMAGED_ESCORT_LIST,					3,	INT_MAX,	SEXP_ACTION_OPERATOR,	},	//phreak
 	{ "damaged-escort-priority-all",	OP_DAMAGED_ESCORT_LIST_ALL,				1,	MAX_COMPLETE_ESCORT_LIST,	SEXP_ACTION_OPERATOR,	},	// Goober5000
 	{ "set-support-ship",				OP_SET_SUPPORT_SHIP,					6,	7,			SEXP_ACTION_OPERATOR,	},	// Goober5000
+	{ "multi-eval",						OP_SCRIPT_EVAL_MULTI,					1,	INT_MAX,	SEXP_ACTION_OPERATOR,   },
 	{ "script-eval",					OP_SCRIPT_EVAL,							1,	INT_MAX,	SEXP_ACTION_OPERATOR,	},
 	{ "debug",							OP_DEBUG,								2,	2,			SEXP_ACTION_OPERATOR,	},	// Karajorma
 	{ "do-nothing",						OP_NOP,									0,	0,			SEXP_ACTION_OPERATOR,	},
@@ -21502,7 +21503,7 @@
 }
 
 //WMC - This is a bit of a hack, however, it's easier than
-//coding in a whole new SCript_system function.
+//coding in a whole new Script_system function.
 int sexp_script_eval(int node, int return_type)
 {
 	int n = node;
@@ -21575,6 +21576,102 @@
 	return -1;
 }
 
+void sexp_script_eval_multi(int node)
+ {
+	char s[TOKEN_LENGTH];
+	bool success = true;
+	int sindex;
+	player *p;
+	
+		strcpy_s(s, CTEXT(node));
+	
+		node = CDR(node);
+	
+		multi_start_callback();
+	multi_send_string(s);
+		// evalutate on all clients
+		if (node == -1) {
+		multi_send_bool(true);
+		success = Script_system.EvalString(s, NULL, NULL, s);
+		
+	}
+		// we have to send to all clients but we need to send a list of ships so that they know if they evaluate or not
+		else {
+		multi_send_bool(false);
+		
+			do {
+			p = get_player_from_ship_node(node, true);
+			
+							// not a player ship so skip it
+				if (p == NULL){
+				node = CDR(node);
+				continue;
+				
+			}
+			else {
+								// if this is me, execute the script
+					if (p == Player) {
+					success = Script_system.EvalString(s, NULL, NULL, s);
+					
+				}
+								// otherwise notify the clients
+					else {
+					sindex = ship_name_lookup(CTEXT(node));
+					multi_send_ship(sindex);
+					
+				}
+				
+			}
+			
+				node = CDR(node);
+			
+		} while (node != -1);
+		
+	}
+	
+		multi_end_callback();
+	
+		if (!success) {
+		Warning(LOCATION, "sexp-script-eval failed to evaluate string \"%s\"; check your syntax", s);
+		
+	}
+}
+
+void multi_sexp_script_eval_multi()
+ {
+	int sindex;
+	char s[TOKEN_LENGTH];
+	bool sent_to_all = false;
+	bool success = true;
+	
+		multi_get_string(s);
+	multi_get_bool(sent_to_all);
+	
+		if (sent_to_all) {
+		success = Script_system.EvalString(s, NULL, NULL, s);
+		
+	}
+		// go through all the ships that were sent and see if any of them match this client.
+		else {
+		while (multi_get_ship(sindex)) {
+			Assertion(sindex >= 0, "Illegal value for the ship index sent in multi_sexp_script_eval_multi()! Ship %d does not exist!", sindex);
+			if (Player->objnum == Ships[sindex].objnum) {
+				success = Script_system.EvalString(s, NULL, NULL, s);
+				
+			}
+			
+		}
+		
+	}
+	
+		if (!success) {
+		Warning(LOCATION, "sexp-script-eval failed to evaluate string \"%s\"; check your syntax", s);
+		
+	}
+	}
+
+
+
 void sexp_force_glide(int node)
 {
 	ship *shipp;
@@ -24263,6 +24360,11 @@
 				sexp_val = sexp_script_eval(node, OPR_NULL);
 				break;
 
+			case OP_SCRIPT_EVAL_MULTI:
+				sexp_script_eval_multi(node);
+				sexp_val = SEXP_TRUE;
+				break;
+
 			case OP_CHANGE_IFF_COLOR:
 				sexp_change_iff_color(node);
 				sexp_val = SEXP_TRUE;
@@ -24694,6 +24796,10 @@
 				multi_sexp_set_ets_values();
 				break;
 
+			case OP_SCRIPT_EVAL_MULTI:
+				multi_sexp_script_eval_multi();
+				break;
+
 			// bad sexp in the packet
 			default: 
 				// probably just a version error where the host supports a SEXP but a client does not
@@ -25296,6 +25402,7 @@
 		case OP_SET_NUM_COUNTERMEASURES:
 		case OP_SCRIPT_EVAL:
 		case OP_SCRIPT_EVAL_STRING:
+		case OP_SCRIPT_EVAL_MULTI:
 		case OP_ENABLE_BUILTIN_MESSAGES:
 		case OP_DISABLE_BUILTIN_MESSAGES:
 		case OP_LOCK_PRIMARY_WEAPON:
@@ -27342,6 +27449,12 @@
 			if (argnum == 1)return OPF_VARIABLE_NAME;
 			else return OPF_STRING;
 
+		case OP_SCRIPT_EVAL_MULTI:
+			if (argnum == 0)
+					return OPF_STRING;
+			else
+					return OPF_SHIP;
+
 		case OP_CHANGE_IFF_COLOR:
 			if ((argnum == 0) || (argnum == 1))
 				return OPF_IFF;
@@ -29119,6 +29232,7 @@
 		case OP_SET_SUPPORT_SHIP:
 		case OP_SCRIPT_EVAL_STRING:
 		case OP_SCRIPT_EVAL:
+		case OP_SCRIPT_EVAL_MULTI:
 			return CHANGE_SUBCATEGORY_OTHER;
 
 		case OP_NUM_SHIPS_IN_BATTLE:
@@ -32739,6 +32853,14 @@
 		"\t1:\tScript to evaluate\r\n"
 	},
 
+	{OP_SCRIPT_EVAL_MULTI, "multi-eval\r\n"
+	 "\tEvaluates script\r\n\r\n"
+	 "Takes at least 1 argument...\r\n"
+	 "\t1:\tScript to evaluate\r\n"
+	 "\t(rest):\tList of players who should evaluate this script. If no player is given, all clients will execute the script\r\n"
+	},
+	
+
 	{OP_FORCE_GLIDE, "force-glide\r\n"
 		"\tForces a given ship into glide mode, provided it is capable of gliding. Note that the player will not be able to leave glide mode on his own,, and that a ship in glide mode cannot warp out or enter autopilot."
 		"Takes 2 Arguments...\r\n"
Index: FS2Source-multieval/code/parse/sexp.h
===================================================================
--- FS2Source-multieval/code/parse/sexp.h	(revision 10927)
+++ FS2Source-multieval/code/parse/sexp.h	(working copy)
@@ -723,6 +723,7 @@
 #define OP_SET_MOTION_DEBRIS				(0x0025 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG)    // The E
 #define OP_HUD_SET_CUSTOM_GAUGE_ACTIVE		(0x0026 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) 	// The E, just revamped a bit by Axem
 #define OP_HUD_SET_RETAIL_GAUGE_ACTIVE		(0x0027 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) 	// The E, just revamped a bit by Axem
+#define OP_SCRIPT_EVAL_MULTI				(0x0028 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG)	// Karajorma
 
 // defined for AI goals
 #define OP_AI_CHASE							(0x0000 | OP_CATEGORY_AI | OP_NONCAMPAIGN_FLAG)
multi-eval-3_7_1.patch (6,131 bytes)   

karajorma

2014-07-28 14:55

administrator   ~0016139

The main reason I haven't committed multi-eval is cause I was planning on working on an even more wide-ranging solution to the issue and I didn't want to have to keep supporting the SEXP once it was obsolete.

That said, I have no objection to adding the SEXP as long as it's with the warning that it is very likely it will be removed one day in favour of my newer system.

If that's fine, I'll ask someone to commit the patch (I'm currently on holiday and have no access to my main dev PC).

Parias

2014-07-29 01:53

developer   ~0016141

That's fine with me. Assuming my little campaign / mod goes public, I'd be OK with updating it down the road to use the newer system when needed.

(Of course, I say that now...)

m_m

2014-08-05 16:36

developer   ~0016173

I have uploaded a new patch that adds a warning that the multi-eval SEXP will possibly be removed from a future version (and I also cleaned up the formatting).

m_m

2014-08-05 16:36

developer  

3079.patch (6,070 bytes)   
Index: code/parse/sexp.cpp
===================================================================
--- code/parse/sexp.cpp	(revision 10969)
+++ code/parse/sexp.cpp	(working copy)
@@ -681,6 +681,7 @@
 	{ "damaged-escort-priority",		OP_DAMAGED_ESCORT_LIST,					3,	INT_MAX,	SEXP_ACTION_OPERATOR,	},	//phreak
 	{ "damaged-escort-priority-all",	OP_DAMAGED_ESCORT_LIST_ALL,				1,	MAX_COMPLETE_ESCORT_LIST,	SEXP_ACTION_OPERATOR,	},	// Goober5000
 	{ "set-support-ship",				OP_SET_SUPPORT_SHIP,					6,	7,			SEXP_ACTION_OPERATOR,	},	// Goober5000
+	{ "multi-eval",						OP_SCRIPT_EVAL_MULTI,					1,	INT_MAX,	SEXP_ACTION_OPERATOR,   },
 	{ "script-eval",					OP_SCRIPT_EVAL,							1,	INT_MAX,	SEXP_ACTION_OPERATOR,	},
 	{ "debug",							OP_DEBUG,								2,	2,			SEXP_ACTION_OPERATOR,	},	// Karajorma
 	{ "do-nothing",						OP_NOP,									0,	0,			SEXP_ACTION_OPERATOR,	},
@@ -21510,7 +21511,7 @@
 }
 
 //WMC - This is a bit of a hack, however, it's easier than
-//coding in a whole new SCript_system function.
+//coding in a whole new Script_system function.
 int sexp_script_eval(int node, int return_type)
 {
 	int n = node;
@@ -21583,6 +21584,90 @@
 	return -1;
 }
 
+void sexp_script_eval_multi(int node)
+ {
+	char s[TOKEN_LENGTH];
+	bool success = true;
+	int sindex;
+	player *p;
+	
+	strcpy_s(s, CTEXT(node));
+	
+	node = CDR(node);
+	
+	multi_start_callback();
+	multi_send_string(s);
+
+	// evalutate on all clients
+	if (node == -1) {
+		multi_send_bool(true);
+		success = Script_system.EvalString(s, NULL, NULL, s);
+	}
+	// we have to send to all clients but we need to send a list of ships so that they know if they evaluate or not
+	else {
+		multi_send_bool(false);
+		
+		do {
+			p = get_player_from_ship_node(node, true);
+			
+			// not a player ship so skip it
+			if (p == NULL){
+				node = CDR(node);
+				continue;
+			}
+			else {
+				// if this is me, execute the script
+				if (p == Player) {
+					success = Script_system.EvalString(s, NULL, NULL, s);
+				}
+				// otherwise notify the clients
+				else {
+					sindex = ship_name_lookup(CTEXT(node));
+					multi_send_ship(sindex);	
+				}
+			}
+			
+			node = CDR(node);
+		} while (node != -1);
+	}
+	
+	multi_end_callback();
+	
+	if (!success) {
+		Warning(LOCATION, "sexp-script-eval failed to evaluate string \"%s\"; check your syntax", s);
+	}
+}
+
+void multi_sexp_script_eval_multi()
+ {
+	int sindex;
+	char s[TOKEN_LENGTH];
+	bool sent_to_all = false;
+	bool success = true;
+	
+	multi_get_string(s);
+	multi_get_bool(sent_to_all);
+	
+	if (sent_to_all) {
+		success = Script_system.EvalString(s, NULL, NULL, s);
+	}
+	// go through all the ships that were sent and see if any of them match this client.
+	else {
+		while (multi_get_ship(sindex)) {
+			Assertion(sindex >= 0, "Illegal value for the ship index sent in multi_sexp_script_eval_multi()! Ship %d does not exist!", sindex);
+			if (Player->objnum == Ships[sindex].objnum) {
+				success = Script_system.EvalString(s, NULL, NULL, s);	
+			}
+		}
+	}
+	
+	if (!success) {
+		Warning(LOCATION, "sexp-script-eval failed to evaluate string \"%s\"; check your syntax", s);
+	}
+}
+
+
+
 void sexp_force_glide(int node)
 {
 	ship *shipp;
@@ -24271,6 +24356,11 @@
 				sexp_val = sexp_script_eval(node, OPR_NULL);
 				break;
 
+			case OP_SCRIPT_EVAL_MULTI:
+				sexp_script_eval_multi(node);
+				sexp_val = SEXP_TRUE;
+				break;
+
 			case OP_CHANGE_IFF_COLOR:
 				sexp_change_iff_color(node);
 				sexp_val = SEXP_TRUE;
@@ -24702,6 +24792,10 @@
 				multi_sexp_set_ets_values();
 				break;
 
+			case OP_SCRIPT_EVAL_MULTI:
+				multi_sexp_script_eval_multi();
+				break;
+
 			// bad sexp in the packet
 			default: 
 				// probably just a version error where the host supports a SEXP but a client does not
@@ -25304,6 +25398,7 @@
 		case OP_SET_NUM_COUNTERMEASURES:
 		case OP_SCRIPT_EVAL:
 		case OP_SCRIPT_EVAL_STRING:
+		case OP_SCRIPT_EVAL_MULTI:
 		case OP_ENABLE_BUILTIN_MESSAGES:
 		case OP_DISABLE_BUILTIN_MESSAGES:
 		case OP_LOCK_PRIMARY_WEAPON:
@@ -27350,6 +27445,12 @@
 			if (argnum == 1)return OPF_VARIABLE_NAME;
 			else return OPF_STRING;
 
+		case OP_SCRIPT_EVAL_MULTI:
+			if (argnum == 0)
+				return OPF_STRING;
+			else
+				return OPF_SHIP;
+
 		case OP_CHANGE_IFF_COLOR:
 			if ((argnum == 0) || (argnum == 1))
 				return OPF_IFF;
@@ -29127,6 +29228,7 @@
 		case OP_SET_SUPPORT_SHIP:
 		case OP_SCRIPT_EVAL_STRING:
 		case OP_SCRIPT_EVAL:
+		case OP_SCRIPT_EVAL_MULTI:
 			return CHANGE_SUBCATEGORY_OTHER;
 
 		case OP_NUM_SHIPS_IN_BATTLE:
@@ -32747,6 +32849,15 @@
 		"\t1:\tScript to evaluate\r\n"
 	},
 
+	{OP_SCRIPT_EVAL_MULTI, "multi-eval\r\n"
+	 "\tEvaluates script on the host and on the clients\r\n"
+	 "\tWARNING: This SEXP is only a preliminary implementation and may be removed in a future version! Use with caution.\r\n\r\n"
+	 "Takes at least 1 argument...\r\n"
+	 "\t1:\tScript to evaluate\r\n"
+	 "\t(rest):\tList of players who should evaluate this script. If no player is given, all clients will execute the script\r\n"
+	},
+	
+
 	{OP_FORCE_GLIDE, "force-glide\r\n"
 		"\tForces a given ship into glide mode, provided it is capable of gliding. Note that the player will not be able to leave glide mode on his own,, and that a ship in glide mode cannot warp out or enter autopilot."
 		"Takes 2 Arguments...\r\n"
Index: code/parse/sexp.h
===================================================================
--- code/parse/sexp.h	(revision 10968)
+++ code/parse/sexp.h	(working copy)
@@ -723,6 +723,7 @@
 #define OP_SET_MOTION_DEBRIS				(0x0025 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG)    // The E
 #define OP_HUD_SET_CUSTOM_GAUGE_ACTIVE		(0x0026 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) 	// The E, just revamped a bit by Axem
 #define OP_HUD_SET_RETAIL_GAUGE_ACTIVE		(0x0027 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) 	// The E, just revamped a bit by Axem
+#define OP_SCRIPT_EVAL_MULTI				(0x0028 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG)	// Karajorma
 
 // defined for AI goals
 #define OP_AI_CHASE							(0x0000 | OP_CATEGORY_AI | OP_NONCAMPAIGN_FLAG)
3079.patch (6,070 bytes)   

m_m

2014-08-05 17:17

developer   ~0016175

Fix committed to trunk@10971.

Related Changesets

fs2open: trunk r10971

2014-08-05 13:45

m_m


Ported: N/A

Details Diff
From karajorma: Adds the multi-eval SEXP
WARNING: This SEXP is subject to change and will likely be removed or changed in a future version, use with caution.
Also fixes Mantis 3079: Add multi-eval to list of available SEXPs (.patch included)
Affected Issues
0003079
mod - /trunk/fs2_open/code/parse/sexp.cpp Diff File
mod - /trunk/fs2_open/code/parse/sexp.h Diff File

Issue History

Date Modified Username Field Change
2014-07-25 04:31 Parias New Issue
2014-07-25 04:31 Parias File Added: multi-eval-3_7_1.patch
2014-07-28 14:55 karajorma Note Added: 0016139
2014-07-28 14:56 karajorma Assigned To => karajorma
2014-07-28 14:56 karajorma Status new => assigned
2014-07-29 01:53 Parias Note Added: 0016141
2014-08-05 16:36 m_m Note Added: 0016173
2014-08-05 16:36 m_m File Added: 3079.patch
2014-08-05 16:36 m_m Assigned To karajorma => m_m
2014-08-05 16:36 m_m Status assigned => code review
2014-08-05 17:17 m_m Changeset attached => fs2open trunk r10971
2014-08-05 17:17 m_m Note Added: 0016175
2014-08-05 17:17 m_m Status code review => resolved
2014-08-05 17:17 m_m Resolution open => fixed