def request_hexinfo(_cls, _self, _data): """ヘックスの情報を取得""" payload = {"event": "response_hexinfo", "data": {}} data = {"hex_info": {}} # 取得しているプレイヤーの情報 self_id = _self.get_secure_cookie("user_id").decode('utf-8') self_info = get_playerinfo_by_id(self_id) # ヘックスの情報 hex_info = get_hexinfo(_data["col"], _data["row"]) if hex_info == None: logging.error("failed to retrieve hex_info : " + str(data["col"]) + " , " + str(data["row"])) _cls.send_error(_self, "エラーでキャンセルされた") data["hex_info"]["type"] = hex_info["type"] if hex_info[self_info["visibility"]] > 0: # 可視範囲ならより詳細な情報取得 data["hex_info"]["food"] = hex_info["food"] data["hex_info"]["money"] = hex_info["money"] # 在中プレイヤーの情報 other_player = get_players_by_visibility(self_info["visibility"], True, [{ "col": _data["col"], "row": _data["row"] }]) if len(other_player) != 0: # プレイヤー情報 data["player_info"] = {} other_player = other_player[0] data["player_info"]["player_name"] = other_player["user_name"] country_id = other_player["country_id"] country_info = get_countryinfo_by_id(other_player["country_id"]) data["player_info"]["country_name"] = country_info["country_name"] # 部隊情報 division_info = get_division_info_by_colrow(_data["col"], _data["row"]) if division_info: branch_info = get_branch_info(division_info["branch_id"]) data["division_info"] = {} data["division_info"]["division_name"] = division_info["division_name"] data["division_info"]["status"] = division_info["status"] data["division_info"]["level"] = division_info["level"] data["division_info"]["quantity"] = division_info["quantity"] data["division_info"]["branch_name"] = branch_info["branch_name"] payload["data"] = data _self.send_you(payload)
def open(self): #TODO: トークン付与 user_id = self.get_secure_cookie("user_id").decode('utf-8') country = None try: player = player_controller.get_playerinfo_by_id(user_id) if player["country_id"] is None: raise DBError(u"国IDが設定されていない。") if player["visibility"] is None: raise DBError(u"可視権が設定されていない") except DBError as e: self.on_error(u"国が特定できなかった。" + e.message) BJSocketHandler.members[user_id] = { "socket": self, "country_id": player["country_id"], "visibility": player["visibility"] } logging.debug(user_id + " connected")
def run(self): """ 内政をする :return: 成功 ? True : False """ self._logger.debug("enter EventDomestic run") self._logger.debug("event_record=", self._event_record) # 例外処理用 user_id = None division_id = None try: # デコード if self._decode_recode() is False: raise Exception("デコード失敗") return False # プレイヤー、部隊情報 player_info = player_controller.get_playerinfo_by_id(self._user_id) division_info = division_controller.get_division_info( self._division_id) # 内政中でないならキャンセル(本来はイベントレコード自体がキャンセルされるべき if player_info["status"] != "domestic": raise Exception("プレイヤーの状態がdomesticではない") return # 移動中でないならキャンセル(本来はイベントレコード自体がキャンセルされるべき) if division_info["status"] != "domestic": raise Exception("部隊の状態がdomesticではない") return # エラーに備えて本処理前にプレイヤーと部隊の状態を初期化する player_controller.update_user_status(self._user_id, "ready") division_controller.update_division_status(self._division_id, "ready") # 現在時刻 now = BJTime.get_time_now() # ヘックス情報 hex = hexgrid_controller.get_hexinfo(self._domestic_col, self._domestic_row) # 対象ヘックスの国籍が変わっていれば失敗 if hex["country_id"] != player_info["country_id"]: BJSocketHandler.BJSocketHandler.send_member_by_id( player_info["user_id"], { "event": "cancel", "data": { "title": "内政キャンセル", "reason": "対象ヘックスの国籍が違う" } }) return # 内政実行 # TODO : ステータスなどに合わせた変化 gm = GameMain.GameMain() message = "(" + str(self._domestic_col) + "," + str( self._domestic_row) + ")\n " # 結果メッセージ isSuccessed = False # 最大値増量 if self._type == "foster_food": new_food = gm.get_affair().get_op_food_lv() + hex["food"] if not hexgrid_controller.update_hex( hex["col"], hex["row"], food=new_food): message = message + "エラー。農業生産失敗" else: message = message + "農業生産 " + str( hex["food"]) + " → " + str(new_food) isSuccessed = True elif self._type == "foster_money": new_money = gm.get_affair().get_op_food_lv() + hex["money"] if not hexgrid_controller.update_hex( hex["col"], hex["row"], money=new_money): message = message + "エラー。商業生産失敗" else: message = message + "商業生産 " + str( hex["money"]) + " → " + str(new_money) isSuccessed = True # 徴税 elif self._type == "get_food": new_food = hex["food"] + division_info["food"] if not division_controller.update_division( division_info["division_id"], food=new_food): message = message + "エラー。農業徴税失敗" else: message = message + "領地から" + str( hex["food"]) + "の食糧を部隊に徴税した" isSuccessed = True elif self._type == "get_money": new_money = hex["money"] + division_info["money"] if not division_controller.update_division( division_info["division_id"], money=new_money): message = message + "エラー。商業徴税失敗" else: message = message + "領地から" + str( hex["money"]) + "の資金を部隊に徴税した" isSuccessed = True # 内政に失敗していればメッセージ送信 if not isSuccessed: BJSocketHandler.BJSocketHandler.send_member_by_id( player_info["user_id"], { "event": "cancel", "data": { "title": "内政失敗", "reason": "不明な内政種類" } }) return # 内政に成功。結果をプレイヤーに通知 BJSocketHandler.BJSocketHandler.send_member_by_id( player_info["user_id"], { "event": "notify", "data": { "title": "内政成功", "message": message } }) except DBError as e: logging.error("EventMove::run: caught DBError: " + e.message) except Exception as e: # 状態を初期化しておく player_controller.update_user_status(user_id, "ready") division_controller.update_division_status(division_id, "ready") logging.error(e) # プレイヤーにエラーを通知 payload = { "event": "cancel", "data": { "title": "内政キャンセル", "reason": "内部エラー" } } BJSocketHandler.BJSocketHandler.send_member_by_id( self._user_id, payload)
def run(self): """ プレイヤーを移動させる 終了後はmove_playerイベントを送信する :return: 成功 ? True : False """ self._logger.debug("enter run") self._logger.debug("event_record=", self._event_record) # 例外処理用 user_id = None division_id = None try: # デコード if self._decode_recode() is False: raise Exception("デコード失敗") return False # プレイヤー情報 player = player_controller.get_playerinfo_by_id(self._user_id) user_id = player["user_id"] moving_player_info = { "user_id": player["user_id"], "country_id": player["country_id"], "ex_col": player["col"], "ex_row": player["row"], "new_col": self._dest_col, "new_row": self._dest_row, "icon": player["icon_id"] } # 移動中でないならキャンセル(本来はイベントレコード自体がキャンセルされるべき if player["status"] != "moving": raise Exception("プレイヤーの状態がmovingではない") return # 部隊情報 division = division_controller.get_division_info( player["division_id"]) # 移動中でないならキャンセル(本来はイベントレコード自体がキャンセルされるべき) if division["status"] != "moving": raise Exception("部隊の状態がmovingではない") return # エラーに備えて本処理前にプレイヤーと部隊の状態を初期化する player_controller.update_user_status(self._user_id, "ready") division_controller.update_division_status(self._division_id, "ready") # 現在時刻 now = BJTime.get_time_now() """ 移動先に既に他の部隊がいる場合 """ division_dest = division_controller.get_division_info_by_colrow( self._dest_col, self._dest_row) if division_dest: # 味方なら移動キャンセルイベント if division_dest["country_id"] == player["country_id"]: data = { "event": "cancel", "data": { "reason": "移動先に味方の部隊がいるため、移動はキャンセルされた" } } BJSocketHandler.BJSocketHandler.send_member_by_id( player["user_id"], data) return # 敵なら戦闘開始 if division_dest["country_id"] != player["country_id"]: return """ 移動 """ # 移動前の可視領域減算 if not hexgrid_controller.update_visible_area( visibility=player["visibility"], division_id=division["division_id"], switch=False): raise Exception("可視領域減算に失敗") # 移動(部隊) if not division_controller.move_division( self._division_id, self._dest_col, self._dest_row): self._logger.error("部隊の移動に失敗") raise Exception("部隊の移動に失敗") # 移動(プレイヤー) if not player_controller.move_user(self._user_id, self._dest_col, self._dest_row): self._logger.error("プレイヤーの移動に失敗") raise Exception("プレイヤーの移動に失敗") # 移動後のヘックスを国の支配下に if not hexgrid_controller.update_hex( self._dest_col, self._dest_row, country_id=player["country_id"]): self._logging.error("移動後の支配に失敗") raise Exception("移動後の支配に失敗") # 移動後の可視領域可算 if not hexgrid_controller.update_visible_area( visibility=player["visibility"], division_id=division["division_id"], switch=True): self._logging.error("移動後の可視領域可算に失敗") raise Exception("移動後の可視領域可算に失敗") # 可視範囲を共有する通信中のプレイヤー(移動するプレイヤーも含む)にプレイヤーの移動を通知 notify_move_player(moving_player_info, player["visibility"], now) except DBError as e: logging.error("EventMove::run: caught DBError: " + e.message) except Exception as e: # 状態を初期化しておく player_controller.update_user_status(user_id, "ready") division_controller.update_division_status(division_id, "ready") logging.error(e) # プレイヤーにエラーを通知 payload = {"event": "error", "data": {"message": "進軍はキャンセルされた"}} BJSocketHandler.send_member_by_id(self._user_id, payload)
def request_domestic(_cls, _self, data): """ 内政要求 """ payload = {"event": "response_ask_domestic", "data": {}} player_info = player_controller.get_playerinfo_by_id( _self.get_secure_cookie("user_id").decode('utf-8')) col = data["col"] row = data["row"] # プレイヤーは行動可能か if not player_info["status"] == "ready": _cls.send_member_by_id(player_info["user_id"], { "event": "cancel", "data": { "title": "内政キャンセル", "reason": "行動中" } }) return # 内政可能な半径か adjacent_area = hexgrid_controller.get_adjacent_area( player_info["col"], player_info["row"]) if not (col == player_info["col"] and row == player_info["row"]) and not ({ "col": col, "row": row } in adjacent_area): _cls.send_member_by_id( player_info["user_id"], { "event": "cancel", "data": { "title": "内政キャンセル", "reason": "内政可能な半径ではない" } }) return # 現在のヘックスの状態 target_hex = hexgrid_controller.get_hexinfo(col, row) if target_hex == None: _cls.send_member_by_id( player_info["user_id"], { "event": "cancel", "data": { "title": "内政キャンセル", "reason": "存在しないヘックス。" } }) # イベント登録 # TODO : プレイヤーのステータスなどによる処理 gm = GameMain() finish_time = BJTime.add_time(BJTime.get_time_now(), gm.get_affair().get_op_domestic_speed()) event = EventDomestic.create_recode(user_id=player_info["user_id"], division_id=player_info["division_id"], col=col, row=row, type=data["type"], datetime=finish_time) add_event(event) # プレイヤーと部隊の状態を変更 division_controller.update_division_status(player_info["division_id"], "domestic") player_controller.update_user_status(player_info["user_id"], "domestic") # メインエンジンにイベントの実行時を通知 gm = GameMain() gm.set_event_timestamp(finish_time)
def ask_domestic(_cls, _self, data): """内政可能なヘックスの問い合わせに対する応答""" payload = {"event": "response_ask_domestic", "data": {}} player_info = player_controller.get_playerinfo_by_id( _self.get_secure_cookie("user_id").decode('utf-8')) col = data["col"] row = data["row"] # 内政可能な半径か adjacent_area = hexgrid_controller.get_adjacent_area( player_info["col"], player_info["row"]) if not (col == player_info["col"] and row == player_info["row"]) and not ({ "col": col, "row": row } in adjacent_area): _cls.send_member_by_id( player_info["user_id"], { "event": "cancel", "data": { "title": "内政キャンセル", "reason": "内政可能な半径ではない" } }) return # 現在のヘックスの状態 target_hex = hexgrid_controller.get_hexinfo(col, row) if target_hex is None: _cls.send_member_by_id(player_info["user_id"], { "event": "cancel", "data": { "title": "内政キャンセル", "reason": "存在しないヘックス" } }) return # 自国のヘックスか if not target_hex["country_id"] == player_info["country_id"]: _cls.send_member_by_id( player_info["user_id"], { "event": "cancel", "data": { "title": "内政キャンセル", "reason": "自国のヘックスではない" } }) return # TODO : プレイヤーのステータスなどによる処理 # 内政後の予想結果と gm = GameMain() food_result = target_hex["food"] + gm.get_affair().get_op_food_lv() money_result = target_hex["money"] + gm.get_affair().get_op_money_lv() required_time = gm.get_affair().get_op_domestic_speed() data = { "response": True, "food_result": int(food_result), "money_result": int(money_result), "required_time": int(required_time) } payload["data"] = data _cls.send_member_by_id(player_info["user_id"], payload)
def ask_move(_cls, _self, data): """進軍可能な進路を問い合わせに対する応答""" payload = {"event" : "response_ask_move", "data" : {}} try: db = DBSingleton() user_id = _self.get_secure_cookie("user_id").decode('utf-8') # プレイヤーの状態 player = get_playerinfo_by_id(user_id) # プレイヤーが待機中でないと移動できない if player["status"] != "ready": payload["data"] = {"response" : "deny", "reason" : "行動中"} _self.send_you(payload) return True # 配下の師団がセットされていないと移動できない if not player["division_id"]: payload["data"] = {"response" : "deny", "reason" : "配下の部隊がセットされていない"} _self.send_you(payload) return True # 配下の師団取得 division = get_division_info(player["division_id"]) # 師団の兵科情報取得 branch_info = get_branch_info(division["branch_id"]) # 師団がヘックスに移動可能かどうか ajacent_area = get_adjacent_area(division["col"], division["row"]) isMovable = False for ajacent_hex in ajacent_area: if ajacent_hex["col"] == data["col"] and ajacent_hex["row"] == data["row"]: isMovable = True break if not isMovable: payload["data"] = {"response" : "deny", "reason" : "移動可能半径ではない"} _self.send_you(payload) return True # ゲームレベルから設定値を取得 gm = GameMain() op_food_lv = gm.get_affair().get_op_food_lv() op_money_lv = gm.get_affair().get_op_money_lv() op_speed_lv = gm.get_affair().get_op_speed_lv() # 運用に必要な食糧と金 : 師団規模 * 兵科固定値 * ゲームレベル food_needed = division["quantity"] * branch_info["op_food"] * op_food_lv money_needed = division["quantity"] * branch_info["op_money"] * op_money_lv # 資金と食糧、それぞれ足りなければ移動不可 if division["food"] < food_needed: payload["data"] = {"response" : "deny", "reason" : ("部隊の運用食糧が足りない", "部隊の保持食糧 : " + str(division["food"]) , "必要な食糧 = 師団規模(" + str(division["quantity"]), ")×兵科補正(" + str(branch_info["op_food"]) , ")×情勢補正(" + str(op_food_lv) + ") = " + str(food_needed))} _self.send_you(payload) return True elif division["money"] < money_needed: payload["data"] = {"response" : "deny", "reason" : ("部隊の運用資金が足りない", "部隊の保持資金 : " + str(division["money"]), "必要な資金 = 師団規模(" + str(division["quantity"]), ")×兵科補正(" + str(branch_info["op_money"]), ")×情勢補正(" + str(op_money_lv) + ") = " + str(money_needed))} _self.send_you(payload) return True # ヘックス情報 hex_info = get_hexinfo(data["col"], data["row"]) # 地形情報 terrian_info = get_terrian_info(hex_info["type"]) # 所要時間 = 地形補正 * 兵科速度 * ゲーム速度 required_time = terrian_info[division["branch_id"]] * branch_info["speed"] * op_speed_lv payload["data"]["response"] = "accept" payload["data"]["food"] = food_needed payload["data"]["money"] = money_needed payload["data"]["required_time"] = int(required_time) _self.send_you(payload) return True except DBError as e: logging.error("move_query失敗" + e.message) _self.send_error("サーバーエラー : 進軍可能な範囲の問い合わせに失敗。行動はキャンセルされた") return False except Exception as e: logging.error(e) payload["data"] = {"response" : "deny", "reason" : "サーバーエラー"} _self.send_error("サーバーエラー : ハンドルされていないエラー。行動はキャンセルされた") return False assert False
def request_move(_cls, _self, data): """ 行軍イベントをセットする :param _cls: BJSocketHandlerのクラス :param _self: BJSocketHandlerのインスタンス :param data: クライアントから受信したデータ :return: """ user_id = _self.get_secure_cookie("user_id").decode('utf-8') payload = {"event" : "response_request_move" , "data" : {}} try: """ move_queryの焼き増しな部分があるが、queryとrequestの時間差または不正防止のため 再度移動可能かどうか調べる """ # 目的地 dest_col = data["col"] dest_row = data["row"] # プレイヤーの状態 user_id = _self.get_secure_cookie("user_id").decode('utf-8') player = get_playerinfo_by_id(user_id) # プレイヤーが待機中でないと移動できない if player["status"] != "ready": payload["data"] = {"response" : "deny", "reason" : "行動中"} _self.send_you(payload) return # 配下の部隊の状態 division = get_division_info(player["division_id"]) # 部隊がセットされていないと移動できない if not division: payload["data"] = {"response" : "deny", "reason" : "配下の師団がセットされていない"} _self.send_you(payload) # 部隊の移動半径内でないと移動できない movable_area = get_movable_area_by_division_id(division["division_id"], player["col"], player["row"]) required_time = False # 所要時間 for hex in movable_area: if hex["col"] == dest_col and hex["row"] == dest_row: required_time = hex["time"] if not required_time: payload["data"] = {"response" : "deny", "reason" : "[" + str(dest_col) + "," + str(dest_row) + "]は移動可能半径外"} _cls.send_player(user_id, payload) # 師団の兵科情報取得 branch_info = get_branch_info(division["branch_id"]) # ゲームレベルから設定値を取得 gm = GameMain() op_food_lv = gm.get_affair().get_op_food_lv() op_money_lv = gm.get_affair().get_op_money_lv() op_speed_lv = gm.get_affair().get_op_speed_lv() # 運用に必要な食糧と金 : 師団規模 * 兵科固定値 * ゲームレベル food_needed = division["quantity"] * branch_info["op_food"] * op_food_lv money_needed = division["quantity"] * branch_info["op_money"] * op_money_lv # 資金と食糧、それぞれ足りなければ移動不可 if division["food"] < food_needed: payload["data"] = {"response" : "deny", "reason" : "部隊の運用食糧が足りない。<br>" + "部隊の保持食糧 : " + str(division["food"]) + "<br>" + "必要な食糧 = 師団規模(" + division["quantity"] + ")×兵科補正(" + str(branch_info["op_food"]) + ")×情勢補正(" + str(op_food_lv) + ") = " + str(food_needed)} _self.send_you(payload) return False elif division["money"] < money_needed: payload["data"] = {"response" : "deny", "reason" : "部隊の運用資金が足りない。<br>" + "部隊の保持資金 : " + str(division["money"]) + "<br>" + "必要な資金 = 師団規模(" + division["quantity"] + ")×兵科補正(" + str(branch_info["op_money"]) + ")×情勢補正(" + str(op_money_lv) + ") = " + str(money_needed)} _self.send_you(payload) return False """ チェックが終わったのでプレイヤー情報等を更新し、行軍イベントをセットする """ # 到着予定時刻計算 required_time = required_time * op_speed_lv # ゲームレベル適用 current_time = BJTime.get_time_now() arrival_time = BJTime.add_time(current_time, required_time) # TODO: チェックと次の処理の間に状態が変更される可能性がある # 行軍のイベントレコードを作成 event_record = EventMove.create_recode(user_id=player["user_id"], division_id=division["division_id"], dest_col=dest_col, dest_row=dest_row, datetime=arrival_time) # レコードの作成に失敗していれば失敗 if event_record is None: payload["data"] = {"response" : "deny", "reason" : "イベントレコードの作成に失敗した。管理者に連絡して下さい。"} _self.send_you(payload) return # レコードをDBに登録 add_event(event_record) # メインエンジンにイベントの実行時を通知 gm = GameMain() gm.set_event_timestamp(arrival_time) # プレイヤーの状態を更新 update_user_before_move(user_id=player["user_id"], wait_untill=arrival_time) update_user_status(player["user_id"],"moving") # 部隊の状態を更新 update_division_before_move(division_id=division["division_id"], food=food_needed, money=money_needed) update_division_status(division["division_id"], "moving") # クライアントに通知 payload["data"] = { "response" : "approval", "arrival_time" : arrival_time.strftime("%Y-%m-%d %H:%M:%S")} _self.send_you(payload) return except Exception as e: logging.error(e) _self.send_error(e.message); return assert False