GET Request dont save data - c#

I'm trying to save some data from a GET request. I use StartCoroutine to request and I use Lambda expression for save the data.
My Code is this:
Using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour {
// Use this for initialization
public void Start () {
string url1 = "http://localhost/virtualTV/query/?risorsa=";
string ciao = "http://desktop-pqb3a65:8080/marmotta/resource/ef299b79-35f2-4942-a33b-7e4d7b7cbfb5";
url1 = url1 + ciao;
WWW www1 = new WWW(url1);
var main=new JSONObject(JSONObject.Type.OBJECT);
var final= new JSONObject(JSONObject.Type.OBJECT);;
StartCoroutine(firstParsing((value)=>{main = value;
final= main.Copy();
Debug.Log(main);
}));
Debug.Log(final);
}
public IEnumerator firstParsing( System.Action<JSONObject> callback)
{
string url2 = "http://localhost/virtualTV/FirstQuery/?risorsa=";
string ciao = "http://desktop-pqb3a65:8080/marmotta/resource/ef299b79-35f2-4942-a33b-7e4d7b7cbfb5";
url2 = url2 + ciao;
WWW www2 = new WWW(url2);
yield return www2;
string json = www2.text;
//Parsing del json con creazione di un array
var firstjson = new JSONObject(json);
var tempVideo = new JSONObject(JSONObject.Type.OBJECT);
var array2 = new JSONObject(JSONObject.Type.OBJECT);
tempVideo.AddField ("id", firstjson.GetField ("id"));
tempVideo.AddField ("type", firstjson.GetField ("type"));
tempVideo.AddField ("url", firstjson.GetField ("url"));
array2.Add (tempVideo);
yield return array2;
callback (array2);
Debug.Log ("First Run" + array2);
}
When I try to use FINAL after the command,
final=main.copy()
it is empty. Can you help me to save the value in the variable final? Thanks all.

A coroutine's execution is spread across many frames. When a coroutine encounters a yield return statement, it returns to the calling method, which finishes executing, till the task finishes.
In your case, the Debug.Log(final) statement in Start executes as soon as yield return www2; in firstParsing is executed. The callback hasn't been called yet which is why final is empty.
To be able to access the value in final after it has been assigned outside the callback function, you will have to set a bool which is set to true after final is assigned in the callback. Something like this:
StartCoroutine(firstParsing((value)=>{main = value;
final= main.Copy();
Debug.Log(main);
isFinalAssigned = true;
}));
// In another method
if(isFinalAssigned)
{
// Access final
}
You will have to note that the above if statement is useful only in a method that is called periodically like Update. If you're accessing final in a method that is called only once (like OnEnable) you will have to wait for final to be assigned. You can use another coroutine for this task like
IEnumerator DoSomethingWithFinal()
{
while(!isFinalAssigned)
yield return null; // Wait for next frame
// Do something with final
}
The easiest way out is to consume (access) final in your callback.
EDIT2: From your comments, you can do something like the following. You will have to use coroutines, because blocking the main game thread is not a good idea.
private JSONObject final = null; // Make final a field
Wherever you use final, you have two options.
Use a null check if(final == null) return; This can be impractical.
Wait for final to be assigned in a coroutine and do something as a callback. This is the only way you can do what you want cleanly.
Look below for the implementation.
// Calls callback after final has been assigned
IEnumerator WaitForFinal(System.Action callback)
{
while(final == null)
yield return null; // Wait for next frame
callback();
}
// This whole method depends on final.
// This should be similar to your method set up if you have
// good coding standards (not very long methods, each method does only 1 thing)
void MethodThatUsesFinal()
{
if (final == null)
{
// Waits till final is assigned and calls this method again
StartCoroutine(WaitForFinal(MethodThatUsesFinal));
return;
}
// use final
}

Related

Attempting to load AssetReference that has already been loaded

When I start the main scene and test a new character it shows this error why?
Attempting to load AssetReference that has already been loaded. Handle is exposed through getter OperationHandle
UnityEngine.AddressableAssets.AssetReference:LoadAssetAsync<UnityEngine.GameObject> ()
TrackManager/<SpawnFromAssetReference>d__104:MoveNext () (at Assets/Scripts/Tracks/TrackManager.cs:565)
UnityEngine.MonoBehaviour:StartCoroutine (System.Collections.IEnumerator)
TrackManager:SpawnObstacle (TrackSegment) (at Assets/Scripts/Tracks/TrackManager.cs:556)
TrackManager/<SpawnNewSegment>d__102:MoveNext () (at Assets/Scripts/Tracks/TrackManager.cs:538)
UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr)
my code :
if (m_SafeSegementLeft <= 0)
{
SpawnObstacle(newSegment);
}
else
m_SafeSegementLeft -= 1;
m_Segments.Add(newSegment);
if (newSegmentCreated != null) newSegmentCreated.Invoke(newSegment);
}
public void SpawnObstacle(TrackSegment segment)
{
if (segment.possibleObstacles.Length != 0)
{
for (int i = 0; i < segment.obstaclePositions.Length; ++i)
{
AssetReference assetRef = segment.possibleObstacles[Random.Range(0, segment.possibleObstacles.Length)];
StartCoroutine(SpawnFromAssetReference(assetRef, segment, i));
}
}
StartCoroutine(SpawnCoinAndPowerup(segment));
}
private IEnumerator SpawnFromAssetReference(AssetReference reference, TrackSegment segment, int posIndex)
{
AsyncOperationHandle op = reference.LoadAssetAsync<GameObject>();
yield return op;
GameObject obj = op.Result as GameObject;
if (obj != null)
{
Obstacle obstacle = obj.GetComponent<Obstacle>();
if (obstacle != null)
yield return obstacle.Spawn(segment, segment.obstaclePositions[posIndex]);
}
}
It says i have error in line 565 which is AsyncOperationHandle op = reference.LoadAssetAsync<GameObject>();
What is the error here?
The error message sounds quite self-explanatory: You try to load the same addressable twice.
As said in
AssetReference assetRef = segment.possibleObstacles[Random.Range(0, segment.possibleObstacles.Length)];
you pick a random entry from available addressables. However, nothing here prevents that you get casually the same element twice.
I would rather either keep track of which ones already are loaded
Dictionary<AssetReference, GameObject> loadedAssets = new Dictionary<AssetReference, GameObject>();
and then do
private IEnumerator SpawnFromAssetReference(AssetReference reference, TrackSegment segment, int posIndex)
{
if(!loadedAssets.TryGetValue(reference, out var obj || !obj)
{
loadedAssets.Add(reference, null);
AsyncOperationHandle op = reference.LoadAssetAsync<GameObject>();
yield return op;
obj = op.Result;
loadedAssets[reference] = obj;
}
if(!obj.TryGetComponent<Obstacle>(out var obstacle))
{
Debug.LogError($"No {nameof(Obstacle)} component on loaded object!");
yield break;
}
yield return obstacle.Spawn(segment, segment.obstaclePositions[posIndex]);
}
And then of course whenever you Release one of the loaded assets you also want to
loadedAssets.Remove(reference);
Or depending on your use case and needs load them all and then start your app if you are going to spawn them more often anyway.
Following derHugo approach of storing values I came up with this to always have the addressable result ready to be returned as a gameobject but prevent it to be loaded more than once, addressables also has a 'address.LoadAssetAsync().WaitForCompletion()' method but in my case when loading many things it gets too laggy.
private async Task<T> GetNewInstance<T>(AssetReferenceGameObject address) where T : MonoBehaviour
{
if (!loadedAssetsTask.ContainsKey(address))
{
LoadNewAddress<T>(address);
}
var asset = await loadedAssetsTask[address];
var newGameObject = Instantiate(asset);
var component = newGameObject.GetComponent<T>();
return component;
}
private void LoadNewAddress<T>(AssetReferenceGameObject address) where T : MonoBehaviour
{
var loadedAssetTask = address.LoadAssetAsync().Task;
loadedAssetsTask.Add(address, loadedAssetTask);
}
A little bit late, but after some dig up I found the explaination from Unity_Bill:
AssetReference.LoadAssetAsync() is a helper we've provided that you in
no way need to use when loading an AssetReference.
Addressables.LoadAssetAsync(AssetReference) will work just as well. If
you do the latter, the async operation handle is returned to you and
you are in charge of it. You can call that as many times as you want,
and get as many handles as you want. Each will be ref-counted.
If you choose to use the AssetReference.LoadAssetAsync() helper, the
asset reference itself will hold on to the handle. This enabled the
helper method AssetReference.ReleaseAsset(). Prior to 1.15.1, if you
called load twice, the first handle would simply get stomped. If you
happened to keep up with it, great, but if not, it was lost forever.
So, in short, AssetReference.LoadAssetAsync() is a convenience helper
that really only works in the most simple case. If you are doing
anything beyond the simple, and are keeping up with the handles
yourself, just use Addr.Load... If I were starting addressables over I
likely wouldn't have the helpers at all, requiring the
Addressables.Load..(AssetRef) be used instead.
TLDR: Use Addressables.LoadAssetAsync(AssetReference) instead of AssetReference.LoadAssetAsync
You can read more here: https://forum.unity.com/threads/1-15-1-assetreference-not-allow-loadassetasync-twice.959910/

C# - Try something twice if if-statement is true

I have a code parsing a website and adding some values to a list. Sometimes I need to parse the website two times and add the second parsevalues to the same list.
This is some of the code:
public async Task<IEnumerable<Info>>....
{
var values = new List<Info>();
var request = something;
var request_rewritten = rewritten request to run the second time;
......
if request contains something do all the under two times. Both for the request and the rewritten request and add it to result.
......
var response = await RequestBytes(request);
var results = Encoding.GetEncoding("iso-8859-1").GetString(response.Content);
_fDom = results;
try
{
do something and a lot of code
......
values.Add(result);
return result
}
}
If request contains something I need try try a second time. Both for the original request and the rewritten request and add both to the result. Can this be done?
You can follow this pattern. Add an additional parameter to your method indicating retries remaining.
void DoSomething(arg1, arg2, int retriesRemaining = 0)
{
try
{
DoWork();
}
catch
{
if (retriesRemaining) DoSomething(arg1, arg2, --retriesRemaining);
}
}
I suppose if you want to avoid writing a method (which is the best answer to your question) you can use a flag:
bool bRunAgain = true;
while (bRunAgain)
{
// Your logic, check result and see if you need to run it again
if (your condition to run again == false)
{
bRunAgain = false;
}
}
Here is a common solution. Pass an action to this method and specify retries count
public bool ExecuteWithRetry(Action doWork, int maxTries=1) {
for(var tryCount=1; tryCount<=maxTries; tryCount++){
try{
doWork();
} catch(Exception ex){
if(tryCount==MaxTriex){
Console.WriteLine("Oops, no luck with DoWork()");
return false;
}
}
return true;
}
}
so in your method
void Something(){
....
if(ExecuteWithRetry(()=>NotTrustyMethod(), 2)) {
//success
} else {
//fail
}
}
void NotTrustyMethod(){ ...}
This solution you can use for any case where you need retry option for methods with any type of arguments (or without them)

Is there a way to store and later execute an arbitrary function call

I know in javascript, I can pass in a function name, and an array of vars, and then execute that function with those vars at an arbitrary moment in time later.
It makes it easier that everything is basically the same var thing. In C#, there is also var, but it looks like the type gets defined depending on what you place into it.
What I am trying to accomplish is to say:
take the function and parameters:
foo(bar1,bar2...barN)
and execute them in 5 seconds.
I'm using Unity, so the timing part is simple, but I can't figure out how to pass a function and specify arbitrary possible parameters of arbitrary types.
pseudo code:
class myTimerClass{
functionHandle myFunction;
var params;
float startTime, delayTime;
bool pending = false;
public myTimerClass(functionHandle myFunction, var params, float delay){
this.myFunction = myFunction;
this.params = params;
this.delay = delay;
this.startTime = System.currentTime;
pending = true;
}
public void update(){
if(System.currentTime>=startTime+delay && pending){
pending = false;
INVOKE(myFunction,params);
}
}
}
<something calls the update() every frame>
I've read up on action and func<> and delegates, but there doesn't seem to be a way to handle an arbitrary function with arbitrary params.
After more searching, I finally found what works:
http://answers.unity3d.com/answers/932529/view.html
I can pass literally any code and it will execute at any time. Perfect!
Now I have a separate class (just to keep it neat) that has the following block:
public void doThingAfterTime(System.Action action, float time){
StartCoroutine(CoroutineUtils.DelaySeconds(action,time));
}
So I can do something like
doThingAfterTime (() => doPrint ("s", "d"), 2);
that will work find to call that function, that, for reference is:
public void doPrint(string s, string s2){
print (s);
print (s2);
}

can a value be stored in variable returned by a function called as a parameter

Hi I was integrating facebook SDK in unity and basically I worked in java earlier and I am new to c# script and a question came to my mind.
I have searched a lot found nothing, may be my searching query is good enough or not but my question is ...
as a function FB.init called here
void Awake ()
{
FB.Init(InitCallback, OnHideUnity);
}
here when init function will be called it will call InitCallBack and OnHideUnity functions and both are returning void these are used form facebook-unity-sdk docs
private void InitCallback ()
{
if (FB.IsInitialized) {
// Signal an app activation App Event
FB.ActivateApp();
// Continue with Facebook SDK
// ...
} else {
Debug.Log("Failed to Initialize the Facebook SDK");
}
}
private void OnHideUnity (bool isGameShown)
{
if (!isGameShown) {
// Pause the game - we will need to hide
Time.timeScale = 0;
} else {
// Resume the game - we're getting focus again
Time.timeScale = 1;
}
}
My question is if I call a function like this and that function return something e.g String and I want wanted to store it something like this
String result="";
SomeFunctions(FunctionOne,result=FunctionTwo);
String FunctionTwo()
{
return "a String";
}
Is this possible?
Is there any way to get value returned by such function call?
Or is this possible that a function that returns value can be called in this way?
It seems like you are confusing a delegate for a function expression. The delegate will have no return value until it is invoked as a function.
void SomeFunction(Func<string> func) {
var result = func(); // only here will the function return value be accessible
Console.WriteLine(result);
}
SomeFunction(() => "test");
Although you do not have access to the return value of the function, the delegate could assign a variable you choose inside it's method body, instead of using it's return value:
string result;
SomeFunction(() => {
result = "test";
return result;
});
// result would now contain "test"
I am not sure what you want to achieve here, but you could use out to change the reference of the parameter.
string result="";
MyMethod(out result);
Debug.Log(string.Format("Result: {0}", result));
void MyMethod(out string pValue)
{
pValue = "my changed value";
}
The out keyword causes arguments to be passed by reference. This is like the ref keyword, except that ref requires that the variable be initialized before it is passed. To use an out parameter, both the method definition and the calling method must explicitly use the out keyword.
https://msdn.microsoft.com/en-us/library/t3c3bfhx.aspx
But in a case like this, you could just return the correct value. In the example below its not even worth passing the parameter since we are not using it.
string result = MyMethod(result);
string MyMethod(string pValue)
{
pValue = "My changed value";
return pValue;
}

I want to create a global array in order to listen for events

I have a coroutine that is invoked several times on my scene.
IEnumerator Save_assets(string file, int i, string name){
var filename = Path.GetFileName(file);
docPath = Application.streamingAssetsPath+"/files/";
var temp_name = docPath+filename;
downloaded_asset = false;
if(!Directory.Exists(docPath)){
Directory.CreateDirectory(docPath);
}
if (!System.IO.File.Exists(temp_name)){
WWW www = new WWW(file);
yield return www;
//Save the image
System.IO.File.WriteAllBytes(temp_name, www.bytes);
}
/* I really would like to have a sort of listener here doing something like:
//pseudocode
while(global.file != true){ //while not done
yield return null;
}
*/
downloaded_asset = true;
finished = false;
tries = 0;
go = GameObject.Find(name);
go.gameObject.BroadcastMessage("paint_file", temp_name);
}
Once paint_file has been invoked the Update function on that very class
is constantly looking for a certain condition to happen, let's say it's "done = true;"
void paint_file(file){
[...]//code
}
void Update () {
var done = true;//let's pretend there's no code here, just done = true
if(done){
Debug.Log("Finished: "+paint_file._filename);
}
}
I have no idea how to set this var global.file = done,
any help would be greatly appreciated
Avoid ever using globals ( statics or singletons ) use direct callbacks instead or hook stuff up with component/object references
Also avoid Find, and broadcastMessage ideally as they are slow :-)
instead have:
var SomeComponentType myReferenceToThatComponent;
on Awake(){
if(myReferenceToThatComponent==null){
myReferenceToThatComponent = GetComponent<SomeComponentType>();
}
}
Once you have a reference to a component you can access any public items on it eg:
myReferenceToThatComponent.done = true;
myReferenceToThatComponent.SomeMethod( true );
benefit is you can set that reference in the Editor, but if you don't set it leaving it null, it goes and tries to find it, and it only finds it once, any further use will uses the cached result and not have to use an expensive search again.
Your www should be surrounded with a 'using' as is the common practice to make sure it garbage collects when done
using ( WWW www = new WWW( url, form ) ) {
yield return www;
}
The myriad of approaches to finding and getting components and objects is beyond the scope of this answer I think
Just remember Unity is preferably Component based which is quite different to the typical OOP Inheritance/Interface style of C# coding.
-
Way to structure Coroutines to run one after another waiting for one to complete:
void Start() {
StartCoroutine( BaseRoutine() );
}
IEnumerator BaseRoutine() {
for ( int i = 0; i < 10; i++ ) {
yield return StartCoroutine( ChildRoutine( i ) );
}
}
IEnumerator ChildRoutine( int i ) {
Debug.Log( "ChildRoutine number: " + i );
yield return new WaitForSeconds( 1 ); // Put your yield return WWW here for example
}

Categories