You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Courses: LR2 course IR flag (button 253, text 183) #404
LR2 marks a course for IR submission with button 253 (L11139-11152). Text 183 shows the flag (L8406), and a flagged course becomes read-only (L18080). be-music has neither the button nor the text.
The likely mapping is to beatoraja's release for made courses, or a fixed string on text 183.
Found in the LR2 / beatoraja course compatibility audit for #373 / #377.
Sources: OpenLR2 LR2f.cpp @ 583a385, the LR2 beta3 binaries (LR2body.exe, and LR2.exe, the config program that imports course files) and LR2files/Config/optionstr.csv.
Where the flag lives
The flag is not in the .lr2crs file. It is the ir column of LR2's own course tables in song.db (CREATE TABLE expert|nonstop|grade(id, title, line, hash, ir), L19281-L19283). It is read as column 4 into courseIR, and courseIR == 1 sets courseReadOnly (L18078-L18080).
Imported courses are always IR ON.LR2.exe reads only title, line and hash from a <courselist> (strings courselist, hash, title, line, with no ir or type tag next to them), and inserts every course with ir fixed to 1: INSERT INTO expert (title,line,hash,ir) VALUES ('%q',%d,'%q',1), and the same for nonstop / grade (LR2.exe strings at VA 0x4a9f80-0x4aa004). The release notes say course files come from the IR ranking page, to join that course's ranking (history.txt, beta3 090916).
Courses made in game start IR OFF.WriteCourse inserts a new course (NEW COURSE, RANDOM MIX) with ir = 0 (L17588-L17603).
Button 253 and text 183
Button 253 (L11141-L11153): when the selected course's flag is 1 the button is drawn at cell 1 and does nothing. When it is 0, a click steps it in 0-1 (so 0 → 1), plays option_change and sets isCourseCreated, which saves the course with UPDATE ... SET title, hash, ir=<courseIR> (L17604-L17616). The flag is one-way in game: once ON it cannot be turned OFF.
Text 183 is optionstr.csv row 24, #COURSE_IR,OFF,ON (L8406). It is set for any bar, so a song bar or a non-course bar reads OFF.
What "read-only" covers
WriteCourse returns at once for a read-only course (L17580-L17584), and buttons 240-248 (NONSTOP connections) are locked for an IR course (L11126-L11129). So the course's stages, connections and hash can no longer change, and the hash (which keys the score and the IR ranking) stays stable.
Not covered: renaming (text 170 → ChangeCourseTitle, L8686-L8691, L17625) and deleting (button 233 → DeleteCourse, L11107-L11115) still work on an IR course.
What the flag does online
On the select screen, IR ranking auto-update starts for a course only when its flag is set (L8452-L8460).
At the course result: with the flag OFF and online, the IR rank is cleared and text 20 reads このコースはIRに対応していません。 ("this course does not support IR"). With the flag ON, the score is sent, unless a long-sound option was used (このコースはIRに登録できません) (L9686-L9710, and the early return at L9517-L9519).
beatoraja
CourseData.release ("公開するかどうか", whether to publish), default true (CourseData.java L31-L34). It only gates the IR send of a course result: send = isUpdateCourseScore() && getCourseData().isRelease() (CourseResult.java L95-L96). It does not make a course read-only.
Courses from an IR table get release = true (BarManager.java L180); a new course in the launcher's course editor starts with release = false (CourseEditorView.java L221-L223), with a checkbox to change it (L144, L181). Drawn random courses are release = false.
So the defaults line up: imported / IR-table courses ranked, self-made courses not ranked until the player says so. The difference is that LR2 also freezes the course once it is flagged.
be-music today
CourseDefinition.release exists (packages/player/src/course/definition.ts) and gates ranking only (packages/player/src/playlog/course-eligibility.ts, reason unreleased).
.lr2crs import sets release: true (packages/player/src/course/lr2crs.ts), which matches LR2.exe's ir = 1.
Courses made with the course maker also get release: true (packages/player/src/course/maker.ts, lr2CourseDefinition). LR2 inserts them with ir = 0 and beatoraja's editor with release = false, so both would keep them off the ranking by default.
Editing is already limited to the player's own courses (packages/player-web/src/session/select/select-session.ts, runCourseMaker: course.editable && maker.owns(...)), which is close to LR2's read-only rule for imported courses.
No button 253 or text 183 in packages/lr2-skin/src/ids/.
Proposed behaviour
Map LR2's IR flag to release: text 183 reads ON when the selected course bar's course is released, else OFF (and OFF on non-course bars, as LR2).
Button 253 on a course the player owns: turns release from false to true and then locks, like LR2; on a released course it shows cell 1 and does nothing. While locked, keep the stages and connections fixed (buttons 240-248 disabled), but still allow renaming and deleting, as LR2 does.
Make course-maker courses start with release: false, as both LR2 and beatoraja do. They become rankable once the player flips button 253 (or an equivalent toggle in the demo's course maker panel).
Open questions
Should be-music keep LR2's one-way flag, or allow turning it off (beatoraja's checkbox allows both ways)? One-way protects the course fingerprint that ranks it; two-way is friendlier.
Changing course-maker courses to release: false changes which existing runs the Leaderboard accepts. Is that wanted?
Activity
nulltask commentedon Oct 19, 2026
Findings
Sources: OpenLR2
LR2f.cpp@583a385, the LR2 beta3 binaries (LR2body.exe, andLR2.exe, the config program that imports course files) andLR2files/Config/optionstr.csv.Where the flag lives
.lr2crsfile. It is theircolumn of LR2's own course tables insong.db(CREATE TABLE expert|nonstop|grade(id, title, line, hash, ir), L19281-L19283). It is read as column 4 intocourseIR, andcourseIR == 1setscourseReadOnly(L18078-L18080).LR2.exereads onlytitle,lineandhashfrom a<courselist>(stringscourselist,hash,title,line, with noirortypetag next to them), and inserts every course withirfixed to 1:INSERT INTO expert (title,line,hash,ir) VALUES ('%q',%d,'%q',1), and the same fornonstop/grade(LR2.exestrings at VA 0x4a9f80-0x4aa004). The release notes say course files come from the IR ranking page, to join that course's ranking (history.txt, beta3 090916).WriteCourseinserts a new course (NEW COURSE, RANDOM MIX) withir = 0(L17588-L17603).Button 253 and text 183
option_changeand setsisCourseCreated, which saves the course withUPDATE ... SET title, hash, ir=<courseIR>(L17604-L17616). The flag is one-way in game: once ON it cannot be turned OFF.optionstr.csvrow 24,#COURSE_IR,OFF,ON(L8406). It is set for any bar, so a song bar or a non-course bar readsOFF.What "read-only" covers
WriteCoursereturns at once for a read-only course (L17580-L17584), and buttons 240-248 (NONSTOP connections) are locked for an IR course (L11126-L11129). So the course's stages, connections and hash can no longer change, and the hash (which keys the score and the IR ranking) stays stable.ChangeCourseTitle, L8686-L8691, L17625) and deleting (button 233 →DeleteCourse, L11107-L11115) still work on an IR course.What the flag does online
このコースはIRに対応していません。("this course does not support IR"). With the flag ON, the score is sent, unless a long-sound option was used (このコースはIRに登録できません) (L9686-L9710, and the early return at L9517-L9519).beatoraja
CourseData.release("公開するかどうか", whether to publish), defaulttrue(CourseData.java L31-L34). It only gates the IR send of a course result:send = isUpdateCourseScore() && getCourseData().isRelease()(CourseResult.java L95-L96). It does not make a course read-only.release = true(BarManager.java L180); a new course in the launcher's course editor starts withrelease = false(CourseEditorView.java L221-L223), with a checkbox to change it (L144, L181). Drawn random courses arerelease = false.be-music today
CourseDefinition.releaseexists (packages/player/src/course/definition.ts) and gates ranking only (packages/player/src/playlog/course-eligibility.ts, reasonunreleased)..lr2crsimport setsrelease: true(packages/player/src/course/lr2crs.ts), which matches LR2.exe'sir = 1.release: true(packages/player/src/course/maker.ts,lr2CourseDefinition). LR2 inserts them withir = 0and beatoraja's editor withrelease = false, so both would keep them off the ranking by default.packages/player-web/src/session/select/select-session.ts,runCourseMaker:course.editable && maker.owns(...)), which is close to LR2's read-only rule for imported courses.packages/lr2-skin/src/ids/.Proposed behaviour
release: text 183 readsONwhen the selected course bar's course is released, elseOFF(andOFFon non-course bars, as LR2).releasefrom false to true and then locks, like LR2; on a released course it shows cell 1 and does nothing. While locked, keep the stages and connections fixed (buttons 240-248 disabled), but still allow renaming and deleting, as LR2 does.release: false, as both LR2 and beatoraja do. They become rankable once the player flips button 253 (or an equivalent toggle in the demo's course maker panel).Open questions
release: falsechanges which existing runs the Leaderboard accepts. Is that wanted?