Open World ~ Deciding an integration approach - uchicago-cs/chiventure GitHub Wiki
Current Integration Status:
2022 Team... We're updating the game struct to prepare for integration in the future.
We've added the gencontext_t and levelspec_t structs in the game_t struct in game-state. Gencontext_t carries information necessary for the generation algorithm and levelspec_t holds information necessary for level-oriented generation. This way we can implement autogeneration dynamically since the game will keep pulling on these two structs which will be continuously updated. Including the two structs in game_t separately also gives us the flexibility to implement both level-oriented and non-level-oriented generation.
Last year's team writes... “As of right now, chiventure can only use the openworld module if it is "monkey-patched" in.” In order for it to be truly integrated into chiventure, we “require more implementation and connection to other chiventure features such as: cli, actionmanagement and npc.”
Why is monkey patching bad?
- It can lead to upgrade problems if the patch makes assumptions about the game that are no longer true, causing the game to ‘break’
- It could overwrite actions by other modules, creating discrepancy between original source code and observed behavior (more difficult to test and debug; confusing to people unaware of patch)
Proposed Integration Approaches
Last year’s team suggested the following approaches:
- Lazy: Triggering auto generation when a player enters a room.
- Eager: Triggering auto generation on chiventure startup.
- Parsing: Using a WDL trigger to auto generation
We thought that 1 and 2 could be placed into slightly broader categories:
- Dynamic: Generation occurs during (and throughout) the execution of the game
- Static: Generation occurs before game execution (worlds are pre-built)
- Parsing: Using a WDL trigger to auto generation
Evaluating each approach
1. Dynamic Generation
Pros
- Faster game start-up because fewer rooms will be loaded
- Lower memory requirement since new sections of the map are generated only when the player is in close proximity
- Flexible: can respond to changes in game state (e.g. we might want to generate rooms corresponding to player stats, which would evolve throughout the game)
- Using procedural generation, we can create very large or infinite maps which cannot be feasibly designed pre-execution
Cons
- More complex dependencies with other modules because generation is intimately linked with player position/action
- Longer load time when entering new rooms–– ‘lag’ due to generation procedure
2. Static Generation
Pros
- Negligible load time when entering adjacent rooms–– smoother gameplay
- More control over final product; emphasis on human design
- More efficient in games in which rooms do not change throughout play or for smaller maps that are easily stored in memory
- May be needed when inserting fixed landmarks/locations
Cons
- Slower game start-up because it generates all the rooms as soon as the game starts
- Higher memory requirement
- Rigid: cannot respond to changes in game state
- Finite map space
3. Parsing
Pros
- Improves customization–– allowing specific rooms to be loaded in specific conditions; would be ideal for game authorship (though this is a more long-term goal)
- Can generate rooms for testing frameworks
Cons
- More work to implement; will require extra coordination with WDL/WDL++ teams
- No real functional downside
Final approach/Priority List:
Each of the three methods have highly desirable features that make a combined approach appealing. Since a good game engine would be able to cater to different games, we would like game authors to have the ability to decide between or use a combination of generation methods. Using a combined approach for world generation is actually quite normal. For example: Hades stitches together pre-built rooms (static) in a highly randomized manner to create different runs (dynamic); however, there are fixed locations/landmarks (static) that you are guaranteed to encounter in each run.
We think it’s practical to start with a static generation framework because it’s the simplest to implement–– it loads the entire map just once during setup. It would be our fastest way to integrate openworld into chiventure.
Our next objective would be to work on a dynamic generation framework because it offers a natural segue into many exciting features/possibilities like:
- Procedural generation, which is the usage of algorithms (not human design) to automate world generation (c.f. minecraft) Note: As maps become large (or even infinite), we might need to consider ways to unload/optimize room storage.
- Game-state dependent world generation (e.g. Dynamically generating more difficult rooms as player stats increase)
However, with a multi-method approach, we would need to be more cautious about interactions between methods. Some questions that we might consider:
- Do we want parsing/dynamic generation to overwrite pre-built rooms?
- How will we assign priority/toggle between different methods?