I have just jumped to Unity and I am doing some experiments to retrive data from an API
Below you can see the test code could you please help me to understand if i am the right way or not please?, because probably i am missing the mapper isn't it ?
Thanks in advance.
void Start()
{
comments= StartCoroutine(this.GetComments("https://jsonplaceholder.typicode.com/comments"));
Debug.Log(comments);
}
private IEnumerator Comments GetComments(string url) {
List<Comments> returnComments = new List<Comments>();
UnityWebRequest comments = UnityWebRequest.Get(url)
comments.SendWebRequest();
while (comments.MoveNext())
{
var comment = comments.Current;
returnItems.Add(comment);
}
return returnComments;
}
Yield the SendWebRequest function.
yield return webRequest.SendWebRequest();
Access the data through the download handler.
var dataString = webRequest.downloadHandler.text;
Full sample code in the docs UnityWebRequest.Get
Related
I have a function in unity that makes a request for a server, and for each value in the result, it should call a function to add a image on a list and get an object from the same server and add on another list
public void SaveServer() {
string serverAddress = inputField.text;
GlobalStateData.getInstance().ServerAdress = serverAddress;
StartCoroutine(Utils.GetRequest(GlobalStateData.getInstance().ServerAdress + "file/ObjectController/",
(UnityWebRequest) => {
JArray jsonResponse = JArray.Parse(UnityWebRequest.downloadHandler.text);
foreach (var json in jsonResponse) {
String base64 = (string)json["trackingImage"]["file"]["base64"];
String name = (string)json["file"]["name"];
int objectId = (int)json["id"];
Texture2D texture = Utils.Base64ToTexture2D(base64);
StartCoroutine(addImageAndObject(objectId, texture, name));
}
Debug.Log(jsonResponse);
transform.parent.Find("canvas_MainMenu").gameObject.SetActive(true);
gameObject.SetActive(false);
}));
}
private IEnumerator addImageAndObject(int objectId, Texture2D texture2D, String name) {
StartCoroutine(addImage(texture2D, name));
yield return AddObjectById(objectId, name).MoveNext();
}
but in the AddObjectById the method is stopping before complete the request
private IEnumerator AddObjectById(int id, string name) {
string url = GlobalStateData.getInstance().ServerAdress + "bundle/ObjectBundleController/" + id;
UnityWebRequest get = UnityWebRequest.Get(url);
yield return get.SendWebRequest(); // it stops here
if (get.result != UnityWebRequest.Result.Success) {
Debug.Log(get.error);
yield return false;
}
else {
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(get);
GameObject obj = (GameObject)bundle.LoadAsset(name);
_place3DObjectRef.ArPrefabs.Add(obj);
yield return true;
}
}
I didn't understand how my GetRequest Method Works and the AddObjectById
Here is the GetRequest
public static IEnumerator GetRequest(string server, Action<UnityWebRequest> successCallback, Action<String> errorCallback = null) {
UnityWebRequest get = UnityWebRequest.Get(server);
yield return get.SendWebRequest();
if (get.result != UnityWebRequest.Result.Success) {
Debug.Log(get.error);
if(errorCallback != null)
errorCallback("Cannot make request to " + server +
"\nerror:" + get.error);
yield return false;
}
else {
successCallback(get);
yield return true;
}
}
and this one runs fine.
What should I do to the method to not stops after the first yield return?
EDIT:
I solved the problem!
The reason why this was happening, it was because the gameObject was setting deactivated before the coroutine finishes, so the scripts was stopping
gameObject.SetActive(false);
https://docs.unity3d.com/ScriptReference/GameObject.SetActive.html
The unity documentation says that "Deactivating a GameObject disables each component, including attached renderers, colliders, rigidbodies, and scripts. For example, Unity will no longer call the Update() method of a script attached to a deactivated GameObject. OnEnable or OnDisable are called as the GameObject received SetActive(true) or SetActive(false)." So, as the script is an component attached to the scene object, makes sense that it stops working
Well, yield works by returning results from one iteration,and what comes after will not be executed. In your method, when a call is made to AddObjectById, it will stop at the first yield it finds and return its value, in this case get.SendWebRequest();, not continuing the flow. If you move yield return get.SendWebRequest(); after of if-else, it will never enter, as it will have some return in yield return coming from "if-else".
I found out that if the gameObject is not active gameObject.SetActive(false); the Coroutines stops too. The problem was not with the coroutines but with the gameObject being deactivated
This is my node.js and c# code.
//Node.Js function
exports.test = function (req, res) {
console.log("test called");
res.status(200).send("test called")
}
//C# code
IEnumerator test()
{
WWW www = new WWW("link here:1338/test");
yield return www;
print(www.text);
}
When I access it using postman it return "test called" but when i run it in browser or in unity it gives " no such file or directory". Please help me i have never done this before.
I'm trying to build a tool in the Unity Editor with an EditorWindow on his own. This tool will need to access a MySQL DB through PHP files so I need to use coroutines. I looked for a solution and fall upon a preview package "Editor Coroutine" and installed it. I don't see how it works and the documentation doesn't say anything (or anything i've understanded) about how to use it. Do you know any way to make this thing work properly ?
I've tried to simply do a "StartCoroutine()", to call it from an Editor class or to create an object (GameObject) to call it, but none of this work :/.
Be aware that the accepted answer's while loop completely blocks the Editor until the download is done. For a simple text that might be fine but for larger files this might become an issue.
There is however EditorApplication.update you can subscripe to in order to call a method every frame in the Editor. So for an EditorWindow you could do something like
private IEnumerator currentDownload;
private void ProcessDownload()
{
if(currentDownload!=null) currentDownload.MoveNext();
}
private IEnumerator UpdateVersion(string message)
{
string post_url = NetworkManager.baseUrl + "VersionUpdate.php";
WWWForm form = new WWWForm();
form.AddField("Message", message);
form.AddField("Version", Application.version);
UnityWebRequest www = UnityWebRequest.Post(post_url, form);
www.chunkedTransfer = false;
yield return www.SendWebRequest();
if(www.error == null){
Debug.Log(www.downloadHandler.text);
} else {
Debug.Log("error!: " + www.error);
}
}
and use it like
// makes sure the callback is added only once
EditorApplication.update -= ProcessDownload;
EditorApplication.update += ProcessDownload;
currentDownload = UpdateVersion("whatever string");
I faced the same problem. I ended up with the following code, which executes the webrequest in a non-coroutine method.
private void UpdateVersion(string message)
{
string post_url = NetworkManager.baseUrl + "VersionUpdate.php";
WWWForm form = new WWWForm();
form.AddField("Message", message);
form.AddField("Version", Application.version);
UnityWebRequest www = UnityWebRequest.Post(post_url, form);
www.chunkedTransfer = false;
www.SendWebRequest();
while (!www.isDone)
{
// do nothing
}
if(www.error == null){
Debug.Log(www.downloadHandler.text);
} else {
Debug.Log("error!: " + www.error);
}
}
I have used a coroutine to do a backend service call to retrieve the player categories in my category.cs file:
public override void OnEnter(Page p)
{
backend = globalScriptObject.GetComponent<IBackendController>();
items.Clear ();
StartCoroutine (backend.GetPlayerProfile ( profile =>{
this.maxSelectableItems = Mathf.CeilToInt(profile.level/10+1);
if(this.maxSelectableItems == 7) maxSelectableItems = int.MaxValue;
DisableSelections();
}));
GetPlayerProfile (In a different class which has been called using instance backend of that class)
public IEnumerator GetPlayerProfile(System.Action<Profile> callback){
yield return GetPlayerProfile (callback, false);
}
Issue:
Since i am using an external service call,sometimes the player profile is uploaded with a delay.
I need to make sure that the startcoroutine is finished with result before the rest of the lines of code is executed.
I tried creating the following class after searching from the internet which can make sure the couroutine call is finished before the rest of the lines are executed:
{
StartCoroutine(FinishFirst(5.0f, DoLast));
}
IEnumerator FinishFirst(float waitTime, Action doLast) {
print("in FinishFirst");
yield return new WaitForSeconds(waitTime);
print("leave FinishFirst");
doLast();
}
void DoLast() {
print("do after everything is finished");
print("done");
}
But how can i use the above in my source code is what i would need suggestions from the community.
Also can i do something like yield return waitForSec(Float) in the GetPlayerProfile method?
Thanks !!
Try using WaitUntil.
https://docs.unity3d.com/ScriptReference/WaitUntil.html
Something like this:
IEnumerator GetProfile(){
var profile = null;
yield GetPlayerProfile((p) => {profile = p});
yield WaitUntil(p != null);
this.maxSelectableItems = Mathf.CeilToInt(profile.level/10+1);
if(this.maxSelectableItems == 7) maxSelectableItems = int.MaxValue;
DisableSelections();
}
And then...
StartCoroutine(GetProfile);
I might be asking something that's extremely obvious and I have overlooked something, but I'm trying to create a pause before it does something.
I have seen this being used in many places online -
yield WaitForSeconds(2);
However I get a syntax error of,
"Error CS1528: Expected ; or = (cannot specify constructor arguments
in declaration) (CS1528) (Assembly-CSharp)
Which confuses me as im not really sure what yield as a keyword really means or does, and im under the assumption that WaitForSeconds is a class of its on with the "2" being in the constructor (not in a declaration) any help would be appreciated. thanks!
What you want is t use an IEnumerator.
IEnumerator Example()
{
print(Time.time);
yield return new WaitForSeconds(5);
print(Time.time);
}
Then you will ask: How do I call this?
void Start()
{
print("Starting " + Time.time);
StartCoroutine(WaitAndPrint(2.0F));
print("Before WaitAndPrint Finishes " + Time.time);
}
IEnumerator WaitAndPrint(float waitTime)
{
yield return new WaitForSeconds(waitTime);
print("WaitAndPrint " + Time.time);
}
I just read the link Jon Skeet posted on the comments, I too recommend it, it has pretty valuable information.
You are using the Javascript code for Unity, and try it in the C# language, that´s why you get the error message.
If you click on the C# language selector on a page like http://docs.unity3d.com/ScriptReference/WaitForSeconds.html
you will get the following example code for C#:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
IEnumerator Example() {
print(Time.time);
yield return new WaitForSeconds(5);
print(Time.time);
}
}