Skip to content

Commit ad90c6a

Browse files
committed
Updated to pymhf 0.1.15 and added some extra functions and example mod
1 parent 6eb2a6a commit ad90c6a

File tree

8 files changed

+220
-64
lines changed

8 files changed

+220
-64
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ It should also be noted that Game updates can very easily break mods utilising N
77
Any responsibility for broken saves is entirely on the users of this library.
88

99
Also note that this library will never contain functions relating to online functionality to avoid any abuse.
10-
The author of this library condones any use of this for any usage that is detrimental to other players.
10+
The author of this library condones any use of this code for any purpose that is directly detrimental to other players.
1111

1212
## Installation
1313

@@ -23,7 +23,8 @@ To run NMS.py, enter the following command into a terminal:
2323
pymhf run nmspy
2424
```
2525

26-
This will display some config options to complete. The only option to consider is the location of the mods folder. It is recommended that you create a new folder inside the normal MODS folder which can contain all the python scripts you want to be run.
26+
This will display some config options to complete. The only option to consider is the location of the mods folder. It is recommended that you specify the `MODS` folder inside the `GAMEDATA` folder as your mod directory (ie. the same one you put normal mods in).
27+
All mods will be placed in either this folder, or in a chcild folder of this. You can essentially think of any mod using NMS.py being able to be "installed" in the same way you would any other normal mod.
2728

2829
If NMS.py starts up successfully you should see two extra windows; an auto-created GUI from pyMHF, and a terminal window which will show the logs for pyMHF.
2930

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# /// script
2+
# dependencies = ["pymhf[gui]>=0.1.13"]
3+
#
4+
# [tool.pymhf]
5+
# exe = "NMS.exe"
6+
# steam_gameid = 275850
7+
# start_paused = false
8+
#
9+
# [tool.pymhf.gui]
10+
# always_on_top = true
11+
#
12+
# [tool.pymhf.logging]
13+
# log_dir = "."
14+
# log_level = "info"
15+
# window_name_override = "NMS audio thing"
16+
# ///
17+
from __future__ import annotations
18+
19+
import ctypes
20+
import logging
21+
from dataclasses import dataclass
22+
23+
from pymhf import Mod, ModState
24+
from pymhf.core.hooking import disable
25+
from pymhf.core.utils import set_main_window_active
26+
from pymhf.gui.decorators import BOOLEAN, STRING, gui_button, gui_combobox
27+
28+
from nmspy.data.audiokinetic import AK
29+
from nmspy.data.enums import GcAudioWwiseEvents
30+
import nmspy.data.types as nms
31+
32+
logger = logging.getLogger("AudioNames")
33+
34+
35+
AUDIO_EVENTS = {i.name: i.value for i in GcAudioWwiseEvents}
36+
AUDIO_EVENTS_REV = {i.value: i.name for i in GcAudioWwiseEvents}
37+
EVENT_NAMES = [i.name for i in GcAudioWwiseEvents]
38+
39+
40+
@dataclass
41+
class AudioState(ModState):
42+
event_id: int = 0
43+
obj_id: int = 0
44+
play_sounds: bool = True
45+
log_sounds: bool = True
46+
47+
48+
@disable
49+
class AudioNames(Mod):
50+
__author__ = "monkeyman192"
51+
__description__ = "Log (almost) all audio events when they happen"
52+
__version__ = "0.1"
53+
54+
state = AudioState()
55+
56+
def __init__(self):
57+
super().__init__()
58+
self.audio_manager = None
59+
60+
@gui_combobox("Audio ID:", items=EVENT_NAMES)
61+
def select_audio_id(self, sender, app_data: str, user_data):
62+
event_id = AUDIO_EVENTS.get(app_data, 0)
63+
self.state.event_id = event_id
64+
65+
@gui_button("Play sound")
66+
def play_sound(self):
67+
if self.state.event_id and self.state.obj_id and self.audio_manager is not None:
68+
set_main_window_active()
69+
audioid = nms.TkAudioID()
70+
audioid.muID = self.state.event_id
71+
self.audio_manager.Play(
72+
event=ctypes.byref(audioid), object=self.state.obj_id
73+
)
74+
75+
@property
76+
@STRING("Event ID", decimal=True)
77+
def event_id(self):
78+
return self.state.event_id
79+
80+
@event_id.setter
81+
def event_id(self, value):
82+
self.state.event_id = int(value)
83+
84+
@property
85+
@STRING("Object ID", decimal=True)
86+
def obj_id(self):
87+
return self.state.obj_id
88+
89+
@obj_id.setter
90+
def obj_id(self, value):
91+
self.state.obj_id = int(value)
92+
93+
@property
94+
@BOOLEAN("Log sounds")
95+
def log_sounds(self):
96+
return self.state.log_sounds
97+
98+
@log_sounds.setter
99+
def log_sounds(self, value):
100+
self.state.log_sounds = value
101+
102+
@disable
103+
@AK.SoundEngine.PostEvent.before
104+
def play_event(self, *args):
105+
if self.state.log_sounds:
106+
event_id = args[0]
107+
event_name = AUDIO_EVENTS_REV.get(event_id, "unknown event thing...")
108+
logger.info(f"{args} -> {event_name}")
109+
110+
@AK.SoundEngine.RegisterGameObj.before
111+
def register_object(self, in_GameObj, in_pszObjName):
112+
if self.state.log_sounds:
113+
logger.info(f"{in_GameObj} name: {ctypes.c_char_p(in_pszObjName).value}")
114+
115+
@disable
116+
@nms.cTkAudioManager.Play.after
117+
def after_play(
118+
self,
119+
this: ctypes._Pointer[nms.cTkAudioManager],
120+
event: ctypes._Pointer[nms.TkAudioID],
121+
object_,
122+
):
123+
audioID = event.contents
124+
logger.info(f"After play: ID: {audioID.muID}, object: {object_}")
125+
self.audio_manager = this.contents
126+
self.state.event_id = audioID.muID
127+
self.state.obj_id = object_
128+
129+
@disable
130+
@nms.cTkAudioManager.Play_attenuated.after
131+
def after_play_attenuated(self, *args):
132+
logger.info(f"Just played an attenuated sound: {args}")

example_mods/gravityManipulator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# /// script
2-
# dependencies = ["pymhf[gui]>=0.1.14"]
2+
# dependencies = ["pymhf[gui]>=0.1.15"]
33
#
44
# [tool.pymhf]
55
# exe = "NMS.exe"

nmspy/data/exported_types.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ class cGcSolarSystemData(Structure):
1919

2020
@partial_struct
2121
class cGcNGuiTextData(Structure):
22-
Text: Annotated[
23-
basic.cTkDynamicArray[ctypes.c_char],
24-
Field(basic.cTkDynamicArray[ctypes.c_char], 0x88),
25-
]
22+
Text: Annotated[basic.cTkDynamicArray[ctypes.c_char], 0x88]
2623

2724

2825
class cGcScanEventData(Structure):
@@ -31,7 +28,7 @@ class cGcScanEventData(Structure):
3128

3229
@partial_struct
3330
class cGcInteractionComponentData(Structure):
34-
mInteractionType: Annotated[c_enum32[enums.GcInteractionType], 0x31C]
31+
InteractionType: Annotated[c_enum32[enums.GcInteractionType], 0x32C]
3532

3633

3734
@partial_struct

nmspy/data/types.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,21 @@ def GetDominantHand(self, this: "ctypes._Pointer[cGcPlayer]") -> ctypes.c_int64:
398398

399399

400400
class cGcPlayerState(Structure):
401-
pass
401+
@function_hook("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 44 8B 81 ? ? ? ? 48 8D 2D")
402+
def AwardUnits(
403+
self,
404+
this: "ctypes._Pointer[cGcPlayerState]",
405+
liChange: ctypes.c_int32,
406+
) -> ctypes.c_uint64:
407+
pass
408+
409+
@function_hook("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 44 8B 81 ? ? ? ? 48 8D 35")
410+
def AwardNanites(
411+
self,
412+
this: "ctypes._Pointer[cGcPlayerState]",
413+
liChange: ctypes.c_int32,
414+
) -> ctypes.c_uint64:
415+
pass
402416

403417

404418
class cGcGameState(Structure):

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ classifiers = [
2323
"Programming Language :: Python :: 3 :: Only",
2424
]
2525
dependencies = [
26-
"pymhf[gui]>=0.1.14"
26+
"pymhf[gui]>=0.1.15"
2727
]
28-
version = "147408.0"
28+
version = "147408.1"
2929

3030
[dependency-groups]
3131
dev = [

tools/data.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,5 +543,15 @@
543543
"name": "cGcPlanetGenerator::Generate",
544544
"signature": "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 4D 8B F8 C6 85",
545545
"mangled_name": "?Generate@cGcPlanetGenerator@@QEAAXAEAVcGcPlanetData@@AEBVcGcPlanetGenerationInputData@@PEAVcGcPlanet@@@Z"
546+
},
547+
{
548+
"name": "cGcPlayerState::AwardUnits",
549+
"signature": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 44 8B 81 ? ? ? ? 48 8D 2D",
550+
"mangled_name": "?AwardUnits@cGcPlayerState@@QEAAIH@Z"
551+
},
552+
{
553+
"name": "cGcPlayerState::AwardNanites",
554+
"signature": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 44 8B 81 ? ? ? ? 48 8D 35",
555+
"mangled_name": "?AwardNanites@cGcPlayerState@@QEAAIH@Z"
546556
}
547557
]

0 commit comments

Comments
 (0)