// The account registration window (PORT; 40250 has no counterpart, its accounts were made on the web), // run by PythonBoot::RunMainScript as module mt_register. It hooks introLogin.LoginWindow.Open/Close and // puts a register button under the login board; the dialog posts to the server's registration service // (tools/40250/register_server.py) through net.RegisterAccount. Strings are UTF-8 here and go through // player.AutoHuntLocalize into the locale's code page. static const char c_szRegisterScript[] = R"PY(# -*- coding: utf-8 -*- import introLogin import net import player import ui import wndMgr L = player.AutoHuntLocalize REGISTER_PORT = 11080 LOGIN_MIN, LOGIN_MAX = 4, 16 PASSWORD_MIN, PASSWORD_MAX = 4, 16 SOCIAL_ID_LEN = 7 LARGE_BUTTON = "d:/ymir work/ui/public/large_button_%02d.sub" MIDDLE_BUTTON = "d:/ymir work/ui/public/middle_button_%02d.sub" COLOR_ERROR = 0xffff7f7f COLOR_INFO = 0xffc8c8c8 ERROR_TEXT = { "BAD_LOGIN": "账号需为4-16位英文字母或数字", "BAD_PASSWORD": "密码需为4-16位字母、数字或符号", "BAD_SOCIAL_ID": "删除码需为7位数字", "EXISTS": "该账号已存在", "RATE_LIMIT": "注册过于频繁,请稍后再试", "CONNECT": "无法连接注册服务器", "TIMEOUT": "注册服务器无响应", "SERVER": "注册服务器出错,请稍后再试", } def _IsAlnum(text): for c in text: if not (("a" <= c <= "z") or ("A" <= c <= "Z") or ("0" <= c <= "9")): return False return True def _IsPrintable(text): for c in text: if not ("!" <= c <= "~"): return False return True def _Validate(login, password, confirm, socialID): if not (LOGIN_MIN <= len(login) <= LOGIN_MAX) or not _IsAlnum(login): return ERROR_TEXT["BAD_LOGIN"] if not (PASSWORD_MIN <= len(password) <= PASSWORD_MAX) or not _IsPrintable(password): return ERROR_TEXT["BAD_PASSWORD"] if password != confirm: return "两次输入的密码不一致" if len(socialID) != SOCIAL_ID_LEN or not socialID.isdigit(): return ERROR_TEXT["BAD_SOCIAL_ID"] return None def _MakeButton(parent, x, y, image, text, event): button = ui.Button() button.SetParent(parent) button.SetPosition(x, y) button.SetUpVisual(image % 1) button.SetOverVisual(image % 2) button.SetDownVisual(image % 3) button.SetText(L(text)) button.SetEvent(event) button.Show() return button class InputRow: LABEL_X = 18 SLOT_X = 96 SLOT_WIDTH = 160 def __init__(self, parent, y, label, maxLen): self.label = ui.TextLine() self.label.SetParent(parent) self.label.SetPosition(self.LABEL_X, y + 2) self.label.SetText(L(label)) self.label.Show() self.slot = ui.SlotBar() self.slot.SetParent(parent) self.slot.SetPosition(self.SLOT_X, y) self.slot.SetSize(self.SLOT_WIDTH, 18) self.slot.Show() self.edit = ui.EditLine() self.edit.SetParent(self.slot) self.edit.SetPosition(4, 2) self.edit.SetSize(self.SLOT_WIDTH - 8, 16) self.edit.SetMax(maxLen) self.edit.SetIMEFlag(0) self.edit.Show() def GetText(self): return self.edit.GetText() def Destroy(self): self.edit.SetReturnEvent(0) self.edit.SetTabEvent(0) self.edit = None self.slot = None self.label = None class RegisterDialog(ui.BoardWithTitleBar): WIDTH = 280 HEIGHT = 222 def __init__(self, loginWindow): ui.BoardWithTitleBar.__init__(self) self.loginWindow = loginWindow self.pending = False self.pendingLogin = "" self.pendingPassword = "" self.AddFlag("movable") self.AddFlag("float") self.SetSize(self.WIDTH, self.HEIGHT) self.SetTitleName(L("注册账号")) self.SetCloseEvent(ui.__mem_func__(self.Close)) self.loginRow = InputRow(self, 38, "账号", LOGIN_MAX) self.passwordRow = InputRow(self, 66, "密码", PASSWORD_MAX) self.passwordRow.edit.SetSecret(True) self.confirmRow = InputRow(self, 94, "确认密码", PASSWORD_MAX) self.confirmRow.edit.SetSecret(True) self.socialRow = InputRow(self, 122, "删除码", SOCIAL_ID_LEN) self.socialRow.edit.SetNumberMode() rows = (self.loginRow, self.passwordRow, self.confirmRow, self.socialRow) for i in xrange(len(rows)): nextEdit = rows[(i + 1) % len(rows)].edit rows[i].edit.SetTabEvent(ui.__mem_func__(nextEdit.SetFocus)) if i + 1 < len(rows): rows[i].edit.SetReturnEvent(ui.__mem_func__(nextEdit.SetFocus)) self.socialRow.edit.SetReturnEvent(ui.__mem_func__(self.__OnClickRegister)) for row in rows: row.edit.SetEscapeEvent(ui.__mem_func__(self.Close)) self.hintLine = ui.TextLine() self.hintLine.SetParent(self) self.hintLine.SetPosition(0, 150) self.hintLine.SetWindowHorizontalAlignCenter() self.hintLine.SetHorizontalAlignCenter() self.hintLine.Show() self.registerButton = _MakeButton(self, self.WIDTH / 2 - 66, 180, MIDDLE_BUTTON, "注册", ui.__mem_func__(self.__OnClickRegister)) self.cancelButton = _MakeButton(self, self.WIDTH / 2 + 5, 180, MIDDLE_BUTTON, "取消", ui.__mem_func__(self.Close)) def Destroy(self): self.Hide() for row in (self.loginRow, self.passwordRow, self.confirmRow, self.socialRow): row.Destroy() self.loginRow = self.passwordRow = self.confirmRow = self.socialRow = None self.registerButton = None self.cancelButton = None self.hintLine = None self.loginWindow = None def Open(self): for row in (self.loginRow, self.passwordRow, self.confirmRow, self.socialRow): row.edit.SetText("") self.__SetHint("账号仅限英文字母和数字,删除码用于删除角色", COLOR_INFO) self.SetPosition((wndMgr.GetScreenWidth() - self.WIDTH) / 2, (wndMgr.GetScreenHeight() - self.HEIGHT) / 2) self.Show() self.SetTop() self.loginRow.edit.SetFocus() def Close(self): for row in (self.loginRow, self.passwordRow, self.confirmRow, self.socialRow): row.edit.KillFocus() self.Hide() if self.loginWindow and self.loginWindow.idEditLine: self.loginWindow.idEditLine.SetFocus() return True def OnPressEscapeKey(self): return self.Close() def __SetHint(self, text, color): self.hintLine.SetText(L(text)) self.hintLine.SetPackedFontColor(color) def __GetHost(self): stream = self.loginWindow.stream if stream.account_addr: return stream.account_addr return stream.addr def __OnClickRegister(self): if self.pending: return login = self.loginRow.GetText() password = self.passwordRow.GetText() error = _Validate(login, password, self.confirmRow.GetText(), self.socialRow.GetText()) if error: self.__SetHint(error, COLOR_ERROR) return host = self.__GetHost() if not host: self.__SetHint("请先选择服务器", COLOR_ERROR) return if not net.RegisterAccount(host, REGISTER_PORT, login, password, self.socialRow.GetText()): return self.pending = True self.pendingLogin = login.lower() self.pendingPassword = password self.registerButton.Disable() self.__SetHint("正在注册...", COLOR_INFO) def OnUpdate(self): if not self.pending: return result = net.GetRegisterAccountResult() if not result: return self.pending = False self.registerButton.Enable() if result == "OK": self.__OnRegistered() return code = result[4:] if result.startswith("ERR ") else "SERVER" self.__SetHint(ERROR_TEXT.get(code, ERROR_TEXT["SERVER"]), COLOR_ERROR) def __OnRegistered(self): loginWindow = self.loginWindow login, password = self.pendingLogin, self.pendingPassword self.pendingPassword = "" self.Close() if loginWindow.idEditLine: loginWindow.idEditLine.SetText(login) if loginWindow.pwdEditLine: loginWindow.pwdEditLine.SetText(password) loginWindow.PopupNotifyMessage(L("账号 %s 注册成功,请点击登录") % login) class RegisterEntry(ui.Window): "The button under the login board; it follows the board's position and visibility every frame." def __init__(self, loginWindow): ui.Window.__init__(self) self.loginWindow = loginWindow self.dialog = RegisterDialog(loginWindow) self.button = ui.Button() self.button.SetUpVisual(LARGE_BUTTON % 1) self.button.SetOverVisual(LARGE_BUTTON % 2) self.button.SetDownVisual(LARGE_BUTTON % 3) self.button.SetText(L("注册账号")) self.button.SetEvent(ui.__mem_func__(self.dialog.Open)) self.SetSize(0, 0) self.Show() def Destroy(self): self.Hide() self.button.Hide() self.button = None self.dialog.Destroy() self.dialog = None self.loginWindow = None def OnUpdate(self): board = self.loginWindow.loginBoard if self.loginWindow else None if not board or not self.loginWindow.IsShow() or not board.IsShow() or self.dialog.IsShow(): if self.button.IsShow(): self.button.Hide() return x, y = board.GetGlobalPosition() self.button.SetPosition(x + (board.GetWidth() - self.button.GetWidth()) / 2, y + board.GetHeight() + 6) if not self.button.IsShow(): self.button.Show() self.button.SetTop() _entries = {} def Attach(loginWindow): key = id(loginWindow) if key not in _entries: _entries[key] = RegisterEntry(loginWindow) def Detach(loginWindow): entry = _entries.pop(id(loginWindow), None) if entry: entry.Destroy() def __Install(): openLogin = introLogin.LoginWindow.Open closeLogin = introLogin.LoginWindow.Close def Open(self): result = openLogin(self) try: Attach(self) except: import dbg dbg.TraceError("mt_register: attach failed") return result def Close(self): Detach(self) return closeLogin(self) introLogin.LoginWindow.Open = Open introLogin.LoginWindow.Close = Close # system.py reaches app.Loop() before this runs, so a login window may already be open. import gc for obj in gc.get_objects(): if isinstance(obj, introLogin.LoginWindow) and getattr(obj, "loginBoard", None): Attach(obj) __Install() )PY";