Author Topic: Game code structure  (Read 1858 times)

Offline Nox

  • Level 35
  • **
  • Posts: 738
  • Reputation: +12/-2
    • View Profile
Game code structure
« on: December 16, 2009, 05:45:48 AM »
Hi I'm not sure the title is appropriate (tips welcomed), but...

I recently reworked my game to OOP (I'm still not that far so it wasn't painful)
but I'm unsure about the whole structure and I'm afraid it would be kinda lame,
so I'd like to ask about it. I looked through pavansss91's bbg framework
but I'm having a hard time understanding it.


For example I have an object for communicating with DB, but then... I don't know if it's alright to use it as static class (like Mysql::query("...") ) so it's accessible everywhere or if to use it as a normal object but then I'd either have to insert "global $db_object, $error_object, $application_object..." everywhere or make it an argument, but I don't really like having e.g.
Code: [Select]
public function login($id, $application_object, $error_object, $db_object...)or as an object which is part of some static class like Application::$http->...

On one hand I know it's bad to use global variables/objects on the other hand there's a number of objects that controll the application or are tool to do something,
and if I need to access DB or get some important variable from basic application object I don't know what's the best way to do it...

Then I have a problem that: I have a class to handle presentation layer, includes appropriate files... but because they're included this way I can't access variables from there. I might do it the template way but it's something I really dislike...making a huge list of commands like
Code: [Select]
$smarty->assign("variable1", $variable1);
$smarty->assign("variable2", $variable2);
$smarty->assign("variable3", $variable3);
...
just duplicate ton's of variables, even those I might not use in the end (due to conditions)

I have a temporary work-around
Code: [Select]
foreach($GLOBALS as $varname => $variable)
  global $$varname;
but I know it's very ugly...

One more question :) I'm not sure how to appropriately work with exceptions, I've been searching articles but found none so far explaining it stupidly enought for me to understand :)
Is it necessary to have try-catch structure around everything that might throw exception? That sounds kinda weird to me...

Thanks a lot

If anyone would look into the project (it's not big at all so far), I'd appreciate it a lot, just send me PM... just if you ever get bored and don't know what else to do :)

I'll just attach index as example...
one thing I'm thinking about is move distinction between script and normal page from View to this index, so you don't have to mention it
« Last Edit: December 16, 2009, 06:12:32 AM by Nox »
Meet us at an IRC irc.freenode.net #bbg as well
Enjoy http://spiritbeacon.noxart.cz/ !

Offline Chris

  • Game Owner
  • Level 35
  • *
  • Posts: 2,134
  • Reputation: +26/-1
    • View Profile
Re: Game code structure
« Reply #1 on: December 16, 2009, 06:30:41 AM »
This was discussed several times, so I will only note it for preserving tradition sake (not trying to start the old argument at all) that OOP is an overkill for something as simple as BBG in my opinion.

To learn exceptions and other OOP stuff I suggest books for C++, these are the best.

Quote
function __autoload($function){
   if( file_exists(R."/objects/$function.php") ) require_once R."/objects/$function.php";
   else die( "Autoload: Missing class file" );
}
This one causes 2 file checks (if exist, then attempt to load it), not very efficient performance wise. I would use this one instead:
Quote
function __autoload($function){
   @require_once R."/objects/$function.php";
   if(!$file_loaded) die( "Autoload: Missing class file" );
}
And put $file_loaded=1; at the beginning of each file.

Offline Nox

  • Level 35
  • **
  • Posts: 738
  • Reputation: +12/-2
    • View Profile
Re: Game code structure
« Reply #2 on: December 16, 2009, 08:11:24 AM »
Thank you ... I might even have one at home, will take a look

Well... I heard that @ is not that efficient either and I guess the second file check would be faster ...?

But it's not a bad idea...just instead of your $file_loaded construction I'd use class_exists(), no extra work and it looks cleaner to me
or
Code: [Select]
$file_loaded = @require_once "...";if(!$file_loaded)...might work since
$bar is the value 1 because the include was successful. Notice the difference between the above examples. (...) . If the file can't be included, FALSE is returned and E_WARNING is issued.
Meet us at an IRC irc.freenode.net #bbg as well
Enjoy http://spiritbeacon.noxart.cz/ !

Offline lolninja

  • Level 19
  • *
  • Posts: 194
  • Reputation: +5/-0
  • BSc powered Programmer
    • View Profile
    • HTTPmmo
Re: Game code structure
« Reply #3 on: December 16, 2009, 09:46:12 AM »
Exception handling is one of those things that really only clicks once your pretty comfortable with OOP, you know how in functional programming you tend to return false if something fails in one of your functions, but the calling function doesn't really know what broke, it just knows that it did.

For example say you have a function that takes gold from a users account, and adds peons like say...
Code: [Select]
/**
 * Used to buy peons.
 * @param int $peons Contains the number of peons that the user wants.
 */
function buyPeons($peons){
    $cost = (50 * $peons);

    // Check to see if we have enough gold
    if ($cost > $_SESSION['gold'])
        return false;

    // Check to see if were below our maximum peon count
    if (($_SESSION['peons']+$peons) > 100)
        return false;

    $_SESSION['gold'] -= $cost;
    $_SESSION['peons'] += $peons;
    return true;
}
If you call that  function and it returns false you don't know if it was rejected because your low on gold or you already have to many peons.

Throwing exceptions is a way of handling a given situation with specific code which solves a given issue, or returning additional information. So taking the above example we could make...
Code: [Select]
/**
 * Used to buy peons.
 * @param int $peons Contains the number of peons that the user wants.
 */
function buyPeons($peons){
    $cost = (50 * $peons);

    // Check to see if we have enough gold
    if ($cost > $_SESSION['gold'])
        throw new Exception('Your to poor');

    // Check to see if were below our maximum peon count
    if (($_SESSION['peons']+$peons) > 100)
        throw new Exception('You already have to many peons');

    $_SESSION['gold'] -= $cost;
    $_SESSION['peons'] += $peons;
    return true;
}

//usage
try {
    buyPeons(150);
} catch(Exception $e) {
    echo 'It looks like you cannot buy any more peons, because "'+$e.getMessage()+'".';
}
The above code will of course fail, and echo 'It looks like you cannot buy any more peons, because "You already have to many peons".' because we tried buying 150, and the limit is only 100.

But Exception handling can do soooo much more say you have multiple systems, one which handles your money, and one that handles your database, you may process a valid transaction, only to have your database fall over, or your process maybe invalid, exception handleing covers this...
Code: [Select]
try {
    MoneyObject::spend(150);

} catch (Database_Exception $e){
    // We want to send our admin a message telling them something is wrong with the database.
    mail(...);

    // Other work that needs to happen to make sure the database falling over doesn't effect the user to much...

} catch (Money_Exception $e){
    echo 'It looks like you maybe far to poor to spend the amount you wanted';

} catch (Exception $e){
    echo 'Something random went wrong, sorry about that...';
}

Within the catch statements you can do pretty much anything you want, and the cool thing is if you implement everything correctly your system should theoretically never fall over and break databases etc. Though as with everything in life practice makes perfect.


I noticed you were playing with autoloaders, its worth reading into http://php.net/manual/en/function.spl-autoload.php it basically allows you to register a function that gets called every time you try and instantiate a new object that hasn't been included yet, which is super handy if you want to lazy load all your game code, meaning you don't have to keep a track of which components are being used when your working, the down side is that your code is a wee bit slower, but tbh its a very time amount of slow down, and the saving in development time is more important than a few ms.

Offline Nox

  • Level 35
  • **
  • Posts: 738
  • Reputation: +12/-2
    • View Profile
Re: Game code structure
« Reply #4 on: December 16, 2009, 10:28:01 AM »
Thank you! That's easily understandable
I can include one try-catch into another so I'd wrap the index into one to catch exceptions from the core initializations? Don't worry, I'll find out myself
Meet us at an IRC irc.freenode.net #bbg as well
Enjoy http://spiritbeacon.noxart.cz/ !

Offline Chris

  • Game Owner
  • Level 35
  • *
  • Posts: 2,134
  • Reputation: +26/-1
    • View Profile
Re: Game code structure
« Reply #5 on: December 16, 2009, 10:44:27 AM »
Thank you ... I might even have one at home, will take a look
PHP books in general sux, these are written either for complete noobs (pages explanations of IF statements) or for those with full understanding of C/C++. And since PHP is mostly directly derived from C/C++, you can usually use the proper and polished academic C books instead :)

Quote
Well... I heard that @ is not that efficient either and I guess the second file check would be faster ...?
I'm not aware of this, if anyone knows details please let us know.

But I think it is for error case only. If you have error then @ might be slower than normal file check since it cast a PHP error which is logged by apache. But, the trick is, you don't care about error case, since it is development check not run check. If the file is not present the game is broken and can not be played anyway and the performance does not matter :D

Offline lolninja

  • Level 19
  • *
  • Posts: 194
  • Reputation: +5/-0
  • BSc powered Programmer
    • View Profile
    • HTTPmmo
Re: Game code structure
« Reply #6 on: December 16, 2009, 11:22:53 AM »
@ is used for error suppression, so it shouldn't have any performance hits, other than having to write text out to the log files.

It is worth doing "if (!file_exists($path))" before you do the include_once/require_once, so you can handle any errors you encounter, rather than basically putting your fingers in your eats and humming :P

Also if you have already included a file php keeps a track that its been included, so calling include_once/require_once with any type of pre-inclusion validation before is a waste, as it will happen anyways.

Offline JGadrow

  • Level 35
  • **
  • Posts: 1,133
  • Reputation: +23/-2
    • View Profile
Re: Game code structure
« Reply #7 on: December 16, 2009, 01:54:55 PM »
Ok, I don't have much to add here but...

You do not want to make your database object static. Doing so prevents you from properly scaling your application in the future. Sure, it may never happen, but it's not wise to build yourself into a corner simply because you didn't expect to need to scale. Additionally, you'd be doing more work to make it a Singleton object than you would just to make it a standard object, so not only is it a better idea, it'll save you a little time. ;)

Personally, I never use the ignore error operator. I like my functions reporting errors. Tracking and fixing errors is the way that we determine that our programs are doing something that we did not intend for it to do! Especially in your autoload() function! If it's trying to include something that you've never written then you probably have a code exploit that somebody is toying with to determine how they can use it to execute arbitrary code!

There are many ways to make autoload() functions. A very simple one is displayed above. I will be writing a base framework that is meant to be extended so my autoload() function will be quite a bit more complex.

As far as books go... I always give the same advice: Pick one that speaks to you, individually! I could read a book that's written in a very clean, technical style but perhaps someone else learns better from something written conversationally or with detailed examples. It's all relative to the way that you learn best.
Idiocy - Never underestimate the power of stupid people in large groups.


Offline Nox

  • Level 35
  • **
  • Posts: 738
  • Reputation: +12/-2
    • View Profile
Re: Game code structure
« Reply #8 on: December 16, 2009, 02:56:10 PM »
Thank you!
Yes, it's right, especially in case of DB it's a dumb idea... I just read in one blog that due to need of testing it would be handy not to have objects as singletons...and that we can't be sure if we will never need more than 1 (he states HttpRequest as example, something one wouldn't think he'd need more than one...but he uses it to solved a data preservation in case of authentication expiry or something) ... so I guess we'll leavy singletons in peace...

can I ask how would you then access the DB object or tell which one to use say in case of a method in some logging function (or whatever you find a good example)?

I'm looking right now at Dependency injection http://www.potstuck.com/2009/01/08/php-dependency-injection/ and it seems promising...
« Last Edit: December 17, 2009, 04:42:45 AM by Nox »
Meet us at an IRC irc.freenode.net #bbg as well
Enjoy http://spiritbeacon.noxart.cz/ !

Offline JGadrow

  • Level 35
  • **
  • Posts: 1,133
  • Reputation: +23/-2
    • View Profile
Re: Game code structure
« Reply #9 on: December 17, 2009, 11:16:57 AM »
Probably the best method for scalability is to create a couple of database pools. It depends upon the needs of your program but I like three separate pools:

Read
Write
System / Admin

Each database object's identity is determined by: pool, host, user. The reason that you utilize a pool is because, especially with multiple servers, you cannot be certain that the database is still online and operational. Likely, you have an infrastructure setup with a group of master databases (for redundancy in case of fail-over) which are slaved out to read-only databases on each application server. However, if an error occurrs and you're unable to access your local database for a read operation, the pool should be able to give you a different database object from another server or from the master pool, allowing you to function. Obviously, in these cases it's important to log the failure so it may be dealt with:

Warning: Database object (Read, localhost, [user]) failed to initialize. Possible hardware / networking failure.

A bunch of these warnings in your log indicates that something is faulty with your setup and you need to take action. Obviously, this setup probably isn't necessary for a browser-based game. But, it's a possible solution in case your game really takes off and you need a 99.99% up-time to protect your revenue stream. ;)
Idiocy - Never underestimate the power of stupid people in large groups.


Offline Nox

  • Level 35
  • **
  • Posts: 738
  • Reputation: +12/-2
    • View Profile
Re: Game code structure
« Reply #10 on: December 19, 2009, 12:26:11 PM »
Sorry for late response

Thank you for advice...though I'm having a hard time processing it. I tried to find other sources but almost everything referred to "database *conection* pool", somewhere mentioning that it's similar to result of using mysql_pconnect, which is probably not what you meant.

Logging faulty I understand, that's easy one...

Maybe with some short example I might get the rest...I'll try something:
you mean instead of
Code: [Select]
<?php $this->db->query("...")?>have
Code: [Select]
<?php $this->dbp->write->query("...")?>where dbp would be injected database pool handler and write would be database chosen by pool handler to handle writing?

and the use appropriate type for every action? like
Code: [Select]
<?php
$this
->dbp->write->query("insert into table...");
$this->dbp->write->query("update table...");
$this->dbp->read->fetchAll("select name, login, password from users...");
$this->dbp->read->result("select count(*) from table");
$this->dbp->system->query(/* dump db into file */);
$this->dbp->system->query(/* create trigger */);
// etc...
?>


I'm feeling dumber with every passed day so please have patience with me :)

Quote
Likely, you have an infrastructure setup with a group of master databases (for redundancy in case of fail-over) which are slaved out to read-only databases on each application server.
Sounds like I'd have like 8 database servers though currently I might afford one all-purpose VPS at best :) I know... I should have it flexible and I'm rather perfectionist myself, just sayin'...

-----

Actually... what you posted is not exactly what I was asking about but I'm grateful for it of course.

I think my question is solved anyway, by the article I linked from edit in previous post
http://www.potstuck.com/2009/01/08/php-dependency-injection/
« Last Edit: December 21, 2009, 04:15:38 AM by Nox »
Meet us at an IRC irc.freenode.net #bbg as well
Enjoy http://spiritbeacon.noxart.cz/ !

Offline Chris

  • Game Owner
  • Level 35
  • *
  • Posts: 2,134
  • Reputation: +26/-1
    • View Profile
Re: Game code structure
« Reply #11 on: December 19, 2009, 12:33:47 PM »
I'm feeling dumber with every passed day so please have patience with me :)
That's what you get for using OOP for something as simple and trivial as BBG :D

Quote
Quote
Likely, you have an infrastructure setup with a group of master databases (for redundancy in case of fail-over) which are slaved out to read-only databases on each application server.
Sounds like I'd have like 8 database servers though currently I might afford one all-purpose VPS at best :) I know... I should have it flexible and I'm rather perfectionist myself, just sayin'...
... You will not have 8 database servers  (unless you make a bet with someone that a game can be done this way :D). Do not let the people who write business applications for multimilion companies brainwash you. 1 game=1 server.

Offline Nox

  • Level 35
  • **
  • Posts: 738
  • Reputation: +12/-2
    • View Profile
Re: Game code structure
« Reply #12 on: December 19, 2009, 12:49:26 PM »
'm gonna kick you :) I'm very glad I switched to OOP, my code is much cleaner and coding of the application itself is now very fast and short

And I think PBBG is as simple/complex as you design it to be... I guess there are many applications PBBG can't compete with in terms of complexity and that I'm not that experienced (especially speaking of larger projects) but still saying BBG=trivial triggers disagreeing LED withing me :)

Still I'm not sure how JGadrow meant the whole thing so maybe he didn't meant more servers but anyway this is something I can probably agree with you... especially in case of my game since I don't really expect it to be blockbuster

Ignace>PM
« Last Edit: December 20, 2009, 04:02:23 AM by Nox »
Meet us at an IRC irc.freenode.net #bbg as well
Enjoy http://spiritbeacon.noxart.cz/ !

Offline ignace

  • Level 3
  • *
  • Posts: 8
  • Reputation: +1/-0
    • View Profile
Re: Game code structure
« Reply #13 on: December 19, 2009, 05:19:58 PM »
Code: [Select]
function __autoload($function){
@require_once R."/objects/$function.php";
if(!$file_loaded) die( "Autoload: Missing class file" );
}

And put $file_loaded=1; at the beginning of each file.

There is an easier approach

Code: [Select]
function __autoload($class) {
    @require_once R."/objects/$class.php";
    if (!class_exists($class)) trigger_error("Autoload: tried to load $class.");
}

Few notes:
1) Stop using __autoload() use spl_autoload() instead.
2) Never use die()
« Last Edit: December 19, 2009, 05:22:21 PM by ignace »

Offline lolninja

  • Level 19
  • *
  • Posts: 194
  • Reputation: +5/-0
  • BSc powered Programmer
    • View Profile
    • HTTPmmo
Re: Game code structure
« Reply #14 on: December 21, 2009, 04:05:57 AM »
Hey, when JGadrow talks about connection pools I believe he's talking about having a master/slave database with mirrored data, This is basically where you have say three database server's once being the master, and the other two being slaves.

The master database is used for writing and modifying data, when you make a change on the master database it mirrors that information over to the two slaves.

Once the information change has been pushed over to the slaves that information can be read when ever. Now because you have one database server thats used for writing data it operates a ton quicker, and because you then have a collection of read only databases which all share the same data you get a bank of super fast access points.

So now we get to the pool bit, within your php code you'd have a list of slave databases which you randomly (or through some other mechanic) read from for that session, so say you have 2 users on your site, one user would access the first slave, and the second with access the second slave, both would get the same data, but it came from a different place.

This allows you to rapidly scale your application, but it gets tricky when you get to the point where the master server is becoming the bottle neck, and you also have to worry about edge cases, because it becomes possible for you to read data that is out of date, and make a modification based upon obsolete data. But solving these issues is all part of fun :D

If I got the wrong end of the stick I do apologize.

Offline JGadrow

  • Level 35
  • **
  • Posts: 1,133
  • Reputation: +23/-2
    • View Profile
Re: Game code structure
« Reply #15 on: December 21, 2009, 07:57:40 AM »
Most of what lolninja said above was correct. However, when I referred to database pools, I meant that the database object used the object pool pattern.

You could still implement this design pattern with a single server that just means your available pool is 1 server. However, should your application grow and need to scale, all you would need to do is setup your replication process and add it to the pool and your application is now scaled. :)

I agree with the statement of using spl_autoload() instead of __autoload() because it allows you to chain auto load calls together instead of only specifying one. I hope they do something similar with the error function in the future. I'm using spl_autoload() in my base application object that I started before 5.3 was released. You know, the one in the vault. lol

I'm working on the auto load function of it now - which is to say I've found maybe an hour or two to work on it in the last year. lol Once the auto loading is completed, I plan on re-uploading it.

Also, it's possible to setup a database network where you have multiple master servers that all replicate to one another. In this way, you'd have multiple points to write data to your servers which is where a pool comes in handy.

However, I state again that this is not likely to occur unless your game has grown massive but there's no point in putting in limitations to your application if you can avoid it. Hopefully this helps the confusion. :D
Idiocy - Never underestimate the power of stupid people in large groups.


 


SimplePortal 2.3.3 © 2008-2010, SimplePortal