Quite a few things to talk about. I’ve been coding quite diligently on the Soldat Client and Server this month, and have greatly improved the ScriptCore, enough to label it as ScriptCore v3. But I am certainly not done yet, still have to recode the threading and test things. I will go into detail further down in this post, click Read More.
EnEsCe needs YOU! As most of you know, Soldat 1.5 is plagued with problems for certain systems which had no problem with Soldat 1.4.2… Due to the nature of these issues, I am unable to test fixes myself; so I need some people to help me test 1.5.1 binaries. If you meet ALL of the following requirements, please contact me ASAP via email and I will give you my IM addresses. I use almost every form of IM client.
* You get Access Violations when starting or exiting Soldat 1.5
* You get a blank screen when starting/joining a game in Soldat 1.5
* You do NOT get the above problems in 1.4.2, only in Soldat 1.5!
* You have any other bug preventing you from playing Soldat 1.5, but you dont get this bug in 1.4.2
* You must be online frequently during daylight times. No school kiddies, sorry.
* Speak and Type very good English. Ppl hu typ liek dis shld di in righteous fire.
The sooner people come forward to help, the sooner Soldat 1.5.1 can be released.
* ScriptCore v3 Progress
MySQL: If you have been following me on Twitter for awhile, you may have seen me mention I was fiddling with MySQL functions. Well, after a week or so of thorough testing, I can safely say that MySQL support is now possible in the ScriptCore. All types of queries are functioning correctly, SELECT, INSERT, DELETE, UPDATE etc. And before you security freaks ask, yes mysql_escape_string is an added function :P. I have modeled the function names and syntax to closely resemble PHP’s MySQL functions; but not exactly the same. These functions will require safe mode disabled.
Here are some examples of whats possible, code is from a login system I wrote for the purpose of testing these functions.
procedure Login(ID: Byte; Username,Password: string);
var
QueryStr: string;
_qry: integer;
begin
Player[ID].Threads.Login := true;
try
Password := MD5String(Password); // Password MD5
QueryStr := 'SELECT * FROM users WHERE `username`='''+mysql_escape_string(Username)+''' AND `password`='''+Password+''';';
DebugMsg('SQL: '+QueryStr);
_qry := mysql_query(_sql,QueryStr);
if mysql_numrows(_qry) > 0 then begin
if mysql_fetch_valuebyname(_qry,'loggedin') = '1' then begin
// Account is already logged in! GTFO please >:\
WriteConsole(ID,'Login failed. That account is already logged in by "'+mysql_fetch_valuebyname(_qry,'lastname')+'"',clRed);
mysql_free_result(_sql); // Free the result since it has been assigned, but wont be used again.
Player[ID].Threads.Login := false;
exit;
end;
// Load SQL data into TPlayerInfo type
Player[ID].Login.ID := strtoint(mysql_fetch_valuebyname(_qry,'id'));
Player[ID].Login.Username := mysql_fetch_valuebyname(_qry,'username');
Player[ID].Login.SQLRowID := _qry;
// Update the last used time(Unix time), IP, and ingame name of the account. And set the status to logged in
QueryStr := 'UPDATE users SET `lastlogin`='''+inttostr(time())+''', `lastip`='''+GetPlayerStat(ID,'ip')+''', `lastname`='''+mysql_escape_string(GetPlayerStat(ID,'name'))+''', `loggedin`=''1'' WHERE `id`='''+inttostr(Player[ID].Login.ID)+''';'
mysql_free_result(mysql_query(_sql,QueryStr));
WriteConsole(ID,'Login success! Welcome '+Player[ID].Login.Username+'!',clGreen);
Player[ID].Threads.Login := false;
end else begin
mysql_free_result(_sql); // No account found, free the result to save memory.
Player[ID].Login.ID := 0;
WriteConsole(ID,'Login failed. Incorrect username or password',clRed);
Player[ID].Threads.Login := false;
end;
finally
Player[ID].Threads.Login := false;
end;
end;
Pretty simple, eh? Maybe not… heh. So, as you can see, mysql_query() will return an integer; which will be the Result ID for use when fetching values from any selected rows. And most importantly, you must always call mysql_free_result() when you no longer need to access the result of a certain query! Every query remains in memory until you call that function. Which can lead to high memory usage, and eventually access violations and crashes.
Here’s sample code for connecting:
procedure ActivateServer();
var QueryStr: string;i: integer;
begin
//** Connect to the MySQL server on localhost **//
_sql := mysql_connect('localhost','root','password','ec_stats',3); // 3 second connect timeout
if mysql_connected(_sql) = false then begin
WriteLn(' [*] MySQL connection failed.');
WriteLn(' '+mysql_error(_sql)); end
else begin
WriteLn(' [*] MySQL connection established. IndexID: '+inttostr(_sql));
// We must set all accounts to logged out, so
QueryStr := 'UPDATE users SET `loggedin`=''0'' WHERE `loggedin`=''1'';'
mysql_free_result(mysql_query(_sql,QueryStr));
for i := 1 to 32 do Logout(i); // Logout all users and tell them, incase script was just recompiled
end;
end;
procedure AppOnIdle(Ticks: integer);
var i: byte;
begin
//** Every 10 seconds, check if MySQL is connected. If not, reconnect! **//
if Ticks mod (60 * 10) = 0 then
if mysql_connected(_sql) = false then begin
WriteLn(' [*] MySQL disconnected. Attempting to reconnect...');
mysql_reconnect(_sql);
end;
end;
Again, pretty simple. In my testing, I was using the “persistent connection” approach, which means A) Constantly connected to MySQL B) alot of threading… Which also ofcourse means alot of crashes. Bummer, eh? Most of the time queries completed in ~0.03 seconds, so there was no humanly noticeable lag or freezes caused by it. But that may change if selecting from a poorly designed database without indexes or a very large database.
If you have any questions, comments, or suggestions regarding the MySQL implementation so far, please leave a comment. I am eager for feedback!
New Events: There will be some new events available, including:
OnGameEnd() -- Called before OnMapChange, so player scores and current map etc have not been reset yet.
OnFlagDrop(Thrown: boolean) -- Called when a flag is dropped. I am not 100% sure yet if throwing will be included, as that can be abused by players in a very bad way. I won’t go into details publicly :)
OnSurvivalRoundEnd() -- As the name suggests, event will be called when a survival round ends.
OnSurvivalRoundStart() -- Come on, you can’t possibly need a description for this one aswell…
Thats all so far. I know alot of other events have been requested, but most of them won’t be added because calling any event too frequently will cause a crash. This is specifically why AppOnIdle remains at 1 second call frequency; and why I will not add OnFire.
SetPlayerStat: Well, it wont be as fancy as most people want. But the function will exists nevertheless. I have only created the base for the function so far, but will add some fancy things and publicise them eventually.
GetWeaponStat: Hohoho. I don’t think I will be able to explain the awesomeness of this function with words, so I will just paste a code sample from my login system again.
QueryStr := 'UPDATE wepstats SET `shots`=`shots`+'+inttostr(GetWeaponStat(ID,b,'shots'))+', `hits`=`hits`+'+inttostr(GetWeaponStat(ID,b,'hits'))+', `kills`=`kills`+'+inttostr(GetWeaponStat(ID,b,'kills'))+', `headshots`=`headshots`+'+inttostr(GetWeaponStat(ID,b,'headshots'))+' WHERE `id`='+inttostr(Player[ID].Login.ID)+' AND `wepID`='+inttostr(GetWeaponStat(ID,b,'num'))+' LIMIT 1;';
Drooling yet? The possibilities for stats scripts is absolutely amazing with these functions… Accuracy, anyone? Also, aimbotters beware… I hope I wont have to exclude these functions from release; but at the moment the weapon stats collection code is sometimes causing access violations after running for many hours in the latest dedicated server software (2.6.5).
Thats all I will say for the moment, there are still alot more features I want to add but have not yet planned out a way to implement them.
* Soldat 1.5.1 Release Date
… Will not be announced yet! Muahaha. Sorry, anywho, I’d just like to announce that there will not be any public beta for Soldat 1.5.1. The change log will also not be released until 1.5.1 is finished. Do not bother asking me on IRC for a release date or changes, no exceptions.
* Non-Soldat related junk
I enjoy sharing things that make me laugh/amazed/wtf, so here you go ^-^
Lag in Real Life: *cough* Soldat *cough*
Damien Walters Parkour
… Look at the Quote on the right, then look at the image on the left.

Please leave a comment on this article if you enjoyed reading it or have a suggestion. I’d like to know how my posts are being perceived by other people :)
auf Wiedersehen!


Probably more logical syntax would be OnRoundEnd() and OnRoundStart() instead of OnGameEnd/OnMapChange but I guess backward compatibility is more important than logically designed syntax.
A ’round’ in Soldat is not when a map changes, it is when a round of Survival ends… So using those event names would only confuse people.
The weapon stat function is a welcomed feature no doubt. I’d like to add that an Accuracy script is quite possible already under the current ScriptCore, I’ve been able to achieve this for one. However it’s not 100% accurate(pun non-intentional).
MySQL support seems intriguing. My biggest problem with it is that you’re adding a massive feature while the rest of the core could still use work. I for one, much rather see the existing scripting framework get fortified and improved before moving on to such a big step. I foresee that this new ‘feature’ will mostly introduce much more new bugs(due to lack of testing/coding or w/e) and draw attention from parts of the core that would provide instant benefits. The AppOnIdle event comes to mind right of the bat. The fact that calling this event at the speed(s) exceeding 1Hz crashes the system is just silly(at this stage of the script cores progress at least). I won’t mention multi-threading because I do realise that this is a non-trivial issue and a REALLY complicated ‘feature’. Which also makes me wonder why its even in a game scripts engine(which one would expect to be much simpler).
At this point in Soldat development I for one have a problem with what is now and for a while has been considered improvement to the game(and/or scriptcore) and that is a wave of new features that is expected and almost ‘demanded’ from the developer(s). I’d rather much see a much more concrete and well thought out version of the game that is currently out there. Instead of the same buggy game with a few new ‘features’ glued on top of it.
I call upon you Nick Cooper to snap out of your funk and step back for a second and take a long,hard look where this project is headed. Because it does not look good. Maybe its time to stop trying to please everyone with useless features that will only benefit a small amount of people and concentrate on writing code that YOU could actually be proud of.
Hahah i really like the GetWeaponStat function.
Thanks for your effort to making those =) Keep it up.
HELL YES – That’s wicked!
Well done EnEsCe. Keep it up :P
Hope to see some more fancy vids like the “Lag in Real Life” in the future :D
Thank ya!
Nice GetWeaponStat.
You forgot the eating in soldat on the vid ;D
Also, it isnt “Aufiderzein!” but “Aufwiedersehen!” :P
Heh, damn. Google corrected my spelling to Aufiderzein, so I blame Google :)
I wet myself out of excitement when I saw GetWeaponStat.
This is amazing, thank you.