System.Volume reset when loading a save game

Started by rongel, Fri 12/02/2021 10:32:29

Previous topic - Next topic

rongel

I have a sound issue connected to the System.Volume. Here's my situation:

I have a simple sound system that has adjustable sliders for Main Volume and Music Volume. Main volume is connected to System.Volume and Music Volume to eAudioTypeMusic.

Everything seems to work during the game. Problems start when I have adjusted the Main Volume and load a save game. Here's two different scenarios:

1. I lower the Main Volume, save the game and exit. I start the game again, load the save, and the Main Volume is playing at default value, eventhough the slider is still set to a low value.
2. I lower the Main Volume, save the game, adjust the Main Volume slider to default again, then load the save. The volume is playing at the default value, but the slider is set to a low value.

So I want the System.Volume to be always using the values from the Main Volume slider. Currently it resets to a default volume when loading a game. The Music Volume works fine, it's always playing at the same value as the Music Volume slider, even if I exit the game and start it again.

I've tried all sorts of tricks to set the System.Volume to the correct value using the eEventRestoreGame. I even tried to save the System.Volume to a config.dat-file. I think I got it right, but it had no effect, the System.Volume was still reset after loading a game. The System.Volume seems to work nicely otherwise, but is it a bad idea to use it to control the master volume? How can I make it to remember the saved values?

Dreams in the Witch House on Steam & GOG

Khris

It sounds like you should update the bad volume value according to the slider in eEventRestoreGame? Since the slider's value does get saved correctly.

You said it had no effect; can you show the code you've used?

rongel

QuoteIt sounds like you should update the bad volume value according to the slider in eEventRestoreGame? Since the slider's value does get saved correctly.

Yes, exactly, I've tried to do something like that using this in eEventRestoreGame:

Code: ags
System.Volume = sldMasterVolume.Value;


It had no effect. Just to check I also used this:

Code: ags
System.Volume =10;


That worked, and the sound was muted when loading the game. Is it normal behaviour that System.Volume resets? It's possible that there's somehting funny in my code which does this.

QuoteYou said it had no effect; can you show the code you've used?

I used this when saving the game (the code was mostly copied from another thread) :

Code: ags
function SaveVolume()
{
  // Save custom config
  music_vol = sldMasterVolume.Value;
  File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileWrite);
  config.WriteInt(music_vol);
  config.Close();
}


And this in eEventRestoreGame:

Code: ags
void AfterLoadGame()
{
  File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileRead);
  music_vol = config.ReadInt();
  config.Close();
   
  System.Volume = music_vol;
}


It seemed to work, I mean it didn't give any errors, but the actual volume didn't change.
Dreams in the Witch House on Steam & GOG

Khris

I can kinda see why the volume setting isn't part of a save game (since the volume level isn't really part of the game state, unlike inventory etc.)
However I have no idea why changing the volume level like that has no effect. The only explanation I can think of is that the code doesn't actually run.

rongel

QuoteHowever I have no idea why changing the volume level like that has no effect. The only explanation I can think of is that the code doesn't actually run.

I did some quick tests with other AGS games that I have and it seemed that they have the same behaviour. I tested the Urban Witch Story, and Kathy Rain. In both games the master volume was reseted to max when loading a game. In Urban Witch Story the volume slider was still in zero where I had put it, in Kathy Rain it was back in max.

So it seems it's easier to reset the slider to max when loading the game, so that it matches the volume. Is this a bug / a feature in AGS, or does someone know a way how to load a System.Volume from a save game? I can live with adjusting the slider, main thing is that their values match.
Dreams in the Witch House on Steam & GOG

Laura Hunt

#5
This is what I have in my game_start() function:

Code: ags
  File *customplayerdata = File.Open("$SAVEGAMEDIR$/playersettings.dat", eFileRead);
  if (customplayerdata == null) {
    System.Volume = 70;
    Game.TextReadingSpeed = 11;
  }
  else {
    System.Volume = customplayerdata.ReadInt();
    Game.TextReadingSpeed = customplayerdata.ReadInt();
    sAudioVolume.Value = System.Volume;
    sTextSpeed.Value = Game.TextReadingSpeed;
    customplayerdata.Close();
  }


Looks like the difference with your code is that I explicitely set both the slider value and the System Volume values. No idea if it might make a difference, but maybe it'll help!

EDIT: This is a complete shot in the dark, but could this have something to do with the fact that you're closing the file and then assigning System.Volume = music_vol? (and maybe you have your variables mixed up? You did mention that you have a Global volume and a Music volume, but here it seems like you're assigning the Music value to the Global volume). Maybe you could try skipping that step and simply doing System.Volume = config.ReadInt() without that intermediate variable?

rongel

Quote from: Laura Hunt on Fri 12/02/2021 12:36:04
This is what I have in my game_start() function:

Thanks Laura! I'll try to test this soon. Maybe adding the slider values to the config file helps. Can you confirm that changing the system volume works in your game? I mean to mute (for example) the system.volume from the slider, save the game, exit, start it again and load the game and check if it's still muted?

In my code I had a value called music_vol, but it was just because the copy / pasting, it should've been called system_vol.
Dreams in the Witch House on Steam & GOG

rongel

Quote from: Laura Hunt on Fri 12/02/2021 12:36:04
Maybe you could try skipping that step and simply doing System.Volume = config.ReadInt() without that intermediate variable?

I tried using this very simple script, I think it should have worked?

Code: ags

// When saving the game
function SaveVolume()
{
  // Save custom config
  File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileWrite);
  config.WriteInt(System.Volume);
  config.Close();
}


And this:

Code: ags

// in eEventRestoreGame
function AfterLoadGame()
{
  File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileRead);
  System.Volume = config.ReadInt();
  config.Close();
}


But it had no effect, the System.Value was again maxed, when loading the save (it should have been muted).
Dreams in the Witch House on Steam & GOG

Laura Hunt

#8
That is SO weird.

I take it you're calling the AfterLoadGame() function from inside eEventRestoreGame, but that you have actually declared the function at the top of your global script and imported it from the global script header, right?

Could you copy your whole on_event function here, if it's not too massive?

This is how mine looks like:

Spoiler
Code: ags
function on_event(EventType event, int data)
{
  if (event == eEventRestoreGame && data == 23) { // I only have one save slot, number 23, but in other cases data != 999 would do I guess
    File *customplayerdata = File.Open("$SAVEGAMEDIR$/playersettings.dat", eFileRead);
    if (customplayerdata != null) { 
      System.Volume = customplayerdata.ReadInt();
      Game.TextReadingSpeed = customplayerdata.ReadInt();
      sAudioVolume.Value = System.Volume;
      sTextSpeed.Value = Game.TextReadingSpeed;
      customplayerdata.Close();
    }
  }
  
  if (event == eEventRestoreGame && data == 999) {
    // do some stuff here, irrelevant for our current purposes
    game_start();
  }
}
[close]

rongel

Yep, here it is. The first block is an old inventorybar fix, but shouldn't be connected.

Code: ags
function on_event (EventType event, int data)   
{
  // Makes the inventory backround deselect bug to go away!
  if (event == eEventGUIMouseDown && mouse.IsButtonDown(eMouseRight) && data == gInventoryBar.ID) 
  {
    GUIControl *theControl = GUIControl.GetAtScreenXY(mouse.x, mouse.y);
    if (theControl==InvWin_Walter) //the InvWindow
    {
      InventoryItem *i = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
      if (i == null)
      { 
        player.ActiveInventory = null;   // lose active inv
        mouse.Mode=eModeInteract;
      }
    }
  }
  
  // RESTORE GAME (Load saved System.Volume ei toimi!)
  if(event == eEventRestoreGame && data !=999) {
    
    AfterLoadGame();
    
  }
}


I wasn't using that "&& data !=999" bit at first. I added it and tested, but no difference. I wasn't sure what you ment by this: 
Quoteand imported it from the global script header, right?
Except this mysterious sound issue, the on_event seems to be working fine, and I can see things happen when I use it.
Dreams in the Witch House on Steam & GOG

Laura Hunt

#10
Quote from: rongel on Fri 12/02/2021 15:17:59
I wasn't sure what you ment by this: 
Quoteand imported it from the global script header, right?

If you define a function in your global script, you need to add it to the header (globalscript.ash) so it can be used anywhere in the game, although I'm not 100% sure if that is relevant here. I don't know if it'll change anything, but I guess it doesn't hurt to go to GlobalScript / Edit Header in the navigation panel, and add this line:

Code: ags
import function AfterLoadGame();


Maybe it would also be a good idea to just put your whole code there instead of the function call and see if it makes a difference?

Code: ags
  if (event == eEventRestoreGame) {
    
      File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileRead);
      System.Volume = config.ReadInt();
      sldMasterVolume.Value = System.Volume;
      config.Close();   
  }



rongel

QuoteIf you define a function in your global script, you need to add it to the header (globalscript.ash) so it can be used anywhere in the game, although I'm not 100% sure if that is relevant here.

Ah, yes. I didn't have that in the header, but I tried this adding the whole code there too, and it didn't help. Weird thing is that I can do this, for example:


Code: ags
if(event == eEventRestoreGame && data !=999) {
    System.Volume =10;
  }


And the volume nicely jumps to the correct value. It seems I can only change the volume here by giving it a fixed number. Using an int doesn't seem to affect it. So that has me thinking that it is a bug of some sort. Especially when I saw the same behaviour in the two games I tested. I think I just reset the slider to max value when loading the game, and then the volume and the slider values are in sync.
Dreams in the Witch House on Steam & GOG

Laura Hunt

Quote from: rongel on Fri 12/02/2021 15:49:25
QuoteIf you define a function in your global script, you need to add it to the header (globalscript.ash) so it can be used anywhere in the game, although I'm not 100% sure if that is relevant here.

Ah, yes. I didn't have that in the header, but I tried this adding the whole code there too, and it didn't help.

Yeah, I guess it makes sense because this is always called from global script, so there's no need to import it. Worth a try though!


Quote from: rongel on Fri 12/02/2021 15:49:25
Weird thing is that I can do this, for example:


Code: ags
if(event == eEventRestoreGame && data !=999) {
    System.Volume =10;
  }


And the volume nicely jumps to the correct value. It seems I can only change the volume here by giving it a fixed number. Using an int doesn't seem to affect it. So that has me thinking that it is a bug of some sort. Especially when I saw the same behaviour in the two games I tested. I think I just reset the slider to max value when loading the game, and then the volume and the slider values are in sync.

That is super weird. I was going to say that it doesn't even make sense because the code I posted earlier works for me, *but* I just realized that actually calling that code in the on_event function is redundant, because I always call it at game_start anyway. So maybe I also have that bug but I haven't noticed it because of my duplicated code :-D

I'm sorry I couldn't help! The last thing I would suggest would be moving the call to load the volume config in game_start if it fits the logic of your game, but otherwise I'm totally out of ideas. Might simply be a weird bug, like you suggested!

rongel

Quote from: Laura Hunt on Fri 12/02/2021 15:56:31
I'm sorry I couldn't help! The last thing I would suggest would be moving the call to load the volume config in game_start if it fits the logic of your game, but otherwise I'm totally out of ideas. Might simply be a weird bug, like you suggested!

Thanks anyway! Good to know that I should be doing the right thing here, and that it's not my crappy code!  :-D

A small update, if I use the config file to store the System.Volume and do this:

Code: ags
if(event == eEventRestoreGame && data !=999) {
        
   AfterLoadGame();
   Display("System.Volume is %d", System.Volume);
  }


It displays the correct value! So the game says the System.Volume is 13 for example, but I can hear everything playing at 100 value. It must mean that the config file is working, but the actual sound that is playing doesn't obey the System.Volume. If I adjust the slider, the volume jumps to correct value. Weird...

Dreams in the Witch House on Steam & GOG

Vincent

I don't have a clue about this but I was thinking that instead having a System.Volume you can split each type of sound separately like for music, sound, speech and ambient sound. So probably it can be avoided having a global volume at all and on slider change it can be done something like this:

Code: ags

function SliderMusic_OnChange(GUIControl *control)
{
  Game.SetAudioTypeVolume(eAudioTypeMusic, SliderMusic.Value, eVolExistingAndFuture);
}

rongel

Quote from: Vincent on Fri 12/02/2021 16:57:34
I don't have a clue about this but I was thinking that instead having a System.Volume you can split each type of sound separately like for music, sound, speech and ambient sound.

Thanks for the suggestion! I like the idea of the Master Volume and don't want too many sliders, but if it's not working correctly, I guess I could make a "Sound volume slider" that controls both the sound and the ambient sound. Then I would have the music on one slider and all the sounds on a separate sliders.
Dreams in the Witch House on Steam & GOG

Laura Hunt

#16
Quote from: rongel on Fri 12/02/2021 17:27:55
Quote from: Vincent on Fri 12/02/2021 16:57:34
I don't have a clue about this but I was thinking that instead having a System.Volume you can split each type of sound separately like for music, sound, speech and ambient sound.

Thanks for the suggestion! I like the idea of the Master Volume and don't want too many sliders, but if it's not working correctly, I guess I could make a "Sound volume slider" that controls both the sound and the ambient sound. Then I would have the music on one slider and all the sounds on a separate sliders.

The problem with this approach is that moving the "sounds" slider does not respect their relative values but instead sets them all to the same volume. I would in fact suggest the opposite: using only a Global Volume slider, which acts as a true master and treats all sounds as percentages of the total.

(This is a well-known issue with the AGS audio system: https://www.adventuregamestudio.co.uk/forums/index.php?topic=58464.0 or https://www.adventuregamestudio.co.uk/forums/index.php?topic=54251.0)

rongel

QuoteThe problem with this approach is that moving the "sounds" slider does not respect their relative values but instead sets them all to the same volume.

Yes, I think this would work if all the sound clips are played at the default volume. So each sound clip has to be at correct volume when importing them into the game. It is a quite big downside that you couldn't adjust the volume clips individually.
Dreams in the Witch House on Steam & GOG

Vincent

Maybe there would be a problem also if you only have a generic slider for the master volume, if I got that right, because if someone wants to hear only the sound without the music or viceversa which maybe they find boring then they can't do that cause they only have a master volume for everything. Between the two things personally I would prefer having more control for each type of sound even though their relative values can be messed up but that's all your choice

Laura Hunt

Quote from: Vincent on Fri 12/02/2021 19:01:50
Maybe there would be a problem also if you only have a generic slider for the master volume, if I got that right, because if someone wants to hear only the sound without the music or viceversa which maybe they find boring then they can't do that cause they only have a master volume for everything. Between the two things personally I would prefer having more control for each type of sound even though their relative values can be messed up but that's all your choice

Oh yes, that's definitely a design decision on my part. I want players to hear the soundscape that I've designed, with the "correct" balance of music and other sounds, so all technical issues aside, I simply do not want to give them control over that. Definitely a personal choice!

SMF spam blocked by CleanTalk