Skip to content
This repository was archived by the owner on Jan 9, 2023. It is now read-only.

Commit 4029e5f

Browse files
committed
escape event attributes and handle Rcon responses
1 parent f303f6a commit 4029e5f

File tree

9 files changed

+43
-23
lines changed

9 files changed

+43
-23
lines changed

Profiles/Factorio - Dev Test.json renamed to Profiles/Factorio - Advanced Usage Example.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
{
2-
"name": "Factorio - Dev Test",
3-
"description": "Development test profile",
2+
"name": "Factorio - Advanced Usage Example",
3+
"description": "Example of some more complicated uses",
44
"reactions": [
55
{
66
"valueType": "money",
77
"filteredActions": [
88
{
99
"condition": "[VALUE] >= 5",
1010
"manipulator": "int([VALUE]/5)",
11-
"action": "/escape_pod_add_level [MODVALUE]"
11+
"action": "/a_custom_command [MODVALUE] '[BESTNAME]'"
1212
},
1313
{
1414
"condition": "[ALL]",
15-
"manipulator": "",
16-
"action": "[NOTHING]"
15+
"manipulator": "'bob'",
16+
"action": "static manipulator value: \"[MODVALUE]\""
1717
}
1818
]
1919
},
@@ -23,17 +23,17 @@
2323
{
2424
"condition": "[ALL]",
2525
"manipulator": "",
26-
"action": "[NOTHING]"
26+
"action": "/sc game.print('[BESTNAME]')"
2727
}
2828
]
2929
},
3030
{
3131
"valueType": "viewer",
3232
"filteredActions": [
3333
{
34-
"condition": "[ALL]",
35-
"manipulator": "",
36-
"action": "[NOTHING]"
34+
"condition": "[VALUE] >= 0",
35+
"manipulator": "'bo\\'b'",
36+
"action": "/sc game.print('[MODVALUE]\\'s great' .. ' and ' .. \"[BESTNAME]'s awesome\")"
3737
}
3838
]
3939
}

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The integration is now running between the Streamlabs account and the game using
1717

1818
Should a critical error occur the progra may fail to load or close. Details can be found in the current log within the Logs folder.
1919

20+
2021
Usage Concepts
2122
========
2223

@@ -28,20 +29,20 @@ The app runs a single grouping of reactions at a time, being loaded and saved as
2829

2930
When an Streamlabs event is received it is processed to have the standard `[ALL]` additional data attributes calculated for them. The reactions are reviewed to find the most approperiate one. First the reactions are checked for the first matching platform and type to the event. If no match is found the ValueType of the event is checked for in the reactions for a match.
3031

31-
Assuming a reaction for the event is found the reaction's filter script is checked for the first that is met (resolves to True). Filters allow a scripts conditions to be used to select the approperiate action to do for the event. All of the events data items from Streamlabs and this app can be used witihn the filter in the format `[DATA_ITEM_NAME]`. i.e. `[VALUE] >= 5 and [VALUE] < 10`. There is a special `ALL` filter option that it configured will be triggered after all other filters have been checked. The filters within a reaction are not order specific and so should not overlap each others conditions.
32+
Assuming a reaction for the event is found the reaction's filter script is checked for the first that is met (resolves to True). Filters allow a scripts conditions to be used to select the approperiate action to do for the event. All of the events data attributes from Streamlabs and this app can be used witihn the filter in the format `[DATA_ITEM_NAME]`. i.e. `[VALUE] >= 5 and [VALUE] < 10`. There is a special `ALL` filter option that it configured will be triggered after all other filters have been checked. The filters within a reaction are not order specific and so should not overlap each others conditions.
3233

3334
The first complying reaction filter will then run an optional manipulator script if configured. This creates a new data item for the event `[MODVALUE]` with the scripts output value. This is used when you want to pass a modified value in to the game.
3435

35-
The action tied to the filter are the Rcon commands that are run in the game. It can utilise any of the events data items in the standard format `[DATA_ITEM_NAME]`. i.e. `[name] supported with $[VALUE] worth $[MODVALUE]` or `/promote [name]`. There is a special `NOTHING` action that is intended for intentionally ignoring the event. This avoids any warnings about unhandled events. Actions can be either a specific Lua command string or the name of a shared Lua command string within the profile. This is to allow re-use of Lua command strings when its convienent.
36+
The action tied to the filter are the Rcon commands that are run in the game. It can utilise any of the events data attributes in the standard format `[DATA_ITEM_NAME]`. i.e. `[name] supported with $[VALUE] worth $[MODVALUE]` or `/promote [name]`. There is a special `NOTHING` action that is intended for intentionally ignoring the event. This avoids any warnings about unhandled events. Actions can be either a specific Lua command string or the name of a shared Lua command string within the profile. This is to allow re-use of Lua command strings when its convienent. Should an Rcon command get a response from the server it will be shown in the Activity Log as is liekly an error from the game.
3637

37-
All data items used in scripts are replaced with their event data values at execution time. The replaced text may require wrapping in quotes if it needs to be treated as a string. A script is a single python expression that can be processed via the Python eval() function.
38+
All data attributes used in scripts are replaced with their event data values at execution time. The replaced text may require wrapping in quotes if it needs to be treated as a string. A script is a single python expression that can be processed via the Python eval() function.
3839

3940
When the application starts up all profiles in the profile folder are checked for their compliance with the event handler types and their attributes. All conditions and manipulators will be tested with a value of "1" for all attributes to confirm they are valid python scripts. Any issues causes the program to stop loading and the issue is recorded to the log file. This is to avoid failure from mis-configuration at run time.
4041
Additional profiles can be created within the Profiles folder following the sample profile syntax and the eventDefinitions.json events and attributes.
4142

4243
After configuring the application it is advised to run it and use the Streamlabs Test Widget option to send test events and confirm it behaves as you expect.
4344

44-
45+
Profile configuration files must be created with knowledge of quote escaping. The profile file is in the JSON syntax and so all text strings must be wrapped in double quotes `"` within it. If you want to use a duoble quote within a text string it must be escaped with a back slash `\`. Single quotes can be used fine within a JSON string and are advised for this reason. Data attributes will be made safe by the program; with any single or doube quotes either being removed by Python automatically or escaped with a backslash before being used as part of an rcon command. If you require a single or double quote to be recieved by Rcon escaped then you must escape it with 2 back slashes `\\'`. See the `Factorio - Advanced Usage Example.json` for examples of the some of these combinations.
4546

4647

4748
Development Building

Source/Config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ def _PopulateMissingConfigDefaults(self):
2525
"Factorio PlayerName": "",
2626
"Rcon Server Address": "",
2727
"Rcon Server Port": 25575,
28-
"Rcon Server Password": ""
28+
"Rcon Server Password": "",
29+
"Rcon Test Command": "/version"
2930
}
3031
for name, value in defaults.items():
3132
if not name in self.settings:

Source/Rcon.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ def __init__(self, state):
99
self.serverPort = self.state.config.GetSetting("Rcon Server Port")
1010
self.serverPassword = self.state.config.GetSetting(
1111
"Rcon Server Password")
12+
self.testCommand = self.state.config.GetSetting("Rcon Test Command")
1213

1314
def TestConnection(self):
1415
try:
15-
self.SendCommand('/version')
16+
self.SendCommand(self.testCommand)
1617
return True
1718
except Exception as ex:
1819
self.state.logging.RecordException(ex, "Rcon server test failed")
@@ -21,4 +22,4 @@ def TestConnection(self):
2122

2223
def SendCommand(self, commandString):
2324
with MCRcon(self.serverAddress, self.serverPassword, self.serverPort) as mcr:
24-
mcr.command(commandString)
25+
return mcr.command(commandString)

Source/Streamlabs Rcon Integration.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,21 +137,25 @@ def OnStreamlabsEventHandler(self, data):
137137
"No profile action for: " + event.GetEventRawTitlesAsPrettyString())
138138
return
139139
actionType = ""
140+
response = ""
140141
if actionText == "":
141142
actionType = "Ignore event"
142143
self.logging.DebugLog(
143144
"NOTHING action specified for: " + event.GetEventRawTitlesAsPrettyString())
144145
else:
145146
actionType = "Rcon command"
146147
try:
147-
self.rcon.SendCommand(actionText)
148+
response = self.rcon.SendCommand(actionText)
148149
except Exception as ex:
149150
self.logging.RecordException(ex, "Rcon event failed")
150151
self.RecordActivity(
151152
self.translations.currentTexts["Rcon CommandError"] + actionText)
152153
return
153154
self.RecordActivity(
154155
self.translations.currentTexts["StreamlabsEvent EventHandled"] + event.GetEventRawTitlesAsPrettyString() + " : " + event.bestName + " : value " + str(event.value) + " : " + actionType)
156+
if response != "":
157+
self.RecordActivity(
158+
self.translations.currentTexts["Rcon CommandResponseWarning"] + response)
155159
self.logging.DebugLog("Action done: " + actionText)
156160
except Exception as ex:
157161
self.logging.RecordException(

Source/StreamlabsEvent.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ def __init__(self, state, data):
4545
len(data["message"])))
4646
self.errored = True
4747
return
48-
message = data["message"][0]
49-
self.rawMessage = message
48+
rawMessage = data["message"][0]
49+
self.rawMessage = rawMessage
5050

5151
self.id = self.rawMessage["_id"]
5252
if "display_name" in self.rawMessage.keys():
@@ -196,7 +196,8 @@ def SubstituteEventDataIntoString(self, string, modValue="''"):
196196
dataKeyValue = self.bestComment
197197
elif dataKeyName in self.rawMessage:
198198
dataKeyValue = self.rawMessage[dataKeyName]
199-
string = string.replace(instance, str(dataKeyValue))
199+
string = string.replace(
200+
instance, StreamlabsEvent.EspaceStringForRcon(str(dataKeyValue)))
200201
return string
201202

202203
@staticmethod
@@ -238,3 +239,10 @@ def IsScriptValid(scriptString):
238239
except Exception:
239240
return "config value: " + scriptString + "\n" + Traceback.format_exc(limit=0, chain=False)
240241
return ""
242+
243+
@staticmethod
244+
def EspaceStringForRcon(text):
245+
text = text.replace("\\", "\\\\")
246+
text = text.replace("'", "\\'")
247+
text = text.replace('"', '\\"')
248+
return text

Source/Translations.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ def GetLocalisedTexts(self, language):
2727
"StreamlabsEvent UnrecognisedTwitchSubscriptionType": "ERROR: unrecognised twitch subscription type: ",
2828
"StreamlabsEvent NoProfileAction": "WARNING: no reaction found for event: ",
2929
"StreamlabsEvent EventHandled": "Event Handled: ",
30-
"Rcon CommandError": "ERROR: Rcon command failed, run manually: "
30+
"Rcon CommandError": "ERROR: Rcon command failed, run manually: ",
31+
"Rcon CommandResponseWarning": "WARNING: Rcon got response from server: "
3132
}

Source/config.sample.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
"Factorio PlayerName": "",
88
"Rcon Server Address": "",
99
"Rcon Server Port": 25575,
10-
"Rcon Server Password": ""
10+
"Rcon Server Password": "",
11+
"Rcon Test Command": "/version"
1112
}

ToDo.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
Make a settings manager GUI
22
Make a profile manager GUI
3-
Make so that profile startup errors are shown in a GUI and disable running until fixed.
3+
Make so that profile startup errors are shown in a GUI and disable running until fixed.
4+
Have seperate Activity and System (status, warning, errors) logs
5+
Have a way to pause logs from updating and then resume
6+
Add a way to fire test events data at this to allow better testing of responses than the Streamlabs Test Widgets button.

0 commit comments

Comments
 (0)