diff --git a/app.py b/app.py index a51e90f..d7c18cf 100644 --- a/app.py +++ b/app.py @@ -190,15 +190,15 @@ def route_api_config(): @app.route('/api/register', methods=['POST']) def route_api_register(): - if session.get('username'): - return api_error('already_logged_in') - data = request.get_json() if not schema.validate(data, schema.register): return abort(400) + if session.get('username'): + session.clear() + username = data.get('username', '') - if len(username) > 20 or not re.match('^[a-zA-Z0-9_]{1,20}$', username): + if len(username) < 3 or len(username) > 20 or not re.match('^[a-zA-Z0-9_]{3,20}$', username): return api_error('invalid_username') if db.users.find_one({'username_lower': username.lower()}): @@ -226,13 +226,13 @@ def route_api_register(): @app.route('/api/login', methods=['POST']) def route_api_login(): - if session.get('username'): - return api_error('already_logged_in') - data = request.get_json() if not schema.validate(data, schema.login): return abort(400) + if session.get('username'): + session.clear() + username = data.get('username', '') result = db.users.find_one({'username_lower': username.lower()}) if not result: @@ -263,15 +263,17 @@ def route_api_account_display_name(): if not schema.validate(data, schema.update_display_name): return abort(400) - display_name = data.get('display_name', '') - if not display_name or len(display_name) > 20: + display_name = data.get('display_name', '').strip() + if not display_name: + display_name = session.get('username') + elif len(display_name) > 25: return api_error('invalid_display_name') db.users.update_one({'username': session.get('username')}, { '$set': {'display_name': display_name} }) - return jsonify({'status': 'ok'}) + return jsonify({'status': 'ok', 'display_name': display_name}) @app.route('/api/account/password', methods=['POST']) @@ -287,8 +289,8 @@ def route_api_account_password(): return api_error('current_password_invalid') new_password = data.get('new_password', '').encode('utf-8') - if not 8 <= len(new_password) <= 5000: - return api_error('invalid_password') + if not 6 <= len(new_password) <= 5000: + return api_error('invalid_new_password') salt = bcrypt.gensalt() hashed = bcrypt.hashpw(new_password, salt) @@ -310,7 +312,7 @@ def route_api_account_remove(): user = db.users.find_one({'username': session.get('username')}) password = data.get('password', '').encode('utf-8') if not bcrypt.checkpw(password, user['password']): - return api_error('current_password_invalid') + return api_error('verify_password_invalid') db.scores.delete_many({'username': session.get('username')}) db.users.delete_one({'username': session.get('username')}) diff --git a/config.example.json b/config.example.json index 9ec88e4..f81c1b7 100644 --- a/config.example.json +++ b/config.example.json @@ -2,5 +2,5 @@ "songs_baseurl": "", "assets_baseurl": "", "email": "", - "_accounts": true + "accounts": true } diff --git a/public/src/css/view.css b/public/src/css/view.css index c1f254e..4696d02 100644 --- a/public/src/css/view.css +++ b/public/src/css/view.css @@ -368,3 +368,11 @@ kbd{ .accountdel-form{ margin: 0.3em auto; } +.view-content .error-div{ + display: none; + width: 80%; + margin: 0 auto; + padding: 0.5em; + font-size: 1.1em; + color: #d00; +} diff --git a/public/src/js/account.js b/public/src/js/account.js index 8476d4a..22757a7 100644 --- a/public/src/js/account.js +++ b/public/src/js/account.js @@ -35,6 +35,7 @@ class Account{ this.inputForms = [] this.shownDiv = "" + this.errorDiv = this.getElement("error-div") this.getElement("displayname-hint").innerText = strings.account.displayName this.displayname = this.getElement("displayname") this.displayname.placeholder = strings.account.displayName @@ -116,6 +117,8 @@ class Account{ this.mode = register ? "register" : "login" this.setAltText(this.getElement("view-title"), strings.account[this.mode]) + + this.errorDiv = this.getElement("error-div") this.items = [] this.form = this.getElement("login-form") this.getElement("username-hint").innerText = strings.account.username @@ -239,14 +242,14 @@ class Account{ password: this.form.password.value } if(!obj.username || !obj.password){ - alert(strings.account.cannotBeEmpty.replace("%s", strings.account[!obj.username ? "username" : "password"])) + this.error(strings.account.cannotBeEmpty.replace("%s", strings.account[!obj.username ? "username" : "password"])) return } if(this.mode === "login"){ obj.remember = this.form.remember.checked }else{ if(obj.password !== this.form.password2.value){ - alert(strings.account.passwordsDoNotMatch) + this.error(strings.account.passwordsDoNotMatch) return } } @@ -260,7 +263,7 @@ class Account{ pageEvents.send("login", account.username) } if(this.mode === "login"){ - this.request("scores/get").then(response => { + this.request("scores/get", false, true).then(response => { loadScores(response.scores) }, () => { loadScores({}) @@ -273,9 +276,13 @@ class Account{ } }, response => { if(response && response.status === "error" && response.message){ - alert(response.message) + if(response.message in strings.serverError){ + this.error(strings.serverError[response.message]) + }else{ + this.error(response.message) + } }else{ - alert(strings.account.error) + this.error(strings.account.error) } }) } @@ -293,17 +300,12 @@ class Account{ account.loggedIn = false delete account.username delete account.displayName - var loadScores = scores => { - Cookies.remove("session") + var loadScores = () => { scoreStorage.load() this.onEnd(false, true) pageEvents.send("logout") } - this.request("logout").then(response => { - loadScores() - }, () => { - loadScores() - }) + this.request("logout").then(loadScores, loadScores) } onSave(event){ if(event){ @@ -316,6 +318,7 @@ class Account{ if(this.locked){ return } + this.clearError() var promises = [] var noNameChange = false if(this.shownDiv === "pass"){ @@ -329,7 +332,7 @@ class Account{ new_password: passwords[1] })) }else{ - alert(strings.account.passwordsDoNotMatch) + this.error(strings.account.newPasswordsDoNotMatch) return } } @@ -341,7 +344,6 @@ class Account{ account.loggedIn = false delete account.username delete account.displayName - Cookies.remove("session") scoreStorage.load() pageEvents.send("logout") return Promise.resolve @@ -351,8 +353,8 @@ class Account{ if(!noNameChange && newName !== account.displayName){ promises.push(this.request("account/display_name", { display_name: newName - }).then(() => { - account.displayName = newName + }).then(response => { + account.displayName = response.display_name })) } var error = false @@ -361,9 +363,13 @@ class Account{ return } if(response && response.message){ - alert(response.message) + if(response.message in strings.serverError){ + this.error(strings.serverError[response.message]) + }else{ + this.error(response.message) + } }else{ - alert(strings.account.error) + this.error(strings.account.error) } } Promise.all(promises).then(() => { @@ -389,11 +395,11 @@ class Account{ new SongSelect(false, false, touched) }, 500) } - request(url, obj){ + request(url, obj, get){ this.lock(true) return new Promise((resolve, reject) => { var request = new XMLHttpRequest() - request.open("POST", "api/" + url) + request.open(get ? "GET" : "POST", "api/" + url) pageEvents.load(request).then(() => { this.lock(false) if(request.status !== 200){ @@ -435,6 +441,14 @@ class Account{ } } } + error(text){ + this.errorDiv.innerText = text + this.errorDiv.style.display = "block" + } + clearError(){ + this.errorDiv.innerText = "" + this.errorDiv.style.display = "" + } clean(eventsOnly, noReset){ if(!eventsOnly){ cancelTouch = true @@ -442,6 +456,10 @@ class Account{ this.gamepad.clean() } if(this.mode === "account"){ + if(!noReset){ + this.accountPass.reset() + this.accountDel.reset() + } pageEvents.remove(this.accounPassButton, ["click", "touchstart"]) pageEvents.remove(this.accountDelButton, ["click", "touchstart"]) pageEvents.remove(this.logoutButton, ["mousedown", "touchstart"]) @@ -449,10 +467,7 @@ class Account{ for(var i = 0; i < this.inputForms.length; i++){ pageEvents.remove(this.inputForms[i], ["keydown", "keyup", "keypress"]) } - if(!noReset){ - this.accountPass.reset() - this.accountDel.reset() - } + delete this.errorDiv delete this.displayname delete this.accountPassButton delete this.accountPass @@ -473,6 +488,7 @@ class Account{ for(var i = 0; i < this.form.length; i++){ pageEvents.remove(this.registerButton, ["keydown", "keyup", "keypress"]) } + delete this.errorDiv delete this.form delete this.password2 delete this.remember diff --git a/public/src/js/assets.js b/public/src/js/assets.js index f7e3ee7..220e6d5 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -1,7 +1,6 @@ var assets = { "js": [ "lib/md5.min.js", - "lib/js.cookie.min.js", "loadsong.js", "parseosu.js", "titlescreen.js", diff --git a/public/src/js/controller.js b/public/src/js/controller.js index 583ffd3..9b06aa1 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -155,10 +155,16 @@ class Controller{ if(this.mainLoopRunning){ if(this.multiplayer !== 2){ requestAnimationFrame(() => { - this.viewLoop() + var player = this.multiplayer ? p2.player : 1 + if(player === 1){ + this.viewLoop() + } if(this.multiplayer === 1){ this.syncWith.viewLoop() } + if(player === 2){ + this.viewLoop() + } if(this.scoresheet){ if(this.view.ctx){ this.view.ctx.save() @@ -197,14 +203,14 @@ class Controller{ displayScore(score, notPlayed, bigNote){ this.view.displayScore(score, notPlayed, bigNote) } - songSelection(fadeIn){ + songSelection(fadeIn, scoreSaveFailed){ if(!fadeIn){ this.clean() } if(this.calibrationMode){ new SettingsView(this.touchEnabled, false, null, "latency") }else{ - new SongSelect(false, fadeIn, this.touchEnabled) + new SongSelect(false, fadeIn, this.touchEnabled, null, scoreSaveFailed) } } restartSong(){ diff --git a/public/src/js/game.js b/public/src/js/game.js index da9534e..e03e1f5 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -506,7 +506,7 @@ class Game{ if(this.musicFadeOut === 0){ if(this.controller.multiplayer === 1){ var obj = this.getGlobalScore() - obj.name = account.loggedIn ? account.displayName : strings.defaultName + obj.name = account.loggedIn ? account.displayName : null p2.send("gameresults", obj) } this.musicFadeOut++ diff --git a/public/src/js/lib/js.cookie.min.js b/public/src/js/lib/js.cookie.min.js deleted file mode 100644 index a0e6820..0000000 --- a/public/src/js/lib/js.cookie.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! js-cookie v3.0.0-rc.0 | MIT */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self,function(){var r=e.Cookies,n=e.Cookies=t();n.noConflict=function(){return e.Cookies=r,n}}())}(this,function(){"use strict";function e(e){for(var t=1;t { @@ -156,22 +156,17 @@ class Loader{ } })) - if(gameConfig._accounts){ - var token = Cookies.get("session") - if(token){ - this.addPromise(this.ajax("/api/scores/get").then(response => { - response = JSON.parse(response) - if(response.status === "ok"){ - account.loggedIn = true - account.username = response.username - account.displayName = response.display_name - scoreStorage.load(response.scores) - pageEvents.send("login", account.username) - } - })) - }else{ - this.assetLoaded() - } + if(gameConfig.accounts){ + this.addPromise(this.ajax("/api/scores/get").then(response => { + response = JSON.parse(response) + if(response.status === "ok"){ + account.loggedIn = true + account.username = response.username + account.displayName = response.display_name + scoreStorage.load(response.scores) + pageEvents.send("login", account.username) + } + })) } settings = new Settings() diff --git a/public/src/js/loadsong.js b/public/src/js/loadsong.js index 3e5b460..4b42555 100644 --- a/public/src/js/loadsong.js +++ b/public/src/js/loadsong.js @@ -264,14 +264,14 @@ class LoadSong{ if(event.type === "gameload"){ this.cancelButton.style.display = "" - if(event.value === song.difficulty){ + if(event.value.diff === song.difficulty){ this.startMultiplayer() }else{ this.selectedSong2 = {} for(var i in this.selectedSong){ this.selectedSong2[i] = this.selectedSong[i] } - this.selectedSong2.difficulty = event.value + this.selectedSong2.difficulty = event.value.diff if(song.type === "tja"){ this.startMultiplayer() }else{ diff --git a/public/src/js/p2.js b/public/src/js/p2.js index 0857381..127b622 100644 --- a/public/src/js/p2.js +++ b/public/src/js/p2.js @@ -4,6 +4,7 @@ class P2Connection{ this.lastMessages = {} this.otherConnected = false this.name = null + this.player = 1 this.allEvents = new Map() this.addEventListener("message", this.message.bind(this)) this.currentHash = "" @@ -103,6 +104,10 @@ class P2Connection{ } message(response){ switch(response.type){ + case "gameload": + if("player" in response.value){ + this.player = response.value.player === 2 ? 2 : 1 + } case "gamestart": this.otherConnected = true this.notes = [] @@ -129,7 +134,7 @@ class P2Connection{ case "gameresults": this.results = {} for(var i in response.value){ - this.results[i] = response.value[i].toString() + this.results[i] = response.value[i] === null ? null : response.value[i].toString() } break case "note": @@ -152,9 +157,12 @@ class P2Connection{ this.clearMessage("users") this.otherConnected = true this.session = true + if("player" in response.value){ + this.player = response.value.player === 2 ? 2 : 1 + } break case "name": - this.name = (response.value || "").toString() || null + this.name = response.value ? response.value.toString() : response.value break } } diff --git a/public/src/js/pageevents.js b/public/src/js/pageevents.js index 46c0a12..7779a24 100644 --- a/public/src/js/pageevents.js +++ b/public/src/js/pageevents.js @@ -86,7 +86,7 @@ class PageEvents{ }) } keyEvent(event){ - if(!("key" in event)){ + if(!("key" in event) || event.ctrlKey && (event.key === "c" || event.key === "x" || event.key === "v")){ return } if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){ diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index a2a62c4..265414e 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -2,9 +2,19 @@ class Scoresheet{ constructor(controller, results, multiplayer, touchEnabled){ this.controller = controller this.resultsObj = results - this.results = {} + this.player = [multiplayer ? (p2.player === 1 ? 0 : 1) : 0] + var player0 = this.player[0] + this.results = [] + this.results[player0] = {} + this.rules = [] + this.rules[player0] = this.controller.game.rules + if(multiplayer){ + this.player.push(p2.player === 2 ? 0 : 1) + this.results[this.player[1]] = p2.results + this.rules[this.player[1]] = this.controller.syncWith.game.rules + } for(var i in results){ - this.results[i] = results[i].toString() + this.results[player0][i] = results[i] === null ? null : results[i].toString() } this.multiplayer = multiplayer this.touchEnabled = touchEnabled @@ -248,7 +258,7 @@ class Scoresheet{ var frameTop = winH / 2 - 720 / 2 var frameLeft = winW / 2 - 1280 / 2 - var players = this.multiplayer && p2.results ? 2 : 1 + var players = this.multiplayer ? 2 : 1 var p2Offset = 298 var bgOffset = 0 @@ -331,28 +341,21 @@ class Scoresheet{ } var rules = this.controller.game.rules - var gaugePercent = rules.gaugePercent(this.results.gauge) - var gaugeClear = [rules.gaugeClear] - if(players === 2){ - gaugeClear.push(this.controller.syncWith.game.rules.gaugeClear) - } - var failedOffset = gaugePercent >= gaugeClear[0] ? 0 : -2000 - if(players === 2){ - var gauge2 = this.controller.syncWith.game.rules.gaugePercent(p2.results.gauge) - if(gauge2 > gaugePercent && failedOffset !== 0 && gauge2 >= gaugeClear[1]){ + var failedOffset = rules.clearReached(this.results[this.player[0]].gauge) ? 0 : -2000 + if(players === 2 && failedOffset !== 0){ + var p2results = this.results[this.player[1]] + if(p2results && this.controller.syncWith.game.rules.clearReached(p2results.gauge)){ failedOffset = 0 } } if(elapsed >= 3100 + failedOffset){ for(var p = 0; p < players; p++){ ctx.save() - var results = this.results - if(p === 1){ - results = p2.results + var results = this.results[p] + if(!results){ + continue } - var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules - var resultGauge = playerRules.gaugePercent(results.gauge) - var clear = resultGauge >= gaugeClear[p] + var clear = this.rules[p].clearReached(results.gauge) if(p === 1 || !this.multiplayer && clear){ ctx.translate(0, 290) } @@ -415,7 +418,7 @@ class Scoresheet{ this.draw.layeredText({ ctx: ctx, - text: this.results.title, + text: this.results[this.player[0]].title, fontSize: 40, fontFamily: this.font, x: 1257, @@ -431,9 +434,11 @@ class Scoresheet{ ctx.save() for(var p = 0; p < players; p++){ - var results = this.results + var results = this.results[p] + if(!results){ + continue + } if(p === 1){ - results = p2.results ctx.translate(0, p2Offset) } @@ -455,10 +460,11 @@ class Scoresheet{ ctx.fillText(text, 395, 308) ctx.miterLimit = 10 - if(p === 0){ - var name = account.loggedIn ? account.displayName : strings.defaultName + var defaultName = p === 0 ? strings.defaultName : strings.default2PName + if(p === this.player[0]){ + var name = account.loggedIn ? account.displayName : defaultName }else{ - var name = results.name + var name = results.name || defaultName } this.nameplateCache.get({ ctx: ctx, @@ -466,7 +472,7 @@ class Scoresheet{ y: 92, w: 273, h: 66, - id: p.toString() + "p", + id: p.toString() + "p" + name, }, ctx => { this.draw.nameplate({ ctx: ctx, @@ -609,7 +615,7 @@ class Scoresheet{ if(this.tetsuoHanaClass){ this.tetsuoHana.classList.remove(this.tetsuoHanaClass) } - this.tetsuoHanaClass = rules.clearReached(this.results.gauge) ? "dance" : "failed" + this.tetsuoHanaClass = this.rules[this.player[0]].clearReached(this.results[this.player[0]].gauge) ? "dance" : "failed" this.tetsuoHana.classList.add(this.tetsuoHanaClass) } } @@ -623,32 +629,32 @@ class Scoresheet{ ctx.translate(frameLeft, frameTop) for(var p = 0; p < players; p++){ - var results = this.results + var results = this.results[p] + if(!results){ + continue + } if(p === 1){ - results = p2.results ctx.translate(0, p2Offset) } - var gaugePercent = rules.gaugePercent(results.gauge) var w = 712 this.draw.gauge({ ctx: ctx, x: 558 + w, y: p === 1 ? 124 : 116, - clear: gaugeClear[p], - percentage: gaugePercent, + clear: this.rules[p].gaugeClear, + percentage: this.rules[p].gaugePercent(results.gauge), font: this.font, scale: w / 788, scoresheet: true, blue: p === 1, multiplayer: p === 1 }) - var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules this.draw.soul({ ctx: ctx, x: 1215, y: 144, scale: 36 / 42, - cleared: playerRules.clearReached(results.gauge) + cleared: this.rules[p].clearReached(results.gauge) }) } }) @@ -661,13 +667,12 @@ class Scoresheet{ var noCrownResultWait = -2000; for(var p = 0; p < players; p++){ - var results = this.results - if(p === 1){ - results = p2.results + var results = this.results[p] + if(!results){ + continue } var crownType = null - var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules - if(playerRules.clearReached(results.gauge)){ + if(this.rules[p].clearReached(results.gauge)){ crownType = results.bad === "0" ? "gold" : "silver" } if(crownType !== null){ @@ -730,7 +735,10 @@ class Scoresheet{ var times = {} var lastTime = 0 for(var p = 0; p < players; p++){ - var results = p === 0 ? this.results : p2.results + var results = this.results[p] + if(!results){ + continue + } var currentTime = 3100 + noCrownResultWait + results.points.length * 30 * this.frame if(currentTime > lastTime){ lastTime = currentTime @@ -739,7 +747,10 @@ class Scoresheet{ for(var i in printNumbers){ var largestTime = 0 for(var p = 0; p < players; p++){ - var results = p === 0 ? this.results : p2.results + var results = this.results[p] + if(!results){ + continue + } times[printNumbers[i]] = lastTime + 500 var currentTime = lastTime + 500 + results[printNumbers[i]].length * 30 * this.frame if(currentTime > largestTime){ @@ -755,9 +766,11 @@ class Scoresheet{ } for(var p = 0; p < players; p++){ - var results = this.results + var results = this.results[p] + if(!results){ + continue + } if(p === 1){ - results = p2.results ctx.translate(0, p2Offset) } ctx.save() @@ -851,7 +864,7 @@ class Scoresheet{ if(elapsed >= 1000){ this.clean() - this.controller.songSelection(true) + this.controller.songSelection(true, this.scoreSaveFailed) } } @@ -918,10 +931,14 @@ class Scoresheet{ delete this.resultsObj.title delete this.resultsObj.difficulty delete this.resultsObj.gauge - scoreStorage.add(hash, difficulty, this.resultsObj, true, title) + scoreStorage.add(hash, difficulty, this.resultsObj, true, title).catch(() => { + this.scoreSaveFailed = true + }) }else if(oldScore && (crown === "gold" && oldScore.crown !== "gold" || crown && !oldScore.crown)){ oldScore.crown = crown - scoreStorage.add(hash, difficulty, oldScore, true, title) + scoreStorage.add(hash, difficulty, oldScore, true, title).catch(() => { + this.scoreSaveFailed = true + }) } } this.scoreSaved = true @@ -936,7 +953,7 @@ class Scoresheet{ snd.buffer.loadSettings() this.redrawRunning = false pageEvents.remove(this.canvas, ["mousedown", "touchstart"]) - if(this.multiplayer !== 2 && this.touchEnabled){ + if(this.touchEnabled){ pageEvents.remove(document.getElementById("touch-full-btn"), "touchend") } if(this.session){ @@ -948,5 +965,7 @@ class Scoresheet{ delete this.ctx delete this.canvas delete this.fadeScreen + delete this.results + delete this.rules } } diff --git a/public/src/js/scorestorage.js b/public/src/js/scorestorage.js index db919c6..db6dd2b 100644 --- a/public/src/js/scorestorage.js +++ b/public/src/js/scorestorage.js @@ -6,23 +6,30 @@ class ScoreStorage{ this.scoreKeys = ["points", "good", "ok", "bad", "maxCombo", "drumroll"] this.crownValue = ["", "silver", "gold"] } - load(strings){ - this.scores = {} - if(strings){ - this.scoreStrings = this.prepareStrings(strings) + load(strings, loadFailed){ + var scores = {} + var scoreStrings = {} + if(loadFailed){ + try{ + var localScores = localStorage.getItem("saveFailed") + if(localScores){ + scoreStrings = JSON.parse(localScores) + } + }catch(e){} + }else if(strings){ + scoreStrings = this.prepareStrings(strings) }else if(account.loggedIn){ return }else{ - this.scoreStrings = {} try{ var localScores = localStorage.getItem("scoreStorage") if(localScores){ - this.scoreStrings = JSON.parse(localScores) + scoreStrings = JSON.parse(localScores) } }catch(e){} } - for(var hash in this.scoreStrings){ - var scoreString = this.scoreStrings[hash] + for(var hash in scoreStrings){ + var scoreString = scoreStrings[hash] var songAdded = false if(typeof scoreString === "string" && scoreString){ var diffArray = scoreString.split(";") @@ -42,14 +49,32 @@ class ScoreStorage{ score[name] = value } if(!songAdded){ - this.scores[hash] = {title: null} + scores[hash] = {title: null} songAdded = true } - this.scores[hash][this.difficulty[i]] = score + scores[hash][this.difficulty[i]] = score } } } } + if(loadFailed){ + for(var hash in scores){ + for(var i in this.difficulty){ + var diff = this.difficulty[i] + if(scores[hash][diff]){ + this.add(hash, diff, scores[hash][diff], true, this.songTitles[hash] || null).then(() => { + localStorage.removeItem("saveFailed") + }, () => {}) + } + } + } + }else{ + this.scores = scores + this.scoreStrings = scoreStrings + } + if(strings){ + this.load(false, true) + } } prepareScores(scores){ var output = [] @@ -126,7 +151,7 @@ class ScoreStorage{ } } } - add(song, difficulty, scoreObject, isHash, setTitle){ + add(song, difficulty, scoreObject, isHash, setTitle, saveFailed){ var hash = isHash ? song : this.titleHash(song) if(!(hash in this.scores)){ this.scores[hash] = {} @@ -137,11 +162,29 @@ class ScoreStorage{ this.scores[hash][difficulty] = scoreObject this.writeString(hash) this.write() - var obj = {} - obj[hash] = this.scoreStrings[hash] - this.sendToServer({ - scores: this.prepareScores(obj) - }).catch(() => this.add.apply(this, arguments)) + if(saveFailed){ + var failedScores = {} + try{ + var localScores = localStorage.getItem("saveFailed") + if(localScores){ + failedScores = JSON.parse(localScores) + } + }catch(e){} + if(!(hash in failedScores)){ + failedScores[hash] = {} + } + failedScores[hash] = this.scoreStrings[hash] + try{ + localStorage.setItem("saveFailed", JSON.stringify(failedScores)) + }catch(e){} + return Promise.reject() + }else{ + var obj = {} + obj[hash] = this.scoreStrings[hash] + return this.sendToServer({ + scores: this.prepareScores(obj) + }).catch(() => this.add(song, difficulty, scoreObject, isHash, setTitle, true)) + } } template(){ var template = {crown: ""} @@ -192,10 +235,10 @@ class ScoreStorage{ } }).catch(() => { if(retry){ + this.scoreSaveFailed = true account.loggedIn = false delete account.username delete account.displayName - Cookies.remove("session") this.load() pageEvents.send("logout") return Promise.reject() diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index 64b65de..0ae5b14 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -1,5 +1,5 @@ class SongSelect{ - constructor(fromTutorial, fadeIn, touchEnabled, songId){ + constructor(fromTutorial, fadeIn, touchEnabled, songId, scoreSaveFailed){ this.touchEnabled = touchEnabled loader.changePage("songselect", false) @@ -167,6 +167,9 @@ class SongSelect{ category: strings.random }) } + if(scoreSaveFailed){ + scoreStorage.scoreSaveFailed = true + } this.songs.push({ title: strings.aboutSimulator, skin: this.songSkin.about, @@ -379,7 +382,12 @@ class SongSelect{ return } var shift = event ? event.shiftKey : this.pressedKeys["shift"] - if(this.state.screen === "song"){ + if(this.state.scoreSaveFailed){ + if(name === "confirm"){ + this.playSound("se_don") + this.state.scoreSaveFailed = false + } + }else if(this.state.screen === "song"){ if(name === "confirm"){ this.toSelectDifficulty() }else if(name === "back"){ @@ -453,10 +461,15 @@ class SongSelect{ var ctrl = false var touch = true } - if(this.state.screen === "song"){ + if(this.state.scoreSaveFailed){ + if(408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550){ + this.playSound("se_don") + this.state.scoreSaveFailed = false + } + }else if(this.state.screen === "song"){ if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){ this.categoryJump(mouse.x < 640 ? -1 : 1) - }else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig._accounts){ + }else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts){ this.toAccount() }else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){ this.toSession() @@ -508,10 +521,14 @@ class SongSelect{ mouseMove(event){ var mouse = this.mouseOffset(event.offsetX, event.offsetY) var moveTo = null - if(this.state.screen === "song"){ + if(this.state.scoreSaveFailed){ + if(408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550){ + moveTo = "scoreSaveFailed" + } + }else if(this.state.screen === "song"){ if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){ moveTo = mouse.x < 640 ? "categoryPrev" : "categoryNext" - }else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig._accounts){ + }else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts){ moveTo = "account" }else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){ moveTo = "session" @@ -831,6 +848,7 @@ class SongSelect{ } if(p2.session){ p2.send("gameend") + this.state.moveHover = null }else{ localStorage["selectedSong"] = this.selectedSong @@ -992,12 +1010,22 @@ class SongSelect{ }else{ this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize + (ms - this.state.screenMS - 1000) } - if(ms > this.state.screenMS + 500){ + if(screen === "titleFadeIn" && ms > this.state.screenMS + 500){ this.state.screen = "title" screen = "title" } } + if(screen === "song" && scoreStorage.scoreSaveFailed && !p2.session){ + if(this.bgmEnabled){ + this.playBgm(false) + } + scoreStorage.scoreSaveFailed = false + this.state.scoreSaveFailed = true + this.state.locked = true + this.playSound("se_pause") + } + if(screen === "song"){ if(this.songs[this.selectedSong].courses){ selectedWidth = this.songAsset.selectedWidth @@ -1441,7 +1469,8 @@ class SongSelect{ ctx: ctx, font: this.font, x: _x, - y: _y - 45 + y: _y - 45, + two: p2.session && p2.player === 2 }) } } @@ -1579,15 +1608,15 @@ class SongSelect{ if(this.selectedDiff === 4 + this.diffOptions.length){ currentDiff = 3 } - if(i === currentSong.p2Cursor && p2.socket.readyState === 1){ + if(songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1){ this.draw.diffCursor({ ctx: ctx, font: this.font, x: _x, - y: _y - (songSel ? 45 : 65), - two: true, - side: songSel ? false : (currentSong.p2Cursor === currentDiff), - scale: songSel ? 0.7 : 1 + y: _y - 45, + two: !p2.session || p2.player === 1, + side: false, + scale: 0.7 }) } if(!songSel){ @@ -1603,7 +1632,8 @@ class SongSelect{ font: this.font, x: _x, y: _y - 65, - side: currentSong.p2Cursor === currentDiff && p2.socket.readyState === 1 + side: currentSong.p2Cursor === currentDiff && p2.socket.readyState === 1, + two: p2.session && p2.player === 2 }) } if(highlight){ @@ -1644,6 +1674,22 @@ class SongSelect{ drawDifficulty(ctx, i, currentUra) } } + for(var i = 0; currentSong.courses && i < 4; i++){ + if(!songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1){ + var _x = x + 402 + i * 100 + var _y = y + 87 + var currentDiff = this.selectedDiff - this.diffOptions.length + this.draw.diffCursor({ + ctx: ctx, + font: this.font, + x: _x, + y: _y - 65, + two: !p2.session || p2.player === 1, + side: currentSong.p2Cursor === currentDiff, + scale: 1 + }) + } + } var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2 var textW = this.songAsset.width - borders @@ -1900,20 +1946,27 @@ class SongSelect{ ctx.lineTo(x + w - 4, y + 4) ctx.fill() + if(!p2.session || p2.player === 1){ + var name = account.loggedIn ? account.displayName : strings.defaultName + var rank = account.loggedIn || !gameConfig.accounts || p2.session ? false : strings.notLoggedIn + }else{ + var name = p2.name || strings.defaultName + var rank = false + } this.nameplateCache.get({ ctx: ctx, x: frameLeft + 60, y: frameTop + 640, w: 273, h: 66, - id: "1p", + id: "1p" + name + "\n" + rank, }, ctx => { this.draw.nameplate({ ctx: ctx, x: 3, y: 3, - name: account.loggedIn ? account.displayName : strings.defaultName, - rank: account.loggedIn || !gameConfig._accounts || p2.session ? false : strings.notLoggedIn, + name: name, + rank: rank, font: this.font }) }) @@ -2049,25 +2102,131 @@ class SongSelect{ } } if(p2.session){ + if(p2.player === 1){ + var name = p2.name || strings.default2PName + }else{ + var name = account.loggedIn ? account.displayName : strings.default2PName + } this.nameplateCache.get({ ctx: ctx, x: frameLeft + 949, y: frameTop + 640, w: 273, h: 66, - id: "2p", + id: "2p" + name, }, ctx => { this.draw.nameplate({ ctx: ctx, x: 3, y: 3, - name: p2.name, + name: name, font: this.font, blue: true }) }) } + if(this.state.scoreSaveFailed){ + if(this.preview){ + this.endPreview() + } + ctx.fillStyle = "rgba(0, 0, 0, 0.5)" + ctx.fillRect(0, 0, winW, winH) + + ctx.save() + ctx.translate(frameLeft, frameTop) + + var pauseRect = (ctx, mul) => { + this.draw.roundedRect({ + ctx: ctx, + x: 269 * mul, + y: 93 * mul, + w: 742 * mul, + h: 494 * mul, + radius: 17 * mul + }) + } + pauseRect(ctx, 1) + ctx.strokeStyle = "#fff" + ctx.lineWidth = 24 + ctx.stroke() + ctx.strokeStyle = "#000" + ctx.lineWidth = 12 + ctx.stroke() + this.draw.pattern({ + ctx: ctx, + img: assets.image["bg_pause"], + shape: pauseRect, + dx: 68, + dy: 11 + }) + this.draw.wrappingText({ + ctx: ctx, + text: strings.scoreSaveFailed, + fontSize: 30, + fontFamily: this.font, + x: 300, + y: 130, + width: 680, + height: 300, + lineHeight: 35, + fill: "#000", + verticalAlign: "middle", + textAlign: "center", + }) + + var _x = 640 + var _y = 470 + var _w = 464 + var _h = 80 + ctx.fillStyle = "#ffb447" + this.draw.roundedRect({ + ctx: ctx, + x: _x - _w / 2, + y: _y, + w: _w, + h: _h, + radius: 30 + }) + ctx.fill() + var layers = [ + {outline: "#000", letterBorder: 10}, + {fill: "#fff"} + ] + this.draw.layeredText({ + ctx: ctx, + text: strings.ok, + x: _x, + y: _y + 18, + width: _w, + height: _h - 54, + fontSize: 40, + fontFamily: this.font, + letterSpacing: -1, + align: "center" + }, layers) + + var highlight = 1 + if(this.state.moveHover === "scoreSaveFailed"){ + highlight = 2 + } + if(highlight){ + this.draw.highlight({ + ctx: ctx, + x: _x - _w / 2 - 3.5, + y: _y - 3.5, + w: _w + 7, + h: _h + 7, + animate: highlight === 1, + animateMS: this.state.moveMS, + opacity: highlight === 2 ? 0.8 : 1, + radius: 30 + }) + } + + ctx.restore() + } + if(screen === "titleFadeIn"){ ctx.save() @@ -2120,7 +2279,7 @@ class SongSelect{ }) } this.draw.songFrame(config) - if(config.song.p2Cursor && p2.socket.readyState === 1){ + if(config.song.p2Cursor !== null && p2.socket.readyState === 1){ this.draw.diffCursor({ ctx: ctx, font: this.font, @@ -2167,6 +2326,9 @@ class SongSelect{ } startPreview(loadOnly){ + if(!loadOnly && this.state && this.state.scoreSaveFailed){ + return + } var currentSong = this.songs[this.selectedSong] var id = currentSong.id var prvTime = currentSong.preview @@ -2242,6 +2404,9 @@ class SongSelect{ } } playBgm(enabled){ + if(enabled && this.state && this.state.scoreSaveFailed){ + return + } if(enabled && !this.bgmEnabled){ this.bgmEnabled = true snd.musicGain.fadeIn(0.4) diff --git a/public/src/js/strings.js b/public/src/js/strings.js index f4d0d75..1f58f11 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -37,6 +37,7 @@ this.oni = "おに" this.songBranch = "譜面分岐あり" this.defaultName = "どんちゃん" + this.default2PName = "かっちゃん" this.notLoggedIn = "ログインしていない" this.sessionStart = "オンラインセッションを開始する!" this.sessionEnd = "オンラインセッションを終了する" @@ -197,6 +198,7 @@ register: "登録", registerAccount: "アカウントを登録", passwordsDoNotMatch: "パスワードが一致しません", + newPasswordsDoNotMatch: "New passwords do not match", cannotBeEmpty: "%sは空にできません", error: "リクエストの処理中にエラーが発生しました", logout: "ログアウト", @@ -213,6 +215,17 @@ deleteAccount: "Delete Account", verifyPassword: "Verify password to delete this account" } + this.serverError = { + not_logged_in: "Not logged in", + invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long", + username_in_use: "A user already exists with that username", + invalid_password: "Cannot use this password, please check that your password is at least 6 characters long", + invalid_username_password: "Invalid Username or Password", + invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long", + current_password_invalid: "Current password does not match", + invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long", + verify_password_invalid: "Verification password does not match" + } this.browserSupport = { browserWarning: "サポートされていないブラウザを実行しています (%s)", details: "詳しく", @@ -263,9 +276,11 @@ function StringsEn(){ this.oni = "Extreme" this.songBranch = "Diverge Notes" this.defaultName = "Don-chan" + this.default2PName = "Katsu-chan" this.notLoggedIn = "Not logged in" this.sessionStart = "Begin an Online Session!" this.sessionEnd = "End Online Session" + this.scoreSaveFailed = "Could not connect to the server, your score has not been saved.\n\nPlease log in or refresh the page to try saving the score again." this.loading = "Loading..." this.waitingForP2 = "Waiting for Another Player..." this.cancel = "Cancel" @@ -423,6 +438,7 @@ function StringsEn(){ register: "Register", registerAccount: "Register account", passwordsDoNotMatch: "Passwords do not match", + newPasswordsDoNotMatch: "New passwords do not match", cannotBeEmpty: "%s cannot be empty", error: "An error occurred while processing your request", logout: "Log Out", @@ -439,6 +455,17 @@ function StringsEn(){ deleteAccount: "Delete Account", verifyPassword: "Verify password to delete this account" } + this.serverError = { + not_logged_in: "Not logged in", + invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long", + username_in_use: "A user already exists with that username", + invalid_password: "Cannot use this password, please check that your password is at least 6 characters long", + invalid_username_password: "Invalid Username or Password", + invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long", + current_password_invalid: "Current password does not match", + invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long", + verify_password_invalid: "Verification password does not match" + } this.browserSupport = { browserWarning: "You are running an unsupported browser (%s)", details: "Details...", @@ -489,6 +516,7 @@ function StringsCn(){ this.oni = "魔王" this.songBranch = "有谱面分歧" this.defaultName = "小咚" + this.default2PName = "小咔" this.notLoggedIn = "未登录" this.sessionStart = "开始在线会话!" this.sessionEnd = "结束在线会话" @@ -649,6 +677,7 @@ function StringsCn(){ register: "注册", registerAccount: "注册帐号", passwordsDoNotMatch: "密码不匹配", + newPasswordsDoNotMatch: "New passwords do not match", cannotBeEmpty: "%s不能为空", error: "处理您的请求时发生错误", logout: "登出", @@ -665,6 +694,17 @@ function StringsCn(){ deleteAccount: "Delete Account", verifyPassword: "Verify password to delete this account" } + this.serverError = { + not_logged_in: "Not logged in", + invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long", + username_in_use: "A user already exists with that username", + invalid_password: "Cannot use this password, please check that your password is at least 6 characters long", + invalid_username_password: "Invalid Username or Password", + invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long", + current_password_invalid: "Current password does not match", + invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long", + verify_password_invalid: "Verification password does not match" + } this.browserSupport = { browserWarning: "You are running an unsupported browser (%s)", details: "Details...", @@ -715,6 +755,7 @@ function StringsTw(){ this.oni = "魔王" this.songBranch = "有譜面分歧" this.defaultName = "小咚" + this.default2PName = "小咔" this.notLoggedIn = "未登錄" this.sessionStart = "開始多人模式!" this.sessionEnd = "結束多人模式" @@ -875,6 +916,7 @@ function StringsTw(){ register: "註冊", registerAccount: "註冊帳號", passwordsDoNotMatch: "密碼不匹配", + newPasswordsDoNotMatch: "New passwords do not match", cannotBeEmpty: "%s不能為空", error: "處理您的請求時發生錯誤", logout: "登出", @@ -891,6 +933,17 @@ function StringsTw(){ deleteAccount: "Delete Account", verifyPassword: "Verify password to delete this account" } + this.serverError = { + not_logged_in: "Not logged in", + invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long", + username_in_use: "A user already exists with that username", + invalid_password: "Cannot use this password, please check that your password is at least 6 characters long", + invalid_username_password: "Invalid Username or Password", + invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long", + current_password_invalid: "Current password does not match", + invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long", + verify_password_invalid: "Verification password does not match" + } this.browserSupport = { browserWarning: "You are running an unsupported browser (%s)", details: "Details...", @@ -941,6 +994,7 @@ function StringsKo(){ this.oni = "귀신" this.songBranch = "악보 분기 있습니다" this.defaultName = "동이" + this.default2PName = "딱이" this.notLoggedIn = "로그인하지 않았습니다" this.sessionStart = "온라인 세션 시작!" this.sessionEnd = "온라인 세션 끝내기" @@ -1101,6 +1155,7 @@ function StringsKo(){ register: "가입하기", registerAccount: "계정 등록", passwordsDoNotMatch: "비밀번호가 일치하지 않습니다", + newPasswordsDoNotMatch: "New passwords do not match", cannotBeEmpty: "%s 비어 있을 수 없습니다", error: "요청을 처리하는 동안 오류가 발생했습니다", logout: "로그 아웃", @@ -1117,6 +1172,17 @@ function StringsKo(){ deleteAccount: "Delete Account", verifyPassword: "Verify password to delete this account" } + this.serverError = { + not_logged_in: "Not logged in", + invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long", + username_in_use: "A user already exists with that username", + invalid_password: "Cannot use this password, please check that your password is at least 6 characters long", + invalid_username_password: "Invalid Username or Password", + invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long", + current_password_invalid: "Current password does not match", + invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long", + verify_password_invalid: "Verification password does not match" + } this.browserSupport = { browserWarning: "You are running an unsupported browser (%s)", details: "Details...", diff --git a/public/src/js/view.js b/public/src/js/view.js index 235b169..12e48b0 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -129,6 +129,11 @@ this.nameplateCache = new CanvasCache(noSmoothing) this.multiplayer = this.controller.multiplayer + if(this.multiplayer === 2){ + this.player = p2.player === 2 ? 1 : 2 + }else{ + this.player = this.controller.multiplayer ? p2.player : 1 + } this.touchEnabled = this.controller.touchEnabled this.touch = -Infinity @@ -224,13 +229,12 @@ this.winH = winH this.ratio = ratio - if(this.multiplayer !== 2){ + if(this.player !== 2){ this.canvas.width = winW this.canvas.height = winH ctx.scale(ratio, ratio) this.canvas.style.width = (winW / this.pixelRatio) + "px" this.canvas.style.height = (winH / this.pixelRatio) + "px" - this.titleCache.resize(640, 90, ratio) } if(!this.multiplayer){ @@ -246,7 +250,7 @@ resized = true }else if(this.controller.game.paused && !document.hasFocus()){ return - }else if(this.multiplayer !== 2){ + }else if(this.player !== 2){ ctx.clearRect(0, 0, winW / ratio, winH / ratio) } winW /= ratio @@ -263,8 +267,8 @@ var frameTop = winH / 2 - 720 / 2 var frameLeft = winW / 2 - 1280 / 2 } - if(this.multiplayer === 2){ - frameTop += this.multiplayer === 2 ? 165 : 176 + if(this.player === 2){ + frameTop += 165 } if(touchMultiplayer){ if(!this.touchp2Class){ @@ -284,11 +288,11 @@ this.drawGogoTime() - if(!touchMultiplayer || this.multiplayer === 1 && frameTop >= 0){ + if(!touchMultiplayer || this.player === 1 && frameTop >= 0){ this.assets.drawAssets("background") } - if(this.multiplayer !== 2){ + if(this.player !== 2){ this.titleCache.get({ ctx: ctx, x: winW - (touchMultiplayer && fullScreenSupported ? 750 : 650), @@ -356,7 +360,7 @@ var score = this.controller.getGlobalScore() var gaugePercent = this.rules.gaugePercent(score.gauge) - if(this.multiplayer === 2){ + if(this.player === 2){ var scoreImg = "bg_score_p2" var scoreFill = "#6bbec0" }else{ @@ -379,17 +383,17 @@ size: 100, paddingLeft: 0 } - this.scorePos = {x: 363, y: frameTop + (this.multiplayer === 2 ? 520 : 227)} + this.scorePos = {x: 363, y: frameTop + (this.player === 2 ? 520 : 227)} var animPos = { x1: this.slotPos.x + 13, - y1: this.slotPos.y + (this.multiplayer === 2 ? 27 : -27), + y1: this.slotPos.y + (this.player === 2 ? 27 : -27), x2: winW - 38, - y2: frameTop + (this.multiplayer === 2 ? 484 : 293) + y2: frameTop + (this.player === 2 ? 484 : 293) } var taikoPos = { x: 19, - y: frameTop + (this.multiplayer === 2 ? 464 : 184), + y: frameTop + (this.player === 2 ? 464 : 184), w: 111, h: 130 } @@ -397,15 +401,16 @@ this.nameplateCache.get({ ctx: ctx, x: 167, - y: this.multiplayer === 2 ? 565 : 160, + y: this.player === 2 ? 565 : 160, w: 219, h: 53, id: "1p", }, ctx => { + var defaultName = this.player === 1 ? strings.defaultName : strings.default2PName if(this.multiplayer === 2){ - var name = p2.name || strings.defaultName + var name = p2.name || defaultName }else{ - var name = account.loggedIn ? account.displayName : strings.defaultName + var name = account.loggedIn ? account.displayName : defaultName } this.draw.nameplate({ ctx: ctx, @@ -414,19 +419,19 @@ scale: 0.8, name: name, font: this.font, - blue: this.multiplayer === 2 + blue: this.player === 2 }) }) ctx.fillStyle = "#000" ctx.fillRect( 0, - this.multiplayer === 2 ? 306 : 288, + this.player === 2 ? 306 : 288, winW, - this.multiplayer === 1 ? 184 : 183 + this.player === 1 ? 184 : 183 ) ctx.beginPath() - if(this.multiplayer === 2){ + if(this.player === 2){ ctx.moveTo(0, 467) ctx.lineTo(384, 467) ctx.lineTo(384, 512) @@ -445,7 +450,7 @@ ctx.fillStyle = scoreFill var leftSide = (ctx, mul) => { ctx.beginPath() - if(this.multiplayer === 2){ + if(this.player === 2){ ctx.moveTo(0, 468 * mul) ctx.lineTo(380 * mul, 468 * mul) ctx.lineTo(380 * mul, 512 * mul) @@ -475,7 +480,7 @@ // Score background ctx.fillStyle = "#000" ctx.beginPath() - if(this.multiplayer === 2){ + if(this.player === 2){ this.draw.roundedCorner(ctx, 184, 512, 20, 0) ctx.lineTo(384, 512) this.draw.roundedCorner(ctx, 384, 560, 12, 2) @@ -493,16 +498,16 @@ ctx.drawImage(assets.image["difficulty"], 0, 144 * this.difficulty[this.controller.selectedSong.difficulty], 168, 143, - 126, this.multiplayer === 2 ? 497 : 228, + 126, this.player === 2 ? 497 : 228, 62, 53 ) } // Badges - if(this.controller.autoPlayEnabled && !this.controller.multiplayer){ + if(this.controller.autoPlayEnabled && !this.multiplayer){ this.ctx.drawImage(assets.image["badge_auto"], 183, - this.multiplayer === 2 ? 490 : 265, + this.player === 2 ? 490 : 265, 23, 23 ) @@ -512,7 +517,7 @@ ctx.fillStyle = "#000" ctx.beginPath() var gaugeX = winW - 788 * 0.7 - 32 - if(this.multiplayer === 2){ + if(this.player === 2){ ctx.moveTo(gaugeX, 464) ctx.lineTo(winW, 464) ctx.lineTo(winW, 489) @@ -527,18 +532,18 @@ this.draw.gauge({ ctx: ctx, x: winW, - y: this.multiplayer === 2 ? 468 : 273, + y: this.player === 2 ? 468 : 273, clear: this.rules.gaugeClear, percentage: gaugePercent, font: this.font, scale: 0.7, - multiplayer: this.multiplayer === 2, - blue: this.multiplayer === 2 + multiplayer: this.player === 2, + blue: this.player === 2 }) this.draw.soul({ ctx: ctx, x: winW - 40, - y: this.multiplayer === 2 ? 484 : 293, + y: this.player === 2 ? 484 : 293, scale: 0.75, cleared: this.rules.clearReached(score.gauge) }) @@ -566,29 +571,30 @@ } this.scorePos = { x: 155, - y: frameTop + (this.multiplayer === 2 ? 318 : 193) + y: frameTop + (this.player === 2 ? 318 : 193) } var animPos = { x1: this.slotPos.x + 14, - y1: this.slotPos.y + (this.multiplayer === 2 ? 29 : -29), + y1: this.slotPos.y + (this.player === 2 ? 29 : -29), x2: winW - 55, - y2: frameTop + (this.multiplayer === 2 ? 378 : 165) + y2: frameTop + (this.player === 2 ? 378 : 165) } var taikoPos = {x: 179, y: frameTop + 190, w: 138, h: 162} this.nameplateCache.get({ ctx: ctx, x: 320, - y: this.multiplayer === 2 ? 460 : 20, + y: this.player === 2 ? 460 : 20, w: 273, h: 66, id: "1p", }, ctx => { + var defaultName = this.player === 1 ? strings.defaultName : strings.default2PName if(this.multiplayer === 2){ - var name = p2.name || strings.defaultName + var name = p2.name || defaultName }else{ - var name = account.loggedIn ? account.displayName : strings.defaultName + var name = account.loggedIn ? account.displayName : defaultName } this.draw.nameplate({ ctx: ctx, @@ -596,7 +602,7 @@ y: 3, name: name, font: this.font, - blue: this.multiplayer === 2 + blue: this.player === 2 }) }) @@ -605,10 +611,10 @@ 0, 184, winW, - this.multiplayer === 1 ? 177 : 176 + this.multiplayer && this.player === 1 ? 177 : 176 ) ctx.beginPath() - if(this.multiplayer === 2){ + if(this.player === 2){ ctx.moveTo(328, 351) ctx.lineTo(winW, 351) ctx.lineTo(winW, 385) @@ -625,17 +631,17 @@ this.draw.gauge({ ctx: ctx, x: winW, - y: this.multiplayer === 2 ? 357 : 135, + y: this.player === 2 ? 357 : 135, clear: this.rules.gaugeClear, percentage: gaugePercent, font: this.font, - multiplayer: this.multiplayer === 2, - blue: this.multiplayer === 2 + multiplayer: this.player === 2, + blue: this.player === 2 }) this.draw.soul({ ctx: ctx, x: winW - 57, - y: this.multiplayer === 2 ? 378 : 165, + y: this.player === 2 ? 378 : 165, cleared: this.rules.clearReached(score.gauge) }) @@ -667,7 +673,7 @@ ctx.drawImage(assets.image["difficulty"], 0, 144 * this.difficulty[this.controller.selectedSong.difficulty], 168, 143, - 16, this.multiplayer === 2 ? 194 : 232, + 16, this.player === 2 ? 194 : 232, 141, 120 ) var diff = this.controller.selectedSong.difficulty @@ -679,13 +685,13 @@ ctx.fillStyle = "#fff" ctx.lineWidth = 7 ctx.miterLimit = 1 - ctx.strokeText(text, 87, this.multiplayer === 2 ? 310 : 348) - ctx.fillText(text, 87, this.multiplayer === 2 ? 310 : 348) + ctx.strokeText(text, 87, this.player === 2 ? 310 : 348) + ctx.fillText(text, 87, this.player === 2 ? 310 : 348) ctx.miterLimit = 10 } // Badges - if(this.controller.autoPlayEnabled && !this.controller.multiplayer){ + if(this.controller.autoPlayEnabled && !this.multiplayer){ this.ctx.drawImage(assets.image["badge_auto"], 125, 235, 34, 34 ) @@ -694,7 +700,7 @@ // Score background ctx.fillStyle = "#000" ctx.beginPath() - if(this.multiplayer === 2){ + if(this.player === 2){ ctx.moveTo(0, 312) this.draw.roundedCorner(ctx, 176, 312, 20, 1) ctx.lineTo(176, 353) @@ -719,11 +725,11 @@ }, { // 560, 10 x: animPos.x1 + animPos.w / 6, - y: animPos.y1 - animPos.h * (this.multiplayer === 2 ? 2.5 : 3.5) + y: animPos.y1 - animPos.h * (this.player === 2 ? 2.5 : 3.5) }, { // 940, -150 x: animPos.x2 - animPos.w / 3, - y: animPos.y2 - animPos.h * (this.multiplayer === 2 ? 3.5 : 5) + y: animPos.y2 - animPos.h * (this.player === 2 ? 3.5 : 5) }, { // 1225, 165 x: animPos.x2, @@ -1443,12 +1449,12 @@ var selectedSong = this.controller.selectedSong var songSkinName = selectedSong.songSkin.name var donLayers = [] - var filename = !selectedSong.songSkin.don && this.multiplayer === 2 ? "bg_don2_" : "bg_don_" + var filename = !selectedSong.songSkin.don && this.player === 2 ? "bg_don2_" : "bg_don_" var prefix = "" this.donBg = document.createElement("div") this.donBg.classList.add("donbg") - if(this.multiplayer === 2){ + if(this.player === 2){ this.donBg.classList.add("donbg-bottom") } for(var layer = 1; layer <= 3; layer++){ diff --git a/public/src/js/viewassets.js b/public/src/js/viewassets.js index dae06c6..9affaf7 100644 --- a/public/src/js/viewassets.js +++ b/public/src/js/viewassets.js @@ -18,7 +18,7 @@ class ViewAssets{ sw: imgw, sh: imgh - 1, x: view.portrait ? -60 : 0, - y: view.portrait ? (view.multiplayer === 2 ? 560 : 35) : (view.multiplayer === 2 ? 360 : 2), + y: view.portrait ? (view.player === 2 ? 560 : 35) : (view.player === 2 ? 360 : 2), w: w, h: h - 1 } diff --git a/public/src/views/account.html b/public/src/views/account.html index 1271156..b236652 100644 --- a/public/src/views/account.html +++ b/public/src/views/account.html @@ -2,9 +2,10 @@
+
- +
diff --git a/public/src/views/login.html b/public/src/views/login.html index c9a58c5..d8a76b6 100644 --- a/public/src/views/login.html +++ b/public/src/views/login.html @@ -2,9 +2,10 @@
+
- +
diff --git a/server.py b/server.py index eb8e73c..fbf1476 100644 --- a/server.py +++ b/server.py @@ -103,8 +103,8 @@ async def connection(ws, path): user["other_user"]["action"] = "loading" user["other_user"]["other_user"] = user await asyncio.wait([ - ws.send(msgobj("gameload", waiting_diff)), - user["other_user"]["ws"].send(msgobj("gameload", diff)), + ws.send(msgobj("gameload", {"diff": waiting_diff, "player": 2})), + user["other_user"]["ws"].send(msgobj("gameload", {"diff": diff, "player": 1})), ws.send(msgobj("name", user["other_user"]["name"])), user["other_user"]["ws"].send(msgobj("name", user["name"])) ]) @@ -138,10 +138,9 @@ async def connection(ws, path): user["other_user"]["other_user"] = user user["action"] = "invite" user["session"] = value["id"] - sent_msg = msgobj("session") await asyncio.wait([ - ws.send(sent_msg), - user["other_user"]["ws"].send(sent_msg), + ws.send(msgobj("session", {"player": 2})), + user["other_user"]["ws"].send(msgobj("session", {"player": 1})), ws.send(msgobj("invite")), ws.send(msgobj("name", user["other_user"]["name"])), user["other_user"]["ws"].send(msgobj("name", user["name"])) @@ -291,8 +290,8 @@ async def connection(ws, path): user["action"] = "loading" user["other_user"]["action"] = "loading" await asyncio.wait([ - ws.send(msgobj("gameload", user["other_user"]["gamediff"])), - user["other_user"]["ws"].send(msgobj("gameload", diff)) + ws.send(msgobj("gameload", {"diff": user["other_user"]["gamediff"]})), + user["other_user"]["ws"].send(msgobj("gameload", {"diff": diff})) ]) else: user["action"] = "waiting"