From 21ecd714ec0e21d4abedbaa5a5548a3041ec5f4a Mon Sep 17 00:00:00 2001
From: ZZYZX <zzyzx@virtual>
Date: Mon, 6 Mar 2017 11:25:30 +0200
Subject: [PATCH] Added a way to tell apart console-executed events from
 code-executed SendNetworkEvent

---
 src/d_net.cpp                    |  5 +++--
 src/events.cpp                   | 19 ++++++++++++-------
 src/events.h                     |  9 ++++++---
 wadsrc/static/zscript/events.txt |  3 +++
 4 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/src/d_net.cpp b/src/d_net.cpp
index 6ba77bc2ae..f9bd55d889 100644
--- a/src/d_net.cpp
+++ b/src/d_net.cpp
@@ -2676,7 +2676,8 @@ void Net_DoCommand (int type, BYTE **stream, int player)
 			int arg[3] = { 0, 0, 0 };
 			for (int i = 0; i < 3; i++)
 				arg[i] = ReadLong(stream);
-			E_Console(player, s, arg[0], arg[1], arg[2]);
+			bool manual = ReadByte(stream);
+			E_Console(player, s, arg[0], arg[1], arg[2], manual);
 		}
 		break;
 
@@ -2727,7 +2728,7 @@ void Net_SkipCommand (int type, BYTE **stream)
 			break;
 
 		case DEM_NETEVENT:
-			skip = strlen((char *)(*stream)) + 14;
+			skip = strlen((char *)(*stream)) + 15;
 			break;
 
 		case DEM_SUMMON2:
diff --git a/src/events.cpp b/src/events.cpp
index 9946a10594..08e4b328d8 100755
--- a/src/events.cpp
+++ b/src/events.cpp
@@ -117,7 +117,7 @@ bool E_UnregisterHandler(DStaticEventHandler* handler)
 	return true;
 }
 
-bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3)
+bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual)
 {
 	if (gamestate != GS_LEVEL)
 		return false;
@@ -128,6 +128,7 @@ bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3)
 	Net_WriteLong(arg1);
 	Net_WriteLong(arg2);
 	Net_WriteLong(arg3);
+	Net_WriteByte(manual);
 
 	return true;
 }
@@ -433,10 +434,10 @@ bool E_Responder(event_t* ev)
 	return false;
 }
 
-void E_Console(int player, FString name, int arg1, int arg2, int arg3)
+void E_Console(int player, FString name, int arg1, int arg2, int arg3, bool manual)
 {
 	for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
-		handler->ConsoleProcess(player, name, arg1, arg2, arg3);
+		handler->ConsoleProcess(player, name, arg1, arg2, arg3, manual);
 }
 
 bool E_CheckUiProcessors()
@@ -523,6 +524,7 @@ DEFINE_FIELD_X(InputEvent, DInputEvent, MouseY);
 DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Player)
 DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Name)
 DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Args)
+DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, IsManual)
 
 DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder)
 {
@@ -545,7 +547,7 @@ DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkEvent)
 	PARAM_INT(arg3);
 	//
 
-	ACTION_RETURN_BOOL(E_SendNetworkEvent(name, arg1, arg2, arg3));
+	ACTION_RETURN_BOOL(E_SendNetworkEvent(name, arg1, arg2, arg3, false));
 }
 
 DEFINE_ACTION_FUNCTION(DEventHandler, Create)
@@ -1091,10 +1093,11 @@ static DConsoleEvent* E_SetupConsoleEvent()
 	e->Name = "";
 	for (size_t i = 0; i < countof(e->Args); i++)
 		e->Args[i] = 0;
+	e->IsManual = false;
 	return e;
 }
 
-void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3)
+void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual)
 {
 	if (player < 0)
 	{
@@ -1111,6 +1114,7 @@ void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int
 			e->Args[0] = arg1;
 			e->Args[1] = arg2;
 			e->Args[2] = arg3;
+			e->IsManual = manual;
 
 			VMValue params[2] = { (DStaticEventHandler*)this, e };
 			GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
@@ -1131,6 +1135,7 @@ void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int
 			e->Args[0] = arg1;
 			e->Args[1] = arg2;
 			e->Args[2] = arg3;
+			e->IsManual = manual;
 
 			VMValue params[2] = { (DStaticEventHandler*)this, e };
 			GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
@@ -1162,7 +1167,7 @@ CCMD(event)
 		for (int i = 0; i < argn; i++)
 			arg[i] = atoi(argv[2 + i]);
 		// call locally
-		E_Console(-1, argv[1], arg[0], arg[1], arg[2]);
+		E_Console(-1, argv[1], arg[0], arg[1], arg[2], true);
 	}
 }
 
@@ -1187,6 +1192,6 @@ CCMD(netevent)
 		for (int i = 0; i < argn; i++)
 			arg[i] = atoi(argv[2 + i]);
 		// call networked
-		E_SendNetworkEvent(argv[1], arg[0], arg[1], arg[2]);
+		E_SendNetworkEvent(argv[1], arg[0], arg[1], arg[2], true);
 	}
 }
diff --git a/src/events.h b/src/events.h
index b838902235..d41c2e26d3 100755
--- a/src/events.h
+++ b/src/events.h
@@ -58,10 +58,10 @@ void E_PlayerDisconnected(int num);
 // this executes on events.
 bool E_Responder(event_t* ev); // splits events into InputProcess and UiProcess
 // this executes on console/net events.
-void E_Console(int player, FString name, int arg1, int arg2, int arg3);
+void E_Console(int player, FString name, int arg1, int arg2, int arg3, bool manual);
 
 // send networked event. unified function.
-bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3);
+bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual);
 
 // check if there is anything that should receive GUI events
 bool E_CheckUiProcessors();
@@ -152,7 +152,7 @@ public:
 	bool UiProcess(event_t* ev);
 	
 	// 
-	void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3);
+	void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual);
 };
 class DEventHandler : public DStaticEventHandler
 {
@@ -300,10 +300,13 @@ public:
 	//
 	FString Name;
 	int Args[3];
+	//
+	bool IsManual;
 
 	DConsoleEvent()
 	{
 		Player = -1;
+		IsManual = false;
 	}
 };
 
diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt
index c6c01c54f0..d7e39e1c0f 100755
--- a/wadsrc/static/zscript/events.txt
+++ b/wadsrc/static/zscript/events.txt
@@ -275,8 +275,11 @@ class ConsoleEvent : BaseEvent native version("2.4")
     // for net events, this will be the activator.
     // for UI events, this is always -1, and you need to check if level is loaded and use players[consoleplayer].
     native readonly int Player;
+    // this is the name and args as specified in SendNetworkEvent or event/netevent CCMDs
     native readonly String Name;
     native readonly int Args[3];
+    // this will be true if the event is fired from the console by event/netevent CCMD
+    native readonly bool IsManual;
 }
 
 class StaticEventHandler : Object native play version("2.4")