Skip to content

Commit

Permalink
Created example_mods w/ Gravity Manipulator script
Browse files Browse the repository at this point in the history
  • Loading branch information
ThatBomberDev committed Aug 26, 2024
1 parent 8ec1661 commit a5ff924
Showing 1 changed file with 63 additions and 0 deletions.
63 changes: 63 additions & 0 deletions example_mods/gravityManipulator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import logging
import ctypes
from dataclasses import dataclass

from pymhf.core.hooking import disable, on_key_pressed
from pymhf.core.memutils import map_struct
from pymhf.core.mod_loader import ModState
from nmspy import NMSMod
from pymhf.core.calling import call_function
import pymhf.core.hooking
from pymhf import FUNCDEF
from pymhf.core.module_data import module_data
from pymhf.gui import FLOAT

# A quick mod used to change the gravity multiplier on all planets simultaneously, utilizing pyMHF's auto-gui.

@dataclass
class gravModState(ModState): #A special class inheriting from ModState which persists between mod Hot Reloads, allowing mod developers to cache pointers, values etc.
Gravity: int = 1
planetAddresses= list()

@disable
class gravityManipulator(NMSMod):
#General "Nice To Have"s
__author__ = "ThatBomberBoi"
__description__ = "Gravity Manipulator"
__version__ = "0.1"
__NMSPY_required_version__ = "0.7.0"

#Create an instance of the persistant ModState Class in your mod class.
state = gravModState()

def __init__(self):
super().__init__()
self.should_print = False

#Used to define a Float Type with a label in the Mod GUI, autogenerated by pyMHF.
@property
@FLOAT("Gravity Multiplier:")
def gravMult(self):
return self.state.Gravity

#Used to actually update the persisted value with the one input by the user in the GUI.
@gravMult.setter
def gravMult(self, value):
self.state.Gravity = value

#Define the FUNCDEF for the function you want to hook, including the return-type and arguments as identified via decompilers (e.x. IDA).
regionSetupFuncDef = FUNCDEF(restype=None, argtypes=[ctypes.c_ulonglong])

#The decorator used to tie a hook to a function. The tied function gets called whenever the in-game function is called. Requires a Function Signature as generated by plugins such as SigMakerEx for IDA.
# If the function you're hooking hasn't changed since 4.13 - Fractals, you can use this lil trick I've done here, and save yourself having to manually write out a FUNCDEF.
@pymhf.core.hooking.manual_hook(name="cGcPlanet::SetupRegionMap", pattern="48 89 5C 24 10 48 89 6C 24 18 56 57 41 56 48 83 EC 40 48 8B D9 8B", func_def=module_data.FUNC_CALL_SIGS["cGcPlanet::SetupRegionMap"], detour_time="after")
def onRegionMap(self, this): #Include each in-game function's arguments seperately in the function, or use *args to inspect all arguments without knowing them prior.
logging.info(f"Generated A Planet!")
self.state.planetAddresses.append(this)
logging.debug(f"Found {len(self.state.planetAddresses)} Planets So Far")

@on_key_pressed("o")
def modifyGravity(self):
for i in self.state.planetAddresses:
call_function("cGcPlanet::UpdateGravity", i, self.state.Gravity, pattern="40 53 48 83 EC 40 83 B9 78") #Used to call an in-game function directly from your mod code. You will need to provide the arguments for the in-game function, as well as the function signature.
logging.info(f"Set Planetary Gravity Multiplier To {self.state.Gravity} For All Planets")

0 comments on commit a5ff924

Please sign in to comment.