Graal Forums  

Go Back   Graal Forums > Development Forums > NPC Scripting
FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply
 
Thread Tools Search this Thread Display Modes
  #16  
Old 03-10-2012, 10:04 AM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
Quote:
Originally Posted by salesman View Post
If the information is going to be accessed frequently on the clientside, you don't really have any other options. Although, I'd recommend caching anything that doesn't need to be secure in client.vars as opposed to clientr.vars. For example, the item's icon file name or a description about the item for displaying in the inventory.
Why client vars? The client doesn't need to change them and I don't think you're gaining anything by doing that.
__________________
Reply With Quote
  #17  
Old 03-10-2012, 10:19 AM
fowlplay4 fowlplay4 is offline
team canada
fowlplay4's Avatar
Join Date: Jul 2004
Location: Canada
Posts: 5,200
fowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond repute
I currently do a hybrid of the above on Zodiac. I cache all item data in the SQL DB as it's needed and use a time-stamp and only update the information when it needs to be.

Graal Script Code:
public function MUDLoadItems(items) {
  
// Determine which item need to be updated and remove 
  // up to date items from the items list as needed.
  
temp.clause SQL.generateInClause("arc"items); 
  
temp.query  "SELECT arc, wname, lastupdate
                   FROM MUDItems
                  WHERE " 
temp.clause " AND lastupdate > " timevar2;
  
temp.data SQL.executeSQL2("items"temp.querytrue);
  for (
temp.rowtemp.data.rows) {
    
temp.updated int(temp.row.lastupdate);
    
temp.mudmod  clientr.("muditem_" temp.row.wname)[12];
    if (
temp.updated == temp.mudmod) {
      
items.remove(temp.row.arc);
    } else {
      
temp.item_updates.add(temp.row.arc);
    }
  }
  
// Mass Item Data Update
  
if (temp.item_updates.size() > 0) {
    
temp.clause SQL.generateInClause("arc"temp.item_updates); 
    
temp.query  "SELECT *
                   FROM MUDItems
                   WHERE " 
temp.clause;
    
temp.data  SQL.executeSQL2("items"temp.querytrue);
    for (
temp.rowtemp.data.rows) {
      
clientr.("muditem_" temp.row.wname) = {
        
temp.row.wnametemp.row.typetemp.row.subtype,
        
temp.row.icontemp.row.imagetemp.row.gani,
        
temp.row.mintemp.row.maxtemp.row.mods,
        
temp.row.reqtemp.row.speedtemp.row.price,
        
int(temp.row.lastupdate)
      };
      
items.remove(temp.row.arc);
    }
  }
  
// Items not found in DB
  // Load Individually from File
  // Cache it in DB
  
for (temp.itemitems) {
    
MUDLoadItem(""temp.item);
  }
}

public function 
generateInClause(columnitems) {
  
temp.clause column " IN (";
  
temp.last   items.size() - 1;
  for (
temp.0temp.items.size(); temp.i++) {
    
temp.item items[temp.i];
    if (
temp.== temp.last) {
      
temp.clause @= "'" escapestring2(temp.item) @ "'";
    } else {
      
temp.clause @= "'" escapestring2(temp.item) @ "',";
    }
  }
  
temp.clause @= ")";
  return 
temp.clause.link();

I get pretty much the same performance as loading it directly from a Cache DB every-time with significantly less memory usage.

If I wanted to put a new system in I would go with salesman's initial suggestion though. clientr variables would merely act as a 'cached' reflection of your database. Just make sure your DB is indexed properly.

Really though just put something basic together the item system is probably the easiest system to put together.

I like putting the data in an array and write accessors to make sense of the data in your script. I.e.

clientr.itemdata.id = {name, type, value};

Graal Script Code:
//#CLIENTSIDE
function getItemName(id) {
  return 
clientr.itemdata.(@id)[0];
}

function 
getItemType(id) {
  return 
clientr.itemdata.(@id)[1];
}

function 
getItemValue(id) {
  return 
clientr.itemdata.(@id)[2];

__________________
Quote:
Reply With Quote
  #18  
Old 03-10-2012, 10:43 AM
Draenin Draenin is offline
Magnificent Bastard
Draenin's Avatar
Join Date: Dec 2004
Location: Bermuda Triangle
Posts: 6,790
Draenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud of
Send a message via AIM to Draenin Send a message via MSN to Draenin Send a message via Yahoo to Draenin Send a message via Skype™ to Draenin
Quote:
Originally Posted by salesman View Post
If the information is going to be accessed frequently on the clientside, you don't really have any other options.
Sure you do.

Information like what you just listed ("the item's icon file name or a description about the item for displaying in the inventory") can be stored more conveniently in database tables as well, and you can read from those tables just as easily as you can read them from player accounts.

Variables which are subject to change and specifically relevant to player accounts should be kept on players, and everything else should be stored in a database.

Last edited by Draenin; 03-10-2012 at 10:54 AM..
Reply With Quote
  #19  
Old 03-10-2012, 02:04 PM
Cubical Cubical is offline
Banned
Join Date: Feb 2007
Posts: 1,348
Cubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant future
Quote:
Originally Posted by Draenin View Post
Sure you do.

Information like what you just listed ("the item's icon file name or a description about the item for displaying in the inventory") can be stored more conveniently in database tables as well, and you can read from those tables just as easily as you can read them from player accounts.

Variables which are subject to change and specifically relevant to player accounts should be kept on players, and everything else should be stored in a database.
Why send 100's of unneeded server request when you can just make 1 and store it?

Also is the general consensus that I should kick the ItemCache in the DBNPC to the curb and solely rely on querying the SQL database?
Reply With Quote
  #20  
Old 03-10-2012, 02:06 PM
jamitsu89 jamitsu89 is offline
Registered User
Join Date: Jun 2011
Posts: 27
jamitsu89 is an unknown quantity at this point
Quote:
Originally Posted by Cubical View Post
I have an item by itself being load which has the unique ID of the item and I also have a bunch of clientr.item.itemname.data.etc vars that are holding the data. Would this be viable to load on each login? Keep in mind this is just one item.
Graal Script Code:
clientr.item.wornsword.1=1,wornsword,none,0
clientr
.item.wornsword.data.bi1=mage
clientr
.item.wornsword.data.bi2=1
clientr
.item.wornsword.data.bi3=fireball
clientr
.item.wornsword.data.gems=red
clientr
.item.wornsword.data.itemdescription=Just a test sword
clientr
.item.wornsword.data.itemgani=walk
clientr
.item.wornsword.data.itemimage=block.png
clientr
.item.wornsword.data.itemname=Worn Sword
clientr
.item.wornsword.data.itemsubtype=onehandsword
clientr
.item.wornsword.data.itemthumbnail=block.png
clientr
.item.wornsword.data.itemtype=weapon
clientr
.item.wornsword.data.realname=wornsword
clientr
.item.wornsword.data.rowid=
Any help, suggestions would be appreciated. I want to keep it like this if at all possible. It would make everything easier for me to expand later on without having just one really long string with no apparent order. I will do it the other way if needed.

If all items are going to have the same variables like above, just store them in one flag as an array? Then, rather than loading 14 flags per item, you load 1 per item with all 14 flags in the array.
Reply With Quote
  #21  
Old 03-10-2012, 03:46 PM
Cubical Cubical is offline
Banned
Join Date: Feb 2007
Posts: 1,348
Cubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant futureCubical has a brilliant future
Quote:
Originally Posted by jamitsu89 View Post
If all items are going to have the same variables like above, just store them in one flag as an array? Then, rather than loading 14 flags per item, you load 1 per item with all 14 flags in the array.
readability
Reply With Quote
  #22  
Old 03-10-2012, 04:13 PM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
Quote:
Originally Posted by Cubical View Post
readability
Readability is not an issue here; instead you should abstract away the variable names in favor of scripter-friendly functions like player.getItemProperty(itemid, property). This has the added benefit of allowing you to easily change how you store this data in the future.
__________________
Reply With Quote
  #23  
Old 03-10-2012, 06:37 PM
salesman salesman is offline
Finger lickin' good.
salesman's Avatar
Join Date: Nov 2008
Location: Colorado
Posts: 1,865
salesman has much to be proud ofsalesman has much to be proud ofsalesman has much to be proud ofsalesman has much to be proud ofsalesman has much to be proud ofsalesman has much to be proud ofsalesman has much to be proud of
Quote:
Originally Posted by Draenin View Post
Sure you do.

Information like what you just listed ("the item's icon file name or a description about the item for displaying in the inventory") can be stored more conveniently in database tables as well, and you can read from those tables just as easily as you can read them from player accounts.

Variables which are subject to change and specifically relevant to player accounts should be kept on players, and everything else should be stored in a database.
Did you even read my proposed general solution? The information would be stored in database tables. But whenever serverside information is going to be needed constantly by the client, it is not viable to repeatedly request that information from the server. Instead, you should cache the information in clientr.variables which are in sync with the server.

Quote:
Originally Posted by cbk1994 View Post
Why client vars? The client doesn't need to change them and I don't think you're gaining anything by doing that.
Yeah, I don't know what I was saying. I was thinking that there was a difference in how they are synchronized (client requiring less overhead), but I was getting mixed up with something else. There could be, but not in the way that I was thinking.

plz 4give
__________________
Reply With Quote
  #24  
Old 03-11-2012, 01:51 AM
jamitsu89 jamitsu89 is offline
Registered User
Join Date: Jun 2011
Posts: 27
jamitsu89 is an unknown quantity at this point
Quote:
Originally Posted by cbk1994 View Post
Readability is not an issue here; instead you should abstract away the variable names in favor of scripter-friendly functions like player.getItemProperty(itemid, property). This has the added benefit of allowing you to easily change how you store this data in the future.
This.
Reply With Quote
  #25  
Old 03-11-2012, 08:10 PM
xXziroXx xXziroXx is offline
Master of Puppets
xXziroXx's Avatar
Join Date: May 2004
Location: Sweden
Posts: 5,288
xXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant future
Send a message via AIM to xXziroXx Send a message via MSN to xXziroXx
I am still very opposed to storing actual item data on clients, one way or the other. Fills up attributes with useless garbage that only have to be sent to clients once per session and stored in a weapon NPC.

I don't know if reading this script will help you at all, since it's not commented, but this is exactly how temporary data like descriptions etc. is handled on Maloria.

Graal Script Code:
function onCreated()
{
  
join("functions_sql");
  
requestSQL("PRAGMA synchronous=OFF"true);
}

function 
onActionServerSide(action)
{
  if (
action == "query") {
    
temp.cache params[1];
    
temp.identifier params[2];
    
temp.querier params[3];
    
    
queryToClient(temp.cachetemp.identifiertemp.querier);
  }
}

public function 
queryToClient(temp.cachetemp.identifiertemp.querier) {
  
temp.object query(temp.cachetemp.identifier);
  
temp.object temp.object.saveVarsToArray(false);
  
  
triggerClient("gui"name"queryReturn"temp.cachetemp.identifiertemp.objecttemp.querier);
}

public function 
query(categoryidentifier)
{
  if (
category in "items""skills""spells""buffs""quests""baddies""nations""enchants" }) {
    
temp.tableName category;
    
    
temp.queryString "SELECT * FROM" SPC temp.tableName SPC "WHERE identifier='" identifier "'";
    
temp.query getSQL(temp.queryString);
    if (
temp.query.rows[0].size() == 0) {
      return;
      echo(
"Query for '" identifier "' failed (" category SPC "@" SPC player.account "), testing callstack:");
      
temp.callstack getCallStack();
    
      for (
temp.temp.callstack.size() - 1temp.>= 0temp.--)
        echo(
"call stack entry " temp.": " temp.callstack[temp.i].scriptcallobject.name "." temp.callstack[temp.i].name);
      
//echo("[" @ name @ "]: Query on '" @ identifier @ "' failed (" @ category SPC "@" SPC player.account @ ")");
      
return false;
    }
    
    
temp.object.copyFrom(temp.query.rows[0]);
    if (
category == "nations") {
      
temp.object.ranks.loadVarsFromArray(temp.object.ranks);
      
temp.object.ranks "";
    }
    return 
temp.object;
  }
  
  else {
    if (
category == null)
      echo(
name ".getObject - parameter category is null");
    else
      echo(
name ".getObject - " category " is not a valid category.");
  }
}

public function 
getTimestamp(tableidentifier)
{
  
temp.query getSQL("SELECT * FROM" SPC table SPC "WHERE identifier='" identifier "'");
  
  if (
temp.query.rows.size() == 0)
    return 
false//return echo("[" @ name @ "]: Query on '" @ identifier @ "' failed");
  
else
    return 
temp.query.timestamp;
}

//#CLIENTSIDE
function onCreated()
{
  
this.queryList = new TStaticVar();
  const 
QUERYTIMELIMIT 5;
  
  
setTimer(0.05);
}

function 
onActionClientside(action)
{
  if (
action == "queryReturn") {
    
temp.cache params[1];
    
temp.identifier params[2];
    
temp.serializedObject params[3];
    
temp.querier params[4];
    
    
temp.object = new TStaticVar();
    
temp.object.loadVarsFromArray(temp.serializedObject);
    
updateCacheEntry(temp.cachetemp.identifiertemp.objecttemp.querier);
    
    
updatePlayerVariables();
    
    
this.(@"query_" querier "_list").remove(temp.identifier);
    
temp.querier this.(@"query_" temp.querier);
    
    
//echo("Debug Query: (" @ temp.identifier @ ") (" @ temp.querier @ ")");
    
if (isObject(temp.querier)) {
      
//echo("yes");
      
temp.querier.onReceivedCacheObject(temp.identifiertemp.cache);
    }
  }
}

public function 
query(cacheidentifierquerier)
{
  if (
cacheEntryExist(cacheidentifier))
    return 
getCacheEntry(cacheidentifier);
  
  
//echo("Query(" @ cache @ "," SPC identifier @ ")...");
  
if (identifier in this.(@"query_" querier "_list"))
    return;
  
  
this.(@"query_" querier) = querier;
  
this.(@"query_" querier "_list").add(identifier);
  
  
triggerServer("gui"name"query"cacheidentifierquerier);
}

public function 
updatePlayerVariables()
{
  
this.playerItemNames player.getItemNames();
  
this.playerItemIdentifiers player.getItemIdentifiers();
}

public function 
getCacheSize(cache)
  return 
cacheExist(cache) ? this.(@"cache_" cache).getDynamicVarNames().size() : -1;

public function 
getCache(cache)
  return 
cacheExist(cache) ? this.(@"cache_" cache).getDynamicVarNames() : -1;

public function 
cacheExist(cache)
  return (
this.(@"cache_" cache).getDynamicVarNames().size() > 0);
  
  
//return this.(@"cache_" @ cache).getDynamicVarNames().size() > 0 ? true : false;

public function getCacheEntrySize(cacheidentifier)
  return 
cacheEntryExist(cacheidentifier) ? this.(@"cache_" cache).(@identifier).getDynamicVarNames().size() : -1;

public function 
getCacheEntry(cacheidentifier)
  return 
cacheEntryExist(cacheidentifier) ? this.(@"cache_" cache).(@identifier) : -1;

public function 
cacheEntryExist(cacheidentifier)
  return (
this.(@"cache_" cache).(@identifier).objecttype() == "TStaticVar");

  
//return this.(@"cache_" @ cache).(@identifier).objecttype() == "TStaticVar" ? true : false;

function updateCacheEntry(cacheidentifierdata)
{
  
this.(@"cache_" cache).(@identifier) = new TStaticVar();
  
this.(@"cache_" cache).(@identifier).copyFrom(data);
  
this.trigger("onCacheUpdated_" cache "_" identifier"");

__________________

"A delayed game is eventually good, but a rushed game is forever bad." - Shigeru Miyamoto
Reply With Quote
  #26  
Old 03-12-2012, 12:43 AM
Draenin Draenin is offline
Magnificent Bastard
Draenin's Avatar
Join Date: Dec 2004
Location: Bermuda Triangle
Posts: 6,790
Draenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud of
Send a message via AIM to Draenin Send a message via MSN to Draenin Send a message via Yahoo to Draenin Send a message via Skype™ to Draenin
Quote:
Originally Posted by salesman
Did you even read my proposed general solution?
Yup. Did you even read mine?

Quote:
Originally Posted by salesman
The information would be stored in database tables. But whenever serverside information is going to be needed constantly by the client, it is not viable to repeatedly request that information from the server. Instead, you should cache the information in clientr.variables which are in sync with the server.
Yeah, but when you cache that information, you don't need to have clientr.variables for every little piece of information on every weapon or item. Only pieces of information which can be manipulated by the player's actions. A simple query is enough to fetch all the information associated with a record you've created in a database table, and that's way easier than trying to fetch those pieces of information one-by-one.
Reply With Quote
  #27  
Old 03-12-2012, 01:20 AM
jamitsu89 jamitsu89 is offline
Registered User
Join Date: Jun 2011
Posts: 27
jamitsu89 is an unknown quantity at this point
The only advantage I see of caching them in a weapon NPC as opposed to storing them in clientr. variables is it takes up less VISIBLE space. Yet if you want to be able to quickly refer to these item flags without checking the Database, you will have them visibly in the flags. GK have over 500 flags as previously stated, and they're running just fine.

Therefore I see no true "better" way, and it's down to a matter of personal preference.

Heck, if you're storing them in clientr. you don't even need to triggerClient; you can just write them then and there to be available Clientside.
Reply With Quote
  #28  
Old 03-12-2012, 01:34 AM
xXziroXx xXziroXx is offline
Master of Puppets
xXziroXx's Avatar
Join Date: May 2004
Location: Sweden
Posts: 5,288
xXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant futurexXziroXx has a brilliant future
Send a message via AIM to xXziroXx Send a message via MSN to xXziroXx
Quote:
Originally Posted by jamitsu89 View Post
The only advantage I see of caching them in a weapon NPC as opposed to storing them in clientr. variables is it takes up less VISIBLE space. Yet if you want to be able to quickly refer to these item flags without checking the Database, you will have them visibly in the flags. GK have over 500 flags as previously stated, and they're running just fine.

Therefore I see no true "better" way, and it's down to a matter of personal preference.
I've spent a lot of time developing on "big" servers, namely Maloria and Zodiac. Along with Kingdoms Debug, they all had one thing in common: player flags was filled with garbage, which made looking through them more annoying than it should be. This was especially annoying on Zodiac.

Quote:
Originally Posted by jamitsu89 View Post
Heck, if you're storing them in clientr. you don't even need to triggerClient; you can just write them then and there to be available Clientside.
clientr. flags trigger to the client automatically, you know. I recall Stefan posting something about updating clientr. flags frequently wasn't very optimal. I can't remember the exact details.
__________________

"A delayed game is eventually good, but a rushed game is forever bad." - Shigeru Miyamoto
Reply With Quote
  #29  
Old 03-12-2012, 01:38 AM
Tolnaftate2004 Tolnaftate2004 is offline
penguin.
Join Date: Jul 2004
Location: Berkeley, CA
Posts: 534
Tolnaftate2004 is a jewel in the roughTolnaftate2004 is a jewel in the rough
Send a message via AIM to Tolnaftate2004 Send a message via Skype™ to Tolnaftate2004
Quote:
Originally Posted by xXziroXx View Post
I recall Stefan posting something about updating clientr. flags frequently wasn't very optimal. I can't remember the exact details.
The details
__________________
◕‿‿◕ · pfa · check yer syntax! · src

Killa Be: when i got that locker in 6th grade the only thing in it was a picture of a midget useing a firehose :/
Reply With Quote
  #30  
Old 03-12-2012, 02:16 AM
jamitsu89 jamitsu89 is offline
Registered User
Join Date: Jun 2011
Posts: 27
jamitsu89 is an unknown quantity at this point
Quote:
Originally Posted by xXziroXx View Post
clientr. flags trigger to the client automatically, you know. I recall Stefan posting something about updating clientr. flags frequently wasn't very optimal. I can't remember the exact details.
Correct. And requesting them from an SQLite DB does not. (Although as you'll notice in my post, this wasn't even a main point. It was simply a whimsical).

Equally, if you are updating clientr. vars a lot it won't be optimal, but you're not in this case, are you. You're caching the data to be Read at a later date, and as such there does not seem to be any benefit for either of the two methods.

So like I said: personal preference.
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 09:49 PM.


Powered by vBulletin® Version 3.8.3
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (C) 1998-2008 Linux cyberjoueurs All Rights Reserved.