Keeps the individual behaviors in their own functions, and cleanly
separate. We can also do a little better by converting the relevant IDs
within the core to a QString only once, instead of converting every
string into a std::string.
Disambiguates what the string represents to help translators more easily
understand what it is that they're translating. While we're at it, we
can move the code to its own function, so that we don't need to specify
the same string twice.
These functions are pretty much identical to BeginImportProgram and EndImportProgram.
We don't need to do anything special in EndImportProgramWithoutCommit and CommitImportPrograms because we don't need to implement the two-phase title installation that the 3DS uses to prevent corruption of the title.db.
FS subfiles are created with File::OpenSubFile, they have a start offset that must be added to all read/write operations.
The implementation in this commit is done using a new FileBackend that wraps the FS::File along with the start offset.
Any SDL invocation can call the even callback on the same thread, which can call GetSDLJoystickBySDLID and eventually cause double lock on joystick_map_mutex. To avoid this, lock guard should be placed as closer as possible to the object accessing code, so that any SDL invocation is with the mutex unlocked
Frame advancing is a commonly used TAS feature which basically means running the game frame by frame. TASers use this feature to press exact buttons at the exact frames. This commit added frame advancing to the framelimiter and two actions to the Movie menu. The default hotkey is `\` for advancing frames, and `Ctrl+A` for toggling frame advancing. The `Advance Frame` hotkey would automatically enable frame advancing if not already enabled.
boost::static_pointer_cast for boost::intrusive_ptr (what SharedPtr is),
takes its parameter by const reference. Given that, it means that this
std::move doesn't actually do anything other than obscure what the
function's actual behavior is, so we can remove this. To clarify, this
would only do something if the parameter was either taking its argument
by value, by non-const ref, or by rvalue-reference.
This adds a clock init time field to the CTM header. The clock settings would be overridden when playing a movie. And when recording a movie, if the clock is set to System Time, it would be set to fixed init time at the current moment as well. In this way this keeps consistency with the RNG even if the user does just no setting.
Changes the interface as well to remove any unique methods that
frontends needed to call such as StartJoystickEventHandler by
conditionally starting the polling thread only if the frontend hasn't
started it already. Additionally, moves all global state into a single
SDLState class in order to guarantee that the destructors are called in
the proper order
This can just be a regular function, getting rid of the need to also
explicitly undef the define at the end of the file. Given FuncReturn()
was already converted into a function, it's #undef can also be removed.
Instead of using an unsigned int as a parameter and expecting a user to
always pass in the correct values, we can just convert the enum into an
enum class and use that type as the parameter type instead, which makes
the interface more type safe.
We also get rid of the bookkeeping "NUM_" element in the enum by just
using an unordered map. This function is generally low-frequency in
terms of calls (and I'd hope so, considering otherwise would mean we're
slamming the disk with IO all the time) so I'd consider this acceptable
in this case.
First of all they are foundamentally broken. As our convention is that std::string is always UTF-8, these functions assume that the multi-byte character version of TString (std::string) from windows is also in UTF-8, which is almost always wrong. We are not going to build multi-byte character build, and even if we do, this dirty work should be handled by frontend framework early.
There were a few places where nested namespace specifiers weren't being
used where they could be within the service code. This amends that to
make the namespacing a tiny bit more compact.
We always use unicode internally. Any dirty work of conversion with other codec should be handled by frontend framework (Qt). Further more, ShiftJIS/CP1252 are not special (they are not code set used by 3ds, or any guest/host dependencies we have), so there is no reason to specifically include them
Qt provides an overload of tr() that operates on quantities in relation
to pluralization. This also allows the translation to adapt based on the
target language rules better.
For example, the previous code would result in an incorrect translation
for the French language (which doesn't use the pluralized version of
"result" in the case of a total of zero. While in English it's
correct to use the pluralized version of "result", that is, "results"
---
For example:
English: "0 results"
French: "0 résultat" (uses the singular form)
In French, the noun being counted is singular if the quantity is 0 or 1.
In English, on the other hand, if the noun being counted has a quantity
of 0 or N > 1, then the noun is pluralized.
---
For another example in a language that has different counting methods
than the above, consider English and Irish. Irish has a special form of
of a grammatical number called a dual. Which alters how a word is
written when N of something is 2. This won't appear in this case with a
direct number "2", but it would change if we ever used "Two" to refer to
two of something. For example:
English: "Zero results"
Irish: "Toradh ar bith"
English: "One result"
Irish: "Toradh amháin"
English: "Two results"
Irish: "Dhá thorthaí" <- Dual case
Which is an important distinction to make between singular and plural,
because in other situations, "two" on its own would be written as "dó"
in Irish. There's also a few other cases where the order the words are
placed *and* whether or not the plural or singular variant of the word
is used *and* whether or not the word is placed after or between a set
of numbers can vary. Counting in Irish also differs depending on whether or not
you're counting things (like above) or counting people, in which case an
entirely different set of numbers are used.
It's not important for this case, but it's provided as an example as to why one
should never assume the placement of values in text will be like that of
English or other languages. Some languages have very different ways to
represent counting, and breaking up the translated string like this
isn't advisable because it makes it extremely difficult to get right
depending on what language a translator is translating text into due to
the ambiguity of the strings being presented for translation.
In this case a translator would see three fragmented strings on
Transifex (and not necessarily grouped beside one another, but even
then, it would still be annoying to decipher):
- "of"
- "result"
- "results"
There is no way a translator is going to know what those sets of words
are actually used for unless they look at the code to see what is being
done with them (which they shouldn't have to do).
This was very likely intended to be a logical OR based off the
conditioning and testing of inversion in one case.
Even if this was intentional, this is the kind of non-obvious thing one
should be clarifying with a comment.