Skip to content

Commit

Permalink
Merge branch 'avasam-complete' of https://github.com/Toufool/Auto-Split
Browse files Browse the repository at this point in the history
… into complete
  • Loading branch information
Avasam committed Nov 26, 2021
2 parents 1999bf6 + 05f4c90 commit fc92197
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 28 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Easy to use image comparison based auto splitter for speedrunning on console or PC.

This program compares split images to a capture region of any window (OBS, Streamlabs, 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.), but can be integrated with LiveSplit. The purpose of this program is to remove the need to manually press your split hotkey and also increase the accuracy of your splits.
This program compares split images to a capture region of any window (OBS, Streamlabs, etc.) and automatically hits your split hotkey when there is a match. It can also be used to start and reset your timer, allowing for it to take full control of starting, splitting, and resetting your timer without ever having to touch a hotkey. It can be used in tandem with any speedrun timer that accepts hotkeys (LiveSplit, wsplit, etc.), but can be integrated with LiveSplit.

![Example](res/example1.6.0.gif)

Expand Down Expand Up @@ -73,14 +73,22 @@ This program compares split images to a capture region of any window (OBS, Strea

- Shows the highest similarity between the capture region and current split image.

### Similarity Threshold
### Current Similarity Threshold

- When the live similarity goes above this value, the program hits your split hotkey and moves to the next split image.

### Default Similarity Threshold

- This value will be set as the threshold for an image if there is no custom threshold set for that image.

### Pause Time

- Time in seconds that the program stops comparison after a split. Useful for if you have two of the same split images in a row and want to avoid double-splitting. Also useful for reducing CPU usage.

### Default Pause Time

- This value will be set as the Pause Time for an image if there is no custom Pause Time set for that image.

### Delay Time

- Time in milliseconds that the program waits before hitting the split hotkey for that specific split.
Expand Down Expand Up @@ -129,9 +137,9 @@ The start image is similar to the reset image. You can only have one start image

### Group dummy splits when undoing / skipping

If this option is disabled, AutoSplit will not account for dummy splits when undoing/skipping. Meaning it will cycle through ths splits normally even if they are dummy splits (this was the normal behavior in versions 1.2.0 and older).
If this option is disabled, AutoSplit will not account for dummy splits when undoing/skipping. Meaning it will cycle through the images normally even if they have the dummy flag `{d}` applied to them.

If it is enabled, AutoSplit will group dummy splits together with a real split when undoing/skipping. This basically allows you to tie one or more dummy splits to a real split to keep it in sync with LiveSplit/wsplit.
If it is enabled, AutoSplit will group dummy splits together with a real split when undoing/skipping. This basically allows you to tie one or more dummy splits to a real split to keep it as in sync as possible with the real splits in LiveSplit/wsplit.

Examples:
Given these splits: 1 dummy, 2 normal, 3 dummy, 4 dummy, 5 normal, 6 normal.
Expand All @@ -157,7 +165,6 @@ If this option is disabled, when the reset hotkey is hit, the reset button is pr
### Settings

- Settings files use the extension `.pkl`. Settings files can be saved and opened by using File -> Save Settings As... and File -> Load Settings. A settings file can be loaded upon opening AutoSplit if placed in the same directory as AutoSplit.exe.
- For v1.4 and below, settings work differently. Each time AutoSplit is closed, it saves a the setting file `settings.pkl` to the directory AutoSplit.exe is located in. This settings file must be in the same directory as AutoSplit.exe and is loaded upon opening the program. Settings can be reloaded using the Reload Settings button.
- 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.
- 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.

Expand Down
10 changes: 5 additions & 5 deletions res/design.ui
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,9 @@
<widget class="QPushButton" name="undosplitButton">
<property name="geometry">
<rect>
<x>480</x>
<x>494</x>
<y>250</y>
<width>71</width>
<width>64</width>
<height>24</height>
</rect>
</property>
Expand Down Expand Up @@ -961,14 +961,14 @@
<widget class="QLabel" name="imageloopLabel">
<property name="geometry">
<rect>
<x>380</x>
<x>379</x>
<y>252</y>
<width>108</width>
<width>113</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Image Loop #:</string>
<string>Image Loop:</string>
</property>
</widget>
<widget class="QLabel" name="pausehotkeyLabel">
Expand Down
48 changes: 33 additions & 15 deletions src/AutoSplit.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def run(self):
self.setpausehotkeyButton.clicked.connect(self.setPauseHotkey)
self.alignregionButton.clicked.connect(self.alignRegion)
self.selectwindowButton.clicked.connect(self.selectWindow)
self.startImageReloadButton.clicked.connect(lambda: self.loadStartImage(True, False))
self.startImageReloadButton.clicked.connect(lambda: self.loadStartImage(True, True))

# update x, y, width, and height when changing the value of these spinbox's are changed
self.xSpinBox.valueChanged.connect(self.updateX)
Expand Down Expand Up @@ -217,7 +217,7 @@ def run(self):
self.check_start_image_timestamp = 0.0

# Try to load start image
self.loadStartImage(wait_for_delay=False)
self.loadStartImage()

# FUNCTIONS

Expand Down Expand Up @@ -323,16 +323,15 @@ def loadStartImage(self, started_by_button=False, wait_for_delay=True):
self.start_image = cv2.resize(self.start_image, COMPARISON_RESIZE)

start_image_pause = split_parser.pause_from_filename(self.start_image_name)
if wait_for_delay and start_image_pause is not None and start_image_pause > 0:
if not wait_for_delay and start_image_pause is not None and start_image_pause > 0:
self.check_start_image_timestamp = time.time() + start_image_pause
self.startImageLabel.setText("Start image: paused")
self.currentSplitImage.setText('none (paused)')
self.highestsimilarityLabel.setText(' ')
self.currentsimilaritythresholdnumberLabel.setText(' ')
else:
self.check_start_image_timestamp = 0.0
self.startImageLabel.setText("Start image: ready")
self.updateSplitImage(self.start_image_name, from_load_start_image=True)
self.updateSplitImage(self.start_image_name, from_start_image=True)

self.highest_similarity = 0.0
self.start_image_split_below_threshold = False
Expand All @@ -343,12 +342,15 @@ def loadStartImage(self, started_by_button=False, wait_for_delay=True):
def startImageFunction(self):
if time.time() < self.check_start_image_timestamp \
or (not self.splitLineEdit.text() and not self.is_auto_controlled):
pause_time_left = "{:.1f}".format(self.check_start_image_timestamp - time.time())
self.currentSplitImage.setText(f'None\n (Paused before loading Start Image).\n {pause_time_left} sec remaining')
self.currentSplitImage.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
return

if self.check_start_image_timestamp > 0:
self.check_start_image_timestamp = 0.0
self.startImageLabel.setText("Start image: ready")
self.updateSplitImage(self.start_image_name)
self.updateSplitImage(self.start_image_name, from_start_image=True)

capture = self.getCaptureForComparison()
start_image_similarity = self.compareImage(self.start_image, self.start_image_mask, capture)
Expand Down Expand Up @@ -390,10 +392,20 @@ def split():
self.startAutoSplitter()

self.timerStartImage.stop()
self.startImageLabel.setText("Start image: started")

self.start_image_split_below_threshold = False
threading.Timer(start_image_delay / 1000, split).start()

# delay start image if needed
if start_image_delay > 0:
self.currentSplitImage.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.startImageLabel.setText("Start image: delaying start...")
delay_start_time = time.time()
while time.time() - delay_start_time < (start_image_delay / 1000):
delay_time_left = round((start_image_delay / 1000) - (time.time() - delay_start_time), 1)
self.currentSplitImage.setText(f'Delayed Before Starting:\n {delay_time_left} sec remaining')
QtTest.QTest.qWait(1)

self.startImageLabel.setText("Start image: started")
split()

# update x, y, width, height when spinbox values are changed
def updateX(self):
Expand Down Expand Up @@ -498,6 +510,9 @@ def is_current_split_out_of_range(self):
def undoSplit(self):
# Can't undo until timer is started
# or Undoing past the first image
if self.startautosplitterButton.text() == 'Start Auto Splitter' or ("Delayed Split") in self.currentSplitImage.text():
return

if (not self.undosplitButton.isEnabled() and not self.is_auto_controlled) \
or self.is_current_split_out_of_range():
return
Expand All @@ -519,6 +534,9 @@ def undoSplit(self):
def skipSplit(self):
# Can't skip or split until timer is started
# or Splitting/skipping when there are no images left
if self.startautosplitterButton.text() == 'Start Auto Splitter' or ("Delayed Split") in self.currentSplitImage.text():
return

if (not self.skipsplitButton.isEnabled() and not self.is_auto_controlled) or self.is_current_split_out_of_range():
return

Expand Down Expand Up @@ -855,7 +873,7 @@ def autoSplitter(self):
if self.number_of_split_images != self.split_image_number:
# set current split image to none
self.currentsplitimagefileLabel.setText(' ')
self.imageloopLabel.setText('Image Loop # -')
self.imageloopLabel.setText('Image Loop: -')

if not self.is_auto_controlled:
# if its the last split image and last loop number, disable the skip split button
Expand Down Expand Up @@ -928,7 +946,7 @@ def guiChangesOnStart(self):

def guiChangesOnReset(self):
self.startautosplitterButton.setText('Start Auto Splitter')
self.imageloopLabel.setText("Image Loop # -")
self.imageloopLabel.setText('Image Loop: -')
self.currentSplitImage.setText(' ')
self.currentsplitimagefileLabel.setText(' ')
self.livesimilarityLabel.setText(' ')
Expand Down Expand Up @@ -1046,7 +1064,7 @@ def removeStartAutoSplitterImage(self):

self.split_image_filenames.remove(start_auto_splitter_image_file)

def updateSplitImage(self, custom_image_file: str = '', from_load_start_image: bool = False):
def updateSplitImage(self, custom_image_file: str = '', from_start_image: bool = False):
# Splitting/skipping when there are no images left or Undoing past the first image
# Start image is expected to be out of range (index 0 of 0-length array)
if "START_AUTO_SPLITTER" not in custom_image_file.upper() and self.is_current_split_out_of_range():
Expand Down Expand Up @@ -1115,11 +1133,11 @@ def updateSplitImage(self, custom_image_file: str = '', from_load_start_image: b
self.split_delay = split_parser.delay_from_filename(split_image_file)

# Set Image Loop #
if not from_load_start_image:
if not from_start_image:
loop_tuple = self.split_image_filenames_and_loop_number[self.split_image_number]
self.imageloopLabel.setText(f"Image Loop # {loop_tuple[1]}/{loop_tuple[2]}")
self.imageloopLabel.setText(f"Image Loop: {loop_tuple[1]}/{loop_tuple[2]}")
else:
self.imageloopLabel.setText("Image Loop # 1/1")
self.imageloopLabel.setText("Image Loop: 1/1")

# need to set split below threshold to false each time an image updates.
self.split_below_threshold = False
Expand Down
6 changes: 3 additions & 3 deletions src/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def setupUi(self, MainWindow):
self.resetButton.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.resetButton.setObjectName("resetButton")
self.undosplitButton = QtWidgets.QPushButton(self.centralwidget)
self.undosplitButton.setGeometry(QtCore.QRect(480, 250, 71, 24))
self.undosplitButton.setGeometry(QtCore.QRect(494, 250, 64, 24))
self.undosplitButton.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.undosplitButton.setObjectName("undosplitButton")
self.skipsplitButton = QtWidgets.QPushButton(self.centralwidget)
Expand Down Expand Up @@ -279,7 +279,7 @@ def setupUi(self, MainWindow):
self.selectwindowButton.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
self.selectwindowButton.setObjectName("selectwindowButton")
self.imageloopLabel = QtWidgets.QLabel(self.centralwidget)
self.imageloopLabel.setGeometry(QtCore.QRect(380, 252, 108, 20))
self.imageloopLabel.setGeometry(QtCore.QRect(379, 252, 113, 20))
self.imageloopLabel.setObjectName("imageloopLabel")
self.pausehotkeyLabel = QtWidgets.QLabel(self.centralwidget)
self.pausehotkeyLabel.setGeometry(QtCore.QRect(230, 418, 31, 16))
Expand Down Expand Up @@ -482,7 +482,7 @@ def retranslateUi(self, MainWindow):
self.alignregionButton.setText(_translate("MainWindow", "Align Region"))
self.groupDummySplitsCheckBox.setText(_translate("MainWindow", "Group dummy splits when undoing/skipping"))
self.selectwindowButton.setText(_translate("MainWindow", "Select Window"))
self.imageloopLabel.setText(_translate("MainWindow", "Image Loop #:"))
self.imageloopLabel.setText(_translate("MainWindow", "Image Loop:"))
self.pausehotkeyLabel.setText(_translate("MainWindow", "Pause"))
self.setpausehotkeyButton.setText(_translate("MainWindow", "Set Hotkey"))
self.loopCheckBox.setText(_translate("MainWindow", "Loop Split Images"))
Expand Down

0 comments on commit fc92197

Please sign in to comment.