Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring my branch up to date #52

Merged
merged 30 commits into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2760e68
Update DevcadeClient.cs
jabbate19 Feb 26, 2023
928b5a7
Add Datadog Reporting for Game
jabbate19 Feb 26, 2023
04b1470
Merge pull request #41 from jabbate19/datadog
MTFT-Games Feb 28, 2023
b5bba2c
Update DevcadeClient.cs
jabbate19 Mar 1, 2023
40f461d
Try to discover bin name, default to DevcadeGame
WillNilges Mar 14, 2023
6567645
Throw an exception if shit breaks
WillNilges Mar 15, 2023
3c51b01
Run dotnet format
WillNilges Mar 15, 2023
c42348c
Add flag to indicate download failed
WillNilges Mar 15, 2023
226d47e
dotnet format
WillNilges Mar 15, 2023
8563369
Merge pull request #43 from ComputerScienceHouse/willnilges/infer-bin
MTFT-Games Mar 16, 2023
c85d9dc
Use both menu buttons or space to reload games
WillNilges Mar 16, 2023
771ce8d
Clear games and re-add them
WillNilges Mar 16, 2023
1bd09dc
Add instruction blurb
WillNilges Mar 16, 2023
c9affed
Display error if can't get game titles
WillNilges Mar 16, 2023
d5b97d6
Add error handling to refresh in Input state
WillNilges Mar 16, 2023
e4903d1
Merge pull request #44 from ComputerScienceHouse/willnilges/update
MTFT-Games Mar 16, 2023
38bc1b8
Use both B4 buttons to switch dev/prod
WillNilges Mar 17, 2023
6676581
Swap graphics
WillNilges Mar 17, 2023
d33cb87
Refactor refresh code into function
WillNilges Mar 17, 2023
2ceb7e1
Fix a few more crashes
WillNilges Mar 17, 2023
e86074a
dotnet format
WillNilges Mar 17, 2023
d7023e7
Merge pull request #46 from ComputerScienceHouse/willnilges/dev-instance
MTFT-Games Mar 18, 2023
22144b5
Add .env template
MTFT-Games Mar 18, 2023
de2d0fa
Removed values
MTFT-Games Mar 18, 2023
ca6522f
Merge pull request #47 from ComputerScienceHouse/env-template
MTFT-Games Mar 20, 2023
afc29cf
Update to new API
jabbate19 Mar 23, 2023
3d46489
Edit to Accept API Names
jabbate19 Mar 23, 2023
9476be1
Update to new API Standards
jabbate19 Mar 26, 2023
3a6e254
Merge pull request #49 from jabbate19/main
jabbate19 Mar 26, 2023
25d214f
Add Google Auth
jabbate19 Apr 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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