Bug in Game.ChangeTranslation("") ?

Started by Monsieur OUXX, Sun 24/05/2020 11:07:30

Previous topic - Next topic

Monsieur OUXX

With 3.5.0.24

Scenario (5 minutes to reproduce) :


- Create an empty AGS game (game1.ags)
- Create another empty AGS game (game2.ags)
- Copy game1.ags into the Compiled folder of game2.
- In game2, create one translation file : "whatever.tra". Just translate one line and compile that language, for test's sake.
- in game_start of game2.ags, Add this instruction : Game.ChangeTranslation("whatever");
   Now we know that no matter what language was chosen in winsetup.exe, it then immediately changes to "whatever"
- in room_AfterFadeIn() of game2's first room, add these instructions :
Code: ags

    bool result = Game.ChangeTranslation(""); //As per documentation, reset to default language
    if (!result) {
      Display("Cannot revert to default language."));
    }
    if (Game.TranslationFilename != "") {
      Display(String.Format(The current translation should be (empty string), instead it's '%s'."), Game.TranslationFilename));
    }
    RunAGSGame("game1.ags", 0, 0);

    Now we know that regardless of what language was chosen as default language in winsetup.exe, and regardless of which language is set programmatically at startup, the language should still be "" just before the call to RunAGSGame

Now the core of the scenario :

- Build the EXE. Go to Compiled. Run game2.exe
  => This is the first execution. The selected language in winsetup.exe is "Default language". The call to RunAGSGame succeeds because when game1 starts, it detects that the current language is "".
- exit the game.
  => Now you will notice that if you start winsetup.exe, the startup language has changed to "whatever" because the engine remembers. OK, why not.
- Start game2.exe again.
  => The game starts with "whatever" (because of winsetup.exe) and immediately switches to "whatever" programmatically (because of game_start). => OK
  => In AfterFadeIn, Game.ChangeTranslation("") succeeds. => OK
  => The game does not enter if (Game.TranslationFilename != "") {. => OK
  => RunAGSGame call happens => OK
  => game1's startup crashes with error message "Failed to read translation file 'whatever.tra'". Why is it trying to read whatever.tra even though we just switched to "" ?

The issue lies in the fact that the engine "remembers" the language that was selected the last time the game exited as the "default language".
In this situation, I don't know how to switch from one game to another if they don't share mutual translation files (same names, same strings, same set of languages)
In other words: I don't know how to revert to "default language" which was supposed to remain "" and be a common, neutral language (i.e. a language that tells the game to use its own strings instead of reading them from any .tra file)
 

Crimson Wizard

#1
This is not a bug in Game.ChangeTranslation as it is merely switching current runtime language. This may be an issue with how engine writes last chosen language in config, and whether it does at all when calling RunAGSGame.
Also, there may be an issue of engine lacking a safe fallback on startup in case current tra is missing (guess it must switch to default language).

I will have to build the test case and see what's going on there.

PS. Of course, the general problem may be that both games share same config file to the last option. RunAGSGame mechanic is very old and may need a redesign too, as well as other related things (for example, IIRC you cannot have separate *.vox files for each game if they are in a bundle).

Monsieur OUXX

Everything you wrote is correct.

The weird thing (to me) is really that Game.ChangeTranslation("") succeeds, but a moment later the engine is still looking for whatever.tra.
I think there's an overlap between "current translation", "defaut language" and "last saved language".
 

Crimson Wizard

#3
Quote from: Monsieur OUXX on Sun 24/05/2020 15:22:11
The weird thing (to me) is really that Game.ChangeTranslation("") succeeds, but a moment later the engine is still looking for whatever.tra.

That's because engine ChangeTranslation was called in one game, and engine runs next one, which does its own initialization at startup. These are unrelated steps.
EDIT: actually, I am not sure this is exactly what happens, need to double check everything.

Quote from: Monsieur OUXX on Sun 24/05/2020 15:22:11
I think there's an overlap between "current translation", "defaut language" and "last saved language".

I don't know what you mean by this. Default is always same default (no TRA).

Also, I am not sure I understand how does not it find "whatever.tra" if it lies in same folder. This may be a separate problem. I will have to built this test case first.

Monsieur OUXX

Quote from: Crimson Wizard on Sun 24/05/2020 15:31:38
I am not sure I understand how does not it find "whatever.tra" if it lies in same folder.

The engine finds it, but has a mechanism to detect that it was generated for the other game. So it finds it but rejects it.

Quote from: Crimson Wizard on Sun 24/05/2020 15:31:38
ChangeTranslation was called in game2, but then game1 does its own initialization at startup.
Yes but it means that game1 reads which language it should boot with from acsetup.cfg. And that's problematic because:
- I can change the current language with an instruction. That happens instantaneously,
- but the language in acsetup.cfg gets changed against my will, and with a delay (at exit time). I have no control over that. The language selected in a previous session of game2 determines what language game1 will try to start with in the current session.

As always, thanks a lot for taking the time of answering. Now you have all the facts.
 

Crimson Wizard

#5
Quote from: Monsieur OUXX on Sun 24/05/2020 15:59:22
Yes but it means that game1 reads which language it should boot with from acsetup.cfg. And that's problematic because:
- I can change the current language with an instruction. That happens instantaneously,
- but the language in acsetup.cfg gets changed against my will, and with a delay (at exit time). I have no control over that. The language selected in a previous session of game2 determines what language game1 will try to start with in the current session.

At exit it should write down whatever you set ChangeTranslation to last. More likely, on contrary, config is not modified on RunAGSGame at all, and then config has what was set at last normal exit.
If this is so, then this is merely a matter of saving current user config before running a different game.

EDIT: it's turned out to be different, neither config is saved nor last translation set at runtime is applied when running next game, instead it applies translation setting loaded from config when the engine just started up. Maybe this was broken during many iterations of the engine and never noticed until now.


Monsieur OUXX

 

Crimson Wizard

No, on second thought something is not right here.

Like you say, game A cannot read translation files made for game B and vice versa.
While game B is running you won't be able to set any translation for game A, because game B will refuse to initialize them. Default translation ("") works simply because there's "default" in any game.

But this means that neither ChangeTranslation neither config from game B should be applied for game A at all. What's the point if you must run ChangeTranslation("") before RunAGSGame to simply make it run? Perhaps, better make RunAGSGame reset translation to default on its own?

How translation setting is supposed to work anyway in case there are two games bundled together? I'd rather find old developers who used RunAGSGame earlier to know what was the expected behavior in this case.

Monsieur OUXX

#9
I need to test more but I'm 90% sure that your patch fixed my issue.

Quote from: Crimson Wizard on Mon 25/05/2020 11:16:37
Default translation ("") works simply because there's "default" in any game.
Well that's what I was hoping and that's the scenario I indentified as the only one that could possible work. I wasn't hoping for more.

Quote from: Crimson Wizard on Mon 25/05/2020 11:16:37
But this means that neither ChangeTranslation neither config from game B should be applied for game A at all. What's the point if you must run ChangeTranslation("") before RunAGSGame to simply make it run? Perhaps, better make RunAGSGame reset translation to default on its own?
How translation setting is supposed to work anyway in case there are two games bundled together? I'd rather find old developers who used RunAGSGame earlier to know what was the expected behavior in this case.
I think that you're entering a dangerous realm here; Indeed the language setting should be even more restrictive, but do we really want that? It increases the risk of you making a mistake on engine-development end, and the risk of the game maker making a mistake on their end.
That being said, you just made me realize that it's unclear to me what ends up in acsetup.cfg after I quit the embedded game. But my code now works with your patched engine.


Here is how I do it (this is currently implemented in my game, and works) :

Quote
Solution for a normal game (no "RunAGSGame") :


- Make the end-user use winsetup.exe if they know about it
  => If they don't, then at first startup "game default" is selected
  => If they do, then at first startup the language is the one they selected
- When the game quits the language hasn't changed and remains the same in acsetup.cfg until next startup


Quote
Solution for a normal game (no "RunAGSGame") that lets the payer choose the language in-game :

- in game_start, the game tests the value of the current translation. If it's "" it means that the player didn't explicitly pick a language.
- Depending on that value and how much we want the player to choose, then :
   => No matter what the player has selected in winsetup.exe, the game immediately does a Game.ChangeTranslation("") at startup
   => The game displays a custom GUI asking to pick a language
   => If the user picks English, then we do Game.ChangeTranslation("English") to be able to tell the difference with "".
         Note: One extra benefit of having an explicit "English" .tra file is that the Tumbleweed and 9verb modules rely on a GUI_LANGUAGE entry that must be translated to "en" in English.tra.
- When the game quits the language is remembered in acsetup.cfg until next startup, so we can decide not to display the languageselection GUI at next startup


Quote
Solution for a game containing another game (uses "RunAGSGame"):

- we forbid the access to winsetup.exe. A game that starts for the first time with something else than "game default" is considered corrupt.
  The reason for that is that winsetup.exe displays the list of .TRA files for both games. If the parent game has "English" and the child game has "EN", then you will see both in the list.
  If the player is a smart arse and tries to force-pick a .TRA entry belonging to the child game, then the game will crash at startup anyways (built-in AGS engine check).

- As an extra safety, we do Game.ChangeTranslation("") in game_start but I'm not even sure that's needed.
- in game_start, the game reads the value of the language in a custom .ini file.
  => If the value does not exist or is not recognized as a correct value for the parent game, then the game displays the "select language" custom GUI
  => We update that value in the .ini file
  => We go Game.ChangeTranslation based on that value.
- Just before calling RunAGSGame, we do Game.ChangeTranslation(""). Thanks to your patch, the child game knows to start with "" and doesn't get confused with the parent's .TRA files.
   => For convenience, in the child game we display the custom language seection screen every time, but we could totally save it into a .ini file too.
- When any of these games exit, then some value is saved in acsetup.cfg
  => I don't care what the value is because the mechanisms described above help me work around it.
 

Crimson Wizard

#10
Quote from: Monsieur OUXX on Mon 25/05/2020 12:18:45
I need to test more but I'm 90% sure that your patch fixed my issue.

I maybe fixed it for your private case, but I doubt if that's good for a general solution, so I am probably goind to cancel it.


Quote from: Monsieur OUXX on Mon 25/05/2020 12:18:45I think that you're entering a dangerous realm here; Indeed the language setting should be even more restrictive, but do we really want that? It increases the risk of you making a mistake on engine-development end, and the risk of the game maker making a mistake on their end.

I am not sure we understand each other.

What I am saying is: right now - with my "fix" - for the next game to start successfully game developer is required to call ChangeTranslation before RunAGSGame. With my current fix it increases the risk of game maker making a mistake (what you were fearing) instead of decreasing it.
If next game cannot have same translation set, and parent game cannot tell it which to set beforehand, so it's only logical that the engine should reset translation to default before running the next game, not requiring user to script ChangeTranslation("").
At least in current situation, when both games are destined to use same config, because of how limited this feature is.



Quote from: Monsieur OUXX on Mon 25/05/2020 12:18:45
- we forbid the access to winsetup.exe. A game that starts for the first time with something else than "game default" is considered corrupt.
  The reason for that is that winsetup.exe displays the list of .TRA files for both games. If the parent game has "English" and the child game has "EN", then you will see both in the list.

This means there's a mistake in winsetup that should be fixed: it should test whether TRA belongs to the current game.

Monsieur OUXX

Quote from: Monsieur OUXX on Mon 25/05/2020 12:18:45
This means there's a mistake in winsetup that should be fixed: it should test whether TRA belongs to the current game.

Yes.
A more general fix would be for winsetup to know what exe it targets, what .cfg file it uses, and what .tra entries it offers. The central issue is that winsetup is a generic program that's meant to autodetect everything in the same folder. If you start making winsetup specific to one game, then you create new constraints.
 

Crimson Wizard

#12
Quote from: Monsieur OUXX on Mon 25/05/2020 14:25:55
A more general fix would be for winsetup to know what exe it targets, what .cfg file it uses,...

But it does know that.
Winsetup.exe is simply a shell executor. It does not detect anything, the game exe name is written into it. It calls "game.exe --setup", and it is engine inside game.exe that detects the game data, and then knowing the game it finds its configs according to certain rules, and so forth.
At the moment when setup dialog opens, it already knows everything about the game, it's name, and most of its general settings.

Unless I misunderstood what you mean, in which case please elaborate...

Quote from: Monsieur OUXX on Mon 25/05/2020 14:25:55
The central issue is that winsetup is a generic program that's meant to autodetect everything in the same folder. If you start making winsetup specific to one game, then you create new constraints.

Not sure I understand this, are you saying that generic winsetup is good or bad?

Cassiebsg

#13
I don't like the "we forbid the access to winsetup.exe" option...  :-\ That's the first thing I run in any AGS game! And I will not play any game that doesn't provide it.

Quote
This means there's a mistake in winsetup that should be fixed: it should test whether TRA belongs to the current game.

(nod) This would be a very good fix. Specially since the TRA provides the game name to which it belongs.
Maybe if this was fixed then it would be possible to run  RunAGSGame, with it's own translation set as well...  ???  :-D Would be cool to be able to do something like RunAGSGame(game.exe, english);  ;)
There are those who believe that life here began out there...

Crimson Wizard

#14
Quote from: Cassiebsg on Mon 25/05/2020 19:26:00
I don't like the "we forbid the access to winsetup.exe" option...  :-\ That's the first thing I run in any AGS game! And I will not play any game that doesn't provide it.

Monsieur OUXX probably means they have custom setup/launcher program. Number of games had in the past.


Quote from: Cassiebsg on Mon 25/05/2020 19:26:00
This would be a very good fix. Specially since the TRA provides the game name to which it belongs.
Maybe if this was fixed then it would be possible to run  RunAGSGame, with it's own translation set as well... 

But there's no relation between these two.  ???

Cassiebsg

I don't understand "there's no relation between these two"... what do you mean?

Right now you can't run a game (game B) inside another game with translation (game A), because game B will try and load the TRA from game A and then crash.
If I had a file called GameA_Eng.TRA and GameB_Eng.TRA and  RunAGSGame would not go and pick GameA_Eng for game B translation file; then there's a chance that one could run GameB with it's own translation, no? Right now, the only option is to set the language to default at then launch Game B.

And apparently  RunAGSGame already have a setting to carry GlobalInt from game A to game B... so telling it to carry also what language to use when running, should be in the realm of possibilities, no?
There are those who believe that life here began out there...

Crimson Wizard

#16
Quote from: Cassiebsg on Mon 25/05/2020 21:43:33
I don't understand "there's no relation between these two"... what do you mean?

I mean that there is no relation between proposed winsetup fix and RunAGSGame (telling next game what language it should use). Fixing first is not required to do second.

Cassiebsg

Oh, that. I know.  (nod)

But fixing first, allows for second possibility.  ;)
There are those who believe that life here began out there...

Crimson Wizard

I don't know if there's any reason to pass language to RunAGSGame, or whether that's a good thing to pass extra variables at all. Currently it's possible to do through a custom file, and that way you can pass any amount of data you need, then initialize it at startup in the called game.

Monsieur OUXX

Quote from: Crimson Wizard on Mon 25/05/2020 15:04:47
Quote from: Monsieur OUXX on Mon 25/05/2020 14:25:55
A more general fix would be for winsetup to know what exe it targets, what .cfg file it uses,...

But it does know that.
It knows the .exe but it doesn't know which .cfg and which .tra to use. Or at least I thought so.

Quote from: Crimson Wizard on Mon 25/05/2020 15:04:47
Not sure I understand this, are you saying that generic winsetup is good or bad?
It's good! But it becomes bad if it gets confused with the settings (again: because it can't tell which .tra files are meant for it and just displays all of them).


Quote from: Cassiebsg on Mon 25/05/2020 19:26:00
I don't like the "we forbid the access to winsetup.exe" option...  :-\ That's the first thing I run in any AGS game! And I will not play any game that doesn't provide it.
The only reason we do that is because of this issue with the translations. Cassiebsg you didn't see that but that's already how it worked in Relic of the Viking 1.0 : All the translations (both for the parent game and the embedded game) appear in the list, that's an issue.
Of course we don't really "forbid" the access to winsetup.exe. We just hide it a little bit to not encourage people who have no idea what they're doing to mess up their settings and be locked out of the game.

Like everyone has said before, there are two ways out of this :
1) Fix the TRA issue in winsetup.exe -- that one I'm not demanding because this is a very specific scenario (very few people have an embedded game and translations!).
OR
2) Use a custom setup programs. That's on my TODO list anyways so I'm OK with it (I'll use eeri0o's program).
 

SMF spam blocked by CleanTalk