Graal Forums

Graal Forums (https://forums.graalonline.com/forums/index.php)
-   NPC Scripting (https://forums.graalonline.com/forums/forumdisplay.php?f=8)
-   -   Posessed DBNPC - Please help (https://forums.graalonline.com/forums/showthread.php?t=134269477)

scriptless 08-15-2014 02:14 AM

Posessed DBNPC - Please help
 
Okay I got a DBNPC. I noticed something that I canno't explain. I did not know it was possible and have no idea how to fix this.

I used the following:

PHP Code:

this.("option." player.account) = 0

as well as

PHP Code:

makevar("this.option." player.account) = 0

Problem I am having is no matter which one I use. I get strange behavior. Either the string does get added but then magically disappears when the player logs off, or it appears and stays in the list but then the next time it just creates a second string, and so on. So then I'm left with 2 strings with 100% the same name.

Also,

PHP Code:

temp.pl2 findplayer("bloodpet");
this.("option." "bloodpet") = 1;
if ( 
this.option.bloodpet == null ) echo("null"); 

Outputs:

PHP Code:

null 

All I am trying to accomplish is add a "option.accountNAME = 0" if there is no string nammed option.accountNAME

PiX 08-15-2014 03:10 AM

this.option.(@ player.account) will access a variable within the "option" var, but this.("option." @ player.account) treats "option.<account>" as a variable name itself. That is how you can have two separate data points with similar paths. It also can make the latter unwanted path impossible to access by makevar.

scriptless 08-15-2014 05:11 AM

Thanks. That helped alot.

Now the only problem I am having with it is the getstringkeys not getting all the flags. Any idea why it might not? I made sure they are all added using the same method.

PHP Code:

  temp.choosefrom getstringkeys("this.option.");
  
temp.options.desc null;

  
// If player is not in the list go ahead and add them anyways
  
if ( this.option.(@player.account) == null ) {
    
this.option.(@player.account) = 0;
  }
  
  for ( 
temp.coption temp.choosefrom ) {
    
// this tells it the option is a playerobject
    // get there account name and head icon
    
if ( player.account != temp.coption ) {
      
temp.pl      findplayer(temp.coption);
      
temp.offline temp.pl == NULL;
      
temp.pl      temp.offline ? new TServerPlayer(@temp.coption) : temp.pl;
      
temp.options.desc.add(temp.pl.account);
    }
  }

  for ( 
temp.pl allplayers ) {
    if ( !(
temp.pl.account in temp.options.desc) ) {
      
// they are RC
      
if ( temp.pl.level != null && temp.pl.account != player.account) {
        
temp.options.desc.add(temp.pl.account);
      }
    }
  }

  
// now send temp.data to be shown in the list :)
  
temp.data temp.options.savevarstoarray(false);
  return 
temp.data

I believe the problem is related to offline players. I could have sworn this was working before for loading head and hair of offline players.

PiX 08-15-2014 01:16 PM

The function getstringkeys will not find a var path if it does not exist. If you are setting your vars to 0, "", {}, or null, the var name and path will not be created because it is equal to null. Try this.option.(@player.account) = 1; or any value not null.

scriptless 08-15-2014 03:25 PM

Quote:

Originally Posted by PiX (Post 1730051)
The function getstringkeys will not find a var path if it does not exist. If you are setting your vars to 0, "", {}, or null, the var name and path will not be created because it is equal to null. Try this.option.(@player.account) = 1; or any value not null.

Thanks, I was wondering that. The DBNPC must be removing all flags = 0 when it is updated.

Restraint 08-21-2014 02:33 AM

Have you considered simply using TStaticVars? It will likely simplify what you're trying to do.

You create a TStaticVar as follows:

PHP Code:

  temp.opt this.options = new TStaticVar(); 

Then you can access, say, this.options.(@player.account) like:

PHP Code:

  opt.(@player.account) = ...; 

You could get the "keystrings" via something like:

PHP Code:

  temp.vars opt.getDynamicVarNames(); 

You could toss it to other scripts easily.

You could pass it from clientside to serverside via something like:

PHP Code:

  temp.info opt.saveVarsToArray(false);
  
triggerServer("weapon"this.nameinfo); 

With the serverside looking like:

PHP Code:

function onActionServerside(info) {
  
temp.opts this.options = new TStaticVar();
  
opts.loadVarsFromArray(info);
  ...


It'd generally allow for a lot more of what you're trying to do, since "this.options" is now a path like you want.

scriptless 08-21-2014 07:27 PM

Kinda what I'm already doing. There's a problem tho. DBNPC seems to not always save flags and they dissapear. Not entirely sure under which circumstances tho. But occasionally I notice some just vanishing. Some people said it happens sometimes when restarting npc server even with the rc save npcs command

PiX 08-21-2014 08:17 PM

TStaticVar is normally not used for database flag storage. It is the same as a TGraalVar (every base data type) except as a global reference. This means that the data would not be stored on the database npc, but actually on a global object, which may be deleted after time or server restart. A common technique for storing persistent dynamic vars to a database npc is using a prefix like this.("option_" @ player.account) . You can then find the full list of accounts by doing getstringkeys("this.option_") .

scriptless 08-21-2014 09:31 PM

I would have to check my script but about the TStaticVar.. but I was meaning I'm using the save art array and loading also the same way. It shows in the flags. Also saves some flags but not every one. I would say I counted 77 saved strings and sadly no way to know for sure how many did not save. Not sure why it would work sometimes... but not all the times..

cbk1994 08-21-2014 09:32 PM

Quote:

Originally Posted by scriptless (Post 1730304)
DBNPC seems to not always save flags and they dissapear. Not entirely sure under which circumstances tho. But occasionally I notice some just vanishing. Some people said it happens sometimes when restarting npc server even with the rc save npcs command

I still have no idea why, but it seems that if you do this.trigger('update'); in a DBNPC after saving some value, it won't be lost. We had tons of trouble in the past with DBNPCs rolling back (especially on Era), and this seemed to fix it.

We also noticed that savenpcs seems not effective; we wrote our own that we called before restarting the NPC-server that just called trigger('update') on every DBNPC with much better results -shrug-

Maybe it's just a placebo but I kind of doubt it. I don't know why it works or if it has to be update.

scriptless 08-21-2014 09:36 PM

Quote:

Originally Posted by cbk1994 (Post 1730310)
I still have no idea why, but it seems that if you do this.trigger('update'); in a DBNPC after saving some value, it won't be lost. We had tons of trouble in the past with DBNPCs rolling back (especially on Era), and this seemed to fix it.

We also noticed that savenpcs seems not effective; we wrote our own that we called before restarting the NPC-server that just called trigger('update') on every DBNPC with much better results -shrug-

Maybe it's just a placebo but I kind of doubt it. I don't know why it works or if it has to be update.

Is that trigger available on all dbnpc or is that a custom trigger? Would like to see any documentation on that if possible. I will try it and see if we get any better results maybe. Would you recommend using that trigger every time a new value is added or no?

Restraint 08-21-2014 09:44 PM

Quote:

Originally Posted by PiX (Post 1730308)
TStaticVar is normally not used for database flag storage. It is the same as a TGraalVar (every base data type) except as a global reference. This means that the data would not be stored on the database npc, but actually on a global object, which may be deleted after time or server restart. A common technique for storing persistent dynamic vars to a database npc is using a prefix like this.("option_" @ player.account) . You can then find the full list of accounts by doing getstringkeys("this.option_") .

This is a terribly ugly way of doing it, as you need to do (" " @ ) every time.

You can do what you're saying via:

this.options.(@player.account)

The advantages of a TStaticVar instead of that are:

1. Easier to send between server and client via savevarstoarray()
2. Easier to write to a file via savevars()
3. Easier to access with smaller variable names and thus cleaner
4?. I would imagine a guess that .getDynamicVarNames() is an O(c) operation, while .getStringKeys() is an O(n) operation.

Also, you claim it's a "global" reference but no more than a DB NPC's variables are.

The advantages outweigh the disadvantages.

However, I am well aware that TStaticVars do not persist for long periods of time. They seem to have some time limit until they are garbage collected. If you're creating a static variable, you can reload it whenever it's garbage collected. If this is a variable that changes rarely but needs to maintain long-term data, saving it to a file is more persistent than BOTH methods described (And a TStaticVar is ideal for that, via .saveVars()).

As Scriptless has stated, even this.'s can have troubles persisting in DB NPCs. If you want true persistence for long-term database usage, I would suggest either:

1. File I/O. This is best method if the files will not change often (since I/O can be laggy). The easiest method for this is, you guessed it, TStaticVars and .savevars

2. SQL DB. This is the best method if the options will be changing frequently, as reading/writing to SQL is less intense than files.

PiX 08-21-2014 10:10 PM

Quote:

Originally Posted by scriptless (Post 1730312)
Is that trigger available on all dbnpc or is that a custom trigger? Would like to see any documentation on that if possible. I will try it and see if we get any better results maybe. Would you recommend using that trigger every time a new value is added or no?

A trigger("update"); can sometimes help with saving dbnpc data, but is normally not needed. It is also sometimes used on the serverside of npc scripts if something is changed on the serverside of it, but does not change on the clientside. Again, normally not needed.

Jakov_the_Jakovasaur 08-21-2014 10:16 PM

hello!

tStaticVars should never be garbage collected for as long as they have an active reference, ive seen them remain for several months and only be destroyed whenever the npc-server is restarted

personally i prefer to store data within an sqlite database, however load the sql data into a tStaticVar cache upon database npc initialization for easier access

scriptless 08-21-2014 11:30 PM

I definately want to move the system to sqlite. But it's currently live on the server and only going to be active another half a week. So it's kinda a bandaid to help make sure it works better till then. I'll try the trigger for now hopefully it buys me time to finish the sql part.

Thanks everyone for the info.


All times are GMT +2. The time now is 08:05 AM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2026, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.