Skip to content

Commit ddfea6f

Browse files
committed
Added new player settings module. Full functionality is not working, and will not until we get a menu system implemented. I also intend upon updating the storage system to use sqlite3 instead of pickle.
Fixed accidental changes committed to LangStrings. Updated _core.settings and _core/core_settings_strings for the player settings implementation.
1 parent 15ab3bf commit ddfea6f

File tree

7 files changed

+565
-9
lines changed

7 files changed

+565
-9
lines changed

addons/source-python/packages/source-python/_core/settings.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,5 +179,44 @@ def _check_logging_settings(self):
179179
self['LOG_SETTINGS'].comments['areas'] = ['\n\n'] + _core_strings[
180180
'log_areas'].get_string(self._language).splitlines()
181181

182+
def _check_user_settings(self):
183+
'''Adds user settings if they are missing'''
184+
185+
# Are there any user settings in the file?
186+
if not 'USER_SETTINGS' in self:
187+
188+
# Add the user settings
189+
self['USER_SETTINGS'] = {}
190+
191+
# Is there a private say commands setting?
192+
if not 'private_say_commands' in self['USER_SETTINGS']:
193+
194+
# Add the private say commands setting
195+
self['USER_SETTINGS']['private_say_commands'] = ''
196+
197+
# Set the private say commands comments
198+
self['USER_SETTINGS'].comments['private_say_commands'] = _core_strings[
199+
'private_say_commands'].get_string(self._language).splitlines()
200+
201+
# Is there a public say commands setting?
202+
if not 'public_say_commands' in self['USER_SETTINGS']:
203+
204+
# Add the public say commands setting
205+
self['USER_SETTINGS']['public_say_commands'] = ''
206+
207+
# Set the public say commands comments
208+
self['USER_SETTINGS'].comments['public_say_commands'] = _core_strings[
209+
'public_say_commands'].get_string(self._language).splitlines()
210+
211+
# Is there a client commands setting?
212+
if not 'client_commands' in self['USER_SETTINGS']:
213+
214+
# Add the client commands setting
215+
self['USER_SETTINGS']['client_commands'] = ''
216+
217+
# Set the client commands comments
218+
self['USER_SETTINGS'].comments['client_commands'] = _core_strings[
219+
'client_commands'].get_string(self._language).splitlines()
220+
182221
# Get the _CoreSettings instance
183222
_CoreSettingsInstance = _CoreSettings(CFG_PATH.joinpath('core_settings.ini'))
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# ../settings/menu.py
2+
3+
# =============================================================================
4+
# >> IMPORTS
5+
# =============================================================================
6+
# Source.Python Imports
7+
# Players
8+
from players.helpers import uniqueid_from_playerinfo
9+
# Settings
10+
from settings.player import _MainSettingsDictionary
11+
from settings.player import _SettingsDictionary
12+
13+
14+
# =============================================================================
15+
# >> CLASSES
16+
# =============================================================================
17+
class _SettingsMenu(object):
18+
''''''
19+
20+
def _private_command(self, *args):
21+
''''''
22+
23+
# Send the menu
24+
self._send_menu(*args)
25+
26+
# Make the command private
27+
return False
28+
29+
def _send_menu(self, playerinfo, *args):
30+
''''''
31+
32+
for name in _MainSettingsDictionary:
33+
for setting in self._get_settings(_MainSettingsDictionary[name]):
34+
print(setting)
35+
36+
def _get_setting(self, settings):
37+
for setting in settings:
38+
if isinstance(setting, _SettingsDictionary):
39+
self._get_settings(setting)
40+
else:
41+
yield setting
42+
43+
_SettingsMenuInstance = _SettingsMenu()
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# ../settings/player.py
2+
3+
# =============================================================================
4+
# >> IMPORTS
5+
# =============================================================================
6+
# Python Imports
7+
# Collections
8+
from collections import OrderedDict
9+
10+
# Source.Python Imports
11+
from public import public
12+
# Settings
13+
from settings.types import _SettingsType
14+
from settings.types import _FloatSetting
15+
from settings.types import _IntegerSetting
16+
from settings.types import _StringSetting
17+
18+
19+
# =============================================================================
20+
# >> GLOBAL VARIABLES
21+
# =============================================================================
22+
# Create a dictionary to store all of the user settings
23+
_MainSettingsDictionary = dict()
24+
25+
26+
# =============================================================================
27+
# >> CLASSES
28+
# =============================================================================
29+
class _SettingsDictionary(OrderedDict):
30+
'''Class used to store user settings'''
31+
32+
def __init__(self, name, text=''):
33+
'''
34+
Verifies the name value on instantiation and stores base attributes
35+
'''
36+
37+
# Is the given name a proper value for a convar?
38+
if not name.replace('_', '').replace(' ', '').isalpha():
39+
40+
# Raise an error
41+
raise ValueError(
42+
'Given name "{0}" is not valid'.format(name))
43+
44+
# Set the base attributes
45+
self._name = name
46+
self._text = text
47+
48+
# Call the super class' __init__ to initialize the OrderedDict
49+
super(_SettingsDictionary, self).__init__()
50+
51+
def __setitem__(self, item, value):
52+
'''Override __setitem__ to verify the type of value given
53+
and that the item is not already in the dictionary'''
54+
55+
# Is the given value a proper type?
56+
if not isinstance(value, (_SettingsDictionary, _SettingsType)):
57+
58+
# Raise an error
59+
raise ValueError(
60+
'Given value "{0}" is not valid'.format(value))
61+
62+
# Is the item already in the dictionary?
63+
if item in self:
64+
65+
# Raise an error
66+
raise ValueError(
67+
'Given item "{0}" is already registered'.format(item))
68+
69+
# Set the item in the dictionary
70+
super(_SettingsDictionary, self).__setitem__(item, value)
71+
72+
# Set the item's prefix
73+
self[item]._prefix = self.prefix + '_'
74+
75+
# Does the section's name need added to the prefix?
76+
if not isinstance(self, PlayerSettings):
77+
78+
# Add the section's name to the prefix
79+
self[item]._prefix += self.name.lower().replace(' ', '_') + '_'
80+
81+
@property
82+
def name(self):
83+
'''Returns the name of the _SettingsDictionary instance'''
84+
return self._name
85+
86+
@property
87+
def prefix(self):
88+
'''Returns the prefix of the _SettingsDictionary instance'''
89+
return self._prefix
90+
91+
def add_float_setting(
92+
self, name, default, text='', min_value=None, max_value=None):
93+
'''Adds a new float setting to the dictionary'''
94+
95+
# Add the new float setting to the dictionary
96+
self[name] = _FloatSetting(name, default, text, min_value, max_value)
97+
98+
# Return the setting
99+
return self[name]
100+
101+
def add_int_setting(
102+
self, name, default, text='', min_value=None, max_value=None):
103+
'''Adds a new integer setting to the dictionary'''
104+
105+
# Add the new integer setting to the dictionary
106+
self[name] = _IntegerSetting(name, default, text, min_value, max_value)
107+
108+
# Return the setting
109+
return self[name]
110+
111+
def add_string_setting(self, name, default, text=''):
112+
'''Adds a new string setting to the dictionary'''
113+
114+
# Add the new string setting to the dictionary
115+
self[name] = _StringSetting(name, default, text)
116+
117+
# Return the setting
118+
return self[name]
119+
120+
def add_section(self, name, text=''):
121+
'''Adds a new section to the dictionary'''
122+
123+
# Add the new section to the dictionary
124+
self[name] = _SettingsDictionary(name, text)
125+
126+
# Return the section
127+
return self[name]
128+
129+
130+
@public
131+
class PlayerSettings(_SettingsDictionary):
132+
'''Class used to register user settings'''
133+
134+
def __init__(self, name, prefix, text=''):
135+
'''Verifies the given values, creates the instance,
136+
and stores the instance in the main dictionary'''
137+
138+
# Is the given name already registered?
139+
if name in _MainSettingsDictionary:
140+
141+
# Raise an error
142+
raise ValueError(
143+
'Given name "{0}" is already registered.'.format(name))
144+
145+
# Is the prefix a proper value?
146+
if not prefix.replace('_', '').isalpha():
147+
148+
# Raise an error
149+
raise ValueError(
150+
'Given prefix "{0}" is not valid'.format(prefix))
151+
152+
# Call the super class' __init__ to verify
153+
# the name and store base attributes
154+
super(PlayerSettings, self).__init__(name, text)
155+
156+
# Set the prefix for the settings
157+
self._prefix = prefix.lower()
158+
159+
# Add the instance to the main dictionary
160+
_MainSettingsDictionary[name] = self
161+
162+
def unregister_settings(self):
163+
'''Unregisters the given settings from the dictionary'''
164+
del _MainSettingsDictionary[self.name]
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# ../settings/storage.py
2+
3+
# =============================================================================
4+
# >> IMPORTS
5+
# =============================================================================
6+
# Python Imports
7+
# Collections
8+
from collections import defaultdict
9+
# Pickle
10+
import pickle
11+
12+
# Source.Python Imports
13+
from paths import SP_DATA_PATH
14+
# Events
15+
from events.manager import EventRegistry
16+
17+
18+
# =============================================================================
19+
# >> GLOBAL VARIABLES
20+
# =============================================================================
21+
_STORAGE_PATH = SP_DATA_PATH.joinpath('settings', 'users.db')
22+
23+
24+
# =============================================================================
25+
# >> CLASSES
26+
# =============================================================================
27+
class _PlayerSettingsDictionary(defaultdict):
28+
'''Dictionary class used to store user specific settings values'''
29+
30+
def __init__(self, default_factory):
31+
'''Loads all values from the database into the dictionary'''
32+
33+
# Has the database previously been saved?
34+
if _STORAGE_PATH.isfile():
35+
36+
# Open/close the settings database
37+
with _STORAGE_PATH.open('rb') as _user_settings:
38+
39+
# Load the database into the dictionary
40+
super(_PlayerSettingsDictionary, self).__init__(
41+
pickle.load(_user_settings))
42+
43+
# Has the database never been saved?
44+
else:
45+
46+
# Call the super class' __init__ to initialize the defaultdict
47+
super(_PlayerSettingsDictionary, self).__init__(default_factory)
48+
49+
def server_spawn(self, game_event):
50+
'''Stores the dictionary to the database on map change'''
51+
52+
# Open/close the settings database as write
53+
with _STORAGE_PATH.open('wb') as _user_settings:
54+
55+
# Dump the dictionary to the database file
56+
pickle.dump(self, _user_settings)
57+
58+
# Get the _PlayerSettingsDictionary instance
59+
_PlayerSettingsStorage = _PlayerSettingsDictionary(dict)
60+
61+
# Register for the event server_spawn in order
62+
# to store the database to file on map change
63+
EventRegistry.register_for_event(
64+
'server_spawn', _PlayerSettingsStorage.server_spawn)

0 commit comments

Comments
 (0)