Atmosphere
Atmosphere copied to clipboard
Add Support For Float/Double Cheats
Feature Request
I am requesting to add float/double casting to the dmnt_cheat process.
What feature are you suggesting?
Overview:
- Currently the supported types are 8 bit,16 bit, 32 bit and 64 bit. Which is nice, but if you're working with a value in memory that is a float or double, then the arithmetic instructions won't work evenly.
Smaller Details:
- Adding F and D to determine the size of the value, like how 1,2,4,8 are already used.
Nature of Request:
- Addition of more data types for sizes of cheats.
- Looks like the size is determined here, so it would be a matter of modifying that switch-case statement.
I just can't for the life of me figure out how to compile, I get errors all over the place, which is why I'm asking as a feature request :)
What component do you feel this would best fit within?
-
Stratosphère
- The dmnt_cheat_vm custom sys-module.
Why would this feature be useful?
Like I said, implementing float/double types will allow for more better cheats, like moon jump or size modifiers, basically anything that modifies anything that is float or double.
Yes, I know what floats would be in hex. I'm mainly concerned about arithmetics. For example, if you were to add 3F800000 + 3F800000 together, you'd get 7F000000 which is 1.70141e+38 in float. Casting it as a float would cause them to be added evenly so that it would be 40000000 which would be 2.0.
Fine with adding this once C++20 std::bit_cast is available.
Fine with adding this once C++20 std::bit_cast is available.
Why not a standard cast?
how do you "standard cast" a hex pattern to float/double
how do you "standard cast" a hex pattern to float/double
You're casting it here, right? If I'm reading the source correct, GetNextVmInt converts the hex pattern to u32, and then it's a matter of casting it to float, right? Float registers would probably need to be implemented, but isn't it just as simple as
(float)first_dword;
(((double)first_dword) << 32ul) | ((u64)GetNextDword())
that is not at all how casting works
To be more specific: float <-> u32 bit pattern conversion is more complicated than that.
Wait, are you thinking of implementing floats/doubles like this?
0F000010 10000000 1.0
I was kind of hoping for it to be like this
0F000010 10000000 3F800000
where the operand (like for the arithmetics opcode's) would be the hexadecimal representation, but it'll be casted as float so that the result would be the hexadecimal representation of said float number.
How would it be more complicated than that?
no, I am thinking of implementing like 0F000010 10000000 3F800000
.
This requires std::bit_cast.
That is not how u32 <-> float casts work.
Wait I feel stupid. I just read up more on bit_cast and now I see why.
Yes, I know what floats would be in hex. I'm mainly concerned about arithmetics. For example, if you were to add 3F800000 + 3F800000 together, you'd get 7F000000 which is 1.70141e+38 in float. Casting it as a float would cause them to be added evenly so that it would be 40000000 which would be 2.0.
Yeah, I just read about math calculations and deleted answer. Sorry. :P
can do it with pointer aliasing too, but yeah, bit_cast is better style
or do it the safe old fashioned way with a union
Type punning with unions is undefined behavior in C++.
I see it's allowed in C but not in C++. Though GNU C++ allows it 😉
Looks like C++20 was released for devkitA64 today!
@leoetlino gnu++20 allows type-punning with unions explicitly, which we use.
Since gcc 10 doesn't implement std::bit_cast....
@rydoginator I spent like 30 minutes trying to implement this. It was awkward because the registers are integers and the desired behavior isn't really clear when doing arithmetic.
Could you write a specification for the cheat changes you'd like? I am happy to implement them.
I don't have any example offsets currently, but I can think of 2 ways I'd like this to be implemented. 1: enabling a floating point flag, so that both operands are treated as float and double. Treat all instructions as double/single floating point if the flag is enabled. If T is 4 or less, treat it as single. If it's 8, treat it as double. Example:
F1000000 00000001 //enable float flag... Treat all arithmetic operations as float / double
94000100 3F800000 // r0 = r0 + 1.0
F1000000 00000000 // disable float flag... Treat all arithmetic operations as integers.
94000100 3F800000 // r0 = r0 + 0x3f800000;
2: adding float + double registers, so if the user chooses F for the T parameter, it'll use one of the float registers.
9F000100 3F800000 //f0 = f0 + 1.0
9D000100 3ff00000 00000000 // d0 = d0 + 1.0
Does that make sense? I don't mind with either method, whatever way is easier for you.
@SciresM yes std::bit_cast will be in c++20, but technically you don't have to wait for it. std::bit_cast has been added to deal with type aliasing (type punning) in the C++ language. According to https://en.cppreference.com/w/cpp/numeric/bit_cast std::bit_cast can be implemented like this:
template <class To, class From>
typename std::enable_if_t<
sizeof(To) == sizeof(From) &&
std::is_trivially_copyable_v<From> &&
std::is_trivially_copyable_v<To>,
To>
bit_cast(const From& src) noexcept
{
static_assert(std::is_trivially_constructible_v<To>,
"This implementation additionally requires destination type to be trivially constructible");
To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
This is of course idiot proof. But you can see that the actual function that does the 'work' is std::memcpy, so if you don't want to use this idiot proof 'bit_cast' code you can always just use std::memcpy.
Like so:
#include <iostream>
#include <cstdint>
#include <cstring>
int main()
{
uint32_t int_value = 0x3f800000; // 1.f in 'raw' form.
float float_value;
std::memcpy(&float_value, &int_value, sizeof(float_value));
std::cout << float_value << "\n"; // this will print "1".
return 0;
}
See https://godbolt.org/z/9c4Erc for a working example
@Captnoord i don't know why you wrote all that.
bit_cast cannot be constexpr without compiler magic. That compiler magic hasn't been implemented yet.