-
Notifications
You must be signed in to change notification settings - Fork 89
Allow relative path for campaign images #1886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
f848509
ac4ed88
7d1fb7c
9467f10
58e9930
feb8eea
94e1931
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,25 +1,56 @@ | ||
| // Copyright (C) 2005 - 2024 Settlers Freaks (sf-team at siedler25.org) | ||
| // Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org) | ||
| // | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
|
|
||
| #include "CampaignDescription.h" | ||
| #include "RttrConfig.h" | ||
| #include "helpers/containerUtils.h" | ||
| #include "helpers/format.hpp" | ||
| #include "lua/CheckedLuaTable.h" | ||
| #include "lua/LuaHelpers.h" | ||
| #include "mygettext/mygettext.h" | ||
|
|
||
| CampaignDescription::CampaignDescription(const boost::filesystem::path& campaignPath, const kaguya::LuaRef& table) | ||
| { | ||
| const auto resolveCampaignPath = [campaignPath](const std::string& path, bool isFolder) { | ||
| const boost::filesystem::path tmpPath = path; | ||
| if(tmpPath.is_relative()) | ||
| { | ||
| // If it is only a file/folder name or empty use path relative to campaign folder | ||
| if(!tmpPath.has_parent_path()) | ||
| return (campaignPath / tmpPath).string(); | ||
| if(!isFolder) | ||
| { | ||
| // For files only allow a single sub folder | ||
| const auto parentPath = tmpPath.parent_path(); | ||
| if(!parentPath.parent_path().has_parent_path()) | ||
| { | ||
| // Only alpha-numeric folder names are allowed | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so my-file.bmp is forbidden? And why is that at all?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we can allow - and _ ?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, only the folder name is checked. I don't see a need for |
||
| const auto isAlNum = [](const char c) { | ||
| return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); | ||
| }; | ||
| const auto isNonAlNum = [isAlNum](const char c) { return !isAlNum(c); }; | ||
| lua::assertTrue(!helpers::contains_if(parentPath.string(), isNonAlNum), | ||
| helpers::format(_("Invalid path '%1%': Must be alpha-numeric"), path)); | ||
| return (campaignPath / tmpPath).string(); | ||
| } | ||
| } | ||
| } | ||
| // Otherwise it must be a valid path inside the game files | ||
| lua::validatePath(path); | ||
| return path; | ||
| }; | ||
|
|
||
| CheckedLuaTable luaData(table); | ||
| luaData.getOrThrow(version, "version"); | ||
| luaData.getOrThrow(author, "author"); | ||
| luaData.getOrThrow(name, "name"); | ||
| luaData.getOrThrow(shortDescription, "shortDescription"); | ||
| luaData.getOrThrow(longDescription, "longDescription"); | ||
| image = luaData.getOptional<std::string>("image"); | ||
| if(image && image->empty()) | ||
| image = std::nullopt; | ||
| const auto imageValue = luaData.getOptional<std::string>("image"); | ||
| if(imageValue && !imageValue->empty()) | ||
| image = resolveCampaignPath(*imageValue, false); | ||
|
|
||
| luaData.getOrThrow(maxHumanPlayers, "maxHumanPlayers"); | ||
|
|
||
| if(maxHumanPlayers != 1) | ||
|
|
@@ -30,22 +61,24 @@ CampaignDescription::CampaignDescription(const boost::filesystem::path& campaign | |
| if(difficulty != gettext_noop("easy") && difficulty != gettext_noop("medium") && difficulty != gettext_noop("hard")) | ||
| throw std::invalid_argument(helpers::format(_("Invalid difficulty: %1%"), difficulty)); | ||
|
|
||
| auto resolveFolder = [campaignPath](const std::string& folder) { | ||
| const boost::filesystem::path tmpPath = folder; | ||
| // If it is only a filename or empty use path relative to campaign folder | ||
| if(!tmpPath.has_parent_path()) | ||
| return campaignPath / tmpPath; | ||
| // Otherwise it must be a valid path inside the game files | ||
| lua::validatePath(folder); | ||
| return RTTRCONFIG.ExpandPath(folder); | ||
| }; | ||
|
|
||
| const auto mapFolder = luaData.getOrDefault("mapFolder", std::string{}); | ||
| mapFolder_ = resolveFolder(mapFolder); | ||
| mapFolder_ = RTTRCONFIG.ExpandPath(resolveCampaignPath(mapFolder, true)); | ||
| // Default lua folder to map folder, i.e. LUA files are side by side with the maps | ||
| luaFolder_ = resolveFolder(luaData.getOrDefault("luaFolder", mapFolder)); | ||
| luaFolder_ = RTTRCONFIG.ExpandPath(resolveCampaignPath(luaData.getOrDefault("luaFolder", mapFolder), true)); | ||
| mapNames_ = luaData.getOrDefault("maps", std::vector<std::string>()); | ||
| selectionMapData = luaData.getOptional<SelectionMapInputData>("selectionMap"); | ||
| if(selectionMapData) | ||
| { | ||
| const auto updatePath = [resolveCampaignPath](std::string& path) { | ||
| if(!path.empty()) | ||
| path = resolveCampaignPath(path, false); | ||
| }; | ||
| updatePath(selectionMapData->background.filePath); | ||
| updatePath(selectionMapData->map.filePath); | ||
| updatePath(selectionMapData->missionMapMask.filePath); | ||
| updatePath(selectionMapData->marker.filePath); | ||
| updatePath(selectionMapData->conquered.filePath); | ||
| } | ||
| luaData.checkUnused(); | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what formats are supported? LBM, BMP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty much anything that has a single image. So yes, LBM & BMP
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now documented.
I'm wondering if this should support indexed archives similar to the selection map. But probably overkill
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, I was about to ask and hope if we could support loading custom objects as well, as I'm still hoping for that addition
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by "loading custom objects"?
Do you have any concrete use case for that as
image?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do, some examples do include but are not limited:
And now that I'm wiring this, I realize, that his would not work in multiplayer at all, or rather would require further implementations. Maybe if we put it into a .lst file we'd distribute then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so that is unrelated to the campaign description and could be done later.
As for placing objects:
AddStaticObjectcan use many graphics already. We could make it accept a resource ID instead of a file number to refer to other archives.As for custom graphics we would indeed be limited to campaigns as we don't transfer archives to clients. Even then we'd need to somehow pass the campaign folder/subfolder to the loader but it supports such overwriting already and we use it for e.g. addons already