Skip to content

CCDirectLink/CCModManager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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 mod options submenu for the mod CrossedEyes

For mod developers

Option types

CHECKBOX

image

{
    type: 'CHECKBOX',
    init: true,
    /* optional */ changeEvent() {
        // 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,
    customNumberDisplay(index) {
        const num = this.min
        return num + index
    },
    name: 'Number slider',
    description: 'My (definitely) somewhat favorite slider.',
}

BUTTON

image

{
    type: 'BUTTON',
    onPress() {
        // code
    },
    name: 'Button',
    description: 'My favorite button.',
}

INFO

image

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

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,
    pressEvent() {
        // keybinding pressed! I will trigger only once
        // code
    },
    holdEvent() {
        // keybinding is pressed now! I will trigger every frame the key is pressed
        // code
    },
    name: 'My keybinding',
    description: 'Does something I guess.',
}

JSON_DATA

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

Full example

image

// for typescript:
// import type * as _ 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',
                        onPress() {
                            console.log('Button presssed!')
                        },
                        name: 'Button',
                        description: 'My favorite button.',
                    },
                    myInfo: {
                        type: 'INFO',
                        name: 'Hello!',
                    },
                    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 },
                    },
                },
            },
        },
    }
)

// 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.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 and BUTTON
  • (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