godot-cpp icon indicating copy to clipboard operation
godot-cpp copied to clipboard

PackedByteArray can't init and pass to const Variant **

Open rendawudi opened this issue 2 years ago • 2 comments

I can't pass PackedByteArray to Variant.call and get error with NIL Type

gdscript code:

$Example.SendRequest("connector.joingame", "aaa".to_ascii_buffer(), func(x :PackedByteArray):
			if (x.size() == 0):
				prints("ok")
			else:
				prints("nono")
			)

c++ code:

....
        String route = args[0]->operator String();
	PackedByteArray tmpdata = args[1]->operator PackedByteArray();
	Variant funcall = *args[2];        

        PackedByteArray tmpVar;
        Variant result;
	GDNativeCallError err;
	std::array<const GDNativeVariantPtr, sizeof(PackedByteArray)> call_args = { &tmpVar };
	funcall.call("call", (const Variant **)call_args.data(), 1, result, err);

rendawudi avatar Aug 09 '22 04:08 rendawudi

        String route = args[0]->operator String();
	PackedByteArray tmpdata = args[1]->operator PackedByteArray();
	Variant funcall = *args[2];        

        PackedByteArray tmpVar;
        Variant qqt = tmpVar;
        const auto **argptr = (const Variant **)alloca(sizeof(Variant *));
        argptr[0] = &qqt;
        Variant result;
        GDNativeCallError err;
        funcall .call("call", argptr, 1, result, err);

this code can get good result...

but if i wan't to save funcall to funcsmap,and wait for the next response from server,the funcall will be memfree, so what can i do to call lambda functions async?

here is my code


String route = args[0]->operator String();
	PackedByteArray tmpdata = args[1]->operator PackedByteArray();
	Variant funcall = *args[2];
   
	return pitayaClient.SendRequest(route.ascii().get_data(), const_cast<uint8_t *>(tmpdata.ptr()), tmpdata.size(), [&callab](const uint8_t* data, size_t length) {
		UtilityFunctions::print("run call back len:" + length);
		PackedByteArray tmpVar;
		if (length != 0) {
			tmpVar.resize(length);
			memcpy(tmpVar.ptrw(), data, length);
		}
        Variant qqt = tmpVar;
        const auto **argptr = (const Variant **)alloca(sizeof(Variant *));
        argptr[0] = &qqt;
        Variant result;
        GDNativeCallError err;
        callab.call("call", argptr, 1, result, err);
	});

sendRequest will save c++ lambda function to map, and use catched temp funcall to call gdscript call

rendawudi avatar Aug 09 '22 10:08 rendawudi

I solved by code,and can get successful result without memory leak

gdscript code

$Example.AddRouteOnMessage("onMessage", func(packMsg: PackedByteArray):
		print(packMsg.get_string_from_ascii())
	)

c++ code

        if (arg_count != 2) {
		error.error = GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS;
		error.expected = 2;
	}
	String route = args[0]->operator String();
	Variant funcall = *args[1]; // args[1] is lambda but godot-cpp doesn't have it,so I should call it by Variant

    // callab = Variant(funcall) avoid memory free, and add RefCount to let godot know when to free it
    // mutable should add , because c++ lambda capture vars by const
    // finally gdscript lambda can be stored into maps, and be called in future with no Null pointer or Nil type
	pitayaClient.AddRouteOnMessage(route.ascii().get_data(),
			[this, callab = Variant(funcall)](const uint8_t* data, size_t length) mutable {
				PackedByteArray tmpVar;
				if (length != 0) {
					tmpVar.resize(length);
					memcpy(tmpVar.ptrw(), data, length);
				}

				Variant qqt = tmpVar;
				const auto **argptr = (const Variant **)alloca(sizeof(Variant *));
				argptr[0] = &qqt;
				Variant result;
				GDNativeCallError err;
                // call_deferred to keep thread safety
				callab.call("call_deferred", argptr, 1, result, err);
			});

rendawudi avatar Aug 10 '22 09:08 rendawudi