From 7ae67e1a7104995fce1dc1b75c2bd187ccb9b5e4 Mon Sep 17 00:00:00 2001
From: Yona-TYT <yonatan.el.amigo@gmail.com>
Date: Wed, 27 Nov 2024 15:44:07 -0400
Subject: [PATCH] ADD Simple data sender from script tool to scenario

---
 simutrans/script/script_base.nut       |  2 +
 simutrans/script/tool_base.nut         | 93 ++++++++++++++++++++++++++
 src/simutrans/dataobj/scenario.cc      | 10 +++
 src/simutrans/dataobj/scenario.h       |  8 +++
 src/simutrans/tool/simtool-scripted.cc | 90 +++++++++++++++++++++++++
 5 files changed, 203 insertions(+)

diff --git a/simutrans/script/script_base.nut b/simutrans/script/script_base.nut
index 1483f70b3..80a83f8b3 100644
--- a/simutrans/script/script_base.nut
+++ b/simutrans/script/script_base.nut
@@ -15,6 +15,8 @@ function max(a, b) { return a > b ? a : b }
  */
 persistent <- {}
 
+sender <- {}
+
 /**
  * writes the persistent table to a string
  */
diff --git a/simutrans/script/tool_base.nut b/simutrans/script/tool_base.nut
index 7128ee1e6..2482c8481 100644
--- a/simutrans/script/tool_base.nut
+++ b/simutrans/script/tool_base.nut
@@ -59,3 +59,96 @@ function correct_missing_flags_argument()
 		mark_tiles = function(player, start, end, flags) { mark_tiles_old(player, start, end) }
 	}
 }
+
+/**
+ * the sender table  will be sent to the scenario script using intern_send_data(str)
+ * only plain data is saved: no classes / instances / functions, no cyclic references
+ */
+sender <- {}
+
+/**
+ * writes the sender table to a string
+ */
+function send_data()
+{
+	if (typeof(sender) != "table") {
+		throw("error during saving: the variable sender is not a table")
+	}
+	local str = "sender = " + recursive_send(sender, "\t", [ sender ] )
+
+	intern_send_data(str)
+}
+
+function is_identifier(str)
+{
+	return (str.toalnum() == str)  &&  (str[0] < '0'  ||  str[0] > '9')
+}
+
+function recursive_send(table, indent, table_stack)
+{
+	local isarray = typeof(table) == "array"
+	local str = (isarray ? "[" : "{") + "\n"
+	foreach(key, val in table) {
+		str += indent
+		if (!isarray) {
+			if (typeof(key)=="string") {
+				if (is_identifier(key)) {
+					str += key + " = "
+				}
+				else {
+					str += "[\"" + key + "\"] = "
+				}
+			}
+			else {
+				str += "[" + key + "] = "
+			}
+		}
+		while( typeof(val) == "weakref" )
+			val = val.ref
+
+		switch( typeof(val) ) {
+			case "null":
+				str += "null"
+				break
+			case "integer":
+			case "float":
+			case "bool":
+				str += val
+				break
+			case "string":
+				str += "@\"" + val + "\""
+				break
+			case "array":
+			case "table":
+				if (!table_stack.find(val)) {
+						table_stack.push( table )
+						str += recursive_send(val, indent + "\t", table_stack )
+						table_stack.pop()
+				}
+				else {
+					// cyclic reference - good luck with resolving
+					str += "null"
+				}
+				break
+			case "generator":
+				str += "null"
+				break
+			case "instance":
+			default:
+				if ("_save" in val) {
+					str += val._save()
+					break
+				}
+				str += "\"unknown(" + typeof(val) + ")\""
+		}
+		if (str.slice(-1) != "\n") {
+			str += ",\n"
+		}
+		else {
+			str = str.slice(0,-1) + ",\n"
+		}
+
+	}
+	str += indent.slice(0,-1) + (isarray ? "]" : "}") + "\n"
+	return str
+}
diff --git a/src/simutrans/dataobj/scenario.cc b/src/simutrans/dataobj/scenario.cc
index c58cc91b5..d3d126abe 100644
--- a/src/simutrans/dataobj/scenario.cc
+++ b/src/simutrans/dataobj/scenario.cc
@@ -666,6 +666,16 @@ const char* scenario_t::jump_to_link_executed(koord3d pos)
 	return NULL;
 }
 
+
+const char* scenario_t::tool_data_to_scenario(const char *str)
+{
+	if (what_scenario == SCRIPTED) {
+		return script->eval_string(str);
+	}
+	return NULL;
+}
+
+
 const char* scenario_t::get_error_text()
 {
 	if (script) {
diff --git a/src/simutrans/dataobj/scenario.h b/src/simutrans/dataobj/scenario.h
index 597844518..9fc795b8a 100644
--- a/src/simutrans/dataobj/scenario.h
+++ b/src/simutrans/dataobj/scenario.h
@@ -483,6 +483,14 @@ public:
 	 */
 	const char* jump_to_link_executed(koord3d pos);
 
+	/**
+	 * Send simple data from script tool to scenario script
+	 *
+	 * @param str string with the values ​​sent
+	 *
+	 */
+	const char* tool_data_to_scenario(const char *str);
+
 	/// @return debug dump of forbidden tools
 	const char* get_forbidden_text();
 	/// @}
diff --git a/src/simutrans/tool/simtool-scripted.cc b/src/simutrans/tool/simtool-scripted.cc
index a1745bb9b..5fb7549bf 100644
--- a/src/simutrans/tool/simtool-scripted.cc
+++ b/src/simutrans/tool/simtool-scripted.cc
@@ -17,6 +17,8 @@
 #include "../world/simworld.h"
 #include "../obj/zeiger.h"
 
+#include "../dataobj/scenario.h"
+
 void export_scripted_tools(HSQUIRRELVM vm);
 
 // -- callback to receive error messages from work/do_work calls
@@ -73,6 +75,23 @@ namespace script_api {
 			return res;
 		}
 	};
+	template<> struct param<tool_exec_script_t*> {
+		static tool_exec_script_t* get(HSQUIRRELVM vm, SQInteger index)
+		{
+			tool_t* tool = param<tool_t*>::get(vm, index);
+			return tool ? dynamic_cast<tool_exec_script_t*>(tool) : NULL;
+		}
+
+		static SQInteger push(HSQUIRRELVM vm, tool_exec_script_t* const& tool)
+		{
+			SQInteger res = push_instance(vm, "command_x", (uint32)(TOOL_EXEC_SCRIPT | GENERAL_TOOL) );
+			if (SQ_SUCCEEDED(res)) {
+				my_tool_t* mtool = new my_tool_t(tool);
+				attach_instance(vm, -1, mtool);
+			}
+			return res;
+		}
+	};
 };
 
 // -- basic script handling --
@@ -200,6 +219,8 @@ tool_exec_script_t::tool_exec_script_t(const scripted_tool_info_t *info) : tool_
 }
 
 
+SQInteger tool_sender(HSQUIRRELVM vm); // see below
+
 bool tool_exec_script_t::init(player_t* player)
 {
 	bool res = false;
@@ -212,10 +233,50 @@ bool tool_exec_script_t::init(player_t* player)
 		cursor_area = koord(old_area.y, old_area.x);
 		cursor_offset = koord(old_area.y-1-old_offset.y, old_offset.x);
 	}
+
+	if (init_vm(player)) {
+		HSQUIRRELVM vm = script->get_vm();
+		// put pointer to this tool into registry
+		sq_pushregistrytable(vm);
+		script_api::create_slot(vm, "my_tool", this);
+		sq_poptop(vm);
+		// export marker function
+		sq_pushroottable(vm);
+		script_api::register_function(vm, tool_sender, "intern_send_data", 2, "..", false ); 
+		sq_poptop(vm);
+	}
+
 	return init_vm(player)  &&  call_function(script_vm_t::FORCE, "init", player, res)== NULL  &&  res;
 }
 
 
+// send simple data
+SQInteger tool_sender(HSQUIRRELVM vm)
+{
+	plainstring str = script_api::param<plainstring>::get(vm, 2);
+
+	// restore sender data--------
+	karte_t *welt = world();
+	scenario_t	*scen = welt->get_scenario();
+	const char* err = scen->tool_data_to_scenario(str);
+
+	if (err) {
+		dbg->warning("scenario_t::rdwr", "error [%s] evaluating persistent scenario data", err);
+		return SQ_ERROR;
+	}
+
+	// tool
+	sq_pushregistrytable(vm);
+	tool_exec_script_t* tool = NULL;
+	if (!SQ_SUCCEEDED(script_api::get_slot<tool_exec_script_t*>(vm, "my_tool", tool))  ||  tool == NULL) {
+		return SQ_ERROR;
+	}
+	sq_poptop(vm);
+
+	return SQ_OK;
+}
+
+
 bool tool_exec_script_t::exit(player_t* player)
 {
 	bool res, res2 = false;
@@ -263,6 +324,7 @@ tool_exec_two_click_script_t::tool_exec_two_click_script_t(const scripted_tool_i
 
 
 SQInteger script_mark_tile(HSQUIRRELVM vm); // see below
+SQInteger two_click_tool_sender(HSQUIRRELVM vm); 
 
 bool tool_exec_two_click_script_t::init(player_t* player)
 {
@@ -284,6 +346,7 @@ bool tool_exec_two_click_script_t::init(player_t* player)
 		// export marker function
 		sq_pushroottable(vm);
 		script_api::register_function(vm, script_mark_tile, "mark_tile", 2, ". t|x|y", false /* static */);
+		script_api::register_function(vm, two_click_tool_sender, "intern_send_data", 2, "..", false ); 
 		sq_poptop(vm);
 	}
 	return res  &&   call_function(script_vm_t::FORCE, "init", player, res)== NULL  &&  res;
@@ -366,6 +429,33 @@ SQInteger script_mark_tile(HSQUIRRELVM vm)
 }
 
 
+// send simple data
+SQInteger two_click_tool_sender(HSQUIRRELVM vm)
+{
+	plainstring str = script_api::param<plainstring>::get(vm, 2);
+
+	// restore sender data--------
+	karte_t *welt = world();
+	scenario_t	*scen = welt->get_scenario();
+	const char* err = scen->tool_data_to_scenario(str);
+
+	if (err) {
+		dbg->warning("scenario_t::rdwr", "error [%s] evaluating persistent scenario data", err);
+		return SQ_ERROR;
+	}
+
+	// tool
+	sq_pushregistrytable(vm);
+	tool_exec_two_click_script_t* tool = NULL;
+	if (!SQ_SUCCEEDED(script_api::get_slot<tool_exec_two_click_script_t*>(vm, "my_two_click_tool", tool))  ||  tool == NULL) {
+		return SQ_ERROR;
+	}
+	sq_poptop(vm);
+
+	return SQ_OK;
+}
+
+
 bool tool_exec_two_click_script_t::mark_tile(player_t* player, const koord3d &pos)
 {
 	grund_t *gr = welt->lookup(pos);
-- 
2.47.0

