From afcc468803a89d5d7fa07a956d3e6a06a0b1d3e0 Mon Sep 17 00:00:00 2001 From: "Crom (Thibaut CHARLES)" Date: Mon, 27 Apr 2015 23:10:07 +0200 Subject: [PATCH] Binding correctly to NPC --- TestingAI.d | 38 +++- nwn2ai_onmoduleload/Agent.cs | 193 ++++++++++++++++++ nwn2ai_onmoduleload/nwn2ai_onmoduleload.cs | 49 +++-- .../nwn2ai_onmoduleload.csproj | 1 + 4 files changed, 262 insertions(+), 19 deletions(-) create mode 100644 nwn2ai_onmoduleload/Agent.cs diff --git a/TestingAI.d b/TestingAI.d index 9b2076a..8b55357 100644 --- a/TestingAI.d +++ b/TestingAI.d @@ -5,18 +5,42 @@ import std.stdio; import std.socket; import std.conv; import std.utf; +import std.string; + +string receiveWait(Socket sock){ + bool blocking = sock.blocking; + + sock.blocking = false; + ubyte[] rawData; + ubyte[256] buf; + int recv; + while((recv = sock.receive(buf))>=0 || rawData.length==0){ + if(recv>0){ + rawData ~= buf[0..recv]; + } + + Thread.sleep(dur!"msecs"(10)); + } + sock.blocking = blocking; + return (cast(char*)rawData.ptr).fromStringz.to!string; +} +void sendWait(Socket sock, string data){ + bool blocking = sock.blocking; + + sock.blocking = true; + sock.send(data.toUTF8); + sock.blocking = blocking; +} void main() { writeln("Start"); auto sock = new TcpSocket; - sock.blocking = 1; + sock.blocking = true; sock.connect(new InternetAddress("127.0.0.1", 8080)); writeln("Connected"); - sock.send(`{"action":"bind","target":"testnpc"}`.toUTF8); - writeln("Sent"); - Thread.sleep(dur!"seconds"(1)); - sock.send(`{"action":"getenv","target":"testnpc"}`.toUTF8); - writeln("Sent2"); - Thread.sleep(dur!"seconds"(1)); + sock.sendWait(`{"action":"bind","target":"testnpc"}`); + writeln(sock.receiveWait); + + sock.shutdown(SocketShutdown.BOTH); } \ No newline at end of file diff --git a/nwn2ai_onmoduleload/Agent.cs b/nwn2ai_onmoduleload/Agent.cs new file mode 100644 index 0000000..d20ec7d --- /dev/null +++ b/nwn2ai_onmoduleload/Agent.cs @@ -0,0 +1,193 @@ +using System; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Collections.Generic; +using System.ComponentModel; + +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 Newtonsoft.Json; + +namespace CLRScript +{ + class Agent : CLRScriptBase{ + public uint objref; + + public Agent(uint obj){ + objref = obj; + } + + public float facing{ + get{ + return _facing; + } + set{ + _facing = value; + AssignCommand(objref, ()=>{SetFacing(_facing, TRUE);}); + } + } + + public NWLocation loc{ + get{ + return _loc; + } + set{ + _loc = value; + AssignCommand(objref, ()=>{ActionForceMoveToLocation(_loc, TRUE, 6f);}); + + //Link effect + RemoveSEFFromObject(objref, "nwai_beam_loc"); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectNWN2SpecialEffectFile("nwai_beam_loc", OBJECT_INVALID, GetPositionFromLocation(_loc)), objref, -1f); + } + } + + //Detection + //======================================================================= + + public bool hasWallFront(float distance=10f){ + Vector3 pointFront = Add(GetPositionFromLocation(loc), Multiply(AngleToVector(facing), distance)); + return LineOfSightVector(GetPosition(objref), pointFront)==1; + } + + public bool isInCombat(){ + return GetIsInCombat(objref)==1; + } + + //Json containing + // {"valid":"true", "id":"366642", "name":"Goblin", "distance":"13.37", "difficulty":"13", "hp":"12"} + public dynamic getNearestEnemy(float distanceMax=15f){ + uint nearestEnemy = GetNearestCreature( + CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, + objref, 1, + CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN_AND_HEARD, + CREATURE_TYPE_IS_ALIVE, CREATURE_ALIVE_TRUE); + + + float dist = GetDistanceBetween(nearestEnemy, objref); + return JsonConvert.DeserializeObject("{" + + "\"valid\":\""+(GetIsObjectValid(nearestEnemy)==TRUE && dist<=distanceMax).ToString()+"\"," + + "\"id\":\""+(nearestEnemy).ToString()+"\"," + + "\"name\":\""+GetName(nearestEnemy)+"\"" + + "\"distance\":\""+(dist).ToString()+"\"," + + "\"difficulty\":\""+GetChallengeRating(nearestEnemy)+"\"" + + "\"hp\":\""+GetCurrentHitPoints(nearestEnemy)+"\"" + + "}"); + } + + //Json containing + // {"valid":"true", "id":"366642", "name":"Guethenoc", "distance":"13.37"} + public dynamic getNearestPlayer(float distanceMax=15f){ + uint pc = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, objref, 1, -1,-1,-1,-1); + + float dist = GetDistanceBetween(pc, objref); + return JsonConvert.DeserializeObject("{" + + "\"valid\":\""+(GetIsObjectValid(pc)==TRUE && dist<=distanceMax).ToString()+"\"," + + "\"id\":\""+(pc).ToString()+"\"," + + "\"name\":\""+GetName(pc)+"\"" + + "\"distance\":\""+(dist).ToString()+"\"," + + "}"); + } + + //Actions + //======================================================================= + + public bool moveForward(float distance=10f){ + if(hasWallFront(distance)) + return false; + + //See NWN2DataLib.AreaSurfaceMesh.PathExists + + Vector3 pointFront = Add(GetPositionFromLocation(loc), Multiply(AngleToVector(facing), distance)); + loc = Location(GetAreaFromLocation(loc), pointFront, facing); + return true; + } + + public bool attackNearest(float distanceMax=15f){ + var nearest = getNearestEnemy(distanceMax); + if(!nearest.valid) + return false; + + AssignCommand(objref, ()=>{ActionAttack(nearest.id, FALSE);}); + return true; + } + + public bool turn(float angleDeg){ + facing+=angleDeg; + return true; + } + + public bool say(string message){ + AssignCommand(objref, ()=>{SpeakString(message, TALKVOLUME_TALK);}); + + return getNearestPlayer().valid; + } + + public string callCommand(string command) + { + Regex regexMethod = new Regex(@"([a-zA-Z_]+?)\s*\((.*?)\)"); + Regex regexParam = new Regex("(\".*?\"|[0-9\\.]+)"); + + string methodName; + List unparsedParams = new List(); + + MatchCollection matches = regexMethod.Matches(command); + if(matches.Count == 1){ + //Match name + methodName = matches[0].Groups[1].ToString(); + + //March parameters + string methodParamList = matches[0].Groups[2].ToString(); + MatchCollection paramMatches = regexParam.Matches(methodParamList); + foreach(var p in paramMatches){ + unparsedParams.Add(p.ToString().Trim('"')); + } + } + else{ + //Failed to parse command + return ""; + } + + MethodInfo method = this.GetType().GetMethod(methodName); + ParameterInfo[] methodParams = method.GetParameters(); + + if(methodParams.Length != unparsedParams.Count){ + //Incorrect number of parameters + return ""; + } + + + List parsedParams = new List(); + for(int i=0 ; i0){ Tuple req = sockBufferIn.Dequeue(); + var socket = req.Item2; var json = JsonConvert.DeserializeObject(req.Item1); + //TODO: check if json correctly parsed switch ((string)json.action) { case "bind": { Debug("Bind request to '"+json.target+"'"); - if (!sockClients.ContainsKey(json.target)) { - sockClients.Add(json.target, req.Item2); - //Reply ok + + try { + if (!sockClients.ContainsKey((string)json.target)) { + + sockClients.Add((string)json.target, socket); + socket.Send(Encoding.UTF8.GetBytes( + "{\"action\":\"bindack\", \"result\":\"ok\"}" + )); + + //handle env + } + else { + socket.Send(Encoding.UTF8.GetBytes( + "{\"action\":\"bindack\", \"result\":\"failed\", \"message\":\"Socket already binded with this NPC\"}" + )); + } } - else { - //Reply Already binded + catch (Exception e) { + socket.Send(Encoding.UTF8.GetBytes( + "{\"action\":\"bindack\", \"result\":\"failed\", \"message\":\"Thrown exception: "+e.ToString().Replace("\"","\\\"")+"\"}" + )); } - }break; + }break; + case "decision": { + + + }break; } } } @@ -114,25 +135,29 @@ namespace CLRScript sockClient.Blocking = true; while (sockClient.Connected) { - byte[] rawData = new byte[sockClient.Available]; + if (sockClient.Available > 0) { + byte[] rawData = new byte[sockClient.Available]; sockClient.Receive(rawData, rawData.Length, 0); string data = Encoding.UTF8.GetString(rawData); - //Debug("Queued "+data); + Debug("Queued "+data); sockBufferIn.Enqueue(new Tuple(data, sockClient)); } - else - Thread.Sleep(100);//TODO: Find another way than sleeping + Thread.Sleep(10); } + //Remove stored bind + var sock = sockClients.First(kvp => kvp.Value==sockClient); + sockClients.Remove(sock.Key); + } Socket sockServer; Queue> sockBufferIn;//Request & client - + Dictionary sockClients;//PNJ tag => Client socket private void Debug(string msg){ diff --git a/nwn2ai_onmoduleload/nwn2ai_onmoduleload.csproj b/nwn2ai_onmoduleload/nwn2ai_onmoduleload.csproj index d03ac2e..36472b9 100644 --- a/nwn2ai_onmoduleload/nwn2ai_onmoduleload.csproj +++ b/nwn2ai_onmoduleload/nwn2ai_onmoduleload.csproj @@ -51,6 +51,7 @@ +