Skip to content

Commit 59cd61e

Browse files
Update Quest mod dev wiki (#582)
* Update quest mod dev pages * Change description and remove phaze's hook viewer * fix lint * Update late_load example --------- Co-authored-by: Bloodcloak <[email protected]>
1 parent fbde32d commit 59cd61e

File tree

5 files changed

+78
-72
lines changed

5 files changed

+78
-72
lines changed

wiki/modding/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ limited to:
6464

6565
- Hooking
6666
- Configuration using `config-utils`
67-
- User Interfaces using `questui`
67+
- User Interfaces using `bsml`
6868
- Custom types
6969

7070
Visit the [Quest Mod Development Intro](./quest-mod-dev-intro.md) page for more information on getting started!

wiki/modding/quest-mod-dev-config.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,15 @@ DECLARE_CONFIG(ModConfig,
6464
## Loading your Config
6565

6666
Make sure to initialize the config! If you attempt to get values from it before it's loaded, your game will crash.
67-
You can run this in `setup()`, `load()`, or even anytime later if you really want to, but it only ever needs to be run once.
67+
You can run this in `setup()`, `load()`, `late_load()`, or even anytime later if you really want to, but it only ever
68+
needs to be run once.
6869
6970
```cpp
7071
#include "modconfig.hpp"
7172
7273
// other code
7374
74-
extern "C" void load() {
75+
extern "C" void late_load() {
7576
// Initialize and load the config
7677
getModConfig().Init(modInfo);
7778
@@ -103,5 +104,5 @@ getModConfig().VariableVector2.SetValue(vec);
103104
104105
Setting a config variable will automatically save the configuration file.
105106
106-
The configuration file is usually stored at `~/ModData/com.beatgames.beatsaber/Config/` on the Quest.
107+
The configuration file is usually stored at `~/ModData/com.beatgames.beatsaber/Configs/` on the Quest.
107108
Your mod id will be used to create the configuration file, eg: `qosmetics.json`.

wiki/modding/quest-mod-dev-custom-types.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,22 +220,23 @@ about running the base class destructor, though.
220220

221221
::: warning
222222
To create a new object, _do not_ run `ctor` yourself or create it in c++ with `new` or any similar operator,
223-
but instead use `il2cpp_utils::New<MyNamespace::Counter*>(...constructor arguments);`, or any C# method that would
223+
but instead use `il2cpp_utils::New<MyNamespace::Counter*>(...constructor arguments);`, `Counter::New_ctor(...constructor
224+
arguments);`, or any C# method that would
224225
create an object, such as `AddComponent`.
225226
:::
226227

227228
### Registering
228229

229230
You can register all the custom types you have created using the `custom_types::Register::AutoRegister()` method.
230231

231-
This method should be put in your `load()` like so:
232+
This method should be put in your `load()` or `late_load()` like so:
232233

233234
```cpp
234235
#include "custom-types/shared/register.hpp"
235236

236237
// other code
237238

238-
extern "C" void load() {
239+
extern "C" void late_load() {
239240
// make sure this is after il2cpp_functions::Init()
240241
custom_types::Register::AutoRegister();
241242

wiki/modding/quest-mod-dev-intro.md

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ and add it to your PATH variable.
5151

5252
### Android NDK
5353

54-
[Download the Android NDK](https://developer.android.com/ndk), unzip it, and add it to a new environment variable called
55-
ANDROID_NDK_HOME.
54+
[Download the Android NDK](https://github.com/QuestPackageManager/ndk-canary-archive/releases/tag/27.0.1), unzip it, and
55+
add it to a new environment variable called ANDROID_NDK_HOME.
5656

5757
## Create a Project
5858

@@ -69,26 +69,26 @@ Templatr will then ask a series of questions to create a mod project.
6969

7070
### Add and Update Dependencies
7171

72-
Once the project has been generated, you should now update the following two dependencies, [beatsaber-hook](https://github.com/sc2ad/beatsaber-hook)
73-
and [codegen](https://github.com/sc2ad/BeatSaber-Quest-Codegen), to the version best suited for the game version you are
72+
Once the project has been generated, you should now update the following two dependencies, [beatsaber-hook](https://github.com/QuestPackageManager/beatsaber-hook/)
73+
and [bs-cordl](https://github.com/QuestPackageManager/bs-cordl), to the version best suited for the game version you are
7474
developing for.
7575

76-
`beatsaber-hook` is a library that allows for modding il2cpp games. `codegen` is a library that allows modders to
76+
`beatsaber-hook` is a library that allows for modding il2cpp games. `bs-cordl` is a library that allows modders to
7777
interface with the game's code.
7878

7979
To update these, open a Powershell terminal in the project directory then run the following commands to add the latest versions:
8080

8181
```powershell
8282
qpm dependency add beatsaber-hook
83-
qpm dependency add codegen
83+
qpm dependency add bs-cordl
8484
```
8585

8686
If the latest versions do match those for the version you are developing for, add `-v ^x.x.x` after the command with the
87-
correct version instead of running those commands. For example, for Beat Saber version 1.28.0, the correct codegen
88-
version is 0.33.0:
87+
correct version instead of running those commands. For example, for Beat Saber version 1.35.0, the correct codegen
88+
version is 3500.0.0:
8989

9090
```powershell
91-
qpm dependency add codegen -v ^0.33.0
91+
qpm dependency add bs-cordl -v ^3500.0.0
9292
```
9393

9494
### Restore Dependencies
@@ -108,33 +108,29 @@ Your project should contain the following structure:
108108

109109
```properties
110110
// Files in .gitignore have been excluded
111+
cmake/
112+
└── ... project cmake files
111113
extern/
112114
└── ... dependencies should be here
113115
include/
114116
└── main.hpp
117+
scripts/
118+
└── ... utility scripts
115119
shared
116120
src/
117121
└── main.cpp
118122
.gitignore
119-
build.ps1
120-
copy.ps1
121123
CMakeLists.txt
122-
createqmod.ps1
123124
mod.template.json
124-
ndk-stack.ps1
125-
pull-tombstone.ps1
126125
qpm.json
127126
README.md
128-
start-logging.ps1
129-
restart-game.ps1
130-
validate-modjson.ps1
131127
```
132128

133129
### Code Breakdown
134130

135131
#### src/main.cpp
136132

137-
`main.cpp` contains the `setup()` and `load()` methods. These methods can exist in any source file as long as they are
133+
`main.cpp` contains the `setup()` and `late_load()` methods. These methods can exist in any source file as long as they are
138134
accessible by the modloader. Take a look inside of `main.cpp` for more information as Laurie has thankfully commented
139135
most of the code.
140136

@@ -152,49 +148,50 @@ The extern folder should be ignored (and/or in some cases excluded). It contains
152148
### Script Breakdown
153149

154150
It is recommended to run these scripts using Powershell Core (v7) - however, it is not required. All scripts can be run
155-
with the `--help` argument for a description of arguments and functionality.
151+
with the `--help` argument for a description of arguments and functionality. Scripts can be manually invoked from the
152+
`scripts` folder or via qpm scripts inside `qpm.json`
156153

157154
#### build.ps1
158155

159-
Usage: `build.ps1`
156+
Usage: `qpm s build`
160157

161158
Builds your mod. Does not produce a QMOD file.
162159

163160
#### copy.ps1
164161

165-
Usage: `copy.ps1`
162+
Usage: `qpm s copy`
166163

167164
Builds your mod, then copies it to your quest and launches Beat Saber if your quest is connected with ADB.
168165

169166
#### createqmod.ps1
170167

171-
Usage: `createqmod.ps1 (optionally) -qmodName {file name}`
168+
Usage: `qpm s qmod`
172169

173170
Generates a QMOD file that can be parsed by BMBF and or QuestPatcher. Will use the most recently built version of your mod.
174171

175172
#### pull-tombstone.ps1
176173

177-
Usage: `pull-tombstone.ps1`
174+
Usage: `qpm s tomb`
178175

179176
Finds the most recently modified Beat Saber crash tombstone and copies it to your device. If the build on your quest matches
180177
what you have most recently built locally, the `-analyze` argument can be provided to generate the source file locations
181178
of any lines mentioned in the backtrace.
182179

183180
#### restart-game.ps1
184181

185-
Usage: `restart-game.ps1`
182+
Usage: `qpm s restart`
186183

187184
Closes and reopens Beat Saber on your quest if it is connected. Mostly used inside of `copy.ps1`. Does not have help text.
188185

189186
#### start-logging.ps1
190187

191-
Usage: `start-logging.ps1 -Self`
188+
Usage: `qpm s logcat`
192189

193190
Prints logs from Beat Saber, just your mod, or also crashes. Usage of `-self` is recommended.
194191

195192
#### validate-modjson.ps1
196193

197-
Usage: `validate-modjson.ps1`
194+
Usage: `qpm s validate`
198195

199196
Generates a `mod.json` from `mod.template.json` if not present and verifies it against the QMOD schema. Mostly used
200197
inside of `createqmod.ps1`. Does not have help text.
@@ -211,28 +208,31 @@ like constructors.
211208
212209
To view a list of methods and classes you can hook, the most convenient option is to use a C# decompiler such as [IlSpy](https://github.com/icsharpcode/ILSpy)
213210
if you own the game on PC, as it provides not only the classes and member names, but also the full contents of most methods.
214-
If you only own the game on the Quest, then you can still view all the classes and methods on [Phaze's hook viewer](https://modtools.phazed.xyz/browser)
215-
or in the `includes/codegen` directory in your `extern` folder.
211+
If you only own the game on the Quest, then you can still view all the classes and methods in the `includes/codegen`
212+
directory in your `extern` folder.
216213

217-
In this example, we will hook onto the initialization of the main menu and change the text on the solo button to
214+
In this example, we will hook onto the initialization of the level screen and change the text on the play button to
218215
something funny.
219216

220-
The main menu runs the event `DidActivate` when it is fully initialized. This is useful for us because we can hook
217+
The level screen runs the event `DidActivate` when it is fully initialized. This is useful for us because we can hook
221218
this event and add our own functionality.
222219

223220
Firstly, create your hook using the `MAKE_HOOK_MATCH` macro:
224221

222+
<!-- markdownlint-disable MD013 -->
223+
225224
```cpp
226-
// You can think of these as C# - using MainMenuViewController, using HMUI.CurvedTextMeshPro, etc.
225+
// You can think of these as C# - using HMUI, UnityEngine, etc, but with individual classes
227226
// Classes without a namespace are assigned to the GlobalNamespace
228227
// If you use a class and do not include it, you may get unclear compiler errors, so make sure to include what you use
229-
#include "GlobalNamespace/MainMenuViewController.hpp"
228+
#include "GlobalNamespace/StandardLevelDetailView.hpp"
229+
#include "GlobalNamespace/StandardLevelDetailViewController.hpp"
230230
#include "UnityEngine/UI/Button.hpp"
231231
#include "UnityEngine/GameObject.hpp"
232232
#include "HMUI/CurvedTextMeshPro.hpp"
233233

234-
// Create a hook struct named MainMenuUIHook
235-
// targeting the method "MainMenuViewController::DidActivate", which takes the following arguments:
234+
// Create a hook struct named LevelUIHook
235+
// targeting the method "StandardLevelDetailViewController::DidActivate", which takes the following arguments:
236236
// bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling
237237
// and returns void.
238238

@@ -241,35 +241,39 @@ Firstly, create your hook using the `MAKE_HOOK_MATCH` macro:
241241
// your code here
242242
// }
243243

244-
MAKE_HOOK_MATCH(MainMenuUIHook, &GlobalNamespace::MainMenuViewController::DidActivate, void,
245-
GlobalNamespace::MainMenuViewController* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) {
244+
245+
MAKE_HOOK_MATCH(LevelUIHook, &GlobalNamespace::StandardLevelDetailViewController::DidActivate, void,
246+
GlobalNamespace::StandardLevelDetailViewController* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) {
246247
// Run the original method before our code.
247248
// Note that you can run the original method after our code or even in the middle
248249
// if you want to change arguments or do something before it runs.
249-
MainMenuUIHook(self, firstActivation, addedToHierarchy, screenSystemEnabling);
250+
LevelUIHook(self, firstActivation, addedToHierarchy, screenSystemEnabling);
250251

251-
// Get the _soloButton text object by accessing the soloButton field and some simple Unity methods.
252+
// Get the actionButton text object by accessing the actionButton field and some simple Unity methods.
252253
// Note that auto can be used instead of declaring the full type in many cases.
253-
UnityEngine::UI::Button* soloMenuButton = self->soloButton;
254-
UnityEngine::GameObject* gameObject = soloMenuButton->get_gameObject();
255-
HMUI::CurvedTextMeshPro* soloMenuText = gameObject->GetComponentInChildren<HMUI::CurvedTextMeshPro*>();
254+
GlobalNamespace::StandardLevelDetailView* standardLevelDetailView = self->_standardLevelDetailView;
255+
UnityEngine::UI::Button* actionButton = standardLevelDetailView->actionButton;
256+
UnityEngine::GameObject* gameObject = actionButton->get_gameObject();
257+
HMUI::CurvedTextMeshPro* actionButtonText = gameObject->GetComponentInChildren<HMUI::CurvedTextMeshPro*>();
256258

257259
// Set the text to "Skill Issue"
258-
soloMenuText->SetText("Skill Issue");
260+
actionButtonText->set_text("Skill Issue");
259261
}
260262
```
261263
262-
Now, you have to install your hook. Usually, hooks are installed in `load()` in `main.cpp`:
264+
<!-- markdownlint-enable MD013 -->
265+
266+
Now, you have to install your hook. Usually, hooks are installed in `load()` or `late_load()` in `main.cpp`:
263267
264268
```cpp
265-
extern "C" void load() {
269+
extern "C" void late_load() {
266270
il2cpp_functions::Init();
267271
268-
getLogger().info("Installing hooks...");
272+
PaperLogger.info("Installing hooks...");
269273
270-
INSTALL_HOOK(getLogger(), MainMenuUIHook);
274+
INSTALL_HOOK(PaperLogger, LevelUIHook);
271275
272-
getLogger().info("Installed all hooks!");
276+
PaperLogger.info("Installed all hooks!");
273277
}
274278
```
275279

@@ -396,7 +400,7 @@ page to learn more about integrating this into your mod.
396400
## User Interface
397401

398402
A user interface (UI) is used by many mods to show configuration options. Visit the [Quest User Interface](./quest-mod-dev-ui.md)
399-
page to see how to use `questui` to create a settings screen for your mod.
403+
page to see how to use `bsml` to create a settings screen for your mod.
400404

401405
## Credits
402406

wiki/modding/quest-mod-dev-ui.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,46 @@ description: Learn how to create a UI for your Quest Mod!
1010
This is a stub page, content is a work in progress! Ask in `#quest-mod-dev` if you want more info!
1111
:::
1212

13-
UI is used by many mods to show configuration options. In this section, we'll show you how to use `questui` to create a
14-
settings screen for your mod.
13+
UI is used by many mods to show configuration options. In this section, we'll show you how to use `bsml` to create a
14+
settings screen for your mod using code. `bsml` also supports creating UI with xml which can be found on the [BSML docs](https://redbrumbler.github.io/Quest-BSML-Docs/).
1515

1616
## Prerequisites
1717

18-
- Install `questui` by running `qpm dependency add questui` in your project directory.
18+
- Install `bsml` by running `qpm dependency add bsml` in your project directory.
1919
- You also need to install `custom-types` even if you don't use it in your mod: `qpm dependency add custom-types`
2020

2121
Make sure to restore after adding the dependencies.
2222

2323
## Creating a `DidActivate` method
2424

25-
`DidActivate` is a method you can register with `questui` that allows you to make a simple mod settings page.
25+
`DidActivate` is a method you can register with `bsml` that allows you to make a simple mod settings page.
2626

2727
Take a look at this example:
2828

2929
- You should only create your components on first activation to prevent duplication.
3030
- You can utilize containers (such as Scrollable, HorizontalLayout and VerticalLayout) to manipulate the locations of components.
3131

3232
```cpp
33-
#include "questui/shared/BeatSaberUI.hpp"
33+
#include "bsml/shared/BSML.hpp"
3434

3535
void DidActivate(HMUI::ViewController* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) {
3636
// Create our UI elements only when shown for the first time.
3737
if(firstActivation) {
3838
// Create a container that has a scroll bar
39-
UnityEngine::GameObject* container = QuestUI::BeatSaberUI::CreateScrollableSettingsContainer(self->get_transform());
39+
UnityEngine::GameObject* container = BSML::Lite::CreateScrollableSettingsContainer(self->get_transform());
4040

4141
// Create a text that says "Hello World!" and set the parent to the container.
42-
QuestUI::BeatSaberUI::CreateText(container->get_transform(), "Hello World!");
42+
BSML::Lite::CreateText(container->get_transform(), "Hello World!");
4343
}
4444
}
4545
```
4646
47-
There are too many UI components and methods to document in this guide. However, the file `BeatSaberUI.hpp` has
48-
comments that document almost all the methods.
47+
There are too many UI components and methods to document in this guide. However, the files in the `BSML-Lite/Creation`
48+
folder have comments that document almost all the methods.
4949
5050
## Registering `DidActivate`
5151
52-
`questui` contains a few locations you can register to:
52+
`bsml` contains a few locations you can register to:
5353
5454
- Main Menu Mod Tabs
5555
![Main Menu Mod Tabs](/.assets/images/modding/quest-menu-mod-tab.png)
@@ -58,18 +58,18 @@ comments that document almost all the methods.
5858
- Gameplay Setup
5959
![Gameplay Setup](/.assets/images/modding/quest-gameplay-settings.jpg)
6060
61-
For `questui` to use your `DidActivate` method, you will need to register it using the `QuestUI::Register` class in your
62-
`load()` method.
61+
For `bsml` to use your `DidActivate` method, you will need to register it using the `BSML::Register` class in your
62+
`late_load()` method.
6363
6464
```cpp
65-
#include "questui/shared/QuestUI.hpp"
65+
#include "bsml/shared/BSML.hpp"
6666
6767
// other code
6868
69-
extern "C" void load() {
69+
extern "C" void late_load() {
7070
// make sure this is after il2cpp_functions::Init()
71-
QuestUI::Init();
72-
QuestUI::Register::RegisterModSettingsViewController(modInfo, DidActivate);
71+
BSML::Init();
72+
BSML::Register::RegisterMainMenuViewControllerMethod(title, text, hoverHint, DidActivate);
7373
7474
// other code
7575
}
@@ -78,4 +78,4 @@ extern "C" void load() {
7878
The gameplay setup location requires a slightly different function signature than the other two, with the arguments
7979
being just `UnityEngine::GameObject* self, bool firstActivation`.
8080

81-
All the register functions can be found in the `QuestUI.hpp` file.
81+
All the register functions can be found in the `BSML.hpp` file.

0 commit comments

Comments
 (0)