In my script im expecting the text bytesDownloadedText to be updated with how many bytes have been downloaded so far but it only runs once and stays on 0. How do I fix this
private IEnumerator DownloadFile(){
WWW w = new WWW (PATH_TO_DOWNLOAD);
bytesDownloadedText.text = w.bytesDownloaded.ToString();
yield return w;
if (w.error != null) {
Debug.LogError ("Error: " + w.error);
} else {
scriptText = w.text;
filesDownloaded = true;
Debug.Log (scriptText);
}
}
Edit: New code + Additional debugging information
private IEnumerator DownloadFile(){
WWW w = new WWW (PATH_TO_DOWNLOAD);
while(!w.isDone){
bytesDownloadedText.text = w.bytesDownloaded.ToString ();
Debug.Log ("Bytes Downloaded: " + w.bytesDownloaded);
yield return null;
}
Debug.Log ("Exiting while loop");
if (w.error != null) {
Debug.LogError ("Error: " + w.error);
} else {
//bytesDownloadedText.text = w.bytesDownloaded.ToString ();
scriptText = w.text;
filesDownloaded = true;
Debug.Log (scriptText);
}
}
Filesize: 337 bytes
Download Path: https://deathcrow.altervista.org/websharp/files.php
3.Code where DownloadFile is called
private void Start(){
StartCoroutine (DownloadFile ());
}
The while loop is exiting
w.text returns the test script from the server(which is code)
using UnityEngine;
public class TestScript: MonoBehaviour{
public void Update(){
if (Input.GetMouseButtonDown (0)) {
RaycastHit hit;
if (Physics.Raycast (Camera.main.ScreenPointToRay(Input.mousePosition),out hit)){
if (hit.transform.tag == "Destroy") {
Destroy (hit.transform.root.gameObject);
}
}
}
}
}
Edit: Online code
<?
$scriptText = "";
$file_handle = fopen("TestScript.cs","r");
while(!feof($file_handle)){
$line = fgets($file_handle);
$scriptText = $scriptText . $line;
}
fclose($file_handle);
$size = strlen($scriptText);
header("Content-length: ".$size);
echo $scriptText;
?>
Do not yield WWW if you want to use the bytesDownloaded property as that will pause your code until WWW returns which makes it impossible to read how much data has been downloaded.
You have to put WWW.bytesDownloaded in a loop then use WWW.isDone to detect when WWW is done and then exit the loop. Inside that loop, you can use WWW.bytesDownloaded to display the downloaded data. Finally, you must wait for a frame after each loop so that other scripts can execute or Unity will freeze until the download is done.
This is what that code should look like:
private IEnumerator DownloadFile()
{
WWW w = new WWW(PATH_TO_DOWNLOAD);
while (!w.isDone)
{
yield return null;
bytesDownloadedText.text = w.bytesDownloaded.ToString();
Debug.Log("Bytes Downloaded: " + w.bytesDownloaded);
}
if (w.error != null)
{
Debug.LogError("Error: " + w.error);
}
else
{
scriptText = w.text;
filesDownloaded = true;
Debug.Log(scriptText);
}
}
Note: There are some instances where the bytesDownloaded property returns 0. This has nothing to do with Unity. This happens mostly when your server is not sending the Content-Length header.
Example of sending the Content-Length header from the server(php):
<?php
//String to send
$data = "Test message to send";
//Get size
$size= strlen($data);
//Set Content-length header
header("Content-length: ".$size);
//Finally, you can send the data
echo $data;
?>
Related
I am trying to figure out how to stop UnityWebRequest download immediately with a button in android application.
Stopping coroutine with StopCoroutine("downLoadFromServer"); does not stop UnityWebRequest.
I tried using UnityWebRequest.Dispose(); or UnityWebRequest.Abort(); with no success.
Below is the download i'm trying to stop.
private IEnumerator downLoadFromServer()
{
var url = "https://example.com/app.apk";
var savePath = Path.Combine(Application.persistentDataPath, "data", "app.apk");
using (var uwr = UnityWebRequest.Get(url))
{
uwr.SetRequestHeader("Authorization", "Basic " + System.Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes("test:test")));
uwr.SendWebRequest();
while (!uwr.isDone)
{
progressText.text = $"Progress: {uwr.downloadProgress:P}";
yield return null;
}
var yourBytes = uwr.downloadHandler.data;
progressText.text = $"Done downloading. Size: {yourBytes.Length}";
//Create Directory if it does not exist
var directoryName = Path.GetDirectoryName(savePath);
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
progressText.text = "Created Dir";
}
try
{
//Now Save it
System.IO.File.WriteAllBytes(savePath, yourBytes);
Debug.Log("Saved Data to: " + savePath.Replace("/", "\\"));
progressText.text = "Saved Data";
}
catch (Exception e)
{
Debug.LogWarning("Failed To Save Data to: " + savePath.Replace("/", "\\"));
Debug.LogWarning("Error: " + e.Message);
progressText.text = "Error Saving Data";
}
}
//Install APK
installApp(savePath);
}
Thank you,
Chris
You are right: Stopping the Coroutine does not cancel the UnityWebRequest, you are just not keeping track of it anymore.
Actually UnityWebRequest.Abort should do exactly that
If in progress, halts the UnityWebRequest as soon as possible.
This method may be called at any time. If the UnityWebRequest has not already completed, the UnityWebRequest will halt uploading or downloading data as soon as possible. Aborted UnityWebRequests are considered to have encountered a system error. Either the isNetworkError or the isHttpError property will return true and the error property will be "User Aborted".
However this makes ofcourse only sense if you actually check the result of the request which currently you aren't doing and you should do anyway!
A way to use it would be to make the uwr a class wide field so you can access it from somewhere else and as said actually add a check if the download succeeded:
private UnityWebRequest uwr;
private IEnumerator downLoadFromServer()
{
...
// NOTE: Remove the var so the class field uwr is assigned to, not only
// a local variable
using(uwr = UnityWebRequest.Get(...))
{
...
// Always check if a request was actually successful before continuing
if(uwr.isHttpError || uwr.isNetworkError || !string.IsNullOrWhiteSpace(uwr.error))
{
Debug.LogWarning($"Download Failed with {uwr.responseCode}, reason: {uwr.error}", this);
progressText.text = $"Download Failed: {uwr.error}";
// Cancel this Coroutine
yield break;
}
var yourBytes = uwr.downloadHandler.data;
...
}
//Install APK
installApp(savePath);
}
Then you can simply do
public void AbortDownload()
{
if(uwr != null && !uwr.isDone)
{
Debug.Log("Aborting download ...", this);
uwr.Abort();
}
else
{
Debug.Log("Not downloading, nothing to do ...", this);
}
}
which should make the download "fail" and thereby also finish the Coroutine
How do I send a PUT request using UnityWebRequest?
The PUT is being sent; Uploaded!! is being printed to the console. However, nothing is being updated. I think I'm formatting myData incorrectly.
The actual URL I'm trying to send the PUT to is formatted like... http://servername.com/api/dogs/1/token=fndskajfdafdsf&cleanliness_level=20
Sorry, I can't remember what that format is called.
This is the code that I have:
public string url = "http://servername.com/api/dogs/1";
.
.
.
void Start() {
StartCoroutine (UpdateDogs ("clean"));
}
IEnumerator UpdateDogs (string button)
{
byte[] myData;
if (button == "feed") {
myData = System.Text.Encoding.UTF8.GetBytes ("?token=" + token + "&health_level=" + healthLevel);
} else {
myData = System.Text.Encoding.UTF8.GetBytes ("?token=" + token + "&cleanliness_level=" + cleanlinessLevel);
}
using (UnityWebRequest www = UnityWebRequest.Put (url, myData)) {
yield return www.Send ();
if (www.isError) {
Debug.Log ("PUT ERROR: " + www.error);
} else {
Debug.Log ("Uploaded!!");
}
}
It looks like you're missing an & in the parameter string after the token.
token + "cleanliness_level=
Should be
token + "&cleanliness_level=
Similarly for the other possible parameters.
myData in UnityWebRequest.Put is only for http body data. It doesn't seem like you need that. Instead you should add your query parameters to the URL, like such:
public string url = "http://servername.com/api/dogs/1";
if (button == "feed") {
url += "?token=" + token + "&health_level=" + healthLevel;
} else {
url += "?token=" + token + "&cleanliness_level=" + cleanlinessLevel;
}
using (UnityWebRequest www = UnityWebRequest.Put (url, "dummy")) { // UnityWebRequest.Put requires a body, see comments below
yield return www.Send ();
if (www.isError) {
Debug.Log ("PUT ERROR: " + www.error);
} else {
Debug.Log ("Uploaded!!");
}
}
I think you are missing a forward slash before token when you send it.
Try debugging what you actually send with
Debug.Log (www.text);
Next advice is that maybe the error is with what code you use on the back end receiving the data.
A few moments ago I posted a question because I wasn't able to download a file using WWW() but now I've come to a new problem:
The file that has to be downloaded is ~127mb in size. When I check the file that has been downloaded it shows 55mb. (Which explains why the file isn't able to be opened).
The code I'm using to download the file:
IEnumerator WaitForGame(){
WWW www = new WWW("https://www.dropbox.com/sh/aayo9iud7t98hgb/AACDqSST_-rT2jIfxq1Zc2SXa?dl=1");
Debug.Log ("Downloading");
yield return www;
byte[] yourBytes = www.bytes;
System.IO.File.WriteAllBytes(FullPath, yourBytes);
Debug.Log ("Done downloading!");
}
void UpdateGame(){
string path = Application.dataPath;
if (Application.platform == RuntimePlatform.OSXPlayer) {
path += "/../../";
}
else if (Application.platform == RuntimePlatform.WindowsPlayer) {
path += "/../";
}
if (System.IO.File.Exists (path+"/Apo_Alpha.app")) {
Debug.Log ("File exists!");
System.IO.File.Delete (path+"/Apo_Alpha.app");
}
FullPath = path + "/Apo_Alpha.app";
StartCoroutine (WaitForGame ());
}
I have no clue to what the problem can be, and it would be great if someone could help me out with this one.
So i'm using MySQL and C# in order to grab info from a database, but when i try to use that database info again in MySQL doesn't work because it seems to be adding a small space in front of the data. Let me show you what i mean.
php code that displays info on webpage
// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);
// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$nick = $_POST["myform_nick"];
$sql = "SELECT Lin FROM scores WHERE name='$nick'";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
// output data of each row
while($row = mysqli_fetch_assoc($result)) {
echo $row["Lin"];
}
}
Then in C# it is like this...
IEnumerator LeagueCheck(){
var form = new WWWForm ();
form.AddField( "myform_nick", formNick );
WWW w = new WWW (URL, form);
yield return w;
if (w.error != null) {
print(w.error); //if there is an error, tell us
}
else {
print("League Check 1");
LinII = w.text; //here we return the data our PHP told us
print (w.text);
Lin = LinI + LinII;
w.Dispose(); //clear our form in game
StartCoroutine (LeagueCheck2 ());
}
}
Inside LeagueCheck2 it uses LinII to grab another thing from the database but it can't find it because it comes back like this
" Dominators"
instead of like this
"Dominators"
So my question is how can i get it to remove that little space in front of Dominators.
What i've tried to fix this
using System;
LinII = String.Trim(w.text);
LinII = w.text;
LinII.Trim();
LinII.Replace(" ","");
void Timer(){
LinII.Trim();
}
//In the IEnumator LeagueCheck();
Lin = LinI + LinII;
w.Dispose(); //clear our form in game
Trimer();
StartCoroutine (LeagueCheck2 ());
This should work if w.text and LinII are a string
if (w.error != null) {
print(w.error); //if there is an error, tell us
}
else {
print("League Check 1");
LinII = w.text.Trim(); //here we return the data our PHP told us
print (LinII );
Lin = LinI + LinII;
w.Dispose(); //clear our form in game
StartCoroutine (LeagueCheck2 ());
}
I'm fairly new to both Unity and PHP, and I am currently working on a project where I can parse data from a MySQL database to Unity, using PHP.
I initially wanted to try and enable a method where the user can perhaps change the php script and enable it to choose a different table of data, however I was advised that it may be safer to list all variables within the php script and call it from Unity accordingly;
Display.php
$table = mysql_real_escape_string($_GET['table'], $db);
if ($table == "shoes") {
$query = "SELECT * FROM `shoes` ORDER by `price` ASC LIMIT 10";
elseif ($table == "sneakers") {
$query = "SELECT * FROM `sneakers` ORDER by `price` ASC LIMIT 10";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
$num_results = mysql_num_rows($result);
for($i = 0; $i < $num_results; $i++)
{
$row = mysql_fetch_array($result);
echo $row['shopname'] . "\t" . $row['price'] . "\n";
}
I'm having trouble calling the php and choosing the table that I want to select, I am pretty new to this, so I apologise if this seems completely incompetent to you guys.
Here is the my Unity Script;
HSController.cs
void Start()
{
StartCoroutine(GetScores());
}
// remember to use StartCoroutine when calling this function!
IEnumerator PostScores(string name, int score)
{
string hash = Md5Sum(name + score + secretKey);
string post_url = addScoreURL + "name=" + WWW.EscapeURL(name) + "&score=" + score + "&hash=" + hash;
WWW hs_post = new WWW(post_url);
yield return hs_post; // Wait until the download is done
if (hs_post.error != null)
{
print("There was an error posting the high score: " + hs_post.error);
}
}
IEnumerator GetScores()
{
gameObject.guiText.text = "Loading...";
WWW hs_get = new WWW(highscoreURL);
yield return hs_get;
if (hs_get.error != null)
{
print("There was an error getting the high score: " + hs_get.error);
}
else
{
gameObject.guiText.text = hs_get.text; // this is a GUIText that will display the scores in game.
}
}
Any help or a point in the right direction would be great!
Kind Regards
Let me try to rewrite this into a working example:
C#
void Start() {
StartCoroutine(GetData());
}
IEnumerator GetData() {
gameObject.guiText.text = "Loading...";
WWW www = new WWW("http://yoururl.com/yourphp.php?table=shoes"); //GET data is sent via the URL
while(!www.isDone && string.IsNullOrEmpty(www.error)) {
gameObject.guiText.text = "Loading... " + www.Progress.ToString("0%"); //Show progress
yield return null;
}
if(string.IsNullOrEmpty(www.error)) gameObject.guiText.text = www.text;
else Debug.LogWarning(www.error);
}
PHP
<?php
//DB connection goes here
if ($_REQUEST['table'] === "shoes") { //I'm using REQUEST instead of GET, so it will work with both GET and POST
$query = "SELECT * FROM `shoes` ORDER by `price` ASC LIMIT 10";
} elseif ($_REQUEST['table'] === "sneakers") {
$query = "SELECT * FROM `sneakers` ORDER by `price` ASC LIMIT 10";
}
$result = mysql_query($query) or die(mysql_error());
while ($row = mysql_fetch_assoc($result)) {
echo $row['shopname'] . "\t" . $row['price'] . "\n";
}
?>
Hope this helps!