def handle (self): character_id = State.clients_sockets[self.websocket] is_master = models.SessionCharacter.query.filter_by( id = character_id, game_session_id = self.game_session_id.data, user_role = "master", ).count() if not is_master: return error_response('Forbidden') character_ids = [points_data['character_id'] for points_data in self.points.data] characters = models.SessionCharacter.query.filter(models.SessionCharacter.id.in_(character_ids)) character_by_ids = {} for character in characters: character_by_ids[character.id] = character data_to_send = [] for points_data in self.points.data: character_id = points_data['character_id'] category_id = points_data['category_id'] value = points_data['value'] character = character_by_ids[character_id] character_points = copy.copy(character.skill_points) character_points[str(category_id)] += value character.skill_points = character_points character.add() data_to_send.append((character_id, category_id, character_points[str(category_id)])) DBSession.commit() self.group_call_client_action("MasterChangedCategoryPoints", {'data_tpls': data_to_send}) return {'success': True}
def rules_perk_create (request): form_data = h.ignore_request_params_fields(request.POST) form = forms.Perk(form_data) if not form.validate(): return form.errors rules_id = form.rules_id.data if not request.user.owned_rules(rules_id): request.response.status = 403 return {'success': False} perk = models.Perk() perk.rules_id = form.rules_id.data perk.title = form.title.data perk.description = form.description.data if form.skills.data: perk_skills = perk.skills or {} for skill in form.skills.data: skill_id = skill['skill_id'] # TODO: Title? mod = skill['mod'] perk_skills[skill_id] = mod perk.skills = perk_skills perk.add() DBSession.flush() return {'success': True, 'perk_id': perk.id}
def create (request): form_data = h.update_request_params(request.matchdict) form = forms.CreateGameSession(form_data) if not form.validate(): return HTTPBadRequest() user = request.user session = models.GameSession() form.populate_obj(session) session.board_image = "" session.status = constants.GameSessionStatuses.AVAILABLE session.add() character = models.SessionCharacter() character.user_id = user.id character.user_role = constants.SessionCharacterRoles.MASTER character.name = user.nickname character.game_session = session character.token = hashlib.sha256('{0}{1}{2}'.format(user.id, time.time(), random.randint(0, 1000))).hexdigest() character.add() DBSession.flush() return HTTPFound(location = request.route_url('play', game_session_id = session.id))
def rules_class_create (request): form_data = h.ignore_request_params_fields(request.POST) form = forms.CharacterClass(form_data) if not form.validate(): return form.errors rules_id = form.rules_id.data if not request.user.owned_rules(rules_id): request.response.status = 403 return {'success': False} char_class = models.CharacterClass() char_class.rules_id = form.rules_id.data char_class.title = form.title.data char_class.skills = {} if form.skills.data: class_skills = {} for skill in form.skills.data: skill_id = skill['skill_id'] # TODO: Title? mod = skill['mod'] class_skills[skill_id] = mod char_class.skills = class_skills char_class.add() DBSession.flush() return {'success': True, 'result': char_class.as_dict()}
def joinable (request): rules_ids_sq = DBSession.query(models.GameRules.id).order_by(models.GameRules.ctime.desc()) joined_games_sq = DBSession.query(models.SessionCharacter.game_session_id).filter_by(user_id = request.user.id).subquery() rules_sessions = (DBSession.query(models.GameRules.id, models.GameRules.title, models.GameRules.max_players, func.count(models.GameSession.id).label('sessions_num')) .join(models.GameSession, models.GameSession.rules_id == models.GameRules.id) .filter(models.GameRules.id.in_(rules_ids_sq)) .filter(models.GameRules.max_players > models.GameSession.players_joined) .filter(models.GameSession.status != constants.GameSessionStatuses.CLOSED) .filter(~models.GameSession.id.in_(joined_games_sq)) .group_by(models.GameRules.id, models.GameRules.title, models.GameRules.max_players) ) pages_total = math.ceil(rules_sessions.count() / float(forms.PageForm.LIMIT)) if not pages_total: return {'rules_sessions': {}} form = forms.PageForm(request.GET, pages_total = pages_total) if not form.validate(): return HTTPFound(location = request.route_url('games.joinable')) offset = (form.page.data - 1) * form.LIMIT rules_sessions = rules_sessions.offset(offset).limit(form.LIMIT) return {'rules_sessions': rules_sessions}
def handle (self): character_id = State.clients_sockets[self.websocket] is_master = models.SessionCharacter.query.filter_by( id = character_id, game_session_id = self.game_session_id.data, user_role = "master", ).count() if not is_master: return error_response('Forbidden') obj = models.PlayObject.query.get(self.object_id.data) if not obj: return error_response('Invalid token') obj.x = self.x.data obj.y = self.y.data obj.add() DBSession.commit() # TODO: wrapper? obj.add() data = {'obj_id': obj.id, 'obj_type': constants.PlayfieldObject.NAME_TO_TYPE.inv[obj.type], 'x': obj.x, 'y': obj.y} self.group_call_client_action('MovePlayfieldObject', data) return {'success': True}
def rules_race_create (request): form_data = h.ignore_request_params_fields(request.POST) form = forms.Race(form_data) if not form.validate(): return form.errors rules_id = form.rules_id.data if not request.user.owned_rules(rules_id): request.response.status = 403 return {'success': False} race = models.Race() race.rules_id = form.rules_id.data race.title = form.title.data race.skills = {} if form.skills.data: race_skills = {} for skill in form.skills.data: skill_id = skill['skill_id'] mod = skill['mod'] race_skills[skill_id] = mod race.skills = race_skills race.add() DBSession.flush() return {'success': True, 'result': race.as_dict()}
def handle (self): master_id = State.clients_sockets[self.websocket] is_master = models.SessionCharacter.query.filter_by( id = master_id, game_session_id = self.game_session_id.data, user_role = "master", ).count() if not is_master: return error_response('Forbidden') session_characters = models.SessionCharacter.query.filter_by( game_session_id = self.game_session_id.data, user_role = "player", ) players_ids = [session_character.id for session_character in session_characters] updated_characters = [] for xp_info in self.xp.data: character_id = xp_info['character_id'] character_xp = xp_info['character_xp'] if character_id not in players_ids: # TODO: Validation error? continue character = models.SessionCharacter.query.filter_by( id = character_id, game_session_id = self.game_session_id.data, user_role = "player", ).first() if not character: continue character.gain_xp(character_xp) character.add() updated_characters.append(character) DBSession.commit() DBSession.add_all(updated_characters) character_params = {char.id: char.as_dict() for char in updated_characters} self.group_call_client_action('CharactersXpChanged', {'characters': character_params}, include_sender = True) return { 'success': True, 'request_id': self.request_id.data, }
def get_skill_by_title (self, skill_title): # TODO: avoid usage of this func by denormalization? skill = DBSession.query(Skill.id).filter_by(title = skill_title).first() if not skill: # TODO raise return skill
def rules_item_group_create (request): form = forms.ItemGroup(request.POST) if not form.validate(): return form.errors rules_id = form.rules_id.data if not request.user.owned_rules(rules_id): request.response.status = 403 return {'success': False} ig = models.ItemGroup() form.populate_obj(ig) ig.add() DBSession.flush() return {'success': True, 'result': ig.as_dict()}
def rules_skills_category_create (request): form = forms.SkillCategory(request.POST) if not form.validate(): return form.errors rules_id = form.rules_id.data if not request.user.owned_rules(rules_id): request.response.status = 403 return {'success': False} category = models.SkillCategory() form.populate_obj(category) category.add() DBSession.flush() return {'success': True, 'result': category.as_dict()}
def handle (self): character_id = State.clients_sockets[self.websocket] game_session_id = self.game_session_id.data character = models.SessionCharacter.query.filter_by(id = character_id, game_session_id = game_session_id).first() if not character or character.user_role != "player": return error_response('Forbidden') item_id = self.item_id.data session_item = models.SessionItem.query.filter_by(id = item_id, owner_id = character.id).first() if session_item: item = session_item.item if not item: return error_response('Item not found') item_group = item.item_group if not item_group.is_equippable: return error_response('Item is not wearable') group_items = models.Item.query.filter(models.Item.group_id == item_group.id) items_by_ids = {} for group_item in group_items: items_by_ids[group_item.id] = group_item slots_consumed = 0 for character_item in character.items_query: if character_item.attrs.get('is_equipped') == True and character_item.item_id in items_by_ids: it = items_by_ids[character_item.item_id] slots_consumed += it.attrs['slots_consumed'] if slots_consumed + item.attrs['slots_consumed'] > item_group.max_worn_items: return {'success': False} session_item.attrs['is_equipped'] = True session_item.attrs = session_item.attrs flag_modified(session_item, 'attrs') session_item.add() DBSession.commit() character.add() items = character.get_items() data = {'character_id': character.id, 'items': items, 'skills': character.get_skills()} self.group_call_client_action("AfterCharacterPutItemOn", data, include_sender = True) return {'success': True, 'items': items}
def handle (self): character_id = State.clients_sockets[self.websocket] game_session_id = self.game_session_id.data character = models.SessionCharacter.query.filter_by(id = character_id, game_session_id = game_session_id).first() if not character or character.user_role != "player": return error_response('Forbidden') new_skills_dict = {skill['id']: skill['value'] for skill in self.skills.data} skills = DBSession.query(models.Skill.id, models.Skill.category_id, models.Skill.formula).filter(models.Skill.id.in_(character.skills.keys())).all() skills_categories_mapper = {skill.id: skill.category_id for skill in skills} skills_with_formulas = {skill.id: True for skill in skills if skill.formula} char_skills = copy.copy(character.skills) char_skill_points = copy.copy(character.skill_points) for skill_id, val_to_add in new_skills_dict.viewitems(): if val_to_add <= 0: continue # TODO: error? if skill_id in skills_with_formulas: continue skill_id = int(skill_id) category_id = skills_categories_mapper[skill_id] cat_points = char_skill_points[str(category_id)] if cat_points < val_to_add: continue # TODO: error? char_skills[str(skill_id)] += val_to_add char_skill_points[str(category_id)] -= val_to_add character.skills = char_skills character.skill_points = char_skill_points character.add() DBSession.commit() character.add() skills = character.get_skills() data = {'character_id': character_id, 'skills': skills, 'skill_points': character.skill_points} self.group_call_client_action("AfterCharacterChangeSkills", data, include_sender = True) return {'success': True, 'skills': skills}
def handle (self): object_forms_by_type = { constants.PlayfieldObject.STR_NPC: self.NPCCase, constants.PlayfieldObject.STR_ITEM: self.ItemCase, } check_form = self.CheckType(self.params) if not check_form.validate(): return check_form.errors form = object_forms_by_type[check_form.object_type.data](self.params) if check_form.object_type.data == constants.PlayfieldObject.STR_ITEM: game_session = models.GameSession.query.filter_by(id = form.game_session_id.data).first() form.item.query = models.Item.query.filter_by(rules_id = game_session.rules_id) if not form.validate(): return form.errors character_id = State.clients_sockets[self.websocket] is_master = models.SessionCharacter.query.filter_by( id = character_id, game_session_id = form.game_session_id.data, user_role = "master", ).count() if not is_master: return error_response('Forbidden') obj = models.PlayObject.query.filter_by(id = form.id.data).first() if not obj: return error_response('Object is not found') if obj.type == constants.PlayfieldObject.ITEM: obj.attrs = {'item': form.item.data.id} obj.title = form.item.data.title elif obj.type == constants.PlayfieldObject.NPC: obj.title = form.title.data obj.add() DBSession.commit() self.group_call_client_action('ReloadPlayfield', {}) return {'success': True}
def main (global_config, **settings): """ This function returns a Pyramid WSGI application. """ sapyens.helpers.set_utc_timezone() engine = engine_from_config(settings, 'sqlalchemy.') boardless.db.init(engine, settings) config = Configurator( settings = settings, root_factory = RootFactory, session_factory = pyramid.session.SignedCookieSessionFactory( # The secret should be at least as long as the block size of the selected hash algorithm. For sha512 this would mean a 128 bit (64 character) secret. # For sha512 this would mean a 128 bit (64 character) secret secret = 'sETbVPAqkZxJTneqWpgnczyGhuwtfHNYMFZUMVwRjDiIRuSKGzdymHNBjDatQlhr', hashalg = 'sha512', cookie_name = 'boardless.session', timeout = 60 * 60 * 24 * 3, # A number of seconds of inactivity before a session times out. If None then the cookie never expires max_age = 60 * 60 * 24 * 3, # The maximum age of the cookie used for sessioning (in seconds). Default: None (browser scope). domain = settings.get('cookie_domain', '.boardless.com'), # TODO set_on_exception = True, # If True, set a session cookie even if an exception occurs while rendering a view ), authentication_policy = pyramid.authentication.SessionAuthenticationPolicy( callback = get_identifiers, debug = False ), authorization_policy = pyramid.authorization.ACLAuthorizationPolicy(), ) # Mailer config.include('pyramid_mailer') json_renderer = JSON() json_renderer.add_adapter(decimal.Decimal, h.decimal_json_encoder) config.add_renderer('json', json_renderer) config.set_request_property(h.get_user, 'user') config.add_static_view('static', 'static', cache_max_age = 3600) config.scan(boardless.views) # Recreate the pool to close left connections (e.g. after reflection) # It prevents connection sharing between later-forked server workers (e.g. gunicorn with preload_app) DBSession.remove() engine.dispose() return config.make_wsgi_app()
def rules_dices_choose (request): form = forms.AddDices(request.POST) if not form.validate(): return form.errors dices = form.dice_id.data rules_id = form.rules_id.data rules = models.GameRules.query.get(rules_id) if not rules: request.response.status = 422 return {'success': False} rules.dices = dices rules.add() DBSession.flush() return {'success': True}
def rules_character_levels (request): form = forms.CharacterLevels(request.POST) if not form.validate(): return form.errors rules_id = form.rules_id.data rules = models.GameRules.query.get(rules_id) if not rules: request.response.status = 422 return {'success': False} levels = [] for lvl, level_settings in enumerate(form.level_settings.data): if level_settings['xp'] is None: break levels.append({ 'level': lvl + 1, 'xp': level_settings['xp'], # 'perks_formula': level_settings['perks_formula'], }) for skills_category_formula in form.skills_categories_formulas.data: level = skills_category_formula['level'] if len(levels) > level: continue category_id = skills_category_formula['category_id'] formula = skills_category_formula['formula'] level_settings = levels[level - 1] level_settings.setdefault('skills_categories_formulas', {}) level_settings['skills_categories_formulas'][category_id] = formula # TODO: Could i-th element of list "levels" sets up a level differs from i-th? # For example: [{...}, {...}, {'level': 500, ...}, {...}] # The 3rd element is for 500th level rules.level_settings = levels rules.add() DBSession.flush() return {'success': True}
def rules_skill_create (request): form = forms.Skill(request.POST) form.category.choices = [(None, 'No category')] + [(category.id, category.title) for category in models.SkillCategory.query.filter_by(rules_id = form.rules_id.data)] if not form.validate(): return form.errors rules_id = form.rules_id.data if not request.user.owned_rules(rules_id): request.response.status = 403 return {'success': False} skill = models.Skill() skill.is_disabled = False # TODO: Convert skill names to IDs? skill.category_id = form.category.data form.populate_obj(skill) skill.add() DBSession.flush() return {'success': True, 'result': skill.as_dict()}
def rules_item_create (request): rules = models.GameRules.query.get(int(request.POST.get('rules_id', -1))) if not rules: request.response.status = 422 return {'success': False} form = forms.ItemCreate(request.POST) form.group_id.choices = [(ig.id, ig.title) for ig in rules.item_groups] if not form.validate(): return form.errors rules_id = form.rules_id.data if not request.user.owned_rules(rules_id): request.response.status = 403 return {'success': False} item = models.Item() item.title = form.title.data item.rules_id = form.rules_id.data item.group_id = form.group_id.data attrs = {} attrs['slots_consumed'] = form.slots_consumed.data item.attrs = attrs item.skills = {} if form.skills.data: item_skills = {} for skill in form.skills.data: skill_id = skill['skill_id'] mod = skill['mod'] item_skills[skill_id] = mod item.skills = item_skills item.add() DBSession.flush() return {'success': True, 'result': item.as_dict()}
def handle (self): character_id = State.clients_sockets[self.websocket] character = models.SessionCharacter.query.filter_by( id = character_id, game_session_id = self.game_session_id.data, user_role = "player", ).first() if not character: return error_response('Forbidden') obj = models.PlayObject.query.filter_by(id = self.obj_id.data, is_deleted = False).first() if not obj: return error_response('Object is not found') if obj.type != constants.PlayfieldObject.ITEM: return error_response('Object is not an item') item_id = int(obj.attrs.get('item', 0)) item = models.SessionItem.query.get(item_id) if not item: # TODO: Delete object if this situation is occured? return error_response('Item is not found') item.owner_id = character.id item.add() obj.is_deleted = True obj.add() DBSession.commit() obj.add() item.add() character.add() items = character.get_items() data = {'obj_id': obj.id, 'obj_type': constants.PlayfieldObject.NAME_TO_TYPE.inv[obj.type]} self.group_call_client_action('DeletePlayfieldObject', data) return {'success': True, 'items': items}
def handle (self): game_session = models.GameSession.query.get(self.game_session_id.data) if not game_session: return error_response('Invalid session ID') character_id = State.clients_sockets[self.websocket] is_master = models.SessionCharacter.query.filter_by( id = character_id, game_session_id = self.game_session_id.data, user_role = "master", ).count() if not is_master: return error_response('Forbidden') game_session.board_image = self.image.data game_session.add() DBSession.commit() self.group_call_client_action('ReloadPlayfield', {}) return {'success': True}
def handle (self): character_id = State.clients_sockets[self.websocket] game_session_id = self.game_session_id.data character = models.SessionCharacter.query.filter_by(id = character_id, game_session_id = game_session_id).first() if not character or character.user_role != "player": return error_response('Forbidden') item_id = self.item_id.data session_item = models.SessionItem.query.filter_by(id = item_id, owner_id = character.id).first() if session_item: session_item.attrs['is_equipped'] = False flag_modified(session_item, 'attrs') session_item.add() DBSession.commit() character.add() items = character.get_items() data = {'character_id': character.id, 'items': items, 'skills': character.get_skills()} self.group_call_client_action("AfterCharacterTookItemOff", data, include_sender = True) return {'success': True, 'items': items}
def websocket_app (environ, start_response): try: if environ['PATH_INFO'] == '/playground': websocket = environ['wsgi.websocket'] while True: try: data = websocket.receive() if not data: State.forget_client(websocket) break else: utils.handle_message(websocket, data) except WebSocketError: raise finally: DBSession.remove() except Exception: logger.warn("Playfield: uncaught error is occured.", exc_info = True)
def validate_skill (self, skill): if not skill.formula: return self.dynamic_keywords = [skill.title,] variable_names = self.get_formula_variable_names(skill.formula) parent_skills = DBSession.query(models.Skill).filter( models.Skill.rules_id == self.rules_id, models.Skill.title.in_(variable_names) ) for parent_skill in parent_skills: self.validate_skill(parent_skill)
def handle (self): character_id = State.clients_sockets[self.websocket] is_master = models.SessionCharacter.query.filter_by( id = character_id, game_session_id = self.game_session_id.data, user_role = "master", ).count() if not is_master: return error_response('Forbidden') obj = models.PlayObject.query.filter_by(game_session_id = self.game_session_id.data, id = self.id.data).first() if not obj: return error_response('Object is not found') obj.is_deleted = True obj.add() DBSession.commit() obj.add() data = {'obj_id': obj.id, 'obj_type': constants.PlayfieldObject.NAME_TO_TYPE.inv[obj.type]} self.group_call_client_action('DeletePlayfieldObject', data) return {'success': True}
def get_child_query_by_priority (self, child_name): CHILD_NAME_TO_MODEL_MAPPER = { 'skills_categories': SkillCategory, 'skills': Skill, 'perks': Perk, 'items': Item, 'item_groups': ItemGroup, 'races': Race, 'character_class': CharacterClass, 'dices': Dice, } _model = CHILD_NAME_TO_MODEL_MAPPER[child_name] # partition_by = rules_id ? return DBSession.query(_model, func.row_number().over(order_by = _model.priority).label('_priority')).filter_by(rules_id = self.id)
def joined (request): # TODO: Pagination session_ids_sq = DBSession.query(models.SessionCharacter.game_session_id).filter_by(user_id = request.user.id).subquery() sessions = models.GameSession.query.filter( models.GameSession.id.in_(session_ids_sq), models.GameSession.status != constants.GameSessionStatuses.CLOSED, ) characters = models.SessionCharacter.query.filter_by(user_id = request.user.id) session_roles = {} for character in characters: session_roles[character.game_session_id] = character.user_role return {'sessions': sessions, 'session_roles': session_roles}
def get_skills (self): skills_dict = {} # Base for skill_id in self.skills.keys(): base_value = self.skills[skill_id] skill_id = int(skill_id) skills_dict[skill_id] = { 'base_value': base_value, 'effective_value': self.get_skill_effective_value(skill_id), } # Add the character's race if self.race_id: race = Race.query.get(self.race_id) for skill_id, skill_val in race.skills.viewitems(): skill_id = int(skill_id) skills_dict.setdefault(skill_id, {'effective_value': 0, 'base_value': 0}) skills_dict[skill_id]['effective_value'] += skill_val # Add the character's class if self.class_id: char_class = CharacterClass.query.get(self.class_id) if char_class.skills: for skill_id, skill_val in char_class.skills.viewitems(): skill_id = int(skill_id) skills_dict.setdefault(skill_id, {'effective_value': 0, 'base_value': 0}) skills_dict[skill_id]['effective_value'] += skill_val # Worn items worn_session_items_query = self.items_query.filter(SessionItem.attrs['is_equippable'].cast(Boolean) == True).options(joinedload('item')) for session_item in worn_session_items_query: item_group_id_sq = DBSession.query(Item.group_id).filter_by(id = session_item.item_id).subquery() item_group = ItemGroup.query.filter_by(id = item_group_id_sq, is_equippable = True).first() if not item_group: continue item = session_item.item for skill_id, skill_val in item.skills.viewitems(): skill_id = int(skill_id) skills_dict.setdefault(skill_id, {'effective_value': 0, 'base_value': 0}) skills_dict[skill_id]['effective_value'] += skill_val # TODO: Used items return skills_dict
def joinable_rules (request): # TODO: Pagination joined_games_sq = DBSession.query(models.SessionCharacter.game_session_id).filter_by(user_id = request.user.id).subquery() sessions = (models.GameSession.query .join(models.GameRules, models.GameSession.rules_id == models.GameRules.id) .filter( models.GameRules.id == request.matchdict['rules_id'], models.GameSession.players_joined < models.GameRules.max_players, models.GameSession.status != constants.GameSessionStatuses.CLOSED, ~models.GameSession.id.in_(joined_games_sq), ) ) return {'sessions': sessions}
def get_role_for_session (self, game_session_id): return DBSession.query(SessionCharacter.user_role).filter(SessionCharacter.user_id == self.id, SessionCharacter.game_session_id == game_session_id).scalar()