Creation/Dev/Local Database NPC Communication: Difference between revisions

From Graal Bible
No edit summary
Line 1: Line 1:
'''http://www.antiunixmad.com/'''
= Introduction =
What exactly is the purpose of database communication? You might have seen the telephone scripts on Era, where anyone can talk to anyone else on another phone on the server. The method that these phones use to transfer messages is database communication. Database communication is really useful for passing data between database instances of NPCs on a server, while at the same time, giving them a friendlier ID. But first, you must understand a couple of things about database NPCs.


'''[[Viper]]'s [[Graal]] Issues.'''
Note: This article '''expects''' a certain degree of knowledge of new engine scripting, using classes and database NPCs, etc.


Hello everyone, as of late, many people have been attacking me on the issues and matters, trying to lie about things, bend the truth, and downright spin to make me and others of my cause look bad, in this text document i will discuss and lay to rest the issues that matter.
=== What are Database NPCs? ===
There are two major types of DB NPC: these are DB NPCs created using [[NC]], and putnpc2()-style NPCs created using scripting, and having your script joined to them using join(). In this tutorial, we will be using both putnpc2()-style NPCs, and DB NPCs. We'll be giving each putnpc2()-style NPC we create a nice friendly identifier.


I have been involved [[Graal]] for over three years now, and i used to really like [[Graal]] and its admins alot, then slowly after about a year [[Graal]] and its admins went in a bad downward spiral, i still stuck with [[Graal]] in hopes [[Graal]] would pull itself out of this hole and [[Unixmad]] would go back to the right path, this however did not happen, instead [[Unixmad]] and even [[Stefan]] went fouler and lower than i could have imageined, First with fireing [[Pachuka]] and [[Fuitad]], two of the BEST [[Graal]] admins ever in my view for no other reason than disagreeing with his future plans, then if just fireing them was not bad enough, he threatend to sue them and kill they're families, this was so wrong and bad [[Fuitad]] even said he would punch [[Unixmad]] in the face for saying that if he met him in real life, but that was just the beginning of the downward spiral [[Unixmad]] foolishly invoked onto [[Graal]], he then blatantly STOLE a domain name [[Graal]].net from Owl Shimy which costed over 30$ US Dollars, and never gave it back to him and never paid him for the cost of the domain, he also threatend to sue Owl Shimy and kill his family although it was [[Unixmad]] which stole the domain from Owl Shimy, then around [[Graal]]1.3.1 he blocked off [[GServer]]s officially and threatend to sue anyone that ran the former [[GServer]]s, although they were released as "Freeware" and actually used to encourage people to use the [[GServer]]s, this was a blatant attempt to monopolise , threaten, and intemidate that players that actually helped [[Graal]] and supported him, he then made claims he copyrighted "[[Graal]]" and would contact so called "Lawres" about anyone that used the name "[[Graal]]" or had "[[Graal]] Files" on there websites, although [[Graal]] was distributed as "Freeware" or "Shareware" and had no official software copyrights related to it, and that the name "[[Graal]]" was actually the name of a holy sacred golden cup used in some religion, and in that he has commited blasphemy against whatever religion has the so called "Holy [[Graal]]", then later on [[Unixmad]] fired SuperNick, because of his country and his origion and called him an American Asian slut, this was the first sign of racism on the part of [[Unixmad]], towards [[Graal]]1.4.1 [[Unixmad]] was secretly unwrapping his sadistic plans, he then started claiming credit and claiming to own the copyrights to [[Graal]], although [[Unixmad]] has done nothing but host some stupid weak as servers, and yet [[Stefan]] Knorr has done all the real work for [[Graal]], and was the one to make ZeldaOnline , [[Graal]]Online in the first place and has written every bit of codeing for the [[Graal]] Client , [[GServer]], RC, ect, yet [[Unixmad]] the worthless pile of trash that he is steals all credit for [[Graal]], then in February 2001, [[Unixmad]] and Antago release [[Graal]]2001 and the start of the "Pay to Play" system, now i have no problem with the fact that it is pay to play, the issue is when you PAY for something you actually expect to get the worth while of your money in this product, but instead they got a shittily made level generated land that was 99% empty, the NPCs were and are laggy as hell, and there were no quests, and there is only two shitty things today for hearts that suck so much i refuse to even call them quests, and to add to that about 40% of everyone that paid and gave [[Unixmad]] there credit card number NEVER got the accounts they paid 27$ or more for, and those that did clearly got chumped out by a cheap peice of crap that aint worth paying for, it sucked so badly that most people played on [[Graal]] Classic still, even those that foolishly paid for pay to play accounts, and in an attempt to "FORCE" people to pay for a shitty product they do not want against they're will [[Unixmad]] hired "Tyhm" to deface and ruin [[Graal]]Classic in an attempt to make it buggier and less fun than even [[Graal]]2001, about this time i was disgusted with [[Unixmad]] and most of the other admins and decided to downright turn against [[Graal]] and for the most part stop playing the peice of crap in general. People starting getting angry, complaining, asking for help, and asking for refunds, of coarse [[Unixmad]] gave noone a cash refund, and simply deleted and banned "PAID ACCOUNTS" of those who complained, asked for help, or asked for a refund these are PAYING CUSTOMERS, they have the rights of basic service that they PAID for, [[Unixmad]] promises pay to play players a quality product and customer service, but instead gives them a grade F product and ripps off his customers and delete they're accounts that they PAID HIM money for, his excuse? Credit card fraud, when infact at least 90% of the people he bans for credit card fraud pay legitamately with there OWN credit cards or pay via paypal by check, and yet [[Unixmad]] has stolen and used others credit card numbers to buy things for himself on several occassions, he also claims he needs pay to play money to keep [[Graal]] alive and running, yet there has been evidence that he makes at least 90% profit out of the monies he gets, and that he uses illegal porn ad banners and illegal cookie style web tracking and giveing email adresses of the players and even phone numbers of every player to spam and telemarketting companies without there permission, he even keeps personal player info, includeing email, adress, and phone number on unsecure servers which have already been leaked out, such info about people should not be on a public webserver accessable to the internet in anyway, then after all that [[Unixmad]] starts banning african american people, asians, koreans, and or people with images of people of that race from the [[Graal]]2001 forums and [[Graal]] itself, yet again they are paying customers and this is another sickening act of racism on the part of [[Unixmad]] and [[Graal]]Online, and then even more disgusting is what [[Stefan]] posts on the [[Graal]]2001 forums, he makes several anti american, racist, pro terrorist, pro nazi, and pro taliban comments on that post and goes on and on several pages bashing americans, this post was offense, obcene, and disgusting to many people includeing myself . If all that does not make you sick to your stomache or dislike [[Unixmad]] yet, i am far from done, then [[Unixmad]] proceeds to illegally DDOS webservers of mafukie and make threats to him over the phone, and has phone assaulted me over 40 times a day between midnight and 5am, and has made threats to sue dozens of people, kill there families, and shut down innocent websites and servers, while hosting illegal stuff and doing illegal things himself with the use of his own wanadoo.fr servers, stuff which includes child porn, bestiality porn, DVD Piracy, DDOS Attacks, theft of copyrighted materials from gameing companies such as nintendo, Credit Card fraud, theft, spamming, phone harrassment, useage of illegal pirated corperate softwares, all this just to start the list of what [[Unixmad]]', [[Stefan]], and they're servers are doing 24/7 for nearly 4 years now , anyone that likes [[Unixmad]] or thinks he is a good person even after all this is clearly a fool, everything in this document is the truth and why i hate [[Unixmad]] so much, if you like [[Unixmad]] after all these sickening things he does, then you are no better than a KKK or Neo Nazi member and should go kill yourselfs, i do not tolerate facists, racists, or nazis, they are all bad people, and [[Unixmad]] is one of the worst of the worst, and no person with any morales could tolerate or support such a person like Stephane Portha or [[Stefan]] Knorr. The people that spin, lie and bend the truth in support of [[Unixmad]] will always exist, but i will always reveal the truth about [[Unixmad]], and EVERYTHING said in this document is true, despite what any assclowns try and say about this, and this supriseingly enough is only 1% of the bad things [[Unixmad]] has done, how some people even tolerate, none the less support such a bad person is beyond me... I fight against bad people like [[Unixmad]], why? Because unlike many others in this world i actually care about other people, and i will do everything in my power to stop [[Unixmad]] from hurting [[Graal]] or its innocent players, many say i want to destroy and kill [[Graal]], this is NOT true, i used to love [[Graal]], i only wish to stop [[Unixmad]]'s evil sadistic illegal actions and restore [[Graal]] to the great game it used to be when it was "for the players, by the players" , but if i have to destroy [[Graal]]Online in exchange to stop [[Unixmad]]'s tyranny, it will be regreteable, but sometimes some sacrifices have to be made for the greater good, lets just hope that [[Unixmad]] drops dead and that sacrifice never has to be made... I love [[Graal]] and lots of its players, and i wish to someday restore it to the grandness it once had, but bad people like [[Unixmad]] must be gotten rid of if that is to be achieved...
=== Important concepts ===
DB NPCs each have a unique identifier.
 
[[Image:rc_classlist_normal.png]] NPCs created using putnpc2() each have a unique identifier, which is dynamically generated when the NPC is created. An example of one of these IDs is "localnpc_era_present_32673165_8". Don't worry about remembering these - we will write methods to save these identifiers automatically.
 
[[Image:rc_localnpcs_normal.png]] NPCs created using NC have a specified identifier that you assign. Again, these must be unique. An example of one of these might be "DB_Phones", or "SkyldTest".
 
In either a database NPC or a putnpc2() NPC, the ID can be found with the '''this.name''' variable.
 
= Objective =
The objective for this tutorial is to create a system where NPCs created using putnpc2() can communicate with each other. So, let's start by designing the system.
 
You will want:
* One Database NPC with a sensible and easy name. For example, if you are creating a system for phones, a suitable name may be "DB_Phones". Try to avoid using "-" in names, since this makes it harder to link to them.
* One script class with your scripting in. In the example of creating phones, you will want to have your phone scripting in here.
* A weapon to place putnpc2() instances of your script class with.
 
=== Database NPC ===
The Database NPC will be one of the core parts of your system. As we've said already, each putnpc2() we have will be assigned a friendly ID, like a phone number. The Database NPC is where these identifiers will be stored, where any NPC can access them. In this case, it's important that our putnpc2() NPCs can read them!
 
Create a Database NPC. For this example, we'll use "DB_Identifiers".
 
=== Script classes ===
The majority of your scripting will be in these script classes. However, there are a few fundamental things that must be inside this class before you can begin.
 
==== Saving the ID of the class ====
When the NPC is placed, it must save it's ID into the database so that we can later access it. In this case, we will generate a random four digit number which will identify the NPC, and then save it to DB_Identifiers.
 
<pre>function onCreated()
{
  while (this.number == NULL)
  {
    temp.try = int(random(1000, 9999);
 
    if (DB_Identifiers.("class_" @ temp.try) == NULL)
    { // Okay, the number is free, let's save it
      DB_Identifiers.("class_" @ temp.try) = this.name;
   
      // Now save the number locally so we know it
      this.number = temp.try;
     
      break;
    }
  }
}</pre>
 
==== Creating a method to find the NPCs by their new ID ====
 
So far, the NPC will assign itself a four digit number and save that number into the database. But there are still a few complications. You need a way to find the ID of a class by just it's four digit number. So, we write a function to retrieve a number if it's available. We'll call it findClass().
 
<pre>function findClass(temp.number)
{
  // Perform a little sanity check on the number
  if (!(temp.number >= 1000 && temp.number <= 9999))
  {
    return -1; // Invalid number, so stop!
  }
 
  // Make sure the number is an integer
  temp.number = int(temp.number);
 
  // Check if the database has the number saved
  if (DB_Identifiers.("class_" @ temp.number) != NULL)
  { // Database has got this identifier, let's return the object ID
    return DB_Identifiers.("class_" @ temp.number);
  }
    else
  { // Database hasn't got the ID, no such NPC?
    return -1;
  }
}</pre>
 
Now, from inside your class, you can see if there is a class on the server with your ID just by using findClass().
 
To better explain, say you created two NPCs. The first NPC named itself with the number 3209. The second NPC named itself with 5563. If you wanted to find the object for the first NPC, you would use:
<pre>with (findClass(3209))
{
  // code
}</pre>
... And likewise for the second NPC:
<pre>with (findClass(5563))
{
  // code
}</pre>
 
This is exactly how we will make the NPCs communicate.
 
==== Creating a function to be run remotely ====
Now, to give the NPC an entry point from other NPCs, we'll create a public function. Public functions can be run by any NPC on the same side (serverside or clientside).
 
So, let's define a public function called entryPoint(). This is where instances of your class will send data to other instances. This is also where the commands will be interpreted to do something useful.
 
<pre>public function entryPoint(temp.data)
{
  // Code
}</pre>
 
Now, the creation of this function means that you can do this:
 
<pre>findClass(5563).entryPoint("I am sending this data!");</pre>
 
Now, does this help you? Well, this has given you a foundation to allow your classes to communicate. Hold on, though. There are still some complications.
 
==== Destroying class instances correctly ====
If you just this.destroy() an instance of your class without first removing the identifier, the identifier will stay there until someone removes it. So, let's make sure that your routine clears out the identifier properly.
 
<pre>function destroyInstance()
{
  DB_Identifiers.("class_" @ temp.number) = NULL;
  this.destroy();
}</pre>
 
Now you can use destroyInstance() to correctly remove your NPC '''and''' it's identifier.
 
==== An example use of what you've created ====
Here's an example of something you might want to put in your class to test if it works.
 
<pre>function onCreated()
{
  while (this.number == NULL)
  {
    temp.try = int(random(1000, 9999);
 
    if (DB_Identifiers.("class_" @ temp.try) == NULL)
    { // Okay, the number is free, let's save it
      DB_Identifiers.("class_" @ temp.try) = this.name;
   
      // Now save the number locally so we know it
      this.number = temp.try;
     
      break;
    }
  }
}
 
function findClass(temp.number)
{
  // Perform a little sanity check on the number
  if (!(temp.number >= 1000 && temp.number <= 9999))
  {
    return -1; // Invalid number, so stop!
  }
 
  // Make sure the number is an integer
  temp.number = int(temp.number);
 
  // Check if the database has the number saved
  if (DB_Identifiers.("class_" @ temp.number) != NULL)
  { // Database has got this identifier, let's return the object ID
    return DB_Identifiers.("class_" @ temp.number);
  }
    else
  { // Database hasn't got the ID, no such NPC?
    return -1;
  }
}
 
public function entryPoint(temp.data)
{
  if (temp.data == "explode")
  {
    putexplosion(2, this.x, this.y);
    return 1; // Let's let the other NPC know that the command was received
  }
}
 
function onPlayerChats()
{
  temp.tok = player.chat.tokenize();
 
  if (temp.tok[0] == "explode")
  {
    if (findClass(temp.tok[1]).entryPoint("explode") == 1)
    {
      player.say2("You successfully exploded the NPC!");
    }
      else
    {
      player.say2("Maybe the NPC doesn't exist?");
    }
  }
}</pre>
 
You could then say "explode 5563" from any other NPC of your instance, and cause it to explode!
 
=== Weapon to place your instances ===
Let's actually create a method to place your NPCs now. For this, you'll need a weapon. The name of the weapon isn't really important. The code for this is simple.
 
<pre>function onActionserverside()
{
  if (params[0] == "place")
  {
    putnpc2(player.x, player.y, "join yourclassname;");
  }
}
 
//#CLIENTSIDE
 
function onPlayerChats()
{
  if (player.chat == "drop")
  {
    triggeraction(0, 0, "serverside", "yourweaponname", "place");
  }
}</pre>
 
= Conclusion =
So, you've got your framework. You could easily now create your system on a framework of these functions by giving each of your NPCs a friendly name. The reason we used four digit numbers here is because they are easy to work with. You might decide to make it 7 digit numbers to resemble phone numbers, or even email addresses!

Revision as of 03:54, 1 July 2007

Introduction

What exactly is the purpose of database communication? You might have seen the telephone scripts on Era, where anyone can talk to anyone else on another phone on the server. The method that these phones use to transfer messages is database communication. Database communication is really useful for passing data between database instances of NPCs on a server, while at the same time, giving them a friendlier ID. But first, you must understand a couple of things about database NPCs.

Note: This article expects a certain degree of knowledge of new engine scripting, using classes and database NPCs, etc.

What are Database NPCs?

There are two major types of DB NPC: these are DB NPCs created using NC, and putnpc2()-style NPCs created using scripting, and having your script joined to them using join(). In this tutorial, we will be using both putnpc2()-style NPCs, and DB NPCs. We'll be giving each putnpc2()-style NPC we create a nice friendly identifier.

Important concepts

DB NPCs each have a unique identifier.

Rc classlist normal.png NPCs created using putnpc2() each have a unique identifier, which is dynamically generated when the NPC is created. An example of one of these IDs is "localnpc_era_present_32673165_8". Don't worry about remembering these - we will write methods to save these identifiers automatically.

Rc localnpcs normal.png NPCs created using NC have a specified identifier that you assign. Again, these must be unique. An example of one of these might be "DB_Phones", or "SkyldTest".

In either a database NPC or a putnpc2() NPC, the ID can be found with the this.name variable.

Objective

The objective for this tutorial is to create a system where NPCs created using putnpc2() can communicate with each other. So, let's start by designing the system.

You will want:

  • One Database NPC with a sensible and easy name. For example, if you are creating a system for phones, a suitable name may be "DB_Phones". Try to avoid using "-" in names, since this makes it harder to link to them.
  • One script class with your scripting in. In the example of creating phones, you will want to have your phone scripting in here.
  • A weapon to place putnpc2() instances of your script class with.

Database NPC

The Database NPC will be one of the core parts of your system. As we've said already, each putnpc2() we have will be assigned a friendly ID, like a phone number. The Database NPC is where these identifiers will be stored, where any NPC can access them. In this case, it's important that our putnpc2() NPCs can read them!

Create a Database NPC. For this example, we'll use "DB_Identifiers".

Script classes

The majority of your scripting will be in these script classes. However, there are a few fundamental things that must be inside this class before you can begin.

Saving the ID of the class

When the NPC is placed, it must save it's ID into the database so that we can later access it. In this case, we will generate a random four digit number which will identify the NPC, and then save it to DB_Identifiers.

function onCreated()
{
  while (this.number == NULL)
  {
    temp.try = int(random(1000, 9999);

    if (DB_Identifiers.("class_" @ temp.try) == NULL)
    { // Okay, the number is free, let's save it
      DB_Identifiers.("class_" @ temp.try) = this.name;
     
      // Now save the number locally so we know it
      this.number = temp.try;
      
      break;
    }
  }
}

Creating a method to find the NPCs by their new ID

So far, the NPC will assign itself a four digit number and save that number into the database. But there are still a few complications. You need a way to find the ID of a class by just it's four digit number. So, we write a function to retrieve a number if it's available. We'll call it findClass().

function findClass(temp.number)
{
  // Perform a little sanity check on the number
  if (!(temp.number >= 1000 && temp.number <= 9999))
  {
    return -1; // Invalid number, so stop!
  }

  // Make sure the number is an integer
  temp.number = int(temp.number);
  
  // Check if the database has the number saved
  if (DB_Identifiers.("class_" @ temp.number) != NULL)
  { // Database has got this identifier, let's return the object ID
    return DB_Identifiers.("class_" @ temp.number);
  }
    else
  { // Database hasn't got the ID, no such NPC?
    return -1;
  }
}

Now, from inside your class, you can see if there is a class on the server with your ID just by using findClass().

To better explain, say you created two NPCs. The first NPC named itself with the number 3209. The second NPC named itself with 5563. If you wanted to find the object for the first NPC, you would use:

with (findClass(3209))
{ 
  // code
}

... And likewise for the second NPC:

with (findClass(5563))
{ 
  // code
}

This is exactly how we will make the NPCs communicate.

Creating a function to be run remotely

Now, to give the NPC an entry point from other NPCs, we'll create a public function. Public functions can be run by any NPC on the same side (serverside or clientside).

So, let's define a public function called entryPoint(). This is where instances of your class will send data to other instances. This is also where the commands will be interpreted to do something useful.

public function entryPoint(temp.data)
{
  // Code
}

Now, the creation of this function means that you can do this:

findClass(5563).entryPoint("I am sending this data!");

Now, does this help you? Well, this has given you a foundation to allow your classes to communicate. Hold on, though. There are still some complications.

Destroying class instances correctly

If you just this.destroy() an instance of your class without first removing the identifier, the identifier will stay there until someone removes it. So, let's make sure that your routine clears out the identifier properly.

function destroyInstance()
{
  DB_Identifiers.("class_" @ temp.number) = NULL;
  this.destroy();
}

Now you can use destroyInstance() to correctly remove your NPC and it's identifier.

An example use of what you've created

Here's an example of something you might want to put in your class to test if it works.

function onCreated()
{
  while (this.number == NULL)
  {
    temp.try = int(random(1000, 9999);

    if (DB_Identifiers.("class_" @ temp.try) == NULL)
    { // Okay, the number is free, let's save it
      DB_Identifiers.("class_" @ temp.try) = this.name;
     
      // Now save the number locally so we know it
      this.number = temp.try;
      
      break;
    }
  }
}

function findClass(temp.number)
{
  // Perform a little sanity check on the number
  if (!(temp.number >= 1000 && temp.number <= 9999))
  {
    return -1; // Invalid number, so stop!
  }

  // Make sure the number is an integer
  temp.number = int(temp.number);
  
  // Check if the database has the number saved
  if (DB_Identifiers.("class_" @ temp.number) != NULL)
  { // Database has got this identifier, let's return the object ID
    return DB_Identifiers.("class_" @ temp.number);
  }
    else
  { // Database hasn't got the ID, no such NPC?
    return -1;
  }
}

public function entryPoint(temp.data)
{
  if (temp.data == "explode")
  {
    putexplosion(2, this.x, this.y);
    return 1; // Let's let the other NPC know that the command was received
  }
}

function onPlayerChats()
{
  temp.tok = player.chat.tokenize();

  if (temp.tok[0] == "explode")
  {
    if (findClass(temp.tok[1]).entryPoint("explode") == 1)
    {
      player.say2("You successfully exploded the NPC!");
    } 
      else
    {
      player.say2("Maybe the NPC doesn't exist?");
    }
  }
}

You could then say "explode 5563" from any other NPC of your instance, and cause it to explode!

Weapon to place your instances

Let's actually create a method to place your NPCs now. For this, you'll need a weapon. The name of the weapon isn't really important. The code for this is simple.

function onActionserverside()
{
  if (params[0] == "place")
  {
    putnpc2(player.x, player.y, "join yourclassname;"); 
  }
}

//#CLIENTSIDE

function onPlayerChats()
{
  if (player.chat == "drop")
  {
    triggeraction(0, 0, "serverside", "yourweaponname", "place");
  }
}

Conclusion

So, you've got your framework. You could easily now create your system on a framework of these functions by giving each of your NPCs a friendly name. The reason we used four digit numbers here is because they are easy to work with. You might decide to make it 7 digit numbers to resemble phone numbers, or even email addresses!