Description
Issue #239 reported that manually setting quest.desc or game.objective gets overwritten by the text generation process during build()/compile(). PR #240 added a fix that copies _objective from a previous build before change_grammar() runs.
However, the fix is incomplete. In build(), the copy happens at line 788-789 beforechange_grammar() is called at line 803. change_grammar() then unconditionally overwrites the objective at line 460 of game.py:
self.objective=describe_event(Event(policy), self, self.grammar)
This means the preserved objective gets clobbered whenever the game has quests with a winning policy (i.e. most games).
The test added in PR #240 (test_manually_defined_objective) only tests a game with no quests, so it doesn't catch this.
Steps to Reproduce
importtextworldfromtextworldimportGameMakerM=GameMaker()
r1=M.new_room("bedroom")
M.set_player(r1)
key=M.new(type="k", name="key", desc="This is a skeleton key.")
r1.add(key)
quest=M.set_quest_from_commands(["take key"])
game=M.build()
game.objective="Find a valuable object."game_file=M.compile("/tmp/test_game.z8")
# Load and check - the objective has been overwrittenloaded=textworld.Game.load("/tmp/test_game.json")
assertloaded.objective=="Find a valuable object.", f"Expected custom objective, got: {loaded.objective[:80]}..."The assertion fails because change_grammar() in the second build() (triggered by compile()) overwrites the objective with auto-generated text.
Proposed Fix
In game.py, change_grammar() should only set the objective if one hasn't already been set:
# Before (line 460):self.objective=describe_event(Event(policy), self, self.grammar)
# After:ifself._objectiveisNone:
self.objective=describe_event(Event(policy), self, self.grammar)
Workaround
Until this is fixed, you can work around it by calling M.build(), setting game.objective, then compiling manually with textworld.generator.compile_game(game, options) instead of M.compile().
Environment
- TextWorld 1.7.0
- Python 3.12
- macOS
Description
Issue #239 reported that manually setting
quest.descorgame.objectivegets overwritten by the text generation process duringbuild()/compile(). PR #240 added a fix that copies_objectivefrom a previous build beforechange_grammar()runs.However, the fix is incomplete. In
build(), the copy happens at line 788-789 beforechange_grammar()is called at line 803.change_grammar()then unconditionally overwrites the objective at line 460 ofgame.py:This means the preserved objective gets clobbered whenever the game has quests with a winning policy (i.e. most games).
The test added in PR #240 (
test_manually_defined_objective) only tests a game with no quests, so it doesn't catch this.Steps to Reproduce
The assertion fails because
change_grammar()in the secondbuild()(triggered bycompile()) overwrites the objective with auto-generated text.Proposed Fix
In
game.py,change_grammar()should only set the objective if one hasn't already been set:Workaround
Until this is fixed, you can work around it by calling
M.build(), settinggame.objective, then compiling manually withtextworld.generator.compile_game(game, options)instead ofM.compile().Environment