Mod manager for the game CrossCode!
Open the menu from the options menu and look for the Mods button.
Read the in-game manual in the help menu for usage instructions.
You can attach this image at the top of your mod's README.md:
Markdown code:
[](https://github.com/CCDirectLink/CCModManager)You can define custom options pages for your own mod.
See full example below.
{ type: 'CHECKBOX', init: true, changeEvent() { /* optional */ // code }, name: 'My checkbox', description: 'My least favorite button.', }{ type: 'BUTTON_GROUP', init: 0 /* option1 */, enum: { option1: 0, option2: 1 }, buttonNames: ['Option 1', 'Option 2'], name: 'My buttons', description: 'My (not really) favorite button group.', }// Or with an enum variable const myenum = { option1: 0, option2: 1, } /// ... { type: 'BUTTON_GROUP', init: myenum.option1 /* option1 */, enum: myenum, buttonNames: ['Option 1', 'Option 2'], name: 'My buttons', description: 'My beloved button group.', }{ // Creates a slider that displays values from 1 to 8 type: 'OBJECT_SLIDER', init: 1, min: 0.8, max: 1.5, step: 0.1, fill: true, name: 'Slider', description: 'My somewhat favorite slider.', }{ // Creates a slider that displays values from 0% to 100% type: 'OBJECT_SLIDER', init: 0.5, min: 0, max: 1, step: 0.1, fill: true, showPercentage: true, thumbWidth: 50, // Force the thumb width to 50px name: 'Percentage slider', description: 'My (maybe) somewhat favorite slider.', }{ // Creates a slider that displays values from 4 to 13 type: 'OBJECT_SLIDER', init: 7, min: 4, max: 13, step: 1, fill: true, // note: when using typescript, you need to specify // the return type of this function manually customNumberDisplay(index) { return this.min + index }, name: 'Number slider', description: 'My (definitely) somewhat favorite slider.', }{ type: 'BUTTON', name: 'Button', description: 'My favorite button.', onPress(button) { // code // you can update the button text as you please button.setText("hi!!") }, }{ type: 'INFO', name: 'Hello to all!\n<-- New line.', description: '', }{ type: 'CONTROLS', init: { key1: ig.KEY.I }, // If false, the keybinding only works in-game // If true, the keybinding works everywhere global: false, /* optional, false by default */ pressEvent() { /* optional */ // keybinding pressed! I will trigger only once // code }, holdEvent() { /* optional */ // keybinding is pressed now! I will trigger every frame the key is pressed // code }, name: 'My keybinding', description: 'Does something I guess.', }// Without name { type: 'INPUT_FIELD', name: '', description: 'boring text, carry on', init: 'initial text', changeEvent() { /* optional */ // code } },// With name { type: 'INPUT_FIELD', name: 'favorite food', description: 'whats your favorite food??', init: 'bricks', changeEvent() { /* optional */ // code } },// Without name { type: 'INPUT_FIELD', name: '', init: 'crossthecodes 123', description: 'how to cross the codes', changeEvent() { /* optional */ // code }, isValid(text) { return text.includes('crossthecodes') } } },// With name { type: 'INPUT_FIELD', name: 'favorite plushie', init: 'lea', changeEvent() { /* optional */ // code }, isValid(text) { return text == 'lea' } } },{ type: 'JSON_DATA', init: 123, changeEvent() { /* optional */ // code } }Each visible option has the optional functions onInit and onDeinit.
For example:
{ type: 'BUTTON', name: 'Button', description: 'My favorite button.', onPress() { console.log('Button presssed!') }, onInit(gui) { gui.button.setText("(evil) Button") }, onDeinit(gui) { console.log("the evil button will return someday!") } },On any option with a name visible, you can set the noNamePadding field to true to disable the padding.
For example:
{ type: 'CHECKBOX', init: true, name: 'My checkbox', noNamePadding: true, description: "It's initialized as true by default.", }Here's the whole page with noNamePadding set to true:
// for typescript: // import type {} from 'ccmodmanager/types/plugin' const Opts = modmanager.registerAndGetModOptions( { modId: 'my-mod', // the same as the `id` field in `ccmod.json` title: 'My mod', // the same as the `title` field in `ccmod.json` }, { general: { settings: { title: 'General', // tab title tabIcon: 'general', // icon id }, headers: { 'My header title': { myCheckbox: { type: 'CHECKBOX', init: true, name: 'My checkbox', description: "It's initialized as true by default.", }, myEnum: { type: 'BUTTON_GROUP', init: 0 /* option1 */, enum: { option1: 0, option2: 1 }, buttonNames: ['Option 1', 'Option 2'], name: 'My buttons', description: 'Hello.', }, mySlider: { // Creates a slider with the following text: // 1 2 3 4 5 6 7 8 // that resolve to the following values: // 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 type: 'OBJECT_SLIDER', init: 1, min: 0.8, max: 1.5, step: 0.1, fill: true, showPercentage: false /* Show the values as % (example: 0.9 => 90%) */, name: 'Slider', description: 'My somewhat favorite slider.', }, myButton: { type: 'BUTTON', name: 'Button', description: 'My favorite button.', onPress() { console.log('Button presssed!') }, }, myInfo: { type: 'INFO', name: 'Hello!', description: '', }, myKeybinding: { type: 'CONTROLS', init: { key1: ig.KEY.I }, // If false, the keybinding only works in-game // If true, the keybinding works everywhere global: false, pressEvent() { console.log('keybinding pressed!') }, name: 'Keybinding', description: 'Does something I guess.', }, // JSON_DATA is not visible in the menu myNumberStorage: { type: 'JSON_DATA', init: 123, }, myJsonStorage: { type: 'JSON_DATA', init: { a: 1, b: 2, c: 3 }, }, myInputField: { type: 'INPUT_FIELD', name: '', description: 'boring text, carry on', init: 'initial text', changeEvent() { /* optional */ // code }, }, myValidatedInputField: { type: 'INPUT_FIELD', name: '', description: 'how to cross the codes', init: 'crossthecodes 123', changeEvent() { /* optional */ // code }, isValid(text) { return text.includes('crossthecodes') }, }, }, }, }, } ) // Usage Opts.myCheckbox // boolean Opts.myEnum // 0 | 1 Opts.mySlider // 0.8 | 0.9 | 1.0 | 1.1 | 1.2 | 1.3 | 1.4 | 1.5 // Opts.myInfo is not accessible, since it does not store data // Opts.myKeybinding is not accessible, since it does not store data Opts.myInputField // string Opts.myValidatedInputField // string Opts.myNumberStorage // number Opts.myJsonStorage.a // number Opts.myJsonStorage.b // number Opts.myJsonStorage.c // number /* Invalid code: */ // Opts.myJsonStorage.a = 2 // The stored data is read-only, you need to override the whole object /* This is how you do it: */ Opts.myJsonStorage = { ...Opts.myJsonStorage, a: 2 }- (javascript) cc-staircase-effect-fix as an example of
INFO,CHECKBOXandOBJECT_SLIDER - (typescript) cc-fancy-crash as an example of
BUTTON_GROUPandCHECKBOX - (typescript) cc-record as an example of
OBJECT_SLIDERandCONTROLS - (typescript) CCModManager as an example of
JSON_DATA,BUTTONandINPUT_FIELD - (typescript) CrossedEyes as an example of a big multi-tab menu with a custom language getter
git clone https://github.com/CCDirectLink/CCModManager cd CCModManager pnpm install pnpm run start # this should return no errors (hopefully) npx tsc
















