Author Topic: [Idea] Persistent scheduled NPCs  (Read 1028 times)

Legacy_Valgav

  • Full Member
  • ***
  • Posts: 118
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« on: April 27, 2015, 02:19:27 pm »


               

I'm trying to mimic the radiantAI which is clearly impossible '<img'> 


 


I'm trying to avoid the overuse of the heartbeat and only use it to check if it is time to do something else than my current task.


 


Instead of using heartbeat to manage specific tasks I'm thinking about triggers and their on_enter event. It could be used with NWNXFuncs_SetEventScript to set trigger heartbeat only if specific npc enters it and then using trigger heartbeat  force creature to do something as long as heartbeat won't signal that it's time to change event, then npc leaves trigger and trigger changes heartbeat script to some dummy.


 


My only problem is about social part. NPCs should talk to each other and show some relations but I couldn't find any information about onPerception and I'm afraid that placing afew dozens of npcs in small town with onPerception could be quite laggy.


 


Maybe some ideas? Maybe AoE with shape of cone is solution to mimic moving trigger like this from paragraph above? And if someone enters then change variables and scripts and proceed.



               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #1 on: April 27, 2015, 02:59:34 pm »


               

TBH - You are really going to need to use c++ or at least c#, maybe Java? to get something similar to Radiant AI working.


 


I've often toyed with the idea of running AI scripts or Pseudo-AI Scripts on other secondary threads to the nwserver process itself.


 


In nwnx - if you wish to invoke a nwserver method, then yes, you do need to be on the main thread in order to preserve the call stack : Eg, variables and local vars can get contaminated if you try to call methods from another thread.


 


However, if you have a reference to an object, you 'might' be able to read from its members.


Eg: Ability Scores, perception list etc


 


Without having to be on MainThread:


Even if you do need to be on the MainThread, there are ways of implementing a critical section, allowing two threads to communicate with eachother.


 


 


I do this in my Server:


I hooked MainLoop, and when the secondary thread has an instruction for the MainLoop to run, it adds it to a collection for the MainLoop to process at its own convenience.


 


This being the case, you could in theory have as much passive processing as you want, running on a second thread.


The only bottleneck is when you try to give instructions to nwmain.


 


Theoretically, computations and AI scripts could be leveraged to be 60-70% passive on the secondary thread, with only 30-40% of it needing access to MainLoop when it tries to give instruction to its creatures.


 


In any case:


One of the major features of Radiant AI was  the ability for NPC's to be carrying out tasks in other parts of the world, without the player being present.


Eg: A farmer will till his fields, or a lumberjack will cut down a tree.render 


Skyrim never actually physically rendered these NPC's to go and do those tasks, they would only NPC's when players are near.


So - in terms of making this a possible system in NWN, you would have to consider despawning creatures - until players come within rendering range (the area?)


When the creature is going to be spawned, check the schedule, and check to see what they are meant to be doing at that time of day, order them to do that activity.


You could either:


Have a heartbeat that runs on each creature, allowing each creature to monitor its own lifetime / usefulness.


(If all players log out - the creature could despawn itself?)


or 


You could have a single pseudo hb that kicks off during the modload event.


This HB would loop through all creatures that are part of the system, and determine what they should be doing, if players are near by that the creatures are still useful etc.


If the creature is deemed to be not useful, remove it or limbo it, until the player is potentially going to see the creature.


 


Essentially, the cleanup operation is around the principle of:


Is a creature in Whiterun, doing his laundry, going to be useful to a player in Riften - given that the player cannot see, hear, or interact with the creature.


If the idea is to 'simulate' that the creature is doing his laundry, then that's basically a computation : Creature does laundry, gets result, record result or give to player.

The creature does not actually have to do his laundry, the only thing that matters is that the player is led to believe that the creature had done his laundry.


 


Thats what I mean when I speak about doing some of these activities 'in the cloud' or just outside of NWN.


An extension application that could run these tasks outside of the nwserver process, would be ideal - kinda like a dedicated brain for doing the calculations and management of all the things that players cannot see.



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #2 on: April 27, 2015, 03:29:11 pm »


               

Offloading the creature AI as much as possible is a neat idea. Hooking the main loop seems like a powerful hack with a lot of potential '<img'>



               
               

               
            

Legacy_kalbaern

  • Hero Member
  • *****
  • Posts: 1531
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #3 on: April 27, 2015, 04:13:32 pm »


               

If NPCs are being despawned when no PCs are in the area, I don't see why using custom OnHearbeat or OnPerception events is an issue. At least when cleanly coded.



               
               

               
            

Legacy_Valgav

  • Full Member
  • ***
  • Posts: 118
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #4 on: April 27, 2015, 04:50:50 pm »


               

I never really though about despawning npcs. I know it's not optimal but if you're gonna limbo them then how you'll get their position later? 


 


Example:


 


Npc has to walk three areas from home to work if you on which location should he spawn if all three suddenly has players? Should i do some vector calculations and divide result by time expected for traveling that distance?


 


You're probably gonna need to load npc for current area and every area connected to current area to create the illusion of persistent.


 


Or what with travelers/caravans encountering bandits? Should i spawn npcs back on locations with encounters?


 


Finally the external brain idea


 


It sounds great to have external process to run the AI but what about combat AI? Moving it outside nwn doesn't sound like a good idea and keeping it inside nwn independent from our "life AI" is like asking for troubles.


 


Also what AI process and nwn process should do with npcs viewed by players? Which one should control them?



               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #5 on: April 27, 2015, 06:07:22 pm »


               

For the external Brain IDEA - I currently use it only for the triggering of complex tasks at the moment, not the actual execution of those tasks.


 


Eg:  I am able to trigger an ExecuteScript call, with certain local vars being set : from the second thread.


            The actual script is still run on MainLoop.


 


To make combat a real possibility, a very robust API would need to be coded to do the instruction transfer from second thread to mainloop and back and forth.


 


But for things where we are just simulating something that the player actually doesn't perceive or interact with : that could in theory be all done on a second thread.


 


Another thing you can do, is create pseudo loops on the second thread, which would be immune or resistant to lag from the MainLoop.


 


Eg: 500 Npc's causing lag - guess what thread they are causing lag on - the MainLoop thread.


If you have a really important process that needs to run every 6 seconds, you could migrate the 'scheduling' of it to the second thread, and have it interact with the MainLoop when it needs to be called.


Once executed, sure, it might run slowly due to the lag, but at least you could always guarantee that it is kicked off every 6 seconds because that second thread is not hampered by the lag from MainLoop , whereas module/area hb is not always so.


(especially if you run the task on another core of your CPU: This is the beauty of C++ or C#, it gives you access to the other cores of your CPU, that nwn does not inherently/naturally have robust access to)



               
               

               
            

Legacy_Valgav

  • Full Member
  • ***
  • Posts: 118
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #6 on: April 27, 2015, 07:13:30 pm »


               

So probably I should use your NWNDotNet to accomplish creating second thread and get the communication between it and thread of server?


 


In fact I never used .NET or C# could you provide some examples where should i start? Alternatively I'm thinking about using elvens nwnx_ruby but I'm not sure if it's compatible with windows version of nwnx.


 


But the whole idea to create second thread or (not if it's possible) even multiple threads to manage AI sounds great and I would really love to try implement this concept.



               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #7 on: April 27, 2015, 09:37:59 pm »


               

nwnx ruby should work in any environment where ruby is installed - windows or linux.


 


As for the NWNDotNet:


https://github.com/Baaleos/NWNDotNet


It uses something called WhiteMagic and a Memory class of mine to hook methods and map the pointers.


I use nwnx_dotnet to inject this via Assembly.Load


If you don't use that : then you will need to use a C++ Bootstrapper to load up .Net framework and then load the DLL.


 


Look at the MainLoop hook:  (its not the best coding - I just did it as a POC)


 


It is setup to continuously check ListOfMessages for any messages incoming from a TCPListener.


 


It shows what I meant about receiving a command from outside of nwn, and then executing a command within nwn based on that command.


The shout command for instance: It receives an argument from the TCPConnection and then uses that as an argument for the Shout, and then the Server will shout, inside the game.


Ala- communication from outside of nwn to inside of nwn.



               
               

               
            

Legacy_Valgav

  • Full Member
  • ***
  • Posts: 118
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #8 on: April 27, 2015, 09:55:52 pm »


               

Yeah I get the idea, but idea is one thing and writing a working code is another and to be honest for now I have no idea where to start '<img'>


 


 


Also we still have a problem with npc position because it's probably not possible for external thread to handle ActionMoveToLocation


 


And about nwnx_ruby I can't compile it to dll.


 


After some playing i found nwnx_cool has nwnx_bridge which also allows to send messages to nwserver which allows to execute scripts, using it with some way of store data i can signal change of daytime from external app. We don't even need heartbeat only way to provide that npc is in battle and app should what for nwn to finish battle to get back to normal routine or remove reference if npc died.


 


But still don't have idea about how to get precise current location.



               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #9 on: April 27, 2015, 11:04:55 pm »


               

Hmmm


Havent used nwnx_ruby.


 


The code I have could work for ActionMoveToLocation:


 


Create a Script : call it - MoveTo.nss


Inside it will read from a specific variable : I cant remember exactly what that variable is : Its defined in my nwnx_cool.dll


You could in theory write the location data out as a  string to a local variable: 


Then execute the script that would read from the variable.


 


That way, the script does a single command: just to trigger the move.


               
               

               
            

Legacy_Valgav

  • Full Member
  • ***
  • Posts: 118
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #10 on: April 27, 2015, 11:26:03 pm »


               

That's not the problem. I just don't know how to handle despawned npces move. Triggering ActionMoveToLocation for 100 npcs on main loop will probably lag or even freeze whole server. 


 


So I probably have to get additional code to create and register progress of movment then manage it from external app by some sort of incrementation on threads.



               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
[Idea] Persistent scheduled NPCs
« Reply #11 on: April 27, 2015, 11:47:08 pm »


               

I think its probably worth while trying to think of what activities the NPC's will be doing.


 


At the very basest level, NPC's are all entities in nwn are just memory pointers.


Eg: 0x0001dcf  or something like that:


 


So if you reduce your thinking to that level, you can imagine that something like this is something that could be managed externally in a database etc


Think about tagging all your NPC's uniquely, and have their 'designated' locations and potentially their scheduled activities set on their entry in the database.


- The way Skyrim works is somewhat similar.


It has an 'activity' of some sort being set/changed against each NPC entity.


EG: I should be mining, therefore I need to find a nearby mining location.


 


I should be sleeping, I need to find a bed....


 


Your NPC's would probably only need to pull 2 variables from the database on regular intervals.


Eg: Where they should be, and what they should be doing.  


(tag of waypoint, and a string or int identifying the activity)


 


Having it on their HB might be difficult for the despawned NPC's 


For that reason, it might be best to have a pseudo hb that is external to the NPC's : 


Looping through the database, checking to see if those NPC'S identified by tag exist, if so, issue the schedule commands etc.


if not : either spawn or wait until their meant to exist.


 


 


From that point of view :


nwserver is going to still issue the commands on mainloop via nwscript.


You could however do any changes you want to the database from outside of nwn - allowing you to change / shuffle the activities.


 


Your 'external brain' could do as much computations as it wants to that database outside of nwn.


It might not sound impressive initially.


But you could have thousands of entities in the database.


Then your brain app could mark those entities as being spawned or despawned.


That way - only the few entities that are deemed useful to the player are spawned, while the others are despawned and no longer consuming CPU cycles.


 


 


Imagine a small PW shaped like this


x = player


N = npc's that are spawned


o = NPC locations as designated by database/brain - which are not spawned


--------------------------------------------------------


|                    |                      |              o       |


|   o               |        x       N  |                       |


|          o        |                      |            o         |


|   o               |     N               |                       |


-------------------------------------------------------


|                    |                      |                       |


|        o          |                      |        o             |


|                    |           o         |                       |


|                    |                      |          o           |


|                    |   o                  |                       |


-------------------------------------------------------


|                    |                      |                       |


|                    |   o                 |      o                |


|          o        |                      |                       |


|                    |                  o  |    o                 |


|   o               |                      |               o      |


--------------------------------------------------------


 


The brain application could check the players location, and spawn the NPC's in the area the player exists in.


It could then mark the npc's as 'despawn' the NPC's in that area when the NPC's are no longer necessary