-
Notifications
You must be signed in to change notification settings - Fork 990
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
Allow the creation of bays that can carry ships of multiple types #9906
base: master
Are you sure you want to change the base?
Conversation
Opening as a draft to show that this is being worked on. Noting that the snag I caught during testing is a rather large one.
This is likely happening because the bays are filled in the same order they are defined. On the Carrier, the fighter bays are defined first, and so the drones fill the fighter bays first. The order that the bays are defined in should not matter, though. I imagine we could make it so that a carrier more intelligently fills its bays by shuffling carried ships to the most restrictive bays first (e.g. if there is a ship of type X docking and the ship has a bay that holds both X and Y and another bay that holds only X, put the ship in the bay that holds only X first), but then we run into issues of having multiple carriers in the same fleet. Say you have two Carriers. That makes 12 drones and 8 fighters. A Carrier can hold up to 10 drones, or 6 drones and 4 fighters. What happens if you recall and 10 of your drones go to one Carrier and 2 go to the other? Well the second carrier would still have space for 4 fighters, but now you have 4 fighters flying around with nowhere to dock. Right now when recalling, fighters and drones basically just go to the first ship they can find that can hold them. If we want to be able to have bays that can hold multiple ship categories, we need to basically reserve every bay the moment that the recall occurs in an order that ensures that every carried ship can dock. Either that, or we completely do away with the fighter/drone distinction for the sake of simplicity. I don't think that's the way we should go if we don't need to, though. |
Is it not possible to make use of the ships' parent attribute for this, making them board their parent if possible? Or would that break every other use case? (I recall a PR from a couple months/years ago that had something like this, not sure what happened to that.) On a separate note, how does this handle plugins adding ship categories to existing bay types? |
An alternative solution would be to have ships take off from a docked state to rearrange themselves, if only a portion of them were docked before. (This would have issues with disabled ships not being able to take off, and would be a bit of a UX nightmare, but might help as a stopgap measure.) |
|
We'd need to be able to intelligently reorder carried ships in the first place to even be able to do that, so might as well just dock them in an intelligent order to begin with. |
That, plus intelligent docking order, would likely solve most of the problem. The only extra case to account for would be intelligently parenting new ships that you capture.
Are you thinking of this one? #6130 |
It's a bit more than that, since you can lose and gain both carriers and fighters, so it might be necessary to re-dock some ships to be able to fit everything in, even if the order was correct previously. (This is amplified if not all ships were requested to dock initially, or there wasn't enough space the first time the order was given.)
Yeah that PR seems to have some useful functionality. Tieing bays and carried ships together would probably allow for caching a bunch of the necessary calculations, but isn't enough when ships are lost (or gained I guess). |
The way this is shaping up, that could be a whole PR of its own changing how fighters and drones reparent. I'm tempted to say we tackle intelligent docking order here so that given a single carrier everything looks good when taking off and recalling, then any sort of permanent parenting and recalculating parents when fighters are gained or carriers are lost could be done next. Nothing changes anyway until we add any |
Just a dumb question, but why not just have 1 'bay type' that allows both drones and/or fighters to use it? I assume that this might mess with plugin compatibility |
We could very easily have that be the case for vanilla, even without this PR or any other engine updates, but then that leaves no customization options for plugins. Compatiblity would be fine. What I'm doing here though is adding capabilities to the engine. How vanilla or any plugins make use of the engine's mechanics is a separate topic. |
Don't mind me I'm just trying learn, I hope I'm not becoming a pest. Just keeping it simple, whats happens if:
Am I right in assuming all existing ship builds in vanilla and plugins would continue as is. ? I afraid that adding even more calculations may have a negative impact to people with weak GPU, like me. |
GPUs are for drawing the frames. Gameplay calculations, which this would be, are for the CPU. |
When a ship docks with a carrier, the carrier now docks the ship in the most restrictive bay first, where restrictiveness is measured by the number of categories the bay allows. If a drone is docking and a carrier has two bays, one that carries only drones and one that carries both drones and fighters, then the first of those two bays is considered the more restrictive and the drone is placed there. That way, drones don't hog fighter bays from fighters when they could've used a drone bay. |
|
||
private: | ||
std::string name; | ||
std::set<std::string> categories; |
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 just a side note, but I did some reading on the stl recently and it seems like a std set is actually slower than a std vector in this situation, especially with such a low element count.
To give an example, this code:
#include <set>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> testE = {"a", "b", "c", "d", "e"};
std::set<std::string> test = {"a", "b", "c", "d"};
for(int x = 0; x < 200000000; x++)
int i = test.count(testE[x % 3]);
return 0;
}
has a worse runtime than this one:
#include <vector>
#include <string>
#include <algorithm>
int main()
{
std::vector<std::string> testE = {"a", "b", "c", "d", "e"};
std::vector<std::string> test = {"a", "b", "c", "d"};
for(int x = 0; x < 200000000; x++)
bool it = std::find(test.begin(), test.end(), testE[x % 3]) == test.end();
return 0;
}
This does not really matter, but I just wanted to note this here as I saw a lot of those really useless set use-cases.
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.
Eh. set.count(val)
is more readable than find(vector.begin(), vector.end(), val) != vector.end()
. Even if the runtime is worse, it doesn't actually result in any tangible difference at the scales we're working at. Checking the categories of a bay isn't exactly a common action, relatively speaking. So this is one of those "We'll change it if it ever actually causes a problem" things.
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.
yea was just giving random thoughts
Co-authored-by: Rising Leaf <85687254+RisingLeaf@users.noreply.github.com>
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.
Looks good to me.
Co-authored-by: TomGoodIdea <108272452+TomGoodIdea@users.noreply.github.com> Co-authored-by: Daniel <101683475+Koranir@users.noreply.github.com>
as thee did request, h're is thy revieweth |
Because of course you should do the true case first Co-authored-by: TomGoodIdea <108272452+TomGoodIdea@users.noreply.github.com>
Co-authored-by: TomGoodIdea <108272452+TomGoodIdea@users.noreply.github.com>
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.
looks good
Co-authored-by: TomGoodIdea <108272452+TomGoodIdea@users.noreply.github.com>
@@ -1101,9 +1104,15 @@ map<const shared_ptr<Ship>, vector<string>> PlayerInfo::FlightCheck() const | |||
if(ship->CanBeCarried() || !ship->HasBays()) | |||
continue; | |||
|
|||
for(auto &bay : ship->Bays()) | |||
auto &bays = ship->Bays(); |
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.
auto &bays = ship->Bays(); | |
const auto &bays = ship->Bays(); |
if(bay.bayType) | ||
for(const string &category : bay.bayType->Categories()) | ||
++bayCount[category]; | ||
else |
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 looks confusing, I would actually prefer the {} here
for(auto &bay : ship->Bays()) | ||
auto &bays = ship->Bays(); | ||
totalBays += bays.size(); | ||
for(auto &bay : bays) |
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.
for(auto &bay : bays) | |
for(const auto &bay : bays) |
if(bayType) | ||
return bayType->Contains(category); | ||
return name == category; |
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.
if(bayType) | |
return bayType->Contains(category); | |
return name == category; | |
return bayType ? bayType->Contains(category) : name == category; |
this would be my personal preference, do as you like
for(const Bay &bay : bays) | ||
count += (bay.category == category); | ||
if(bay.CanContain(category)) | ||
++count; |
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.
you could use a std::count_if
|
||
// Confirm that all categories of ship that this bay can hold | ||
// are carriable. If not, set isValid to false. | ||
void BayType::FinishLoading() |
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.
Would it make sense to ignore those categories instead of disabling the entire bay?
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.
Some tests for the new feature could be useful. (Making sure it can load, detects when invalid categories are used, etc.)
Feature
This PR addresses the bug/feature described in issue #9896.
Summary
This PR adds a new root node
bay
that behaves as follows:bay <name>
: A named bay type. When a ship definition includes abay
point, that bay will be able to store ships from the matchingbay
root node. If nobay
root node matches the name of the ship'sbay
, then it is assumed that the name of the ship'sbay
matches a singular category of ship that can be carried. This is done for backwards compatibility.category
root node. The children strings are the categories of ship that bays of this type can store. The category must also be present in thecategory "bay type"
root node.This PR only adds the mechanics for bay root nodes. No bay root nodes are added by this PR.
Usage examples
Testing Done
When I took off, all my ships were docked. Deploying worked fine. Upon recalling, only the drones would redock. Sometimes a fighter would redock, but as soon as a drone would dock, the fighters wouldn't dock anymore. Seems like the fighter bays were being filled first, so as soon as the drones would dock, the fighters would be unable to do so.Fixed by f7f7558Flipped the order that I purchased the ships so that it was 6 drones then 4 fighters. On take-off, the ships appear to be filling the bays in their order in your ships list, meaning the drones filled the Carrier first and therefore stole the fighter bays from the fighters.Fixed by f7f7558