How to use user-defined structs

You can talk about ManiaScript for ManiaPlanet here

Moderator: English Moderator

Post Reply
cgdb
Nadeo
Nadeo
Posts: 13
Joined: 23 Oct 2018, 12:33

How to use user-defined structs

Post by cgdb » 16 Nov 2018, 15:28

Hi, I'm cgdb, one of the newest members of the Nadeo team, currently working on improving the ManiaScript. Here I will explain one of its new features : user-defined structs.


- Definition
You can define a struct type using the new directive #Struct :

Code: Select all

#Struct StructName {
	Type1 MemberName1;
	Type2 MemberName2;
	Type3 MemberName3;
}
The members can have any type, including objects or other previously defined struct types (order matters!).


- Basic usage
Once defined, your new struct can be used in the same way as most other types.
When you define a new struct variable, all its members are initialized to default values ("", False, 0, Null, []...).
Use the symbol '.' to access its members.

Code: Select all

#Struct MyStruct {
	Integer MyMember;
}

main() {
	declare MyStruct MyVar;
	log(MyVar.MyMember); //Output : 0
	MyVar.MyMember = 1;
	log(MyVar.MyMember); //Output : 1
	declare MyStruct MyCopy = MyVar;
	log(MyCopy.MyMember); //Output : 1
	MyVar.MyMember = MyVar.MyMember + 1;
	log(MyVar.MyMember); //Output : 2
	log(MyCopy.MyMember); //Output : 1
}
Struct types usually behave like any other type regarding basic features like functions.

Code: Select all

#Struct MyStruct {
	Integer MyMember;
}

MyStruct ToMyStruct(Integer _Value) {
	declare MyStruct Result;
	Result.MyMember = _Value;
	return Result;
}

Integer FromMyStruct(MyStruct _Value) {
	return _Value.MyMember;
}

main() {
	declare MyStruct MyVar;
	MyVar.MyMember = 1;
	declare MyStruct MyCopy = MyVar;
	log(MyCopy == MyVar); //Output : True
	MyVar = ToMyStruct(2);
	log(MyCopy); //Output : {Integer MyMember 1}
	log(MyCopy == MyVar); //Output : False
}

- Traits
Struct types are compatible with declare for, metadata, persistent, netread and netwrite, but only if all their members are compatible too.


- Libraries
There are two ways to use a struct from a library. The first one is to use the "::" symbol to access a struct the same way you can access a constant.

Code: Select all

#Include "MyLibFile.Script.txt" as MyLib

main() {
	declare MyLib::MyStruct MyVar;
}
The second one is to use an alias using the keyword "as". Note that it works for constants too.

Code: Select all

//Order matters : be careful not to declare library aliases before the corresponding #Include
#Include "MyLibFile.Script.txt" as MyLib

#Struct MyLib::MyStruct as AliasStruct
#Const MyLib::MyConst as AliasConst

main() {
	//The next line means exactly the same as declare MyLib::MyStruct MyVar;
	declare AliasStruct MyVar;
}
This can be used to expose a struct or a constant in an intermediate library file.

Note that if you want to use the same struct in two different script files (or a script file and a manialink script), you will need to define the exact same struct in the different contexts, ie same struct name and same members (name and type) in the same order.
Be aware that if two libs define the very same struct, you'll see a warning telling you that there are two definitions of the same struct type that are interchangeables, since this may not be the intended behaviour.
If you need to use the same struct in two different files, you can define it in an other library file and include it in both scripts.


- Initialization
You can create a struct variable using the syntax StructName{StructMember1 = Value1, StructMember2 = Value2, StructMember3 = Value3}.

Code: Select all

#Struct MyStruct {
	Real MyRealMember;
	Text MyTextMember;
}

main() {
	declare MyStruct MyVar = MyStruct{MyRealMember = 1.0, MyTextMember = "Example"};
}
Any missing member will be initialized to the corresponding default value, so StructName{} is a valid way to create a struct with default values.

On the topic of default values, please note that structs do NOT support implicit type to value conversion and that feature is now deprecated. Please use explicit values instead in your future scripts (yes, [] is now a valid way to create an empty list).
For example:

Code: Select all

Text[] AddEmpty(Text[] _List)
{
	declare Text[] Result = _List;
	Result.add("");
	return Result;
}

main()
{
	// Deprecated
	declare Text[] MyList = AddEmpty(Text[]);
	// Use this instead
	declare Text[] MyList = AddEmpty([]);
}

- JSON conversion
ManiaScript includes two functions to handle conversion between structs variables and JSON objects, .tojson() and .fromjson(Text).

The first one produces the JSON Text representing the struct variable. The second one fills the members of a struct variable according to the JSON Text and returns a boolean value.
This value is True only if all struct member that were matched with a JSON element were filled correctly. Do note that missing or unneeded JSON elements will be skipped and won't impact the return value.

Code: Select all

#Struct MyStruct {
	Real MyRealMember;
	Text MyTextMember;
}

main() {
	declare MyStruct MyVar = MyStruct{MyRealMember = 1.0, MyTextMember = "Example"};
	declare JSONText = MyVar.tojson();
	log (JSONText); //output : {"MyRealMember":1,"MyTextMember":"Example"}
	declare MyStruct MyCopy;
	declare Boolean CopyOk = MyCopy.fromjson(JSONText); //MyCopy is now a copy of MyVar
}
Only some ManiaScript types can be converted to JSON : Boolean, Integer, Real, Text, enums, vectors, arrays and structs. For associative arrays, the accepted key types are Boolean, Integer, Real, Text and enums. Struct members using other types will be skipped by both functions.

Note that these two functions work with array types too, but in this case the root of the JSON Text will be an array instead of an object, and some JSON readers may flag this JSON as incorrect.


That's it! I hope that this new feature will make writing scripts easier and better! If you have any question or, really, anything to say about structs, please tell us here.

Post Reply

Return to “ManiaScript”

Who is online

Users browsing this forum: No registered users and 0 guests