// // This script serves as a basis for new scripts. New scripts can copy this // source file to start out. // using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Reflection; using System.Reflection.Emit; using CLRScriptFramework; using NWScript; using NWScript.ManagedInterfaceLayer.NWScriptManagedInterface; using NWEffect = NWScript.NWScriptEngineStructure0; using NWEvent = NWScript.NWScriptEngineStructure1; using NWLocation = NWScript.NWScriptEngineStructure2; using NWTalent = NWScript.NWScriptEngineStructure3; using NWItemProperty = NWScript.NWScriptEngineStructure4; using System.Threading; using System.IO; using System.Net; using System.Net.Sockets; using Newtonsoft.Json; namespace CLRScript { public partial class nwn2ai_onmoduleload : CLRScriptBase, ICLRScriptImplementation, IGeneratedScriptProgram { public static nwn2ai_onmoduleload get; public nwn2ai_onmoduleload([In] NWScriptJITIntrinsics Intrinsics, [In] INWScriptProgram Host) { InitScript(Intrinsics, Host); get = this; } private nwn2ai_onmoduleload([In] nwn2ai_onmoduleload Other) { InitScript(Other); LoadScriptGlobals(Other.SaveScriptGlobals()); get = this; } // // Include the list of types for parameters to the main function here. // An empty list means no parameters. // public static Type[] ScriptParameterTypes = { }; StreamWriter debugFile; public Int32 ScriptMain([In] object[] ScriptParameters, [In] Int32 DefaultReturnCode) { debugFile = File.AppendText("nwnx4\\customlog.txt"); Debug("====================================> Start"); sockBufferIn = new Queue>(); sockClients = new Dictionary(); SocketConfigure(); AssignCommand(OBJECT_SELF, delegate() { ActionSpeakString("Start!", TALKVOLUME_TALK); }); DelayCommand(0.5f, Heartbeat); return DefaultReturnCode; } public void Heartbeat() { ActionSpeakString("hb", TALKVOLUME_SHOUT); DelayCommand(0.5f, Heartbeat); //Process queued requests //Debug("Proc cmds"); while(sockBufferIn.Count>0){ Tuple req = sockBufferIn.Dequeue(); var socket = req.Item2; try { var json = JsonConvert.DeserializeObject(req.Item1); //TODO: check if json correctly parsed switch ((string)json.type) { case "bind": { Debug("Bind request to '"+json.target+"'"); string npcTag = (string)json.target; uint npcID = GetObjectByTag(npcTag, 0); try { try{ var res = sockClients.First((kvp)=>kvp.Value.objref==npcID); //Will continue if the socket is already registered socket.Send(Encoding.UTF8.GetBytes( "{\"action\":\"bindack\", \"result\":\"failed\", \"message\":\"Socket already binded with this NPC\"}" )); } catch (Exception e) { //Will go here if the socket is nbot registered Agent npc = new Agent(npcID); sockClients.Add(socket, npc); socket.Send(Encoding.UTF8.GetBytes( "{\"action\":\"bindack\", \"result\":\"ok\"}" )); //handle env recording } } catch (Exception e) { socket.Send(Encoding.UTF8.GetBytes( "{\"action\":\"bindack\", \"result\":\"failed\", \"message\":\"Thrown exception: "+e.ToString().Replace("\"","\\\"")+"\"}" )); } }break; case "command": { Debug("command"); if (sockClients.ContainsKey(socket)) { Agent npc = sockClients[socket]; foreach(var cmd in json.cmd){ Debug("exec "+(string)cmd); try { npc.callCommand((string)cmd); } catch(Exception e){ Debug(e.ToString()); } } } else { Debug("Commands must be executed on a binded NPC"); } }break; } } catch(Exception e){ Debug("Heartbeat Thrown exception: "+e.ToString()); } } } void SocketConfigure() { sockServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint iep = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 8080); sockServer.Bind(iep); sockServer.Listen(10); sockServer.BeginAccept(new AsyncCallback(RequestHandler), null); } void RequestHandler(IAsyncResult state) { Socket sockClient = sockServer.EndAccept(state); sockServer.BeginAccept(new AsyncCallback(RequestHandler), null); sockClient.Blocking = false; try { while (sockClient.Connected && IsSocketConnected(sockClient)) { byte[] rawData = new byte[0]; byte[] buf = new byte[256]; int recv; while (sockClient.Available>0 && (recv = sockClient.Receive(buf))>0) { rawData = rawData.Concat(buf.Take(recv)).ToArray(); Thread.Sleep(10); } if (rawData.Length > 0) { string data = Encoding.UTF8.GetString(rawData); Debug("Queued "+data); sockBufferIn.Enqueue(new Tuple(data, sockClient)); } Thread.Sleep(100); } } catch (Exception e) { Debug(e.ToString()); } //Remove stored bind Debug("EXIT"); sockClients.Remove(sockClient); } public static bool IsSocketConnected(Socket socket) { try { return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0); } catch (SocketException) { return false; } } Socket sockServer; Queue> sockBufferIn;//Request & client Dictionary sockClients;//Client socket=>NPC ref private void Debug(string msg){ debugFile.WriteLine(DateTime.Now.ToLongTimeString()+": "+msg); debugFile.Flush(); } } }