Skip to content

Commit

Permalink
Merge pull request #52 from ComputerScienceHouse/main
Browse files Browse the repository at this point in the history
Bring my branch up to date
  • Loading branch information
MTFT-Games committed Apr 7, 2023
2 parents 95ce24f + 25d214f commit 717950a
Show file tree
Hide file tree
Showing 8 changed files with 651 additions and 387 deletions.
4 changes: 4 additions & 0 deletions idiot/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export VIEW_WIDTH=
export VIEW_HEIGHT=
export DEVCADE_API_DOMAIN=
export DEVCADE_DEV_API_DOMAIN=
12 changes: 12 additions & 0 deletions onboard/Content/Content.mgcb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@
/processorParam:TextureFormat=Color
/build:OnboardBackgroundGradient.png

#begin transparent-dev-logo.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:transparent-dev-logo.png

#begin transparent-logo-white.png
/importer:TextureImporter
/processor:TextureProcessor
Expand Down
Binary file added onboard/Content/transparent-dev-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
215 changes: 153 additions & 62 deletions onboard/DevcadeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
using System.IO.Compression;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

using Microsoft.Xna.Framework; // FIXME: Is this necessary for the client code?

// For making requests to the API
using System.Net.Http;
using Microsoft.Xna.Framework.Graphics;
using Newtonsoft.Json;

namespace onboard
Expand All @@ -25,26 +23,73 @@ public class DevcadeGame
public string name { get; set; }
public string hash { get; set; }
public string description { get; set; }
public string iconLink { get; set; }
public string bannerLink { get; set; }
public DevcadeUser user { get; set; }
public DevcadeTag[] tags { get; set; }
}

public class DevcadeUser
{
public string id { get; set; }
public string user_type { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public string picture { get; set; }
public bool admin { get; set; }
}

public class DevcadeTag
{
public string name { get; set; }
public string description { get; set; }
}

public class DevcadeClient
{
private readonly string _apiDomain;
private readonly string _apiProdDomain;
private readonly string _apiDevDomain;
private string _apiDomain;

// Basically a semaphore for communicating between the main thread (doing the menu animations)
// and the thread that loads the game.
public bool DownloadFailed = false;

public DevcadeClient()
{
_apiProdDomain = Environment.GetEnvironmentVariable("DEVCADE_API_DOMAIN");
_apiDevDomain = Environment.GetEnvironmentVariable("DEVCADE_DEV_API_DOMAIN");
_apiDomain = _apiProdDomain;
}

// Point at Dev/Prod
public void SwapDomains()
{
if (_apiDomain == _apiDevDomain)
_apiDomain = _apiProdDomain;
else if (_apiDomain == _apiProdDomain)
_apiDomain = _apiDevDomain;
Console.WriteLine($"Switching to: {_apiDomain}");
}

public String GetDomain()
{
if (_apiDomain == _apiDevDomain)
return "Development";

public DevcadeClient() {
_apiDomain = Environment.GetEnvironmentVariable("DEVCADE_API_DOMAIN");
//if (_apiDomain == _apiProdDomain)
return "Production";
}

public List<DevcadeGame> GetGames() {

public List<DevcadeGame> GetGames()
{
using var client = new HttpClient();
try {
string uri = $"https://{_apiDomain}/api/games/gamelist/"; // TODO: Env variable URI tld
try
{
string uri = $"https://{_apiDomain}/games/"; // TODO: Env variable URI tld
using Task<string> responseBody = client.GetStringAsync(uri);
List<DevcadeGame> games = JsonConvert.DeserializeObject<List<DevcadeGame>>(responseBody.Result);
// TODO: Add error handling if there is no games from the API
if(games == null || games.Count == 0)
if (games == null || games.Count == 0)
{
Console.WriteLine("Where the games at?");
}
Expand All @@ -62,33 +107,35 @@ public void GetBanner(DevcadeGame game)
{
// Path to where the banner image will be saved
// Making this game.name will name the downloaded image have that name, could set it to anything like id etc..
string path = $"/tmp/{game.id}Banner.png";
string path = $"/tmp/{game.id}Banner";

Console.WriteLine($"Downloading banner for: {game.name}");

using var client = new HttpClient();
try
{
// Download the image from this uri, save it to the path
string uri = $"https://{_apiDomain}/api/games/download/banner/{game.id}";
string uri = $"https://{_apiDomain}/games/{game.id}/banner";
using Task<Stream> s = client.GetStreamAsync(uri);
using var fs = new FileStream(path, FileMode.OpenOrCreate);
s.Result.CopyTo(fs);
}
catch(HttpRequestException e)
catch (HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} ", e.Message);
}
}

private void getBanner(object callback) {
private void getBanner(object callback)
{
var game = (DevcadeGame)callback;
GetBanner(game);
Menu.instance.notifyTextureAvailable(game.id);
}

public void getBannerAsync(DevcadeGame game) {
public void getBannerAsync(DevcadeGame game)
{
ThreadPool.QueueUserWorkItem(getBanner, game);
}

Expand All @@ -98,65 +145,109 @@ private static void Chmod(string filePath, string permissions = "700", bool recu
{
string cmd = recursive ? $"chmod -R {permissions} {filePath}" : $"chmod {permissions} {filePath}";

try {
try
{
using Process proc = Process.Start("/bin/bash", $"-c \"{cmd}\"");
proc?.WaitForExit();
}
catch {
catch
{
// ignored
}
}

public void startGame(DevcadeGame game) {

public void startGame(DevcadeGame game)
{
DownloadFailed = false;
ThreadPool.QueueUserWorkItem(DownloadGame, game);
}

private void DownloadGame(object gameObj) {
var game = (DevcadeGame)gameObj;
private void DownloadGame(object gameObj)
{
try
{
var game = (DevcadeGame)gameObj;
string gameName = game.name.Replace(' ', '_');
Console.WriteLine($"Game is: {gameName}");
string path = $"/tmp/{gameName}.zip";
string URI = $"https://{_apiDomain}/games/{game.id}/game";
Console.WriteLine($"Getting {game.name} from {URI}");

using var client = new HttpClient();
using Task<Stream> s = client.GetStreamAsync(URI);
using var fs = new FileStream(path, FileMode.OpenOrCreate);
s.Result.CopyTo(fs);
notifyDownloadComplete(game);
}
catch (Exception e)
{
Console.WriteLine(e);
DownloadFailed = true;
}
}

public static void reportToDatadog(DevcadeGame game)
{
// Create a new UdpClient
UdpClient udpClient = new UdpClient();

// Create a new IPEndPoint for the destination IP address and port number
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
int port = 8125;
IPEndPoint endPoint = new IPEndPoint(ipAddress, port);

string gameName = game.name.Replace(' ', '_');
Console.WriteLine($"Game is: {gameName}");
string path = $"/tmp/{gameName}.zip";
string URI = $"https://{_apiDomain}/api/games/download/{game.id}";
Console.WriteLine($"Getting {game.name} from {URI}");

using var client = new HttpClient();
using Task<Stream> s = client.GetStreamAsync(URI);
using var fs = new FileStream(path, FileMode.OpenOrCreate);
s.Result.CopyTo(fs);
notifyDownloadComplete(game);
// Convert the message to a byte array
string message = $"devcade.game_launch:1|c|#game:{gameName}";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(message);

// Send the message
udpClient.Send(bytes, bytes.Length, endPoint);

// Close the UdpClient
udpClient.Close();
}

private static void notifyDownloadComplete(DevcadeGame game) {

private static void notifyDownloadComplete(DevcadeGame game)
{
string gameName = game.name.Replace(' ', '_');
// Try extracting the game
string path = $"/tmp/{gameName}.zip";
try {
Console.WriteLine($"Extracting {path}");
Directory.CreateDirectory($"/tmp/{gameName}");
ZipFile.ExtractToDirectory(path, $"/tmp/{gameName}");
} catch (Exception e) {
Console.WriteLine($"Error extracting {path}: {e.Message}");
Console.WriteLine($"Extracting {path}");
if (Directory.Exists($"/tmp/{gameName}"))
{
Directory.Delete($"/tmp/{gameName}", true);
}
Directory.CreateDirectory($"/tmp/{gameName}");
ZipFile.ExtractToDirectory(path, $"/tmp/{gameName}");

try {
string execPath = $"/tmp/{gameName}/publish/{gameName.Replace("_", " ")}";
Console.WriteLine($"Running {execPath}");
Chmod(execPath, "+x");
Process proc = new() {
StartInfo = new ProcessStartInfo(execPath) {
WindowStyle = ProcessWindowStyle.Normal,
WorkingDirectory = Path.GetDirectoryName(execPath) ?? string.Empty,
RedirectStandardError = true,
RedirectStandardOutput = true,
}
};
// Redirect stdout and stderr to the console
proc.OutputDataReceived += (_, args) => Console.WriteLine($"[{game.name}] {args.Data}");
proc.ErrorDataReceived += (_, args) => Console.WriteLine($"[{game.name}] {args.Data}");
proc.Start();
Game1.instance.setActiveProcess(proc);
} catch (System.ComponentModel.Win32Exception e) {
Game1.instance.notifyLaunchError(e);
}
// Try running the game
// Infer the name of the executable based off of an automatically generated dotnet publish file
// FIXME: This is fucking gross
string[] binFiles = System.IO.Directory.GetFiles($"/tmp/{gameName}/publish/", "*.runtimeconfig.json");
string execPath = binFiles[0].Split(".")[0];
// Check if that worked. If it didn't, L plus ratio.
if (!File.Exists(execPath))
throw new System.ComponentModel.Win32Exception();
Console.WriteLine($"Running {execPath}");
reportToDatadog(game);
Chmod(execPath, "+x");
Process proc = new()
{
StartInfo = new ProcessStartInfo(execPath)
{
WindowStyle = ProcessWindowStyle.Normal,
WorkingDirectory = Path.GetDirectoryName(execPath) ?? string.Empty,
RedirectStandardError = true,
RedirectStandardOutput = true,
}
};
// Redirect stdout and stderr to the console
proc.OutputDataReceived += (_, args) => Console.WriteLine($"[{game.name}] {args.Data}");
proc.ErrorDataReceived += (_, args) => Console.WriteLine($"[{game.name}] {args.Data}");
proc.Start();
Game1.instance.setActiveProcess(proc);
}
}
}
Loading

0 comments on commit 717950a

Please sign in to comment.