Skip to content

Commit

Permalink
Pack manifests and metadata are now also loaded too.
Browse files Browse the repository at this point in the history
- This means content can now also be fetched from these packs.
- This has not been properly tested yet.
  • Loading branch information
Espyo committed Nov 7, 2024
1 parent ce7f2f1 commit efb17ee
Show file tree
Hide file tree
Showing 15 changed files with 237 additions and 24 deletions.
66 changes: 49 additions & 17 deletions source/documents/todo.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
Point I left on (so I can continue the next day without losing my train of thought)
Point I left on (so I can continue the next day without losing my train of thought)


Current tasks (tasks being worked on, but not yet committed)

Editor load dialogs
Load dialog should have:
History
A button to create, which opens a new dialog
Selection of items
A way to show what pack it's from
A search filter, which is highlighted by default when the dialog opens
If you choose the base pack, complain
For loading, each editor has:
Anim: globals, mobs per category
Area: simple, mission
GUI: one list
Particle: one list
For creating, each editor needs:
Common: internal name, pack, highlight name red if it already exists in this pack
Anim: (global only) common
Area: common + type
GUI: N/A (allow copying to a different pack instead?)
Particle: common
Pack creation dialog
Ask the internal name (highlight red if it already exists)
Ask maker, name, etc.
Note saying how you can change this later by editing X.txt
If you chose the base pack, complain


Next tasks (roughly sorted most important first)
--- To fix ---
Expand All @@ -14,7 +38,7 @@ Next tasks (roughly sorted most important first)
Test -S-'s get_onion_info branch
Check Helodity's particle editor
https://github.com/Helodity/Pikifen/tree/throwing-improvements
Update to Dear ImGui 1.91.4
Update to Dear ImGui 1.91.5
Implement shortcuts?
Use multi-selection in the body part panel of the animation editor?
GetWindowContentRegionMax().x + GetWindowPos().x --> GetCursorScreenPos().x + GetContentRegionAvail().x
Expand Down Expand Up @@ -155,6 +179,7 @@ Next tasks (roughly sorted most important first)
Pikmin movement and other actions should have random offsets and delays of tiny amounts, just so that the army feels like a group of individuals, instead of several robots
New mobs
Burrowing Snagret
Bulbears
A tall grass mob
Nuggets
Add Helodity's Plasm Wraith
Expand Down Expand Up @@ -197,40 +222,46 @@ Next tasks (roughly sorted most important first)
Find some way of making content sharing easier
The idea
The Game_data folder should have a "base" folder where everything goes, and people can make their own folders for their own content. Then, they simply share that folder
Some sort of data.txt where you can write the author, version, engine version, what other packages it depends on (including optionally specific versions), what packages it's incompatible with, license
Some sort of data.txt where you can write the author, version, engine version, what other packs it depends on (including optionally specific versions), what packs it's incompatible with, license
Problems with the current way of doing things "by hand"
When makers want to share their content, they have to fish its requirements from several folders
When players want to install content, they have to place it in the right folders
Implementation
Loading
When the game needs something to exist in memory, it calls the content manager to load it
Content manager is responsible for loading all X into memory, or a specific X, plus performance monitor and packages logic
Content manager is responsible for loading all X into memory, or a specific X, plus performance monitor and packs logic
The content's class is responsible only for being fed a data node and to load stuff from it
All content will need to be able to:
Load from the base folder first and then from all packages, in alphabetical order
Load from the base folder first and then from all packs, in alphabetical order
Load resources or not, based on the boolean given
Check if content by that name already exists, and if so report it
Unload
Make assets inherit from the plain_content class?
Add the new common content properties to everything in the engine
Internal names should be sanitized
Editors should separate creating and loading
Editors should have a unified dialog (in the editor class) that can create a new package, with some basic fields, and some text saying how you can change this later by editing game_data/<package name>/data.txt
Editors should warn if you try to edit or create something in the base package, saying how it'll affect the usual experience, may affect all packages, and will make it harder for you to share stuff in the future. Are you sure? This dialog shouldn't appear if, in the options, engine_developer = true
Editors should have a unified dialog (in the editor class) that can create a new pack, with some basic fields, and some text saying how you can change this later by editing game_data/<pack name>/data.txt
Editors should warn if you try to edit or create something in the base pack, saying how it'll affect the usual experience, may affect all packs, and will make it harder for you to share stuff in the future. Are you sure? This dialog shouldn't appear if, in the options, engine_developer = true
Allow pack thumbnails
Other info
Right now, this is how each type of content works:
One per file: global anims, sounds, songs, graphics, GUI, hazards, liquids, particle generators, spike damage types, sprays, statuses, weather
Other ways: areas, mob types
Problems to watch out for
How do you create packages that extend scripts, or replace parameters in existing mobs or the game config?
How do you choose what package, if any, do you create a new area/animation/GUI setting in when you're in an editor?
How do you create packs that extend scripts, or replace parameters in existing mobs or the game config?
How do you choose what pack, if any, do you create a new area/animation/GUI setting in when you're in an editor?
What should happen when the player opens the texture selection dialog in the area editor?
Area backups should be saved on a sub-folder matching the package
Area backups should be saved on a sub-folder matching the pack
When it's all done
Organize the performance monitor start/end points
Run a memory leak check
Test editing every single piece of content, both in the base package, and in a new package
Test editing every single piece of content, both in the base pack, and in a new pack
For later on, maybe, the content manager should be able to figure out a dependency tree
Find a way to manage the installed packs
Players should be able to choose which ones are enabled or disabled, and their load order
The load order (bottom first vs. top first) should be explained
It should also show and/or explain in some way how there's the base content
When enabling, disabling, or re-ordering, a notification should appear saying how the game may need to be restarted
There should be a button to open the packs folder
Missions should have a property where the maker can specify their best score (and date)
Add a screenshot, or better yet, a gif to the readme
Update screenshots in the manual that still show off the Play area
Expand Down Expand Up @@ -258,7 +289,7 @@ Next tasks (roughly sorted most important first)

--- Future ---
A way to port content from previous versions
It could check each loaded package's engine version, and if there are known breaking changes, tell the user about it. If it's possible to auto-port, ask the user if they want to do so, and just run some simple code to port it, mostly via find-and-replace (if instead you load and save data files you risk ruining spacing and comments)
It could check each loaded pack's engine version, and if there are known breaking changes, tell the user about it. If it's possible to auto-port, ask the user if they want to do so, and just run some simple code to port it, mostly via find-and-replace (if instead you load and save data files you risk ruining spacing and comments)
Some tweaks to the HUD
Shrink some element sizes -- HUD elements in P1 and P2 used to be chunky because of the televisions back then, but Pikmin 3 lowered their sizes a bit, so maybe I can do the same
Prefer populating corners over populating sides/bottom/top
Expand Down Expand Up @@ -292,7 +323,8 @@ Next tasks (roughly sorted most important first)
The ability to load TTF fonts
[NEEDS BRAINSTORMING] Should the secondary menus from the main menu also contain Pikmin formations in the background?
Allow the player to drag their mouse on the scrollbar GUI item
In the results menu, show by how much you've beaten your previous best score
Results menu
Show a chart with the requirements for each medal, your current run's score, your personal record score, and the maker's personal record score
The difficulty listing in the area menu should use fire icons instead of numbers
The code that determines what GUI item to go to via keyboard navigation isn't working so well for stuff inside box GUI items. In the results menu, with a mission with a lot of stuff in the stats, select "Retry" and press right. It'll select an unrelated item in the stats list
Here's an idea: items that are inside of a scrollable box but are currently not visible should be considered as being outside the box, but with an ultra-tiny offset. For instance, a GUI item that spans from Y=10 to Y=50 on-screen and is a vertical list of buttons. The buttons currently visible on-screen inside this item are at Y=15, Y=25, Y=35, and Y=45. The next three buttons would technically be at Y=55, Y=65, and Y=75, but they're not applicable because they're beyond the bounds of the list GUI item. When calculating their position for the sake of keyboard navigation, just pretend their coordinates are at Y=50 (bottom of the list item) + 0.001 for the first item, 0.002 for the second item, 0.003 for the third. To keep relative dimensions intact, which may be a good idea, it's probably best to grab their offset from the bottom of the list item (so 55-50=5 for the first, 65-50=15 for the second, 75-50=25 for the third) and multiply them by 0.001.
Expand Down Expand Up @@ -320,7 +352,7 @@ Next tasks (roughly sorted most important first)
The player only edits and creates control schemes, like the list of saved rulesets in Smash Ultimate
When assigning an input to an action, if it's a controller, also save a controller placeholder number, which can be changed in this menu
A button or text or something explaining that this is just a control scheme, and if you want to assign it to player 1, go to the player setup menu
It should come pre-packaged with a few schemes: "Keyboard+Mouse and Pro Controller" (default), "Keyboard+Mouse", "Single Joy-Con", etc.
It should come pre-packed with a few schemes: "Keyboard+Mouse and Pro Controller" (default), "Keyboard+Mouse", "Single Joy-Con", etc.
Confirm that these work both on Linux and on Windows
If the player assigns an input that is already assigned to something else, it should give a warning
If the player leaves the menu but some important actions don't have input binds, it should give a warning. Important actions are like throwing and whistling, not something like changing the leader backward
Expand Down Expand Up @@ -629,7 +661,7 @@ Next tasks (roughly sorted most important first)
Wild Pikmin and sprouts should be immune to the sunset
Catalogs
There can be multiple catalogs -- Piklopedia and Treasure Hoard are two different catalogs
A file, likely game_data/<package>/misc/catalogs.txt is responsible for:
A file, likely game_data/<pack>/misc/catalogs.txt is responsible for:
Which catalogs exist, as well as their icons, unlock criteria, etc.
What entries exist in each, in order
What logs each entry contains (Olimar's notes, Louie's notes, Sales pitch, etc.)
Expand Down
3 changes: 3 additions & 0 deletions source/source/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ const string MAKER_TOOLS = "tools.txt";
//Options file.
const string OPTIONS = "options.txt";

//Pack data file.
const string PACK_DATA = "data.txt";

//Performance log file.
const string PERFORMANCE_LOG = "performance_log.txt";

Expand Down
37 changes: 37 additions & 0 deletions source/source/content.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,40 @@ class content : public plain_content {
void save_metadata_to_data_node(data_node* node) const;

};


/**
* @brief Data about an installed pack.
*/
struct pack {

//--- Members ---

//Optional player/maker-facing name.
string name;

//Optional description.
string description;

//Optional tags, separated by semicolon.
string tags;

//Optional person(s) who made it.
string maker;

//Optional version name or number.
string version;

//Optional version of the engine it was made for.
string engine_version;

//Optional list of packs it depends on, separated by semicolon.
string dependencies;

//Optional list of packs it conflicts with.
string conflicts;

//Optional notes of any kind.
string notes;

};
83 changes: 83 additions & 0 deletions source/source/content_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#include "functions.h"
#include "game.h"
#include "load.h"
#include "utils/allegro_utils.h"


/**
Expand Down Expand Up @@ -153,6 +155,16 @@ void content_manager::load_area_as_current(
}


/**
* @brief Loads all packs.
* This only loads their manifests and metadata, not their content!
*/
void content_manager::load_packs() {
packs.fill_manifests();
packs.load_all();
}


/**
* @brief Unloads the "current area".
*
Expand Down Expand Up @@ -187,3 +199,74 @@ void content_manager::unload_all(const vector<CONTENT_TYPE> &types) {
load_levels[types[t]] = CONTENT_LOAD_LEVEL_UNLOADED;
}
}


/**
* @brief Unloads all packs.
* This only unloads their metadata and manifests, not their content!
*/
void content_manager::unload_packs() {
packs.clear_manifests();
packs.unload_all();
}


/**
* @brief Clears all loaded manifests.
*/
void pack_manager::clear_manifests() {
manifests.clear();
}


/**
* @brief Fills in the manifests.
*/
void pack_manager::fill_manifests() {
vector<string> folders = folder_to_vector(FOLDER_PATHS_FROM_ROOT::GAME_DATA, true);

for(size_t f = 0; f < folders.size(); f++) {
if(folders[f] != FOLDER_NAMES::BASE_PACK) {
manifests.push_back(folders[f]);
}
}
}


/**
* @brief Loads all packs in the manifests.
* This only loads their metadata, not their content!
*/
void pack_manager::load_all() {
for(size_t p = 0; p < manifests.size(); p++) {
data_node pack_file =
load_data_file(
FOLDER_PATHS_FROM_ROOT::GAME_DATA + "/" +
manifests[p] + "/" +
FILE_NAMES::PACK_DATA
);

pack pack_data;
reader_setter rs(&pack_file);
rs.set("name", pack_data.name);
rs.set("description", pack_data.description);
rs.set("tags", pack_data.tags);
rs.set("maker", pack_data.maker);
rs.set("version", pack_data.version);
rs.set("engine_version", pack_data.engine_version);
rs.set("dependencies", pack_data.dependencies);
rs.set("conflicts", pack_data.conflicts);
rs.set("notes", pack_data.notes);

list[manifests[p]] = pack_data;
}
}


/**
* @brief Unloads all loaded packs.
* This only unloads their metadata, not their content!
*/
void pack_manager::unload_all() {
list.clear();
}
28 changes: 28 additions & 0 deletions source/source/content_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,29 @@ using std::map;
using std::string;


/**
* @brief Manages everything regarding the installed game content packs.
*/
struct pack_manager {

//--- Members ---

//Manifests.
vector<string> manifests;

//List of loaded packs.
map<string, pack> list;

//--- Function declarations ---

void clear_manifests();
void fill_manifests();
void load_all();
void unload_all();

};


/**
* @brief Manages everything regarding game content, be it assets, types of
* mobs, etc.
Expand Down Expand Up @@ -79,6 +102,9 @@ struct content_manager {
//Weather conditions.
weather_condition_content_manager weather_conditions;

//Packs.
pack_manager packs;


//--- Function declarations ---

Expand All @@ -88,8 +114,10 @@ struct content_manager {
CONTENT_LOAD_LEVEL level, bool from_backup
);
void load_all(const vector<CONTENT_TYPE> &types, CONTENT_LOAD_LEVEL level);
void load_packs();
void unload_all(const vector<CONTENT_TYPE> &types);
void unload_current_area(CONTENT_LOAD_LEVEL level);
void unload_packs();

private:

Expand Down
25 changes: 19 additions & 6 deletions source/source/content_type_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ void content_type_manager::fill_manifests_map(
map<string, content_manifest> &manifests, const string &content_rel_path, bool folders
) {
fill_manifests_map_from_pack(manifests, FOLDER_NAMES::BASE_PACK, content_rel_path, folders);
for(const auto &p : game.content.packs.manifests) {
fill_manifests_map_from_pack(manifests, p, content_rel_path, folders);
}
}


Expand Down Expand Up @@ -782,12 +785,22 @@ void mob_anim_content_manager::fill_manifests() {
mob_category* category = game.mob_categories.get((MOB_CATEGORY) c);
if(category->folder_name.empty()) return;

const string category_path = FOLDER_PATHS_FROM_ROOT::GAME_DATA + "/" + FOLDER_NAMES::BASE_PACK + "/" + FOLDER_PATHS_FROM_PACK::MOB_TYPES + "/" + category->folder_name;
vector<string> type_folders = folder_to_vector_recursively(category_path, true);
for(size_t f = 0; f < type_folders.size(); f++) {
string internal_name = type_folders[f];
manifests[internal_name] = content_manifest(internal_name, category_path + "/" + internal_name + "/animations.txt", FOLDER_NAMES::BASE_PACK);
}
fill_cat_manifests_from_pack(category, FOLDER_NAMES::BASE_PACK);
}
}


/**
* @brief Fills in the manifests from a specific pack.
*/
void mob_anim_content_manager::fill_cat_manifests_from_pack(
mob_category* category, const string &pack_name
) {
const string category_path = FOLDER_PATHS_FROM_ROOT::GAME_DATA + "/" + pack_name + "/" + FOLDER_PATHS_FROM_PACK::MOB_TYPES + "/" + category->folder_name;
vector<string> type_folders = folder_to_vector_recursively(category_path, true);
for(size_t f = 0; f < type_folders.size(); f++) {
string internal_name = type_folders[f];
manifests[internal_name] = content_manifest(internal_name, category_path + "/" + internal_name + "/animations.txt", FOLDER_NAMES::BASE_PACK);
}
}

Expand Down
3 changes: 3 additions & 0 deletions source/source/content_type_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ class mob_anim_content_manager : public content_type_manager {
private:

//--- Function declarations ---
void fill_cat_manifests_from_pack(
mob_category* category, const string &pack_name
);
void load_animation(content_manifest* manifest, CONTENT_LOAD_LEVEL level);

};
Expand Down
Loading

0 comments on commit efb17ee

Please sign in to comment.