How to update Url used by UnityWebRequest to InputField? - c#

I want the user to be able to change the ID of the link, which is why I used InputField to get their input. Unfortunately, I can't seem to figure out, how to make it work smoothly with a Coroutine.
When I try to update the link, it just ends in an endless loop like with the implementation below. When I don't update the link the Coroutine seems to start without getting the input and gets stuck.
I would really appreciate any help.
public class CSVDownloader : MonoBehaviour
{
public static string googleSheetDocID;
public static string url;
public InputField InputField;
public static string csvDownloaded;
public static CSVParametersData downloadedData;
public void Start()
{
googleSheetDocID = InputField.text;
Debug.Log(googleSheetDocID);
StartCoroutine(DownloadData());
}
public void Update()
{
googleSheetDocID = InputField.text;
Debug.Log(googleSheetDocID);
}
public static IEnumerator DownloadData()
{
Debug.Log(("In Coroutine"));
//url = "https://docs.google.com/spreadsheets/d/1ufpl1MsxXU2bk0Kt5YT_BkM1uI2WMLxr/export? format=csv";
url = "https://docs.google.com/spreadsheets/d/" + googleSheetDocID + "/export?format=csv";
Debug.Log(url);
UnityWebRequest webRequest = UnityWebRequest.Get(url);
yield return new WaitForEndOfFrame();
Debug.Log("Starting Download...");
yield return webRequest.SendWebRequest();
Debug.Log("Webrequestsend");
}
}

How about doing it in a few more steps?
In the code presented above, the user interaction ends with keyboard input. So trying to do everything in real time is a problem.
If the only user interaction is the keyboard, it is complex and difficult to achieve the desired task.
If it were me, I would improve the code to make it easier to achieve what you want by proceeding like this:
Add that script to your Button GameObject
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class CsvDownloader : MonoBehaviour
{
[SerializeField] private InputField inputField;
private Button changeUrlButotn;
private string googleSheetDocID;
private string url;
private void Awake()
{
changeUrlButotn = GetComponent<Button>();
changeUrlButotn.onClick.AddListener(OnChangeUrl);
}
private void OnChangeUrl()
{
googleSheetDocID = inputField.text;
StartCoroutine(DownloadData());
}
private IEnumerator DownloadData()
{
url = Path.Combine(
"https://docs.google.com/spreadsheets/d",
googleSheetDocID,
"export?format=csv");
Debug.Log(url);
using var unityWebRequest = UnityWebRequest.Get(url);
unityWebRequest.SendWebRequest();
while (!unityWebRequest.isDone)
{
yield return null;
// Things to process in units of frames
// when unityWebRequest has not finished downloading ex) progress
// ...
}
Debug.Log("Success DownloadData()");
}
}
Separate the part that inputs the InputField with the keyboard and the part that updates the googleSheetDocID.
FYI, as #Max Play said, infinite loop doesn't happen.
Hope your problem is solved :)

Related

Netcode For Gameobjects - How to allow the user to put in a username?

So i have followed the tutorial series from Dilmer Valecillos on how to use Netcode and got it working with friends and all! I wanted to add a simple Inputfield in the menu to type in your username, and then apply that to the username logic the video had. However, whenever i do this, the host sees everyone as there own username, and so do the clients.
PlayerHud.CS
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.Netcode;
using UnityEngine;
public class PlayerHud : NetworkBehaviour
{
private NetworkVariable<NetworkString> playersName = new NetworkVariable<NetworkString>();
private TMP_InputField nameInput;
private NetworkManagerUI uimanager;
private bool overlaySet = false;
public override void OnNetworkSpawn()
{
if (IsServer)
{
uimanager = GameObject.FindObjectOfType<NetworkManagerUI>();
playersName.Value = uimanager.username.Value + $" ({OwnerClientId})";
}
}
public void SetOverlay()
{
var localPlayerOverlay = gameObject.GetComponentInChildren<TMP_Text>();
localPlayerOverlay.text = playersName.Value;
}
private void Update()
{
if (!overlaySet && !string.IsNullOrEmpty(playersName.Value))
{
SetOverlay();
overlaySet = true;
}
}
}
Any idea how to fix this?
Tried alot of PlayerPrefs, input etc but did not work

Unity - is there a way to show the popup in my game only once per game session?

[EDIT] Everything is working now! Thank's to #MrMoonMan!
As the title says, I'm working on a mobile game and I just implemented a Check Update popup.
The thing is, the popup is displayed every time the menu scene is loaded, and this is very annoying because if the player goes to the weapon menu and then comes back to the main menu 10 times, he will see the popup 10 times. The goal is to have the popup appear only once per game session, Here is what I tried for the moment but without success:
Using a bool variable
Destroy the gameobject to which the checkupdate script is attached when the user presses the "No Thank's" button
Here is the code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class CheckUpdate : MonoBehaviour
{
public string versionUrl = "";
public string currentVersion;
private string latestVersion;
public GameObject newVersionAvailable;
private static bool hasBeenChecked = false;
void OnAwake()
{
DontDestroyOnLoad(this);
StartCoroutine(LoadTxtData(versionUrl));
}
private IEnumerator LoadTxtData(string url)
{
UnityWebRequest loaded = new UnityWebRequest(url);
loaded.downloadHandler = new DownloadHandlerBuffer();
yield return loaded.SendWebRequest();
latestVersion = loaded.downloadHandler.text;
CheckVersion();
}
private void CheckVersion()
{
Debug.Log("currentVersion = " + currentVersion);
Debug.Log("latestVersion = " + latestVersion);
Version versionDevice = new Version(currentVersion);
Version versionServer = new Version(latestVersion);
int result = versionDevice.CompareTo(versionServer);
if ((latestVersion != "") && (result < 0))
{
newVersionAvailable.SetActive(true);
}
if (GetChecked())
return;
}
public void ClosePopUp(GameObject obj)
{
obj.SetActive(false);
Destroy(this);
}
public void OpenURL(string url)
{
Application.OpenURL(url);
}
public static bool GetChecked()
{
if (hasBeenChecked)
{
return hasBeenChecked;
}
hasBeenChecked = true;
return false;
}
}
EDIT
Ok so you mentioned that it still happens every time the scene is reloaded. That is because the object is created when the scene is loaded. It isn't saved between scenes. To handle that properly you need to tell it to not get destroyed when the scene is unloaded and to do that is simple, and that is by Adding DontDestroyOnAwake. Here is an example of the code:
public class CheckUpdate : MonoBehaviour
{
public string versionUrl = "";
public string currentVersion;
private string latestVersion;
public GameObject newVersionAvailable;
void OnAwake()
{
DontDestroyOnLoad(this);
}
void OnStart()
{
StartCoroutine(LoadTxtData(versionUrl));
}
private IEnumerator LoadTxtData(string url)
{
UnityWebRequest loaded = new UnityWebRequest(url);
loaded.downloadHandler = new DownloadHandlerBuffer();
yield return loaded.SendWebRequest();
latestVersion = loaded.downloadHandler.text;
}
private void CheckVersion()
{
Debug.Log("currentVersion = " + currentVersion);
Debug.Log("latestVersion = " + latestVersion);
Version versionDevice = new Version(currentVersion);
Version versionServer = new Version(latestVersion);
int result = versionDevice.CompareTo(versionServer);
if ((latestVersion != "") && (result < 0))
{
newVersionAvailable.SetActive(true);
}
}
public void ClosePopUp(GameObject obj)
{
obj.SetActive(false);
}
public void OpenURL(string url)
{
Application.OpenURL(url);
}
}
,,Menu scene''? It sound some suspicious. If you load and unload whole new scene as menu, state as bool field in MonoBehaviours or modifing the scene structure (destory, create object) will not work beacuse allways will be loaded new scene from scratch. ;)
If you have to have menu on seperated scene use someting other to manage the state. For example:
DontDestoryOnLoad objects.
Or some C# static class or singleton (not a MonoBehaviour).

Not registering when the trigger is pressed

i have some code, that when the trigger of the right hand controller is pressed, it shoots a gun, however it doesn't appear to be working, i've tried to add a debug into the actual TriggerPressed section, and that doesn't show up in the log when i click it in game either, im just not sure where this problem is orginating from, and im stumped as to why it isn't working. It also compiles, so any guidance is appreciated
Edit: Not sure of its importance but decided to add this anyway, im using oculus rift controller's
Here's the (edit: UPDATED) code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EZEffects;
public class adamadam : MonoBehaviour
{
public SteamVR_TrackedController controllerRight;
private SteamVR_TrackedObject trackedObj;
private SteamVR_Controller.Device device;
private SteamVR_TrackedController controller;
public EffectTracer TracerEffect;
public Transform muzzleTransform;
// Use this for initialization
void Start()
{
// controller = controllerRight.GetComponent<SteamVR_TrackedController>();
controller.TriggerClicked += TriggerPressed;
// trackedObj = controllerRight.GetComponent<SteamVR_TrackedObject>();
}
private void TriggerPressed(object sender, ClickedEventArgs e)
{
Debug.Log("Clicked");
ShootWeapon();
}
public void ShootWeapon()
{
RaycastHit hit = new RaycastHit();
Ray ray = new Ray(muzzleTransform.position, muzzleTransform.forward);
device = SteamVR_Controller.Input((int)trackedObj.index);
device.TriggerHapticPulse(750);
TracerEffect.ShowTracerEffect(muzzleTransform.position,
muzzleTransform.forward, 250f);
if (Physics.Raycast(ray, out hit, 5000f))
{
if (hit.collider.attachedRigidbody)
{
Debug.Log("Hit" + hit.collider.gameObject.name);
}
}
}
}

Is there any way to switch to scene mode from game mode when pressing the play button?

So basically my question: Is there any way to switch from scene mode to gamemode script wise?
Image of what I want to do but from script
I am basically asking because I want to take a screenshot of the assets I load into the scene.
My code:
using UnityEngine;
using UnityEngine.SceneManagement;
public class NewBehaviourScript : MonoBehaviour {
// Use this for initialization
void Start () {
Debug.Log("HELLO");
var rss = AssetBundle.LoadFromFile(#"//MyFileLocation");
Debug.Log(SceneManager.GetActiveScene().name);
foreach (var asset in rss.LoadAllAssets<GameObject>())//<Texture2D>())
{
GameObject obj = Instantiate(asset, transform);
}
Debug.Log(transform.position);
Application.CaptureScreenshot(#"//MyScreenshotlocation");
Debug.Log("captured");
}
// Update is called once per frame
void Update () {
}
}
Any help is appreciated! Thank you!
You can switch to any Window with the EditorWindow.FocusWindowIfItsOpen function. To switch to Scene view, pass SceneView to it. You can use EditorApplication.playModeStateChanged to determine when you enter play mode.
This is an Editor plugin and must be placed in a folder named "Editor". Create a script called SceneSwitcher and copy everything below inside it. It should automatically switch to Scene View when you click the play button.
using UnityEditor;
[InitializeOnLoadAttribute]
public static class SceneSwitcher
{
static SceneSwitcher()
{
EditorApplication.playModeStateChanged += LogPlayModeState;
}
private static void LogPlayModeState(PlayModeStateChange state)
{
if (state == PlayModeStateChange.EnteredPlayMode)
SwitchToSceneView();
}
static void SwitchToSceneView()
{
EditorWindow.FocusWindowIfItsOpen<SceneView>();
/////OR
//SceneView sceneView = EditorWindow.GetWindow<SceneView>(); ;
//Type type = sceneView.GetType();
//EditorWindow.FocusWindowIfItsOpen(type);
}
}

Create events that fires off a coroutine from another script

I'm making an event that does the failLevel stuff when it fires off. For that I have made a delegate
public delegate Coroutine FailGame(IEnumerator function);
public static event FailGame gameFailedEvent;
like so and I subscribed the appropriate function to it
void Start ()
{
gameFailedEvent += StartCoroutine;
}
It works when it is called from the same script like so:
gameFailedEvent(WaitThenFailLevel());
when this WaitThenFailLevel() looks like this:
IEnumerator WaitThenFailLevel()
{
CharacterController2D.playerDied = true;
if (CharacterController2D.animState != CharacterController2D.CharAnimStates.fall)
{
CharacterController2D.currentImageIndex = 0;
CharacterController2D.animState = CharacterController2D.CharAnimStates.fall;
}
CharacterController2D.movementDisabled = true;
yield return new WaitForSeconds(0.2f);
StartCoroutine(ScaleTime(1.0f, 0.0f, 1.2f));
}
It works fine here. Now, I have another object that can kill the player (dangerous times I know) and I don't want to copy paste everything again, I just want it to fire off the static event made in the script above.
I DID try making the WaitThenFailGame function
public static
and make static all my other ienumerators but I got an error named "An object reference is required for non-static field..."
Hence I tried the event stuff.
All well and fine, but I can't call the event from the other script because I can't pass it the function from the script mentioned.
What to do now?
Here is the example code:
EventContainor.cs
public class EventContainer : MonoBehaviour
{
public static event Action<string> OnGameFailedEvent;
void Update()
{
if (Input.GetKey(KeyCode.R))
{
// fire the game failed event when user press R.
if(OnGameFailedEvent = null)
OnGameFailedEvent("some value");
}
}
}
Listener.cs
public class Listener : MonoBehaviour
{
void Awake()
{
EventContainer.OnGameFailedEvent += EventContainer_OnGameFailedEvent;
}
void EventContainer_OnGameFailedEvent (string value)
{
StartCoroutine(MyCoroutine(value));
}
IEnumerator MyCoroutine(string someParam)
{
yield return new WaitForSeconds(5);
Debug.Log(someParam);
}
}
using UnityEngine;
public class ScriptA : MonoBehaviour
{
public ScriptB anyName;
void Update()
{
anyName.DoSomething();
}
}
using UnityEngine;
public class ScriptB : MonoBehaviour
{
public void DoSomething()
{
Debug.Log("Hi there");
}
}
This is linking functions between scripts , Copied from Here, maybe coroutines are the same, Then you need to start the coroutine in void Start() {} , You may find this useful as well.

Categories

Resources