Skip to content

CCDirectLink/CCModManager

Repository files navigation

CCModManager

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.

Mod icon grid

Screenshots

Screenshot of the Online tab sorted by the mod star count Screenshot of the Online tab with grid mode enabled Screenshot of the mod options submenu for the mod CCModManager

For mod developers

Badge

You can attach this image at the top of your mod's README.md:

CCModManager badge

Markdown code:

[![CCModManager badge](https://raw.githubusercontent.com/CCDirectLink/CCModManager/refs/heads/master/icon/badge.png)](https://github.com/CCDirectLink/CCModManager)

Custom mod options

You can define custom options pages for your own mod.
See full example below.

Option types

CHECKBOX

image

{ type: 'CHECKBOX', init: true, changeEvent() { /* optional */ // code }, name: 'My checkbox', description: 'My least favorite button.', }

BUTTON_GROUP

image

{ 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.', }

OBJECT_SLIDER

image

{ // 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.', }

image

{ // 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.', }

image

{ // 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.', }

BUTTON

image

{ type: 'BUTTON', name: 'Button', description: 'My favorite button.', onPress(button) { // code // you can update the button text as you please button.setText("hi!!") }, }

INFO

image

{ type: 'INFO', name: 'Hello to all!\n<-- New line.', description: '', }

CONTROLS

image

{ 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.', }

INPUT_FIELD

image

// Without name { type: 'INPUT_FIELD', name: '', description: 'boring text, carry on', init: 'initial text', changeEvent() { /* optional */ // code } },

image

// With name { type: 'INPUT_FIELD', name: 'favorite food', description: 'whats your favorite food??', init: 'bricks', changeEvent() { /* optional */ // code } },

image

// Without name { type: 'INPUT_FIELD', name: '', init: 'crossthecodes 123', description: 'how to cross the codes', changeEvent() { /* optional */ // code }, isValid(text) { return text.includes('crossthecodes') } } },

image

// With name { type: 'INPUT_FIELD', name: 'favorite plushie', init: 'lea', changeEvent() { /* optional */ // code }, isValid(text) { return text == 'lea' } } },

JSON_DATA

{ type: 'JSON_DATA', init: 123, changeEvent() { /* optional */ // code } }

onInit and onDeinit

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!") } },

Name padding

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:

image

Full example

image

// 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 }

Other examples

  • (javascript) cc-staircase-effect-fix as an example of INFO, CHECKBOX and OBJECT_SLIDER
  • (typescript) cc-fancy-crash as an example of BUTTON_GROUP and CHECKBOX
  • (typescript) cc-record as an example of OBJECT_SLIDER and CONTROLS
  • (typescript) CCModManager as an example of JSON_DATA, BUTTON and INPUT_FIELD
  • (typescript) CrossedEyes as an example of a big multi-tab menu with a custom language getter

Building CCModManager

git clone https://github.com/CCDirectLink/CCModManager cd CCModManager pnpm install pnpm run start # this should return no errors (hopefully) npx tsc

About

An ingame mod manager for CrossCode

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 5