MantisBT - Zandronum
View Issue Details
0001831Zandronum[All Projects] Suggestionpublic2014-06-11 21:542018-09-30 21:35
Watermelon 
Torr Samaho 
highfeatureN/A
closedfixed 
1.2 
1.31.3 
0001831: SQLite database for persistent data storage
Continuation of the database discussion to move it out of the account system thread.
No tags attached.
related to 0001176new  Account system development/discussion 
Issue History
2014-06-11 21:54WatermelonNew Issue
2014-06-11 21:54WatermelonRelationship addedrelated to 0001176
2014-06-11 21:57WatermelonNote Added: 0009129
2014-06-11 22:32AlexMaxNote Added: 0009134
2014-06-12 00:06HypnotoadNote Added: 0009137
2014-06-12 20:16Torr SamahoNote Added: 0009158
2014-06-13 08:19HypnotoadNote Added: 0009181
2014-06-14 03:30WatermelonNote Added: 0009271
2014-06-14 03:31WatermelonNote Edited: 0009271bug_revision_view_page.php?bugnote_id=9271#r4933
2014-06-14 03:31WatermelonNote Edited: 0009271bug_revision_view_page.php?bugnote_id=9271#r4934
2014-06-14 03:32WatermelonNote Edited: 0009271bug_revision_view_page.php?bugnote_id=9271#r4935
2014-06-14 04:59DuskNote Added: 0009273
2014-06-14 05:00DuskNote Edited: 0009273bug_revision_view_page.php?bugnote_id=9273#r4937
2014-06-14 05:12WatermelonNote Edited: 0009271bug_revision_view_page.php?bugnote_id=9271#r4938
2014-06-14 06:02HypnotoadNote Added: 0009275
2014-06-14 06:23HypnotoadNote Added: 0009277
2014-06-14 06:24HypnotoadNote Edited: 0009277bug_revision_view_page.php?bugnote_id=9277#r4942
2014-06-14 06:25HypnotoadNote Edited: 0009277bug_revision_view_page.php?bugnote_id=9277#r4943
2014-06-14 06:25HypnotoadNote Edited: 0009277bug_revision_view_page.php?bugnote_id=9277#r4944
2014-06-14 07:52Torr SamahoNote Added: 0009278
2014-06-14 10:04HypnotoadNote Added: 0009279
2014-06-14 11:59HypnotoadNote Edited: 0009279bug_revision_view_page.php?bugnote_id=9279#r4948
2014-06-14 13:21Torr SamahoNote Added: 0009283
2014-06-14 13:35Torr SamahoNote Edited: 0009283bug_revision_view_page.php?bugnote_id=9283#r4955
2014-06-14 14:04HypnotoadNote Added: 0009285
2014-06-14 14:09HypnotoadNote Edited: 0009285bug_revision_view_page.php?bugnote_id=9285#r4957
2014-06-14 14:12Torr SamahoNote Added: 0009287
2014-06-14 14:14HypnotoadNote Edited: 0009285bug_revision_view_page.php?bugnote_id=9285#r4958
2014-06-14 14:14HypnotoadNote Added: 0009288
2014-06-14 14:33Torr SamahoNote Added: 0009290
2014-06-14 14:38HypnotoadNote Added: 0009291
2014-06-14 14:50Torr SamahoNote Added: 0009292
2014-06-14 15:02HypnotoadNote Added: 0009293
2014-06-14 15:31DuskNote Added: 0009294
2014-06-14 15:31DuskAssigned To => Torr Samaho
2014-06-14 15:31DuskStatusnew => needs testing
2014-06-14 15:31DuskSummaryDatabase discussion => SQLite database for persistent data storage
2014-06-15 15:13HypnotoadNote Added: 0009416
2014-06-16 00:22WatermelonNote Added: 0009498
2014-06-16 07:41HypnotoadNote Added: 0009510
2014-06-16 09:08Konar6Note Added: 0009516
2014-06-17 11:21HypnotoadNote Added: 0009542
2014-06-17 14:44HypnotoadNote Edited: 0009542bug_revision_view_page.php?bugnote_id=9542#r5035
2014-06-17 14:44WatermelonNote Added: 0009543
2014-06-17 18:44Torr SamahoNote Added: 0009554
2014-06-17 19:28HypnotoadNote Added: 0009556
2014-06-17 20:12CatastropheNote Added: 0009557
2014-06-17 20:17Torr SamahoNote Added: 0009558
2014-06-17 20:50StrikerMan780Note Added: 0009559
2014-06-17 20:50StrikerMan780Note Edited: 0009559bug_revision_view_page.php?bugnote_id=9559#r5045
2014-06-17 20:51StrikerMan780Note Edited: 0009559bug_revision_view_page.php?bugnote_id=9559#r5046
2014-06-17 20:54StrikerMan780Note Edited: 0009559bug_revision_view_page.php?bugnote_id=9559#r5047
2014-06-17 21:09Torr SamahoNote Added: 0009562
2014-06-17 22:52AlexMaxNote Added: 0009564
2014-06-17 23:16StrikerMan780Note Added: 0009565
2014-06-17 23:17StrikerMan780Note Edited: 0009565bug_revision_view_page.php?bugnote_id=9565#r5052
2014-06-17 23:18StrikerMan780Note Edited: 0009565bug_revision_view_page.php?bugnote_id=9565#r5053
2014-06-17 23:21StrikerMan780Note Edited: 0009565bug_revision_view_page.php?bugnote_id=9565#r5054
2014-06-17 23:22StrikerMan780Note Edited: 0009565bug_revision_view_page.php?bugnote_id=9565#r5055
2014-06-17 23:23StrikerMan780Note Edited: 0009565bug_revision_view_page.php?bugnote_id=9565#r5056
2014-06-18 09:27HypnotoadNote Added: 0009569
2014-06-18 19:05StrikerMan780Note Edited: 0009565bug_revision_view_page.php?bugnote_id=9565#r5076
2014-06-19 06:51AlexMaxNote Added: 0009590
2014-06-19 06:51AlexMaxNote Edited: 0009590bug_revision_view_page.php?bugnote_id=9590#r5080
2014-06-19 07:30HypnotoadNote Added: 0009591
2014-06-19 17:51Torr SamahoNote Added: 0009595
2014-06-20 11:48HypnotoadNote Added: 0009601
2014-06-20 11:50HypnotoadNote Added: 0009602
2014-06-20 11:51HypnotoadNote Edited: 0009602bug_revision_view_page.php?bugnote_id=9602#r5084
2014-06-20 11:51HypnotoadNote Edited: 0009602bug_revision_view_page.php?bugnote_id=9602#r5085
2014-06-21 18:17StrikerMan780Note Added: 0009627
2014-06-21 18:18StrikerMan780Note Edited: 0009627bug_revision_view_page.php?bugnote_id=9627#r5096
2014-06-21 18:22StrikerMan780Note Edited: 0009627bug_revision_view_page.php?bugnote_id=9627#r5097
2014-06-21 18:23StrikerMan780Note Edited: 0009627bug_revision_view_page.php?bugnote_id=9627#r5098
2014-06-21 19:08Torr SamahoNote Added: 0009629
2014-06-21 19:08Torr SamahoNote Edited: 0009629
2014-06-21 19:09Torr SamahoNote Edited: 0009629bug_revision_view_page.php?bugnote_id=9629#r5103
2014-06-21 19:09Torr SamahoNote Revision Dropped: 9629: 0005101
2014-06-21 19:09Torr SamahoNote Revision Dropped: 9629: 0005102
2014-06-22 11:43Torr SamahoNote Added: 0009648
2014-06-22 12:16HypnotoadNote Added: 0009649
2014-06-22 12:30Torr SamahoNote Added: 0009650
2014-06-22 13:13HypnotoadNote Added: 0009651
2014-06-22 13:16DuskNote Added: 0009652
2014-06-22 13:24Torr SamahoNote Added: 0009653
2014-06-22 13:31Torr SamahoNote Edited: 0009653bug_revision_view_page.php?bugnote_id=9653#r5119
2014-06-22 14:01HypnotoadNote Added: 0009656
2014-06-22 14:05Torr SamahoNote Added: 0009657
2014-06-22 14:07DuskNote Added: 0009658
2014-06-22 14:08DuskNote Edited: 0009658bug_revision_view_page.php?bugnote_id=9658#r5121
2014-06-22 14:16Torr SamahoNote Added: 0009659
2014-06-22 14:44HypnotoadNote Added: 0009660
2014-06-22 14:45HypnotoadNote Edited: 0009660bug_revision_view_page.php?bugnote_id=9660#r5125
2014-06-22 14:52Torr SamahoNote Added: 0009661
2014-06-22 14:55HypnotoadNote Added: 0009662
2014-06-22 15:24Torr SamahoNote Added: 0009663
2014-06-22 15:32HypnotoadNote Added: 0009664
2014-06-22 15:33HypnotoadNote Edited: 0009664bug_revision_view_page.php?bugnote_id=9664#r5127
2014-06-22 15:34HypnotoadNote Edited: 0009664bug_revision_view_page.php?bugnote_id=9664#r5128
2014-06-22 15:40Torr SamahoNote Added: 0009665
2014-06-22 15:47HypnotoadNote Added: 0009667
2014-06-22 15:51Torr SamahoNote Added: 0009668
2014-06-22 16:11HypnotoadNote Added: 0009669
2014-06-22 17:22AlexMaxNote Added: 0009672
2014-06-22 17:29Torr SamahoNote Added: 0009673
2014-06-22 17:46AlexMaxNote Added: 0009674
2014-06-23 19:13Torr SamahoNote Added: 0009717
2014-06-29 20:17HypnotoadNote Added: 0009794
2014-06-30 01:24ZzZomboNote Added: 0009798
2014-06-30 06:03Torr SamahoProduct Version1.3 => 1.2
2014-06-30 06:06Torr SamahoNote Added: 0009801
2014-06-30 06:06Torr SamahoNote Edited: 0009801bug_revision_view_page.php?bugnote_id=9801#r5241
2014-06-30 06:07Torr SamahoNote Revision Dropped: 9801: 0005240
2014-06-30 14:01HypnotoadNote Added: 0009803
2014-06-30 17:35Torr SamahoNote Added: 0009804
2014-07-02 18:29HypnotoadNote Added: 0009822
2014-07-02 18:39CatastropheNote Added: 0009823
2014-07-02 20:07Torr SamahoNote Added: 0009824
2014-07-11 13:19HypnotoadNote Added: 0009933
2014-07-12 14:33Torr SamahoNote Added: 0009944
2014-07-12 14:33Torr SamahoNote Edited: 0009944bug_revision_view_page.php?bugnote_id=9944#r5329
2014-07-12 16:33HypnotoadNote Added: 0009950
2014-07-12 16:57Torr SamahoNote Added: 0009951
2014-07-12 20:10HypnotoadNote Added: 0009955
2014-07-12 22:15HypnotoadNote Edited: 0009955bug_revision_view_page.php?bugnote_id=9955#r5336
2014-07-29 08:31HypnotoadNote Added: 0010074
2014-07-29 08:32HypnotoadNote Edited: 0010074bug_revision_view_page.php?bugnote_id=10074#r5426
2014-07-29 08:37HypnotoadNote Edited: 0010074bug_revision_view_page.php?bugnote_id=10074#r5427
2014-07-29 08:41HypnotoadNote Edited: 0010074bug_revision_view_page.php?bugnote_id=10074#r5428
2014-07-29 08:51HypnotoadNote Edited: 0010074bug_revision_view_page.php?bugnote_id=10074#r5429
2014-07-29 21:05Torr SamahoNote Added: 0010091
2014-07-29 21:24HypnotoadNote Added: 0010092
2014-07-29 21:26HypnotoadNote Edited: 0010092bug_revision_view_page.php?bugnote_id=10092#r5472
2014-07-29 21:27HypnotoadNote Edited: 0010092bug_revision_view_page.php?bugnote_id=10092#r5473
2014-07-30 21:21Torr SamahoNote Added: 0010098
2014-07-30 23:11HypnotoadNote Added: 0010099
2014-08-23 20:18HypnotoadNote Added: 0010223
2014-08-23 20:19HypnotoadNote Edited: 0010223bug_revision_view_page.php?bugnote_id=10223#r5539
2014-08-23 20:19HypnotoadNote Edited: 0010223bug_revision_view_page.php?bugnote_id=10223#r5540
2014-08-23 21:52AlexMaxNote Added: 0010224
2014-08-23 22:35HypnotoadNote Added: 0010225
2014-08-23 22:35HypnotoadNote Edited: 0010225bug_revision_view_page.php?bugnote_id=10225#r5542
2014-08-23 22:59HypnotoadNote Edited: 0010225bug_revision_view_page.php?bugnote_id=10225#r5543
2014-08-23 23:02HypnotoadNote Edited: 0010225bug_revision_view_page.php?bugnote_id=10225#r5544
2014-08-23 23:02HypnotoadNote Edited: 0010225bug_revision_view_page.php?bugnote_id=10225#r5545
2014-08-24 16:32Torr SamahoNote Added: 0010226
2014-08-24 16:53HypnotoadNote Added: 0010227
2014-08-24 18:48Torr SamahoNote Added: 0010228
2014-08-24 18:57HypnotoadNote Added: 0010229
2014-08-24 19:05HypnotoadNote Edited: 0010229bug_revision_view_page.php?bugnote_id=10229#r5547
2014-08-24 19:09HypnotoadNote Edited: 0010229bug_revision_view_page.php?bugnote_id=10229#r5548
2014-08-24 20:03HypnotoadNote Added: 0010231
2014-08-24 20:56HypnotoadNote Edited: 0010231bug_revision_view_page.php?bugnote_id=10231#r5550
2014-08-25 07:00Blzut3Note Added: 0010234
2014-08-25 12:16HypnotoadNote Added: 0010235
2014-08-25 17:34HypnotoadNote Added: 0010237
2014-08-25 19:06Blzut3Note Added: 0010238
2014-08-31 20:05Torr SamahoNote Added: 0010245
2014-08-31 20:05Torr SamahoNote Edited: 0010245bug_revision_view_page.php?bugnote_id=10245#r5554
2014-10-05 22:20DuskFixed in Version => 1.3
2014-10-05 22:22DuskNote Added: 0010347
2014-10-05 22:22DuskStatusneeds testing => resolved
2014-10-05 22:22DuskResolutionopen => fixed
2018-09-30 21:35Blzut3Statusresolved => closed

Notes
(0009129)
Watermelon   
2014-06-11 21:57   
To continue this discussion:


Quote
That would somehow encourage mods not to interfere with each others data, but still doesn't enforce it. Adding the extra column won't be a problem, but then all of the ACS DB functions get an additional argument. What's the general opinion on this? Since a mod could just write "zanrun-time" (one argument, i.e. namespace) instead of "zanrun", "time" (two argument, i.e. namespace and section), we don't really get much out of the more complicated interface except of this slight encouragement to use a unique namespace. Another possibility would be renaming the namespace argument in the ACS functions to section and to force selecting a namespace via a new lump.


I don't think there is a way to enforce it.

The idea of a lump might work, though then it introduces a lot of overhead to deal with (ex: conflicts, who gets what priority, when...etc).
If we miss something here and find out later down the road, it could be very painful.



We also have to take into account hosting services like Best-Ever where people might maliciously try to write into other people's DB's.
How does one stop this?
(0009134)
AlexMax   
2014-06-11 22:32   
> That would somehow encourage mods not to interfere with each others data, but still doesn't enforce it. Adding the extra column won't be a problem, but then all of the ACS DB functions get an additional argument. What's the general opinion on this? Since a mod could just write "zanrun-time" (one argument, i.e. namespace) instead of "zanrun", "time" (two argument, i.e. namespace and section), we don't really get much out of the more complicated interface except of this slight encouragement to use a unique namespace. Another possibility would be renaming the namespace argument in the ACS functions to section and to force selecting a namespace via a new lump.

See that's the thing - I don't necessarily want to ENFORCE separation between mods. If one mod wants to peek into another mod's namespace, I'd like to leave that option open. I just feel like the EASY thing that most mod makers will end up doing is assuming that they have exclusive access to the database all to themselves.

However, part of me also agrees with you about the additional parameters to each DB command that would require. Perhaps the best thing we can do is document the use of these functions and ensure that the documentation has the mod-specific namespace as part of the documentation. That way, people who "learn" by copypasting will get this extra namepsacing "for free".

> I think technically strings in ACS are something like a "handle" internally, but I'm not fond of the idea of introducing more handle types. As far as I can tell ACS is not designed for these kind of things. IMO the Prepare and GetPrepared functions I proposed are more in line with the limited scope of ACS.

What I was going to suggest is not necessarily a new type, but merely returning an integer that acted like any other number from the point of view of ACS, but could be passed to functions that would do the handle lookup at the time of the call.

I can see where you're coming from in terms of complexity, but I am still not a fan of your use of global state. Especially considering the number of different scopes available in ACS, I feel like this will end up footgunning ACS coders in unexpected ways when they try to use these API's in more than one scope at the same time. Are there any other instances in the ZDoom ACS API that global state is used...other than perhaps setting the currently in-use font?

If I had handles, I feel like I could...say...run a couple of queries on OPEN and then merely keep the handles around in order to easily refer back to data as-needed without having to waste time copying the entire dataset out of the database by hand.

Also, just an unrelated side note, I feel like providing constants along with the API like DB_ORDER_ASC/DB_ORDER_DESC would be a good idea, to make the function calls more readable by sight.
(0009137)
Hypnotoad   
2014-06-12 00:06   
I'd just like to say that it's definitely useful to have full control over both a keyname and namespace as I've seen some question whether we should be allowed to specify namespace as a parameter in each function. The namespace gives an extra degree of freedom which makes it much easier to filter out data without having to rely too much on constantly constructing unique strings using strparam, plus it's very useful for sorting; how are you supposed to tell the database to sort only keys with say a MAP01_ prefix?
(0009158)
Torr Samaho   
2014-06-12 20:16   
Quote from Watermelon

We also have to take into account hosting services like Best-Ever where people might maliciously try to write into other people's DB's.
How does one stop this?

I don't see any feasible way to introduce a permission system, but Best-Ever simply could make each custom server to use its own database by forcing how the CVAR databasefile is set.

Quote from AlexMax

However, part of me also agrees with you about the additional parameters to each DB command that would require. Perhaps the best thing we can do is document the use of these functions and ensure that the documentation has the mod-specific namespace as part of the documentation. That way, people who "learn" by copypasting will get this extra namepsacing "for free".

So just let the documentation encourage to uses namespaces like "zanrun-time" and leave it at this?

Quote from AlexMax

Are there any other instances in the ZDoom ACS API that global state is used...other than perhaps setting the currently in-use font?

Not really, but there is nothing really comparable to the kind of handle you suggest either. Extending the global state idea to a kind of handle that is just an int to ACS shouldn't be that complicated though. The biggest issue is how to free handles. A mod would need to do this explicitly.

Quote from AlexMax

Also, just an unrelated side note, I feel like providing constants along with the API like DB_ORDER_ASC/DB_ORDER_DESC would be a good idea, to make the function calls more readable by sight.

Yes, we should do this.

Quote from Jroc

I'd just like to say that it's definitely useful to have full control over both a keyname and namespace as I've seen some question whether we should be allowed to specify namespace as a parameter in each function.

We will definitely keep both. The only question is whether it's really necessary to add a third thing, e.g. section. I think it's not as long as modders use namespaces like "zanrun-time".
(0009181)
Hypnotoad   
2014-06-13 08:19   
Can I request an "ignore parameter case" bool parameter for retrieving and setting DB entries? When retrieving, if this bool is true it will ignore the case and only match the letters when looking up namespace and keyname strings, and when setting it will force the namespace and keyname strings to be upper case. This not being the case currently has caused me a bunch of problems, for instance if you try to use n:PRINTNAME_LEVEL as part of your namespace, this will sometimes set it with a lowercase map lump name and sometimes upper case (of the same map lump) depending on certain circumstances, and so will set and retrieve different records depending on arbitrary stuff (such as whether you did map map01 or map MAP01 to change to that map).
(0009271)
Watermelon   
2014-06-14 03:30   
(edited on: 2014-06-14 05:12)
EDIT: Do Dusk's one

(0009273)
Dusk   
2014-06-14 04:59   
(edited on: 2014-06-14 05:00)
maybe this? Didn't compile this either, but needs just one strparam call


#define CASE_DIFFERENCE ('a' - 'A')
int g_toLowerBuffer[1024];

function str toLower (str s)
{
    int i, c;

    for (i = 0; str[i] != '\0'; ++i)
    {
        c = GetChar (str, i);

        if (c >= 'A' && c <= 'Z')
            g_toLowerBuffer[i] = c + CASE_DIFFERENCE;
        else
            g_toLowerBuffer[i] = c;
    }

    g_toLowerBuffer[i] = '\0';
    return strparam (a:g_toLowerBuffer);
}


(0009275)
Hypnotoad   
2014-06-14 06:02   
Thanks, positron provided me with a strtoupper function but it requires bcc ('http://zandronum.com/forum/showthread.php?tid=4864 [^]' ) so I'm aware this stuff is possible. However many people might have no idea that some of the strings they are sending have inconsistent casing, I didn't catch this for a couple of days and it caused a lot of problems.
(0009277)
Hypnotoad   
2014-06-14 06:23   
(edited on: 2014-06-14 06:25)
Also, can I request the public beta on zandro.com be updated with the DB features? We've had a lot of fun populating the database with our personal bests on zanrun IDL flagrunning (see here:'http://modenov.com/hypnotoad/test/ [^]' , click on map names and player names for more stats ), but a lot of people are unable to join due to the difficulty for them of obtaining a cutting edge build and getting it to work with doomseeker/ide.

(0009278)
Torr Samaho   
2014-06-14 07:52   
Quote from Jroc
Also, can I request the public beta on zandro.com be updated with the DB features?
Sure. Is a beta of the latest 1.3 version sufficient or do you need features from 2.0?
(0009279)
Hypnotoad   
2014-06-14 10:04   
(edited on: 2014-06-14 11:59)
I'm not sure, could you provide a 1.3 build of the windows binary and files so I can see if zanrun works on it? Also, will account features be available for it yet? Otherwise, some way to get a player's ip address will probably be needed before it's public because at the moment I'm only using the player's name which could be changed or someone else could impersonate; Watermelon said he'd be making a function for getting the IP as an int so hopefully this can be put in first before the public beta is updated.

edit: come to think of it, the latest version of 2.0 should be fine, since 2.0 is what's linked under the development builds anyway.

(0009283)
Torr Samaho   
2014-06-14 13:21   
(edited on: 2014-06-14 13:35)
The current 1.3 repository version has the same account and database support that 2.0 has. I'd prefer a 1.3 beta release since we plan to release this as stable rather soon and this would give us some extra testing for 1.3.

I'll upload a windows binary you can test.

EDIT: Here is the current 1.3 Windows build.

(0009285)
Hypnotoad   
2014-06-14 14:04   
(edited on: 2014-06-14 14:14)
Testing at the moment, database doesn't seem to be working at all now, not reading from the database file, can't narrow down the problem at the moment, will update if I find out more info.

edit: problem seems to be the namespace, this function:

SetDBEntryInt (maplump, "MapRecordTime", timec );
Where str maplump = strtoupper(strparam(n:PRINTNAME_LEVEL));

for some reason stores to a namespace of the player's name, rather than the name of the map lump as it did before.

edit2: so looks like n:PRINTNAME_LEVEL doesn't exist in 1.3 only 2.0. Can that be backported, or another function to determine the maplumps name be added?

(0009287)
Torr Samaho   
2014-06-14 14:12   
Did you print the result of strtoupper(strparam(n:PRINTNAME_LEVEL)) to the console to make sure that the problem is really in SetDBEntryInt?
(0009288)
Hypnotoad   
2014-06-14 14:14   
See my edit
(0009290)
Torr Samaho   
2014-06-14 14:33   
So far I didn't plan any ZDoom backports for 1.3. We'd like to finish this version as soon as possible.
(0009291)
Hypnotoad   
2014-06-14 14:38   
Well there definitely needs to be some way to get the maplump name, otherwise how can you get or set map specific stats? Dusk mentioned using levelnum but this only works for MAPXX format maps or if it's defined in mapinfo, and many mapsets don't use this naming format at all (and zanrun is designed to work for almost any ctf or survival mapset).
(0009292)
Torr Samaho   
2014-06-14 14:50   
I see and looked at the necessary changes. Fortunately, they are isolated. Please try this binary.
(0009293)
Hypnotoad   
2014-06-14 15:02   
Thanks, seems to be working so far.
(0009294)
Dusk   
2014-06-14 15:31   
Ticket reformatted.
(0009416)
Hypnotoad   
2014-06-15 15:13   
Since this says needs testing, thought I'd just further re-iterate that after some more hefty zanrun sessions there seems to have been absolutely no problems with the build provided.
(0009498)
Watermelon   
2014-06-16 00:22   
How is the DB working? All well?
(0009510)
Hypnotoad   
2014-06-16 07:41   
All is working well, but of course I'm being held back by lack of sorting and no way to uniquely identify players regardless of their on screen nick yet.
(0009516)
Konar6   
2014-06-16 09:08   
You will have to wait for the account system being operational or use names for now. IP address is not a way to identify players across sessions, it only identifies the current connection. IP addresses of some players change daily.
(0009542)
Hypnotoad   
2014-06-17 11:21   
(edited on: 2014-06-17 14:44)
Another useful feature would be to have a method to get and store the date. It can be useful to know when certain stats, records etc.. were set, and how long they have been this way. It may also help further sort top 10 lists, as if multiple people get the same score, the person who got it first should be given priority.

edit: oh and on the topic of new features - I think along with the sorting, something like GetDBSortedPosition will be needed. It's all very well to be able to sort and get the top x entries, but what if you want to find the position of a specific entry? For instance, what if I want to display someone's personal best time on a map, and also display what position that time is in the rankings (e.g. Personal Best: 15.34s (5th)). Something like GetDBSortedPosition(str namespace, str keyname, bool ascending) or however the formatting would be with the prepare functions would be nice. This would return an int that is the position in the namespace the entry appears when sorted.

(0009543)
Watermelon   
2014-06-17 14:44   
For the date:
'http://zandronum.com/tracker/view.php?id=1501 [^]'
(0009554)
Torr Samaho   
2014-06-17 18:44   
Quote from Jroc

I think along with the sorting, something like GetDBSortedPosition will be needed. It's all very well to be able to sort and get the top x entries, but what if you want to find the position of a specific entry

I see why you want this kind of function, but things are starting to get quite specialized here. I'll think about whether we want an ACS interface for this kind of query. Technically, it should be doable in SQLite by checking the value of the entry and then counting how many entries are not lower (or not higher) than the given value.

Quote from StrikerMan780
So, the database system only uses SQLite? Or is it possible to connect to an external MySQL database server? I kind of need to be able to connect to an external server if I'm gonna do what I plan to do.

So far our backend uses a local SQLite database. As long as you implement the functions necessary for the ACS interface, you can use any other database backend though. We tried to make the API independent of the specific database choice. Given the limitations of ACS it is important that the functions used by ACS return instantly. You can't use any kind of threading in ACS.
(0009556)
Hypnotoad   
2014-06-17 19:28   
Well, I wouldn't say it's that specialized. Player rankings will be one of the main uses of this database feature, there are already plans to add rankings for duel and ctf players.
(0009557)
Catastrophe   
2014-06-17 20:12   
Hey, I've begun documenting some of the new functions, here:'http://wiki.zandronum.com/SetDBEntryInt, [^]' and here:'http://wiki.zandronum.com/GetDBEntryInt. [^]'

Is there documentation anywhere on the other commands? Also what should I add to my ACC to get this working?
(0009558)
Torr Samaho   
2014-06-17 20:17   
The necessary zspecial.acs entries to add the new functions to ACC are

    -108:SetDBEntryInt(3),
    -109:GetDBEntryInt(2),
    -110:SetDBEntryString(3),
    -111:GetDBEntryString(2),
    -112:IncrementDBEntryInt(3),
    -113:PlayerIsLoggedIn(1),
    -114:GetPlayerAccountName(1),

The only documentation on them is what I wrote in the tracker tickets and the commit messages.
(0009559)
StrikerMan780   
2014-06-17 20:50   
(edited on: 2014-06-17 20:54)
@Torr: How would I connect it to a MySQL server then? Any examples?

About threading... Hate always using it to compare with, but SourcePawn cannot use threading either. However, they get around that by using Callbacks.

In that, you can call a function with several parameters. First being the database handle, the second being the query, and the third being what Script to use as a callback. The function returns immediately, and the rest of whatever script is running will continue to execute. Once the query is successfully completed, it executes another script (the one you defined in the function) where you can work with the results of the query.

Would a system like this work?

(0009562)
Torr Samaho   
2014-06-17 21:09   
Quote from StrikerMan780
How would I connect it to a MySQL server then? Any examples?
I have never connected to a MySQL server with C/C++, so I don't know. To use MySQL, the following internal Zandronum functions need to be implemented based on MySQL:

void DATABASE_SaveSetEntry ( const char *Namespace, const char *EntryName, const char *EntryValue );
void DATABASE_SaveSetEntryInt ( const char *Namespace, const char *EntryName, int EntryValue );
FString DATABASE_SaveGetEntry ( const char *Namespace, const char *EntryName );
void DATABASE_SaveIncrementEntryInt ( const char *Namespace, const char *EntryName, int Increment );


Quote from StrikerMan780

About threading... Hate always using it to compare with, but SourcePawn cannot use threading either. However, they get around that by using Callbacks.

Well, in theory you could probably define an ACS script as callback, but then you'll still need to somehow make Zandronum execute the query in a thread that will call the ACS script once the query is finished. This is completely incompatible with our ACS database API though.
(0009564)
AlexMax   
2014-06-17 22:52   
Coming back to some database concerns.

> So just let the documentation encourage to uses namespaces like "zanrun-time" and leave it at this?

Yeah.

> Not really, but there is nothing really comparable to the kind of handle you suggest either. Extending the global state idea to a kind of handle that is just an int to ACS shouldn't be that complicated though. The biggest issue is how to free handles. A mod would need to do this explicitly.

Yeah, that's the downside of having to manage handles yourself. On the other hand, with the global function if you want data to stick around you have to copy it out of the returned dataset by hand.

> Well, in theory you could probably define an ACS script as callback, but then you'll still need to somehow make Zandronum execute the query in a thread that will call the ACS script once the query is finished. This is completely incompatible with our ACS database API though.

Also, as soon as you start adding other databases to the mix, there's the possibility that the connection to them might be interrupted. What happens then...does the gamesim stop the world while your database query tries to execute?

Sigh, one of the big reasons I wanted to keep a simple API is because trying to get a real database API working means you have to solve all of these hard problems with a scripting language like ACS.

Does anybody have a list of things that coders want out of the database API that they're not getting as it stands? Not function names, but actual functionality? I know that Hypnotoad wants to be able to retrieve a sorted list of data and to be able to pull individual rows out of that sorted list...is there anything else that I missed in the gigantic thread?
(0009565)
StrikerMan780   
2014-06-17 23:16   
(edited on: 2014-06-18 19:05)
Sourcemod made calls to a seperate DLL module (dbi.mysql.ext.dll, which handles everything MySQL.), which would tell the core to run the script.

With Zandronum on the other hand, Is there a way to get an external library like that to tell Zandro to execute an ACS Script? or is it not capable of that whatsoever?

(I keep bringing Sourcemod up because it's familiar to me, it's very similar to ACS, and I can explain things easier through example. It has a very good system for handling Databases, and think it would be ideal to follow similar concepts.)

> Also, as soon as you start adding other databases to the mix, there's the possibility that the connection to them might be interrupted. What happens then...does the gamesim stop the world while your database query tries to execute?

Probably return blank query results, and parameter used to determine whether or not it failed, allowing the modder to choose how to react to the situation. The game would keep going as it's trying to connect. That's the whole idea of using a callback instead of just waiting for the function to return.


The only other thing I can think of... is some form of MySQL proxy. Having all stuff done via SQLite, and then having some sort of external system that synchronizes the databases periodically, merging changes/differences.

(0009569)
Hypnotoad   
2014-06-18 09:27   
>is there anything else that I missed in the gigantic thread?

Well, I think someone mentioned a way to get the keyname from an entry value and namespace, which would save you from having to do some silly stuff.

GetDBEntryKeyfromString(str namespace, str entry), GetDBEntryKeyfromInt(str namespace, int entry) ?
(0009590)
AlexMax   
2014-06-19 06:51   
> Well, I think someone mentioned a way to get the keyname from an entry value and namespace, which would save you from having to do some silly stuff.

Keys are designed to be unique. Values are not. If you want a reverse mapping, just put the key/value pair in the database twice - once one way and once the other.

(0009591)
Hypnotoad   
2014-06-19 07:30   
That's what I'm doing currently it just seems a bit silly. Nevermind.
(0009595)
Torr Samaho   
2014-06-19 17:51   
Quote from Jroc
Player rankings will be one of the main uses of this database feature, there are already plans to add rankings for duel and ctf players.

Alright, I added the internal function DATABASE_GetEntryRank and will expose this via ACS.

Quote from StrikerMan780
With Zandronum on the other hand, Is there a way to get an external library like that to tell Zandro to execute an ACS Script? or is it not capable of that whatsoever?

The only way to communicate with Zandronum from the outside so far is via RCON.

Quote from StrikerMan780
Probably return blank query results, and parameter used to determine whether or not it failed, allowing the modder to choose how to react to the situation. The game would keep going as it's trying to connect. That's the whole idea of using a callback instead of just waiting for the function to return.

As I said, callbacks would require a complete redesign of the ACS database interface and would make the whole thing more complicated to use. Not to mention that ACS is not designed for this kind of approach.

Quote from StrikerMan780

The only other thing I can think of... is some form of MySQL proxy. Having all stuff done via SQLite, and then having some sort of external system that synchronizes the databases periodically, merging changes/differences.

I think that this is the most feasible approach. If one would accept that the "get" functions sometimes return outdated values, Zandronum could keep a local copy of the external database, use that to handle "get" and send all "set" and "increments" to the external database. The fact that "get" may return an outdated value is a pretty bad design though.

Quote from AlexMax
Keys are designed to be unique. Values are not. If you want a reverse mapping, just put the key/value pair in the database twice - once one way and once the other.

Which will also only work if the value is unique.

Anyway, since Zandronum will not assume the uniqueness of values, GetDBEntryKeyfromString/Int doesn't make sense (unless you want a list of all entries with that value).
(0009601)
Hypnotoad   
2014-06-20 11:48   
Quote
Alright, I added the internal function DATABASE_GetEntryRank and will expose this via ACS.


Thanks, so assuming the prepare sort functions or something similar will also be implemented(?) all we need now is accounts and then as far as I'm concerned we have all that's needed.
(0009602)
Hypnotoad   
2014-06-20 11:50   
(edited on: 2014-06-20 11:51)
Oh I forgot to mention I had another idea. While the devs are against exposing the time/date to acs, I think what you could safely do is save a timestamp every time an entry is written which is stored in a new column in the database, the column would be inaccessible via acs, but would exist in the database so that websites and other things can make use of it.

(0009627)
StrikerMan780   
2014-06-21 18:17   
(edited on: 2014-06-21 18:23)
"As I said, callbacks would require a complete redesign of the ACS database interface and would make the whole thing more complicated to use. Not to mention that ACS is not designed for this kind of approach."

No way to get ACS Functions to call things that don't reside in the ACS System in and of itself to break free of whatever limitations ACS may have? (Be it threading, or w/e.) Also, how would it be that much more complicated, if at all? I'm kind of modeling my approach after this:'https://wiki.alliedmods.net/SQL_%28SourceMod_Scripting%29 [^]'

"I think that this is the most feasible approach. If one would accept that the "get" functions sometimes return outdated values, Zandronum could keep a local copy of the external database, use that to handle "get" and send all "set" and "increments" to the external database. The fact that "get" may return an outdated value is a pretty bad design though."

Perhaps there's a way to get a timestamp / last modified time of sorts? There must be some way to determine if the values in the database are outdated.

(0009629)
Torr Samaho   
2014-06-21 19:08   
(edited on: 2014-06-21 19:09)
Quote from StrikerMan780
No way to get ACS Functions to call things that don't reside in the ACS System in and of itself to break free of whatever limitations ACS may have?

There are a lot of things you could hack into ACS, but that doesn't necessarily mean that it's a good idea in the long run.

Quote from StrikerMan780
Perhaps there's a way to get a timestamp / last modified time of sorts? There must be some way to determine if the values in the database are outdated.

I think it should be no problem to add a fourth column to the table with the time the entry was last changed. This would also resolve Jroc's request: 0001831:0009602

The timestamp may not be exposed via ACS though, otherwise we run into 0001501:0009497. Nevertheless, you could have another program monitor the database and do things based on the timestamp (like synchronizing the data with another db).

(0009648)
Torr Samaho   
2014-06-22 11:43   
I continued working on the database support. In addition to some changes in how Zandronum internally queries the SQLite database (increment is a single query now instead of a get / set query pair that is marked as exclusive transaction), Zandronum now maintains a fourth column in the database table that stores the unix epoch in seconds (including the fractional part) the last time the entry was changed. This column is inaccessible via ACS and meant to be used by external programs that access the SQLite database directly.

Furthermore, I finished a first version of the sorting related database ACS functions and added the following new functions:

    int QuerySortedDBEntries ( string Namespace, int N, int Offset, bool Ascending ),
    int GetDBResultSize ( int Handle ),
    void ClearDBResultHandle ( int Handle ),
    string GetDBResultEntryNameString ( int Handle, int ResultsIndex ),
    string GetDBResultEntryValueString ( int Handle, int ResultsIndex ),
    int GetDBEntryRank ( string Namespace, string EntryName, bool Ascending ),

Here is a binary that supports them. You'll need to put

    -115:QuerySortedDBEntries(4),
    -116:GetDBResultSize(1),
    -117:ClearDBResultHandle(1),
    -118:GetDBResultEntryNameString(2),
    -119:GetDBResultEntryValueString(2),
    -120:GetDBEntryRank(3),

into zspecial.acs to use them. This is all very experimental and needs to be tested thoroughly.
(0009649)
Hypnotoad   
2014-06-22 12:16   
This is great thanks! I'm just wondering though if you could help me with understanding how these new functions work.
The first function, what does the offset argument do exactly?
Where exactly do you get the handle from, is the handle created when you assign the first function to a variable?
Does "EntryName" in the 4th and 6th functions refer to the keyname?
Does the 5th function return a string from a sorted set of strings? How did you sort them if so?
(0009650)
Torr Samaho   
2014-06-22 12:30   
The int returned by QuerySortedDBEntries is the handle you need to access the results of the query. Here is an example that gets and prints the top 3 entries (with ascending order, i.e. lowest is best) of the namespace named "Random":

int handle = QuerySortedDBEntries ( "Random", 3, 0, 1 );
int numEntries = GetDBResultSize(handle);
Log (s:"Query returned entries: ", d:numEntries );
for ( int i = 0; i < numEntries; ++i )
{
    Log ( s:GetDBResultEntryNameString(handle, i), s:" ", s:GetDBResultEntryValueString(handle, i) );
}
ClearDBResultHandle ( handle );

The offset parameter allows you to start with a different entry than the top entry, i.e. with an offset QuerySortedDBEntries will not return entries 1,...N, but 1+offset,...,N+offset.
Yes, EntryName means keyname.

I hope the example also answers your question regarding the 5th function. If you have more questions, feel free to ask.
(0009651)
Hypnotoad   
2014-06-22 13:13   
Thanks, this basically answers all of my questions, but why isn't there a function to return an entry value as an int rather than a string? True I can just use GetDBResultEntryNameString in GetDBEntryInt, but I can do that with GetDBEntryString too, so how come there is a function specifically to get the string?
(0009652)
Dusk   
2014-06-22 13:16   
Looks like we could use an ACS constant for query sort order? That is, if I'm reading the QuerySortedDBEntries call correctly.
(0009653)
Torr Samaho   
2014-06-22 13:24   
(edited on: 2014-06-22 13:31)
Quote from Jroc
Thanks, this basically answers all of my questions, but why isn't there a function to return an entry value as an int rather than a string? True I can just use GetDBResultEntryNameString in GetDBEntryInt, but I can do that with GetDBEntryString too, so how come there is a function specifically to get the string?
I added the string version because the value is stored internally as string and thus the string version is more general. It would be no problem to add GetDBResultEntryNameInt though.

Quote from Dusk
Looks like we could use an ACS constant for query sort order? That is, if I'm reading the QuerySortedDBEntries call correctly.

Yes, we should add a constant for the search order. AlexMax proposed DB_ORDER_ASC/DB_ORDER_DESC in 0001831:0009134.

EDIT: I added

// Zandronum database additions ---------------------------------------------
#define DB_ORDER_DESC 0
#define DB_ORDER_ASC 1

to zdefs.acs.

(0009656)
Hypnotoad   
2014-06-22 14:01   
Just wondering, what exactly are the consequences if I fail to do ClearDBResultHandle.
(0009657)
Torr Samaho   
2014-06-22 14:05   
The results of the query will stick around in memory. I added code that is supposed to clear them when moving to the next map, but didn't test yet if it works.
(0009658)
Dusk   
2014-06-22 14:07   
(edited on: 2014-06-22 14:08)
Perhaps the query could be automatically cleared when the script terminates?

(0009659)
Torr Samaho   
2014-06-22 14:16   
The handle is in no way tied to the script that called the function creating the handle. Nobody stops you from storing the handle in a global var or from handing it to other scripts. AFAIK the general practice for handles is the same as for pointers: The one who created it is responsible for freeing it.
(0009660)
Hypnotoad   
2014-06-22 14:44   
(edited on: 2014-06-22 14:45)
I'm getting errors now when attempting to set new database values, previously it worked fine in the old binary:

Could not prepare statement. Error: table Zandronum has 3 columns but 4 values were supplied
Could not bind text. Error: table Zandronum has 3 columns but 4 values were supplied
Could not bind text. Error: table Zandronum has 3 columns but 4 values were supplied
Could not bind text. Error: table Zandronum has 3 columns but 4 values were supplied
Could not execute statement. Error: table Zandronum has 3 columns but 4 values were supplied
Could not prepare statement. Error: table Zandronum has 3 columns but 4 values were supplied
Could not bind text. Error: table Zandronum has 3 columns but 4 values were supplied
Could not bind text. Error: table Zandronum has 3 columns but 4 values were supplied
Could not bind text. Error: table Zandronum has 3 columns but 4 values were supplied
Could not execute statement. Error: table Zandronum has 3 columns but 4 values were supplied

Do I need to start with a brand new database? Can the old one be modified to add a 4th column?

(0009661)
Torr Samaho   
2014-06-22 14:52   
Did you create the table with the old binary? Then it lacks the timestamp column and thus only has three columns. You need to delete the database. Zandronum will then automatically create a new table with four columns.
(0009662)
Hypnotoad   
2014-06-22 14:55   
I've managed to add the fourth column to the existing database myself, it seems to work for now.
(0009663)
Torr Samaho   
2014-06-22 15:24   
BTW: The interface I created so far (0001831:0009648) is not necessarily final. If anybody has suggestions on how to improve it, I'm all ears.

One I idea I had about the handles: Instead of having QuerySortedDBEntries (or similar functions we may add in the future) create a new handle every time it is called, we could separate the allocation into a new function, e.g. NewDBResultHandle and supply the handle as argument to QuerySortedDBEntries. While this makes the code a little longer, it would make more clear that you are allocating something that has to be freed.
(0009664)
Hypnotoad   
2014-06-22 15:32   
(edited on: 2014-06-22 15:34)
Regarding GetDBEntryRank, how does it sort among entries that have exactly the same value? Suppose the 2nd lowest value is achieved twice by two entries, will it consider them "joint 2nd" for instance so return both of them as 2? If not, how does it decide which is 2nd and which is 3rd, is it based on the timestamp? Would it be possible to add a parameter which allows you to specify what to do in this situation, whether to rank by timestamp (or whatever is currently default), giving them the same lowest possible rank (e.g. both 2) or giving them both the highest possible rank (e.g. both 3)?

So the function could be changed to:

GetDBEntryRank ( string Namespace, string EntryName, bool Ascending, int ranktype)

And you could add constants for the last parameter corresponding to 3 options, e.g:

#define DB_RANK_TIES_BY_TIMESTAMP 0
#define DB_RANK_TIES_AS_LOWEST_POSSIBLE 1
#define DB_RANK_TIES_AS_HIGHEST_POSSIBLE 2

(0009665)
Torr Samaho   
2014-06-22 15:40   
GetDBEntryRank counts how many entries have a strictly lower (ascending case, strictly higher for descending) value and returns that number + 1. So, in your case, if multiple entries have the second lowest value, they are considered "join 2nd". In theory, we could add another parameter to configure how ties are handled, but here we are starting to get too specialized for my taste.
(0009667)
Hypnotoad   
2014-06-22 15:47   
So just to be clear, if you have 11 entries, one with value 10, and the remaining 10 with a value of 20, all of those remaining 10 entries will return a rank of 2 (assuming ascending)?
(0009668)
Torr Samaho   
2014-06-22 15:51   
At least that what's supposed to happen. Considering how little testing the ranking code received so far, I don't give any guarantees that it actually does happen ;).
(0009669)
Hypnotoad   
2014-06-22 16:11   
Well, that behavior suits my needs for now fortunately.

As for the interface, I personally think it's fine how it is now, but a function to get an int rather than string would probably be convenient.
(0009672)
AlexMax   
2014-06-22 17:22   
> The results of the query will stick around in memory. I added code that is supposed to clear them when moving to the next map, but didn't test yet if it works.

How does this work with global ACS scripts?
(0009673)
Torr Samaho   
2014-06-22 17:29   
Good question. Now that I think about it, if you store the handle in a global var it would become invalid. I'll change it so that the handles are only cleared when the global ACS vars are reset.
(0009674)
AlexMax   
2014-06-22 17:46   
I've gone over the new ACS functions and tried to normalize and simplify their names:

void SetDBEntry(string namespace, string key, int value);
int GetDBEntry(string namespace, string key);
void IncrementDBEntry(string namespace, string key);
void SetDBEntryString(string namespace, string key, string value);
string GetDBEntryString(string namespace, string key);

int SortDBEntries(string namespace, int limit, int offset, bool descending);
int CountDBResults(int handle);
void FreeDBResults(int handle);
int GetDBResultKey(int handle, int index);
int GetDBResultValue(int handle, int index);
string GetDBResultKeyString(int handle, int index);
string GetDBResultValueString(int handle, int index);

int SortedDBEntryPosition(string namespace, string key, bool descending);

A few notes:
- I have removed the "Int" from any integer-related functions, in order to be consistent with the CVar functions.
- Ascending sorting is the "default" i.e. if you use 0 instead of a named constant. This is in line with how SQL works.
(0009717)
Torr Samaho   
2014-06-23 19:13   
The int returned by SortedDBEntryPosition is not the same as the position in the results returned by SortDBEntries, so I'd rather keep a bigger difference in the name of the function. IMO "Rank" should be in the name.
(0009794)
Hypnotoad   
2014-06-29 20:17   
Could there be a flag that can enable or disable the database features, and can it be off by default? I think a malicious wad could fill up a database with thousands of entries of gibberish every tic as soon as you run it which would be harmful. Something like sv_enabledatabase.
(0009798)
ZzZombo   
2014-06-30 01:24   
sv_db_maxsize <0 for unlimited storage | positive integer otherwise>
(0009801)
Torr Samaho   
2014-06-30 06:06   
Quote from Jroc

Could there be a flag that can enable or disable the database features, and can it be off by default?
To prevent this the DB already defaults to volatile in-memory storage. Isn't this enough? Sure, a mod could clog the RAM, but there are already many ways for a mod to make the game unplayable.

(0009803)
Hypnotoad   
2014-06-30 14:01   
It seems like it archives the value whenever you set it. If I host a server and specify a database file on that, then if I run a wad in singleplayer afterwards that will still be the database file.
(0009804)
Torr Samaho   
2014-06-30 17:35   
Yes, the CVAR databasefile is archived intentionally.
(0009822)
Hypnotoad   
2014-07-02 18:29   
Okay, just seems a bit dangerous if a user forgets to change it back after hosting a server.

Anyway, since it seems as if the accounts system will take longer than thought, is it possible the public beta of 1.3/new 2.0 can be updated without it for now? I can just keep using player names for the time being.
(0009823)
Catastrophe   
2014-07-02 18:39   
No, please release 1.3 with the account system. I am willing to wait.
(0009824)
Torr Samaho   
2014-07-02 20:07   
AlexMax and I got the planned changes on the account protocol done on Sunday evening. I'm just polishing a few things and plan to release the 1.3 beta soon (probably tomorrow).
(0009933)
Hypnotoad   
2014-07-11 13:19   
It doesn't look like any server is using the current 1.3 beta at the moment. I don't know about other modders, but if a version of 1.3 beta with sorting function is released I'll be able to get a Zanrun (and possibly another mod I'm working on) server up and running so that the new account/db features can get a more thorough testing.
(0009944)
Torr Samaho   
2014-07-12 14:33   
Made a bunch of changes and ported them to 1.3:
- Added new CVAR database_maxpagecount (defaults to 32768) that controls the maximal allowed size in pages of the database.
- Added new ACS functions SortDBEntries, CountDBResults, FreeDBResults, GetDBResultKeyString, GetDBResultValueString, GetDBResultValue and GetDBEntryRank.

This covers the renaming and the bool changes AlexMax suggested, except that I kept the name GetDBEntryRank (see 0001831:0009717) and didn't add GetDBResultKey. The key is supposed to be a string (all functions only allow a string argument for the key), so I don't think that it would make sense to return the key as int.

(0009950)
Hypnotoad   
2014-07-12 16:33   
Awesome, what do I need to add to my zspecial.acs? Are the numbers the same as last time?
(0009951)
Torr Samaho   
2014-07-12 16:57   
zspecials.acs

    -115:SortDBEntries(4),
    -116:CountDBResults(1),
    -117:FreeDBResults(1),
    -118:GetDBResultKeyString(2),
    -119:GetDBResultValueString(2),
    -120:GetDBResultValue(2),
    -121:GetDBEntryRank(3),

zdefs.acs

#define DB_ORDER_ASC 0
#define DB_ORDER_DESC 1
(0009955)
Hypnotoad   
2014-07-12 20:10   
(edited on: 2014-07-12 22:15)
Thanks, everything seems to work fine.

edit: will a new public beta be released with this stuff?

(0010074)
Hypnotoad   
2014-07-29 08:31   
(edited on: 2014-07-29 08:51)
So it appears too much database activity can cause major cpu load, causing the server to hang and player's ping to skyrocket temporarily. This is currently very difficult to reproduce, as this seems to only happen sometimes. I'm looking for ways to optimize the script at the moment, I'm pretty sure this is the script which causes the occasional cpu load:'http://pastebin.com/syicm01N [^]' , however not that much is being written to the database, one entry per player in the database so in the test we jut did there was only 3 people in the database so it only wrote 3 times. The loop is mostsly just checking the DB entries, and I don't see why that should cause so much cpu load.

edit: this loop is another candidate'http://pastebin.com/2b5MEgmq [^]' but I'm pretty sure from the testing I've done that it's not this.

(0010091)
Torr Samaho   
2014-07-29 21:05   
For instance, calling GetDBEntryString ("MapNames", mapid ) thrice instead of only once and saving the result in script 463 certainly doesn't improve performance ;).

What exactly is script 463 supposed to do? Since I have no idea what you are saving, I don't know what kind of logic you are following. I just noticed that you have playerid, playerid2 and playerid3 and all seem to be exactly the same.
(0010092)
Hypnotoad   
2014-07-29 21:24   
(edited on: 2014-07-29 21:27)
Playerid, playerid2 and playerid3 are the same because they occur at different times, and strparam (really really annoyingly) only lasts for one tic. There is a specific reason that they had to be 3 unique variables for it to work properly, rather than constantly reassigning the same variable, but I can't recall now, but some kind of ACS limitation or bug forced me to I believe, it shouldn't really affect performance regardless though.

This is what the script does, it accumulates all the points for a player. Every time someone gets a personal best time, they may improve their rank on that map, you are awarded points depending on your rank for that map; if your rank goes up you earn more points, if someone else overtakes you causing your rank to go down you then lose points. The latter script in the edit checks whether each player in the database has changed in rank for that map, then changes their point score for that map, it then executes 463 which tally's up all the points for each player by adding all of their points from each map to provide a total points score by which players are globally ranked.

I've managed to completely bypass this script for now, what happens instead now is that when a player's point score for one map is changed, their previous score is taken away from their totalpoints and then the new score is added, rather than having to tally up all the points each time. I think this has improved performance somewhat but it's hard to tell due to the rarity of performance drops, I have noticed the occasional ping spike still which I cannot rule out as coincidental but has happened occasionally enough (this may change when lots of people play at the same time) that it's hard to know for sure exactly what causes it.

Perhaps some guidance on how many times Zandro can query the database in one tic before performance is affected would be helpful.

(0010098)
Torr Samaho   
2014-07-30 21:21   
Quote from Jroc

Perhaps some guidance on how many times Zandro can query the database in one tic before performance is affected would be helpful.
AFAIK nobody has ever used Zandronum's database backend for anything performance critical, so there is no experience with this yet.

What I see from your script though is a limitation of the current database interface that makes you spam the database with unnecessary calls. For instance, the outer loop is supposed to iterate over all entries in the namespace "PlayerNames", isn't it? Ignoring the inner loop completely, the outer loop leads to 2*MAXIDS database queries (with my comment above you can cut this down to MAXIDS queries) no matter how many entries are in the namespace. It would be much better to add a database function that just iterates over all entries in a namespace directly (like the function that iterates over the top N entries).
(0010099)
Hypnotoad   
2014-07-30 23:11   
FYI it doesn't iterate over all of MAXIDS, only over the amount of playerids in the PlayerNames namespace, and will break out of the loop as soon as it encounters no player name recorded for the id. Since there were about 3 or 4 players in the database at the time of that initial test, this would have been 8 queries in the outer loop.

But yes, being able to iterate over all entries in a namespace would be handy.
(0010223)
Hypnotoad   
2014-08-23 20:18   
(edited on: 2014-08-23 20:19)
Sorry for yet another feature request but I thought it'd be worth a shot:

I was looking into using the database to make wads that record players wins and losses, particularly in gamemodes like duel, but also in ctf, and then use these stats to create rankings/league tables. But I've ran into a snag, in order to properly rank players in a gamemode that doesn't have a fixed amount of matches/players you generally need some kind of special algorithm to award or reduce a player's points. Most notable is the Elo ranking, which is used in chess, as well as other sports and some video games. Ranking players by the number of wins, or the ratio of wins to losses for instance, is simply not suitable as it doesn't take into account the quality of players' opponents, or the differences in quantity of games played. Therefore it seems that it is impossible to properly rank players without using an algorithm like this.

The problem is, algorithms like Elo are a bit complex mathematically, enough to basically be impossible or extremely difficult to implement in acs. So far the only way one would be able to do a proper ranking would be to make some external application to perform calculations on the database.

What would be extremely great is if a new function could be created for Zandronum, you supply it with three numbers and a bool (the rating of the player, the rating of his opponent, the K-factor, and whether the player won or lost), and it then internally calculates how many points to award or take away from the player using the elo algorithm (or something similar), which should be much more straightforward to implement using a proper programing language, and returns that number. This would be really great for Zandronum as it would enable people to easily add player rankings to their mod if it involves competitive PvP play.

(0010224)
AlexMax   
2014-08-23 21:52   
IMHO if the math to do a particular ranking system is too complicated to implement in ACS, then it's probably a better idea to leave the idea of a ranking system alone and try an alternative, or simply rank them by number of wins or something simple.
(0010225)
Hypnotoad   
2014-08-23 22:35   
(edited on: 2014-08-23 23:02)
It is hard in acs because acs does not have floating point, but I believe it would not be difficult to hardcode into Zandronum. Ranking simply by number of wins does not mean much, it gives an advantage to people who have played longer, and it does not take into account the quality of the opposition. I could just play a clone of myself, or a friend, hundreds of times and lead the ranking in number of wins without having to face difficult opposition, it wouldn't be a true ranking.

edit: to be clear, it's not difficult or complicated in the sense that it requires a lot of number crunching or to sift through lots of data, it's only "difficult" because doing something like A' = A + K*(S - ( 1/(1 + 10^((x-y)/400)))) (this is the elo formula itself) is really hard with fixed point only.

(0010226)
Torr Samaho   
2014-08-24 16:32   
I agree that it would be good if mods could do Elo like ranking. Is it already possible to do the necessary calculations in ACS with the latest ZDoom version? If so, we can talk about backporting the necessary ACS additions.
(0010227)
Hypnotoad   
2014-08-24 16:53   
It wouldn't be any easier to do the calculations in acs using the latest zdoom, as far as i know, I didn't see any new mathematical functions on the wiki that would be of use.
(0010228)
Torr Samaho   
2014-08-24 18:48   
In that case, I wouldn't mind adding one such function. We have to make sure though that we chose a rating system the majority of the players accepts.
(0010229)
Hypnotoad   
2014-08-24 18:57   
(edited on: 2014-08-24 19:09)
I think the standard Elo is probably the simplest/easiest to implement, but apparently there are better systems, like Microsoft's TrueSkill:'http://research.microsoft.com/en-us/projects/trueskill/details.aspx [^]'

edit: nevermind trueskill, it's closed source

edit2: on the other hand many people have implemented their own verion:'https://github.com/search?utf8=%E2%9C%93&q=trueskill [^]'

(0010231)
Hypnotoad   
2014-08-24 20:03   
(edited on: 2014-08-24 20:56)
I just noticed Quake Live Ranks uses ELO'http://www.qlranks.com/ [^]' and this seems to be a popular resource, so since Elo is well accepted by the quake community I don't see why it wouldn't be accepted by the Zandro community.

(0010234)
Blzut3   
2014-08-25 07:00   
Jroc:'http://pastebin.com/SdzVXgrF [^]'

Give that a try. The MAXELO constant isn't quite right due to potential signed integer overflow I think. But the general idea there is sacrificing a little bit of range gives a few more bits of precision allowing it to be done entirely in ACS. From what I understand elo typically ranges between 0-3000.
(0010235)
Hypnotoad   
2014-08-25 12:16   
Wow, thanks a lot for this, this is really great! So far it seems to be working fairly well, the only problem is it seems to always round down the result, but then this may not be a bad thing if you want to keep Elo changes slightly conservative? Do you know if there is an optimal K-value and/or starting values that this library will work best with?
(0010237)
Hypnotoad   
2014-08-25 17:34   
Actually this rounding is more serious than I thought, it seems that you will often (practically always) lose more points than you will gain. If I gain 2, the other person will usually lose 3 for instance.
(0010238)
Blzut3   
2014-08-25 19:06   
I believe you can fix that with: return ra + ((k*((w<<16) - e) + 0.5)>>16);

If negative values need special handling, remember you can ultimately replace that right shift 16 with a rounding function of your choice. At the typical k values, I do not believe any possible loss of fractional precision for e makes any practical difference so it's just a matter of how you decide to do the conversion to a normal integer (in the code I pastebin'd it's simple truncation).

I believe the safe input range for r is [0-3130] assuming my thoughts about an overflow going to 3251 is correct. For k it should work up to 32767, but that would be useless.
(0010245)
Torr Samaho   
2014-08-31 20:05   
For the record, I added the new ACS functions BeginDBTransaction, EndDBTransaction and GetDBEntries.

(0010347)
Dusk   
2014-10-05 22:22   
Marking as resolved as 1.3 is now released.