diff --git a/parts/modes/netBattle.lua b/parts/modes/netBattle.lua index 638c9b10..f0d263a8 100644 --- a/parts/modes/netBattle.lua +++ b/parts/modes/netBattle.lua @@ -12,7 +12,7 @@ return{ bgm={'battle','beat5th','cruelty','distortion','echo','far','final','here','hope','memory','moonbeam','push','rectification','secret7th remix','secret7th','secret8th remix','secret8th','shift','shining terminal','storm','super7th','there','truth','vapor','waterfall'}, }, load=function() - for k,v in next,NET.roomState.roomData do + for k,v in next,NET.roomState.data do GAME.modeEnv[k]=v end GAME.modeEnv.allowMod=false diff --git a/parts/net.lua b/parts/net.lua index a85dc20f..8b75fa7e 100644 --- a/parts/net.lua +++ b/parts/net.lua @@ -9,12 +9,16 @@ local NET={ name=false, type=false, version=false, + description=false, + }, + data={}, + count={ + Gamer=0, + Spectator=0, }, - roomData={}, - count=false, capacity=false, private=false, - start=false, + state='Playing', }, spectate=false,-- If player is spectating @@ -33,6 +37,22 @@ function NET.connectLost() while SCN.stack[#SCN.stack-1]~='main' and #SCN.stack>0 do SCN.pop() end SCN.back() end +function NET.freshRoomState() + local playCount,readyCount=0,0 + for j=1,#NETPLY.list do + if NETPLY.list[j].playMode=='Gamer' then playCount=playCount+1 end + if NETPLY.list[j].readyMode=='Ready' then readyCount=readyCount+1 end + end + + if playCount-readyCount==1 then + local p=NETPLY.map[USER.uid] + if p.playMode=='Gamer' and p.readyMode~='Ready' then + SFX.play('warn_2',.5) + end + end + + NET.roomReadyState=playCount>0 and playCount==readyCount +end -------------------------- local availableErrorTextType={info=1,warn=1,error=1} @@ -352,11 +372,11 @@ local actMap={ player_updateConf= 1200, player_finish= 1201, player_joinGroup= 1202, - player_setReady= 1203, + player_setReadyMode= 1203, player_setHost= 1204, player_setState= 1205, player_stream= 1206, - player_setPlaying= 1207, + player_setPlayMode= 1207, room_chat= 1300, room_create= 1301, room_getData= 1302, @@ -373,7 +393,7 @@ local actMap={ local function wsSend(act,data) -- print(("Send: $1 -->"):repD(act)) - -- print(("Send: $1 -->"):repD(act)) print(type(data)=='table' and TABLE.dump(data) or tostring(data),"\n") + print(("Send: $1 -->"):repD(act)) print(type(data)=='table' and TABLE.dump(data) or tostring(data),"\n") WS.send('game',JSON.encode{ action=assert(act), data=data, @@ -382,11 +402,12 @@ end --Remove player when leave local function _playerLeaveRoom(uid) - NETPLY.remove(uid) for i=1,#PLAYERS do if PLAYERS[i].uid==uid then table.remove(PLAYERS,i) break end end for i=1,#PLY_ALIVE do if PLY_ALIVE[i].uid==uid then table.remove(PLAYERS,i) break end end if uid==USER.uid and SCN.cur=='net_game' then SCN.back() + else + NETPLY.remove(uid) end end @@ -407,20 +428,11 @@ function NET.room_chat(msg,rid) return true end end -function NET.room_create(roomName,description,capacity,roomType,roomData,password) +function NET.room_create(data) if not TASK.lock('createRoom',10) then MES.new('warn',text.tooFrequently) return end + TABLE.coverR(data,NET.roomState) WAIT{timeout=12} - wsSend(actMap.room_create,{ - capacity=capacity, - info={ - name=roomName, - type=roomType, - version=VERSION.room, - description=description, - }, - data=roomData, - password=password, - }) + wsSend(actMap.room_create,data) end function NET.room_getData(rid) wsSend(actMap.room_getData,{ @@ -491,8 +503,8 @@ end function NET.player_joinGroup(gid) wsSend(actMap.player_joinGroup,gid) end -function NET.player_setReady(bool) - wsSend(actMap.player_setReady,bool) +function NET.player_setReadyMode(mode) + wsSend(actMap.player_setReadyMode,mode) end function NET.player_setHost(pid) wsSend(actMap.player_setHost,{ @@ -506,8 +518,8 @@ end function NET.player_stream(stream) wsSend(actMap.player_stream,stream) end -function NET.player_setPlaying(playing) - wsSend(actMap.player_setPlaying,playing and 'Gamer' or 'Spectator') +function NET.player_setPlayMode(mode) + wsSend(actMap.player_setPlayMode,mode) end -- Match @@ -535,24 +547,37 @@ function NET.wsCallBack.room_create(body) NET.wsCallBack.room_enter(body) end function NET.wsCallBack.room_getData(body) - NET.roomState.roomData=body.data + NET.roomState.data=body.data end function NET.wsCallBack.room_setData(body) NET.wsCallBack.room_getData(body) end function NET.wsCallBack.room_getInfo(body) - NET.roomState.roomInfo=body.info + NET.roomState.info=body.info end function NET.wsCallBack.room_setInfo(body) NET.wsCallBack.room_getInfo(body) end -function NET.wsCallBack.room_enter(body)-- TODO +function NET.wsCallBack.room_enter(body) TASK.unlock('enterRoom') - -- NET.roomState=... NET.textBox.hide=true NET.inputBox.hide=true NET.textBox:clear() NET.inputBox:clear() + + NET.roomState=body.data + NETPLY.clear() + if body.data.players then + for _,p in next,body.data.players do + NETPLY.add{ + uid=p.playerId, + playMode=p.type, + readyMode=p.state, + config=p.config, + } + end + end + loadGame('netBattle',true,true) WAIT.interrupt() end @@ -561,10 +586,10 @@ function NET.wsCallBack.room_kick(body) _playerLeaveRoom(body.data.playerId) end function NET.wsCallBack.room_leave(body) - if body.data.playerId~=USER.uid then - MES.new('info',text.leaveRoom:repD(body.data.playerId)) + if body.data then + MES.new('info',text.leaveRoom:repD(body.data.playerId),2.6) end - _playerLeaveRoom(body.data.playerId) + _playerLeaveRoom(body.data and body.data.playerId or USER.uid) end function NET.wsCallBack.room_fetch(body) TASK.unlock('fetchRoom') @@ -577,21 +602,24 @@ function NET.wsCallBack.room_remove() MES.new('info',text.roomRemoved) _playerLeaveRoom(USER.uid) end -function NET.wsCallBack.player_updateConf(body)-- TODO +function NET.wsCallBack.player_updateConf(body) + NETPLY.setConf(body.data.playerId,body.data.config) end function NET.wsCallBack.player_finish(body)-- TODO end function NET.wsCallBack.player_joinGroup(body)-- TODO end -function NET.wsCallBack.player_setReady(body)-- TODO -end function NET.wsCallBack.player_setHost(body)-- TODO end function NET.wsCallBack.player_setState(body)-- TODO end function NET.wsCallBack.player_stream(body)-- TODO end -function NET.wsCallBack.player_setPlaying(body)-- TODO +function NET.wsCallBack.player_setPlayMode(body) + NETPLY.setPlayMode(body.data.playerId,body.data.type) +end +function NET.wsCallBack.player_setReadyMode(body) + NETPLY.setReadyMode(body.data.playerId,body.data.type) end function NET.ws_connect() @@ -642,7 +670,7 @@ function NET.ws_update() if WS.status('game')=='dead' then return end updateOnlineCD=updateOnlineCD%626+1 - if updateOnlineCD==0 then NET.global_getOnlineCount() end + if updateOnlineCD==1 then NET.global_getOnlineCount() end local msg,op=WS.read('game') if msg then @@ -660,7 +688,7 @@ function NET.ws_update() elseif msg then msg=JSON.decode(msg) -- print(("Recv: <-- $1 err:$2"):repD(msg.action,msg.errno)) - -- print(("Recv: <-- $1 err:$2"):repD(msg.action,msg.errno)) print(TABLE.dump(msg),"\n") + print(("Recv: <-- $1 err:$2"):repD(msg.action,msg.errno)) print(TABLE.dump(msg),"\n") if msg.errno~=0 then parseError(msg.message~=nil and msg.message or msg) else diff --git a/parts/netPlayer.lua b/parts/netPlayer.lua index fdaa572f..2e089ae7 100644 --- a/parts/netPlayer.lua +++ b/parts/netPlayer.lua @@ -71,8 +71,8 @@ local nullIndex={ MES.new('error',"User not loaded: "..k) NETPLY.add{ uid=k, - username="Stacker", - mode=0, + playMode='Spectator', + readyMode='Standby', config="", } return self[k] @@ -106,10 +106,10 @@ end function NETPLY.add(d) local p={ uid=d.uid, - username=d.username, - mode=d.mode, - config=d.config, - connected=false, + playMode=d.playMode,-- 'Gamer'|'Spectator' + readyMode=d.readyMode,-- 'Standby'|'Ready'|'Playing'|'Finished' + config=d.config,-- A long string generated by dumpBasicConfig() + place=1e99, stat=false, } @@ -132,34 +132,26 @@ function NETPLY.remove(uid) end function NETPLY.getCount() return #PLYlist end -function NETPLY.getSelfJoinMode() return PLYmap[USER.uid].mode end -function NETPLY.getSelfReady() return PLYmap[USER.uid].mode>0 end +function NETPLY.getSelfPlayMode() return PLYmap[USER.uid].playMode end +function NETPLY.getSelfReadyMode() return PLYmap[USER.uid].playMode end +function NETPLY.getSelfReady() return PLYmap[USER.uid].readyMode end function NETPLY.setPlayerObj(ply,p) ply.p=p end function NETPLY.setConf(uid,config) PLYmap[uid].config=config end -function NETPLY.setJoinMode(uid,ready) - for _,p in next,PLYlist do - if p.uid==uid then - if p.mode~=ready then - p.mode=ready - if ready==0 then NET.roomReadyState=false end - SFX.play('spin_0',.6) - if p.uid==USER.uid then - TASK.unlock('ready') - elseif PLYmap[USER.uid].mode==0 then - for j=1,#PLYlist do - if not p.uid==USER.uid and PLYlist[j].mode==0 then - return - end - end - SFX.play('warn_2',.5) - end - end - return - end +function NETPLY.setPlayMode(uid,mode) + local p=PLYmap[uid] + if p and p.playMode~=mode then + p.playMode=mode + NET.freshRoomState() + end +end +function NETPLY.setReadyMode(uid,mode) + local p=PLYmap[uid] + if p and p.ReadyMode~=mode then + p.ReadyMode=mode + NET.freshRoomState() end end -function NETPLY.setConnect(uid) PLYmap[uid].connected=true end function NETPLY.setPlace(uid,place) PLYmap[uid].place=place end function NETPLY.setStat(uid,S) PLYmap[uid].stat={ @@ -170,8 +162,7 @@ function NETPLY.setStat(uid,S) end function NETPLY.resetState() for i=1,#PLYlist do - PLYlist[i].mode=0 - PLYlist[i].connected=false + PLYlist[i].playMode=0 end end @@ -209,18 +200,19 @@ function NETPLY.draw() local p=PLYlist[i] gc_translate(p.x,p.y) -- Rectangle - gc_setColor(COLOR[ - p.mode==0 and 'lH' or - p.mode==1 and 'N' or - p.mode==2 and 'F' - ]) + if p.playMode=='Gamer' then + gc_setColor(COLOR[ + p.playMode=='Spectator' and 'lH' or + p.playMode=='Gamer' and ( + p.readyMode=='Standby' and 'Z' or + 'N' + ) or 'dH' + ]) + else + gc_setColor(COLOR.lH) + end gc_setLineWidth(2) gc_rectangle('line',0,0,p.w,p.h) - if p.connected then - local c=p.mode==1 and COLOR.N or COLOR.F - gc_setColor(c[1],c[2],c[3],.26) - gc_rectangle('fill',0,0,p.w,p.h) - end -- Stencil stencilW,stencilH=p.w,p.h @@ -236,12 +228,12 @@ function NETPLY.draw() if p.h>=47 then setFont(40) gc_print("#"..p.uid,50,-5) - gc_print(p.username,210,-5) + gc_print(USERS.getUsername(p.uid),210,-5) else setFont(15) gc_print("#"..p.uid,46,-1) setFont(30) - gc_print(p.username,p.h,8) + gc_print(USERS.getUsername(p.uid),p.h,8) end -- Stat @@ -273,7 +265,7 @@ function NETPLY.draw() setFont(30) gc_print("#"..selP.uid,75,0) setFont(35) - gc_print(selP.username,75,25) + gc_print(USERS.getUsername(selP.uid),75,25) setFont(20) gc_printf(USERS.getMotto(selP.uid),5,70,390) if selP.stat then diff --git a/parts/scenes/main.lua b/parts/scenes/main.lua index 587587bd..13cc012b 100644 --- a/parts/scenes/main.lua +++ b/parts/scenes/main.lua @@ -157,12 +157,6 @@ function scene.draw() -- Player PLAYERS[1]:draw() - - -- Profile - drawSelfProfile() - - -- Player count - drawOnlinePlayerCount() end scene.widgetList={ diff --git a/parts/scenes/net_game.lua b/parts/scenes/net_game.lua index f25811ed..a602c300 100644 --- a/parts/scenes/net_game.lua +++ b/parts/scenes/net_game.lua @@ -27,14 +27,15 @@ local function _hideReadyUI() end local function _setCancel() - NET.player_setPlaying(true) - NET.player_setReady(true) + NET.player_setPlayMode('Gamer') + NET.player_setReadyMode(false) end local function _setReady() - NET.player_setReady(true) + NET.player_setPlayMode('Gamer') + NET.player_setReadyMode(true) end local function _setSpectate() - NET.player_setPlaying(false) + NET.player_setPlayMode('Spectator') end local function _gotoSetting() @@ -153,7 +154,7 @@ function scene.keyDown(key,isRep) end elseif not _hideReadyUI() then if key=='space' then - if NETPLY.getSelfJoinMode()==0 then + if NETPLY.getSelfPlayMode()~='Gamer' then (kb.isDown('lctrl','rctrl','lalt','ralt') and _setSpectate or _setReady)() else _setCancel() @@ -323,8 +324,8 @@ function scene.draw() gc_print("M",430,10) end end -local function _hideF_ingame() return _hideReadyUI() or NETPLY.getSelfReady() end -local function _hideF_ingame2() return _hideReadyUI() or not NETPLY.getSelfReady() end +local function _hideF_ingame() return _hideReadyUI() or NETPLY.getSelfReadyMode()=='Spectator' end +local function _hideF_ingame2() return _hideReadyUI() or NETPLY.getSelfReadyMode()=='Gamer' end scene.widgetList={ textBox, inputBox, diff --git a/parts/scenes/net_newRoom.lua b/parts/scenes/net_newRoom.lua index 00a0cc29..48abcd43 100644 --- a/parts/scenes/net_newRoom.lua +++ b/parts/scenes/net_newRoom.lua @@ -36,14 +36,17 @@ local function _createRoom() if #roomname==0 then roomname=(USERS.getUsername(USER.uid) or "Anonymous").."'s room" end - NET.room_create( - roomname, - descriptionBox.value, - ROOMENV.capacity, - "normal", - ROOMENV, - pw - ) + NET.room_create{ + capacity=ROOMENV.capacity, + info={ + name=roomname, + type="normal", + version=VERSION.room, + description=descriptionBox.value, + }, + data=ROOMENV, + password=pw, + } end end diff --git a/parts/users.lua b/parts/users.lua index 5fe5d573..67231e71 100644 --- a/parts/users.lua +++ b/parts/users.lua @@ -62,28 +62,27 @@ local USERS={} avatar_frame=0, }]] function USERS.updateUserData(data) - local id=data.id - db[id].username=data.username - db[id].motto=data.motto - if type(data.avatar_hash)=='string' and (db[id].hash~=data.avatar_hash or not fs.getInfo("cache/"..data.avatar_hash)) then - db[id].hash=data.avatar_hash - NET.getAvatar(id) + local uid=data.id + db[uid].username=data.username + db[uid].motto=data.motto + if type(data.avatar_hash)=='string' and (db[uid].hash~=data.avatar_hash or not fs.getInfo("cache/"..data.avatar_hash)) then + db[uid].hash=data.avatar_hash + NET.getAvatar(uid) end - fs.write("cache/user"..id..".dat",JSON.encode{ + fs.write("cache/user"..uid..".dat",JSON.encode{ username=data.username, motto=data.motto, - hash=db[id].hash, + hash=db[uid].hash, }) end -function USERS.updateAvatar(id,imgData) - local hash=db[id].hash +function USERS.updateAvatar(uid,imgData) + local hash=db[uid].hash fs.write("cache/"..hash,love.data.decode('string','base64',imgData:sub(imgData:find(",")+1))) - db_img[id]=_loadAvatar("cache/"..hash) + db_img[uid]=_loadAvatar("cache/"..hash) end function USERS.getUsername(uid) return db[uid].username end function USERS.getMotto(uid) return db[uid].motto end -function USERS.getHash(uid) return db[uid].hash or "" end function USERS.getAvatar(uid) if uid then if not db[uid].new then