Skip to content

Commit 336a96c

Browse files
committed
Support LiveSplit integration with start and reset image
1 parent 89fd6e2 commit 336a96c

File tree

6 files changed

+75
-102
lines changed

6 files changed

+75
-102
lines changed

README.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# <img src="https://raw.githubusercontent.com/Avasam/Auto-Split/main/res/icon.ico" alt="LiveSplit" height="42" width="45" align="top"/> AutoSplit
1+
# <img src="https://raw.githubusercontent.com/TouFool/Auto-Split/master/res/icon.ico" alt="LiveSplit" height="42" width="45" align="top"/> AutoSplit
22

33
This program compares split images to a capture region of any window (OBS, xsplit, etc.) and automatically hits your split hotkey when there is a match. It can be used in tandem with any speedrun timer that accepts hotkeys (LiveSplit, wsplit, etc.). The purpose of this program is to remove the need to manually press your split hotkey and also increase the accuracy of your splits.
44

@@ -14,14 +14,14 @@ This program compares split images to a capture region of any window (OBS, xspli
1414

1515
### Opening the program
1616

17-
- Download the [latest version](/Toufool/Auto-Split/releases)
17+
- Download the [latest version](/../../releases)
1818
- Extract the file and open AutoSplit.exe.
1919

2020
### Building
2121

2222
(This is not required for normal use)
2323

24-
- Microsoft Visual C++ 14.0 or greater may be required. Get it with [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
24+
- Microsoft Visual C++ 14.0 or greater may be required. Get it with [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
2525
- Read [requirements.txt](/scripts/requirements.txt) for information on how to run/build the python code
2626
- Run `.\scripts\install.bat` to install all dependencies
2727
- Run the app directly with `py .\src\AutoSplit.py`
@@ -34,7 +34,7 @@ This program compares split images to a capture region of any window (OBS, xspli
3434
- Images can be any size.
3535
- Images are matched in alphanumerical order.
3636
- Recommended filenaming convention: `001_SplitName.png, 002_SplitName.png, 003_SplitName.png`...
37-
- Custom split image settings are handled in the filename. See how [here](https://github.com/Toufool/Auto-Split#custom-split-image-settings).
37+
- Custom split image settings are handled in the filename. See how [here](#custom-split-image-settings).
3838
- Images can be created using Print Screen, [Snipping Tool](https://support.microsoft.com/en-us/help/4027213/windows-10-open-snipping-tool-and-take-a-screenshot), or AutoSplit's Take Screenshot button.
3939

4040
## Capture Region
@@ -86,8 +86,8 @@ This program compares split images to a capture region of any window (OBS, xspli
8686

8787
- Each split image can have different thresholds, pause times, delay split times, loop amounts, and can be flagged.
8888
- These settings are handled in the image's filename.
89-
- Custom thresholds are place between parenthesis `()` in the filename and the custom thresholds checkbox must be checked. All images must have a custom threshold if the box is checked.
90-
- Custom pause times are placed between square brackets `[]` in the filename and the custom pause times checkbox must be checked. All images must have a custom threshold if the box is checked.
89+
- Custom thresholds are place between parenthesis `()` in the filename. This value will override the default threshold.
90+
- Custom pause times are placed between square brackets `[]` in the filename. This value will override the default pause time.
9191
- Custom delay times are placed between hash signs `##` in the filename. Note that these are in milliseconds. For example, a 10 second split delay would be `#10000#`. You cannot skip or undo splits during split delays.
9292
- Image loop amounts are placed between at symbols `@@` in the filename. For example, a specific image that you want to split 5 times in a row would be `@5@`. The current loop # is conveniently located beneath the current split image.
9393
- Flags are placed between curly brackets `{}` in the filename. Multiple flags are placed in the same set of curly brackets. Current available flags:
@@ -103,13 +103,19 @@ This program compares split images to a capture region of any window (OBS, xspli
103103

104104
### How to Create a Masked Image
105105

106+
Masked images are very useful if only a certain part of the capture region is consistent (for example, consistent text on the screen, but the background is always different). Histogram or L2 norm comparison is recommended if you use any masked images. It is highly recommended that you do NOT use pHash comparison if you use any masked images, as it is very inaccurate.
107+
106108
The best way to create a masked image is to set your capture region as the entire game screen, take a screenshot, and use a program like [paint.net](https://www.getpaint.net/) to "erase" (make transparent) everything you don't want the program to compare. More on how to creating images with transparency using paint.net can be found in [this tutorial](https://www.youtube.com/watch?v=v53kkUYFVn8). For visualization, here is what the capture region compared to a masked split image looks like if you would want to split on "Shine Get!" text in Super Mario Sunshine:
107109

108110
![Mask Example](res/mask_example_image.PNG)
109111

110112
### Reset image
111113

112-
You can have one (and only one) image with the keyword `reset` in its name. AutoSplit will press the reset button when it finds this image. This image will only be used for resets and it will not be tied to any split. You can set a probability and pause time for it. A custom threshold MUST be applied to this image. The pause time is the amount of seconds AutoSplit will wait before checking for the reset image once the run starts. Also the image can be masked, for example: `Reset_(0.95)_[10].png`.
114+
You can have one (and only one) image with the keyword `reset` in its name. AutoSplit will press the reset button when it finds this image. This image will only be used for resets and it will not be tied to any split. You can set a probability and pause time for it. The pause time is the amount of seconds AutoSplit will wait before checking for the reset image once the run starts. For example: `Reset_(0.95)_[10].png`.
115+
116+
### Start image
117+
118+
The start image is similar to the reset image. You can only have one start image with the keyword `start_auto_splitter`.You can reload the image using the "`Reload Start Image`" button. The pause time is the amount of seconds AutoSplit will wait before checking for the start image once a run ends/is reset.
113119

114120
### Timer Global Hotkeys
115121

@@ -154,22 +160,27 @@ If this option is disabled, when the reset hotkey is hit, the reset button is pr
154160
- The settings in the settings file include split image directory, capture region, capture region dimensions, fps limit, threshold and pause time settings, all hotkeys, "Group dummy splits when undoing/skipping" check box, "Loop Split Images" check box, and "Auto Start On Reset" check box.
155161
- If you are upgrading to Windows 11, it's possible that save files may not transfer perfectly. You may need to readjust or reselect your Capture Region, for example.
156162

163+
## LiveSplit integration
164+
165+
There is a LiveSplit Component available that will directly connect AutoSplit with LiveSplit. You can get it [here](/KaDiWa4/LiveSplit.AutoSplitIntegration).
166+
157167
## Known Limitations
158168

159169
- For many games, it will be difficult to find a split image for the last split of the run.
160170
- The window of the capture region cannot be minimized.
161171

162172
## Resources
163173

164-
- Still need help? [Open an issue](https://github.com/Toufool/Auto-Split/issues)
174+
- Still need help? [Open an issue](../../issues)
165175
- Join the [AutoSplit Discord](https://discord.gg/Qcbxv9y)
166176

167177
## Credits
168178

169-
- <https://github.com/harupy/> for the snipping tool code that I used to integrate into the autosplitter.
179+
- [Harutaka Kawamura](https://github.com/harupy/) for the snipping tool code that I used to integrate into the autosplitter.
170180
- [amaringos](https://twitter.com/amaringos) for the icon.
171181
- [ZanasoBayncuh](https://twitter.com/ZanasoBayncuh) for motivating me to start this project back up and for all of the time spent testing and suggesting improvements.
172182
- [Avasam](https://twitter.com/Avasam06) for their continued work on making an incredible amount of improvements and changes to AutoSplit while I have not had the time/motivation to do so.
183+
- [KaDiWa](https://github.com/KaDiWa4) for the LiveSplit integration.
173184
- Created by [Toufool](https://twitter.com/Toufool) and [Faschz](https://twitter.com/faschz).
174185

175186
## Donate

scripts/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# Python: CPython 3.9+
44
#
5-
# Usage: .scripts/install.bat
5+
# Usage: ./scripts/install.bat
66
#
77
# If you're having issues with the libraries, you might want to first run:
88
# pip3.9 uninstall -r requirements.txt

src/AutoSplit.py

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import threading
1414
import time
1515

16-
from hotkeys import send_hotkey
1716
from menu_bar import about, VERSION, viewHelp
1817
import error_messages
1918
import compare
@@ -23,6 +22,7 @@
2322

2423

2524
class AutoSplit(QtWidgets.QMainWindow, design.Ui_MainWindow):
25+
from hotkeys import send_command
2626
from settings_file import saveSettings, saveSettingsAs, loadSettings, haveSettingsChanged, getSaveSettingsValues
2727
from screen_region import selectRegion, selectWindow, alignRegion
2828
from hotkeys import afterSettingHotkey, setSplitHotkey, setResetHotkey, setSkipSplitHotkey, setUndoSplitHotkey, setPauseHotkey
@@ -341,7 +341,7 @@ def startImageFunction(self):
341341
or (start_image_similarity >= start_image_threshold and start_image_flags & 0x04 == 0):
342342
def split():
343343
self.hasSentStart = False
344-
send_hotkey(self.splitLineEdit.text())
344+
self.send_command("start")
345345
time.sleep(1 / self.fpslimitSpinBox.value())
346346
self.startAutoSplitter()
347347

@@ -470,7 +470,7 @@ def checkFPS(self):
470470

471471
# undo split button and hotkey connect to here
472472
def undoSplit(self):
473-
if self.undosplitButton.isEnabled() == False and self.is_auto_controlled == False:
473+
if self.undosplitButton.isEnabled() == False and not self.is_auto_controlled:
474474
return
475475

476476
if self.loop_number != 1 and self.groupDummySplitsCheckBox.isChecked() == False:
@@ -493,7 +493,7 @@ def undoSplit(self):
493493
# skip split button and hotkey connect to here
494494
def skipSplit(self):
495495

496-
if self.skipsplitButton.isEnabled() == False and self.is_auto_controlled == False:
496+
if self.skipsplitButton.isEnabled() == False and not self.is_auto_controlled:
497497
return
498498

499499
if self.loop_number < self.split_image_loop_amount[self.split_image_number] and self.groupDummySplitsCheckBox.isChecked() == False:
@@ -577,26 +577,24 @@ def autoSplitter(self):
577577
# according to all of the settings selected by the user.
578578
for image in self.split_image_filenames:
579579
# Test for image without transparency
580-
if cv2.imread(self.split_image_directory + image, cv2.IMREAD_COLOR) is None:
581-
# Test for image with transparency
582-
if cv2.imread(self.split_image_directory + image, cv2.IMREAD_UNCHANGED) is None:
583-
# Opencv couldn't open this file as an image, this isn't a correct
584-
# file format that is supported
585-
self.guiChangesOnReset()
586-
error_messages.imageTypeError(image)
587-
return
588-
else:
589-
# TODO: Now that we know the image has transparency, error out if it is completely transparent
590-
# Will fix https://github.com/Toufool/Auto-Split/issues/52
591-
pass
580+
if (cv2.imread(self.split_image_directory + image, cv2.IMREAD_COLOR) is None
581+
# Test for image with transparency
582+
and cv2.imread(self.split_image_directory + image, cv2.IMREAD_UNCHANGED) is None):
583+
# Opencv couldn't open this file as an image, this isn't a correct
584+
# file format that is supported
585+
self.guiChangesOnReset()
586+
error_messages.imageTypeError(image)
587+
return
592588

593-
#error out if there is a {p} flag but no pause hotkey set.
594-
if self.pausehotkeyLineEdit.text() == '' and split_parser.flags_from_filename(image) & 0x08 == 0x08 and self.is_auto_controlled == False:
589+
# error out if there is a {p} flag but no pause hotkey set and is not auto controlled.
590+
if (self.pausehotkeyLineEdit.text() == ''
591+
and split_parser.flags_from_filename(image) & 0x08 == 0x08
592+
and not self.is_auto_controlled):
595593
self.guiChangesOnReset()
596594
error_messages.pauseHotkeyError()
597595
return
598596

599-
if self.splitLineEdit.text() == '' and self.is_auto_controlled == False:
597+
if self.splitLineEdit.text() == '' and not self.is_auto_controlled:
600598
self.guiChangesOnReset()
601599
error_messages.splitHotkeyError()
602600
return
@@ -612,8 +610,8 @@ def autoSplitter(self):
612610
error_messages.multipleKeywordImagesError('reset')
613611
return
614612

615-
# If there is no reset hotkey set but a reset image is present, throw an error.
616-
if self.resetLineEdit.text() == '' and self.reset_image is not None and self.is_auto_controlled == False:
613+
# If there is no reset hotkey set but a reset image is present, and is not auto controlled, throw an error.
614+
if self.resetLineEdit.text() == '' and self.reset_image is not None and not self.is_auto_controlled:
617615
self.guiChangesOnReset()
618616
error_messages.resetHotkeyError()
619617
return
@@ -689,11 +687,7 @@ def autoSplitter(self):
689687
if self.shouldCheckResetImage():
690688
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
691689
if reset_similarity >= self.reset_image_threshold:
692-
if self.is_auto_controlled:
693-
print("reset", flush = True)
694-
else:
695-
send_hotkey(self.resetLineEdit.text())
696-
self.reset()
690+
self.send_command("reset")
697691

698692
if self.checkForReset():
699693
return
@@ -722,7 +716,7 @@ def autoSplitter(self):
722716
else:
723717
self.highestsimilarityLabel.setText(' ')
724718

725-
if self.is_auto_controlled == False:
719+
if not self.is_auto_controlled:
726720
# if its the last split image and last loop number, disable the skip split button
727721
if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
728722
self.skipsplitButton.setEnabled(False)
@@ -787,10 +781,7 @@ def autoSplitter(self):
787781

788782
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
789783
if reset_similarity >= self.reset_image_threshold:
790-
if self.is_auto_controlled:
791-
print("reset", flush = True)
792-
else:
793-
send_hotkey(self.resetLineEdit.text())
784+
self.send_command("reset")
794785
self.reset()
795786
continue
796787

@@ -800,15 +791,9 @@ def autoSplitter(self):
800791

801792
# if {p} flag hit pause key, otherwise hit split hotkey
802793
if (self.flags & 0x08 == 0x08):
803-
if self.is_auto_controlled:
804-
print("pause", flush = True)
805-
else:
806-
send_hotkey(self.pausehotkeyLineEdit.text())
794+
self.send_command("pause")
807795
else:
808-
if self.is_auto_controlled:
809-
print("split", flush = True)
810-
else:
811-
send_hotkey(self.splitLineEdit.text())
796+
self.send_command("split")
812797

813798
# increase loop number if needed, set to 1 if it was the last loop.
814799
if self.loop_number < self.split_image_loop_amount[self.split_image_number]:
@@ -837,7 +822,7 @@ def autoSplitter(self):
837822
self.currentSplitImage.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
838823
self.imageloopLabel.setText('Image Loop #: -')
839824

840-
if self.is_auto_controlled == False:
825+
if not self.is_auto_controlled:
841826
# if its the last split image and last loop number, disable the skip split button
842827
if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
843828
self.skipsplitButton.setEnabled(False)
@@ -875,7 +860,7 @@ def autoSplitter(self):
875860

876861
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
877862
if reset_similarity >= self.reset_image_threshold:
878-
send_hotkey(self.resetLineEdit.text())
863+
self.send_command("reset")
879864
self.reset()
880865
continue
881866

@@ -892,7 +877,7 @@ def guiChangesOnStart(self):
892877
self.groupDummySplitsCheckBox.setEnabled(False)
893878
self.startImageReloadButton.setEnabled(False)
894879

895-
if self.is_auto_controlled == False:
880+
if not self.is_auto_controlled:
896881
self.startautosplitterButton.setEnabled(False)
897882
self.resetButton.setEnabled(True)
898883
self.undosplitButton.setEnabled(True)
@@ -917,7 +902,7 @@ def guiChangesOnReset(self):
917902
self.groupDummySplitsCheckBox.setEnabled(True)
918903
self.startImageReloadButton.setEnabled(True)
919904

920-
if self.is_auto_controlled == False:
905+
if not self.is_auto_controlled:
921906
self.startautosplitterButton.setEnabled(True)
922907
self.resetButton.setEnabled(False)
923908
self.undosplitButton.setEnabled(False)

src/AutoSplit.spec

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/hotkeys.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,22 @@ def is_digit(key):
3939
return False
4040

4141

42+
def send_command(self, command):
43+
if self.is_auto_controlled:
44+
print(command, flush=True)
45+
else:
46+
if command == "split" or command == "start":
47+
_send_hotkey(self.splitLineEdit.text())
48+
elif command == "pause":
49+
_send_hotkey(self.pausehotkeyLineEdit.text())
50+
elif command == "reset":
51+
_send_hotkey(self.resetLineEdit.text())
52+
else:
53+
raise KeyError(f"'{command}' is not a valid LiveSplit.AutoSplitIntegration command")
54+
55+
4256
# Supports sending the appropriate scan code for all the special cases
43-
def send_hotkey(key_or_scan_code):
57+
def _send_hotkey(key_or_scan_code):
4458
hotkey_type = type(key_or_scan_code)
4559

4660
# Deal with regular inputs

0 commit comments

Comments
 (0)