5
\$\begingroup\$

I'm developing a browser game, using PHP, but I'm unsure if the way I'm going about doing it is to be encouraged anymore.

It's basically one of those MMOs where you level up various buildings and what have you, but, you then commit some abstract fighting entity that the game gives you, to an automated battle with another player (producing a textual, but hopefully amusing and varied combat report).

Basically, as soon as two players agree to fight, PHP functions on the "fight.php" page run queries against a huge MySQL database, looking up all sorts of complicated fight moves and outcomes. There are about three hundred thousand combinations of combat stance, attack, move and defensive stances, so obviously this is quite a resource hungry process, and, on the super cheapo hosted server I'm using for development, it rapidly runs out of memory.

The PHP script for the fight logic currently has about a thousand lines of code in it, and I'd say it's about half-finished as I try to add a bit of AI into the fight script.

Is there a better way to do something this massive than simply having some functions in a PHP file calling the MySQL Database?

I taught myself a modicum of PHP a while ago, and most of the stuff I read online (ages ago) about similar games was all PHP-based. but a) am I right to be using PHP at all, and b) am I missing some clever way of doing things that will somehow reduce server resource requirements?

I'd consider non PHP alternatives but, if PHP is suitable, I'd rather stick to that, so there's no overhead of learning something new. I think I'd bite that bullet if it's the best option for a better game, though.

\$\endgroup\$
6
  • 4
    \$\begingroup\$ This sounds like a problem specific to your code and data structures rather than specific to PHP/MySQL. In particular, why should 300,000 combinations require a lot of resources? \$\endgroup\$
    – Kylotan
    Sep 17, 2012 at 15:09
  • \$\begingroup\$ I just hit out of memory errors on my current hosted server, as soon as the combat goes on for "too long". I'm hoping that it's just terrible hosting, and that, as we get serious about this and look for a deidcated server, the problem will go away. \$\endgroup\$
    – JimBadger
    Sep 17, 2012 at 16:06
  • 4
    \$\begingroup\$ The quality of the hosting will not be the issue. Nothing you're doing should intrinsically require a lot of resources, but it sounds like the way you're doing it is very unusual. \$\endgroup\$
    – Kylotan
    Sep 17, 2012 at 16:25
  • 2
    \$\begingroup\$ I agree with Kylotan, sounds like the algorithm is doing things the wrong way around or brute forcing something. With more details about the algorithm itself people may be able to suggest ways to speed it up. If it's a case of AI searching for the most effective attack by brute force, then maybe you need to make it smarter. Or simpler. Or optimize dataflow. Or allow less than perfect results. Or cache calculations. Or a combination of the above. Anyway, at the end of the day it's probably a problem with the implementation, and it would cause trouble at some point regardless of language or DB. \$\endgroup\$
    – Supr
    Sep 17, 2012 at 18:40
  • \$\begingroup\$ Can we see an example of the database? \$\endgroup\$ Sep 20, 2012 at 5:36

5 Answers 5

5
\$\begingroup\$

Although I'm not PHP fan, I don't think it's a problem of the language, 300,000 rows in a database is not that big (I worked with much more). Your problem is most likly in the code-> algorithms you use..

As a side note..
1000 lines of code for just fight logic? How maintainable is that? It's ok that you know what's going on in there right now, but will you know it after half a year? ;)

\$\endgroup\$
3
  • \$\begingroup\$ Funny you should mention that, because we shelved the game for a year, and, now, coming back to it is a case of "what the bleep does THAT do!?". I've already started heavily commenting the code as I work out what was going through my head a year ago! :) \$\endgroup\$
    – JimBadger
    Sep 17, 2012 at 15:55
  • 1
    \$\begingroup\$ @JimBadger It's not about lack of commenting, it's about whether that means you have bad architectural design or not. \$\endgroup\$
    – you786
    Sep 17, 2012 at 20:54
  • \$\begingroup\$ @JimBadger Having expressive code ( eg well named functions that only perform what their name suggests ) is much better than cluttering code with ( soon to be outdated ) comments. \$\endgroup\$
    – rootlocus
    Mar 6, 2013 at 5:52
4
\$\begingroup\$

Better? Probably, but at what cost? PHP has a truly fully-featured string API which will come in handy as soon as you do just about anything with text.

C# has native code and some added speed at the cost of having to use an awful API and the JIT compilation on first launch makes testing painful.

Python has a rather uncomfortable reference system so copying data is painful. But it's ~10x faster than PHP.

But never mind what I said about speed because your bottleneck will most probably be MySQL and the data you retrieve and you'll want to keep things simple. PHP is good for just that.

So instead of a language change I'd suggest you use LIMIT/OFFSET features of MySQL to limit the amount of memory that is used by the results at any time, disable some extensions that you don't use and do some throttling (storing server load info and reacting appropriately to high load situations).


By limiting memory usage with LIMIT/OFFSET I meant loading the first N results and checking if result count is N and if so, loading the next N results and repeating this until all results are processed.

This will require you to add an ORDER BY clause which in turn might benefit from having a indexed column to sort by, something (but not necessarily) like the primary key. In fact, any well-placed index will do. You can use the MySQL EXPLAIN feature to find out if/when/how an index is used and what generally happens during the execution of a certain query.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks, I'll see if there's any limits I can put in place that wouldn't compromise the breadth of the combat report. A balance between that and responsiveness of the game may have to be found. \$\endgroup\$
    – JimBadger
    Sep 17, 2012 at 15:56
  • \$\begingroup\$ You don't have to compromise anything (except a bit of speed) if you use LIMIT/OFFSET to execute the query partially (I'll update the answer to explain). It might be required to make an index for the sorting order though, just to make result skipping faster. The MySQL "EXPLAIN" feature might help you find more about what's happening there. \$\endgroup\$
    – snake5
    Sep 17, 2012 at 16:21
4
\$\begingroup\$

As the others already mentioned....300k of rows from a database and 1k lines of code shouldn't really be that huge of a problem for the memory.

Although if you load all 300k rows into memory at once (depending on how much data is in each row) that COULD pose a problem. Another possibility would be memory leaks especially as the phenomenon that you write about with the medium sized data and 1k lines of code sounds like a memory leak is happening inside your code. There are 2 things that I can see where it COULD come from (without knowing the code): Loading too much data, or having a memory leak in a loop. I'll go into a bit more details to these two things below (also how you could counter those):

a.) For getting data from the database be sure to only load the really relevant ones. Thus if only 1 of the 300k rows is really applicable load only that one and dont select all 300k rows (if you have quite a few coloumns with 5-100 bytes each it could already result in 10MB+ memory usage there).

b.) Be sure to eliminate unused variables or variables you need to reinitialise. Especially if you use loops. Depending on the PHP version it can happen that the variables if you overwrite them don't get cleared and instead a copy of the variable is created in memory while the old data still consists. (with earlier php versions this problem was even worse as variables created in functions weren't "unset" automatically). For example:

$arr=GetFightingDataALLRows()
foreach ($arr as $row)
{
   .....//do something
}

At least up to PHP 5.3 (not 100% about 5.4 as in most projects I still have to use 5.3) it was so that $row if you didnt use unset($row) at the end of the foreach-loop was not "unsetted", thus even though in the next iteration of the loop you got new data into $row a copy of the old data still existed in memory thus leading for example if you have 3MB of data you load that you have at least 6 MB memory usage. If you have a loop inside the loop where you also don't delete the variables manually by using "unset".....lets say the result for the memory usage is not pretty (if for example we iterate through all 300k rows and inside the iteration we have another loop creating another set of variables which use 1 MB each then in total you have a memory usage of 300k x meory usage per row x 2 plus 300000 x 1 MB). With PHP 5.3 this could happen very often and easily, thus I always suggest that you use unset at the end of a loop too unset every and all variables that you don't need outside the loop.

\$\endgroup\$
3
\$\begingroup\$

I would like to comment on game performance:

It is very-very unlikely that the code is not the culprit if you are running into issues with only two users during the combat phase. There games (should be designed) to host hundreds if not thousands of users. One user should never cause performance issues. Did you test it offline on your computer to see if it works?

Another area that puzzles me is why would you need DataBase rows for combat moves, you could and probably should include the combat moves and AI in the code itself inside php files.

If this project is one you wish to share with the public without spending a lot on resources (at least until the project grows in scale), I would recommend using Google App Engine for - reliable performance. It uses a DataStore system that treats each user individually and each request separately and handles it within a short amount of time from one of many servers. You the application owner - will only pay per user and the prices are reasonable.

I cannot comment on code efficiency since you did not share your code. There are ways to improve code more times than not and especially DataBase performance is an area where a lot of adjustments and improvements can be made to squeeze out better performance.

\$\endgroup\$
1
  • \$\begingroup\$ I agree with the Comment about needing Database for combat engine. you should only have to grab the stats for each player (1 Row) maybe the Armor stats, weapon stats, other boosts (Total around 5 rows) per Player in the fight. then use PHP Logic to figure the outcome of the battle or show the play by play. if you are keeping a log then you would insert those statistics into the Database, only inserting 1-(a couple) of Rows into your Database. \$\endgroup\$
    – Malachi
    Mar 5, 2013 at 20:12
3
\$\begingroup\$

I think that as others have said, your issue does lie in your code. I think that it is likely in your interaction with the database. Since you've gone to the trouble of putting all your data in there, you should be able to use it. A database can be all about set theory and filtering of data.

I wouldn't build a system in the following way, but I'll infer one possible "easy to implement" optimization that you appear to be missing:

If Player_1 chooses Attack_Move_X and Player_2 chooses Defensive_Move_Y then you could simply ask your database to SELECT The_Result WHERE Move1 = Attack_Move_X AND Move2 = Defensive_Move_Y and it will spit out the result pronto. It appears from your description that you are loading many of the possible maneuvers into memory instead of letting your database do the filtering for which you could likely optimize it to do.

That said, as again others have pointed out, you should likely be handling combat in a different way. Maybe Attack_Move_X has a set of negative modifiers against your combat statistics, maybe Armor and Dexterity, while Defensive_Move_Y has a positive modifier to Dexterity and you simply do the modifier math, possibly after your randomization.

Since you asked about PHP specifically, my answer is to use whatever language you are comfortable with. Since this is a browser based game I'm not overly concerned about someone using it to steal my credit card information. However, if you are going to offer microtransactions then you need to be especially aware of PHP's Inherent Insecurity.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .