@@ -7,7 +7,6 @@ using RobocraftX.GUI.CommandLine; | |||
using RobocraftX.Multiplayer; | |||
using RobocraftX.Services.MultiplayerNetworking; | |||
using RobocraftX.StateSync; | |||
using Svelto.Context; | |||
using Svelto.ECS; | |||
using Unity.Entities; | |||
using UnityEngine; | |||
@@ -17,11 +16,11 @@ namespace GCDC | |||
[HarmonyPatch] | |||
public class DiscordEngineInjectionPatch | |||
{ | |||
static void Postfix(EnginesRoot enginesRoot, ref StateSyncRegistrationHelper stateSyncReg, bool isAuthoritative) | |||
static void Postfix(EnginesRoot enginesRoot, in StateSyncRegistrationHelper stateSyncReg, bool isAuthoritative) | |||
{ | |||
if (isAuthoritative) | |||
{ | |||
stateSyncReg.AddEngine(new TextBlockUpdateEngine()); | |||
stateSyncReg.AddDeterministicEngine(new TextBlockUpdateEngine()); | |||
Debug.Log($"Added Discord text block update engine"); | |||
} | |||
else | |||
@@ -33,7 +32,7 @@ namespace GCDC | |||
return _ComposeMethodInfo(ConsoleBlockCompositionRoot.Compose); | |||
} | |||
private delegate void ComposeAction(EnginesRoot er, ref StateSyncRegistrationHelper ssrh, | |||
private delegate void ComposeAction(EnginesRoot er, in StateSyncRegistrationHelper ssrh, | |||
NetworkReceivers networkReceivers, NetworkSender networkSende, bool isAuthoritative); | |||
private static MethodInfo _ComposeMethodInfo(ComposeAction a) | |||
{ | |||
@@ -32,26 +32,35 @@ | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="BlockEntityFactory, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\BlockEntityFactory.dll</HintPath> | |||
</Reference> | |||
<Reference Include="CommandLine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\CommandLine.dll</HintPath> | |||
</Reference> | |||
<Reference Include="DataLoader, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\DataLoader.dll</HintPath> | |||
</Reference> | |||
<Reference Include="FullGame, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\FullGame.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Gamecraft.Blocks.ConsoleBlock, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Gamecraft.Blocks.ConsoleBlock.dll</HintPath> | |||
</Reference> | |||
<Reference Include="GamecraftModdingAPI, Version=0.2.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>..\..\GamecraftModdingAPI\GamecraftModdingAPI\bin\Debug\net472\GamecraftModdingAPI.dll</HintPath> | |||
</Reference> | |||
<Reference Include="IllusionPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>IllusionPlugin.dll</HintPath> | |||
</Reference> | |||
<Reference Include="MultiplayerNetworking, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\MultiplayerNetworking.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<Reference Include="Newtonsoft.Json, Version=12.0.1.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Newtonsoft.Json.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Robocraft.MainGame.AutoEnterSimulation, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Robocraft.MainGame.AutoEnterSimulation.dll</HintPath> | |||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Newtonsoft.Json.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.AccountPreferences, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.AccountPreferences.dll</HintPath> | |||
@@ -74,15 +83,9 @@ | |||
<Reference Include="RobocraftX.Crosshair, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.Crosshair.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.EntityStreamUtility, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.EntityStreamUtility.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.FrontEnd, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.FrontEnd.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.GameSignalHandling, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.GameSignalHandling.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.GUI, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.GUI.dll</HintPath> | |||
</Reference> | |||
@@ -95,18 +98,12 @@ | |||
<Reference Include="RobocraftX.GUI.ScaleGhost, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.GUI.ScaleGhost.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.GUI.SignalLabel, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.GUI.SignalLabel.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.GUIs.WorkshopPrefabs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.GUIs.WorkshopPrefabs.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.Input, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.Input.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.Inventory, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.Inventory.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.MachineEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.MachineEditor.dll</HintPath> | |||
</Reference> | |||
@@ -140,9 +137,6 @@ | |||
<Reference Include="RobocraftX.Player, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.Player.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.Priority, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.Priority.dll</HintPath> | |||
</Reference> | |||
<Reference Include="RobocraftX.Rendering, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocraftX.Rendering.dll</HintPath> | |||
</Reference> | |||
@@ -176,9 +170,6 @@ | |||
<Reference Include="RobocratX.SimulationCompositionRoot, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\RobocratX.SimulationCompositionRoot.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Svelto.Common, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Svelto.Common.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Svelto.ECS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Svelto.ECS.dll</HintPath> | |||
</Reference> | |||
@@ -192,6 +183,9 @@ | |||
<Reference Include="Unity.Entities, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Unity.Entities.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Mathematics, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Unity.Mathematics.dll</HintPath> | |||
</Reference> | |||
<Reference Include="Unity.Physics, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>ref\Unity.Physics.dll</HintPath> | |||
</Reference> | |||
@@ -1,15 +1,19 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Net.Http; | |||
using System.Net.Mime; | |||
using System.Reflection; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using Discord; | |||
using Discord.WebSocket; | |||
using GamecraftModdingAPI.Utility; | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json.Linq; | |||
using RobocraftX.Blocks.GUI; | |||
using RobocraftX.Common; | |||
using RobocraftX.Common.Input; | |||
using RobocraftX.Common.Utilities; | |||
@@ -23,84 +27,114 @@ using uREPL; | |||
namespace GCDC | |||
{ | |||
public class TextBlockUpdateEngine : IQueryingEntitiesEngine, IDeterministicSim, IInitializeOnBuildStart | |||
public class TextBlockUpdateEngine : IDeterministicSim, IInitializeOnBuildStart, IApiEngine | |||
{ | |||
private DiscordSocketClient _client; | |||
private string _token; | |||
private bool _running; | |||
private Thread _rect; | |||
public void Ready() | |||
{ | |||
try | |||
{ | |||
/*Console.WriteLine("Current directory: " + Environment.CurrentDirectory); | |||
Console.WriteLine(Assembly.LoadFrom("Discord.Net.WebSocket.dll")?.DefinedTypes?.Select(t => t.FullName) | |||
.Aggregate((a, b) => a + "\n" + b));*/ //Spent a couple hours trying to figure out why it doesn't even load anymore - somehow I got a completely different System.Collections.Immutable.dll | |||
if (!RuntimeCommands.HasRegistered("dc")) | |||
RuntimeCommands.Register<string>("dc", AddMessage); | |||
Start(); | |||
} | |||
catch (TypeLoadException e) | |||
if (!RuntimeCommands.HasRegistered("dc")) | |||
RuntimeCommands.Register<string>("dc", SendMessage); | |||
if (!RuntimeCommands.HasRegistered("dcsetup")) | |||
RuntimeCommands.Register<string>("dcsetup", Setup); | |||
if (File.Exists("gcdc.json")) | |||
{ | |||
Console.WriteLine("Type load exception for type: "+e.TypeName); | |||
Console.WriteLine(e); | |||
var jo = JObject.Load(new JsonTextReader(File.OpenText("gcdc.json"))); | |||
_token = jo["token"]?.Value<string>(); | |||
} | |||
if (_token != null) | |||
Start(); | |||
} | |||
private void Start() | |||
public void Setup(string token) | |||
{ | |||
_client=new DiscordSocketClient(new DiscordSocketConfig() | |||
{ | |||
LogLevel = LogSeverity.Debug, | |||
DefaultRetryMode = RetryMode.RetryRatelimit | |||
}); | |||
_client.Log += msg=> | |||
if (string.IsNullOrWhiteSpace(token)) | |||
{ | |||
Log.Output(msg.Message); | |||
//Window.selected.OutputLog(new Log.Data(msg.Message, "Discord", Log.Level.Verbose)); | |||
return Task.CompletedTask; | |||
}; | |||
Setup(); | |||
} | |||
private async void Setup() | |||
{ | |||
try | |||
Process.Start( | |||
"https://discordapp.com/oauth2/authorize?client_id=680138144812892371&redirect_uri=https%3A%2F%2Fgcdc.herokuapp.com%2Fapi%2Fusers%2Fregister&response_type=code&scope=identify&state=551075431336378398"); | |||
Log.Output( | |||
"Please authorize the GCDC app on the page that should open. This connection is only used to avoid account spam and to display your Discord name."); | |||
} | |||
else | |||
{ | |||
const string path = "discordToken.json"; | |||
const string notoken = | |||
"Please add your bot token to the discordToken.json file in game files and run this again."; | |||
if (!File.Exists(path)) | |||
{ | |||
var obj = new JObject {["token"] = "Put your token here"}; | |||
File.WriteAllText(path, obj.ToString()); | |||
Log.Error(notoken); | |||
return; | |||
} | |||
string token; | |||
_token = token; | |||
try | |||
{ | |||
token = (string) JObject.Parse(File.ReadAllText(path))["token"]; | |||
if (token.Contains(" ")) | |||
if (JObject.Parse(WebUtils.Request("users/get?token=" + token))["response"].Value<string>() == "OK") | |||
{ | |||
Log.Error(notoken); | |||
return; | |||
var jo = new JObject(); | |||
jo["token"] = token; | |||
File.WriteAllText("gcdc.json", jo.ToString()); | |||
Start(); | |||
Log.Output( | |||
"Successfully logged in. You can now use a text block named Discord and the dc command."); | |||
} | |||
else | |||
Log.Error("Failed to verify login. Please try again."); | |||
} | |||
catch (JsonReaderException exception) | |||
catch (Exception e) | |||
{ | |||
Log.Error("Failed to read token! " + exception); | |||
return; | |||
Log.Error("Failed to verify login. Please try again. (Error logged.)"); | |||
Console.WriteLine(e); | |||
} | |||
} | |||
} | |||
await _client.LoginAsync(TokenType.Bot, token); | |||
await _client.StartAsync(); | |||
public void SendMessage(string message) | |||
{ | |||
if (!_running) | |||
{ | |||
Log.Error("Run dcsetup first."); | |||
return; | |||
} | |||
try | |||
{ | |||
var parameters = "token=" + _token + "&message=" + message; | |||
var resp = JObject.Parse(WebUtils.Request("messages/send?" + parameters, "")); | |||
if (resp["response"] | |||
.Value<string>() == "OK") | |||
{ | |||
AddMessage("<nobr><" + resp["username"] + "> " + message); | |||
Log.Output("Message sent"); | |||
} | |||
else | |||
Log.Error("Failed to send message"); | |||
} | |||
catch (Exception e) | |||
{ | |||
Log.Error(e.ToString()); | |||
Log.Error("Failed to send message (error logged)."); | |||
Console.WriteLine(e); | |||
} | |||
} | |||
public IEntitiesDB entitiesDB { get; set; } | |||
public void Start() | |||
{ | |||
if (_running) return; | |||
_running = true; | |||
_rect = new Thread(() => | |||
{ | |||
Console.WriteLine("Starting DC receiver thread..."); | |||
while (_running) | |||
{ | |||
try | |||
{ | |||
string resp = WebUtils.Request("messages/get?token=" + _token); | |||
var jo = JObject.Parse(resp); | |||
AddMessage("<nobr><" + jo["username"] + "> " + jo["message"]); | |||
} | |||
catch (WebException) | |||
{ | |||
// ignored | |||
} | |||
} | |||
}) {Name = "DC Receiver Thread"}; | |||
_rect.Start(); | |||
} | |||
public EntitiesDB entitiesDB { get; set; } | |||
public string name { get; } = "GCDC-TextUpdate"; | |||
private volatile Queue<string> messages = new Queue<string>(); | |||
private volatile bool updatedTextBlock; | |||
@@ -132,5 +166,13 @@ namespace GCDC | |||
updatedTextBlock = false; //Update text block | |||
return new JobHandle(); | |||
} | |||
public void Dispose() | |||
{ | |||
_running = false; | |||
_rect.Interrupt(); | |||
} | |||
public string Name { get; } = "GCDCEngine"; | |||
} | |||
} |
@@ -0,0 +1,42 @@ | |||
using System; | |||
using System.IO; | |||
using System.Net; | |||
using System.Text; | |||
namespace GCDC | |||
{ | |||
public static class WebUtils | |||
{ | |||
public static string Request(string url, string post = null) | |||
{ | |||
WebRequest request = WebRequest.CreateHttp("https://gcdc.herokuapp.com/api/" + url); | |||
request.Method = post != null ? "POST" : "GET"; | |||
Stream dataStream; | |||
if (post != null) | |||
{ | |||
byte[] byteArray = Encoding.UTF8.GetBytes(post); | |||
request.ContentType = "application/x-www-form-urlencoded"; | |||
request.ContentLength = byteArray.Length; | |||
dataStream = request.GetRequestStream(); | |||
dataStream.Write(byteArray, 0, byteArray.Length); | |||
dataStream.Close(); | |||
} | |||
WebResponse response = request.GetResponse(); | |||
Console.WriteLine(((HttpWebResponse) response).StatusDescription); | |||
string responseFromServer; | |||
using (dataStream = response.GetResponseStream()) | |||
{ | |||
StreamReader reader = new StreamReader(dataStream); | |||
responseFromServer = reader.ReadToEnd(); | |||
} | |||
response.Close(); | |||
return responseFromServer; | |||
} | |||
} | |||
} |