Last active
April 2, 2023 04:11
-
-
Save TheGreatRambler/899ff02155d7c2ea9f8a8e5ad7442a51 to your computer and use it in GitHub Desktop.
Super Mario Maker 2 Data ID to Course ID
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package id | |
import ( | |
"fmt" | |
"strings" | |
) | |
func CourseIdToNum(id string) (int, error) { | |
id = strings.ToUpper(strings.ReplaceAll(id, "-", "")) | |
// https://github.com/kinnay/NintendoClients/wiki/Data-Store-Codes#super-mario-maker-2 | |
if len(id) != 9 { | |
return 0, fmt.Errorf("invalid length for course id %d", len(id)) | |
} | |
charset := map[string]int{ | |
"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "B": 10, "C": 11, "D": 12, "F": 13, "G": 14, "H": 15, "J": 16, "K": 17, "L": 18, "M": 19, "N": 20, "P": 21, "Q": 22, "R": 23, "S": 24, "T": 25, "V": 26, "W": 27, "X": 28, "Y": 29, | |
} | |
num := 0 | |
for i := len(id) - 1; i >= 0; i-- { | |
c := string(id[i]) | |
index, ok := charset[c] | |
if !ok { | |
return 0, fmt.Errorf("invalid char for course id %s", c) | |
} | |
num = num*30 + index | |
} | |
return num, nil | |
} | |
func CourseIdToDataId(id string) (uint64, error) { | |
num, err := CourseIdToNum(id) | |
if err != nil { | |
return 0, err | |
} | |
leftSide := num | |
leftSide = leftSide << 34 | |
const leftSideReplaceMask = 0b1111111111110000000000000000000000000000000000 | |
num = num ^ ((num ^ leftSide) & leftSideReplaceMask) | |
num = num >> 14 | |
num = num ^ 0b00010110100000001110000001111100 | |
return uint64(num), nil | |
} | |
func DataIdToCourseId(id uint64, isCourse bool) (string, error) { | |
charset := "0123456789BCDFGHJKLMNPQRSTVWXY" | |
if id > 4294967295 { | |
return "", fmt.Errorf("dataID > 4294967295") | |
} | |
var fieldA, fieldB, exed, fieldC, fieldE, fieldF, fieldD, intermediate uint64 | |
fieldA = 0b1000 | |
fieldB = (id - 31) % 64 | |
exed = id ^ 0b00010110100000001110000001111100 | |
fieldC = exed & 0b00000000000011111111111111111111 | |
fieldE = 0b1 | |
fieldF = exed >> 20 | |
if isCourse { | |
fieldD = 0b0 | |
} else { | |
fieldD = 0b1 | |
} | |
intermediate = (fieldA << 40) + (fieldB << 34) + (fieldC << 14) + (fieldD << 13) + (fieldE << 12) + fieldF | |
converted_id := []byte{} | |
for intermediate > 0 { | |
charIndex := intermediate % 30 | |
converted_id = append(converted_id, charset[charIndex]) | |
intermediate = intermediate / 30 | |
} | |
return string(converted_id), nil | |
} | |
func AddDashes(id string) string { | |
if len(id) != 9 { | |
return id | |
} | |
return fmt.Sprintf("%s-%s-%s", id[0:3], id[3:6], id[6:9]) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdint> | |
#include <iostream> | |
#include <string> | |
#include <unordered_map> | |
#include <vector> | |
std::string dataIdToCourseId(uint64_t id, bool isCourse) { | |
static char charset[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', | |
'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y' }; | |
if(id > 4294967295) { | |
return ""; | |
} | |
uint64_t fieldA = 0b1000; | |
uint64_t fieldB = (id - 31) % 64; | |
uint64_t exed = id ^ 0b00010110100000001110000001111100; | |
uint64_t fieldC = exed & 0b00000000000011111111111111111111; | |
uint64_t fieldE = 0b1; | |
uint64_t fieldF = exed >> 20; | |
uint64_t fieldD; | |
if(isCourse) { | |
fieldD = 0b0; | |
} else { | |
fieldD = 0b1; | |
} | |
uint64_t intermediate = (fieldA << 40) + (fieldB << 34) + (fieldC << 14) + (fieldD << 13) + (fieldE << 12) + fieldF; | |
std::string converted_id = ""; | |
while(intermediate > 0) { | |
uint64_t charIndex = intermediate % 30; | |
converted_id += charset[charIndex]; | |
intermediate /= 30; | |
} | |
return converted_id; | |
} | |
// static const std::vector<std::string> arrayOfTargets | |
// = { "DR4G0N", "G1BL3V", "D14LG4", "DR34M", "W4RSPY", "M4K3R", "T3ND0G", "4SP3N", "0TT3R", "P41K14", "P1GUY", | |
// "V3L3S", "3NTHR0", "CYNR4", "K1NGB00", "CH3RRY", "D3RG", "C0R4", "S4K1" }; | |
static const std::vector<std::string> arrayOfTargets = { "D3RG", "C0R4", "S4K1" }; | |
uint64_t dataId = 0; | |
bool isCourse = true; | |
uint64_t counter = 0; | |
int main() { | |
while(counter < 50000000) { | |
std::string id = dataIdToCourseId(dataId + counter, isCourse); | |
for(auto& x : arrayOfTargets) { | |
if(id.find(x) != std::string::npos) { | |
std::cout << "Found data_id " << (dataId + counter) << " with id " << id << std::endl; | |
} | |
} | |
if(counter % 1000000 == 0) { | |
std::cout << "Checked " << counter << " ids" << std::endl; | |
} | |
counter += 1; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
# written by mainline2 | |
# free to use in all ways as long as you credit mainline2 as the original author | |
# based on the algorithm at https://github.com/kinnay/NintendoClients/wiki/Data-Store-Codes#super-mario-maker-2 | |
fieldA = 0b1000 | |
fieldDCourse = 0b0 | |
fieldDMaker = 0b1 | |
fieldE = 0b1 | |
fieldCMask = 0b00000000000011111111111111111111 | |
fieldCShiftRight = 14 | |
fieldFMask = 0b00000000000000000000111111111111 | |
fieldFShiftRight = 20 | |
theXOR = 0b00010110100000001110000001111100 | |
fieldAShiftLeft = 40 | |
fieldBShiftLeft = 34 | |
fieldCShiftLeft = 14 | |
fieldDShiftLeft = 13 | |
fieldEShiftLeft = 12 | |
charset = "0123456789BCDFGHJKLMNPQRSTVWXY" | |
def usage(): | |
print("Converts SMM2 course or maker IDs to data IDs and vice-versa") | |
print("Usage: smm2id.py [c2d|d2c|m2d|d2m] <id>") | |
exit() | |
def d2x(ids, isCourse): | |
id = int(ids) | |
if id > 4294967295: | |
printf("Id appears too large!") | |
exit() | |
fieldB = (id - 31) % 64 | |
exed = id ^ theXOR | |
fieldC = exed & fieldCMask | |
fieldF = exed >> fieldFShiftRight | |
# print("id is %s, fieldA %s fieldB %s fieldC %s fieldD %s fieldE %s fieldF %s" % (id, '{0:b}'.format(fieldA), '{0:b}'.format(fieldB), '{0:b}'.format(fieldC), '{0:b}'.format(fieldD), '{0:b}'.format(fieldE), '{0:b}'.format(fieldF))) | |
if isCourse: | |
fieldD = fieldDCourse | |
else: | |
fieldD = fieldDMaker | |
intermediate = (fieldA << fieldAShiftLeft) + (fieldB << fieldBShiftLeft) + (fieldC << fieldCShiftLeft) + (fieldD << fieldDShiftLeft) + (fieldE << fieldEShiftLeft) + fieldF | |
# print("intermediate is %s" % '{0:b}'.format(intermediate)) | |
converted_id = "" | |
index = 0 | |
while intermediate > 0: | |
charIndex = intermediate % 30 | |
converted_id += charset[charIndex] | |
intermediate //= 30 | |
index += 1 | |
if (index % 3 == 0) and (intermediate > 0): | |
converted_id += "-" | |
if isCourse: | |
print("course id is %s" % converted_id) | |
else: | |
print("maker id is %s" % converted_id) | |
def x2d(ids, isCourse): | |
uppered = ids.upper() | |
reverseNoHashes = uppered.replace("-", "")[::-1] | |
intermediate = 0 | |
for c in reverseNoHashes: | |
intermediate = (intermediate * 30) + charset.index(c) | |
# print('{0:b}'.format(intermediate)) | |
fieldF = intermediate & fieldFMask | |
fieldC = (intermediate >> fieldCShiftRight) & fieldCMask | |
# print("fieldC %s fieldF %s" % ('{0:b}'.format(fieldC), '{0:b}'.format(fieldF))) | |
converted_id = ((fieldF << fieldFShiftRight) + fieldC) ^ theXOR | |
if isCourse: | |
print("course data id is %s" % converted_id) | |
else: | |
print("maker data id is %s" % converted_id) | |
def main(): | |
if len(sys.argv) != 3: | |
usage() | |
cmd = sys.argv[1] | |
id = sys.argv[2] | |
if cmd == "c2d": | |
x2d(id, True) | |
elif cmd == "d2c": | |
d2x(id, True) | |
elif cmd == "m2d": | |
x2d(id, False) | |
elif cmd == "d2m": | |
d2x(id, False) | |
else: | |
usage() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment