I have an object and a script attached to it.
I want to send data to a web server in script's Update function.
So I create a WWW object.
But after some time Unity begins to report "thread shouldn't be running anymore".
Here is the Update function:
void Update ()
{
//ambil tindakan dari server
//bikin object www
//bikin request ke localhost/vacuum?r=index/action
//ambil hasilnya (json)
//ambil perintah
//eksekusi perintah
//scan lingkungan
var fwd = transform.TransformDirection (Vector3.forward);
var left = transform.TransformDirection (Vector3.left);
var right = transform.TransformDirection (Vector3.right);
var back = transform.TransformDirection (Vector3.back);
RaycastHit hit_fwd = new RaycastHit(),
hit_left = new RaycastHit(),
hit_right = new RaycastHit(),
hit_back = new RaycastHit();
bool bool_hit_fwd, bool_hit_left, bool_hit_right, bool_hit_back;
float
distance_fwd = 0.0f,
distance_left = 0.0f,
distance_right = 0.0f,
distance_back = 0.0f;
bool_hit_fwd = Physics.Raycast (transform.position, fwd, out hit_fwd, 50);
bool_hit_left = Physics.Raycast (transform.position, left, out hit_left, 50);
bool_hit_right = Physics.Raycast (transform.position, right, out hit_right, 50);
bool_hit_back = Physics.Raycast (transform.position, back, out hit_back, 50);
if (bool_hit_fwd)
{
distance_fwd = hit_fwd.distance;
}
if (bool_hit_left)
{
distance_left = hit_left.distance;
}
if (bool_hit_right)
{
distance_right = hit_right.distance;
}
if (bool_hit_back)
{
distance_back = hit_back.distance;
}
transform.Rotate(0, 0.01f, 0);
print(
"rot-y/pos-x/pos-y :: fwd/left/right/back = " +
transform.rotation.eulerAngles.y + '/' +
transform.position.x + '/' +
transform.position.y + '/' +
" :: " +
distance_fwd + '/' +
distance_left + '/' +
distance_right + '/' +
distance_back);
String url = "http://localhost:1234/minibrain?" +
"roty=" + transform.rotation.eulerAngles.y.ToString() +
"&posx=" + transform.position.x.ToString() +
"&posy=" + transform.position.y.ToString() +
"&fwddist=" + distance_fwd.ToString() +
"&leftdist=" + distance_left.ToString() +
"&rightdist=" + distance_right.ToString() +
"&backdist=" + distance_back.ToString();
WWW www = new WWW(url);
}
There is no error. Data was received correctly by the web server. But the data transmission rate decreased greatly. Like down to 10 transmissions per second from 100 transmissions per second.
Is there a way to create WWW object without causing "thread shouldn't be running anymore"?
The problem here is most likely that you run everything in your Update(). That will generally steam ahead as fast as it can. Your call to WWW will return immediately (it won't wait until all actions are done) and you move on to your next frame.
As a result, if your Update runs fast enough, you'll end up with more and more WWW objects that haven't completed. I don't know how fast it is currently running, but you have to ask yourself if you either need that many data points, or if going trough a WWW call is the best approach. If available on your setup, a socket connection might work better.
If you're happy with sending data as fast as it can be handled, make sure you check for the isDone by making the call a coroutine, or in that case just yield for its return. (Don't use a while loop on it) Or perhaps just determine a regular interval at which you'd like the data, and send it at that, if that ends up being easier on your setup there.
Use coroutines. It is bad experience to implement web requests in Update() function, because web requests need some time to be executed.
Related
Anyone knows any method on how i can store the Ping in a float value so later i can display it in a chart. Currently with the below code, Pinging is only displaying -1 while in the text the correct ping is showing. Thanks
Ping Code
IEnumerator TestPing()
{
var PingTest = new Ping("http://localhost:8081/website/index.php");
pinging = PingTest.time;
while (!PingTest.isDone)
yield return new WaitForSeconds(.1f);
pingText.text = (PingTest.time).ToString() + " ms";
}
Seems you may want to get the ping time after isDone?
IEnumerator TestPing()
{
var PingTest = new Ping("http://localhost:8081/website/index.php");
while (!PingTest.isDone)
yield return new WaitForSeconds(.1f);
pinging = PingTest.time;
pingText.text = pinging + " ms";
}
PingTest.time is an int - a value type. And pinging is a float - also a value type. That means, when you assign pinging = PingTest.time, you are assigning the current value of PingTest.time to pinging and that no matter what happens to PingTest.time after that, the value of pinging will not change unless you update it.
If you want pinging to have the value of PingTest.time value after the pinging is done, you have to set it after the pinging is done. You can use WaitUntil for this, by the way:
IEnumerator TestPing()
{
var PingTest = new Ping("http://localhost:8081/website/index.php");
yield return new WaitUntil(()=>PingTest.isDone);
pinging = PingTest.time;
pingText.text = (PingTest.time).ToString() + " ms";
}
By the way, typical convention for C# is to name local variables in camelCase like pingTest.
I have the following upload code using Unity's UnityWebRequest API (Unity 2019.2.13f1):
public IEnumerator UploadJobFile(string jobId, string path)
{
if (!File.Exists(path))
{
Debug.LogError("The given file to upload does not exist. Please re-create the recording and try again.");
yield break;
}
UnityWebRequest upload = new UnityWebRequest(hostURL + "/jobs/upload/" + jobId);
upload.uploadHandler = new UploadHandlerFile(path);
upload.downloadHandler = new DownloadHandlerBuffer();
upload.method = UnityWebRequest.kHttpVerbPOST;
upload.SetRequestHeader("filename", Path.GetFileName(path));
UnityWebRequestAsyncOperation op = upload.SendWebRequest();
while (!upload.isDone)
{
//Debug.Log("Uploading file...");
Debug.Log("Uploading file. Progress " + (int)(upload.uploadProgress * 100f) + "%"); // <-----------------
yield return null;
}
if (upload.isNetworkError || upload.isHttpError)
{
Debug.LogError("Upload error:\n" + upload.error);
}
else
{
Debug.Log("Upload success");
}
// this is needed to clear resources on the file
upload.Dispose();
}
string hostURL = "http://localhost:8080";
string jobId = "manualUploadTest";
string path = "E:/Videos/short.mp4";
void Update()
{
if (Input.GetKeyDown(KeyCode.O))
{
Debug.Log("O key was pressed.");
StartCoroutine(UploadAndTest(jobId, path));
}
}
And the files I receive on the server side arrive broken, especially if they are larger (30 MB or more). They are missing bytes in the end and sometimes have entire byte blocks duplicated in the middle.
This happens both when testing client and server on the same machine or when running on different machines.
The server does not complain - from its perspective, no transport errors happened.
I noticed that if I comment out the access to upload.uploadProgress (and e.g. instead use the commented-out debug line above it which just prints a string literal), the files stay intact. Ditching the wile loop altogether and replacing it with yield return op also works.
I tested this strange behavior repeatedly in an outer loop - usually after at most 8 repetitions with the "faulty" code, the file appears broken. If I use the "correct" variant, 100 uploads (update: 500) in a row were successful.
Has upload.uploadProgress side-effects? For what it's worth, the same happens if I print op.progress instead - the files are also broken.
This sounds like a real bug. uploadProgress obviously should not have side effects.
So i'm currently working on a game with unity, it's an air hockey. And i would like to add a multiplayer mode (1 vs 1).
So after the player have a match with an opponent, they are connected in a room where the game begins.
But i'm having issue when i want to receive the opponent message.
In the player script movement, i add this on the void update()
Multiplayer.Instance.SendMyUpdate(positionX, PositionZ);
and in the multiplayer script, i add this:
public void SendMyUpdate(float posX, float posZ) {
string PlayerUserNameString = PlayGamesPlatform.Instance.RealTime.GetSelf ().DisplayName;
char[] characters = PlayerUserNameString.ToCharArray ();
string data = characters + ":" + posX + ":" + posZ;
byte[] bytedata = System.Text.ASCIIEncoding.Default.GetBytes (data);
PlayGamesPlatform.Instance.RealTime.SendMessageToAll (false, bytedata);
}
And on the method OnRealTimeMessageReceived:
string rawdata = System.Text.ASCIIEncoding.Default.GetString (data);
string[] cut = rawdata.Split (new string[] { ":" }, System.StringSplitOptions.RemoveEmptyEntries);
OpponentUserName = System.Convert.ToSingle (cut[1]).ToString();
Transform target = GameObject.Find ("mallet Opponent").transform;
Vector3 newpos = new Vector3
(
System.Convert.ToSingle(cut[2]),
0,
System.Convert.ToSingle(cut[3])
);
After i wrote this and build it on two devices, when the room is connected and the game begins, the opponent player doesn't move at all, and i don't know where the issue.
Any ideas?
Arrays are zero based so opponent user name should be cut[0] and:
System.Convert.ToSingle(cut[3])
cut[3] will look for the 4th split result and there are only three so an exception will occur. That is enough to prevent the method working and the position updating. If so there should also be an error in the console log.
However perhaps the OnRealTimeMessageReceived is not even being called. You need to throw in some breakpoints and debug, or add some debug logs to see how far things are getting. If it isn't even getting to a method you expect then the question can be rephrased "why is method X not being called"
This project is develop in Unity3d and build it to iOS.
This is my .cs file.
IEnumerator DownloadModel(string modelUrl)
{
isDownloading = true;
// Wait for the Caching system to be ready
while (!Caching.ready)
yield return null;
// Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
WWW www = WWW.LoadFromCacheOrDownload (modelUrl, 1);
Debug.Log ("modelURL : " + modelUrl);
while (!www.isDone) {
progressText.text = "Progress : " + (www.progress * 100).ToString ("N0") + "%";
Debug.Log("Download Progress : " + (www.progress * 100).ToString ("N0") + "%");
yield return null;
}
yield return www;
isDownloading = false;
if (www.error != null) {
throw new UnityException ("WWW download had an error:" + www.error);
}
AssetBundle bundle = www.assetBundle;
downloadedObjectContainer = bundle.LoadAllAssets ();
// tempObj = Instantiate(downloadedObjectContainer[0]) as GameObject;
//
// tempObj.transform.SetParent(this.transform);
isDownloading = false;
// Unload the AssetBundles compressed contents to conserve memory
bundle.Unload (false);
// memory is freed from the web stream (www.Dispose() gets called implicitly)
Debug.LogWarning ("START CALLING OUT OBJECT");
if (downloadedObjectContainer[0] != null) {
Debug.Log("Downloadable content count : " + downloadedObjectContainer.Length );
currentDownloadedModel = Instantiate(downloadedObjectContainer[0]) as GameObject;
Debug.Log("OBJECT INSTANTIATE.");
currentDownloadedModel.transform.SetParent(this.transform);
//set the ARContent and ImageTarget
sic.setARContentAndMarker(currentDownloadedModel, ImageTarget);
Debug.Log("CONTENT MARKER SET.");
currentDownloadedModel.SetActive(true);
}
Debug.LogWarning ("COROUTINE FINISHED");
}
and my "currentDownloadedModel" is declared at the top as GameObject.
public class cloudTrackableEventHandler : MonoBehaviour{
GameObject currentDownloadedModel;
When i build my App to Android, there is no problem at all. But once i build it in iOS, this error occurs
START CALLING OUT OBJECT
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 64)
Downloadable content count : 1
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 64)
MarcV2 was compiled with optimization - stepping may behave oddly; variables may not be available.
By the Debug.Log(), I found out that the problem occurs when I want to assign the currentDownloadedModel with the model i instantiate. Can anyone help me on this ? Thanks in advance.
Note : the "Script call optimization" at the unity player settings is set to "slow and safe"
For anyone who also face this problem, try uncheck the "Strip Engine Code" at File > Build Settings > Player Settings (iOS).
http://docs.unity3d.com/Manual/iphone-playerSizeOptimization.html
I have a function which have a long execution time.
public void updateCampaign()
{
context.Session[processId] = "0|Fetching Lead360 Campaign";
Lead360 objLead360 = new Lead360();
string campaignXML = objLead360.getCampaigns();
string todayDate = DateTime.Now.ToString("dd-MMMM-yyyy");
context.Session[processId] = "1|Creating File for Lead360 Campaign on " + todayDate;
string fileName = HttpContext.Current.Server.MapPath("campaigns") + todayDate + ".xml";
objLead360.createFile(fileName, campaignXML);
context.Session[processId] = "2|Reading The latest Lead360 Campaign";
string file = File.ReadAllText(fileName);
context.Session[processId] = "3|Updating Lead360 Campaign";
string updateStatus = objLead360.updateCampaign(fileName);
string[] statusArr = updateStatus.Split('|');
context.Session[processId] = "99|" + statusArr[0] + " New Inserted , " + statusArr[1] + " Updated , With " + statusArr[2] + " Error , ";
}
So to track the Progress of the function I wrote a another function
public void getProgress()
{
if (context.Session[processId] == null)
{
string json = "{\"error\":true}";
Response.Write(json);
Response.End();
}else{
string[] status = context.Session[processId].ToString().Split('|');
if (status[0] == "99") context.Session.Remove(processId);
string json = "{\"error\":false,\"statuscode\":" + status[0] + ",\"statusmsz\":\"" + status[1] + "\" }";
Response.Write(json);
Response.End();
}
}
To call this by jQuery post request is used
reqUrl = "AjaxPages/lead360Campaign.aspx?processid=" + progressID + "&action=updatecampaign";
$.post(reqUrl);
setTimeout(getProgress, 500);
get getProgress is :
function getProgress() {
reqUrl = "AjaxPages/lead360Campaign.aspx?processid=" + progressID + "&action=getProgress";
$.post(reqUrl, function (response) {
var progress = jQuery.parseJSON(response);
console.log(progress)
if (progress.error) {
$("#fetchedCampaign .waitingMsz").html("Some error occured. Please try again later.");
$("#fetchedCampaign .waitingMsz").css({ "background": "url(common/images/ajax_error.jpg) no-repeat center 6px" });
return;
}
if (progress.statuscode == 99) {
$("#fetchedCampaign .waitingMsz").html("Update Status :"+ progress.statusmsz );
$("#fetchedCampaign .waitingMsz").css({ "background": "url(common/images/ajax_loded.jpg) no-repeat center 6px" });
return;
}
$("#fetchedCampaign .waitingMsz").html("Please Wait... " + progress.statusmsz);
setTimeout(getProgress, 500);
});
}
But the problem is that I can't see the intermediate message. Only the last message is been displayed after a long lime of ajax loading message
Also on the browser console I just see that after a long time first requested is completed and after that the second request is completed. but there should be for getProgress ?
I have checked jquery.doc and it says that $post is an asynchronous request.
Can anyone please explain what is wrong with the code or logic?
You are in a situation discussed here:
ASP.net session request queuing
While a request for a given user's session is processed, other requests for the same session are waiting. You need to run your long function in a background thread and let the request that initiates it finish. However, the background thread will not have access to session, and you will need a different mechanism to communicate its progress.
From the information you've provided, I would suspect that it's not your javascript code that's being synchronous, but rather the server-side code. You can test this by using Firebug or Chrome's dev tools to look at the start and end times of the two AJAX requests. If I'm right, you'll see that the second request begins after half a second, but doesn't complete until after the first one.
If that's the case, possible causes are:
Running in a dev environment in Visual Studio, especially in debug mode, seems to reduce the amount of asynchronicity. The dev environment seems to like to process one request at a time.
See Igor's answer about session request queueing.
You may have code that explicitly locks resources and causes the second request to block until the long-running request is done.
One other possible culprit is the fact that most browsers only allow a limited number of concurrent requests to a particular domain. If you have a few requests pending at any given moment, the browser may just be queuing up the remaining requests until they return.