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

Commit 05fd359

Browse files
FromDarkHellFromDarkHell
authored andcommitted
Fix some stuff with the init & add my mods cause why not
* Add Logging for imports * Have `ModOptionChanged` fire on mod enable * Changing a hidden value should save the mod settings * Fix mod saving * Add my 3 *whole* mods
1 parent 6f5d41a commit 05fd359

File tree

7 files changed

+277
-6
lines changed

7 files changed

+277
-6
lines changed

Mods/BackpackManager/__init__.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from bl2sdk import *
2+
from ..ModManager import BL2MOD, RegisterMod
3+
from ..OptionManager import Options
4+
5+
class BackpackManager(BL2MOD):
6+
Name = "Backpack Manager"
7+
Description = "Customize the size of your character's backpack on the fly!"
8+
Types = [ModTypes.Gameplay]
9+
Author = "FromDarkHell"
10+
11+
Options = [
12+
Options.Slider("Backpack", "Change the size of your character's backpack<br>Default is 39", 39,0,200,1)
13+
]
14+
15+
backpackSpace = 39
16+
17+
def Enable(self):
18+
def HookCreateWeaponScopeMovie(caller: UObject, function: UFunction, params: FStruct) -> bool:
19+
PC = GetEngine().GamePlayers[0].Actor
20+
if PC and PC.Pawn:
21+
pawn = PC.Pawn
22+
pawn.InvManager.InventorySlotMax_Misc = self.backpackSpace
23+
return True
24+
25+
RegisterHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "HookCreateWeaponScopeMovie", HookCreateWeaponScopeMovie)
26+
27+
def Disable(self):
28+
RemoveHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "HookCreateWeaponScopeMovie")
29+
30+
31+
def ModOptionChanged(self, option, newValue):
32+
if option.Caption == "Backpack":
33+
self.backpackSpace = int(newValue)
34+
PC = GetEngine().GamePlayers[0].Actor
35+
if PC and PC.Pawn:
36+
pawn = PC.Pawn
37+
pawn.InvManager.InventorySlotMax_Misc = self.backpackSpace
38+
39+
RegisterMod(BackpackManager())

Mods/ModManager.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ def SettingsInputPressed(self, name):
9898
self.Status = "Enabled"
9999
self.SettingsInputs = {"Enter": "Disable"}
100100
self.Enable()
101+
for option in self.Options:
102+
self.ModOptionChanged(option, option.CurrentValue)
101103
elif name == "Disable":
102104
self.Status = "Disabled"
103105
self.SettingsInputs = {"Enter": "Enable"}

Mods/OptionManager.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import json
44

55
from .Util import getLoadedMods
6+
from .SaveManager import storeModSettings
67

78
class Options:
89
""" A generic helper class that stores all of the option types available in the `PLUGINS` menu. """
@@ -71,6 +72,7 @@ def __init__(self, Caption: str, Description: str, StartingValue: bool):
7172
class Hidden:
7273
""" This class is a type of option that is never shown to the user but is specified in the settings.json file.
7374
You can use this to store things the user has no need to see but is still important to have persistent. """
75+
EventID = -700000
7476
OptionType = -1
7577

7678
def __init__(self, valueName: str, StartingValue):
@@ -84,6 +86,7 @@ def CurrentValue(self):
8486
@CurrentValue.setter
8587
def CurrentValue(self, value):
8688
self._currentValue = value
89+
storeModSettings()
8790

8891

8992
bl2sdk.Options = Options
@@ -144,10 +147,10 @@ def PopulateGameOptions(caller: UObject, function: UFunction, params: FStruct) -
144147
if Options.isMenuPluginMenu == True:
145148
for mod in getLoadedMods():
146149
for option in mod.Options:
147-
caption = (mod.Name + ": " + option.Caption).upper()
148-
option.EventID = startingIndex
149150
if option.OptionType == -1:
150151
continue
152+
caption = (mod.Name + ": " + option.Caption).upper()
153+
option.EventID = startingIndex
151154
if option.OptionType == 0:
152155
if type(option) is Options.Spinner:
153156
params.TheList.AddSpinnerListItem(
@@ -184,8 +187,8 @@ def HookValueChange(caller: UObject, function: UFunction, params: FStruct) -> bo
184187
for option in mod.Options:
185188
if option.EventID == params.EventID:
186189
if params.NewSliderValue != None:
187-
mod.ModOptionChanged(option, float(params.NewSliderValue))
188190
option.CurrentValue = float(params.NewSliderValue)
191+
mod.ModOptionChanged(option, float(params.NewSliderValue))
189192
return True
190193
elif params.NewChoiceIndex != None:
191194
if type(option) is Options.Boolean:
@@ -194,6 +197,8 @@ def HookValueChange(caller: UObject, function: UFunction, params: FStruct) -> bo
194197
elif type(option) is Options.Spinner:
195198
option.CurrentValue = option.Choices[params.NewChoiceIndex]
196199
mod.ModOptionChanged(option, option.Choices[params.NewChoiceIndex])
200+
elif type(option) is Options.Hidden:
201+
continue
197202
else:
198203
option.CurrentValue = int(params.NewChoiceIndex)
199204
mod.ModOptionChanged(option, int(params.NewChoiceIndex))

Mods/Quickload/__init__.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
from bl2sdk import *
2+
3+
4+
class MapLoader(BL2MOD):
5+
Name = "Borderlands 2 Map Reloader"
6+
Description = "Quickly Farm Items in Borderlands 2!"
7+
Types = [ModTypes.Utility]
8+
Author = "FromDarkHell"
9+
10+
def __init__(self):
11+
# Our rotation etc etc
12+
self.X = 0
13+
self.Y = 0
14+
self.Z = 0
15+
self.Pitch = 0
16+
self.Yaw = 0
17+
self.Roll = 0
18+
19+
# It might be a good idea to restore our position after a load.
20+
self.saveLocation = True
21+
self.loading = False
22+
self.consistentLocation = False
23+
self.toggledLocation = False
24+
25+
# Store some data that we can use to reload the map
26+
self.currentSelectedDifficulty = 0
27+
self.currentSelectedOverpowerLevel = 0
28+
29+
self.DefaultGameInfo = UObject.FindObjectsContaining("WillowCoopGameInfo WillowGame.Default__WillowCoopGameInfo")[0]
30+
31+
Keybinds = [
32+
["Quickload w/o Saving", "F7"],
33+
["Quickload w/ Saving", "F8"],
34+
["Toggle Quickload Save States", "F10"],
35+
["Consistent Location States", "F5"]
36+
]
37+
38+
def reloadCurrentMap(self, skipSave):
39+
PC = GetEngine().GamePlayers[0].Actor
40+
if self.toggledLocation:
41+
if self.consistentLocation:
42+
locale = PC.Pawn.Location
43+
self.X = locale.X
44+
self.Y = locale.Y
45+
self.Z = locale.Z
46+
rotate = PC.Rotation
47+
self.Pitch = rotate.Pitch
48+
self.Yaw = rotate.Yaw
49+
self.Roll = rotate.Roll
50+
else:
51+
if not self.consistentLocation:
52+
locale = PC.Pawn.Location
53+
self.X = locale.X
54+
self.Y = locale.Y
55+
self.Z = locale.Z
56+
rotate = PC.Rotation
57+
self.Pitch = rotate.Pitch
58+
self.Yaw = rotate.Yaw
59+
self.Roll = rotate.Roll
60+
61+
self.toggledLocation = False
62+
# Our currently selected difficulty for the main menu
63+
self.currentSelectedDifficulty = PC.GetCurrentPlaythrough()
64+
# Get our current save game we'll need it for the OP levels
65+
wsg = PC.GetCachedSaveGame()
66+
# Our current OP level if we need it, game is weird
67+
if wsg.LastOverpowerChoice and wsg.NumOverpowerLevelsUnlocked:
68+
self.currentSelectedOverpowerLevel = max(min(wsg.LastOverpowerChoice, wsg.NumOverpowerLevelsUnlocked), 0)
69+
else:
70+
self.currentSelectedOverpowerLevel = -1
71+
72+
# Load Map
73+
self.loading = True
74+
# This is the function that BL2 uses for save quits.
75+
PC.ReturnToTitleScreen(skipSave, False)
76+
77+
def GameInputPressed(self, input):
78+
name = input.Name
79+
if name == "Quickload w/o Saving" or name == "Quickload w/ Saving":
80+
self.reloadCurrentMap(name == "Quickload w/o Saving")
81+
elif name == "Toggle Quickload Save States":
82+
self.saveLocation = not self.saveLocation
83+
state = "Location Saving is now {}".format("enabled" if self.saveLocation else "disabled")
84+
Log(state)
85+
pc = GetEngine().GamePlayers[0].Actor
86+
HUDMovie = pc.myHUD.HUDMovie
87+
# Show a training text for our location state.
88+
HUDMovie.ClearTrainingText()
89+
HUDMovie.AddTrainingText(state, "Map Loader", 2.0 * self.DefaultGameInfo.GameSpeed, (), "", False, 0, pc.PlayerReplicationInfo, True, 0, 0)
90+
elif name == "Consistent Location States":
91+
self.toggledLocation = True
92+
self.consistentLocation = not self.consistentLocation
93+
state = "Consistent Location States is now {}".format("enabled" if self.consistentLocation else "disabled")
94+
Log(state)
95+
pc = GetEngine().GamePlayers[0].Actor
96+
HUDMovie = pc.myHUD.HUDMovie
97+
# Show a training text for our location state.
98+
HUDMovie.ClearTrainingText()
99+
HUDMovie.AddTrainingText(state, "Map Loader", 2.0 * self.DefaultGameInfo.GameSpeed, (), "", False, 0, pc.PlayerReplicationInfo, True, 0, 0)
100+
101+
def GameInputRebound(self, name, key):
102+
"""Invoked by the SDK when one of the inputs we have registered for is
103+
rebound by the user. Use it to save our settings for the key binding."""
104+
pass
105+
106+
def Enable(self):
107+
108+
def map_load_hook(caller: UObject, function: UFunction, params: FStruct):
109+
if self.saveLocation and self.loading:
110+
pc = GetEngine().GamePlayers[0].Actor
111+
HUDMovie = pc.myHUD.HUDMovie
112+
# PC is sometimes none when the hooked function is called, this means this execution of the hook is running to early.
113+
# Same thing with the HUDMovie.
114+
if pc.Pawn is None or HUDMovie is None:
115+
return True
116+
# Restore our location.
117+
locale = pc.Pawn.Location
118+
locale.X = self.X
119+
locale.Y = self.Y
120+
locale.Z = self.Z
121+
rotate = pc.Rotation
122+
rotate.Roll = self.Roll
123+
rotate.Pitch = self.Pitch
124+
rotate.Yaw = self.Yaw
125+
126+
HUDMovie.ClearTrainingText()
127+
HUDMovie.AddTrainingText("Farming Location Restored", "Map Loader", 3.0 * self.DefaultGameInfo.GameSpeed, (), "", False, 0, pc.PlayerReplicationInfo, True, 0, 0)
128+
# Restore our rotation to the saved values.
129+
130+
self.loading = False
131+
return True
132+
133+
def main_menu_hook(caller: UObject, function: UFunction, params: FStruct):
134+
try:
135+
if self.loading:
136+
PC = GetEngine().GamePlayers[0].Actor
137+
# We'll need this to reload to the current difficulty.
138+
gfx = UObject.FindObjectsContaining("FrontendGFxMovie ")[1]
139+
if gfx is None or PC is None:
140+
return True
141+
# This is how the game knows what OP level we're on.
142+
if self.currentSelectedOverpowerLevel != -1:
143+
PC.OnSelectOverpowerLevel(PC.GetCachedSaveGame(), self.currentSelectedOverpowerLevel)
144+
# I don't *think* this does anything, might want to do it just in case. Weird Game.
145+
gfx.CurrentSelectedOverpowerLevel = self.currentSelectedOverpowerLevel
146+
Log("[Map Loader] Loading WSG on playthrough %s at OP %s" % (self.currentSelectedDifficulty, self.currentSelectedOverpowerLevel))
147+
# Here we reload our save, like how the `Continue` button does.
148+
gfx.LaunchSaveGame(self.currentSelectedDifficulty)
149+
except: pass
150+
return True
151+
152+
# This is how we know that we're in the main menu. Its slightly janky, but it works.
153+
RegisterHook("WillowGame.FrontendGFxMovie.OnTick", "HookMainMenu", main_menu_hook)
154+
# This is how we know that we've loaded a new map. Once again, janky.
155+
RegisterHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "MapHookLoad", map_load_hook)
156+
157+
def Disable(self):
158+
RemoveHook("WillowGame.FrontendGFxMovie.OnTick", "HookMainMenu")
159+
RemoveHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "MapHookLoad")
160+
161+
162+
RegisterMod(MapLoader())

Mods/ReadOnly/__init__.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from bl2sdk import *
2+
from ..ModManager import BL2MOD, RegisterMod
3+
import math
4+
5+
class ReadOnly(BL2MOD):
6+
Name = "Borderlands Easy Read Only"
7+
Description = "Toggle Read Only on a button press"
8+
readOnly = False
9+
toggledReadOnly = False
10+
11+
DefaultGameInfo = UObject.FindObjectsContaining("WillowCoopGameInfo WillowGame.Default__WillowCoopGameInfo")[0]
12+
Keybinds = [["Toggle Read Only", "F2"]]
13+
14+
def displayFeedback(self):
15+
PC = GetEngine().GamePlayers[0].Actor
16+
HUDMovie = PC.myHUD.HUDMovie
17+
try:
18+
if PC is None or HUDMovie is None:
19+
return True
20+
if self.readOnly:
21+
HUDMovie.AddTrainingText("Read Only: Enabled", "Read Only", math.inf, (), "", False, 0, PC.PlayerReplicationInfo, True, 0, 0)
22+
elif self.toggledReadOnly:
23+
self.toggledReadOnly = False
24+
HUDMovie.ClearTrainingText()
25+
except:
26+
return True
27+
return True
28+
29+
def GameInputPressed(self, input):
30+
if input.Name == "Toggle Read Only":
31+
self.toggledReadOnly = True
32+
self.readOnly = not self.readOnly
33+
self.displayFeedback()
34+
35+
def Enable(self):
36+
37+
def hookCanSaveGame(caller: UObject, function: UFunction, params: FStruct) -> bool:
38+
if self.readOnly:
39+
return False
40+
return True
41+
42+
def hookTrainingText(caller: UObject, function: UFunction, params: FStruct):
43+
self.displayFeedback()
44+
return True
45+
46+
RegisterHook("WillowGame.WillowPlayerController.CanSaveGame", "HookSaveGame", hookCanSaveGame)
47+
RegisterHook("WillowGame.WillowHUDGFxMovie.DrawTrainingText", "HookTrainingText", hookTrainingText)
48+
RegisterHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "HookTrainingText", hookTrainingText)
49+
50+
def Disable(self):
51+
RemoveHook("WillowGame.WillowPlayerController.CanSaveGame", "HookSaveGame")
52+
RemoveHook("WillowGame.WillowHUDGFxMovie.DrawTrainingText", "HookTrainingText")
53+
RemoveHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "HookTrainingText")
54+
55+
RegisterMod(ReadOnly())

Mods/SaveManager.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import os
22
import json
33
from bl2sdk import *
4+
import bl2sdk
45
from .Util import getLoadedMods
56

7+
from .OptionManager import *
68

79
""" Save all of our mod settings, keybinds, etc"""
810
def storeModSettings():
@@ -14,7 +16,7 @@ def storeModSettings():
1416
modSettings["Options"] = {}
1517
modSettings["Keybinds"] = {}
1618
for setting in mod.Options:
17-
if type(setting) is Options.Spinner:
19+
if type(setting) is bl2sdk.Options.Spinner:
1820
currentVal = setting.Choices[setting.Choices.index(setting.CurrentValue)]
1921
modSettings["Options"].update( {setting.Caption : currentVal } )
2022
else:

Mods/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import traceback
12
import bl2sdk
23

34
""" Increment this version any time you update ANY core Python API """
@@ -12,11 +13,16 @@
1213

1314
import os, importlib
1415

16+
1517
for module in os.listdir(os.path.dirname(__file__)):
1618
absolute_file = f"{os.path.dirname(__file__)}\\{module}"
1719
if not os.path.isdir(absolute_file):
1820
continue
1921
try:
2022
importlib.import_module(f".{module}", "Mods")
21-
except:
22-
bl2sdk.Log(f"Failed to import mod: {module}")
23+
except Exception as ex:
24+
bl2sdk.Log(f"Failed to import mod: {module}")
25+
tb = traceback.format_exc()
26+
tb = tb.split('\n')
27+
bl2sdk.Log(" " + tb[len(tb) - 3].strip())
28+
bl2sdk.Log(" " + tb[len(tb) - 2].strip())

0 commit comments

Comments
 (0)