Client/GamerServices/Systems/Game.cs

525 lines
19 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace GamerServices
{
public class Game {
#region Enums & classes
public enum GameStatus : byte {
INSTALLED = 0,
DOWNLOADING = 1,
UNINSTALLED = 2,
NONE = 254
}
public enum GameAPIReturn : byte {
NONE = 0,
YES = 1,
NO = 2,
}
public class Achievement {
public String Name;
public String Desc;
public String Hash;
public int CurProg;
public int TargetProg;
public int ID;
public short Points;
}
public class LeaderboardRow {
public String Username;
public int Pos;
public int Score;
}
public class Leaderboard {
public String Name;
public String Desc;
public String Identifier;
public int ID;
public int SelfRow;
public LeaderboardRow[] Rows;
public LeaderboardRow GetRow(string user) {
foreach (LeaderboardRow r in Rows) {
if (r.Username == user)
return r;
}
return null;
}
}
#endregion
#region Varibles
public String Identifier = "tetris";
public String MainExe = "";
public String Name = "";
public String Description = "";
public String Version = "0";
public GameAPIReturn APIStatus = GameAPIReturn.NONE;
public GameStatus Status = GameStatus.NONE;
public List<Achievement> Achievements = new List<Achievement>();
public Dictionary<String, bool> AvatarsSend = new Dictionary<string, bool>();
public Leaderboard[] LeaderBoards;
public short GameID = -1;
public byte GamePort = 1;
public bool ForceStop;
public bool Devmode;
public bool IsDevUser;
public FormMain Main;
private TcpListener APIListener;
private MrAG.Networking.TCPClient APIConnection;
private Process GameProc;
private Thread GameAPIThread;
private FormGameDev FormDev;
private FormDevUpdate FormDevUpdater;
private String GameAPISessID;
#endregion
public Game(FormMain main)
{
Main = main;
}
public Achievement GetAchievement(string hash) {
foreach (Achievement a in Achievements) {
if (a.Hash == hash)
return a;
}
return null;
}
public Leaderboard GetLeaderboard(string boardname) {
foreach (Leaderboard board in LeaderBoards) {
if (board.Identifier == boardname) {
return board;
}
}
return null;
}
#region Dev functions
public void DevUpdate() {
FormDevUpdater = new FormDevUpdate(this);
FormDevUpdater.Show();
}
public void DevStop() {
Devmode = false;
FormDev.Close();
Stop();
}
public void DevStart() {
if (Main.CurrentPlayingGame != null) {
Main.Error("Humans are bad at multi-tasking!");
return;
}
Devmode = true;
APIListener = new TcpListener(IPAddress.Any, 17000 + GamePort);
APIListener.Start();
GameAPIThread = new Thread(new ThreadStart(APIThink));
GameAPIThread.Start();
Main.CurrentPlayingGame = this;
System.Windows.Forms.MessageBox.Show("Go to your Visual studio, then project properties\nDebug > Start options > Command line arguments\nSet that to: \"None " + (17000 + GamePort) + "\" whitout the quotes", "Developer Debug mode", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
FormDev = new FormGameDev(this);
FormDev.Show();
FormDev.Location = new System.Drawing.Point(Main.Location.X + ((Main.Size.Width / 2) - (FormDev.Size.Width / 2)), Main.Location.Y + ((Main.Size.Height / 2) - (FormDev.Size.Height / 2)));
}
#endregion
#region Default functions
public void Stop() {
if ((!Devmode || ForceStop) && GameProc != null && !GameProc.HasExited) {
GameProc.Kill();
GameProc = null;
}
if (APIListener != null && (!Devmode || ForceStop)) {
APIListener.Stop();
APIListener = null;
}
if (APIConnection != null) {
APIConnection.Connection.Close();
APIConnection = null;
}
if (ForceStop)
if (this.FormDev != null && !this.FormDev.IsDisposed)
this.FormDev.Close();
ForceStop = false;
if (Main.CurrentPlayingGame == this && !Devmode) Main.CurrentPlayingGame = null;
if (!Devmode && GameAPISessID != "") {
if (Main.Networker.Connection != null)
Main.Networker.Connection.Send(14, 0, false, GameID);
}
AvatarsSend = new Dictionary<string, bool>();
if (GameAPIThread != null) {
APIConnection = null;
if (Devmode) {
GameAPIThread = new Thread(new ThreadStart(APIThink));
GameAPIThread.Start();
} else {
GameAPIThread.Abort();
}
}
}
public MrAG.Networking.TCPClient GetAPIConnection() {
return APIConnection;
}
public void Start() {
Devmode = false;
if (Main.CurrentPlayingGame != null) {
if (System.Windows.Forms.MessageBox.Show("Already ingame, want to force exit " + Main.CurrentPlayingGame.Name + " and startup " + this.Name + "?", "Already ingame", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Warning) != System.Windows.Forms.DialogResult.Yes) {
return;
} else if(Main.CurrentPlayingGame != null) {
if (Main.CurrentPlayingGame.Devmode)
Main.CurrentPlayingGame.DevStop();
else
Main.CurrentPlayingGame.Stop();
}
}
GameAPISessID = "";
Stop();
GameAPISessID = Main.Networker.MD5(Main.Sessionkey + Main.Username);
APIListener = new TcpListener(IPAddress.Any, 17000 + GamePort);
APIListener.Start();
GameProc = new System.Diagnostics.Process();
GameProc.StartInfo.Arguments = GameAPISessID + " " + (17000 + GamePort);
GameProc.StartInfo.WorkingDirectory = System.IO.Directory.GetCurrentDirectory() + "/Games/" + GameID;
GameProc.StartInfo.FileName = "\"" + GameProc.StartInfo.WorkingDirectory + "/" + MainExe + "\"";
try {
GameProc.Start();
}catch(Exception e) {
Main.Error("Could not find " + MainExe);
APIListener.Stop();
APIListener = null;
GameProc = null;
GameAPISessID = "";
return;
}
GameAPIThread = new Thread(new ThreadStart(APIThink));
GameAPIThread.Start();
Main.CurrentPlayingGame = this;
}
public void Install() {
System.IO.Directory.CreateDirectory("Games/" + GameID);
System.IO.File.WriteAllText("Games/" + GameID + "/version.txt", "0.0.0");
Status = Game.GameStatus.DOWNLOADING;
Version = "";
if (!Main.Downloader.UpdateParser(GameID, Version)) {
if (IsDevUser) {
System.Windows.Forms.MessageBox.Show("Could not find download list, however becouse your the developer of this game, im going to ignore it and send an team of highly trained unicorns to create it.", "Error while looking for online game files", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
Main.SortGames();
} else {
Status = Game.GameStatus.UNINSTALLED;
System.Windows.Forms.MessageBox.Show("Could not find download list", "Error while instaling", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
}
}else
Main.SortGames();
Main.Networker.Connection.Send(12, 3, GameID);
Main.Networker.Connection.Send(13, 3, GameID);
}
public void Uninstall() {
System.IO.Directory.Delete("Games/" + GameID, true);
Status = Game.GameStatus.UNINSTALLED;
Main.SortGames();
}
public void Update() {
Main.Networker.Connection.Send(11, 3, GameID);
}
#endregion
#region The dark corner of API crap
private void APIThink() {
double lastping = DateTime.Now.TimeOfDay.TotalMilliseconds;
double lastDevUpdate = DateTime.Now.TimeOfDay.TotalMilliseconds;
while (true) {
if (APIListener != null) {
if (APIListener.Pending()) {
APIConnection = new MrAG.Networking.TCPClient(APIListener.AcceptTcpClient());
APIConnection.DebugMode = false;
APIConnection.Packets[0] = new Action<MrAG.Networking.Packet>(Packet_00); // Main Connection
APIConnection.Packets[1] = new Action<MrAG.Networking.Packet>(Packet_01); // Ping
APIConnection.Packets[2] = new Action<MrAG.Networking.Packet>(Packet_02); // Achievements
APIConnection.Packets[3] = new Action<MrAG.Networking.Packet>(Packet_03); // Leaderboard
APIConnection.Packets[4] = new Action<MrAG.Networking.Packet>(Packet_04); // Logout for some reason
APIConnection.Packets[5] = new Action<MrAG.Networking.Packet>(Packet_05); // Remote print
APIConnection.Packets[6] = new Action<MrAG.Networking.Packet>(Packet_06); // Avatar
APIConnection.Packets[7] = new Action<MrAG.Networking.Packet>(Packet_07); // ServerList
if (FormDev != null) FormDev.AddMessage("Game logged in");
if (!Devmode){
APIListener.Stop();
APIListener = null;
}
}
}
if (APIConnection != null){
try {
APIConnection.Update();
} catch {
if (!Devmode)
Main.Error("The api session for " + Name + " has crashed!");
Stop();
return;
}
}
if (Main == null || Main.IsDisposed || ForceStop || (!Devmode && GameProc != null && GameProc.HasExited)) {
Stop();
return;
}
if (Math.Abs(lastping - DateTime.Now.TimeOfDay.TotalMilliseconds) > 5000){
if (APIConnection != null) APIConnection.Send(1, 1);
lastping = DateTime.Now.TimeOfDay.TotalMilliseconds;
}
if (FormDev != null && Math.Abs(lastDevUpdate - DateTime.Now.TimeOfDay.TotalMilliseconds) > 1000){
try { FormDev.UpdateAv(); } catch { }
lastDevUpdate = DateTime.Now.TimeOfDay.TotalMilliseconds;
}
Thread.Sleep(50);
}
}
private void Packet_00(MrAG.Networking.Packet p){
string SessID = p.ReadString();
string APIKey = p.ReadString();
string Identifier = p.ReadString();
APIStatus = GameAPIReturn.YES;
if (SessID == "None" && Devmode) {
} else {
Main.Networker.Connection.Send(14, 0, true, GameID);
}
while (APIStatus == GameAPIReturn.NONE) {
Thread.Sleep(100);
}
if (APIStatus == GameAPIReturn.YES) {
APIConnection.Send(0, Main.Username.Length + 5, Main.Username);
} else {
Main.Error("Failed to start " + Name);
Stop();
}
if (FormDev != null) {
FormDev.AddIn(SessID.Length + APIKey.Length + Identifier.Length + 13);
FormDev.AddOut(Main.Username.Length + 5);
}
}
private void Packet_01(MrAG.Networking.Packet p){
if (FormDev != null) FormDev.AddMessage("Pinged!");
if (FormDev != null) {
FormDev.AddIn(1);
FormDev.AddOut(1);
}
}
private void Packet_02(MrAG.Networking.Packet p){
byte type = p.ReadByte();
string ach_hash;
int addin = 1;
int addout = 0;
switch (type) {
case 0: // list
p.Start_Send();
p.AddByte(2);
p.AddByte(0);
p.AddShort((short)Achievements.Count);
foreach (Achievement a in Achievements) {
p.AddString(a.Name);
p.AddString(a.Hash);
p.AddString(a.Desc);
p.AddInt(a.CurProg);
p.AddInt(a.TargetProg);
p.AddByte(a.Points);
addout += a.Name.Length + a.Hash.Length + a.Desc.Length + 22;
}
p.Finish_Send();
if (FormDev != null) FormDev.AddMessage(this.Achievements.Count +" achievements sent to game " + this.Name);
break;
case 1: // add
ach_hash = p.ReadString();
int toadd = p.ReadInt();
Achievement ach = GetAchievement(ach_hash);
if (ach != null) {
ach.CurProg += toadd;
Main.Networker.Connection.Send(40, 9, ach.ID, toadd);
if (FormDev != null) FormDev.AddMessage("Achievement Added " + toadd + " for " + ach.Name);
}
addin += ach_hash.Length + 9;
break;
case 2: // set
ach_hash = p.ReadString();
int toset = p.ReadInt();
Achievement ach2 = GetAchievement(ach_hash);
if (ach2 != null){
ach2.CurProg = toset;
Main.Networker.Connection.Send(41, 9, ach2.ID, toset);
if (FormDev != null) FormDev.AddMessage("Achievement set " + ach2.Name+ " to " + toset);
}
addin += ach_hash.Length + 9;
break;
}
if (FormDev != null) {
FormDev.AddIn(addin);
FormDev.AddOut(addout);
}
}
private void Packet_03(MrAG.Networking.Packet p){
int addin = 1;
int addout = 0;
byte type = p.ReadByte();
switch (type) {
case 0: // list
break;
case 1: // Submit
double startime = DateTime.Now.TimeOfDay.TotalMilliseconds;
string boardname = p.ReadString();
int score = p.ReadInt();
Main.Networker.Connection.Send(42, 9, GetLeaderboard(boardname).ID, score);
if (FormDev != null) FormDev.AddMessage("Leaderboard submit " + boardname + " with " + score + " score, took " + (DateTime.Now.TimeOfDay.TotalMilliseconds - startime) + "MS");
addin += boardname.Length + 9;
addout += 5;
break;
case 2: // Get
string user = p.ReadString();
string board = p.ReadString();
Leaderboard l = GetLeaderboard(board);
LeaderboardRow row = l.GetRow(user);
p.Start_Send();
p.AddInt(row.Pos);
p.AddInt(row.Score);
p.Finish_Send();
if (FormDev != null) FormDev.AddMessage("Leaderboard get " + board + " for " + row.Username);
addin += user.Length + board.Length + 9;
addout += 9;
break;
}
if (FormDev != null) {
FormDev.AddIn(addin);
FormDev.AddOut(addout);
}
}
private void Packet_04(MrAG.Networking.Packet p){
if (FormDev != null) FormDev.AddMessage("Game logged out");
if (FormDev != null) FormDev.AddIn(1);
}
private void Packet_05(MrAG.Networking.Packet p){
string msg = p.ReadString();
if (FormDev != null) FormDev.AddMessage("GAME: " + msg);
if (FormDev != null) FormDev.AddIn(msg.Length + 5);
}
private void Packet_06(MrAG.Networking.Packet p){
string user = p.ReadString();
if (AvatarsSend.ContainsKey(user))
return;
AvatarsSend[user] = true;
Friend f = this.Main.GetFriend(user);
if (f == null){
if (FormDev != null) FormDev.AddMessage("Requested avatar for " + user);
this.Main.Networker.Connection.Connection.Send(31, 0, user);
}else {
if (FormDev != null) FormDev.AddMessage("Ninja'd avatar for " + user);
string url = "http://" + "www.gravatar.com/avatar/" + f.AvatarURL + "?s=64";
p.Send(6, 9 + url.Length + user.Length, user, url);
}
if (FormDev != null) FormDev.AddIn(user.Length + 5);
if (FormDev != null) FormDev.AddOut(user.Length + 5);
}
private void Packet_07(MrAG.Networking.Packet p){
string id = p.ReadString();
this.Main.Networker.Connection.Send(15, id.Length + 3, id);
if (FormDev != null) FormDev.AddMessage("Requested serverlist");
if (FormDev != null) FormDev.AddIn(id.Length + 3);
}
#endregion
}
}