Commit 2af924a9 authored by LoveEevee's avatar LoveEevee

Add everything for accounts

parent 47545e9d
......@@ -291,3 +291,80 @@ kbd{
.left-buttons .taibtn{
z-index: 1;
}
.accountpass-form,
.accountdel-form,
.login-form{
text-align: center;
width: 80%;
margin: auto;
}
.accountpass-form .accountpass-div,
.accountdel-form .accountdel-div,
.login-form .password2-div{
display: none;
}
.account-view .displayname,
.accountpass-form input[type=password],
.accountdel-form input[type=password],
.login-form input[type=text],
.login-form input[type=password]{
width: 100%;
font-size: 1.4em;
margin: 0.1em 0;
padding: 0.3em;
box-sizing: border-box;
}
.accountpass-form input[type=password]{
width: calc(100% / 3);
}
.accountpass-form input[type=password]::placeholder{
font-size: 0.8em;
}
.login-form input[type=checkbox]{
transform: scale(1.4);
}
.account-view .displayname-hint,
.login-form .username-hint,
.login-form .password-hint,
.login-form .remember-label{
display: block;
font-size: 1.1em;
padding: 0.5em;
}
.login-form .remember-label{
padding: 0.85em;
}
.account-view .save-btn{
float: right;
padding: 0.4em 1.5em;
font-weight: bold;
border-color: #000;
color: #000;
z-index: 1;
}
.account-view .view-end-button{
margin-right: 0.4em;
font-weight: normal;
border-color: #dacdb2;
color: #555;
}
.account-view .save-btn:hover,
.account-view .save-btn.selected,
.account-view .view-end-button:hover,
.account-view .view-end-button.selected{
color: #fff;
border-color: #fff;
}
.account-view .displayname-div{
width: 80%;
margin: 0 auto;
}
.accountpass-form .accountpass-btn,
.accountdel-form .accountdel-btn,
.login-form .login-btn{
z-index: 1;
}
.accountpass-form,
.accountdel-form{
margin: 0.3em auto;
}
This diff is collapsed.
var assets = {
"js": [
"lib/md5.min.js",
"lib/js.cookie.min.js",
"loadsong.js",
"parseosu.js",
"titlescreen.js",
......@@ -31,7 +32,8 @@ var assets = {
"importsongs.js",
"logo.js",
"settings.js",
"scorestorage.js"
"scorestorage.js",
"account.js"
],
"css": [
"main.css",
......@@ -137,7 +139,9 @@ var assets = {
"about.html",
"debug.html",
"session.html",
"settings.html"
"settings.html",
"account.html",
"login.html"
],
"songs": [],
......
......@@ -706,12 +706,12 @@
})
}else if(r.smallHiragana.test(symbol)){
// Small hiragana, small katakana
drawn.push({text: symbol, x: 0, y: 0, w: 30})
drawn.push({text: symbol, kana: true, x: 0, y: 0, w: 30})
}else if(r.hiragana.test(symbol)){
// Hiragana, katakana
drawn.push({text: symbol, x: 0, y: 0, w: 35})
drawn.push({text: symbol, kana: true, x: 0, y: 0, w: 35})
}else{
drawn.push({text: symbol, x: 0, y: 0, w: 39})
drawn.push({text: symbol, kana: true, x: 0, y: 0, w: 39})
}
}
......@@ -720,6 +720,9 @@
if(config.letterSpacing){
symbol.w += config.letterSpacing
}
if(config.kanaSpacing && symbol.kana){
symbol.w += config.kanaSpacing
}
drawnWidth += symbol.w * mul
}
......@@ -1549,6 +1552,99 @@
ctx.restore()
}
nameplate(config){
var ctx = config.ctx
var w = 264
var h = 57
var r = h / 2
var pi = Math.PI
ctx.save()
ctx.translate(config.x, config.y)
if(config.scale){
ctx.scale(config.scale, config.scale)
}
ctx.fillStyle="rgba(0, 0, 0, 0.25)"
ctx.beginPath()
ctx.arc(r + 4, r + 5, r, pi / 2, pi / -2)
ctx.arc(w - r + 4, r + 5, r, pi / -2, pi / 2)
ctx.fill()
ctx.beginPath()
ctx.moveTo(r, 0)
this.roundedCorner(ctx, w, 0, r, 1)
ctx.lineTo(r, r)
ctx.fillStyle = config.blue ? "#67cecb" : "#ff421d"
ctx.fill()
ctx.beginPath()
ctx.moveTo(r, r)
this.roundedCorner(ctx, w, h, r, 2)
ctx.lineTo(r, h)
ctx.fillStyle = "rgba(255, 255, 255, 0.8)"
ctx.fill()
ctx.strokeStyle = "#000"
ctx.lineWidth = 4
ctx.beginPath()
ctx.moveTo(r, 0)
ctx.arc(w - r, r, r, pi / -2, pi / 2)
ctx.lineTo(r, h)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(r, r - 1)
ctx.lineTo(w, r - 1)
ctx.lineWidth = 2
ctx.stroke()
ctx.beginPath()
ctx.arc(r, r, r, 0, pi * 2)
ctx.fillStyle = config.blue ? "#67cecb" : "#ff421d"
ctx.fill()
ctx.lineWidth = 4
ctx.stroke()
ctx.font = this.bold(config.font) + "28px " + config.font
ctx.textAlign = "center"
ctx.textBaseline = "middle"
ctx.lineWidth = 5
ctx.miterLimit = 1
ctx.strokeStyle = "#fff"
ctx.fillStyle = "#000"
var text = config.blue ? "2P" : "1P"
ctx.strokeText(text, r + 2, r + 1)
ctx.fillText(text, r + 2, r + 1)
if(config.rank){
this.layeredText({
ctx: ctx,
text: config.rank,
fontSize: 20,
fontFamily: config.font,
x: w / 2 + r * 0.7,
y: r * 0.5,
width: 180,
align: "center",
baseline: "middle"
}, [
{fill: "#000"}
])
}
this.layeredText({
ctx: ctx,
text: config.name || "",
fontSize: 21,
fontFamily: config.font,
x: w / 2 + r * 0.7,
y: r * 1.5 - 0.5,
width: 180,
kanaSpacing: 10,
align: "center",
baseline: "middle"
}, [
{outline: "#000", letterBorder: 6},
{fill: "#fff"}
])
ctx.restore()
}
alpha(amount, ctx, callback, winW, winH){
if(amount >= 1){
return callback(ctx)
......
......@@ -505,7 +505,9 @@ class Game{
var musicDuration = duration * 1000 - this.controller.offset
if(this.musicFadeOut === 0){
if(this.controller.multiplayer === 1){
p2.send("gameresults", this.getGlobalScore())
var obj = this.getGlobalScore()
obj.name = account.loggedIn ? account.displayName : strings.defaultName
p2.send("gameresults", obj)
}
this.musicFadeOut++
}else if(this.musicFadeOut === 1 && ms >= started + 1600){
......
......@@ -202,12 +202,16 @@
var tja = new ParseTja(data, "oni", 0, 0, true)
var songObj = {
id: index + 1,
order: index + 1,
type: "tja",
chart: file,
stars: [],
stars: {},
music: "muted"
}
var coursesAdded = false
var titleLang = {}
var titleLangAdded = false
var subtitleLangAdded = false
var subtitleLang = {}
var dir = file.webkitRelativePath.toLowerCase()
dir = dir.slice(0, dir.lastIndexOf("/") + 1)
......@@ -221,7 +225,11 @@
}
songObj.subtitle = subtitle
songObj.preview = meta.demostart || 0
songObj.stars[this.courseTypes[diff]] = (meta.level || "0") + (meta.branch ? " B" : "")
songObj.courses[diff] = {
stars: meta.level || 0,
branch: !!meta.branch
}
coursesAdded = true
if(meta.wave){
songObj.music = this.otherFiles[dir + meta.wave.toLowerCase()] || songObj.music
}
......@@ -264,32 +272,27 @@
}
if(meta["title" + id]){
titleLang[id] = meta["title" + id]
titleLangAdded = true
}else if(songTitle in this.songTitle && this.songTitle[songTitle][id]){
titleLang[id] = this.songTitle[songTitle][id] + ura
titleLangAdded = true
}
if(meta["subtitle" + id]){
subtitleLang[id] = meta["subtitle" + id]
subtitleLangAdded = true
}
}
}
var titleLangArray = []
for(var id in titleLang){
titleLangArray.push(id + " " + titleLang[id])
}
if(titleLangArray.length !== 0){
songObj.title_lang = titleLangArray.join("\n")
}
var subtitleLangArray = []
for(var id in subtitleLang){
subtitleLangArray.push(id + " " + subtitleLang[id])
if(titleLangAdded){
songObj.title_lang = titleLang
}
if(subtitleLangArray.length !== 0){
songObj.subtitle_lang = subtitleLangArray.join("\n")
if(subtitleLangAdded){
songObj.subtitle_lang = subtitleLang
}
if(!songObj.category){
songObj.category = category || this.getCategory(file, [songTitle || songObj.title, file.name.slice(0, file.name.lastIndexOf("."))])
}
if(songObj.stars.length !== 0){
if(coursesAdded){
this.songs[index] = songObj
}
var hash = md5.base64(event.target.result).slice(0, -2)
......@@ -316,12 +319,20 @@
dir = dir.slice(0, dir.lastIndexOf("/") + 1)
var songObj = {
id: index + 1,
order: index + 1,
type: "osu",
chart: file,
subtitle: osu.metadata.ArtistUnicode || osu.metadata.Artist,
subtitle_lang: osu.metadata.Artist || osu.metadata.ArtistUnicode,
subtitle_lang: {
en: osu.metadata.Artist || osu.metadata.ArtistUnicode
},
preview: osu.generalInfo.PreviewTime / 1000,
stars: [null, null, null, parseInt(osu.difficulty.overallDifficulty) || 1],
courses: {
oni:{
stars: parseInt(osu.difficulty.overallDifficulty) || 0,
branch: false
}
},
music: this.otherFiles[dir + osu.generalInfo.AudioFilename.toLowerCase()] || "muted"
}
var filename = file.name.slice(0, file.name.lastIndexOf("."))
......@@ -333,7 +344,9 @@
suffix = " " + matches[0]
}
songObj.title = title + suffix
songObj.title_lang = (osu.metadata.Title || osu.metadata.TitleUnicode) + suffix
songObj.title_lang = {
en: (osu.metadata.Title || osu.metadata.TitleUnicode) + suffix
}
}else{
songObj.title = filename
}
......
/*! 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<arguments.length;t++){var r=arguments[t];for(var n in r)e[n]=r[n]}return e}var t={read:function(e){return e.replace(/%3B/g,";")},write:function(e){return e.replace(/;/g,"%3B")}};return function r(n,i){function o(r,o,u){if("undefined"!=typeof document){"number"==typeof(u=e({},i,u)).expires&&(u.expires=new Date(Date.now()+864e5*u.expires)),u.expires&&(u.expires=u.expires.toUTCString()),r=t.write(r).replace(/=/g,"%3D"),o=n.write(String(o),r);var c="";for(var f in u)u[f]&&(c+="; "+f,!0!==u[f]&&(c+="="+u[f].split(";")[0]));return document.cookie=r+"="+o+c}}return Object.create({set:o,get:function(e){if("undefined"!=typeof document&&(!arguments.length||e)){for(var r=document.cookie?document.cookie.split("; "):[],i={},o=0;o<r.length;o++){var u=r[o].split("="),c=u.slice(1).join("="),f=t.read(u[0]).replace(/%3D/g,"=");if(i[f]=n.read(c,f),e===f)break}return e?i[e]:i}},remove:function(t,r){o(t,"",e({},r,{expires:-1}))},withAttributes:function(t){return r(this.converter,e({},this.attributes,t))},withConverter:function(t){return r(e({},this.converter,t),this.attributes)}},{attributes:{value:Object.freeze(i)},converter:{value:Object.freeze(n)}})}(t,{path:"/"})});
......@@ -104,11 +104,12 @@ class Loader{
}))
this.afterJSCount =
["blurPerformance", "P2Connection"].length +
["blurPerformance"].length +
assets.audioSfx.length +
assets.audioMusic.length +
assets.audioSfxLR.length +
assets.audioSfxLoud.length
assets.audioSfxLoud.length +
(gameConfig._accounts ? 1 : 0)
Promise.all(this.promises).then(() => {
......@@ -155,65 +156,92 @@ class Loader{
}
}))
var readyEvent = "normal"
var songId
var hashLower = location.hash.toLowerCase()
p2 = new P2Connection()
if(hashLower.startsWith("#song=")){
var number = parseInt(location.hash.slice(6))
if(number > 0){
songId = number
readyEvent = "song-id"
}
}else if(location.hash.length === 6){
p2.hashLock = true
this.addPromise(new Promise(resolve => {
p2.open()
pageEvents.add(p2, "message", response => {
if(response.type === "session"){
pageEvents.send("session-start", "invited")
readyEvent = "session-start"
resolve()
}else if(response.type === "gameend"){
p2.hash("")
p2.hashLock = false
readyEvent = "session-expired"
resolve()
}
})
p2.send("invite", location.hash.slice(1).toLowerCase())
setTimeout(() => {
if(p2.socket.readyState !== 1){
p2.hash("")
p2.hashLock = false
resolve()
if(gameConfig._accounts){
var token = Cookies.get("token")
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)
}
}, 10000)
}).then(() => {
pageEvents.remove(p2, "message")
}))
}else{
p2.hash("")
}))
}else{
this.assetLoaded()
}
}
settings = new Settings()
pageEvents.setKbd()
scoreStorage = new ScoreStorage()
for(var i in assets.songsDefault){
var song = assets.songsDefault[i]
if(!song.hash){
song.hash = song.title
}
scoreStorage.songTitles[song.title] = song.hash
var score = scoreStorage.get(song.hash, false, true)
if(score){
score.title = song.title
}
}
Promise.all(this.promises).then(() => {
this.canvasTest.drawAllImages().then(result => {
if(!account.loggedIn){
scoreStorage.load()
}
for(var i in assets.songsDefault){
var song = assets.songsDefault[i]
if(!song.hash){
song.hash = song.title
}
scoreStorage.songTitles[song.title] = song.hash
var score = scoreStorage.get(song.hash, false, true)
if(score){
score.title = song.title
}
}
var promises = []
var readyEvent = "normal"
var songId
var hashLower = location.hash.toLowerCase()
p2 = new P2Connection()
if(hashLower.startsWith("#song=")){
var number = parseInt(location.hash.slice(6))
if(number > 0){
songId = number
readyEvent = "song-id"
}
}else if(location.hash.length === 6){
p2.hashLock = true
promises.push(new Promise(resolve => {
p2.open()
pageEvents.add(p2, "message", response => {
if(response.type === "session"){
pageEvents.send("session-start", "invited")
readyEvent = "session-start"
resolve()
}else if(response.type === "gameend"){
p2.hash("")
p2.hashLock = false
readyEvent = "session-expired"
resolve()
}
})
p2.send("invite", {
id: location.hash.slice(1).toLowerCase(),
name: account.loggedIn ? account.displayName : null
})
setTimeout(() => {
if(p2.socket.readyState !== 1){
p2.hash("")
p2.hashLock = false
resolve()
}
}, 10000)
}).then(() => {
pageEvents.remove(p2, "message")
}))
}else{
p2.hash("")
}
promises.push(this.canvasTest.drawAllImages())
Promise.all(promises).then(result => {
perf.allImg = result
perf.load = Date.now() - this.startTime
this.canvasTest.clean()
......
......@@ -297,7 +297,8 @@ class LoadSong{
})
p2.send("join", {
id: song.folder,
diff: song.difficulty
diff: song.difficulty,
name: account.loggedIn ? account.displayName : null
})
}else{
this.clean()
......
......@@ -84,6 +84,7 @@ var strings
var vectors
var settings
var scoreStorage
var account = {}
pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){
......
......@@ -3,6 +3,7 @@ class P2Connection{
this.closed = true
this.lastMessages = {}
this.otherConnected = false
this.name = null
this.allEvents = new Map()
this.addEventListener("message", this.message.bind(this))
this.currentHash = ""
......@@ -123,6 +124,7 @@ class P2Connection{
this.hash("")
this.hashLock = false
}
this.name = null
break
case "gameresults":
this.results = {}
......@@ -151,6 +153,9 @@ class P2Connection{
this.otherConnected = true
this.session = true
break
case "name":
this.name = (response.value || "").toString() || null
break
}
}
onhashchange(){
......
......@@ -86,6 +86,9 @@ class PageEvents{
})
}
keyEvent(event){
if(!("key" in event)){
return
}
if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){
this.lastKeyEvent = Date.now()
event.preventDefault()
......
......@@ -39,6 +39,7 @@ class Scoresheet{
this.draw = new CanvasDraw(noSmoothing)
this.canvasCache = new CanvasCache(noSmoothing)
this.nameplateCache = new CanvasCache(noSmoothing)
this.keyboard = new Keyboard({
confirm: ["enter", "space", "esc", "don_l", "don_r"]
......@@ -208,6 +209,7 @@ class Scoresheet{
this.canvas.style.height = (winH / this.pixelRatio) + "px"
this.canvasCache.resize(winW / ratio, 80 + 1, ratio)
this.nameplateCache.resize(274, 134, ratio + 0.2)
if(!this.multiplayer){
this.tetsuoHana.style.setProperty("--scale", ratio / this.pixelRatio)
......@@ -233,6 +235,9 @@ class Scoresheet{
if(!this.canvasCache.canvas){
this.canvasCache.resize(winW / ratio, 80 + 1, ratio)
}
if(!this.nameplateCache.canvas){
this.nameplateCache.resize(274, 67, ratio + 0.2)
}
}
this.winW = winW
this.winH = winH
......@@ -450,6 +455,29 @@ class Scoresheet{
ctx.fillText(text, 395, 308)
ctx.miterLimit = 10
if(p === 0){
var name = account.loggedIn ? account.displayName : strings.defaultName
}else{
var name = results.name
}
this.nameplateCache.get({
ctx: ctx,
x: 259,
y: 92,
w: 273,
h: 66,
id: p.toString() + "p",
}, ctx => {
this.draw.nameplate({
ctx: ctx,
x: 3,
y: 3,
name: name,
font: this.font,
blue: p === 1
})
})
if(this.controller.autoPlayEnabled){
ctx.drawImage(assets.image["badge_auto"],
431, 311, 34, 34
......
......@@ -5,17 +5,22 @@ class ScoreStorage{
this.difficulty = ["oni", "ura", "hard", "normal", "easy"]
this.scoreKeys = ["points", "good", "ok", "bad", "maxCombo", "drumroll"]
this.crownValue = ["", "silver", "gold"]
this.load()
}
load(){
load(strings){
this.scores = {}
this.scoreStrings = {}
try{
var localScores = localStorage.getItem("scoreStorage")
if(localScores){
this.scoreStrings = JSON.parse(localScores)
}
}catch(e){}
if(strings){
this.scoreStrings = strings
}else if(account.loggedIn){
return
}else{
this.scoreStrings = {}
try{
var localScores = localStorage.getItem("scoreStorage")
if(localScores){
this.scoreStrings = JSON.parse(localScores)
}
}catch(e){}
}
for(var hash in this.scoreStrings){
var scoreString = this.scoreStrings[hash]
var songAdded = false
......@@ -46,16 +51,22 @@ class ScoreStorage{
}
}
}
save(){
save(localOnly){
for(var hash in this.scores){
this.writeString(hash)
}
this.write()
return this.sendToServer({
scores: this.scoreStrings,
is_import: true
})
}
write(){
try{
localStorage.setItem("scoreStorage", JSON.stringify(this.scoreStrings))
}catch(e){}
if(!account.loggedIn){
try{
localStorage.setItem("scoreStorage", JSON.stringify(this.scoreStrings))
}catch(e){}
}
}
writeString(hash){
var score = this.scores[hash]
......@@ -112,6 +123,11 @@ class ScoreStorage{
this.scores[hash][difficulty] = scoreObject
this.writeString(hash)
this.write()
var obj = {}
obj[hash] = this.scoreStrings[hash]
this.sendToServer({
scores: obj
}).catch(() => this.add.apply(this, arguments))
}
template(){
var template = {crown: ""}
......@@ -146,6 +162,42 @@ class ScoreStorage{
delete this.scoreStrings[hash]
}
this.write()
this.sendToServer({
scores: this.scoreStrings,
is_import: true
})
}
}
sendToServer(obj, retry){
if(account.loggedIn){
var request = new XMLHttpRequest()
request.open("POST", "api/scores/save")
var promise = pageEvents.load(request).then(response => {
if(request.status !== 200){
return Promise.reject()
}
}).catch(() => {
if(retry){
account.loggedIn = false
delete account.username
delete account.displayName
Cookies.remove("token")
this.load()
pageEvents.send("logout")
return Promise.reject()
}else{
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 3000)
}).then(() => this.sendToServer(obj, true))
}
})
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
request.send(JSON.stringify(obj))
return promise
}else{
return Promise.resolve()
}
}
}
......@@ -34,7 +34,10 @@ class Session{
pageEvents.send("session-start", "host")
}
})
p2.send("invite")
p2.send("invite", {
id: null,
name: account.loggedIn ? account.displayName : null
})
pageEvents.send("session")
}
getElement(name){
......
This diff is collapsed.
......@@ -36,6 +36,8 @@
this.hard = "むずかしい"
this.oni = "おに"
this.songBranch = "譜面分岐あり"
this.defaultName = "どんちゃん"
this.notLoggedIn = "ログインしていない"
this.sessionStart = "オンラインセッションを開始する!"
this.sessionEnd = "オンラインセッションを終了する"
this.loading = "ロード中..."
......@@ -184,6 +186,24 @@
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.account = {
username: "ユーザー名",
enterUsername: "ユーザー名を入力",
password: "パスワード",
enterPassword: "パスワードを入力",
repeatPassword: "パスワードを再入力",
remember: "ログイン状態を保持する",
login: "ログイン",
register: "登録",
registerAccount: "アカウントを登録",
passwordsDoNotMatch: "パスワードが一致しません",
cannotBeEmpty: "%sは空にできません",
error: "リクエストの処理中にエラーが発生しました",
logout: "ログアウト",
back: "もどる",
cancel: "Cancel",
save: "Save"
}
this.browserSupport = {
browserWarning: "サポートされていないブラウザを実行しています (%s)",
details: "詳しく",
......@@ -233,6 +253,8 @@ function StringsEn(){
this.hard = "Hard"
this.oni = "Extreme"
this.songBranch = "Diverge Notes"
this.defaultName = "Don-chan"
this.notLoggedIn = "Not logged in"
this.sessionStart = "Begin an Online Session!"
this.sessionEnd = "End Online Session"
this.loading = "Loading..."
......@@ -381,6 +403,33 @@ function StringsEn(){
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.account = {
username: "Username",
enterUsername: "Enter Username",
password: "Password",
enterPassword: "Enter Password",
repeatPassword: "Repeat Password",
remember: "Remember me",
login: "Log In",
register: "Register",
registerAccount: "Register account",
passwordsDoNotMatch: "Passwords do not match",
cannotBeEmpty: "%s cannot be empty",
error: "An error occurred while processing your request",
logout: "Log Out",
back: "Back",
cancel: "Cancel",
save: "Save",
displayName: "Displayed Name",
changePassword: "Change Password",
currentNewRepeat: [
"Current Password",
"New Password",
"Repeat New Password"
],
deleteAccount: "Delete Account",
verifyPassword: "Verify password to delete this account"
}
this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)",
details: "Details...",
......@@ -430,6 +479,8 @@ function StringsCn(){
this.hard = "困难"
this.oni = "魔王"
this.songBranch = "有谱面分歧"
this.defaultName = "小咚"
this.notLoggedIn = "未登录"
this.sessionStart = "开始在线会话!"
this.sessionEnd = "结束在线会话"
this.loading = "加载中..."
......@@ -578,6 +629,24 @@ function StringsCn(){
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.account = {
username: "登录名",
enterUsername: "输入用户名",
password: "密码",
enterPassword: "输入密码",
repeatPassword: "重新输入密码",
remember: "记住登录",
login: "登录",
register: "注册",
registerAccount: "注册帐号",
passwordsDoNotMatch: "密码不匹配",
cannotBeEmpty: "%s不能为空",
error: "处理您的请求时发生错误",
logout: "登出",
back: "返回",
cancel: "Cancel",
save: "Save"
}
this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)",
details: "Details...",
......@@ -627,6 +696,8 @@ function StringsTw(){
this.hard = "困難"
this.oni = "魔王"
this.songBranch = "有譜面分歧"
this.defaultName = "小咚"
this.notLoggedIn = "未登錄"
this.sessionStart = "開始多人模式!"
this.sessionEnd = "結束多人模式"
this.loading = "讀取中..."
......@@ -775,6 +846,24 @@ function StringsTw(){
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.account = {
username: "使用者名稱",
enterUsername: "輸入用戶名",
password: "密碼",
enterPassword: "輸入密碼",
repeatPassword: "再次輸入密碼",
remember: "記住登錄",
login: "登入",
register: "註冊",
registerAccount: "註冊帳號",
passwordsDoNotMatch: "密碼不匹配",
cannotBeEmpty: "%s不能為空",
error: "處理您的請求時發生錯誤",
logout: "登出",
back: "返回",
cancel: "Cancel",
save: "Save"
}
this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)",
details: "Details...",
......@@ -824,6 +913,8 @@ function StringsKo(){
this.hard = "어려움"
this.oni = "귀신"
this.songBranch = "악보 분기 있습니다"
this.defaultName = "동이"
this.notLoggedIn = "로그인하지 않았습니다"
this.sessionStart = "온라인 세션 시작!"
this.sessionEnd = "온라인 세션 끝내기"
this.loading = "로딩 중..."
......@@ -972,6 +1063,24 @@ function StringsKo(){
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.account = {
username: "사용자 이름",
enterUsername: "사용자 이름을 입력하십시오",
password: "비밀번호",
enterPassword: "비밀번호 입력",
repeatPassword: "비밀번호 재입력",
remember: "자동 로그인",
login: "로그인",
register: "가입하기",
registerAccount: "계정 등록",
passwordsDoNotMatch: "비밀번호가 일치하지 않습니다",
cannotBeEmpty: "%s 비어 있을 수 없습니다",
error: "요청을 처리하는 동안 오류가 발생했습니다",
logout: "로그 아웃",
back: "돌아간다",
cancel: "Cancel",
save: "Save"
}
this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)",
details: "Details...",
......
......@@ -126,6 +126,7 @@
this.comboCache = new CanvasCache(noSmoothing)
this.pauseCache = new CanvasCache(noSmoothing)
this.branchCache = new CanvasCache(noSmoothing)
this.nameplateCache = new CanvasCache(noSmoothing)
this.multiplayer = this.controller.multiplayer
......@@ -235,6 +236,11 @@
if(!this.multiplayer){
this.pauseCache.resize(81 * this.pauseOptions.length * 2, 464, ratio)
}
if(this.portrait){
this.nameplateCache.resize(220, 54, ratio + 0.2)
}else{
this.nameplateCache.resize(274, 67, ratio + 0.2)
}
this.fillComboCache()
this.setDonBgHeight()
resized = true
......@@ -388,6 +394,32 @@
h: 130
}
if(this.multiplayer !== 2){
this.nameplateCache.get({
ctx: ctx,
x: 167,
y: 160,
w: 219,
h: 53,
id: "1p",
}, ctx => {
if(this.multiplayer === 2){
var name = p2.name || strings.defaultName
}else{
var name = account.loggedIn ? account.displayName : strings.defaultName
}
this.draw.nameplate({
ctx: ctx,
x: 3,
y: 3,
scale: 0.8,
name: name,
font: this.font,
blue: this.multiplayer === 2
})
})
}
ctx.fillStyle = "#000"
ctx.fillRect(
0,
......@@ -547,6 +579,29 @@
}
var taikoPos = {x: 179, y: frameTop + 190, w: 138, h: 162}
this.nameplateCache.get({
ctx: ctx,
x: 320,
y: this.multiplayer === 2 ? frameTop + 305 : frameTop + 20,
w: 273,
h: 66,
id: "1p",
}, ctx => {
if(this.multiplayer === 2){
var name = p2.name || strings.defaultName
}else{
var name = account.loggedIn ? account.displayName : strings.defaultName
}
this.draw.nameplate({
ctx: ctx,
x: 3,
y: 3,
name: name,
font: this.font,
blue: this.multiplayer === 2
})
})
ctx.fillStyle = "#000"
ctx.fillRect(
0,
......
<div class="view-outer">
<div class="view account-view">
<div class="view-title stroke-sub"></div>
<div class="view-content">
<div class="displayname-div">
<div class="displayname-hint"></div>
<input type="text" class="displayname">
</div>
<form class="accountpass-form">
<div>
<div class="accountpass-btn taibtn stroke-sub link-btn"></div>
</div>
<div class="accountpass-div">
<input type="password" name="password"><input type="password" name="newpassword" autocomplete="new-password"><input type="password" name="newpassword2" autocomplete="new-password">
</div>
</form>
<form class="accountdel-form">
<div>
<div class="accountdel-btn taibtn stroke-sub link-btn"></div>
</div>
<div class="accountdel-div">
<input type="password" name="password">
</div>
</form>
</div>
<div id="diag-txt"></div>
<div class="left-buttons">
<div class="logout-btn taibtn stroke-sub link-btn"></div>
</div>
<div class="save-btn taibtn stroke-sub selected"></div>
<div class="view-end-button taibtn stroke-sub"></div>
</div>
</div>
<div class="view-outer">
<div class="view">
<div class="view-title stroke-sub"></div>
<div class="view-content">
<form class="login-form">
<div class="username-hint"></div>
<input type="text" name="username" required>
<div class="password-hint"></div>
<input type="password" name="password" required>
<div class="password2-div"></div>
<div class="remember-div">
<label class="remember-label">
<input type="checkbox" checked="checked" name="remember">
</label>
</div>
<div class="login-btn taibtn stroke-sub link-btn"></div>
</form>
</div>
<div class="left-buttons">
<div class="register-btn taibtn stroke-sub link-btn"></div>
</div>
<div class="view-end-button taibtn stroke-sub selected"></div>
</div>
</div>
......@@ -42,7 +42,8 @@ async def connection(ws, path):
user = {
"ws": ws,
"action": "ready",
"session": False
"session": False,
"name": None
}
server_status["users"].append(user)
try:
......@@ -79,6 +80,7 @@ async def connection(ws, path):
waiting = server_status["waiting"]
id = value["id"] if "id" in value else None
diff = value["diff"] if "diff" in value else None
user["name"] = value["name"] if "name" in value else None
if not id or not diff:
continue
if id not in waiting:
......@@ -92,6 +94,7 @@ async def connection(ws, path):
await ws.send(msgobj("waiting"))
else:
# Join the other user and start game
user["name"] = value["name"] if "name" in value else None
user["other_user"] = waiting[id]["user"]
waiting_diff = waiting[id]["diff"]
del waiting[id]
......@@ -101,7 +104,9 @@ async def connection(ws, path):
user["other_user"]["other_user"] = user
await asyncio.wait([
ws.send(msgobj("gameload", waiting_diff)),
user["other_user"]["ws"].send(msgobj("gameload", diff))
user["other_user"]["ws"].send(msgobj("gameload", diff)),
ws.send(msgobj("name", user["other_user"]["name"])),
user["other_user"]["ws"].send(msgobj("name", user["name"]))
])
else:
# Wait for another user
......@@ -116,27 +121,31 @@ async def connection(ws, path):
# Update others on waiting players
await notify_status()
elif type == "invite":
if value == None:
if value and "id" in value and value["id"] == None:
# Session invite link requested
invite = get_invite()
server_status["invites"][invite] = user
user["action"] = "invite"
user["session"] = invite
user["name"] = value["name"] if "name" in value else None
await ws.send(msgobj("invite", invite))
elif value in server_status["invites"]:
elif value and "id" in value and value["id"] in server_status["invites"]:
# Join a session with the other user
user["other_user"] = server_status["invites"][value]
del server_status["invites"][value]
user["name"] = value["name"] if "name" in value else None
user["other_user"] = server_status["invites"][value["id"]]
del server_status["invites"][value["id"]]
if "ws" in user["other_user"]:
user["other_user"]["other_user"] = user
user["action"] = "invite"
user["session"] = value
user["session"] = value["id"]
sent_msg = msgobj("session")
await asyncio.wait([
ws.send(sent_msg),
user["other_user"]["ws"].send(sent_msg)
user["other_user"]["ws"].send(sent_msg),
ws.send(msgobj("invite")),
ws.send(msgobj("name", user["other_user"]["name"])),
user["other_user"]["ws"].send(msgobj("name", user["name"]))
])
await ws.send(msgobj("invite"))
else:
del user["other_user"]
await ws.send(msgobj("gameend"))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment