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

Commit

Permalink
Fix some stuff with the init & add my mods cause why not
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
FromDarkHell authored and FromDarkHell committed Jun 18, 2019
1 parent 6f5d41a commit 05fd359
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 6 deletions.
39 changes: 39 additions & 0 deletions Mods/BackpackManager/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from bl2sdk import *
from ..ModManager import BL2MOD, RegisterMod
from ..OptionManager import Options

class BackpackManager(BL2MOD):
Name = "Backpack Manager"
Description = "Customize the size of your character's backpack on the fly!"
Types = [ModTypes.Gameplay]
Author = "FromDarkHell"

Options = [
Options.Slider("Backpack", "Change the size of your character's backpack<br>Default is 39", 39,0,200,1)
]

backpackSpace = 39

def Enable(self):
def HookCreateWeaponScopeMovie(caller: UObject, function: UFunction, params: FStruct) -> bool:
PC = GetEngine().GamePlayers[0].Actor
if PC and PC.Pawn:
pawn = PC.Pawn
pawn.InvManager.InventorySlotMax_Misc = self.backpackSpace
return True

RegisterHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "HookCreateWeaponScopeMovie", HookCreateWeaponScopeMovie)

def Disable(self):
RemoveHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "HookCreateWeaponScopeMovie")


def ModOptionChanged(self, option, newValue):
if option.Caption == "Backpack":
self.backpackSpace = int(newValue)
PC = GetEngine().GamePlayers[0].Actor
if PC and PC.Pawn:
pawn = PC.Pawn
pawn.InvManager.InventorySlotMax_Misc = self.backpackSpace

RegisterMod(BackpackManager())
2 changes: 2 additions & 0 deletions Mods/ModManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ def SettingsInputPressed(self, name):
self.Status = "Enabled"
self.SettingsInputs = {"Enter": "Disable"}
self.Enable()
for option in self.Options:
self.ModOptionChanged(option, option.CurrentValue)
elif name == "Disable":
self.Status = "Disabled"
self.SettingsInputs = {"Enter": "Enable"}
Expand Down
11 changes: 8 additions & 3 deletions Mods/OptionManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import json

from .Util import getLoadedMods
from .SaveManager import storeModSettings

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

def __init__(self, valueName: str, StartingValue):
Expand All @@ -84,6 +86,7 @@ def CurrentValue(self):
@CurrentValue.setter
def CurrentValue(self, value):
self._currentValue = value
storeModSettings()


bl2sdk.Options = Options
Expand Down Expand Up @@ -144,10 +147,10 @@ def PopulateGameOptions(caller: UObject, function: UFunction, params: FStruct) -
if Options.isMenuPluginMenu == True:
for mod in getLoadedMods():
for option in mod.Options:
caption = (mod.Name + ": " + option.Caption).upper()
option.EventID = startingIndex
if option.OptionType == -1:
continue
caption = (mod.Name + ": " + option.Caption).upper()
option.EventID = startingIndex
if option.OptionType == 0:
if type(option) is Options.Spinner:
params.TheList.AddSpinnerListItem(
Expand Down Expand Up @@ -184,8 +187,8 @@ def HookValueChange(caller: UObject, function: UFunction, params: FStruct) -> bo
for option in mod.Options:
if option.EventID == params.EventID:
if params.NewSliderValue != None:
mod.ModOptionChanged(option, float(params.NewSliderValue))
option.CurrentValue = float(params.NewSliderValue)
mod.ModOptionChanged(option, float(params.NewSliderValue))
return True
elif params.NewChoiceIndex != None:
if type(option) is Options.Boolean:
Expand All @@ -194,6 +197,8 @@ def HookValueChange(caller: UObject, function: UFunction, params: FStruct) -> bo
elif type(option) is Options.Spinner:
option.CurrentValue = option.Choices[params.NewChoiceIndex]
mod.ModOptionChanged(option, option.Choices[params.NewChoiceIndex])
elif type(option) is Options.Hidden:
continue
else:
option.CurrentValue = int(params.NewChoiceIndex)
mod.ModOptionChanged(option, int(params.NewChoiceIndex))
Expand Down
162 changes: 162 additions & 0 deletions Mods/Quickload/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from bl2sdk import *


class MapLoader(BL2MOD):
Name = "Borderlands 2 Map Reloader"
Description = "Quickly Farm Items in Borderlands 2!"
Types = [ModTypes.Utility]
Author = "FromDarkHell"

def __init__(self):
# Our rotation etc etc
self.X = 0
self.Y = 0
self.Z = 0
self.Pitch = 0
self.Yaw = 0
self.Roll = 0

# It might be a good idea to restore our position after a load.
self.saveLocation = True
self.loading = False
self.consistentLocation = False
self.toggledLocation = False

# Store some data that we can use to reload the map
self.currentSelectedDifficulty = 0
self.currentSelectedOverpowerLevel = 0

self.DefaultGameInfo = UObject.FindObjectsContaining("WillowCoopGameInfo WillowGame.Default__WillowCoopGameInfo")[0]

Keybinds = [
["Quickload w/o Saving", "F7"],
["Quickload w/ Saving", "F8"],
["Toggle Quickload Save States", "F10"],
["Consistent Location States", "F5"]
]

def reloadCurrentMap(self, skipSave):
PC = GetEngine().GamePlayers[0].Actor
if self.toggledLocation:
if self.consistentLocation:
locale = PC.Pawn.Location
self.X = locale.X
self.Y = locale.Y
self.Z = locale.Z
rotate = PC.Rotation
self.Pitch = rotate.Pitch
self.Yaw = rotate.Yaw
self.Roll = rotate.Roll
else:
if not self.consistentLocation:
locale = PC.Pawn.Location
self.X = locale.X
self.Y = locale.Y
self.Z = locale.Z
rotate = PC.Rotation
self.Pitch = rotate.Pitch
self.Yaw = rotate.Yaw
self.Roll = rotate.Roll

self.toggledLocation = False
# Our currently selected difficulty for the main menu
self.currentSelectedDifficulty = PC.GetCurrentPlaythrough()
# Get our current save game we'll need it for the OP levels
wsg = PC.GetCachedSaveGame()
# Our current OP level if we need it, game is weird
if wsg.LastOverpowerChoice and wsg.NumOverpowerLevelsUnlocked:
self.currentSelectedOverpowerLevel = max(min(wsg.LastOverpowerChoice, wsg.NumOverpowerLevelsUnlocked), 0)
else:
self.currentSelectedOverpowerLevel = -1

# Load Map
self.loading = True
# This is the function that BL2 uses for save quits.
PC.ReturnToTitleScreen(skipSave, False)

def GameInputPressed(self, input):
name = input.Name
if name == "Quickload w/o Saving" or name == "Quickload w/ Saving":
self.reloadCurrentMap(name == "Quickload w/o Saving")
elif name == "Toggle Quickload Save States":
self.saveLocation = not self.saveLocation
state = "Location Saving is now {}".format("enabled" if self.saveLocation else "disabled")
Log(state)
pc = GetEngine().GamePlayers[0].Actor
HUDMovie = pc.myHUD.HUDMovie
# Show a training text for our location state.
HUDMovie.ClearTrainingText()
HUDMovie.AddTrainingText(state, "Map Loader", 2.0 * self.DefaultGameInfo.GameSpeed, (), "", False, 0, pc.PlayerReplicationInfo, True, 0, 0)
elif name == "Consistent Location States":
self.toggledLocation = True
self.consistentLocation = not self.consistentLocation
state = "Consistent Location States is now {}".format("enabled" if self.consistentLocation else "disabled")
Log(state)
pc = GetEngine().GamePlayers[0].Actor
HUDMovie = pc.myHUD.HUDMovie
# Show a training text for our location state.
HUDMovie.ClearTrainingText()
HUDMovie.AddTrainingText(state, "Map Loader", 2.0 * self.DefaultGameInfo.GameSpeed, (), "", False, 0, pc.PlayerReplicationInfo, True, 0, 0)

def GameInputRebound(self, name, key):
"""Invoked by the SDK when one of the inputs we have registered for is
rebound by the user. Use it to save our settings for the key binding."""
pass

def Enable(self):

def map_load_hook(caller: UObject, function: UFunction, params: FStruct):
if self.saveLocation and self.loading:
pc = GetEngine().GamePlayers[0].Actor
HUDMovie = pc.myHUD.HUDMovie
# PC is sometimes none when the hooked function is called, this means this execution of the hook is running to early.
# Same thing with the HUDMovie.
if pc.Pawn is None or HUDMovie is None:
return True
# Restore our location.
locale = pc.Pawn.Location
locale.X = self.X
locale.Y = self.Y
locale.Z = self.Z
rotate = pc.Rotation
rotate.Roll = self.Roll
rotate.Pitch = self.Pitch
rotate.Yaw = self.Yaw

HUDMovie.ClearTrainingText()
HUDMovie.AddTrainingText("Farming Location Restored", "Map Loader", 3.0 * self.DefaultGameInfo.GameSpeed, (), "", False, 0, pc.PlayerReplicationInfo, True, 0, 0)
# Restore our rotation to the saved values.

self.loading = False
return True

def main_menu_hook(caller: UObject, function: UFunction, params: FStruct):
try:
if self.loading:
PC = GetEngine().GamePlayers[0].Actor
# We'll need this to reload to the current difficulty.
gfx = UObject.FindObjectsContaining("FrontendGFxMovie ")[1]
if gfx is None or PC is None:
return True
# This is how the game knows what OP level we're on.
if self.currentSelectedOverpowerLevel != -1:
PC.OnSelectOverpowerLevel(PC.GetCachedSaveGame(), self.currentSelectedOverpowerLevel)
# I don't *think* this does anything, might want to do it just in case. Weird Game.
gfx.CurrentSelectedOverpowerLevel = self.currentSelectedOverpowerLevel
Log("[Map Loader] Loading WSG on playthrough %s at OP %s" % (self.currentSelectedDifficulty, self.currentSelectedOverpowerLevel))
# Here we reload our save, like how the `Continue` button does.
gfx.LaunchSaveGame(self.currentSelectedDifficulty)
except: pass
return True

# This is how we know that we're in the main menu. Its slightly janky, but it works.
RegisterHook("WillowGame.FrontendGFxMovie.OnTick", "HookMainMenu", main_menu_hook)
# This is how we know that we've loaded a new map. Once again, janky.
RegisterHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "MapHookLoad", map_load_hook)

def Disable(self):
RemoveHook("WillowGame.FrontendGFxMovie.OnTick", "HookMainMenu")
RemoveHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "MapHookLoad")


RegisterMod(MapLoader())
55 changes: 55 additions & 0 deletions Mods/ReadOnly/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from bl2sdk import *
from ..ModManager import BL2MOD, RegisterMod
import math

class ReadOnly(BL2MOD):
Name = "Borderlands Easy Read Only"
Description = "Toggle Read Only on a button press"
readOnly = False
toggledReadOnly = False

DefaultGameInfo = UObject.FindObjectsContaining("WillowCoopGameInfo WillowGame.Default__WillowCoopGameInfo")[0]
Keybinds = [["Toggle Read Only", "F2"]]

def displayFeedback(self):
PC = GetEngine().GamePlayers[0].Actor
HUDMovie = PC.myHUD.HUDMovie
try:
if PC is None or HUDMovie is None:
return True
if self.readOnly:
HUDMovie.AddTrainingText("Read Only: Enabled", "Read Only", math.inf, (), "", False, 0, PC.PlayerReplicationInfo, True, 0, 0)
elif self.toggledReadOnly:
self.toggledReadOnly = False
HUDMovie.ClearTrainingText()
except:
return True
return True

def GameInputPressed(self, input):
if input.Name == "Toggle Read Only":
self.toggledReadOnly = True
self.readOnly = not self.readOnly
self.displayFeedback()

def Enable(self):

def hookCanSaveGame(caller: UObject, function: UFunction, params: FStruct) -> bool:
if self.readOnly:
return False
return True

def hookTrainingText(caller: UObject, function: UFunction, params: FStruct):
self.displayFeedback()
return True

RegisterHook("WillowGame.WillowPlayerController.CanSaveGame", "HookSaveGame", hookCanSaveGame)
RegisterHook("WillowGame.WillowHUDGFxMovie.DrawTrainingText", "HookTrainingText", hookTrainingText)
RegisterHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "HookTrainingText", hookTrainingText)

def Disable(self):
RemoveHook("WillowGame.WillowPlayerController.CanSaveGame", "HookSaveGame")
RemoveHook("WillowGame.WillowHUDGFxMovie.DrawTrainingText", "HookTrainingText")
RemoveHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "HookTrainingText")

RegisterMod(ReadOnly())
4 changes: 3 additions & 1 deletion Mods/SaveManager.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import os
import json
from bl2sdk import *
import bl2sdk
from .Util import getLoadedMods

from .OptionManager import *

""" Save all of our mod settings, keybinds, etc"""
def storeModSettings():
Expand All @@ -14,7 +16,7 @@ def storeModSettings():
modSettings["Options"] = {}
modSettings["Keybinds"] = {}
for setting in mod.Options:
if type(setting) is Options.Spinner:
if type(setting) is bl2sdk.Options.Spinner:
currentVal = setting.Choices[setting.Choices.index(setting.CurrentValue)]
modSettings["Options"].update( {setting.Caption : currentVal } )
else:
Expand Down
10 changes: 8 additions & 2 deletions Mods/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import traceback
import bl2sdk

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

import os, importlib


for module in os.listdir(os.path.dirname(__file__)):
absolute_file = f"{os.path.dirname(__file__)}\\{module}"
if not os.path.isdir(absolute_file):
continue
try:
importlib.import_module(f".{module}", "Mods")
except:
bl2sdk.Log(f"Failed to import mod: {module}")
except Exception as ex:
bl2sdk.Log(f"Failed to import mod: {module}")
tb = traceback.format_exc()
tb = tb.split('\n')
bl2sdk.Log(" " + tb[len(tb) - 3].strip())
bl2sdk.Log(" " + tb[len(tb) - 2].strip())

0 comments on commit 05fd359

Please sign in to comment.