mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-12 11:07:27 +08:00
[Bug Fix][Enhance] About Link Play
- Fix a bug that the room host will be changed late when finishing a song - Add logging module for linkplay server
This commit is contained in:
@@ -37,13 +37,13 @@ class Constant:
|
|||||||
DOWNLOAD_TIME_GAP_LIMIT = Config.DOWNLOAD_TIME_GAP_LIMIT
|
DOWNLOAD_TIME_GAP_LIMIT = Config.DOWNLOAD_TIME_GAP_LIMIT
|
||||||
DOWNLOAD_LINK_PREFIX = Config.DOWNLOAD_LINK_PREFIX
|
DOWNLOAD_LINK_PREFIX = Config.DOWNLOAD_LINK_PREFIX
|
||||||
|
|
||||||
LINK_PLAY_UNLOCK_LENGTH = 512 # Units: bytes
|
LINKPLAY_UNLOCK_LENGTH = 512 # Units: bytes
|
||||||
LINK_PLAY_TIMEOUT = 5 # Units: seconds
|
LINKPLAY_TIMEOUT = 5 # Units: seconds
|
||||||
|
|
||||||
LINK_PLAY_HOST = '127.0.0.1' if Config.SET_LINK_PLAY_SERVER_AS_SUB_PROCESS else Config.LINK_PLAY_HOST
|
LINKPLAY_HOST = '127.0.0.1' if Config.SET_LINKPLAY_SERVER_AS_SUB_PROCESS else Config.LINKPLAY_HOST
|
||||||
LINK_PLAY_TCP_PORT = Config.LINK_PLAY_TCP_PORT
|
LINKPLAY_TCP_PORT = Config.LINKPLAY_TCP_PORT
|
||||||
LINK_PLAY_UDP_PORT = Config.LINK_PLAY_UDP_PORT
|
LINKPLAY_UDP_PORT = Config.LINKPLAY_UDP_PORT
|
||||||
LINK_PLAY_AUTHENTICATION = Config.LINK_PLAY_AUTHENTICATION
|
LINKPLAY_AUTHENTICATION = Config.LINKPLAY_AUTHENTICATION
|
||||||
|
|
||||||
COURSE_STAMINA_COST = 4
|
COURSE_STAMINA_COST = 4
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ from core.error import ArcError, Timeout
|
|||||||
from .constant import Constant
|
from .constant import Constant
|
||||||
from .user import UserInfo
|
from .user import UserInfo
|
||||||
|
|
||||||
socket.setdefaulttimeout(Constant.LINK_PLAY_TIMEOUT)
|
socket.setdefaulttimeout(Constant.LINKPLAY_TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
def get_song_unlock(client_song_map: dict) -> bytes:
|
def get_song_unlock(client_song_map: dict) -> bytes:
|
||||||
'''处理可用歌曲bit,返回bytes'''
|
'''处理可用歌曲bit,返回bytes'''
|
||||||
|
|
||||||
user_song_unlock = [0] * Constant.LINK_PLAY_UNLOCK_LENGTH
|
user_song_unlock = [0] * Constant.LINKPLAY_UNLOCK_LENGTH
|
||||||
for i in range(0, Constant.LINK_PLAY_UNLOCK_LENGTH*2, 2):
|
for i in range(0, Constant.LINKPLAY_UNLOCK_LENGTH*2, 2):
|
||||||
x = 0
|
x = 0
|
||||||
y = 0
|
y = 0
|
||||||
if str(i) in client_song_map:
|
if str(i) in client_song_map:
|
||||||
@@ -98,8 +98,8 @@ class RemoteMultiPlayer:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def tcp(data: str) -> str:
|
def tcp(data: str) -> str:
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||||
sock.connect((Constant.LINK_PLAY_HOST,
|
sock.connect((Constant.LINKPLAY_HOST,
|
||||||
Constant.LINK_PLAY_TCP_PORT))
|
Constant.LINKPLAY_TCP_PORT))
|
||||||
sock.sendall(bytes(data + "\n", "utf-8"))
|
sock.sendall(bytes(data + "\n", "utf-8"))
|
||||||
try:
|
try:
|
||||||
received = str(sock.recv(1024), "utf-8").strip()
|
received = str(sock.recv(1024), "utf-8").strip()
|
||||||
@@ -111,7 +111,7 @@ class RemoteMultiPlayer:
|
|||||||
|
|
||||||
def data_swap(self, data: tuple) -> tuple:
|
def data_swap(self, data: tuple) -> tuple:
|
||||||
|
|
||||||
received = self.tcp(Constant.LINK_PLAY_AUTHENTICATION +
|
received = self.tcp(Constant.LINKPLAY_AUTHENTICATION +
|
||||||
'|' + '|'.join([str(x) for x in data]))
|
'|' + '|'.join([str(x) for x in data]))
|
||||||
|
|
||||||
self.data_recv = received.split('|')
|
self.data_recv = received.split('|')
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
from telnetlib import AUTHENTICATION
|
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
'''
|
'''
|
||||||
Link Play server configuration
|
Link Play server configuration
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import base64
|
import base64
|
||||||
|
import logging
|
||||||
import random
|
import random
|
||||||
import socketserver
|
import socketserver
|
||||||
import threading
|
import threading
|
||||||
@@ -19,6 +20,9 @@ player_dict = {} # 'player_id' : Player
|
|||||||
clean_timer = 0
|
clean_timer = 0
|
||||||
lock = threading.RLock()
|
lock = threading.RLock()
|
||||||
|
|
||||||
|
logging.basicConfig(format='[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
|
||||||
|
level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def random_room_code():
|
def random_room_code():
|
||||||
# 随机生成房间号
|
# 随机生成房间号
|
||||||
@@ -102,7 +106,7 @@ class UDP_handler(socketserver.BaseRequestHandler):
|
|||||||
|
|
||||||
plaintext = decrypt(user['key'], b'', iv, ciphertext, tag)
|
plaintext = decrypt(user['key'], b'', iv, ciphertext, tag)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logging.error(e)
|
||||||
return None
|
return None
|
||||||
# print(binascii.b2a_hex(plaintext))
|
# print(binascii.b2a_hex(plaintext))
|
||||||
|
|
||||||
@@ -135,11 +139,14 @@ class TCP_handler(socketserver.StreamRequestHandler):
|
|||||||
data = message.split('|')
|
data = message.split('|')
|
||||||
if data[0] != Config.AUTHENTICATION:
|
if data[0] != Config.AUTHENTICATION:
|
||||||
self.wfile.write(b'No authentication')
|
self.wfile.write(b'No authentication')
|
||||||
|
logging.warning('TCP-%s-No authentication' %
|
||||||
|
self.client_address[0])
|
||||||
return None
|
return None
|
||||||
|
|
||||||
global clean_timer
|
global clean_timer
|
||||||
now = round(time.time() * 1000)
|
now = round(time.time() * 1000)
|
||||||
if now - clean_timer >= Config.TIME_LIMIT:
|
if now - clean_timer >= Config.TIME_LIMIT:
|
||||||
|
logging.info('Start cleaning memory...')
|
||||||
clean_timer = now
|
clean_timer = now
|
||||||
memory_clean(now)
|
memory_clean(now)
|
||||||
|
|
||||||
@@ -186,6 +193,7 @@ def data_swap(data: list) -> str:
|
|||||||
'player_index': 0,
|
'player_index': 0,
|
||||||
'player_id': player_id}
|
'player_id': player_id}
|
||||||
|
|
||||||
|
logging.info('TCP-Create room `%s` by player `%s`' % (room_code, name))
|
||||||
return '|'.join([str(x) for x in (0, room_code, room_id, token, base64.b64encode(key).decode('utf-8'), player_id)])
|
return '|'.join([str(x) for x in (0, room_code, room_id, token, base64.b64encode(key).decode('utf-8'), player_id)])
|
||||||
|
|
||||||
elif data[0] == '2':
|
elif data[0] == '2':
|
||||||
@@ -230,6 +238,7 @@ def data_swap(data: list) -> str:
|
|||||||
'player_index': player_index,
|
'player_index': player_index,
|
||||||
'player_id': player_id}
|
'player_id': player_id}
|
||||||
|
|
||||||
|
logging.info('TCP-Player `%s` joins room `%s`' % (name, room_code))
|
||||||
return '|'.join([str(x) for x in (0, room_code, room.room_id, token, base64.b64encode(key).decode('utf-8'), player_id, base64.b64encode(room.song_unlock).decode('utf-8'))])
|
return '|'.join([str(x) for x in (0, room_code, room.room_id, token, base64.b64encode(key).decode('utf-8'), player_id, base64.b64encode(room.song_unlock).decode('utf-8'))])
|
||||||
|
|
||||||
elif data[0] == '3':
|
elif data[0] == '3':
|
||||||
@@ -238,6 +247,7 @@ def data_swap(data: list) -> str:
|
|||||||
token = int(data[1])
|
token = int(data[1])
|
||||||
if token in link_play_data:
|
if token in link_play_data:
|
||||||
r = link_play_data[token]
|
r = link_play_data[token]
|
||||||
|
logging.info('TCP-Room `%s` info update' % room_code)
|
||||||
return '|'.join([str(x) for x in (0, r['room'].room_code, r['room'].room_id, base64.b64encode(r['key']).decode('utf-8'), r['room'].players[r['player_index']].player_id, base64.b64encode(r['room'].song_unlock).decode('utf-8'))])
|
return '|'.join([str(x) for x in (0, r['room'].room_code, r['room'].room_id, base64.b64encode(r['key']).decode('utf-8'), r['room'].players[r['player_index']].player_id, base64.b64encode(r['room'].song_unlock).decode('utf-8'))])
|
||||||
else:
|
else:
|
||||||
return '108'
|
return '108'
|
||||||
|
|||||||
@@ -230,6 +230,9 @@ class CommandParser:
|
|||||||
self.room.countdown = Config.COUNTDOWM_TIME
|
self.room.countdown = Config.COUNTDOWM_TIME
|
||||||
self.room.timestamp = round(time.time() * 1000)
|
self.room.timestamp = round(time.time() * 1000)
|
||||||
self.room.state = 4
|
self.room.state = 4
|
||||||
|
if self.room.round_switch == 1:
|
||||||
|
# 将换房主时间提前到此刻
|
||||||
|
self.room.make_round()
|
||||||
|
|
||||||
if self.room.state == 4 or self.room.state == 5 or self.room.state == 6:
|
if self.room.state == 4 or self.room.state == 5 or self.room.state == 6:
|
||||||
timestamp = round(time.time() * 1000)
|
timestamp = round(time.time() * 1000)
|
||||||
@@ -279,8 +282,6 @@ class CommandParser:
|
|||||||
flag_13 = True
|
flag_13 = True
|
||||||
self.room.state = 1
|
self.room.state = 1
|
||||||
self.room.song_idx = 0xffff
|
self.room.song_idx = 0xffff
|
||||||
if self.room.round_switch == 1:
|
|
||||||
self.room.make_round()
|
|
||||||
|
|
||||||
for i in self.room.players:
|
for i in self.room.players:
|
||||||
i.timer = 0
|
i.timer = 0
|
||||||
|
|||||||
@@ -142,15 +142,15 @@ def main():
|
|||||||
except:
|
except:
|
||||||
app.logger.warning('Initialization error!')
|
app.logger.warning('Initialization error!')
|
||||||
|
|
||||||
if Config.LINK_PLAY_HOST and Config.SET_LINK_PLAY_SERVER_AS_SUB_PROCESS:
|
if Config.LINKPLAY_HOST and Config.SET_LINKPLAY_SERVER_AS_SUB_PROCESS:
|
||||||
from linkplay_server import link_play
|
from linkplay_server import link_play
|
||||||
process = [Process(target=link_play, args=(
|
process = [Process(target=link_play, args=(
|
||||||
Config.LINK_PLAY_HOST, int(Config.LINK_PLAY_UDP_PORT), int(Config.LINK_PLAY_TCP_PORT)))]
|
Config.LINKPLAY_HOST, int(Config.LINKPLAY_UDP_PORT), int(Config.LINKPLAY_TCP_PORT)))]
|
||||||
[p.start() for p in process]
|
[p.start() for p in process]
|
||||||
app.logger.info("Link Play UDP server is running on " +
|
app.logger.info("Link Play UDP server is running on " +
|
||||||
Config.LINK_PLAY_HOST + ':' + str(Config.LINK_PLAY_UDP_PORT) + " ...")
|
Config.LINKPLAY_HOST + ':' + str(Config.LINKPLAY_UDP_PORT) + " ...")
|
||||||
app.logger.info("Link Play TCP server is running on " +
|
app.logger.info("Link Play TCP server is running on " +
|
||||||
Config.LINK_PLAY_HOST + ':' + str(Config.LINK_PLAY_TCP_PORT) + " ...")
|
Config.LINKPLAY_HOST + ':' + str(Config.LINKPLAY_TCP_PORT) + " ...")
|
||||||
tcp_server_run()
|
tcp_server_run()
|
||||||
[p.join() for p in process]
|
[p.join() for p in process]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
flask>=2.0.2
|
flask>=2.0.2
|
||||||
cryptography
|
cryptography>=35.0.0
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ bp = Blueprint('multiplayer', __name__, url_prefix='/multiplayer')
|
|||||||
@auth_required(request)
|
@auth_required(request)
|
||||||
@arc_try
|
@arc_try
|
||||||
def room_create(user_id):
|
def room_create(user_id):
|
||||||
if not Config.LINK_PLAY_HOST:
|
if not Config.LINKPLAY_HOST:
|
||||||
raise ArcError('The link play server is unavailable.', 151, status=404)
|
raise ArcError('The link play server is unavailable.', 151, status=404)
|
||||||
|
|
||||||
with Connect() as c:
|
with Connect() as c:
|
||||||
@@ -24,8 +24,8 @@ def room_create(user_id):
|
|||||||
x.create_room(user)
|
x.create_room(user)
|
||||||
r = x.to_dict()
|
r = x.to_dict()
|
||||||
r['endPoint'] = request.host.split(
|
r['endPoint'] = request.host.split(
|
||||||
':')[0] if Config.LINK_PLAY_DISPLAY_HOST == '' else Config.LINK_PLAY_DISPLAY_HOST
|
':')[0] if Config.LINKPLAY_DISPLAY_HOST == '' else Config.LINKPLAY_DISPLAY_HOST
|
||||||
r['port'] = int(Config.LINK_PLAY_UDP_PORT)
|
r['port'] = int(Config.LINKPLAY_UDP_PORT)
|
||||||
return success_return(r)
|
return success_return(r)
|
||||||
|
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ def room_create(user_id):
|
|||||||
@auth_required(request)
|
@auth_required(request)
|
||||||
@arc_try
|
@arc_try
|
||||||
def room_join(user_id, room_code):
|
def room_join(user_id, room_code):
|
||||||
if not Config.LINK_PLAY_HOST:
|
if not Config.LINKPLAY_HOST:
|
||||||
raise ArcError('The link play server is unavailable.', 151, status=404)
|
raise ArcError('The link play server is unavailable.', 151, status=404)
|
||||||
|
|
||||||
with Connect() as c:
|
with Connect() as c:
|
||||||
@@ -45,8 +45,8 @@ def room_join(user_id, room_code):
|
|||||||
x.join_room(room, user)
|
x.join_room(room, user)
|
||||||
r = x.to_dict()
|
r = x.to_dict()
|
||||||
r['endPoint'] = request.host.split(
|
r['endPoint'] = request.host.split(
|
||||||
':')[0] if Config.LINK_PLAY_DISPLAY_HOST == '' else Config.LINK_PLAY_DISPLAY_HOST
|
':')[0] if Config.LINKPLAY_DISPLAY_HOST == '' else Config.LINKPLAY_DISPLAY_HOST
|
||||||
r['port'] = int(Config.LINK_PLAY_UDP_PORT)
|
r['port'] = int(Config.LINKPLAY_UDP_PORT)
|
||||||
return success_return(r)
|
return success_return(r)
|
||||||
|
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ def room_join(user_id, room_code):
|
|||||||
@auth_required(request)
|
@auth_required(request)
|
||||||
@arc_try
|
@arc_try
|
||||||
def multiplayer_update(user_id):
|
def multiplayer_update(user_id):
|
||||||
if not Config.LINK_PLAY_HOST:
|
if not Config.LINKPLAY_HOST:
|
||||||
raise ArcError('The link play server is unavailable.', 151, status=404)
|
raise ArcError('The link play server is unavailable.', 151, status=404)
|
||||||
|
|
||||||
with Connect() as c:
|
with Connect() as c:
|
||||||
@@ -64,6 +64,6 @@ def multiplayer_update(user_id):
|
|||||||
x.update_room(user)
|
x.update_room(user)
|
||||||
r = x.to_dict()
|
r = x.to_dict()
|
||||||
r['endPoint'] = request.host.split(
|
r['endPoint'] = request.host.split(
|
||||||
':')[0] if Config.LINK_PLAY_DISPLAY_HOST == '' else Config.LINK_PLAY_DISPLAY_HOST
|
':')[0] if Config.LINKPLAY_DISPLAY_HOST == '' else Config.LINKPLAY_DISPLAY_HOST
|
||||||
r['port'] = int(Config.LINK_PLAY_UDP_PORT)
|
r['port'] = int(Config.LINKPLAY_UDP_PORT)
|
||||||
return success_return(r)
|
return success_return(r)
|
||||||
|
|||||||
@@ -42,15 +42,18 @@ class Config():
|
|||||||
Setting of your link play server
|
Setting of your link play server
|
||||||
Please ensure that the settings on the side of Link Play server are consistent.
|
Please ensure that the settings on the side of Link Play server are consistent.
|
||||||
'''
|
'''
|
||||||
# SET_LINK_PLAY_SERVER_AS_SUB_PROCESS: If it is `True`, the link play server will run with the main server locally at the same time.
|
# SET_LINKPLAY_SERVER_AS_SUB_PROCESS: 是否同时在本地启动Link Play服务器
|
||||||
SET_LINK_PLAY_SERVER_AS_SUB_PROCESS = True
|
# SET_LINKPLAY_SERVER_AS_SUB_PROCESS: If it is `True`, the link play server will run with the main server locally at the same time.
|
||||||
# LINK_PLAY_HOST: If it is blank, the link play feature will be disabled.
|
SET_LINKPLAY_SERVER_AS_SUB_PROCESS = True
|
||||||
LINK_PLAY_HOST = '0.0.0.0'
|
# LINKPLAY_HOST: 对主服务器来说的Link Play服务器的地址
|
||||||
LINK_PLAY_UDP_PORT = 10900
|
# LINKPLAY_HOST: The address of the linkplay server based on the main server. If it is blank, the link play feature will be disabled.
|
||||||
LINK_PLAY_TCP_PORT = 10901
|
LINKPLAY_HOST = '0.0.0.0'
|
||||||
LINK_PLAY_AUTHENTICATION = 'my_link_play_server'
|
LINKPLAY_UDP_PORT = 10900
|
||||||
# LINK_PLAY_DISPLAY_HOST: If it is blank, the host of link play server for the client will be obtained automatically.
|
LINKPLAY_TCP_PORT = 10901
|
||||||
LINK_PLAY_DISPLAY_HOST = ''
|
LINKPLAY_AUTHENTICATION = 'my_link_play_server'
|
||||||
|
# LINKPLAY_DISPLAY_HOST: 对客户端来说的Link Play服务器地址,如果为空,则自动获取
|
||||||
|
# LINKPLAY_DISPLAY_HOST: The address of the linkplay server based on the client. If it is blank, the host of link play server for the client will be obtained automatically.
|
||||||
|
LINKPLAY_DISPLAY_HOST = ''
|
||||||
'''
|
'''
|
||||||
--------------------
|
--------------------
|
||||||
'''
|
'''
|
||||||
|
|||||||
Reference in New Issue
Block a user