Skip to content

Commit a5ff924

Browse files
committed
Created example_mods w/ Gravity Manipulator script
1 parent 8ec1661 commit a5ff924

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

example_mods/gravityManipulator.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import logging
2+
import ctypes
3+
from dataclasses import dataclass
4+
5+
from pymhf.core.hooking import disable, on_key_pressed
6+
from pymhf.core.memutils import map_struct
7+
from pymhf.core.mod_loader import ModState
8+
from nmspy import NMSMod
9+
from pymhf.core.calling import call_function
10+
import pymhf.core.hooking
11+
from pymhf import FUNCDEF
12+
from pymhf.core.module_data import module_data
13+
from pymhf.gui import FLOAT
14+
15+
# A quick mod used to change the gravity multiplier on all planets simultaneously, utilizing pyMHF's auto-gui.
16+
17+
@dataclass
18+
class gravModState(ModState): #A special class inheriting from ModState which persists between mod Hot Reloads, allowing mod developers to cache pointers, values etc.
19+
Gravity: int = 1
20+
planetAddresses= list()
21+
22+
@disable
23+
class gravityManipulator(NMSMod):
24+
#General "Nice To Have"s
25+
__author__ = "ThatBomberBoi"
26+
__description__ = "Gravity Manipulator"
27+
__version__ = "0.1"
28+
__NMSPY_required_version__ = "0.7.0"
29+
30+
#Create an instance of the persistant ModState Class in your mod class.
31+
state = gravModState()
32+
33+
def __init__(self):
34+
super().__init__()
35+
self.should_print = False
36+
37+
#Used to define a Float Type with a label in the Mod GUI, autogenerated by pyMHF.
38+
@property
39+
@FLOAT("Gravity Multiplier:")
40+
def gravMult(self):
41+
return self.state.Gravity
42+
43+
#Used to actually update the persisted value with the one input by the user in the GUI.
44+
@gravMult.setter
45+
def gravMult(self, value):
46+
self.state.Gravity = value
47+
48+
#Define the FUNCDEF for the function you want to hook, including the return-type and arguments as identified via decompilers (e.x. IDA).
49+
regionSetupFuncDef = FUNCDEF(restype=None, argtypes=[ctypes.c_ulonglong])
50+
51+
#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.
52+
# 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.
53+
@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")
54+
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.
55+
logging.info(f"Generated A Planet!")
56+
self.state.planetAddresses.append(this)
57+
logging.debug(f"Found {len(self.state.planetAddresses)} Planets So Far")
58+
59+
@on_key_pressed("o")
60+
def modifyGravity(self):
61+
for i in self.state.planetAddresses:
62+
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.
63+
logging.info(f"Set Planetary Gravity Multiplier To {self.state.Gravity} For All Planets")

0 commit comments

Comments
 (0)