📜 ⬆️ ⬇️

The first steps in developing Flash games. Making Backend on AMFPHP

Social games are a very unstable, but at the same time very demanding and interesting branch of development.

When you start working with a new project, you are always between two fires - on the one hand, you need to do everything very quickly, because Most likely, several of your competitors have also begun to develop, and they step on your heels, but on the other hand, you must do so that if tomorrow attendance increases 5 times, your servers must endure it.

But this is all the lyrics, and there is plenty of lyricism and romance in our life, so let's get straight to the technical details.
')



AMF
This is a binary format that uses serialized ActionScript objects for cross-domain communication. In principle, this is sufficient information to understand why to use it, but for those who want to learn more, there is a wikipedia that I don’t see to quote.

AMFPHP
AMFPHP is used as the AMF parsing library, because:
1. It can be quickly installed
2. Does not require installation of additional extensions on the server
3. Opensource, and written in PHP, which helps to quickly understand it and change its behavior as it should (this is an extreme case, but the opportunity should still be)
3. Not tied to any framework and is not a framework itself.
4. Native Parsit JSON
5. Contains built-in profiler.

Primary setting.
To begin with, we introduce some conventions. Access to the project is carried out at http: // game /. DOCUMENT_ROOT for our project is the www folder, the application is in the app folder, and all third-party libraries in the lib folder. Models are in the app / model folder, and abstract classes are in the app / model / abstract folder, controllers are in the / app / controller folder. If you decide to blindly follow my guide, then I advise you to create these folders.

The process of raising the server.
0. Create a file www / gateway.php with this content:
<?php <br/> require_once '../app/config.php' ; <br/> require_once 'amfphp/gateway.php' ;

1. Download AMFPHP , unpack it, put the core folder and all the files that are in the root (except .htaccess) in the lib / amfphp folder

2. Create an app / config.php file with the following content:
<?php <br/> // <br/> define ( 'ROOT_DIR' , '/var/www/game/' ) ; // <br/> define ( 'LOG_DIR' , ROOT_DIR . 'log/' ) ; // <br/> define ( 'GAME_PLATFORM' , 'development' ) ; // <br/> $paths = array ( <br/> '.' , <br/> ROOT_DIR . 'lib' , <br/> ROOT_DIR . 'app' <br/> ) ; <br/> set_include_path ( implode ( PATH_SEPARATOR , $paths ) ) ;

3. In the file lib / amfphp / globals.php, assign the value $ ROOT_DIR to the variable $ servicesPath. "App / controller /"

4. Create an app / model / Response.php file with the following content:
<?php <?php <br/>abstract class Response<br/> { <br/> protected $error ; <br/> protected $content = array ( ) ; <br/> <br/> public function __construct ( array $content = null ) <br/> { <br/> if ( isset ( $content ) ) { <br/> $this -> content = $content ; <br/> } <br/> } <br/> <br/> public function addContent ( $content ) <br/> { <br/> if ( ! is_array ( $content ) ) { <br/> return false ; <br/> } <br/> foreach ( $content as $name => $data ) { <br/> $this -> content [ $name ] = $data ; <br/> } <br/> } <br/> <br/> public function getData ( ) <br/> { <br/> return array ( <br/> 'error' => $this -> error , <br/> 'response' => $this -> content , <br/> ) ; <br/> } <br/> } <br/> <br/> class ErrorResponse extends Response<br/> { <br/> public function __construct ( array $content = null ) <br/> { <br/> parent :: __construct ( $content ) ; <br/> $this -> error = 1 ; <br/> } <br/> } <br/> <br/> class SuccessResponse extends Response<br/> { <br/> public function __construct ( array $content = null ) <br/> { <br/> parent :: __construct ( $content ) ; <br/> $this -> error = 0 ; <br/> } <br/> }
<?php <?php <br/>abstract class Response<br/> { <br/> protected $error ; <br/> protected $content = array ( ) ; <br/> <br/> public function __construct ( array $content = null ) <br/> { <br/> if ( isset ( $content ) ) { <br/> $this -> content = $content ; <br/> } <br/> } <br/> <br/> public function addContent ( $content ) <br/> { <br/> if ( ! is_array ( $content ) ) { <br/> return false ; <br/> } <br/> foreach ( $content as $name => $data ) { <br/> $this -> content [ $name ] = $data ; <br/> } <br/> } <br/> <br/> public function getData ( ) <br/> { <br/> return array ( <br/> 'error' => $this -> error , <br/> 'response' => $this -> content , <br/> ) ; <br/> } <br/> } <br/> <br/> class ErrorResponse extends Response<br/> { <br/> public function __construct ( array $content = null ) <br/> { <br/> parent :: __construct ( $content ) ; <br/> $this -> error = 1 ; <br/> } <br/> } <br/> <br/> class SuccessResponse extends Response<br/> { <br/> public function __construct ( array $content = null ) <br/> { <br/> parent :: __construct ( $content ) ; <br/> $this -> error = 0 ; <br/> } <br/> }

This file describes two different response options: an answer with an error (ErrorResponse) and a “successful” answer (SuccessResponse)

5. Create a shell for the controller (file app / model / abstract / AbstractAMFController.php) <?php <?php <br/> require_once 'model/Response.php' ; <br/> <br/> class AbstractAMFController { <br/> <br/> protected $controller ; <br/> <br/> public function __construct ( $controllerName ) <br/> { <br/> $this -> controller = new $controllerName ( ) ; <br/> } <br/> <br/> protected function methodWrapper ( $method , $data ) { <br/> try { <br/> $result = $this -> controller -> $method ( $data ) ; <br/> $response = new SuccessResponse ( ) ; <br/> $response -> addContent ( $result ) ; <br/> } catch ( Exception $e ) { <br/> $response = new ErrorResponse ( $e -> getMessage ( ) . '\n' . $e -> getTraceAsString ( ) ) ; <br/> } <br/> } <br/> return $response -> getData ( ) ; <br/> } <br/> }
<?php <?php <br/> require_once 'model/Response.php' ; <br/> <br/> class AbstractAMFController { <br/> <br/> protected $controller ; <br/> <br/> public function __construct ( $controllerName ) <br/> { <br/> $this -> controller = new $controllerName ( ) ; <br/> } <br/> <br/> protected function methodWrapper ( $method , $data ) { <br/> try { <br/> $result = $this -> controller -> $method ( $data ) ; <br/> $response = new SuccessResponse ( ) ; <br/> $response -> addContent ( $result ) ; <br/> } catch ( Exception $e ) { <br/> $response = new ErrorResponse ( $e -> getMessage ( ) . '\n' . $e -> getTraceAsString ( ) ) ; <br/> } <br/> } <br/> return $response -> getData ( ) ; <br/> } <br/> }

This shell calls the controller's method specified in the constructor, and if suddenly there is an action inside the method, it generates a request with an error and returns it. This shell is convenient because in the future it will be able to store a lot of code inside it (for example, logging, automatic creation of a player's class, traces, and much more, it makes no sense to list now)

6. Create app / controller / wrappers.php
class Game extends AbstractAMFController { <br/> public function __construct ( ) { <br/> parent :: __construct ( 'GameController' ) ; <br/> } <br/> <br/> public function hello ( $data ) { <br/> return $this -> methodWrapper ( 'hello' , $data ) ; <br/> } <br/> }

Here will be stored wrappers methods. The fact is that AMFPHP does not want to work with the magic function __call, so you have to write a little more code than you would like

7. Well, the final chord. Create app / controller / Game.php
class GameController { <br/> <br/> public function hello ( $data ) { <br/> return 'hello' ; <br/> } <br/> } <br/> include 'wrappers.php' ;

Now you can open the browser (it lies in the archive with AMFPHP in the browser folder, the address is http: //game/gateway.php, the method is hello. Voila, you should get something like {"error": 0, "response" : "Hello"}
That's it, now the server is ready, and you can start implementing the first calls. But this is all later, and now drink up the tea and go home, almost 9, and I'm still at work :).

Source: https://habr.com/ru/post/113503/


All Articles