December 04, 2020, 11:10:37 AM

Author Topic: [bb] Preference library by Zethrax [ 1+ years ago ]  (Read 470 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bb] Preference library by Zethrax [ 1+ years ago ]
« on: June 29, 2017, 12:28:40 AM »
Title : Preference library
Author : Zethrax
Posted : 1+ years ago

Description : *** Blitz3D Code ***
=== Preferences ===

This lib allows you to set, get, save, and load configuration preferences.
- Interface for use with settings and preferences menus -

Note that normally the preference values will be stored in global variables of the data type suitable for whatever the value is. Those globals can be used when populating the GUI settings and preferences menus, or you can use the 'GetPreference' function below. Any changes to the settings and preferences should involve updating the global variable that their live value is stored in and should also include updating the preference via 'SetPreference' so that the preferences file is updated.

GetPreference$( name$, value$ = "" )
   - This function returns a string which represents the preference value with the specified preference 'name$'. The 'value$' parameter is a default value that will be returned if no existing preference with that name exists.
   - See the function declaration for more info.

SetPreference( name$, value$ )
   - This function sets the preference with the specified preference 'name$' to the specified 'value$'.
   - See the function declaration for more info.

G_preferences_changed - (global boolean integer) If this holds a True value then the preferences have been changed (via 'GetPreference' or 'SetPreference') and 'SavePreferenceEntries' should be called at the earliest opportunity to save the preferences to file. Note that 'SavePreferenceEntries' doesn't save anything unless 'G_preferences_changed' is set to True, so you can just blind call that function whenever you might need or want to save preferences. Both 'GetPreference' and 'SetPreference' will set this global to True if they make any changes to the preference entries in the 'T_preference' type list, so you usually won't need to explicitely set this global.
- Functions for use with your program -

LoadPreferenceEntries()
   - Loads the preferences from a file.
   - Run this at the start of your program before you need to use any of your preference galbals.
   - If the preference file is not found then  the 'GetPreference' function will end up using its default preferences instead and the preferences will be flagged to be saved.

SavePreferenceEntries()
   - Saves the preferences to a file.
   - This function should be called before shutting down your program 'nicely'. Don't call it for a fatal error shutdown as it can call 'FatalError' itself (which could result in a loop).
   - This function can be called irregardless of whether preferences actually need saving. If the preferences don't need to be saved then the function will return without saving anything.
NOTES:-

There should be a folder named 'preferences' inside the folder where this code is run from (inside whichever folder your program is in), or inside whatever folder is specified via 'G_program_save_folderpath$'. If you want to use a different name than 'preferences' for the preferences folder then you can change it by setting a different folder name in the 'G_preferences_folder$' global. This should just be the folder name without any slash characters added.

A global named 'G_program_save_folderpath$' should be supplied by your program to specify the base folderpath where all your transient data will get saved. The global should be declared and have its value assigned before 'LoadPreferenceEntries' is called (as that's where it is used).
Note that the folderpath stored in 'G_program_save_folderpath$' must end with a slash character - unless it's an empty string.
Since the operating system doesn't like data to be dynamically saved in some locations ('Program Files', etc) using this global allows you to specify a different save folder location.
If you use a different identifier for this global in your program then you'll need to change it where it appears in this library.
If your program isn't in a location where writes are disabled then you can just set this global to hold an empty string.
If your program is in a location where writes are disabled then you'll need to specify a writable location that contains the 'preferences' folder. Normally you'll set this up using an installer which will save the folderpath to a file you can load at program start to set the value of 'G_program_save_folderpath$'.

A function named 'Error( msg$ )' should be provided by your program to issue non-fatal error messages to the player. If you want to use a different identifier for this function in your program then you'll need to change it where it appears in this library.

A function named 'FatalError( msg$ )' should be provided by your program to issue fatal error messages to the player and shutdown the program. If you want to use a different identifier for this function in your program then you'll need to change it where it appears in this library.

Code: [Select]

; === Preferences ===

; This lib allows you to set, get, save, and load configuration preferences.


; - Interface for use with settings and preferences menus -

; Note that normally the preference values will be stored in global variables of the data type suitable for whatever the value is. Those globals can be used when populating the GUI settings and preferences menus, or you can use the 'GetPreference' function below. Any changes to the settings and preferences should involve updating the global variable that their live value is stored in and should also include updating the preference via 'SetPreference' so that the preferences file is updated.

; GetPreference$( name$, value$ = "" ) ; This function returns a string which represents the preference value with the specified preference 'name$'. The 'value$' parameter is a default value that will be returned if no existing preference with that name exists. See the function declaration for more info.

; SetPreference( name$, value$ ) ; This function sets the preference with the specified preference 'name$' to the specified 'value$'. See the function declaration for more info.

; G_preferences_changed - (global boolean integer) If this holds a True value then the preferences have been changed (via 'GetPreference' or 'SetPreference') and 'SavePreferenceEntries' should be called at the earliest opportunity to save the preferences to file. Note that 'SavePreferenceEntries' doesn't save anything unless 'G_preferences_changed' is set to True, so you can just blind call that function whenever you might need or want to save preferences. Both 'GetPreference' and 'SetPreference' will set this global to True if they make any changes to the preference entries in the 'T_preference' type list, so you usually won't need to explicitely set this global.


; - Functions for use with your program -

; LoadPreferenceEntries()
; Loads the preferences from a file.
; Run this at the start of your program before you need to use any of your preference galbals.
; If the preference file is not found then  the 'GetPreference' function will end up using its default preferences instead and the preferences will be flagged to be saved.

; SavePreferenceEntries()
; Saves the preferences to a file.
; This function should be called before shutting down your program 'nicely'. Don't call it for a fatal error shutdown as it can call 'FatalError' itself (which could result in a loop).
; This function can be called irregardless of whether preferences actually need saving. If the preferences don't need to be saved then the function will return without saving anything.


; NOTES:-

; There should be a folder named 'preferences' inside the folder where this code is run from (inside whichever folder your program is in), or inside whatever folder is specified via 'G_program_save_folderpath$'. If you want to use a different name than 'preferences' for the preferences folder then you can change it by setting a different folder name in the 'G_preferences_folder$' global. This should just be the folder name without any slash characters added.

; A global named 'G_program_save_folderpath$' should be supplied by your program to specify the base folderpath where all your transient data will get saved. The global should be declared and have its value assigned before 'LoadPreferenceEntries' is called (as that's where it is used).
; Note that the folderpath stored in 'G_program_save_folderpath$' must end with a slash character - unless it's an empty string.
; Since the operating system doesn't like data to be dynamically saved in some locations ('Program Files', etc) using this global allows you to specify a different save folder location.
; If you use a different identifier for this global in your program then you'll need to change it where it appears in this library.
; If your program isn't in a location where writes are disabled then you can just set this global to hold an empty string.
; If your program is in a location where writes are disabled then you'll need to specify a writable location that contains the 'preferences' folder. Normally you'll set this up using an installer which will save the folderpath to a file you can load at program start to set the value of 'G_program_save_folderpath$'.

; A function named 'Error( msg$ )' should be provided by your program to issue non-fatal error messages to the player. If you want to use a different identifier for this function in your program then you'll need to change it where it appears in this library.

; A function named 'FatalError( msg$ )' should be provided by your program to issue fatal error messages to the player and shutdown the program. If you want to use a different identifier for this function in your program then you'll need to change it where it appears in this library.

;==========


; === START: Preference globals ===

; > Map save and player profile globals should go here.

; - Graphics.
;Global G_prf_graphics_screen_mode; = C_GMODE_WINDOWED ; 1 = C_GMODE_FULLSCREEN, 2 = C_GMODE_WINDOWED, 3 = C_GMODE_WINDOWED_FULLSCREEN, C_GMODE_WINDOWED_MAXIMIZED
;Global G_prf_fullscreen_resolution_width; = 1280
;Global G_prf_fullscreen_resolution_height; = 720
;Global G_prf_windowed_resolution_width; = 800
;Global G_prf_windowed_resolution_height; = 600
;Global G_prf_field_of_view; = 64 ; Use: CameraZoom G_player_camera, GetCameraZoomFromAngle#( G_prf_field_of_view ) ; Set the player camera's field of view.
;
;; - Audio.
;Global G_prf_master_audio_volume#; = 1.0
;Global G_prf_gameplay_sound_volume#; = 1.0
;Global G_prf_background_music_volume#; = 1.0
;Global G_prf_background_music_muted; = False
;Global G_prf_background_music_randomize; = False
;
;; - Mouse controls.
;Global G_prf_flip_mouse_buttons; = False ; Flip left and right mouse buttons.
;Global G_prf_flip_mouselook_horizontal; = False ; Invert mouselook horizontal direction.
;Global G_prf_flip_mouselook_vertical; = False ; Invert mouselook vertical direction.
;Global G_prf_mouselook_sensitivity#; = 0.25 ; Mouselook sensitivity.
;Global G_prf_allow_mouselook_smoothing; = True ; Enable/disable mouselook smoothing.
;Global G_prf_mouselook_smoothing_level; = 3 ; Mouselook smoothing level.
;
;; - Key bindings.
;Global G_prf_player_move_right; = 32 ; Right. The 'D' key.
;Global G_prf_player_move_left; = 30 ; Left. The 'A' key.
;Global G_prf_player_move_forward; = 17 ; Forward. The 'W' key.
;Global G_prf_player_move_backward; = 31 ; Backward. The 'S' key.
;Global G_prf_player_jump; = 57 ; The 'Spacebar' key.
;Global G_prf_player_sprint; = 42 ; The 'Left-Shift' key.
;Global G_prf_take_screenshot; = 183 ; The 'Print Screen' key.

; === END: Preference globals ===


; The type list used to store preferences for the current profile.
Type T_preference
Field name$
Field value$
End Type


; -- The values in the two lines below can be customized.
Global G_preferences_folder$ = "preferences" ; The name of the preferences folder. This should just be the folder name without any slash characters added.
Global G_current_profile$ = "Player" ; The name of the current player profile. This is left over from the profile system, but is still necessary. Leave it here to support a future profile system.
;------
Global G_preferences_folderpath$ ; Holds the current filepath to the preferences file for the current profile.
Global G_preferences_changed ; A flag that indicates that the preferences have been changed and need to be saved. If a save is required then this will be done upon exiting the settings menu and also when the program ends.



Function ApplyNonRestartPreferences()
; Applies any preferences that don't require a program restart.
; The contents of this function need to be supplied by you to suit your individual program.

; ; Note: For a release version, first delete the profile and preference files from the "preferences" folder to force a new set of files to be created using the default values set in the 'GetPreference' function calls below.
;
;
; ; Get graphics preferences. (done)
; ; (The graphics mode settings are applied by 'SetGraphics3D' once the graphics screen is ready to be created. Updating them requires a program restart so we can't do that here.)
; ; (The field of view setting will be applied when the player character is created during map loading. No need to apply it here.
; ;SetPlayerCameraFOV( G_prf_field_of_view, False )
;
; ; Get and apply audio preferences.
; ; > These will also set the preference globals, but won't change the preference entries.
; SetMasterAudioVolume( G_prf_master_audio_volume#, False )
; SetGameplaySoundVolume( G_prf_gameplay_sound_volume#, False )
; SetBackgroundMusicVolume( G_prf_background_music_volume#, False )
; SetBackgroundMusicMuted( G_prf_background_music_muted, False )
; SetBackgroundMusicRandomize( G_prf_background_music_randomize, False )
;
;
; ; - Mouse controls.
; ; (These settings are initially applied in the 'player.bb' file.
; SetFlipMouseButtons( G_prf_flip_mouse_buttons, False ) ; Flip left and right mouse buttons.
; ; Flip mouselook horizontal (This doesn't need to be explicitely applied as it is used dynamically.)
; ; Flip mouselook vertical (This doesn't need to be explicitely applied as it is used dynamically.)
; ; Mouselook sensitivity. (This doesn't need to be explicitely applied as it is used dynamically.)
; ; Enable/disable mouselook smoothing. (This doesn't need to be explicitely applied as it is used dynamically.)
; SetMouselookSmoothingLevel( G_prf_mouselook_smoothing_level, False ) ; Mouselook smoothing level.

; - Key bindings. (done)
; (These don't need to be explicitely applied as they are used dynamically.)

; If default preference values were used by 'GetPreference' then they need to be saved, so we call 'SavePreferenceEntries'.
; If nothing needs to be saved then 'SavePreferenceEntries' won't do anything, so it's safe to call it blind.
SavePreferenceEntries
End Function



Function AssignPreferencesToGlobals()
; Assigns the preferences for the current profile.
; The contents of this function need to be supplied by you to suit your individual program.
; Normally this is where you'll have all your 'GetPreference' calls to copy the value of preference entries to to their respective preference globals.
; This function is also called by 'SetCurrentPreferenceProfile' after switching to a new profile. It's important that all the code required to load, get, sanitize, and apply the preferences for the new profile be present here.

; ; Note: For a release version, first delete the profile and preference files from the "preferences" folder to force a new set of files to be created using the default values set in the 'GetPreference' function calls below.
;
;
; ; Graphics preferences.
; ; (These settings are applied by 'SetGraphics3D' once the graphics screen is ready to be created. Updating them requires a program restart.)
; G_prf_graphics_screen_mode = GetPreference$( "graphics_screen_mode", "1" ) ; Full screen mode.
; G_prf_fullscreen_resolution_width = GetPreference$( "fullscreen_resolution_width", "" ) ; Value should be "" for release version to force the value to be properly allocated for the user's system.
; G_prf_fullscreen_resolution_height = GetPreference$( "fullscreen_resolution_height", "" ) ; Value should be "" for release version to force the value to be properly allocated for the user's system.
; G_prf_windowed_resolution_width = GetPreference$( "windowed_resolution_width", "800" ) ; Value should be "800" for release version.
; G_prf_windowed_resolution_height = GetPreference$( "windowed_resolution_height", "600" ) ; Value should be "600" for release version.
; ; (This setting is initially applied in the 'player.bb' file and can be updated via 'SetPlayerCameraFOV( False )'.)
; G_prf_field_of_view = GetPreference$( "field_of_view", "64" ) ; Value should be "64" for release version.
;
; ; Audio preferences.
; G_prf_master_audio_volume# = GetPreference$( "master_audio_volume", "1.0" )
; G_prf_gameplay_sound_volume# = GetPreference$( "gameplay_sound_volume", "0.5" )
; G_prf_background_music_volume# = GetPreference$( "background_music_volume", "0.5" )
; G_prf_background_music_muted = GetPreference$( "background_music_muted", "0" )
; G_prf_background_music_randomize = GetPreference$( "background_music_randomize", "0" )
;
; ; - Mouse control preferences.
; ; (These settings are initially applied in the 'player.bb' file.
; G_prf_flip_mouse_buttons = GetPreference$( "flip_mouse_buttons", "0" ) ; Flip left and right mouse buttons. (This needs a function set up to apply it.)
; G_prf_flip_mouselook_horizontal = GetPreference$( "flip_mouselook_horizontal", "0" ) ; Invert mouselook horizontal direction. (This needs a function set up to apply it.)
; G_prf_flip_mouselook_vertical = GetPreference$( "flip_mouselook_vertical", "0" ) ; Invert mouselook vertical direction. (This needs a function set up to apply it.)
; G_prf_mouselook_sensitivity# = GetPreference$( "mouselook_sensitivity", "0.25" ) ; Mouselook sensitivity. (This doesn't need to be explicitely applied as it is used dynamically.)
; G_prf_allow_mouselook_smoothing = GetPreference$( "allow_mouselook_smoothing", "1" ) ; Enable/disable mouselook smoothing. (This doesn't need to be explicitely applied as it is used dynamically.)
; G_prf_mouselook_smoothing_level = GetPreference$( "mouselook_smoothing_level", "3" ) ; Mouselook smoothing level. (This will get setup in 'CreatePlayer' but needs a function set up to apply settings changes.)
;
; ; - Key binding preferences.
; G_prf_player_move_right = GetPreference$( "player_move_right", "32" ) ; Right. The 'D' key.
; G_prf_player_move_left = GetPreference$( "player_move_left", "30" ) ; Left. The 'A' key.
; G_prf_player_move_forward = GetPreference$( "player_move_forward", "17" ) ; Forward. The 'W' key.
; G_prf_player_move_backward = GetPreference$( "player_move_backward", "31" ) ; Backward. The 'S' key.
; G_prf_player_jump = GetPreference$( "player_jump", "57" ) ; The 'Spacebar' key.
; G_prf_player_sprint = GetPreference$( "player_sprint", "42" ) ; The 'Left-Shift' key.
; G_prf_take_screenshot = GetPreference$( "take_screenshot", "14" ) ; The 'Backspace' key.

; If default preference values were used by 'GetPreference' then they need to be saved, so we call 'SavePreferenceEntries'.
; If nothing needs to be saved then 'SavePreferenceEntries' won't do anything, so it's safe to call it blind.
SavePreferenceEntries
End Function



Function GetPreference$( name$, value$ = "" )
; Finds and returns the preference value with the specified 'name$'.
; If a preference with the specified name is not found then the default 'value$' supplied as a parameter will be returned instead and a new element will be created on the preference list with the specified name and value. In this case the name and value strings will be trimmed of surrounding whitespace.

For pref.T_preference = Each T_preference
If name$ = pref
ame$
value$ = prefvalue$
found = True
Exit
EndIf
Next
If Not found
; Create a new preference entry and set its name and value from the supplied parameters.
pref.T_preference = New T_preference
pref
ame$ = Trim( name$ )
prefvalue$ = Trim( value$ )
G_preferences_changed = True ; Flag that the preferences need to be saved to file.
EndIf
Return value$ ; Return either the found value or the default value.
End Function



Function SetPreference( name$, value$ )
; Finds and sets the preference value with the specified 'name$'.
; If a preference with the specified name is not found then a new element will be created on the preference list with the specified name and value.
; The preference name can contain any character other than an equals sign or an end-of-line character. It can also contain spaces, but any surrounding spaces or other whitespace will be trimmed.
; The preference value can contain any character other than an end-of-line character. It can also contain spaces, but any surrounding spaces or other whitespace will be trimmed.

; Sanitize the strings.
name$ = Trim( name$ ) : value$ = Trim( value$ )

For pref.T_preference = Each T_preference
If name$ = pref
ame$
prefvalue$ = value$
found = True
Exit
EndIf
Next
If Not found
; Create a new preference entry and set its name and value from the supplied parameters.
pref.T_preference = New T_preference
pref
ame$ = name$
prefvalue$ = value$
EndIf
G_preferences_changed = True ; Flag that the preferences need to be saved to file.
End Function



Function LoadPreferenceEntries()
; Loads the preferences for the current profile.
; Run this at the start of your program before you need to use any of your preference galbals.
; If the preference file is not found then  the 'GetPreference' function will end up using its default preferences instead and the preferences will be flagged to be saved.

; Set the base path for the preferences folder.
; Note that the value of 'G_program_save_folderpath$' must already have been set by this point.
; Also note that 'G_program_save_folderpath$' must either be an empty string or a folderpath terminated with a backslash.
G_preferences_folderpath$ = G_program_save_folderpath$ + G_preferences_folder$ + ""

Delete Each T_preference ; Clear the existing preferences. Allows new preferences to be loaded when switching profiles.
file = ReadFile( G_preferences_folderpath$ + G_current_profile$ + ".ini" )
If file
While Not Eof( file )
l$ = Trim( ReadLine( file ) )
If l$ <> "" ; If the line is not blank...
s = Instr( l$, "=" )
If s
pref.T_preference = New T_preference
pref
ame$ = Trim( Left( l$, s - 1 ) )
prefvalue$ = Trim( Right( l$, Len( l$ ) - s ) )
EndIf
EndIf
Wend
CloseFile file
Else ; The preferences file doesn't exist, so flag that one needs to be created with default preferences.
G_preferences_changed = True ; Flag that the default preferences that will be set when using 'GetPreference' will need to be saved to file.
EndIf
End Function



Function SavePreferenceEntries()
; Saves the preferences to a file.
; This function should be called before shutting down your program 'nicely'. Don't call it for a fatal error shutdown as it can call 'FatalError' itself (which could result in a loop).
; This function can be called irregardless of whether preferences actually need saving. If the preferences don't need to be saved then the function will return without saving anything.

If G_preferences_changed = False Then Return ; Abort if the preferences don't need saving.

file = WriteFile( G_preferences_folderpath$ + G_current_profile$ + ".ini" )
If file
For pref.T_preference = Each T_preference
WriteLine file, pref
ame$ + "=" + prefvalue$
Next
CloseFile file
G_preferences_changed = False ; Set the flag to false to indicate that the preferences no longer need saving.
Else
; If we've reached this point and can't create the file then it's probably time to pop an error message and exit.
; If we keep going and this save location is dodgy then we may end up having more critical save problems later on or saving data in places we shouldn't.
FatalError "Unable to save preferences. Check that the '" + G_preferences_folder$ + "' folder exists in the save folder at '" + G_program_save_folderpath$ + "' and that write permissions exist for that location."
EndIf
End Function


; === EXAMPLE USAGE ===


; (This is just some code I pulled from my current project as an example of how I use this lib. Some of the comments included are notes to myself.)


;Include "preferences.bb" ; This assumes you have this lib saved to this file.
;LoadPreferenceEntries ; Load the preferences into the 'T_preference' preference entries type list.
;AssignPreferencesToGlobals ; Assign you preferences to your preference globals in this function. The contents of the function need to be supplied by you. I've left some of the (commented out) code from my current project in there as an example.
;
;
;; *** Do all your program start stuff here. Basically anything that can make use of the preference globals, but doesn't need to apply preferences to objects that don't yet exist should go here.
;
;
;; Apply any preference settings that don't require a program restart.
;; > Note that this needs to go here as many of the objects configured by this function won't exist before this point.
;ApplyNonRestartPreferences ; Apply any preference changes that don't require a program restart. This should go after you've created the objects that these preferences will be applied to. The contents of the function need to be supplied by you. I've left some of the (commented out) code from my current project in there as an example. Whether you stick all your preference application stuff into this function or do it in other parts of your program is up to you.
;
;
;; *** The rest of your program goes here (menus, main loop, etc).
;
;
;;===========
;
;
;; Here's an example of one of my functions called in 'ApplyNonRestartPreferences'. It shows how I handle updating preferences from that function (where the pref global and entry have already been set) and from a settings menu change (where the pref global and entry need to be updated).
;
;
;Function SetMasterAudioVolume( volume#, update_prefs = True )
; ; Sets the master audio volume from the preference global.
; ; This affects both gameplay sounds and background music.
; ; In the event GUI sounds and other sounds are added then is should be extended to also affect them.
; ; update_prefs - True = Update the preference global and entry. False = Don't update.
; ; Note that if 'update_prefs' is true then this is being called from the settings menu, so both the preference global and entry will need to be updated. If false then this is being called from the 'ApplyNonRestartPreferences' function, so both the preference global and entry are already set and don't need to be updated. There are no other places where this will be called from.
;
;
; If update_prefs
; G_prf_master_audio_volume# = volume#
; SetPreference( "master_audio_volume", G_prf_master_audio_volume# ) ; This also sets 'G_preferences_changed = True' to flag that a preference save is required.
; EndIf
;
; ; Apply setting.
; SetBackgroundMusicVolume( G_prf_background_music_volume#, False ) ; Sync the background music volume with the volume changes.
; SyncGameplaySoundChannels ; Sync the gameplay sound volume with the volume changes. This will get called anyway on a return from the menu, but we'll leave this here for the moment.
;End Function


Code :
Code: BlitzBasic
  1. ; === Preferences ===
  2.  
  3. ; This lib allows you to set, get, save, and load configuration preferences.
  4.  
  5.  
  6. ; - Interface for use with settings and preferences menus -
  7.  
  8. ; Note that normally the preference values will be stored in global variables of the data type suitable for whatever the value is. Those globals can be used when populating the GUI settings and preferences menus, or you can use the 'GetPreference' function below. Any changes to the settings and preferences should involve updating the global variable that their live value is stored in and should also include updating the preference via 'SetPreference' so that the preferences file is updated.
  9.  
  10. ; GetPreference$( name$, value$ = "" ) ; This function returns a string which represents the preference value with the specified preference 'name$'. The 'value$' parameter is a default value that will be returned if no existing preference with that name exists. See the function declaration for more info.
  11.  
  12. ; SetPreference( name$, value$ ) ; This function sets the preference with the specified preference 'name$' to the specified 'value$'. See the function declaration for more info.
  13.  
  14. ; G_preferences_changed - (global boolean integer) If this holds a True value then the preferences have been changed (via 'GetPreference' or 'SetPreference') and 'SavePreferenceEntries' should be called at the earliest opportunity to save the preferences to file. Note that 'SavePreferenceEntries' doesn't save anything unless 'G_preferences_changed' is set to True, so you can just blind call that function whenever you might need or want to save preferences. Both 'GetPreference' and 'SetPreference' will set this global to True if they make any changes to the preference entries in the 'T_preference' type list, so you usually won't need to explicitely set this global.
  15.  
  16.  
  17. ; - Functions for use with your program -
  18.  
  19. ; LoadPreferenceEntries()
  20.         ; Loads the preferences from a file.
  21.         ; Run this at the start of your program before you need to use any of your preference galbals.
  22.         ; If the preference file is not found then  the 'GetPreference' function will end up using its default preferences instead and the preferences will be flagged to be saved.
  23.  
  24. ; SavePreferenceEntries()
  25.         ; Saves the preferences to a file.
  26.         ; This function should be called before shutting down your program 'nicely'. Don't call it for a fatal error shutdown as it can call 'FatalError' itself (which could result in a loop).
  27.         ; This function can be called irregardless of whether preferences actually need saving. If the preferences don't need to be saved then the function will return without saving anything.
  28.  
  29.  
  30. ; NOTES:-
  31.  
  32. ; There should be a folder named 'preferences' inside the folder where this code is run from (inside whichever folder your program is in), or inside whatever folder is specified via 'G_program_save_folderpath$'. If you want to use a different name than 'preferences' for the preferences folder then you can change it by setting a different folder name in the 'G_preferences_folder$' global. This should just be the folder name without any slash characters added.
  33.  
  34. ; A global named 'G_program_save_folderpath$' should be supplied by your program to specify the base folderpath where all your transient data will get saved. The global should be declared and have its value assigned before 'LoadPreferenceEntries' is called (as that's where it is used).
  35. ; Note that the folderpath stored in 'G_program_save_folderpath$' must end with a slash character - unless it's an empty string.
  36. ; Since the operating system doesn't like data to be dynamically saved in some locations ('Program Files', etc) using this global allows you to specify a different save folder location.
  37. ; If you use a different identifier for this global in your program then you'll need to change it where it appears in this library.
  38. ; If your program isn't in a location where writes are disabled then you can just set this global to hold an empty string.
  39. ; If your program is in a location where writes are disabled then you'll need to specify a writable location that contains the 'preferences' folder. Normally you'll set this up using an installer which will save the folderpath to a file you can load at program start to set the value of 'G_program_save_folderpath$'.
  40.  
  41. ; A function named 'Error( msg$ )' should be provided by your program to issue non-fatal error messages to the player. If you want to use a different identifier for this function in your program then you'll need to change it where it appears in this library.
  42.  
  43. ; A function named 'FatalError( msg$ )' should be provided by your program to issue fatal error messages to the player and shutdown the program. If you want to use a different identifier for this function in your program then you'll need to change it where it appears in this library.
  44.  
  45. ;==========
  46.  
  47.  
  48. ; === START: Preference globals ===
  49.  
  50. ; > Map save and player profile globals should go here.
  51.  
  52. ; - Graphics.
  53. ;Global G_prf_graphics_screen_mode; = C_GMODE_WINDOWED ; 1 = C_GMODE_FULLSCREEN, 2 = C_GMODE_WINDOWED, 3 = C_GMODE_WINDOWED_FULLSCREEN, C_GMODE_WINDOWED_MAXIMIZED
  54. ;Global G_prf_fullscreen_resolution_width; = 1280
  55. ;Global G_prf_fullscreen_resolution_height; = 720
  56. ;Global G_prf_windowed_resolution_width; = 800
  57. ;Global G_prf_windowed_resolution_height; = 600
  58. ;Global G_prf_field_of_view; = 64 ; Use: CameraZoom G_player_camera, GetCameraZoomFromAngle#( G_prf_field_of_view ) ; Set the player camera's field of view.
  59. ;
  60. ;; - Audio.
  61. ;Global G_prf_master_audio_volume#; = 1.0
  62. ;Global G_prf_gameplay_sound_volume#; = 1.0
  63. ;Global G_prf_background_music_volume#; = 1.0
  64. ;Global G_prf_background_music_muted; = False
  65. ;Global G_prf_background_music_randomize; = False
  66. ;
  67. ;; - Mouse controls.
  68. ;Global G_prf_flip_mouse_buttons; = False ; Flip left and right mouse buttons.
  69. ;Global G_prf_flip_mouselook_horizontal; = False ; Invert mouselook horizontal direction.
  70. ;Global G_prf_flip_mouselook_vertical; = False ; Invert mouselook vertical direction.
  71. ;Global G_prf_mouselook_sensitivity#; = 0.25 ; Mouselook sensitivity.
  72. ;Global G_prf_allow_mouselook_smoothing; = True ; Enable/disable mouselook smoothing.
  73. ;Global G_prf_mouselook_smoothing_level; = 3 ; Mouselook smoothing level.
  74. ;
  75. ;; - Key bindings.
  76. ;Global G_prf_player_move_right; = 32 ; Right. The 'D' key.
  77. ;Global G_prf_player_move_left; = 30 ; Left. The 'A' key.
  78. ;Global G_prf_player_move_forward; = 17 ; Forward. The 'W' key.
  79. ;Global G_prf_player_move_backward; = 31 ; Backward. The 'S' key.
  80. ;Global G_prf_player_jump; = 57 ; The 'Spacebar' key.
  81. ;Global G_prf_player_sprint; = 42 ; The 'Left-Shift' key.
  82. ;Global G_prf_take_screenshot; = 183 ; The 'Print Screen' key.
  83.  
  84. ; === END: Preference globals ===
  85.  
  86.  
  87. ; The type list used to store preferences for the current profile.
  88. Type T_preference
  89.         Field name$
  90.         Field value$
  91. End Type
  92.  
  93.  
  94. ; -- The values in the two lines below can be customized.
  95. Global G_preferences_folder$ = "preferences" ; The name of the preferences folder. This should just be the folder name without any slash characters added.
  96. Global G_current_profile$ = "Player" ; The name of the current player profile. This is left over from the profile system, but is still necessary. Leave it here to support a future profile system.
  97. ;------
  98. Global G_preferences_folderpath$ ; Holds the current filepath to the preferences file for the current profile.
  99. Global G_preferences_changed ; A flag that indicates that the preferences have been changed and need to be saved. If a save is required then this will be done upon exiting the settings menu and also when the program ends.
  100.  
  101.  
  102.  
  103. Function ApplyNonRestartPreferences()
  104.         ; Applies any preferences that don't require a program restart.
  105.         ; The contents of this function need to be supplied by you to suit your individual program.
  106.  
  107. ;       ; Note: For a release version, first delete the profile and preference files from the "preferences" folder to force a new set of files to be created using the default values set in the 'GetPreference' function calls below. 
  108. ;      
  109. ;
  110. ;       ; Get graphics preferences. (done)     
  111. ;       ; (The graphics mode settings are applied by 'SetGraphics3D' once the graphics screen is ready to be created. Updating them requires a program restart so we can't do that here.)
  112. ;       ; (The field of view setting will be applied when the player character is created during map loading. No need to apply it here.
  113. ;       ;SetPlayerCameraFOV( G_prf_field_of_view, False )      
  114. ;
  115. ;       ; Get and apply audio preferences.
  116. ;       ; > These will also set the preference globals, but won't change the preference entries.
  117. ;       SetMasterAudioVolume( G_prf_master_audio_volume#, False )
  118. ;       SetGameplaySoundVolume( G_prf_gameplay_sound_volume#, False )
  119. ;       SetBackgroundMusicVolume( G_prf_background_music_volume#, False )
  120. ;       SetBackgroundMusicMuted( G_prf_background_music_muted, False )
  121. ;       SetBackgroundMusicRandomize( G_prf_background_music_randomize, False )
  122. ;
  123. ;      
  124. ;       ; - Mouse controls.
  125. ;       ; (These settings are initially applied in the 'player.bb' file.
  126. ;       SetFlipMouseButtons( G_prf_flip_mouse_buttons, False ) ; Flip left and right mouse buttons.
  127. ;       ; Flip mouselook horizontal (This doesn't need to be explicitely applied as it is used dynamically.)
  128. ;       ; Flip mouselook vertical (This doesn't need to be explicitely applied as it is used dynamically.)
  129. ;       ; Mouselook sensitivity. (This doesn't need to be explicitely applied as it is used dynamically.)
  130. ;       ; Enable/disable mouselook smoothing. (This doesn't need to be explicitely applied as it is used dynamically.)
  131. ;       SetMouselookSmoothingLevel( G_prf_mouselook_smoothing_level, False ) ; Mouselook smoothing level.
  132.  
  133.         ; - Key bindings. (done)
  134.         ; (These don't need to be explicitely applied as they are used dynamically.)
  135.  
  136.         ; If default preference values were used by 'GetPreference' then they need to be saved, so we call 'SavePreferenceEntries'.
  137.         ; If nothing needs to be saved then 'SavePreferenceEntries' won't do anything, so it's safe to call it blind.
  138.         SavePreferenceEntries
  139. End Function
  140.  
  141.  
  142.  
  143. Function AssignPreferencesToGlobals()
  144.         ; Assigns the preferences for the current profile.
  145.         ; The contents of this function need to be supplied by you to suit your individual program.
  146.         ; Normally this is where you'll have all your 'GetPreference' calls to copy the value of preference entries to to their respective preference globals.
  147.         ; This function is also called by 'SetCurrentPreferenceProfile' after switching to a new profile. It's important that all the code required to load, get, sanitize, and apply the preferences for the new profile be present here.     
  148.  
  149. ;       ; Note: For a release version, first delete the profile and preference files from the "preferences" folder to force a new set of files to be created using the default values set in the 'GetPreference' function calls below.
  150. ;      
  151. ;
  152. ;       ; Graphics preferences.
  153. ;       ; (These settings are applied by 'SetGraphics3D' once the graphics screen is ready to be created. Updating them requires a program restart.)
  154. ;       G_prf_graphics_screen_mode = GetPreference$( "graphics_screen_mode", "1" ) ; Full screen mode.
  155. ;       G_prf_fullscreen_resolution_width = GetPreference$( "fullscreen_resolution_width", "" ) ; Value should be "" for release version to force the value to be properly allocated for the user's system.
  156. ;       G_prf_fullscreen_resolution_height = GetPreference$( "fullscreen_resolution_height", "" ) ; Value should be "" for release version to force the value to be properly allocated for the user's system.
  157. ;       G_prf_windowed_resolution_width = GetPreference$( "windowed_resolution_width", "800" ) ; Value should be "800" for release version.
  158. ;       G_prf_windowed_resolution_height = GetPreference$( "windowed_resolution_height", "600" ) ; Value should be "600" for release version.
  159. ;       ; (This setting is initially applied in the 'player.bb' file and can be updated via 'SetPlayerCameraFOV( False )'.)
  160. ;       G_prf_field_of_view = GetPreference$( "field_of_view", "64" ) ; Value should be "64" for release version.      
  161. ;
  162. ;       ; Audio preferences.
  163. ;       G_prf_master_audio_volume# = GetPreference$( "master_audio_volume", "1.0" )
  164. ;       G_prf_gameplay_sound_volume# = GetPreference$( "gameplay_sound_volume", "0.5" )
  165. ;       G_prf_background_music_volume# = GetPreference$( "background_music_volume", "0.5" )
  166. ;       G_prf_background_music_muted = GetPreference$( "background_music_muted", "0" )
  167. ;       G_prf_background_music_randomize = GetPreference$( "background_music_randomize", "0" )
  168. ;      
  169. ;       ; - Mouse control preferences.
  170. ;       ; (These settings are initially applied in the 'player.bb' file.
  171. ;       G_prf_flip_mouse_buttons = GetPreference$( "flip_mouse_buttons", "0" ) ; Flip left and right mouse buttons. (This needs a function set up to apply it.)
  172. ;       G_prf_flip_mouselook_horizontal = GetPreference$( "flip_mouselook_horizontal", "0" ) ; Invert mouselook horizontal direction. (This needs a function set up to apply it.)
  173. ;       G_prf_flip_mouselook_vertical = GetPreference$( "flip_mouselook_vertical", "0" ) ; Invert mouselook vertical direction. (This needs a function set up to apply it.)
  174. ;       G_prf_mouselook_sensitivity# = GetPreference$( "mouselook_sensitivity", "0.25" ) ; Mouselook sensitivity. (This doesn't need to be explicitely applied as it is used dynamically.)
  175. ;       G_prf_allow_mouselook_smoothing = GetPreference$( "allow_mouselook_smoothing", "1" ) ; Enable/disable mouselook smoothing. (This doesn't need to be explicitely applied as it is used dynamically.)
  176. ;       G_prf_mouselook_smoothing_level = GetPreference$( "mouselook_smoothing_level", "3" ) ; Mouselook smoothing level. (This will get setup in 'CreatePlayer' but needs a function set up to apply settings changes.)
  177. ;
  178. ;       ; - Key binding preferences.
  179. ;       G_prf_player_move_right = GetPreference$( "player_move_right", "32" ) ; Right. The 'D' key.
  180. ;       G_prf_player_move_left = GetPreference$( "player_move_left", "30" ) ; Left. The 'A' key.
  181. ;       G_prf_player_move_forward = GetPreference$( "player_move_forward", "17" ) ; Forward. The 'W' key.
  182. ;       G_prf_player_move_backward = GetPreference$( "player_move_backward", "31" ) ; Backward. The 'S' key.
  183. ;       G_prf_player_jump = GetPreference$( "player_jump", "57" ) ; The 'Spacebar' key.
  184. ;       G_prf_player_sprint = GetPreference$( "player_sprint", "42" ) ; The 'Left-Shift' key.
  185. ;       G_prf_take_screenshot = GetPreference$( "take_screenshot", "14" ) ; The 'Backspace' key.
  186.  
  187.         ; If default preference values were used by 'GetPreference' then they need to be saved, so we call 'SavePreferenceEntries'.
  188.         ; If nothing needs to be saved then 'SavePreferenceEntries' won't do anything, so it's safe to call it blind.
  189.         SavePreferenceEntries
  190. End Function
  191.  
  192.  
  193.  
  194. Function GetPreference$( name$, value$ = "" )
  195. ; Finds and returns the preference value with the specified 'name$'.
  196. ; If a preference with the specified name is not found then the default 'value$' supplied as a parameter will be returned instead and a new element will be created on the preference list with the specified name and value. In this case the name and value strings will be trimmed of surrounding whitespace.
  197.        
  198.         For pref.T_preference = Each T_preference
  199.                 If name$ = pref
  200. ame$
  201.                         value$ = prefvalue$
  202.                         found = True
  203.                         Exit
  204.                 EndIf
  205.         Next
  206.         If Not found
  207.                 ; Create a new preference entry and set its name and value from the supplied parameters.
  208.                 pref.T_preference = New T_preference
  209.                 pref
  210. ame$ = Trim( name$ )
  211.                 prefvalue$ = Trim( value$ )
  212.                 G_preferences_changed = True ; Flag that the preferences need to be saved to file.
  213.         EndIf
  214.         Return value$ ; Return either the found value or the default value.
  215. End Function
  216.  
  217.  
  218.  
  219. Function SetPreference( name$, value$ )
  220. ; Finds and sets the preference value with the specified 'name$'.
  221. ; If a preference with the specified name is not found then a new element will be created on the preference list with the specified name and value.
  222. ; The preference name can contain any character other than an equals sign or an end-of-line character. It can also contain spaces, but any surrounding spaces or other whitespace will be trimmed.
  223. ; The preference value can contain any character other than an end-of-line character. It can also contain spaces, but any surrounding spaces or other whitespace will be trimmed.
  224.  
  225.         ; Sanitize the strings.
  226.         name$ = Trim( name$ ) : value$ = Trim( value$ )
  227.  
  228.         For pref.T_preference = Each T_preference
  229.                 If name$ = pref
  230. ame$
  231.                         prefvalue$ = value$
  232.                         found = True
  233.                         Exit
  234.                 EndIf
  235.         Next
  236.         If Not found
  237.                 ; Create a new preference entry and set its name and value from the supplied parameters.
  238.                 pref.T_preference = New T_preference
  239.                 pref
  240. ame$ = name$
  241.                 prefvalue$ = value$
  242.         EndIf
  243.         G_preferences_changed = True ; Flag that the preferences need to be saved to file.
  244. End Function
  245.  
  246.  
  247.  
  248. Function LoadPreferenceEntries()
  249.         ; Loads the preferences for the current profile.
  250.         ; Run this at the start of your program before you need to use any of your preference galbals.
  251.         ; If the preference file is not found then  the 'GetPreference' function will end up using its default preferences instead and the preferences will be flagged to be saved.    
  252.  
  253.         ; Set the base path for the preferences folder.
  254.         ; Note that the value of 'G_program_save_folderpath$' must already have been set by this point.
  255.         ; Also note that 'G_program_save_folderpath$' must either be an empty string or a folderpath terminated with a backslash.
  256.         G_preferences_folderpath$ = G_program_save_folderpath$ + G_preferences_folder$ + ""
  257.        
  258.         Delete Each T_preference ; Clear the existing preferences. Allows new preferences to be loaded when switching profiles.
  259.         file = ReadFile( G_preferences_folderpath$ + G_current_profile$ + ".ini" )
  260.         If file
  261.                 While Not Eof( file )
  262.                         l$ = Trim( ReadLine( file ) )
  263.                         If l$ <> "" ; If the line is not blank...
  264.                                 s = Instr( l$, "=" )
  265.                                 If s
  266.                                         pref.T_preference = New T_preference
  267.                                         pref
  268. ame$ = Trim( Left( l$, s - 1 ) )
  269.                                         prefvalue$ = Trim( Right( l$, Len( l$ ) - s ) )
  270.                                 EndIf
  271.                         EndIf
  272.                 Wend
  273.                 CloseFile file
  274.         Else ; The preferences file doesn't exist, so flag that one needs to be created with default preferences.
  275.                 G_preferences_changed = True ; Flag that the default preferences that will be set when using 'GetPreference' will need to be saved to file.
  276.         EndIf
  277. End Function
  278.  
  279.  
  280.  
  281. Function SavePreferenceEntries()
  282.         ; Saves the preferences to a file.
  283.         ; This function should be called before shutting down your program 'nicely'. Don't call it for a fatal error shutdown as it can call 'FatalError' itself (which could result in a loop).
  284.         ; This function can be called irregardless of whether preferences actually need saving. If the preferences don't need to be saved then the function will return without saving anything.
  285.        
  286.         If G_preferences_changed = False Then Return ; Abort if the preferences don't need saving.
  287.        
  288.         file = WriteFile( G_preferences_folderpath$ + G_current_profile$ + ".ini" )
  289.         If file
  290.                 For pref.T_preference = Each T_preference
  291.                         WriteLine file, pref
  292. ame$ + "=" + prefvalue$
  293.                 Next
  294.                 CloseFile file
  295.                 G_preferences_changed = False ; Set the flag to false to indicate that the preferences no longer need saving.
  296.         Else
  297.                 ; If we've reached this point and can't create the file then it's probably time to pop an error message and exit.
  298.                 ; If we keep going and this save location is dodgy then we may end up having more critical save problems later on or saving data in places we shouldn't.
  299.                 FatalError "Unable to save preferences. Check that the '" + G_preferences_folder$ + "' folder exists in the save folder at '" + G_program_save_folderpath$ + "' and that write permissions exist for that location."
  300.         EndIf
  301. End Function
  302.  
  303.  
  304. ; === EXAMPLE USAGE ===
  305.  
  306.  
  307. ; (This is just some code I pulled from my current project as an example of how I use this lib. Some of the comments included are notes to myself.)
  308.  
  309.  
  310. ;Include "preferences.bb" ; This assumes you have this lib saved to this file.
  311. ;LoadPreferenceEntries ; Load the preferences into the 'T_preference' preference entries type list.
  312. ;AssignPreferencesToGlobals ; Assign you preferences to your preference globals in this function. The contents of the function need to be supplied by you. I've left some of the (commented out) code from my current project in there as an example.
  313. ;
  314. ;
  315. ;; *** Do all your program start stuff here. Basically anything that can make use of the preference globals, but doesn't need to apply preferences to objects that don't yet exist should go here.
  316. ;
  317. ;
  318. ;; Apply any preference settings that don't require a program restart.
  319. ;; > Note that this needs to go here as many of the objects configured by this function won't exist before this point.
  320. ;ApplyNonRestartPreferences ; Apply any preference changes that don't require a program restart. This should go after you've created the objects that these preferences will be applied to. The contents of the function need to be supplied by you. I've left some of the (commented out) code from my current project in there as an example. Whether you stick all your preference application stuff into this function or do it in other parts of your program is up to you.
  321. ;
  322. ;
  323. ;; *** The rest of your program goes here (menus, main loop, etc).
  324. ;
  325. ;
  326. ;;===========
  327. ;
  328. ;
  329. ;; Here's an example of one of my functions called in 'ApplyNonRestartPreferences'. It shows how I handle updating preferences from that function (where the pref global and entry have already been set) and from a settings menu change (where the pref global and entry need to be updated).
  330. ;
  331. ;
  332. ;Function SetMasterAudioVolume( volume#, update_prefs = True )
  333. ;       ; Sets the master audio volume from the preference global.
  334. ;       ; This affects both gameplay sounds and background music.
  335. ;       ; In the event GUI sounds and other sounds are added then is should be extended to also affect them.
  336. ;       ; update_prefs - True = Update the preference global and entry. False = Don't update.
  337. ;       ; Note that if 'update_prefs' is true then this is being called from the settings menu, so both the preference global and entry will need to be updated. If false then this is being called from the 'ApplyNonRestartPreferences' function, so both the preference global and entry are already set and don't need to be updated. There are no other places where this will be called from.
  338. ;
  339. ;      
  340. ;       If update_prefs
  341. ;               G_prf_master_audio_volume# = volume#
  342. ;               SetPreference( "master_audio_volume", G_prf_master_audio_volume# ) ; This also sets 'G_preferences_changed = True' to flag that a preference save is required.
  343. ;       EndIf
  344. ;      
  345. ;       ; Apply setting.
  346. ;       SetBackgroundMusicVolume( G_prf_background_music_volume#, False ) ; Sync the background music volume with the volume changes.
  347. ;       SyncGameplaySoundChannels ; Sync the gameplay sound volume with the volume changes. This will get called anyway on a return from the menu, but we'll leave this here for the moment.
  348. ;End Function


Comments :


Rick Nasher(Posted 1+ years ago)

 Nice, but if you go through the trouble of putting this up here, why not include a working example right away?


Zethrax(Posted 1+ years ago)

 There's a usage example down the bottom which shows basic usage (commented out though). I've left commented-out code from the project this is taken from in too, to show how it's meant to be used. It's a pretty simple lib with a lot of comments documenting it.


BlitzSupport(Posted 1+ years ago)

 You're posting some good stuff, but any reason the code can't be placed in the proper code section, instead of just a link to the URL? It means if you try to download via the "Download source code" link you just get this:
Code: [Select]
; ID: 3188
; Author: Zethrax
; Date: 2015-02-13 19:31:28
; Title: Preference library
; Description: This lib allows you to set, get, save, and load configuration preferences.

The code can be found at: <a href="codearcs7715.html?code=3188" target="_blank">http://www.blitzbasic.com/codearcs/codearcs.php?code=3188</a>
Kinda screws up the whole format of the Code Archives!


Zethrax(Posted 1+ years ago)

 I tend to use word-wrap when writing code (not a fan of micro-managing line length), and I like to add a lot of detailed comments. Since the standard [ code ] forum code doesn't wrap lines, that usually means the whole post block ends up pushed off the page - including the description part of the post. This just ends up as a horrible mess and [ codebox ] is the only solution I've found for that.If there was a way to wrap lines for the [ code ] block or if [ codebox ] was an option for the code entry area then I'd happily use that. It'd save me going back to the post to add the URL.


BlitzSupport(Posted 1+ years ago)

 Even if you put the code in your comments section as you're doing now, you could also place it in the code section so that it can be downloaded -- that code should still display correctly in the IDE, even if it wraps 'in-browser'.


Zethrax(Posted 1+ years ago)

 As I said, putting the code into the code section is the problem as it forces the whole post over width - including the description/docs part.It's not really a problem for me personally (posting straight into the proper code textbox would actually simplify things), but it ends up being a mess for anyone who wants to read the description and docs above the code.I'll change this post to the standard setup anyway. I'm happy to discuss solutions to this issue,etc, but I'm not going to start splitting lines to accommodate non word-wrapped situations (as I said, not a fan of micro-managing line length when I can just turn on word-wrap in the IDE I use).One solution would be if the description area and code display area on the web-page were styled as separate posts. That way the code area could go over-width without also pushing the description area over-width. [/i]

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal