Lyrics, search, and other fixes

- #LYRIC
  - Parse #LYRIC commands and apply them to all difficulties that do not have them
  - #LYRIC command now supports branches
  - Fix last #LYRIC at the end of the chart getting ignored
- Fix the glitchy dragging and dropping of files on the custom song importing page
- Fix Ctrl and Shift keys getting stuck on song select when switching tabs with Ctrl(+Shift)+Tab
- Search
  - Fix the search box "random:yes" query to randomize the entire results and not just the first 50
  - Add "all:yes" query to the search box to remove the result limit and display all of the results
  - Fix searching for an invalid query (like "cleared:yes" or ":") unexpectedly returning all the songs
  - Fix pressing Q then jumping to a song through search not unmuting the sound
  - Pressing the search key on mobile will hide the keyboard
  - Fix search tips changing rapidly when the window is resized
- Use comments instead of `######` in the issue template so that the warning does not appear in the issue
- Fix TJA MAKER: url between angle brackets not working
- Add a check for Class field declarations in the browser support warning
- Fix gpicker getting stuck if a network error occurs
- Fix not being able to replace some assets using a "taiko-web assets" folder
- Fix selectable song title not being aligned with the game if the game window is too wide
- Allow plugin developers to use the "select" type for the settings options
  - It uses "options" array and "options_lang" object
- Fix plugins not getting removed from the plugin list on syntax error
- Fix error messages not working if a default plugin is broken
- Fix the start of default plugins not stopping the page from loading on error
- Fix not being able to scroll the plugins screen on mobile
This commit is contained in:
KatieFrogs 2022-07-15 16:00:43 +02:00
parent 7722813879
commit e43c4afceb
16 changed files with 354 additions and 180 deletions

View File

@ -1,3 +1,3 @@
###### 下記の問題を説明してください。 スクリーンショットと診断情報を含めてください。 <!--下記の問題を説明してください。 スクリーンショットと診断情報を含めてください。-->
###### Describe the problem you are having below. Please include a screenshot and the diagnostic information. <!--Describe the problem you are having below. Please include a screenshot and the diagnostic information.-->

View File

@ -14,6 +14,10 @@ function browserSupport(){
eval("class a{}") eval("class a{}")
return true return true
}, },
"Class field declarations": function(){
eval("class a{a=1}")
return true
},
"Array.find": function(){ "Array.find": function(){
return "find" in Array.prototype && "findIndex" in Array.prototype return "find" in Array.prototype && "findIndex" in Array.prototype
}, },

View File

@ -462,8 +462,8 @@
config.selectable.innerHTML = "" config.selectable.innerHTML = ""
var scale = config.selectableScale var scale = config.selectableScale
var style = config.selectable.style var style = config.selectable.style
style.left = (config.x - config.width / 2) * scale + "px" style.left = ((config.x - config.width / 2) * scale + (config.selectableX || 0)) + "px"
style.top = config.y * scale + "px" style.top = (config.y * scale + (config.selectableY || 0)) + "px"
style.width = config.width * scale + "px" style.width = config.width * scale + "px"
style.height = (drawnHeight+15) * scale + "px" style.height = (drawnHeight+15) * scale + "px"
style.fontSize = 40 * mul * scale + "px" style.fontSize = 40 * mul * scale + "px"

View File

@ -89,6 +89,11 @@ class CustomSongs{
var dropContent = this.dropzone.getElementsByClassName("view-content")[0] var dropContent = this.dropzone.getElementsByClassName("view-content")[0]
dropContent.innerText = strings.customSongs.dropzone dropContent.innerText = strings.customSongs.dropzone
this.dragging = false this.dragging = false
this.dragTarget = null
pageEvents.add(document, "dragenter", event => {
event.preventDefault()
this.dragTarget = event.target
})
pageEvents.add(document, "dragover", event => { pageEvents.add(document, "dragover", event => {
event.preventDefault() event.preventDefault()
if(!this.locked){ if(!this.locked){
@ -100,8 +105,11 @@ class CustomSongs{
} }
}) })
pageEvents.add(document, "dragleave", () => { pageEvents.add(document, "dragleave", () => {
if(this.dragTarget === event.target){
event.preventDefault()
this.dropzone.classList.remove("dragover") this.dropzone.classList.remove("dragover")
this.dragging = false this.dragging = false
}
}) })
pageEvents.add(document, "drop", this.filesDropped.bind(this)) pageEvents.add(document, "drop", this.filesDropped.bind(this))
} }
@ -522,8 +530,9 @@ class CustomSongs{
pageEvents.remove(this.errorDiv, ["mousedown", "touchstart"]) pageEvents.remove(this.errorDiv, ["mousedown", "touchstart"])
pageEvents.remove(this.errorEnd, ["mousedown", "touchstart"]) pageEvents.remove(this.errorEnd, ["mousedown", "touchstart"])
if(DataTransferItem.prototype.webkitGetAsEntry){ if(DataTransferItem.prototype.webkitGetAsEntry){
pageEvents.remove(document, ["dragover", "dragleave", "drop"]) pageEvents.remove(document, ["dragenter", "dragover", "dragleave", "drop"])
delete this.dropzone delete this.dropzone
delete this.dragTarget
} }
if(gpicker){ if(gpicker){
gpicker.tokenResolve = null gpicker.tokenResolve = null

View File

@ -172,7 +172,8 @@ class Game{
var measure = measures[i] var measure = measures[i]
if(measure.ms > ms){ if(measure.ms > ms){
break break
}else if(measure.nextBranch && !measure.gameChecked){ }else{
if(measure.nextBranch && !measure.gameChecked){
measure.gameChecked = true measure.gameChecked = true
var branch = measure.nextBranch var branch = measure.nextBranch
if(branch.type){ if(branch.type){
@ -201,9 +202,19 @@ class Game{
p2.send("branch", "normal") p2.send("branch", "normal")
} }
} }
if(!measure.branch){
this.controller.lyrics.branch = null
}else if(measure.branch.active){
this.controller.lyrics.branch = measure.branch.name
} }
} }
} }
}
if(this.controller.lyrics){
this.controller.lyrics.update(ms)
}
}
fixNoteStream(keysDon){ fixNoteStream(keysDon){
var circleIsNote = circle => { var circleIsNote = circle => {
var type = circle.type var type = circle.type

View File

@ -14,7 +14,7 @@ class Gpicker{
this.clientCallbackBind = this.clientCallback.bind(this) this.clientCallbackBind = this.clientCallback.bind(this)
} }
browse(lockedCallback, errorCallback){ browse(lockedCallback, errorCallback){
return this.loadApi() return this.loadApi(lockedCallback, errorCallback)
.then(() => this.getToken(lockedCallback, errorCallback)) .then(() => this.getToken(lockedCallback, errorCallback))
.then(() => new Promise((resolve, reject) => { .then(() => new Promise((resolve, reject) => {
this.displayPicker(data => { this.displayPicker(data => {
@ -120,7 +120,7 @@ class Gpicker{
}) })
})) }))
} }
loadApi(){ loadApi(lockedCallback=()=>{}, errorCallback=()=>{}){
if(window.gapi && gapi.client && gapi.client.drive){ if(window.gapi && gapi.client && gapi.client.drive){
return Promise.resolve() return Promise.resolve()
} }
@ -128,15 +128,27 @@ class Gpicker{
loader.loadScript("https://apis.google.com/js/api.js"), loader.loadScript("https://apis.google.com/js/api.js"),
loader.loadScript("https://accounts.google.com/gsi/client") loader.loadScript("https://accounts.google.com/gsi/client")
] ]
var apiLoaded = false
return Promise.all(promises).then(() => new Promise((resolve, reject) => return Promise.all(promises).then(() => new Promise((resolve, reject) =>
gapi.load("picker:client", { gapi.load("picker:client", {
callback: resolve, callback: resolve,
onerror: reject onerror: reject
}) })
)) ))
.then(() => new Promise((resolve, reject) => .then(() => new Promise((resolve, reject) => {
gapi.client.load("drive", "v3").then(resolve, reject) setTimeout(() => {
)) if(!apiLoaded){
lockedCallback(false)
}
}, 3000)
return gapi.client.load("drive", "v3").then(resolve, reject)
})).then(() => {
apiLoaded = true
lockedCallback(true)
}).catch(e => {
errorCallback(Array.isArray(e) ? e[0] : e)
return Promise.reject("cancel")
})
} }
getClient(errorCallback=()=>{}, force){ getClient(errorCallback=()=>{}, force){
var obj = { var obj = {

View File

@ -37,17 +37,14 @@
} }
} }
}) })
this.assetSelectors = { this.assetSelectors = {}
"bg-pattern-1": ".pattern-bg", for(var selector in assets.cssBackground){
"bg_genre_0": "#song-select", var filename = assets.cssBackground[selector]
"title-screen": "#title-screen", var index = filename.lastIndexOf(".")
"dancing-don": "#loading-don", if(index !== -1){
"touch_drum": "#touch-drum-img", filename = filename.slice(0, index)
"touch_fullscreen": "#touch-full-btn", }
"touch_pause": "#touch-pause-btn", this.assetSelectors[filename] = selector
"bg_stage_1": ".song-stage-1",
"bg_stage_2": ".song-stage-2",
"bg_stage_3": ".song-stage-3"
} }
this.comboVoices = ["v_combo_50"].concat(Array.from(Array(50), (d, i) => "v_combo_" + ((i + 1) * 100))) this.comboVoices = ["v_combo_50"].concat(Array.from(Array(50), (d, i) => "v_combo_" + ((i + 1) * 100)))
} }
@ -64,7 +61,7 @@
var file = files[i] var file = files[i]
var name = file.name.toLowerCase() var name = file.name.toLowerCase()
var path = file.path.toLowerCase() var path = file.path.toLowerCase()
if(name.endsWith(".tja")){ if(name.endsWith(".tja") || name.endsWith(".tjf")){
this.tjaFiles.push({ this.tjaFiles.push({
file: file, file: file,
index: i index: i
@ -292,9 +289,9 @@
if(gt === maker.length - 1){ if(gt === maker.length - 1){
var lt = maker.lastIndexOf("<") var lt = maker.lastIndexOf("<")
if(lt !== -1 && lt !== gt - 2){ if(lt !== -1 && lt !== gt - 2){
url = maker.slice(lt + 2, gt) url = maker.slice(lt + 1, gt).trim()
if(url.startsWith("http://") || url.startsWith("https://")){ if(url.startsWith("http://") || url.startsWith("https://")){
maker = maker.slice(0, lt).trim() maker = maker.slice(0, lt)
}else{ }else{
url = null url = null
} }
@ -452,12 +449,20 @@
vectors = JSON.parse(response) vectors = JSON.parse(response)
})) }))
} }
if(name.endsWith(".png")){ if(name.endsWith(".png") || name.endsWith(".gif")){
let image = document.createElement("img") let image = document.createElement("img")
promises.push(pageEvents.load(image).then(() => { promises.push(pageEvents.load(image).then(() => {
if(id in this.assetSelectors){ if(id in this.assetSelectors){
var selector = this.assetSelectors[id] var selector = this.assetSelectors[id]
this.stylesheet.push(selector + '{background-image:url("' + image.src + '")}') var gradient = ""
if(selector === "#song-search"){
gradient = loader.songSearchGradient
}
this.stylesheet.push(loader.cssRuleset({
[selector]: {
"background-image": gradient + "url(\"" + image.src + "\")"
}
}))
} }
})) }))
image.id = name image.id = name

View File

@ -9,6 +9,7 @@ class Loader{
this.screen = document.getElementById("screen") this.screen = document.getElementById("screen")
this.startTime = Date.now() this.startTime = Date.now()
this.errorMessages = [] this.errorMessages = []
this.songSearchGradient = "linear-gradient(to top, rgba(245, 246, 252, 0.08), #ff5963), "
var promises = [] var promises = []
@ -105,7 +106,7 @@ class Loader{
if(selector === ".pattern-bg"){ if(selector === ".pattern-bg"){
loader.screen.style.backgroundImage = "url(\"" + blobUrl + "\")" loader.screen.style.backgroundImage = "url(\"" + blobUrl + "\")"
}else if(selector === "#song-search"){ }else if(selector === "#song-search"){
gradient = "linear-gradient(to top, rgba(245, 246, 252, 0.08), #ff5963), " gradient = this.songSearchGradient
} }
css.push(this.cssRuleset({ css.push(this.cssRuleset({
[selector]: { [selector]: {
@ -377,9 +378,9 @@ class Loader{
plugin.loadErrors = true plugin.loadErrors = true
promises.push(plugin.load(true).then(() => { promises.push(plugin.load(true).then(() => {
if(obj.start){ if(obj.start){
plugin.start() return plugin.start(false, true)
} }
}, response => { }).catch(response => {
return this.errorMsg(response, obj.url) return this.errorMsg(response, obj.url)
})) }))
} }
@ -394,14 +395,14 @@ class Loader{
this.callback(songId) this.callback(songId)
this.ready = true this.ready = true
pageEvents.send("ready", readyEvent) pageEvents.send("ready", readyEvent)
}, () => this.errorMsg()) }, e => this.errorMsg(e))
}, () => this.errorMsg()) }, e => this.errorMsg(e))
}) })
} }
addPromise(promise, url){ addPromise(promise, url){
this.promises.push(promise) this.promises.push(promise)
promise.then(this.assetLoaded.bind(this), response => { promise.then(this.assetLoaded.bind(this), response => {
this.errorMsg(response, url) return this.errorMsg(response, url)
}) })
} }
soundUrl(name){ soundUrl(name){
@ -417,9 +418,20 @@ class Loader{
return name.slice(0, name.lastIndexOf(".")) return name.slice(0, name.lastIndexOf("."))
} }
errorMsg(error, url){ errorMsg(error, url){
var rethrow
if(url || error){ if(url || error){
if(typeof error === "object" && error.constructor === Error){
rethrow = error
error = error.stack || ""
var index = error.indexOf("\n ")
if(index !== -1){
error = error.slice(0, index)
}
}else if(Array.isArray(error)){
error = error[0]
}
if(url){ if(url){
error = (Array.isArray(error) ? error[0] + ": " : (error ? error + ": " : "")) + url error = (error ? error + ": " : "") + url
} }
this.errorMessages.push(error) this.errorMessages.push(error)
pageEvents.send("loader-error", url || error) pageEvents.send("loader-error", url || error)
@ -495,7 +507,10 @@ class Loader{
} }
var percentage = Math.floor(this.loadedAssets * 100 / (this.promises.length + this.afterJSCount)) var percentage = Math.floor(this.loadedAssets * 100 / (this.promises.length + this.afterJSCount))
this.errorTxt.element[this.errorTxt.method] = "```\n" + this.errorMessages.join("\n") + "\nPercentage: " + percentage + "%\n```" this.errorTxt.element[this.errorTxt.method] = "```\n" + this.errorMessages.join("\n") + "\nPercentage: " + percentage + "%\n```"
return Promise.reject(error) if(rethrow || error){
console.error(rethrow || error)
}
return Promise.reject()
} }
assetLoaded(){ assetLoaded(){
if(!this.error){ if(!this.error){

View File

@ -131,12 +131,14 @@ class Lyrics{
} }
ms += this.songOffset + this.vttOffset ms += this.songOffset + this.vttOffset
var currentLine = this.lines[this.current] var currentLine = this.lines[this.current]
while(currentLine && ms > currentLine.end){ while(currentLine && (ms > currentLine.end || currentLine.branch && this.branch && currentLine.branch !== this.branch)){
currentLine = this.lines[++this.current] currentLine = this.lines[++this.current]
} }
if(this.shown !== this.current){ if(this.shown !== this.current){
if(currentLine && ms >= currentLine.start){ if(currentLine && ms >= currentLine.start){
this.setText(this.lines[this.current].text) if(!currentLine.copy){
this.setText(currentLine.text)
}
this.shown = this.current this.shown = this.current
}else if(this.shown !== -1){ }else if(this.shown !== -1){
this.setText("") this.setText("")

View File

@ -48,7 +48,7 @@
this.beatInfo = {} this.beatInfo = {}
this.events = [] this.events = []
if(!metaOnly){ if(!metaOnly){
this.circles = this.parseCircles() this.circles = this.parseCircles(difficulty)
} }
} }
parseMetadata(){ parseMetadata(){
@ -135,13 +135,15 @@
} }
return [string.slice(0, index), string.slice(index + delimiter.length)] return [string.slice(0, index), string.slice(index + delimiter.length)]
} }
parseCircles(){ parseCircles(difficulty, lyricsOnly){
var meta = this.metadata[this.difficulty] || {} var meta = this.metadata[difficulty] || {}
var ms = (meta.offset || 0) * -1000 + this.offset var ms = (meta.offset || 0) * -1000 + this.offset
var bpm = Math.abs(meta.bpm) || 120 var bpm = Math.abs(meta.bpm) || 120
var scroll = 1 var scroll = 1
var measure = 4 var measure = 4
if(!lyricsOnly){
this.beatInfo.beatInterval = 60000 / bpm this.beatInfo.beatInterval = 60000 / bpm
}
var gogo = false var gogo = false
var barLine = true var barLine = true
@ -150,6 +152,7 @@
var lastDrumroll = false var lastDrumroll = false
var branches
var branch = false var branch = false
var branchObj = {} var branchObj = {}
var currentBranch = false var currentBranch = false
@ -158,12 +161,17 @@
var sectionBegin = true var sectionBegin = true
var lastBpm = bpm var lastBpm = bpm
var lastGogo = gogo var lastGogo = gogo
var lyrics
var lyricsIndex = null
var lyricsLine = null var lyricsLine = null
var lyricsCopy = false
var measures = []
var currentMeasure = [] var currentMeasure = []
var firstNote = true var firstNote = true
var circles = [] var circles = []
var circleID = 0 var circleID = 0
var events = []
var regexAZ = /[A-Z]/ var regexAZ = /[A-Z]/
var regexSpace = /\s/ var regexSpace = /\s/
var regexLinebreak = /\\n/g var regexLinebreak = /\\n/g
@ -200,7 +208,8 @@
}else{ }else{
var speed = bpm * scroll / 60 var speed = bpm * scroll / 60
} }
this.measures.push({ if(!lyricsOnly){
measures.push({
ms: ms, ms: ms,
originalMS: ms, originalMS: ms,
speed: speed, speed: speed,
@ -208,6 +217,7 @@
branch: currentBranch, branch: currentBranch,
branchFirst: branchFirstMeasure branchFirst: branchFirstMeasure
}) })
}
branchFirstMeasure = false branchFirstMeasure = false
if(currentMeasure.length){ if(currentMeasure.length){
for(var i = 0; i < currentMeasure.length; i++){ for(var i = 0; i < currentMeasure.length; i++){
@ -229,8 +239,8 @@
} }
var note_chain = []; var note_chain = [];
for (var i = 0; i < currentMeasure.length; i++){ for (var i = 0; i < currentMeasure.length; i++){
//console.log(note_chain.length);
var note = currentMeasure[i] var note = currentMeasure[i]
if(!lyricsOnly){
circleID++ circleID++
var circleObj = new Circle({ var circleObj = new Circle({
id: circleID, id: circleID,
@ -245,14 +255,14 @@
branch: currentBranch, branch: currentBranch,
section: note.section section: note.section
}) })
if (note.type) { if(note.type){
if (note.type === "don" || note.type === "ka" || note.type === "daiDon" || note.type === "daiKa") { if(note.type === "don" || note.type === "ka" || note.type === "daiDon" || note.type === "daiKa"){
note_chain.push(circleObj); note_chain.push(circleObj)
} else { }else{
if (note_chain.length > 1 && currentMeasure.length >= 8) { if(note_chain.length > 1 && currentMeasure.length >= 8){
checkChain(note_chain, currentMeasure.length, false); checkChain(note_chain, currentMeasure.length, false)
} }
note_chain = []; note_chain = []
} }
if (lastDrumroll === note) { if (lastDrumroll === note) {
lastDrumroll = circleObj lastDrumroll = circleObj
@ -261,31 +271,47 @@
if(note.type !== "event"){ if(note.type !== "event"){
circles.push(circleObj) circles.push(circleObj)
} }
} else if (!(currentMeasure.length >= 24 && (!currentMeasure[i + 1] || currentMeasure[i + 1].type)) }else if(
&& !(currentMeasure.length >= 48 && (!currentMeasure[i + 2] || currentMeasure[i + 2].type || !currentMeasure[i + 3] || currentMeasure[i + 3].type))) { (currentMeasure.length < 24 ||
if (note_chain.length > 1 && currentMeasure.length >= 8) { currentMeasure[i + 1]
checkChain(note_chain, currentMeasure.length, true); && !currentMeasure[i + 1].type
) && (currentMeasure.length < 48 ||
currentMeasure[i + 2]
&& !currentMeasure[i + 2].type
&& currentMeasure[i + 3]
&& !currentMeasure[i + 3].type
)
){
if(note_chain.length > 1 && currentMeasure.length >= 8){
checkChain(note_chain, currentMeasure.length, true)
} }
note_chain = []; note_chain = []
} }
if(note.event){ if(note.event){
this.events.push(circleObj) events.push(circleObj)
} }
}
var lyricsObj = null
if("lyricsLine" in note){ if("lyricsLine" in note){
if(!this.lyrics){ lyricsObj = {
this.lyrics = []
}
if(this.lyrics.length !== 0){
this.lyrics[this.lyrics.length - 1].end = note.start
}
this.lyrics.push({
start: note.start, start: note.start,
text: note.lyricsLine text: note.lyricsLine
}) }
}else if(note.lyricsCopy){
lyricsObj = {
start: note.start,
copy: true
} }
} }
if (note_chain.length > 1 && currentMeasure.length >= 8) { if(lyricsObj){
checkChain(note_chain, currentMeasure.length, false); if(currentBranch){
lyricsObj.branch = currentBranch.name
}
insertLyrics(lyricsObj)
}
}
if(!lyricsOnly && note_chain.length > 1 && currentMeasure.length >= 8){
checkChain(note_chain, currentMeasure.length, false)
} }
}else{ }else{
var msPerMeasure = 60000 * measure / bpm var msPerMeasure = 60000 * measure / bpm
@ -302,7 +328,10 @@
if(lyricsLine !== null){ if(lyricsLine !== null){
circleObj.lyricsLine = lyricsLine circleObj.lyricsLine = lyricsLine
lyricsLine = null lyricsLine = null
}else if(lyricsCopy){
circleObj.lyricsCopy = true
} }
lyricsCopy = false
currentMeasure.push(circleObj) currentMeasure.push(circleObj)
} }
} }
@ -322,17 +351,32 @@
if(lyricsLine !== null){ if(lyricsLine !== null){
circleObj2.lyricsLine = lyricsLine circleObj2.lyricsLine = lyricsLine
lyricsLine = null lyricsLine = null
}else if(lyricsCopy){
circleObj2.lyricsCopy = true
} }
lyricsCopy = false
currentMeasure.push(circleObj2) currentMeasure.push(circleObj2)
} }
if(circleObj){ if(circleObj){
if(lyricsLine !== null){ if(lyricsLine !== null){
circleObj.lyricsLine = lyricsLine circleObj.lyricsLine = lyricsLine
lyricsLine = null lyricsLine = null
}else if(lyricsCopy){
circleObj.lyricsCopy = true
} }
lyricsCopy = false
currentMeasure.push(circleObj) currentMeasure.push(circleObj)
} }
} }
var insertLyrics = obj => {
if(!lyrics){
lyrics = []
}else if(lyricsIndex !== null){
lyrics[lyricsIndex].end = obj.start
}
lyricsIndex = lyrics.length
lyrics.push(obj)
}
for(var lineNum = meta.start; lineNum < meta.end; lineNum++){ for(var lineNum = meta.start; lineNum < meta.end; lineNum++){
var line = this.data[lineNum] var line = this.data[lineNum]
@ -377,11 +421,18 @@
gogo: gogo, gogo: gogo,
bpm: bpm, bpm: bpm,
scroll: scroll, scroll: scroll,
sectionBegin: sectionBegin sectionBegin: sectionBegin,
lyricsCopy: !!lyrics
} }
if(lyrics && lyricsIndex !== null){
var line = lyrics[lyricsIndex]
line.end = ms
}
lyricsIndex = null
value = value.split(",") value = value.split(",")
if(!this.branches){ if(!branches){
this.branches = [] branches = []
} }
var req = { var req = {
advanced: parseFloat(value[1]) || 0, advanced: parseFloat(value[1]) || 0,
@ -399,12 +450,12 @@
type: value[0].trim().toLowerCase() === "r" ? "drumroll" : "accuracy", type: value[0].trim().toLowerCase() === "r" ? "drumroll" : "accuracy",
requirement: req requirement: req
} }
this.branches.push(branchObj) branches.push(branchObj)
if(this.measures.length === 1 && branchObj.type === "drumroll"){ if(measures.length === 1 && branchObj.type === "drumroll"){
for(var i = circles.length; i--;){ for(var i = circles.length; i--;){
var circle = circles[i] var circle = circles[i]
if(circle.endTime && circle.type === "drumroll" || circle.type === "daiDrumroll" || circle.type === "balloon"){ if(circle.endTime && (circle.type === "drumroll" || circle.type === "daiDrumroll" || circle.type === "balloon")){
this.measures.push({ measures.push({
ms: circle.endTime, ms: circle.endTime,
originalMS: circle.endTime, originalMS: circle.endTime,
speed: circle.bpm * circle.scroll / 60, speed: circle.bpm * circle.scroll / 60,
@ -415,13 +466,14 @@
} }
} }
} }
if(this.measures.length !== 0){ if(measures.length !== 0){
this.measures[this.measures.length - 1].nextBranch = branchObj measures[measures.length - 1].nextBranch = branchObj
} }
break break
case "branchend": case "branchend":
branch = false branch = false
currentBranch = false currentBranch = false
lyricsCopy = lyricsCopy || !!lyrics
break break
case "section": case "section":
sectionBegin = true sectionBegin = true
@ -433,11 +485,19 @@
if(!branch){ if(!branch){
break break
} }
if(lyrics){
if(lyricsIndex !== null){
var line = lyrics[lyricsIndex]
line.end = ms
}
lyricsIndex = null
}
ms = branchSettings.ms ms = branchSettings.ms
gogo = branchSettings.gogo gogo = branchSettings.gogo
bpm = branchSettings.bpm bpm = branchSettings.bpm
scroll = branchSettings.scroll scroll = branchSettings.scroll
sectionBegin = branchSettings.sectionBegin sectionBegin = branchSettings.sectionBegin
lyricsCopy = branchSettings.lyricsCopy
branchFirstMeasure = true branchFirstMeasure = true
var branchName = name === "m" ? "master" : (name === "e" ? "advanced" : "normal") var branchName = name === "m" ? "master" : (name === "e" ? "advanced" : "normal")
currentBranch = { currentBranch = {
@ -556,31 +616,52 @@
} }
} }
pushMeasure()
if(lastDrumroll){ if(lastDrumroll){
lastDrumroll.endTime = ms lastDrumroll.endTime = ms
lastDrumroll.originalEndTime = ms lastDrumroll.originalEndTime = ms
} }
if(lyricsLine !== null){
insertLyrics({
start: ms,
text: lyricsLine
})
}
pushMeasure()
if(this.branches){ if(!lyricsOnly){
if(branches){
circles.sort((a, b) => a.ms > b.ms ? 1 : -1) circles.sort((a, b) => a.ms > b.ms ? 1 : -1)
this.measures.sort((a, b) => a.ms > b.ms ? 1 : -1) measures.sort((a, b) => a.ms > b.ms ? 1 : -1)
circles.forEach((circle, i) => circle.id = i + 1) circles.forEach((circle, i) => circle.id = i + 1)
} }
this.scoreinit = meta.scoreinit; this.measures = measures
this.scorediff = meta.scorediff; this.events = events
if (this.scoreinit && this.scorediff) { this.branches = branches
this.scoremode = meta.scoremode || 1; this.scoreinit = meta.scoreinit
} else { this.scorediff = meta.scorediff
this.scoremode = meta.scoremode || 2; if(this.scoreinit && this.scorediff){
var autoscore = new AutoScore(this.difficulty, this.stars, this.scoremode, circles); this.scoremode = meta.scoremode || 1
this.scoreinit = autoscore.ScoreInit; }else{
this.scorediff = autoscore.ScoreDiff; this.scoremode = meta.scoremode || 2
var autoscore = new AutoScore(difficulty, this.stars, this.scoremode, circles)
this.scoreinit = autoscore.ScoreInit
this.scorediff = autoscore.ScoreDiff
} }
if(this.lyrics){ }
var line = this.lyrics[this.lyrics.length - 1] if(lyrics && lyricsIndex !== null){
var line = lyrics[lyricsIndex]
line.end = Math.max(ms, line.start) + 5000 line.end = Math.max(ms, line.start) + 5000
} }
if(lyrics){
this.lyrics = lyrics
}else if(!lyricsOnly){
for(var courseName in this.metadata){
if(this.metadata[courseName].inlineLyrics){
this.parseCircles(courseName, true)
break
}
}
}
return circles return circles
} }
} }

View File

@ -373,6 +373,7 @@ class PluginLoader{
} }
}, e => { }, e => {
this.error() this.error()
plugins.remove(this.name)
if(e.name === "SyntaxError"){ if(e.name === "SyntaxError"){
var error = new SyntaxError() var error = new SyntaxError()
error.stack = "Error in plugin syntax: " + this.name + "\n" + e.stack error.stack = "Error in plugin syntax: " + this.name + "\n" + e.stack
@ -388,7 +389,7 @@ class PluginLoader{
}) })
} }
} }
start(orderChange){ start(orderChange, startErrors){
if(!orderChange){ if(!orderChange){
plugins.startOrder.push(this.name) plugins.startOrder.push(this.name)
} }
@ -403,10 +404,15 @@ class PluginLoader{
this.module.start() this.module.start()
} }
}catch(e){ }catch(e){
this.error()
var error = new Error() var error = new Error()
error.stack = "Error in plugin start: " + this.name + "\n" + e.stack error.stack = "Error in plugin start: " + this.name + "\n" + e.stack
if(startErrors){
return Promise.reject(error)
}else{
console.error(error) console.error(error)
this.error() return Promise.resolve()
}
} }
} }
}) })

View File

@ -49,9 +49,7 @@ class Search{
var results = [] var results = []
var filters = {} var filters = {}
var querySplit = query.split(" ") var querySplit = query.split(" ").filter(word => {
var editedSplit = query.split(" ")
querySplit.forEach(word => {
if(word.length > 0){ if(word.length > 0){
var parts = word.toLowerCase().split(":") var parts = word.toLowerCase().split(":")
if(parts.length > 1){ if(parts.length > 1){
@ -82,19 +80,23 @@ class Search{
case "maker": case "maker":
case "diverge": case "diverge":
case "random": case "random":
case "all":
filters[parts[0]] = parts[1] filters[parts[0]] = parts[1]
break break
default:
return true
} }
return false
editedSplit.splice(editedSplit.indexOf(word), 1)
} }
} }
return true
}) })
query = this.normalizeString(editedSplit.join(" ").trim()) query = this.normalizeString(querySplit.join(" ").trim())
var totalFilters = Object.keys(filters).length var totalFilters = Object.keys(filters).length
var random = false var random = false
var allResults = false
for(var i = 0; i < assets.songs.length; i++){ for(var i = 0; i < assets.songs.length; i++){
var song = assets.songs[i] var song = assets.songs[i]
var passedFilters = 0 var passedFilters = 0
@ -169,6 +171,12 @@ class Search{
passedFilters++ passedFilters++
} }
break break
case "all":
if(value === "yes" || value === "no"){
allResults = value === "yes"
passedFilters++
}
break
} }
}) })
@ -177,7 +185,7 @@ class Search{
} }
} }
var maxResults = totalFilters > 0 && !query ? 100 : 50 var maxResults = allResults ? Infinity : (totalFilters > 0 && !query ? 100 : 50)
if(query){ if(query){
results = fuzzysort.go(query, results, { results = fuzzysort.go(query, results, {
@ -233,6 +241,15 @@ class Search{
} }
} }
} }
if(random){
var rand = Math.random() * -9000
if(score0 !== -Infinity){
score0 = rand
}
if(score1 !== -Infinity){
score1 = rand
}
}
if(a[0]){ if(a[0]){
return a[1] ? Math.max(score0, score1) : score0 return a[1] ? Math.max(score0, score1) : score0
}else{ }else{
@ -241,10 +258,6 @@ class Search{
} }
}) })
}else{ }else{
results = results.slice(0, maxResults).map(result => {
return {obj: result}
})
}
if(random){ if(random){
for(var i = results.length - 1; i > 0; i--){ for(var i = results.length - 1; i > 0; i--){
var j = Math.floor(Math.random() * (i + 1)) var j = Math.floor(Math.random() * (i + 1))
@ -253,6 +266,10 @@ class Search{
results[j] = temp results[j] = temp
} }
} }
results = results.slice(0, maxResults).map(result => {
return {obj: result}
})
}
return results return results
} }
@ -402,7 +419,7 @@ class Search{
this.input = this.div.querySelector(":scope #song-search-input") this.input = this.div.querySelector(":scope #song-search-input")
this.input.setAttribute("placeholder", strings.search.searchInput) this.input.setAttribute("placeholder", strings.search.searchInput)
pageEvents.add(this.input, ["input"], this.onInput.bind(this)) pageEvents.add(this.input, ["input"], () => this.onInput())
this.songSelect.playSound("se_pause") this.songSelect.playSound("se_pause")
loader.screen.appendChild(this.div) loader.screen.appendChild(this.div)
@ -484,6 +501,9 @@ class Search{
var song = this.songSelect.songs.find(song => song.id === songId) var song = this.songSelect.songs.find(song => song.id === songId)
this.remove() this.remove()
this.songSelect.playBgm(false) this.songSelect.playBgm(false)
if(this.songSelect.previewing === "muted"){
this.songSelect.previewing = null
}
var songIndex = this.songSelect.songs.findIndex(song => song.id === songId) var songIndex = this.songSelect.songs.findIndex(song => song.id === songId)
this.songSelect.setSelectedSong(songIndex) this.songSelect.setSelectedSong(songIndex)
@ -532,13 +552,15 @@ class Search{
return ranges return ranges
} }
onInput(){ onInput(resize){
var text = this.input.value var text = this.input.value
localStorage.setItem("lastSearchQuery", text) localStorage.setItem("lastSearchQuery", text)
text = text.toLowerCase() text = text.toLowerCase()
if(text.length === 0){ if(text.length === 0){
if(!resize){
this.setTip() this.setTip()
}
return return
} }
@ -623,6 +645,9 @@ class Search{
this.proceed(parseInt(this.results[this.active].dataset.songId)) this.proceed(parseInt(this.results[this.active].dataset.songId))
}else{ }else{
this.onInput() this.onInput()
if(event.keyCode === 13 && this.songSelect.touchEnabled){
this.input.blur()
}
} }
} }
} }

View File

@ -367,7 +367,7 @@ class SettingsView{
if(event.target.tagName !== "SPAN"){ if(event.target.tagName !== "SPAN"){
this.setValue(i) this.setValue(i)
} }
}) }, true)
}else{ }else{
this.addTouchEnd(settingBox, event => this.setValue(i)) this.addTouchEnd(settingBox, event => this.setValue(i))
} }
@ -494,9 +494,9 @@ class SettingsView{
} }
this.addTouch(settingBox, event => { this.addTouch(settingBox, event => {
if(event.target.tagName !== "SPAN"){ if(event.target.tagName !== "SPAN"){
this.latencySetValue(current, event.type === "touchstart") this.latencySetValue(current, event.type === "touchend")
} }
}) }, true)
if(current !== "calibration"){ if(current !== "calibration"){
outputObject.valueDiv = valueDiv outputObject.valueDiv = valueDiv
outputObject.valueText = valueText outputObject.valueText = valueText
@ -543,7 +543,9 @@ class SettingsView{
var touchEvent = end ? "touchend" : "touchstart" var touchEvent = end ? "touchend" : "touchstart"
pageEvents.add(element, ["mousedown", touchEvent], event => { pageEvents.add(element, ["mousedown", touchEvent], event => {
if(event.type === touchEvent){ if(event.type === touchEvent){
if(event.cancelable){
event.preventDefault() event.preventDefault()
}
this.touched = true this.touched = true
}else if(event.which !== 1){ }else if(event.which !== 1){
return return
@ -594,7 +596,11 @@ class SettingsView{
if(current.type === "language"){ if(current.type === "language"){
value = allStrings[value].name + " (" + value + ")" value = allStrings[value].name + " (" + value + ")"
}else if(current.type === "select" || current.type === "gamepad"){ }else if(current.type === "select" || current.type === "gamepad"){
if(current.options_lang && current.options_lang[value]){
value = this.getLocalTitle(value, current.options_lang[value])
}else if(!current.getItem){
value = strings.settings[name][value] value = strings.settings[name][value]
}
}else if(current.type === "toggle"){ }else if(current.type === "toggle"){
value = value ? strings.settings.on : strings.settings.off value = value ? strings.settings.on : strings.settings.off
}else if(current.type === "keyboard"){ }else if(current.type === "keyboard"){

View File

@ -412,7 +412,7 @@ class SongSelect{
if(name === "ctrl" || name === "shift" || !this.redrawRunning){ if(name === "ctrl" || name === "shift" || !this.redrawRunning){
return return
} }
var ctrl = this.pressedKeys["ctrl"] || this.pressedKeys["ctrlGamepad"] var ctrl = event ? event.ctrlKey : (this.pressedKeys["ctrl"] || this.pressedKeys["ctrlGamepad"])
var shift = event ? event.shiftKey : this.pressedKeys["shift"] var shift = event ? event.shiftKey : this.pressedKeys["shift"]
if(this.state.showWarning){ if(this.state.showWarning){
if(name === "confirm"){ if(name === "confirm"){
@ -1076,12 +1076,13 @@ class SongSelect{
this.selectableText = "" this.selectableText = ""
if(this.search.opened && this.search.container){ if(this.search.opened && this.search.container){
this.search.onInput() this.search.onInput(true)
} }
}else if(!document.hasFocus() && !p2.session){ }else if(!document.hasFocus() && !p2.session){
if(this.state.focused){ if(this.state.focused){
this.state.focused = false this.state.focused = false
this.songSelect.classList.add("unfocused") this.songSelect.classList.add("unfocused")
this.pressedKeys = {}
} }
return return
}else{ }else{
@ -2046,7 +2047,8 @@ class SongSelect{
fontSize: 40, fontSize: 40,
fontFamily: this.font, fontFamily: this.font,
selectable: this.selectable, selectable: this.selectable,
selectableScale: this.ratio / this.pixelRatio selectableScale: this.ratio / this.pixelRatio,
selectableX: Math.max(0, innerWidth / 2 - lastHeight * 16 / 9)
}) })
this.selectable.style.display = "" this.selectable.style.display = ""
this.selectableText = currentSong.title this.selectableText = currentSong.title

View File

@ -101,7 +101,7 @@ class Titlescreen{
}).then(() => { }).then(() => {
if(noError){ if(noError){
setTimeout(() => { setTimeout(() => {
new SongSelect("customSongs", false, this.touchEnabled) new SongSelect("customSongs", false, this.touched)
}, 500) }, 500)
} }
}) })

View File

@ -255,10 +255,6 @@
this.setDonBgHeight() this.setDonBgHeight()
} }
if(this.controller.lyrics){
this.controller.lyrics.update(ms)
}
ctx.save() ctx.save()
ctx.translate(0, frameTop) ctx.translate(0, frameTop)