213 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
//
 | 
						|
// 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<Tuple<string,Socket>>();
 | 
						|
            sockClients = new Dictionary<Socket, Agent>();
 | 
						|
            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<string, Socket> req = sockBufferIn.Dequeue();
 | 
						|
                var socket = req.Item2;
 | 
						|
 | 
						|
                try {
 | 
						|
 | 
						|
                    var json = JsonConvert.DeserializeObject<dynamic>(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<string,Socket>(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<Tuple<string,Socket>> sockBufferIn;//Request & client
 | 
						|
        
 | 
						|
        Dictionary<Socket, Agent> sockClients;//Client socket=>NPC ref
 | 
						|
 | 
						|
        private void Debug(string msg){
 | 
						|
            debugFile.WriteLine(DateTime.Now.ToLongTimeString()+": "+msg);
 | 
						|
            debugFile.Flush();
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |