using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
///
/// Clickable that boots a PCjs OS on the monitor (adds a MonitorBrowser to the screen) and glides the camera
/// to the Computer close-up. Two of these sit on the desk so the player can choose: the Mouse boots Windows 95,
/// the Keyboard boots Windows 3.1. Each names an OS so the shared monitor shows what's currently running and
/// clicking the OTHER launcher while one is running saves it and swaps to the new one instead of doing nothing.
///
/// Saved sessions: before booting, the launcher asks the server (afx-api) for this player's newest saved state
/// of the machine and, if there is one, boots the page with ?state= so Windows carries on exactly
/// where it was. The MonitorBrowser then keeps saving while it runs and once more when switched off.
///
[RequireComponent(typeof(Collider))]
public class MonitorBrowserLauncher : MonoBehaviour, ILobbyClickable
{
public Renderer screen;
public ViewTarget computerView;
public string osName = "Windows 95";
public string url = "http://78.110.173.123/VM/win95/blog/2015/09/21/";
public string offlineUrl = "http://78.110.173.123/VM/win95/blog/2015/09/21/";
[Tooltip("Prefix of the PCjs state key for this machine (the from machine.xml plus a dot), used to find the player's latest save.")]
public string machineId = "deskpro386.";
[Tooltip("Host running afx-api (and serving the /VM mirrors).")]
public string apiBase = "http://78.110.173.123";
public float autoSaveEvery = 120f;
[Tooltip("Texture tiling/offset for the browser picture on this screen (see MonitorBrowser.flipScale). (1,-1)/(0,1) = vertical flip, the confirmed setting for the monitor quad.")]
public Vector2 screenFlipScale = new Vector2(1f, -1f), screenFlipOffset = new Vector2(0f, 1f);
[Tooltip("How the saved state is used on boot. Disk = boot the machine normally onto the saved hard disks: files persist, " +
"the running session does not, like a real PC (the default for both machines). Full = resume the exact snapshot " +
"(works for Windows 3.1 only; PCjs cannot restore a protected-mode Windows 95 snapshot).")]
public ResumeMode resumeMode = ResumeMode.Disk;
public enum ResumeMode { Full, Disk }
bool booting;
public string Hint
{
get
{
var running = screen != null ? screen.GetComponent() : null;
if (running == null) return osName + ": click to boot it on the PC (" + (resumeMode == ResumeMode.Disk ? "your files are kept between sessions" : "carries on from your last save") + ")";
return running.osName == osName ? osName + " is running (F1 saves and switches it off)" : "Save and switch to " + osName + " (currently running " + running.osName + ")";
}
}
public void Click()
{
if (screen == null || booting) return;
var running = screen.GetComponent();
if (running != null)
{
if (running.osName == osName) { if (computerView != null) LobbyCamera.RequestView(computerView); return; }
running.ShutDown(); // saves first; MonitorBrowser.OnDestroyed() then resumes the stream and we boot the new OS
}
if (computerView != null) LobbyCamera.RequestView(computerView);
StartCoroutine(BootWhenFree());
}
[System.Serializable] class ApiReply { public string code; public string data; }
IEnumerator BootWhenFree()
{
booting = true;
while (screen.GetComponent() != null) yield return null;
// Our own v86 pages take the player id in the URL ({user}) and load their own saved disk changes; only the
// PCjs pages need the saved state looked up here and passed as ?state=.
if (url.Contains("{user}"))
{
string u = url.Replace("{user}", AfxPlayer.Id);
var v = screen.gameObject.AddComponent();
v.screen = screen; v.osName = osName; v.userId = AfxPlayer.Id; v.autoSaveEvery = autoSaveEvery;
v.flipScale = screenFlipScale; v.flipOffset = screenFlipOffset;
v.SetUrl(u, string.IsNullOrEmpty(offlineUrl) ? "" : offlineUrl.Replace("{user}", AfxPlayer.Id));
booting = false;
yield break;
}
// Newest saved state for this machine and player, if any (404 = fresh boot from the stock image/state)
string stateQuery = "";
string q = apiBase + "/api/v1/user?req=latest&user=" + AfxPlayer.Id + "&machine=" + UnityWebRequest.EscapeURL(machineId)
+ (resumeMode == ResumeMode.Disk ? "&mode=disk" : "");
using (var req = UnityWebRequest.Get(q))
{
req.timeout = 5;
yield return req.SendWebRequest();
if (req.result == UnityWebRequest.Result.Success && req.responseCode == 200)
{
ApiReply reply = null;
try { reply = JsonUtility.FromJson(req.downloadHandler.text); } catch { }
if (reply != null && reply.code == "ok" && !string.IsNullOrEmpty(reply.data)) stateQuery = "?state=" + reply.data;
}
}
Boot(stateQuery);
booting = false;
}
void Boot(string stateQuery)
{
var b = screen.gameObject.AddComponent();
b.screen = screen;
b.osName = osName;
b.SetUrl(url + stateQuery, string.IsNullOrEmpty(offlineUrl) ? "" : offlineUrl + stateQuery);
b.userId = AfxPlayer.Id;
b.autoSaveEvery = autoSaveEvery;
b.flipScale = screenFlipScale;
b.flipOffset = screenFlipOffset;
}
}