Skip to content

API changes in v4

Archie_UwU edited this page Oct 12, 2024 · 2 revisions

Caution

All of the content below is subject to change until v4.0.0 is merged into the stable branch.

Note

The following article assumes that your mod was made for YYToolkit v3.

If this is not the case, information below may not be entirely relevant.

RValue access

The methods for accessing RValues have been reworked in order to encourage their usage instead of code that directly accesses the member variables.

Please refer to the table below for more information:

C++ Type SDK v3.x.x SDK v4.x.x
bool AsBool() ToBoolean()
int32_t m_i32 ToInt32()
int64_t m_i64 ToInt64()
double AsReal() ToDouble()
const char* N/A ToCString()
std::string AsString() ToString()
std::u8string N/A ToUTF8String()
YYObjectBase* N/A ToObject()
CInstance* m_Object ToInstance()

Behavior of the methods listed below has changed as well:

AsBool / ToBoolean

This method now evaluates "truthyness" according to the table below:

RValue Type SDK v3.x.x SDK v4.x.x
VALUE_REAL
VALUE_BOOL
True if m_Real > 0.5 True if m_Real > 0.5
VALUE_STRING Console error, always false True if string is "true"
True if string contains numerical value > 0.5
VALUE_INT64 True if m_i64 > 0 True if m_i64 > 0
VALUE_OBJECT
VALUE_PTR
True if m_Pointer != nullptr True if m_Pointer != nullptr
VALUE_INT32
VALUE_REF
True if m_i32 > 0 True if m_i32 > 0
VALUE_ARRAY Console error, always false Error: bool argument is array
VALUE_UNDEFINED Always false Always false
VALUE_UNSET Console error, always false Error: bool argument is unset

AsReal / ToDouble

This method's behavior has only changed for a few types:

RValue Type SDK v3.x.x SDK v4.x.x
VALUE_STRING Console error Tries to get string numerical value

If this fails, an error is thrown:
unable to convert string to number
VALUE_OBJECT Console error If instance: gets the instance ID
If JS object: Tries to call valueOf
VALUE_UNSET Console error, always false Error: REAL argument is unset
Invalid types Console error, always false Error: REAL argument incorrect type

Structs

Structs can now be created without the need for manually calling runner interface functions. They can also be constructed from a std::map<std::string, RValue>, where the key is the member name.

Instead of using the runner interface, the syntax is as follows:

RValue value = {
    { "real_value", 1.234 },
    { "string_value", "test" },
    { "array_value", { 1, "second element", 3.14 }} 
};

To retrieve values from a struct, you can either use the GetInstanceMember function, the value["member_name"] syntax, or the new ToMap / ToRefMap functions. Using the value["member_name"] syntax is recommended for ease of reading. If a status code is required, use GetInstanceMember.

For looking up all members of a struct in one fell swoop, consider using the ToRefMap function. If you wish to get copies of the variables, use the ToMap function.

Warning

The ToRefMap and ToMap functions call EnumInstanceMembers behind the scenes, which can be slow for large structs.

See the Remarks section of EnumInstanceMembers for more information.

Initialization

The kind assigned upon initialization of an RValue may differ from v3 to v4. This is due to numerous fixes being implemented to prevent type confusion from happening within the runner.

Please refer to the table below for more information:

Initialization Kind (SDK v3.x.x) Kind (SDK v4.x.x)
Default constructor VALUE_UNDEFINED VALUE_UNDEFINED
std::initializer_list<RValue> VALUE_ARRAY VALUE_ARRAY
bool VALUE_BOOL VALUE_BOOL
double
float
VALUE_REAL VALUE_REAL
Any other floating point type
(long double)
Error VALUE_REAL
CInstance* VALUE_OBJECT VALUE_OBJECT
Any object that inherits from CInstanceBase
(YYObjectBase, CScriptRef, ...)
VALUE_BOOL VALUE_OBJECT
Any other pointer type VALUE_BOOL VALUE_PTR
std::vector<RValue> Error VALUE_ARRAY

Arrays

Array accesses can now be made via a vector. You can take a snapshot of the array (where all values are copied instead of being referenced) using the ToVector function. If you wish to get pointers to the actual C++ array, use the ToArray function (only possible on non-const instances of RValue).

For example:

// Creates an array of [1, 2, 3, 4]
RValue my_array = { 1, 2, 3, 4 };

// Get the reference to the first element using the index operator.
RValue& first_element = my_array[0];

// Get the reference to the second element using the reference vector WITH bounds checking.
RValue& second_element = *my_array.ToRefVector().at(1);

// Get the reference to the third element using the raw array.
RValue& third_element = my_array.ToArray()[2];

// Get a COPY of the fourth element using the non-reference vector WITHOUT bounds checking.
RValue fourth_element_copy = my_array.ToVector()[3];

Implicit conversions

Implicit conversions to and from RValues have been improved to support easier conversion to and from C++ types.

In v3.4.3, the following code does not compile:

// Assign integral value to the RValue. Initialized as VALUE_INT32.
RValue my_rvalue = 5;

// Error: No suitable conversion from RValue to int32_t.
int32_t integer_value = my_rvalue;

// Error: No suitable conversion from std::string_view to std::string
std::string string_value = my_rvalue.AsString();

// All lines error. No suitable conversion exists for any of these types.
float float_value = my_rvalue;
double double_value = my_rvalue;
long double long_double_value = my_rvalue;

// All lines error. No suitable conversion exists for any of these types.
int int_value = my_rvalue;
long long_value = my_rvalue;
long long_long_value = my_rvalue;

In v4.0.0, the code compiles, but the RValue initialization behavior is a little different:

// Assign integral value to the RValue. Initialized as VALUE_INT64.
RValue my_rvalue = 5;

// OK. RValues can be casted to int32_t.
// The result is the same as when calling .ToInt32().
int32_t integer_value = my_rvalue;

// OK. ToString returns an std::string.
std::string string_value = my_rvalue.ToString();

// OK. All the floating-point types can be implicitely converted-to from an RValue.
float float_value = my_rvalue;
double double_value = my_rvalue;
long double long_double_value = my_rvalue;

// OK. All the integral types can be implicitely converted-to from an RValue.
int int_value = my_rvalue;
long long_value = my_rvalue;
long long_long_value = my_rvalue;

Explicit conversions

Many conversions are now able to be done without the need for calling a .ToXXX() function. For example, std::string and std::u8string can now be constructed directly from RValues.

In v3.4.3, one would encounter the following errors:

// Initialize a string RValue with "This is a C-style string!".
RValue string_rvalue = "This is a C-style string!";

// Error: Strings cannot be created implicitely.
std::string cpp_string_implicit = string_rvalue;

// Error: No constructor of std::string accepts an RValue.
std::string cpp_string_constructed = std::string(string_rvalue);

// Error: No explicit conversion exists from an RValue to a std::string.
std::string cpp_string_casted = static_cast<std::string>(string_rvalue);

On the other hand, v4.0.0 allows all but one of these ways of creating strings:

// Initialize a string RValue with "This is a C-style string!".
RValue string_rvalue = "This is a C-style string!";

// Error: Strings cannot be created implicitely.
std::string cpp_string_implicit = string_rvalue;

// OK. Strings can be constructed from an RValue.
std::string cpp_string_constructed = std::string(string_rvalue);

// OK. An RValue can be explicitely casted to a string.
std::string cpp_string_casted = static_cast<std::string>(string_rvalue);

Instances

The at and operator[] methods have been removed from CInstance. New methods can be used for a similar purpose as per the table below:

Old method name New method name
operator[] GetRefMember
at GetRefMember

Further-more, a static method is now added to aid getting pointers to CInstance objects from a GameMaker instance ID. The syntax for that is as follows:

int32_t instance_id = 103'545; // Assume this is an ID found at runtime
CInstance* object = CInstance::FromInstanceID(instance_id);

All of the newly added methods, together with their compatibility with ISA, can be seen below:

Old method name New method name Requires ISA const-compatible
GetMembers GetMembers
operator[] GetMember
GetRefMember
at GetMember
GetRefMember
N/A GetMemberCount
N/A FromInstanceID N/A

Quick Access

Documentation

Writeups

Clone this wiki locally