Skip to content

Commit

Permalink
Merge branch 'master' into 4.3.0-dev (apply 4.2.3-post2 and post3 bug…
Browse files Browse the repository at this point in the history
…fixes)
  • Loading branch information
Chrezm committed Jan 15, 2020
2 parents 7a58f00 + 7ff0f44 commit 59f91de
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 35 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,13 @@

### 191231b (4.2.3-post1)
* Fixed non-numerical HDIDs not being recognized with /whois

### 200110a (4.2.3-post2)
* Fixed players in first person mode being unable to talk after a server-initiated IC message

### 200112a (4.2.3-post3)
* Aligned wording of music list loading outputs with the ones from area list loading outputs
* Fixed players/server being able to load music lists with invalid syntax. An informative error message will be returned to assist in fixing the music list

### 200112b (4.2.3-post4)
* Fixed players/server being able to load any YAML files with invalid YAML syntax. An informative error message will be returned to assist in fixing said file
2 changes: 1 addition & 1 deletion server/area_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ def load_areas(self, area_list_file='config/areas.yaml'):

# Check if valid area list file
with Constants.fopen(area_list_file, 'r') as chars:
areas = yaml.safe_load(chars)
areas = Constants.yaml_load(chars)

def_param = {
'bglock': False,
Expand Down
29 changes: 20 additions & 9 deletions server/client_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,17 +288,23 @@ def pop_if_there(dictionary, argument):

# Done modifying IC message
# Now send it
if sender != self:
self.last_ic_notme = self.area.id, pargs

# This step also takes care of filtering out the packet arguments that the client
# cannot parse, and also make sure they are in the correct oder.
# cannot parse, and also make sure they are in the correct order.
final_pargs = dict()
to_send = list()
for x in self.packet_handler.MS_OUTBOUND.value:
for (field, default_value) in self.packet_handler.MS_OUTBOUND.value:
try:
to_send.append(pargs[x[0]])
value = pargs[field]
except KeyError: # Case the key was popped (e.g. in pair code), use defaults then
to_send.append(x[1])
value = default_value
to_send.append(value)
final_pargs[field] = value

# Keep track of packet details in case this was sent by someone else
# This is used, for example, for first person mode
if sender != self:
self.last_ic_notme = self.area.id, final_pargs

self.send_command('MS', *to_send)

Expand Down Expand Up @@ -404,12 +410,10 @@ def reload_music_list(self, new_music_file=None):
reachable areas+music. Useful when moving areas/logging in or out.
"""

# Check if a new music file has been chosen, and if so, parse it and set it as the
# client's own music list.
# Check if a new music file has been chosen, and if so, parse it
if new_music_file:
raw_music_list = self.server.load_music(music_list_file=new_music_file,
server_music_list=False)
self.music_list = raw_music_list
else:
raw_music_list = None

Expand All @@ -433,6 +437,13 @@ def reload_music_list(self, new_music_file=None):
specific_music_list=raw_music_list)
self.send_command('FM', *music_list)

# Update the new music list of the client once everything is done, if a new music list
# was indeed loaded. Doing this only now prevents setting the music list to something
# broken, as build_music_list_ao2 checks for syntax and raises an error if bad syntax
# so if the code makes it here, the loaded music list is good.
if raw_music_list:
self.music_list = raw_music_list

def check_change_area(self, area, override_passages=False, override_effects=False,
more_unavail_chars=None):
checker = self.area_changer.check_change_area
Expand Down
16 changes: 11 additions & 5 deletions server/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -3162,18 +3162,24 @@ def ooc_cmd_music_list(client: ClientManager.Client, arg: str):
/music_list :: Reset the music list to its default value.
"""

if len(arg) == 0:
if not arg:
client.music_list = None
client.reload_music_list()
client.send_ooc('Restored music list to its default value.')
client.send_ooc('You have restored the original music list of the server.')
else:
try:
new_music_file = 'config/music_lists/{}.yaml'.format(arg)
client.reload_music_list(new_music_file=new_music_file)
except ServerError:
raise ArgumentError('Could not find music list file: {}'.format(arg))
except ServerError.MusicInvalidError as exc:
raise ArgumentError('The music list {} returned the following error when loading: `{}`.'
.format(new_music_file, exc))
except ServerError as exc:
if exc.code == 'FileNotFound':
raise ArgumentError('Could not find the music list file `{}`.'
.format(new_music_file))
raise # Weird exception, reraise it

client.send_ooc('Loaded music list: {}'.format(arg))
client.send_ooc('You have loaded the music list {}.'.format(arg))

def ooc_cmd_music_lists(client: ClientManager.Client, arg: str):
"""
Expand Down
14 changes: 14 additions & 0 deletions server/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import re
import time
import warnings
import yaml

from enum import Enum
from server.exceptions import ClientError, ServerError, ArgumentError, AreaError
Expand Down Expand Up @@ -164,6 +165,19 @@ def fopen(file, *args, **kwargs):
except OSError as ex:
raise ServerError(str(ex))

@staticmethod
def yaml_load(file):
try:
return yaml.safe_load(file)
except yaml.YAMLError as exc:
# Extract the name of the yaml
separator = max(file.name.rfind('\\'), file.name.rfind('/'))
file_name = file.name[separator+1:]
# Then raise the exception
msg = ('File {} returned the following YAML error when loading: `{}`.'
.format(file_name, exc))
raise ServerError.YAMLInvalidError(msg)

@staticmethod
def get_time():
return time.asctime(time.localtime(time.time()))
Expand Down
16 changes: 16 additions & 0 deletions server/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,25 @@ class ArgumentError(TsuserverException):
pass

class ServerError(TsuserverException):
class ServerFileNotFoundError(TsuserverException):
pass

class MusicNotFoundError(TsuserverException):
pass

class MusicInvalid(TsuserverException):
# Remove, kept for backwards compatibility
pass

class MusicInvalidError(TsuserverException):
pass

class YAMLNotFoundError(TsuserverException):
pass

class YAMLInvalidError(TsuserverException):
pass

class PartyError(TsuserverException):
pass

Expand Down
58 changes: 38 additions & 20 deletions server/tsuserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ def __init__(self, protocol=None, client_manager=None, in_test=False):
self.release = 4
self.major_version = 3
self.minor_version = 0
self.segment_version = 'a2'
self.internal_version = '200107a'
self.segment_version = 'a3'
self.internal_version = '200115a'
version_string = self.get_version_string()
self.software = 'TsuserverDR {}'.format(version_string)
self.version = 'TsuserverDR {} ({})'.format(version_string, self.internal_version)
Expand Down Expand Up @@ -205,13 +205,13 @@ def get_version_string(self):

def reload(self):
with Constants.fopen('config/characters.yaml', 'r') as chars:
self.char_list = yaml.safe_load(chars)
self.char_list = Constants.yaml_load(chars)
with Constants.fopen('config/music.yaml', 'r') as music:
self.music_list = yaml.safe_load(music)
self.music_list = Constants.yaml_load(music)
self.build_music_pages_ao1()
self.build_music_list_ao2()
with Constants.fopen('config/backgrounds.yaml', 'r') as bgs:
self.backgrounds = yaml.safe_load(bgs)
self.backgrounds = Constants.yaml_load(bgs)

def reload_commands(self):
try:
Expand Down Expand Up @@ -239,11 +239,11 @@ def get_player_count(self):

def load_backgrounds(self):
with Constants.fopen('config/backgrounds.yaml', 'r', encoding='utf-8') as bgs:
self.backgrounds = yaml.safe_load(bgs)
self.backgrounds = Constants.yaml_load(bgs)

def load_config(self):
with Constants.fopen('config/config.yaml', 'r', encoding='utf-8') as cfg:
self.config = yaml.safe_load(cfg)
self.config = Constants.yaml_load(cfg)
self.config['motd'] = self.config['motd'].replace('\\n', ' \n')

for i in range(1, 8):
Expand Down Expand Up @@ -302,7 +302,7 @@ def load_config(self):

def load_characters(self):
with Constants.fopen('config/characters.yaml', 'r', encoding='utf-8') as chars:
self.char_list = yaml.safe_load(chars)
self.char_list = Constants.yaml_load(chars)
self.build_char_pages_ao1()

def load_commandhelp(self):
Expand Down Expand Up @@ -403,7 +403,7 @@ def load_ids(self):
def load_iniswaps(self):
try:
with Constants.fopen('config/iniswaps.yaml', 'r', encoding='utf-8') as iniswaps:
self.allowed_iniswaps = yaml.safe_load(iniswaps)
self.allowed_iniswaps = Constants.yaml_load(iniswaps)
except Exception as ex:
message = 'WARNING: Error loading config/iniswaps.yaml. Will assume empty values.\n'
message += '{}: {}'.format(type(ex).__name__, ex)
Expand All @@ -412,7 +412,7 @@ def load_iniswaps(self):

def load_music(self, music_list_file='config/music.yaml', server_music_list=True):
with Constants.fopen(music_list_file, 'r', encoding='utf-8') as music:
music_list = yaml.safe_load(music)
music_list = Constants.yaml_load(music)

if server_music_list:
self.music_list = music_list
Expand Down Expand Up @@ -452,12 +452,22 @@ def build_music_pages_ao1(self):
self.music_pages_ao1.append('{}#{}'.format(index, area.name))
index += 1
# then add music
for item in self.music_list:
self.music_pages_ao1.append('{}#{}'.format(index, item['category']))
index += 1
for song in item['songs']:
self.music_pages_ao1.append('{}#{}'.format(index, song['name']))
try:
for item in self.music_list:
self.music_pages_ao1.append('{}#{}'.format(index, item['category']))
index += 1
for song in item['songs']:
self.music_pages_ao1.append('{}#{}'.format(index, song['name']))
index += 1
except KeyError as err:
msg = ("The music list expected key '{}' for item {}, but could not find it."
.format(err.args[0], item))
raise ServerError.MusicInvalid(msg)
except TypeError:
msg = ("The music list expected songs to be listed for item {}, but could not find any."
.format(item))
raise ServerError.MusicInvalid(msg)

self.music_pages_ao1 = [self.music_pages_ao1[x:x + 10] for x in range(0, len(self.music_pages_ao1), 10)]

def build_music_list_ao2(self, from_area=None, c=None, music_list=None, include_areas=True,
Expand Down Expand Up @@ -534,11 +544,19 @@ def prepare_music_list(self, c=None, specific_music_list=None):
specific_music_list = c.music_list

prepared_music_list = list()
for item in specific_music_list:
prepared_music_list.append(item['category'])
for song in item['songs']:
prepared_music_list.append(song['name'])

try:
for item in specific_music_list:
prepared_music_list.append(item['category'])
for song in item['songs']:
prepared_music_list.append(song['name'])
except KeyError as err:
msg = ("The music list expected key '{}' for item {}, but could not find it."
.format(err.args[0], item))
raise ServerError.MusicInvalid(msg)
except TypeError:
msg = ("The music list expected songs to be listed for item {}, but could not find any."
.format(item))
raise ServerError.MusicInvalid(msg)
return prepared_music_list

def is_valid_char_id(self, char_id):
Expand Down

0 comments on commit 59f91de

Please sign in to comment.