Author Topic: script-eval and scripts longer than 31 characters [COMMITED]  (Read 4065 times)

0 Members and 1 Guest are viewing this topic.

Offline niffiwan

  • 211
  • Eluder Class
script-eval and scripts longer than 31 characters [COMMITED]
As many of you know, script-eval is limited to being able to call 31 32 characters worth of script. This leads to *fun* workarounds like really short script names and using variables (also with short names) to hold script parameters. Then Axem said to me on IRC the other day, "What if all the script-eval arguments could be concatenated together and passed to the scripting system?"  Intriguing concept... and this is the result :)

Code: [Select]
commit c7363f011de4260572fcfe3bf9d25c5961be6579
Author: niffiwan <[email protected]>
Date:   Sun Mar 30 15:04:17 2014 +1000

    allow script-eval to run scripts longer than 31 chars
   
    It's a workaround to the sexp TOKEN_LENGTH limit
    The script can be broken up across multiple arguments
    e.g.
    ( script-eval
      "ba.warning('foo"
      " more and more and more"
      " and the rest')"
    )
    Kudos to Axem for suggesting the idea

diff --git a/code/parse/scripting.cpp b/code/parse/scripting.cpp
index 1c3060f..6d04a80 100644
--- a/code/parse/scripting.cpp
+++ b/code/parse/scripting.cpp
@@ -1068,7 +1068,7 @@ int script_state::OutputMeta(char *filename)
  return 1;
 }
 
-bool script_state::EvalString(char* string, char *format, void *rtn, char *debug_str)
+bool script_state::EvalString(const char* string, char *format, void *rtn, const char *debug_str)
 {
  char lastchar = string[strlen(string)-1];
 
diff --git a/code/parse/scripting.h b/code/parse/scripting.h
index 9d28528..f7f8056 100644
--- a/code/parse/scripting.h
+++ b/code/parse/scripting.h
@@ -189,7 +189,7 @@ public:
  void RemHookVars(unsigned int num, ...);
 
  //***Hook creation functions
- bool EvalString(char* string, char *format=NULL, void *rtn=NULL, char *debug_str=NULL);
+ bool EvalString(const char* string, char *format=NULL, void *rtn=NULL, const char *debug_str=NULL);
  void ParseChunk(script_hook *dest, char* debug_str=NULL);
  bool ParseCondition(const char *filename="<Unknown>");
 
diff --git a/code/parse/sexp.cpp b/code/parse/sexp.cpp
index 18d0d71..50024d7 100644
--- a/code/parse/sexp.cpp
+++ b/code/parse/sexp.cpp
@@ -21391,6 +21391,7 @@ int sexp_script_eval(int node, int return_type)
 {
  int n = node;
  char *s = CTEXT(n);
+ SCP_string lua_cmd;
  bool success = false;
 
  int r = -1;
@@ -21406,9 +21407,10 @@ int sexp_script_eval(int node, int return_type)
  case OPR_NULL:
  while(n != -1)
  {
- success = Script_system.EvalString(s, NULL, NULL, CTEXT(n));
+ lua_cmd.append(CTEXT(n));
  n = CDR(n);
  }
+ success = Script_system.EvalString(lua_cmd.c_str(), NULL, NULL, lua_cmd.c_str());
  break;
  default:
  Error(LOCATION, "Bad type passed to sexp_script_eval - get a coder");
@@ -32560,9 +32562,11 @@ sexp_help_struct Sexp_help[] = {
  },
 
  {OP_SCRIPT_EVAL, "script-eval\r\n"
- "\tEvaluates script"
+ "\tEvaluates one script\r\n"
+ "\tAdditional arguments are the rest of the script in 31 (+NULL character) chunks\r\n\r\n"
  "Takes at least 1 argument...\r\n"
  "\t1:\tScript to evaluate\r\n"
+ "\tRest:\tRemainder of script if the script length exceeds 32 characters\r\n"
  },
 
  {OP_FORCE_GLIDE, "force-glide\r\n"

In other words, at the cost of a little ugliness in the script-eval arguments, you can now pass an arbitrary1 length script to script-eval.

Before I consider committing this to trunk, I'd like some wider testing of the solution, so please grab the executables linked here and let me know the results.
http://www.mediafire.com/download/e9u1z5bkpv9o0wc/new-script-eval.7z

Lastly, please note that script-eval was already designed to accept multiple parameters, but the implementation was broken. It called the 1st argument in place of all arguments.  i.e. 3 arguments equalled three calls of the 1st argument. Therefore I'm confident that changing the sexp like this won't break any existing missions.

1. There are no prizes if you break it by passing 11MB of text to script-eval :p

edit: (yep, its 32 chars, not 31)
« Last Edit: March 20, 2015, 08:36:30 pm by niffiwan »
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 

Offline General Battuta

  • Poe's Law In Action
  • 214
  • i wonder when my postcount will exceed my iq
Re: script-eval and scripts longer than 31 characters
SORCERY

 

Offline niffiwan

  • 211
  • Eluder Class
Re: script-eval and scripts longer than 31 characters
:D

Here's another example using a slightly modified turret hotkey script:

(yes, turretHotKeyAdder is a bit contrived in order to exceed the 32 char limit... the ship names for thkShip() on the other hand...)

Code: [Select]
$Formula: ( when
   ( true )
   ( script-eval
        "thkEnable()"
   )
   ( script-eval
        "thkShip('GTC Aeolus 1'," " 'GTC 2')"
   )
   ( script-eval "turretHotKeyAdder(1," " 'Turret01')")
   ( script-eval "turretHotKeyAdder(1," " 'Turret02')")
   ( script-eval "turretHotKeyAdder(1," " 'Turret03')")
   ( script-eval "turretHotKeyAdder(1," " 'Turret04')")
   ( script-eval "turretHotKeyAdder(2," " 'Turret01')")
   ( script-eval "turretHotKeyAdder(2," " 'Turret02')")
   ( script-eval "turretHotKeyAdder(2," " 'Turret03')")
   ( script-eval "turretHotKeyAdder(2," " 'Turret04')")
   ( script-eval "thkKey('F12')")
)
+Name: turrethotkey
+Repeat Count: 1
+Interval: 1
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Re: script-eval and scripts longer than 31 characters
I've been intending on fixing this for a long time but never got around to it, so this is great.

However, wouldn't it be better if instead of brute string concatenation, you could also directly pass arguments to a Lua function as the SEXP arguments?

For example...
Code: [Select]
( script-eval
    "turretHotKeyAdder()"
    "1"
    "Turret01"
)

I guess it might make more sense to have a separate script-eval-func SEXP though.

 

Offline m!m

  • 211
Re: script-eval and scripts longer than 31 characters
A seperate SEXP would be better for calling a single Lua functions as the solution niffiwan has implemented can also be used for more complicated things than just executing a single function.

 

Offline Axem

  • 211
Re: script-eval and scripts longer than 31 characters
Yeah, a separate script-eval-func sexp would be ideal for that (and pretty cool).

I mean with this new way of doing things you can do something like...

Code: [Select]
"hv.Player.Target = mn.Ships['"
"@StringVar[GTC Orff]"
"']

to force a player's target to a ship name specified in a sexp variable!

EDIT: Haha, or even
Code: [Select]
"for i = 1, #mn.Ships do "
"mn.Ships[i].HitpointsLeft"
" = 50000 end"

To give every ship 50,000 HP regardless of their actual max health (hello 6500% hull integrity fighters!)
« Last Edit: March 30, 2014, 09:14:25 am by Axem »

 

Offline mjn.mixael

  • Cutscene Master
  • 212
  • Chopped liver
    • Steam
    • Twitter
Re: script-eval and scripts longer than 31 characters

EDIT: Haha, or even
Code: [Select]
"for i = 1, #mn.Ships do "
"mn.Ships[i].HitpointsLeft"
" = 50000 end"

To give every ship 50,000 HP regardless of their actual max health (hello 6500% hull integrity fighters!)

Oh dear.. JAD 2.2245683 is going to be hell.  :lol:
Cutscene Upgrade Project - Mainhall Remakes - Between the Ashes
Youtube Channel - P3D Model Box
Between the Ashes is looking for committed testers, PM me for details.
Freespace Upgrade Project See what's happening.

 

Offline mjn.mixael

  • Cutscene Master
  • 212
  • Chopped liver
    • Steam
    • Twitter
Re: script-eval and scripts longer than 31 characters
I apparently didn't look at this closely enough before... I'll need to do some more specific testing and checks, but I'm pretty confident multiple script-eval arguments work or my checkpoints in BtA wouldn't.

EDIT: After my tests, it's looking more like I was too good at defensibly FREDing and my checkpoint in the one mission affected worked for an entirely different reason. So I defer to your coding knowledge.
« Last Edit: May 31, 2014, 10:11:24 pm by mjn.mixael »
Cutscene Upgrade Project - Mainhall Remakes - Between the Ashes
Youtube Channel - P3D Model Box
Between the Ashes is looking for committed testers, PM me for details.
Freespace Upgrade Project See what's happening.

 

Offline m!m

  • 211
Re: script-eval and scripts longer than 31 characters
Has this been committed to trunk yet? I made some changes to the script eval functions and I don't want to introduce behavior that breaks later on.

 

Offline mjn.mixael

  • Cutscene Master
  • 212
  • Chopped liver
    • Steam
    • Twitter
Re: script-eval and scripts longer than 31 characters
I'm pretty sure it's not in trunk.
Cutscene Upgrade Project - Mainhall Remakes - Between the Ashes
Youtube Channel - P3D Model Box
Between the Ashes is looking for committed testers, PM me for details.
Freespace Upgrade Project See what's happening.

 

Offline niffiwan

  • 211
  • Eluder Class
Re: script-eval and scripts longer than 31 characters
Ahahaha.  It's nearly been a year since I 1st posted this  :nervous:

Based on feedback I've decided to move this to a separate sexp, script-eval-block rather than potentially stomp all over existing uses of script-eval.

Code: [Select]
commit 50e588bb9e0b7fccd836058f922a500e13a112db
Author: niffiwan <[email protected]>
Date:   Mon Mar 16 18:48:13 2015 +1000

    add script-eval-block sexp
   
    This is a workaround to the sexp TOKEN_LENGTH limit
    The script can be split across multiple arguments to allow scripts
    longer than 32 chars (i.e. current TOKEN_LENGTH)
    e.g.
    ( script-eval
      "ba.warning('foo"
      " more and more and more"
      " and the rest')"
    )
    Kudos to Axem for suggesting the idea
    (And to zookeeper for reminding me to actually commit it!)

diff --git a/code/parse/sexp.cpp b/code/parse/sexp.cpp
index f86d2d9..f5f6b1e 100644
--- a/code/parse/sexp.cpp
+++ b/code/parse/sexp.cpp
@@ -683,6 +683,7 @@ sexp_oper Operators[] = {
  { "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
  { "script-eval", OP_SCRIPT_EVAL, 1, INT_MAX, SEXP_ACTION_OPERATOR, },
+ { "script-eval-block", OP_SCRIPT_EVAL_BLOCK, 1, INT_MAX, SEXP_ACTION_OPERATOR, },
  { "multi-eval", OP_SCRIPT_EVAL_MULTI, 2, INT_MAX, SEXP_ACTION_OPERATOR, },
  { "debug", OP_DEBUG, 2, 2, SEXP_ACTION_OPERATOR, }, // Karajorma
  { "do-nothing", OP_NOP, 0, 0, SEXP_ACTION_OPERATOR, },
@@ -21659,7 +21660,7 @@ void multi_sexp_show_hide_jumpnode(bool show)
 
 //WMC - This is a bit of a hack, however, it's easier than
 //coding in a whole new Script_system function.
-int sexp_script_eval(int node, int return_type)
+int sexp_script_eval(int node, int return_type, bool concat_args = false)
 {
  int n = node;
 
@@ -21711,16 +21712,33 @@ int sexp_script_eval(int node, int return_type)
  break;
  case OPR_NULL:
  {
+ SCP_string script_cmd;
  while (n != -1)
  {
  char* s = CTEXT(n);
- bool success = Script_system.EvalString(s, NULL, NULL);
 
- if (!success)
- Warning(LOCATION, "sexp-script-eval failed to evaluate string \"%s\"; check your syntax", s);
+ if (concat_args)
+ {
+ script_cmd.append(CTEXT(n));
+ }
+ else
+ {
+ bool success = Script_system.EvalString(s, NULL, NULL);
+
+ if (!success)
+ Warning(LOCATION, "sexp-script-eval failed to evaluate string \"%s\"; check your syntax", s);
+ }
 
  n = CDR(n);
  }
+
+ if (concat_args)
+ {
+ bool success = Script_system.EvalString(script_cmd.c_str(), NULL, NULL);
+
+ if (!success)
+ Warning(LOCATION, "sexp-script-eval failed to evaluate string \"%s\"; check your syntax", script_cmd.c_str());
+ }
  }
  break;
  default:
@@ -24515,6 +24533,10 @@ int eval_sexp(int cur_node, int referenced_node)
  sexp_val = sexp_script_eval(node, OPR_NULL);
  break;
 
+ case OP_SCRIPT_EVAL_BLOCK:
+ sexp_val = sexp_script_eval(node, OPR_NULL, true);
+ break;
+
  case OP_SCRIPT_EVAL_MULTI:
  sexp_script_eval_multi(node);
  sexp_val = SEXP_TRUE;
@@ -25552,6 +25574,7 @@ int query_operator_return_type(int op)
  case OP_SET_SECONDARY_WEAPON:
  case OP_SET_NUM_COUNTERMEASURES:
  case OP_SCRIPT_EVAL:
+ case OP_SCRIPT_EVAL_BLOCK:
  case OP_SCRIPT_EVAL_STRING:
  case OP_SCRIPT_EVAL_MULTI:
  case OP_ENABLE_BUILTIN_MESSAGES:
@@ -27634,6 +27657,7 @@ int query_operator_argument_type(int op, int argnum)
  return OPF_BOOL;
 
  case OP_SCRIPT_EVAL_NUM:
+ case OP_SCRIPT_EVAL_BLOCK:
  case OP_SCRIPT_EVAL:
  return OPF_STRING;
 
@@ -29420,6 +29444,7 @@ int get_subcategory(int sexp_id)
  case OP_DAMAGED_ESCORT_LIST_ALL:
  case OP_SET_SUPPORT_SHIP:
  case OP_SCRIPT_EVAL_STRING:
+ case OP_SCRIPT_EVAL_BLOCK:
  case OP_SCRIPT_EVAL:
  case OP_SCRIPT_EVAL_MULTI:
  return CHANGE_SUBCATEGORY_OTHER;
@@ -33056,6 +33081,12 @@ sexp_help_struct Sexp_help[] = {
  "\t1:\tScript to evaluate\r\n"
  },
 
+ {OP_SCRIPT_EVAL_BLOCK, "script-eval-block\r\n"
+ "\tEvaluates the concatenation of all arguments as a script\r\n"
+ "Takes at least 1 argument...\r\n"
+ "\tAll:\tScript to evaluate\r\n"
+ },
+
  {OP_SCRIPT_EVAL_MULTI, "multi-eval\r\n"
  "\tEvaluates script\r\n\r\n"
  "Takes at least 2 arguments...\r\n"
diff --git a/code/parse/sexp.h b/code/parse/sexp.h
index f215c63..48fec5a 100644
--- a/code/parse/sexp.h
+++ b/code/parse/sexp.h
@@ -726,6 +726,7 @@ class waypoint_list;
 #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
 #define OP_PAUSE_SOUND_FROM_FILE (0x0029 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) // Goober5000
+#define OP_SCRIPT_EVAL_BLOCK (0x002a | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) // niffiwan
 
 // defined for AI goals
 #define OP_AI_CHASE (0x0000 | OP_CATEGORY_AI | OP_NONCAMPAIGN_FLAG)

If you have further feedback let me know this week as I'm going to commit this (for realz this time) next weekend  :D

* niffiwan runs off and sets a reminder in his calendar...
Creating a fs2_open.log | Red Alert Bug = Hex Edit | MediaVPs 2014: Bigger HUD gauges | 32bit libs for 64bit Ubuntu
----
Debian Packages (testing/unstable): Freespace2 | wxLauncher
----
m|m: I think I'm suffering from Stockholm syndrome. Bmpman is starting to make sense and it's actually written reasonably well...

 
Re: script-eval and scripts longer than 31 characters
For the love of gods YES!!!