Last active
August 29, 2021 02:01
-
-
Save sheeperino/a60c03af87144bd0f67dfb13e5e92c5f to your computer and use it in GitHub Desktop.
Custom Pigeon Macro pre1.9
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; Pre 1.9 RSG Multi Instance Macro, Created by FinestPigeon. Coding help from: Peej, ScarRuns, Specnr, and Four. | |
; ***READ*** (common issues that need to be addressed) | |
; Sometimes a clogged saves folder can make it so the GUI seems "Too slow for the macro" If this happens, clear your saves folders | |
; You will most likley need to have 2 OBS' running to ensure verification. 1 OBS with Display Capture (For streams and main recordings), And a second with 4 Game Captures running on the same screen. | |
; An example of my OBS setups, Main OBS: https://imgur.com/a/55yuwxS | Verification OBS: https://imgur.com/a/rw5agz1 | |
; An example of how i set up my verification OBS: https://youtu.be/Nmsanpob7C0 | |
; If you use a custom texture pack, make sure the title screen's splash text color is default (Yellow). This is used in the macro to make sure you are in the title screen before creating the world | |
; If you have any other questions/concerns, message me on discord. FinestPigeon#8738 | |
#NoEnv | |
#SingleInstance, force | |
Process, Priority, , A | |
; Options: | |
global savesDirectories := ["C:\Users\Sophie\Desktop\MultiMC\instances\1.7.21\.minecraft\saves\","C:\Users\Sophie\Desktop\MultiMC\instances\1.7.22\.minecraft\saves\"] | |
global oldWorldsFolder := "C:\Users\Sophie\Desktop\MultiMC\instances\1.7.21\.minecraft\oldWorlds\" | |
global KeyDelay := 10 ; Delay between each keypress | |
global HardcoreDelay := 50 ; Delay to ensure you activate hardcore | |
global SaveAndQuitDelay := 100 ; The amount of time between the macro pressing "Escape" and it pressing "SaveAndQuit". If you are experiencing crashes, Increase this number | |
global obsDelay := 50 ; Delay for obs scene switching | |
global liveSplitStart := "Numpad5" ; The key that starts your LiveSplit timer, Preferably use a function key | |
global liveSplitReset := "Numpad6" ; The key that resets yourLiveSplit timer, Preferably use a function key | |
global hardcore := "Yes" ; Change this to "Yes" if you play Hardcore mode | |
; edit at your own risk | |
global GUIscale := getGUIscale() | |
OutputDebug, gui scale: %GUIscale% | |
global instances := savesDirectories.MaxIndex() | |
OutputDebug, number of instances: %instances% | |
global PIDs := SetupPIDs() | |
global currInst := -1 | |
global titles := [] | |
tmptitle := "" | |
for i, tmppid in PIDs{ | |
WinGetTitle, tmptitle, ahk_pid %tmppid% | |
titles.Push(tmptitle) | |
} | |
SetDefaultMouseSpeed, 0 | |
SetMouseDelay, -1 | |
SetKeyDelay, -1 | |
SetTitleMatchMode, 2 | |
IfNotExist, %oldWorldsFolder% | |
FileCreateDir %oldWorldsFolder% | |
SleepGUI(time) | |
{ | |
DllCall("Sleep",UInt,time) | |
} | |
Main() { | |
SendInput, {%liveSplitReset%} | |
ExitWorld() | |
Loop, | |
{ | |
PixelSearch, Px, Py, 0, 0, 1920, 1080, 0xFFFF00, 0, Fast RGB | |
if (!ErrorLevel) | |
Break | |
} | |
EnterSinglePlayer() | |
Loop, | |
{ | |
PixelSearch, Px, Py, 0, 0, 1920, 1080, 0xA0A0A0, 0, Fast RGB | |
if (!ErrorLevel) | |
Break | |
} | |
OutputDebug, in world list | |
CreateWorld() | |
if (idx := GetActiveInstanceNum()) > 0 | |
{ | |
nextIdx := Mod(idx, instances) + 1 | |
SwitchInstance(nextIdx) | |
MoveWorlds(idx) | |
} | |
} | |
RunHide(Command) | |
{ | |
OutputDebug, runhide | |
dhw := A_DetectHiddenWindows | |
DetectHiddenWindows, On | |
Run, %ComSpec%,, Hide, cPid | |
WinWait, ahk_pid %cPid% | |
DetectHiddenWindows, %dhw% | |
DllCall("AttachConsole", "uint", cPid) | |
Shell := ComObjCreate("WScript.Shell") | |
Exec := Shell.Exec(Command) | |
Result := Exec.StdOut.ReadAll() | |
DllCall("FreeConsole") | |
Process, Close, %cPid% | |
Return Result | |
} | |
EnterSinglePlayer() | |
{ | |
; Sleep MenuDelay | |
OutputDebug, in title screen | |
if (GUIscale = "Auto") { | |
SleepGUI(KeyDelay) | |
MouseClick, Left, 950, 500 | |
SleepGUI(KeyDelay) | |
} | |
else if (GUIscale = "Small") { | |
SleepGUI(KeyDelay) | |
MouseClick, Left, 1150, 560 | |
SleepGUI(KeyDelay) | |
} | |
else if (GUIscale = "Normal") { | |
SleepGUI(KeyDelay) | |
MouseClick, Left, 960, 390 | |
SleepGUI(KeyDelay) | |
} | |
else if (GUIscale = "Large") { | |
SleepGUI(KeyDelay) | |
MouseClick, Left, 650, 380 | |
SleepGUI(KeyDelay) | |
} | |
} | |
ExitWorld() | |
{ | |
if (guiScale = "Auto") | |
{ | |
Send, {Escape} | |
SleepGUI(SaveAndQuitDelay) | |
MouseClick, Left, 960, 720 | |
} | |
else if (guiScale = "Large") | |
{ | |
Send, {Escape} | |
SleepGUI(SaveAndQuitDelay) | |
MouseClick, Left, 650, 550 | |
} | |
else if (guiScale = "Normal") | |
{ | |
Send, {Escape} | |
SleepGUI(SaveAndQuitDelay) | |
MouseClick, Left, 960, 500 | |
} | |
else if (guiScale = "Small") | |
{ | |
Send, {Escape} | |
SleepGUI(SaveAndQuitDelay) | |
MouseClick, Left, 960, 385 | |
} | |
OutputDebug, exited world | |
} | |
CreateWorld() | |
{ | |
if (guiScale = "Auto") | |
{ | |
MouseClick, Left, 1270, 910 | |
if (hardcore = "Yes"){ | |
SleepGUI(HardcoreDelay) | |
MouseClick, Left, 950, 500 | |
SleepGUI(HardcoreDelay) | |
} | |
} | |
else if (guiScale = "Large") | |
{ | |
MouseClick, Left, 1000, 620 | |
if (hardcore = "Yes"){ | |
SleepGUI(HardcoreDelay) | |
MouseClick, Left, 650, 380 | |
SleepGUI(HardcoreDelay) | |
} | |
} | |
else if (guiScale = "Normal") | |
{ | |
MouseClick, Left, 1118, 1000 | |
if (hardcore = "Yes"){ | |
SleepGUI(HardcoreDelay) | |
MouseClick, Left, 960, 250 | |
SleepGUI(HardcoreDelay) | |
} | |
} | |
else if (guiScale = "Small") | |
{ | |
MouseClick, Left, 1150, 800 | |
if (hardcore = "Yes"){ | |
SleepGUI(HardcoreDelay) | |
MouseClick, Left, 1150, 580 | |
SleepGUI(HardcoreDelay) | |
} | |
} | |
SleepGUI(KeyDelay) | |
Send, {Enter} | |
OutputDebug, might have created a world | |
} | |
MoveWorlds(idx) | |
{ | |
dir := SavesDirectories[idx] | |
Loop, Files, %dir%*, D | |
{ | |
If (InStr(A_LoopFileName, "New World")) | |
FileMoveDir, %dir%%A_LoopFileName%, %oldWorldsFolder%%A_LoopFileName%%A_NowUTC%Instance %idx%, R | |
} | |
} | |
CheckJoined(idx) | |
{ | |
rawLogFile := StrReplace(savesDirectories[idx], "saves", "logs\latest.log") | |
StringTrimRight, logFile, rawLogFile, 1 | |
numLines := 0 | |
Loop, Read, %logFile% | |
{ | |
numLines += 1 | |
} | |
joined := False | |
startTime := A_TickCount | |
Loop, Read, %logFile% | |
{ | |
if ((numLines - A_Index) < 1) | |
{ | |
if (InStr(A_LoopReadLine, "joined the game")) { | |
joined := True | |
break | |
} | |
} | |
} | |
return joined | |
} | |
getGUIscale() | |
{ | |
optionsFile := StrReplace(savesDirectories[1], "saves\", "options.txt") | |
FileReadLine, guiScaleLine, %optionsFile%, 7 | |
if InStr(guiScaleLine, 1) | |
return "Small" | |
else if InStr(guiScaleLine, 2) | |
return "Normal" | |
else if InStr(guiScaleLine, 3) | |
return "Large" | |
else | |
return "Auto" | |
} | |
GetInstanceNum(pid) | |
{ | |
command := Format("powershell.exe $x = Get-WmiObject Win32_Process -Filter \""ProcessId = {1}\""; $x.CommandLine", pid) | |
rawOut := RunHide(command) | |
for i, savesDir in SavesDirectories { | |
if (InStr(savesDir, ".minecraft")) { | |
StringTrimRight, tmp, savesDir, 18 | |
tmp := StrReplace(tmp, "\", "/") | |
OutputDebug, %tmp% | |
} | |
Else | |
StringTrimRight, tmp, savesDir, 7 | |
if (InStr(rawOut, tmp)) | |
return i | |
} | |
return -1 | |
} | |
GetActiveInstanceNum() { | |
WinGet, pid, PID, A | |
WinGetTitle, title, ahk_pid %pid% | |
for i, tmppid in PIDs { | |
if (tmppid == pid) | |
return i | |
} | |
} | |
SwitchInstance(idx) | |
{ | |
#WinActivateForce | |
currInst := idx | |
pid := PIDs[idx] | |
WinActivate, ahk_pid %pid% | |
send {esc} | |
sleep, 50 | |
send {Numpad%idx% down} | |
sleep, 50 | |
send {Numpad%idx% up} | |
} | |
SetupPIDs() | |
{ | |
OutputDebug, setting up pids | |
orderedPIDs := [] | |
loop, %instances% | |
orderedPIDs.Push(-1) | |
WinGet, all, list | |
Loop, %all% | |
{ | |
WinGet, pid, PID, % "ahk_id " all%A_Index% | |
WinGetTitle, title, ahk_pid %pid% | |
if (InStr(title, "Minecraft 1.") || InStr(title, "Instance") && !InStr(title, "Not Responding")) | |
Output .= pid "`n" | |
} | |
tmpPids := StrSplit(Output, "`n") | |
for i, pid in tmpPids { | |
if (pid) { | |
inst := GetInstanceNum(pid) | |
OutputDebug, instance num: %inst% | |
orderedPIDs[inst] := pid | |
} | |
} | |
return orderedPIDs | |
} | |
SetTitles() { | |
for i, pid in PIDs { | |
WinSetTitle, ahk_pid %pid%, , Minecraft - Instance %i% Singleplayer | |
OutputDebug, %i% | |
OutputDebug, %pid% | |
} | |
} | |
#:: | |
SetTitles() | |
return | |
*CapsLock:: ; The keybind for exiting a world, creating world, switching instances | |
Main() | |
return |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Changelog
v0.4:
v0.3:
v0.2:
v0.1:
v0.0.2:
v0.0.1: