├── public_html ├── modules │ ├── 404 │ │ ├── 404.html │ │ └── 404.js │ ├── README.md │ ├── server │ │ └── server.js │ ├── about │ │ ├── about.js │ │ └── about.html │ ├── news │ │ ├── news.html │ │ └── news.js │ ├── players │ │ ├── online.html │ │ ├── player.html │ │ └── players.js │ ├── guilds │ │ ├── wars.html │ │ ├── guilds.html │ │ ├── wars.js │ │ ├── guilds.js │ │ ├── guild.html │ │ └── war.html │ ├── highscores │ │ ├── highscores.js │ │ └── highscores.html │ ├── account │ │ ├── register.html │ │ ├── account.html │ │ └── account.js │ ├── houses │ │ ├── houses.html │ │ ├── houses.js │ │ └── house.html │ └── main │ │ └── main.js ├── .htaccess ├── web.config ├── news │ ├── Markdown.md │ └── About DevAAC.md ├── config.sample.php ├── index.php └── DevAAC.js ├── composer.json ├── LICENSE ├── DevAAC ├── Models │ ├── AccountPublic.php │ ├── ServerConfig.php │ ├── PlayerOnline.php │ ├── PlayerSpell.php │ ├── HouseList.php │ ├── PlayerStorage.php │ ├── GuildInvite.php │ ├── GuildRank.php │ ├── Town.php │ ├── GuildMembership.php │ ├── PlayerNamelock.php │ ├── MarketOffer.php │ ├── GuildwarKill.php │ ├── AccountBan.php │ ├── AccountBanHistory.php │ ├── MarketHistory.php │ ├── IpBan.php │ ├── PlayerDeath.php │ ├── GuildWar.php │ ├── Guild.php │ ├── Account.php │ └── House.php ├── Helpers │ └── DateTime.php ├── Http │ └── Request.php └── routes │ ├── market.php │ ├── houses.php │ └── server.php ├── plugins ├── ipban.php ├── example.php ├── ratelimiter.php ├── simple.php └── templates │ └── simple.php └── README.md /public_html/modules/README.md: -------------------------------------------------------------------------------- 1 | Directory 'main' holds controllers for the static elements of layout (main, header, footer, navigation, widget). 2 | -------------------------------------------------------------------------------- /public_html/modules/404/404.html: -------------------------------------------------------------------------------- 1 | 2 |

Page not found.

3 |

The page you requested was not found.
Home Page

4 | -------------------------------------------------------------------------------- /public_html/modules/404/404.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.otherwise({ 4 | templateUrl: PageUrl('404') 5 | }); 6 | }]); 7 | 8 | // Module Controller(s) 9 | // ...404 don't have a controller yet. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DevelopersPL/DevAAC", 3 | "description": "Automatic Account Creator for TFS 1.X", 4 | "license": "MIT", 5 | "require": { 6 | "slim/slim": "2.*", 7 | "illuminate/database": "^4.2", 8 | "zircote/swagger-php": "^1.0" 9 | } 10 | } -------------------------------------------------------------------------------- /public_html/.htaccess: -------------------------------------------------------------------------------- 1 | DirectoryIndex index.html index.php 2 | RewriteEngine On 3 | RewriteBase / 4 | RewriteRule ^index\.php$ - [L] 5 | RewriteRule ^index\.html$ - [L] 6 | RewriteCond %{REQUEST_FILENAME} !-f 7 | RewriteCond %{REQUEST_FILENAME} !-d 8 | RewriteRule ^/api/ /index.php [L] 9 | RewriteRule . /index.html [L] 10 | -------------------------------------------------------------------------------- /public_html/modules/server/server.js: -------------------------------------------------------------------------------- 1 | // Module Factories(s) 2 | DevAAC.factory('Server', ['$resource', 3 | function($resource){ 4 | return $resource(ApiUrl('server/:what'), {}, { 5 | config: { params: {what: 'config'}, isArray: true, cache: true }, 6 | info: { params: {what: 'info'}, cache: true }, 7 | vocations: { params: {what: 'vocations'}, isArray: true, cache: true } 8 | }); 9 | } 10 | ]); 11 | -------------------------------------------------------------------------------- /public_html/modules/about/about.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.when('/about', { 4 | templateUrl: PageUrl('about'), 5 | controller: 'AboutController' 6 | }); 7 | }]); 8 | 9 | // Module Controller(s) 10 | DevAAC.controller('AboutController', ['$scope', 'Server', 11 | function($scope, Server) { 12 | $scope.vocations = Server.vocations(); 13 | $scope.config = Server.config(); 14 | } 15 | ]); -------------------------------------------------------------------------------- /public_html/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public_html/modules/news/news.html: -------------------------------------------------------------------------------- 1 |

{{errorMessage}}

2 | 3 |
4 |

5 |
6 | 7 | 8 | {{news.date}} 9 | 10 |

{{news.title}}

11 | 12 |
13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /public_html/news/Markdown.md: -------------------------------------------------------------------------------- 1 | You can use [Markdown](http://daringfireball.net/projects/markdown/syntax) language writing news. 2 | If you need help, you can use an [online editor like Dilliger.io](http://dillinger.io/) to format the text. 3 | 4 | 5 | Here are some examples: 6 | 7 | # Hello There 8 | This is [an example](http://example.com/ "I'm the title") of an inline link. 9 | 10 | ### Define a list below 11 | 12 | + Get milk 13 | + Buy food 14 | - pizza 15 | - even more pizza 16 | - and some ketchup, too 17 | 18 | This is paragraph text with some **bold** or some _italics_ how about _**both**_ ? 19 | 20 | **Code** block below: 21 | 22 | function hello() { 23 | alert('Hello world!'); 24 | } -------------------------------------------------------------------------------- /public_html/modules/players/online.html: -------------------------------------------------------------------------------- 1 |
2 |

Online Players there are {{ players.length }} online

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
NameVocationLevel
{{ player.name }}{{ vocation(player.vocation).name }}{{ player.level }}
20 | 21 |

22 | Nobody is online right now. 23 |

24 |
-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Daniel Speichert & Wojciech Guziak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /public_html/config.sample.php: -------------------------------------------------------------------------------- 1 | 2 |

Wars there are {{ wars.length }} on this server

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
DescriptionStartedEndedStats
{{ war.name1 }} are at war against {{ war.name2 }}{{ war.started | moment: 'LLL' }}{{ war.ended | moment: 'LLL' }}{{ war.guild1_kills }} - {{ war.guild2_kills }}Show details
24 | 25 |

26 | There are no wars yet! 27 |

28 | 29 |

30 | Loading... 31 |

32 | 33 | -------------------------------------------------------------------------------- /public_html/modules/highscores/highscores.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.when('/highscores', { 4 | // When a module contains multiple routes, use 'moduleName/viewName' in PageUrl function. 5 | templateUrl: PageUrl('highscores'), 6 | controller: 'HighscoresController', 7 | resolve: { 8 | vocations: function(Server) { 9 | return Server.vocations().$promise; 10 | } 11 | } 12 | }); 13 | }]); 14 | 15 | // Module Controller(s) 16 | DevAAC.controller('HighscoresController', ['$scope', 'Player', 'Server', 'vocations', 17 | function($scope, Player, Server, vocations) { 18 | $scope.order = 'level'; 19 | $scope.$watch('order', function(val) { 20 | $scope.loaded = false; 21 | $scope.players = Player.query({sort: '-'+val+',-level', limit: 100}, function(val) { 22 | $scope.loaded = true; 23 | }); 24 | }); 25 | 26 | $scope.players = Player.query(function(val){ 27 | $scope.loaded = true; 28 | return {sort: '-'+val+',-level', limit: 100}; 29 | }); 30 | 31 | $scope.vocation = function(id) { 32 | return _.findWhere(vocations, {id: id}); 33 | }; 34 | } 35 | ]); 36 | -------------------------------------------------------------------------------- /public_html/modules/guilds/guilds.html: -------------------------------------------------------------------------------- 1 |
2 |

Guilds there are {{ guilds.length }} on this server

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
NameLeaderOnlineAverage LevelFounded
{{ guild.name }}{{ guild.owner.name }} ({{ guild.owner.level}}) Online{{ guild.online_members }} / {{ guild.members_count }}{{ guild.average_level }}{{ guild.creationdata | date: fullDate }}
24 | 25 |

26 | There are no guilds yet! 27 |

28 | 29 |

30 | Loading... 31 |

32 |
33 | -------------------------------------------------------------------------------- /public_html/modules/account/register.html: -------------------------------------------------------------------------------- 1 |

Register new account

2 | 3 |
{{errorMessage}}
4 | 5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 | 17 |
18 |
19 | 20 | 21 |
22 |
23 | 26 |
27 | 28 |
-------------------------------------------------------------------------------- /public_html/news/About DevAAC.md: -------------------------------------------------------------------------------- 1 | [DevAAC](https://github.com/DevelopersPL/DevAAC) is the best AAC for [TFS 1.0+](https://github.com/otland/forgottenserver), written with good coding practices in mind and lots of love for development! 2 | It supports **only** TFS 1.0+, so if you really want to use other/older buggy engines, it's probably not useful for you. 3 | 4 | ### How to replace this text? 5 | This is sample news. You can edit news in your public_html/news directory and use [Markdown](http://daringfireball.net/projects/markdown/syntax) language. 6 | 7 | ### Quick facts 8 | - It is a Single Page Application, so it's super-fast once it loads 9 | - It's based on AngularJS and is supposed to be SEO-friendly, too 10 | - This is the place which you can fork and edit heavily to adapt to your server 11 | - It uses RESTful API exposed by the backend to do everything 12 | - The default frontend is based on Bootstrap 13 | - You should not edit any PHP files! If you think we should change or edit something, [open an issue](https://github.com/DevelopersPL/DevAAC/issues/new)! 14 | 15 | ### What do do now? 16 | If you see your server name in the top-left corner, you are good to go! There is no installation required. 17 | 18 | If you like it, please join [stargazers](https://github.com/DevelopersPL/DevAAC/stargazers) and star us on [GitHub](https://github.com/DevelopersPL/DevAAC)! 19 | 20 | ### Updates 21 | If you cloned this DevAAC from git (or if it came pre-installed with your server), the only thing you need to do is ```git pull``` in DevAAC directory to update to newest version. -------------------------------------------------------------------------------- /DevAAC/Models/AccountPublic.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | class AccountPublic extends Account { 35 | 36 | protected $table = 'accounts'; 37 | 38 | protected $hidden = array('name', 'password', 'email'); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /public_html/modules/guilds/wars.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.when('/guilds/wars', { 4 | templateUrl: PageUrl('guilds/wars'), 5 | controller: 'WarsController' 6 | }); 7 | 8 | $routeProvider.when('/guilds/wars/:id', { 9 | templateUrl: PageUrl('guilds/war'), 10 | controller: 'WarController', 11 | resolve: { 12 | vocations: function(Server) { 13 | return Server.vocations().$promise; 14 | }, 15 | war: function(War, $route) { 16 | return War.get({id: $route.current.params.id}).$promise; 17 | } 18 | } 19 | }); 20 | }]); 21 | 22 | // Module Controller(s) 23 | DevAAC.controller('WarsController', ['$scope', 'War', 24 | function($scope, War) { 25 | $scope.wars = War.query(function() { 26 | $scope.loaded = true; 27 | }); 28 | } 29 | ]); 30 | 31 | DevAAC.controller('WarController', ['$scope', '$route', '$location', 'Server', 'War', 'Player', 'vocations', 'war', 32 | function($scope, $route, $location, Server, War, Player, vocations, war) { 33 | 34 | $scope.war = war; 35 | 36 | $scope.players = []; 37 | $scope.player = function(id) { 38 | if(id == 0) 39 | return; 40 | 41 | if($scope.players[id] == undefined) 42 | $scope.players[id] = Player.get({id: id}); 43 | 44 | return $scope.players[id]; 45 | }; 46 | } 47 | ]); 48 | 49 | // Module Factories(s) 50 | DevAAC.factory('War', ['$resource', 51 | function($resource) { 52 | return $resource(ApiUrl('guilds/wars/:id'), {}, { 53 | get: { cache: true, params: { embed: 'kills' } }, 54 | query: { isArray: true, cache: true } 55 | }); 56 | } 57 | ]); -------------------------------------------------------------------------------- /public_html/modules/news/news.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.when('/', { 4 | templateUrl: PageUrl('news'), 5 | controller: 'NewsController' 6 | }); 7 | }]); 8 | 9 | // Module Controller(s) 10 | DevAAC.controller('NewsController', ['$scope', 'News', 'StatusMessage', 11 | function($scope, News, StatusMessage) { 12 | $scope.errorMessage = StatusMessage.error(); 13 | $scope.successMessage = StatusMessage.success(); 14 | $scope.newsA = News.query(function(result){ 15 | $scope.news = result[0]; 16 | $scope.news['date'] = moment($scope.news['date']).format('LLLL'); 17 | }); 18 | 19 | $scope.next = function() { 20 | index = $scope.newsA.indexOf($scope.news); 21 | if(index >= 0 && index < $scope.newsA.length - 1) { 22 | $scope.news = $scope.newsA[index + 1]; 23 | $scope.news['date'] = moment($scope.news['date']).format('LLLL'); 24 | } 25 | }; 26 | 27 | $scope.nextAvailable = function() { 28 | index = $scope.newsA.indexOf($scope.news); 29 | if(index >= 0 && index < $scope.newsA.length - 1) 30 | return true; 31 | }; 32 | 33 | $scope.previous = function() { 34 | index = $scope.newsA.indexOf($scope.news); 35 | if(index > 0 && index <= $scope.newsA.length - 1) { 36 | $scope.news = $scope.newsA[index - 1]; 37 | $scope.news['date'] = moment($scope.news['date']).format('LLLL'); 38 | } 39 | }; 40 | 41 | $scope.previousAvailable = function() { 42 | index = $scope.newsA.indexOf($scope.news); 43 | if(index > 0 && index <= $scope.newsA.length - 1) 44 | return true; 45 | }; 46 | } 47 | ]); 48 | 49 | // Module Factories(s) 50 | DevAAC.factory('News', ['$resource', 51 | function($resource){ 52 | return $resource(ApiUrl('news'), {}, { 53 | get: { cache: true }, 54 | query: { isArray: true, cache: true } 55 | }); 56 | } 57 | ]); -------------------------------------------------------------------------------- /public_html/modules/guilds/guilds.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.when('/guilds', { 4 | templateUrl: PageUrl('guilds/guilds'), 5 | controller: 'GuildsController' 6 | }); 7 | $routeProvider.when('/guilds/:id', { 8 | templateUrl: PageUrl('guilds/guild'), 9 | controller: 'GuildController', 10 | resolve: { 11 | vocations: function(Server) { 12 | return Server.vocations().$promise; 13 | }, 14 | guild: function(Guild, $route) { 15 | return Guild.get({id: $route.current.params.id}).$promise; 16 | } 17 | } 18 | }); 19 | }]); 20 | 21 | // Module Controller(s) 22 | DevAAC.controller('GuildsController', ['$scope', 'Guild', 23 | function($scope, Guild) { 24 | $scope.guilds = Guild.query({embed: 'owner'}, function() { 25 | $scope.loaded = true; 26 | }); 27 | } 28 | ]); 29 | DevAAC.controller('GuildController', ['$scope', '$route', '$location', 'Server', 'Guild', 'Player', 'vocations', 'guild', 30 | function($scope, $route, $location, Server, Guild, Player, vocations, guild) { 31 | $scope.guild = guild; 32 | 33 | $scope.vocation = function(id) { 34 | return _.findWhere(vocations, {id: id}); 35 | }; 36 | 37 | $scope.rank = function(id) { 38 | return _.findWhere(guild.ranks, {id: id}); 39 | }; 40 | 41 | $scope.players = []; 42 | $scope.player = function(id) { 43 | if(id == 0) 44 | return; 45 | 46 | if($scope.players[id] == undefined) 47 | $scope.players[id] = Player.get({id: id}); 48 | 49 | return $scope.players[id]; 50 | }; 51 | } 52 | ]); 53 | 54 | // Module Factories(s) 55 | DevAAC.factory('Guild', ['$resource', 56 | function($resource){ 57 | return $resource(ApiUrl('guilds/:id'), {}, { 58 | get: { cache: true, params: { embed: 'owner,members,invitations,ranks' } }, 59 | query: { isArray: true, cache: true } 60 | }); 61 | } 62 | ]); 63 | -------------------------------------------------------------------------------- /DevAAC/Helpers/DateTime.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Helpers; 33 | 34 | use Illuminate\Support\Contracts\JsonableInterface; 35 | use JsonSerializable; 36 | 37 | 38 | class DateTime extends \DateTime implements JsonSerializable, JsonableInterface { 39 | 40 | public function __toString() 41 | { 42 | return $this->format(DateTime::ISO8601); 43 | } 44 | 45 | public function jsonSerialize() 46 | { 47 | return $this->format(DateTime::ISO8601); 48 | } 49 | 50 | public function toJson($options = 0) 51 | { 52 | return json_encode($this->format(DateTime::ISO8601, $options)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /DevAAC/Models/ServerConfig.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['config','value']") 39 | */ 40 | class ServerConfig extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="config", type="string") 43 | * @SWG\Property(name="value", type="string") 44 | */ 45 | public $timestamps = false; 46 | 47 | protected $primaryKey = 'config'; 48 | 49 | public $incrementing = false; 50 | 51 | protected $table = 'server_config'; 52 | } 53 | -------------------------------------------------------------------------------- /DevAAC/Models/PlayerOnline.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['player_id']") 39 | */ 40 | class PlayerOnline extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="player_id", type="integer") 43 | */ 44 | public $timestamps = false; 45 | 46 | protected $primaryKey = 'player_id'; 47 | 48 | public $incrementing = false; 49 | 50 | protected $table = 'players_online'; 51 | 52 | public function player() 53 | { 54 | return $this->belongsTo('DevAAC\Models\Player'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /DevAAC/Models/PlayerSpell.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['player_id','name']") 39 | */ 40 | class PlayerSpell extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="player_id", type="integer") 43 | * @SWG\Property(name="name", type="string") 44 | */ 45 | public $timestamps = false; 46 | 47 | protected $primaryKey = null; 48 | 49 | public $incrementing = false; 50 | 51 | public function player() 52 | { 53 | return $this->belongsTo('DevAAC\Models\Player'); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /DevAAC/Models/HouseList.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['house_id','list_id','text']") 39 | */ 40 | class HouseList extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="house_id", type="integer") 43 | * @SWG\Property(name="list_id", type="integer") 44 | * @SWG\Property(name="text", type="string") 45 | */ 46 | public $timestamps = false; 47 | 48 | protected $primaryKey = null; 49 | 50 | public $incrementing = false; 51 | 52 | public function house() 53 | { 54 | return $this->belongsTo('DevAAC\Models\House'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /DevAAC/Models/PlayerStorage.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['player_id','key','value']") 39 | */ 40 | class PlayerStorage extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="player_id", type="integer") 43 | * @SWG\Property(name="key", type="integer") 44 | * @SWG\Property(name="value", type="integer") 45 | */ 46 | public $timestamps = false; 47 | 48 | protected $primaryKey = null; 49 | 50 | public $incrementing = false; 51 | 52 | protected $table = 'player_storage'; 53 | 54 | public function player() 55 | { 56 | return $this->belongsTo('DevAAC\Models\Player'); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /DevAAC/Models/GuildInvite.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['player_id','guild_id']") 39 | */ 40 | class GuildInvite extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="player_id", type="integer") 43 | * @SWG\Property(name="guild_id", type="string") 44 | */ 45 | 46 | public $timestamps = false; 47 | 48 | protected $primaryKey = null; 49 | 50 | public $incrementing = false; 51 | 52 | public function player() 53 | { 54 | return $this->belongsTo('DevAAC\Models\Player'); 55 | } 56 | 57 | public function guild() 58 | { 59 | return $this->belongsTo('DevAAC\Models\Guild'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /DevAAC/Models/GuildRank.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['id','guild_id','name','level']") 39 | */ 40 | class GuildRank extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="id", type="integer") 43 | * @SWG\Property(name="guild_id", type="integer") 44 | * @SWG\Property(name="name", type="string") 45 | * @SWG\Property(name="level", type="integer") 46 | */ 47 | 48 | public $timestamps = false; 49 | 50 | protected $guarded = array('id'); 51 | 52 | protected $attributes = array( 53 | 'level' => 1 54 | ); 55 | 56 | public function guild() 57 | { 58 | return $this->belongsTo('DevAAC\Models\Guild'); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /public_html/modules/guilds/guild.html: -------------------------------------------------------------------------------- 1 |
2 |

Loading...

3 |
4 | 5 |
6 |

Guild: {{guild.name}}

7 | 8 |
9 |

{{guild.motd}}

10 |
11 | 12 |

13 | Guild was founded on: {{guild.created | moment: 'LLL'}}
14 | Total level: {{guild.total_level}}
15 | Average level: {{guild.average_level}} 16 |

17 | 18 |
19 |
Guild Members ({{guild.online_members}} of {{guild.members_count}} online)
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
RankNameLevelVocation
{{ rank(player.membership.rank_id).name }} ({{ player.membership.nick }}) Leader {{ player.name }} Online{{ player.level }}{{ vocation(player.vocation).name }}
39 |
40 | 41 |
42 |
Invited Players
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
NameLevelVocation
{{ player(inv.player_id).name }} Online{{ player(inv.player_id).level }}{{ vocation(player(inv.player_id).vocation).name }}
60 |
61 |
62 | -------------------------------------------------------------------------------- /public_html/modules/highscores/highscores.html: -------------------------------------------------------------------------------- 1 |
2 |

Highscores

3 | 4 |
5 | 8 | 11 | 14 | 17 | 20 | 23 | 26 | 29 | 32 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
RankNameVocationLevelSelected Skill
{{$index+1}}{{ player.name }}{{ vocation(player.vocation).name }}{{ player.level }}{{ player[order] | number }}
57 | 58 |

59 | There are no players on this server. 60 |

61 | 62 |

63 | Loading... 64 |

65 |
-------------------------------------------------------------------------------- /DevAAC/Models/Town.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['id','name','posx','posy','posz']") 39 | */ 40 | class Town extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="id", type="integer") 43 | * @SWG\Property(name="name", type="string") 44 | * @SWG\Property(name="posx", type="integer") 45 | * @SWG\Property(name="posy", type="integer") 46 | * @SWG\Property(name="posz", type="integer") 47 | */ 48 | public $timestamps = false; 49 | 50 | // this is redundant 51 | protected $hidden = array( 52 | 'posx', 'posy', 'posz' 53 | ); 54 | 55 | protected $visible = array( 56 | 'id', 'name' 57 | ); 58 | 59 | public function players() 60 | { 61 | return $this->hasMany('DevAAC\Models\Player'); 62 | } 63 | 64 | public function houses() 65 | { 66 | return $this->hasMany('DevAAC\Models\House'); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /DevAAC/Models/GuildMembership.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 35 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 36 | 37 | /** 38 | * @SWG\Model(required="['player_id','guild_id','rank_id','nick']") 39 | */ 40 | class GuildMembership extends \Illuminate\Database\Eloquent\Model { 41 | /** 42 | * @SWG\Property(name="player_id", type="integer") 43 | * @SWG\Property(name="guild_id", type="integer") 44 | * @SWG\Property(name="rank_id", type="integer") 45 | * @SWG\Property(name="nick", type="string") 46 | */ 47 | 48 | protected $table = 'guild_membership'; 49 | 50 | public $timestamps = false; 51 | 52 | protected $primaryKey = 'player_id'; 53 | 54 | public $incrementing = false; 55 | 56 | protected $attributes = array( 57 | 'nick' => '' 58 | ); 59 | 60 | public function player() 61 | { 62 | return $this->belongsTo('DevAAC\Models\Player'); 63 | } 64 | 65 | public function guild() 66 | { 67 | return $this->belongsTo('DevAAC\Models\Guild'); 68 | } 69 | 70 | public function rank() 71 | { 72 | return $this->belongsTo('DevAAC\Models\GuildRank'); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /DevAAC/Http/Request.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Http; 33 | 34 | use InputErrorException; 35 | 36 | class Request extends \Slim\Http\Request 37 | { 38 | /** 39 | * This is similar to parent's params() but also includes params parsed with ContentTypes middleware 40 | * The order of preference is: Body, POST/PUT/PATCH/DELETE, GET 41 | * 42 | * @param string $key 43 | * @param mixed $default Default return value when key does not exist 44 | * @return array|mixed|null 45 | * @throws InputErrorException 46 | */ 47 | public function getAPIParam($key = null, $default = null) 48 | { 49 | $body = $this->getBody(); 50 | 51 | if(!$key) 52 | if(is_array($body)) 53 | return array_merge($body, $this->get(), $this->post()); 54 | else 55 | return array_merge($this->get(), $this->post()); 56 | 57 | if( is_array($body) && array_key_exists($key, $body) ) 58 | return $body[$key]; 59 | 60 | elseif( $this->post($key) ) 61 | return $this->post($key); 62 | 63 | elseif( $this->get($key) ) 64 | return $this->get($key); 65 | 66 | elseif( $default !== null ) 67 | return $default; 68 | 69 | else 70 | throw new InputErrorException('API parameter "' . $key . '" is missing.', 400); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /public_html/modules/guilds/war.html: -------------------------------------------------------------------------------- 1 |
2 |

Loading...

3 |
4 | 5 |
6 |

Guild War: {{ war.name1 }} vs. {{ war.name2 }} {{ war.guild1_kills }} - {{ war.guild2_kills }}

7 | 8 |

This guild war began at {{ war.started | moment: 'LLL' }} and ended at {{ war.ended | moment: 'LLL' }}

9 | 10 |
 
11 | 12 | 13 | 14 |
15 | 16 |
17 |

{{ war.name1 }} kills {{ war.guild1_kills }}

18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
KillerTargetTime
{{ kill.killer }} {{ player(kill.killer).level }}{{ kill.target }} {{ player(kill.target).level }}{{ kill.time | moment: 'LLL' }}
34 |
35 | 36 |
37 |

{{ war.name2 }} kills {{ war.guild2_kills }}

38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
KillerTargetTime
{{ kill.killer }} {{ player(kill.killer).level }}{{ kill.target }} {{ player(kill.target).level }}{{ kill.time | moment: 'LLL' }}
54 |
55 | 56 |
57 | 58 |
59 | -------------------------------------------------------------------------------- /public_html/modules/houses/houses.html: -------------------------------------------------------------------------------- 1 |
2 |

Houses there are {{ houses.length }} on this server

3 | 4 |
5 | Sort by 6 | 9 | 12 | 15 | 18 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 46 | 47 | 48 |
NameTownSize{{info.houseRentPeriod | capitalize}} rentPriceOwner
{{ house.name }}{{ house.town_name || house.town_id }}{{ house.size }}{{ house.rent | number }} gp 41 | {{ player(house.owner).name }} ({{player(house.owner).level}}) 42 | No Owner - Start bidding 43 | Auction ends {{ fromNow(house.bid_end) }}! 44 | !buyhouse in game to buy 45 |
49 | 50 |

51 | There are no houses on this server :( 52 |

53 | 54 |

55 | Loading... 56 |

57 |
-------------------------------------------------------------------------------- /plugins/ipban.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | use DevAAC\Models\IpBan; 33 | 34 | $meta = array('name' => 'IP Ban', 35 | 'description' => 'Disallows access to users who are IP banned. APC user cache is recommended for performance.', 36 | 'version' => '0.1', 37 | 'author' => 'Don Daniello', 38 | 'link' => 'https://github.com/DevelopersPL/DevAAC' 39 | ); 40 | 41 | /* 42 | * This plugin strongly benefits from APC user cache! 43 | */ 44 | 45 | if( !in_array(basename(__FILE__), $DevAAC->enabled_plugins) ) 46 | return array_merge($meta, array('enabled' => false)); 47 | 48 | // http://docs.slimframework.com/#How-to-Use-Hooks 49 | $DevAAC->hook('slim.before', function () use ($DevAAC) { 50 | $req = $DevAAC->request; 51 | $apc = false; 52 | 53 | if(extension_loaded('apc') && ini_get('apc.enabled')) 54 | { 55 | $apc = true; 56 | $objname = 'ipban_'.$req->getIp(); 57 | } 58 | 59 | if($apc && apc_fetch($objname)) 60 | { 61 | $DevAAC->halt(403, 'Your IP address is banned.'); 62 | } 63 | else 64 | { 65 | $ipban = IpBan::find( ip2long($req->getIp()) ); 66 | if($ipban) 67 | { 68 | $DevAAC->halt(403, 'Your IP address is banned.'); 69 | if($apc) 70 | apc_store($objname, true, 10 * 60); 71 | // THE INFORMATION WILL BE IN CACHE FOR 10 MINUTES SO WE CAN REJECT REQUESTS WITHOUT RUNNING ANY SQL QUERIES 72 | } 73 | } 74 | }); 75 | 76 | return array_merge($meta, array('enabled' => true)); 77 | -------------------------------------------------------------------------------- /plugins/example.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | // THIS IS ONLY OPTIONAL, YOU CAN DEFINE PLUGIN META DATA 33 | // THIS CAN BE ANY INFORMATION YOU WANT 34 | $meta = array('name' => 'Example plugin', 35 | 'description' => 'This is an example how to write plugins. It exposes /uptime. It requires shell_exec function.', 36 | 'version' => '1.0', 37 | 'author' => 'Don Daniello', 38 | 'link' => 'https://github.com/DevelopersPL/DevAAC' 39 | ); 40 | 41 | // IF THE PLUGIN IS NOT ACTIVATED IN CONFIG, THEN DISABLE IT 42 | if( !in_array(basename(__FILE__), $DevAAC->enabled_plugins) ) 43 | return array_merge($meta, array('enabled' => false)); 44 | 45 | // YOU CAN ADD EXTRA REQUIREMENTS FOR THE PLUGIN TO BE ENABLED 46 | if( !function_exists('shell_exec') ) 47 | return array_merge($meta, array('enabled' => false)); 48 | 49 | /** 50 | * This is an example plugin that is automatically loaded 51 | * You can find instance of Slim framework app as $DevAAC 52 | * Check out Slim documentation at http://docs.slimframework.com/ 53 | */ 54 | $DevAAC->get(ROUTES_PREFIX.'/uptime', function() use($DevAAC) { 55 | $DevAAC->response->headers->set('Content-Type', 'text'); 56 | $DevAAC->response->setBody(shell_exec('uptime')); 57 | }); 58 | 59 | $DevAAC->get(ROUTES_API_PREFIX.'/uptime', function() use($DevAAC) { 60 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 61 | $DevAAC->response->setBody(json_encode(array('uptime' => shell_exec('uptime')), JSON_PRETTY_PRINT)); 62 | }); 63 | 64 | // THIS RETURNS META DATA SPECIFIED ABOVE 65 | return array_merge($meta, array('enabled' => true)); 66 | -------------------------------------------------------------------------------- /DevAAC/Models/PlayerNamelock.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['player_id','reason','namelocked_by','namelocked_by']") 41 | */ 42 | class PlayerNamelock extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="player_id", type="integer") 45 | * @SWG\Property(name="reason", type="string") 46 | * @SWG\Property(name="namelocked_at", type="DateTime::ISO8601") 47 | * @SWG\Property(name="namelocked_by", type="integer") 48 | */ 49 | public $timestamps = false; 50 | 51 | protected $primaryKey = 'player_id'; 52 | 53 | public $incrementing = false; 54 | 55 | public function player() 56 | { 57 | return $this->belongsTo('DevAAC\Models\Player'); 58 | } 59 | 60 | public function namelockedBy() 61 | { 62 | return $this->belongsTo('DevAAC\Models\Player', 'namelocked_by'); 63 | } 64 | 65 | public function getNamelockedAtAttribute() 66 | { 67 | $date = new DateTime(); 68 | $date->setTimestamp($this->attributes['namelocked_at']); 69 | return $date; 70 | } 71 | 72 | public function setNamelockedAtAttribute($d) 73 | { 74 | if($d instanceof \DateTime) 75 | $this->attributes['namelocked_at'] = $d->getTimestamp(); 76 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 77 | $dt = new DateTime($d); 78 | $this->attributes['namelocked_at'] = $dt->getTimestamp(); 79 | } else // it is a UNIX timestamp 80 | $this->attributes['namelocked_at'] = $d; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /DevAAC/Models/MarketOffer.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use \Illuminate\Database\Eloquent\Model; 35 | use DevAAC\Helpers\DateTime; 36 | 37 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 38 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 39 | 40 | /** 41 | * @SWG\Model(required="['id','player_id','sale','itemtype','amount','created','anonymous','price']") 42 | */ 43 | class MarketOffer extends Model { 44 | /** 45 | * @SWG\Property(name="id", type="integer") 46 | * @SWG\Property(name="player_id", type="integer") 47 | * @SWG\Property(name="sale", type="boolean") 48 | * @SWG\Property(name="itemtype", type="integer") 49 | * @SWG\Property(name="amount", type="integer") 50 | * @SWG\Property(name="created", type="DateTime::ISO8601") 51 | * @SWG\Property(name="anonymous", type="boolean") 52 | * @SWG\Property(name="price", type="integer") 53 | */ 54 | 55 | protected $table = 'market_history'; 56 | 57 | public $timestamps = false; 58 | 59 | public $incrementing = false; 60 | 61 | public function player() 62 | { 63 | return $this->belongsTo('DevAAC\Models\Player'); 64 | } 65 | 66 | public function getCreatedAttribute() 67 | { 68 | $date = new DateTime(); 69 | $date->setTimestamp($this->attributes['created']); 70 | return $date; 71 | } 72 | 73 | public function setCreatedAttribute($d) 74 | { 75 | if($d instanceof \DateTime) 76 | $this->attributes['created'] = $d->getTimestamp(); 77 | elseif((int) $d != (string) $d) { // it's not a UNIX timestamp 78 | $dt = new DateTime($d); 79 | $this->attributes['created'] = $dt->getTimestamp(); 80 | } else // it is a UNIX timestamp 81 | $this->attributes['created'] = $d; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /DevAAC/Models/GuildwarKill.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['id','killer','target','killerguild','targetguild','warid','time']") 41 | */ 42 | class GuildwarKill extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="id", type="integer") 45 | * @SWG\Property(name="killer", type="string") 46 | * @SWG\Property(name="target", type="string") 47 | * @SWG\Property(name="killerguild", type="integer") 48 | * @SWG\Property(name="targetguild", type="integer") 49 | * @SWG\Property(name="warid", type="integer") 50 | * @SWG\Property(name="time", type="DateTime::ISO8601") 51 | */ 52 | 53 | public $timestamps = false; 54 | 55 | protected $guarded = array('id'); 56 | 57 | public function getTimeAttribute() 58 | { 59 | $date = new DateTime(); 60 | $date->setTimestamp($this->attributes['time']); 61 | return $date; 62 | } 63 | 64 | public function setTimeAttribute($d) 65 | { 66 | if($d instanceof \DateTime) 67 | $this->attributes['time'] = $d->getTimestamp(); 68 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 69 | $dt = new DateTime($d); 70 | $this->attributes['time'] = $dt->getTimestamp(); 71 | } else // it is a UNIX timestamp 72 | $this->attributes['time'] = $d; 73 | } 74 | 75 | public function killerGuild() 76 | { 77 | return $this->belongsTo('DevAAC\Models\Guild', 'killerguild'); 78 | } 79 | 80 | public function targetGuild() 81 | { 82 | return $this->belongsTo('DevAAC\Models\Guild', 'targetguild'); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /public_html/modules/account/account.html: -------------------------------------------------------------------------------- 1 |

Your account

2 |

3 | Email: {{account.email}}
4 | Premium account: {{(account.premdays > 0) ? 'Yes' : 'No'}} 5 |

6 | 7 |
8 | 9 |
10 |
{{errorMessage}}
11 |
{{successMessage}}
12 |
13 | 14 | 15 |
16 |

Create player:

17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 | 26 |
27 |
28 | 29 | 33 |
34 | 35 | 36 |
37 |
38 |
39 | 40 | 41 |
42 |

Change password:

43 |
44 |
45 | 46 | 47 |
48 |
49 | 50 | 51 |
52 | 53 | 54 |
55 |
56 |
57 | 58 | 59 | 60 | 61 |

Player list

62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 |
NameVocationLevel
{{ player.name }}{{ vocation(player.vocation).name }}{{ player.level }} 75 | Delete 76 |
80 | -------------------------------------------------------------------------------- /public_html/modules/main/main.js: -------------------------------------------------------------------------------- 1 | DevAAC.controller('MainController', ['$scope', 'Server', 'Account', 2 | function($scope, Server, Account) { 3 | $scope.info = Server.info(); 4 | 5 | $scope.isLoggedIn = function() { 6 | return Cookie.get('DevAACToken'); 7 | }; 8 | 9 | $scope.lostPassword = function () { 10 | $('#loading-lostpw-btn').button('loading'); 11 | 12 | Account.factory.recover({email: $('#inputEmail').val()}, function() { 13 | $('#recoverResponse').removeClass('hidden').addClass('text-success') 14 | .text('Your account name and new password has been sent to your e-mail address.'); 15 | 16 | $('#loading-lostpw-btn').remove(); 17 | }, function(response) { 18 | 19 | message = response.statusText; 20 | if (response.data.message != undefined) 21 | message = response.data.message; 22 | 23 | $('#recoverResponse').removeClass('hidden').addClass('text-danger').text(message); 24 | $('#loading-lostpw-btn').button('reset'); 25 | }); 26 | }; 27 | } 28 | ]); 29 | 30 | DevAAC.controller('HeaderController', ['$scope', 'Server', 31 | function($scope, Server) { 32 | Server.info(function(i) { 33 | $scope.name = i.serverName; 34 | document.title = i.serverName; 35 | }); 36 | } 37 | ]); 38 | 39 | DevAAC.controller('NavigationController', ['$scope', '$location', 'Account', 40 | function ($scope, $location, Account) { 41 | $scope.form = { 42 | name: '', 43 | password: '' 44 | }; 45 | 46 | $scope.isActive = function(route) { 47 | return route === $location.path(); 48 | }; 49 | 50 | $scope.isLoggedIn = function() { 51 | return Cookie.get('DevAACToken'); 52 | }; 53 | 54 | if($scope.isLoggedIn()) 55 | $scope.account = Account.factory.my(); 56 | 57 | $scope.Login = function () { 58 | $('#loading-login-btn').button('loading'); 59 | Account.authenticate($scope.form.name, $scope.form.password) 60 | .success(function(data, status) { 61 | $location.path('/account'); 62 | $scope.form.password = ''; 63 | $scope.account = Account.factory.my(); 64 | }) 65 | .error(function(data, status) { 66 | $('#loading-login-btn').button('reset'); 67 | $scope.form.password = ''; 68 | }); 69 | }; 70 | 71 | $scope.Logout = function () { 72 | Account.logout(); 73 | $location.path('/'); 74 | $scope.account = null; 75 | }; 76 | } 77 | ]); 78 | 79 | DevAAC.controller('FooterController', ['$scope', 80 | function($scope) { 81 | $scope.year = moment().format('YYYY'); 82 | } 83 | ]); 84 | 85 | DevAAC.controller('WidgetController', ['$scope', '$location', 'Player', 86 | function($scope, $location, Player) { 87 | $scope.highExperience = Player.highExperience(); 88 | 89 | $scope.goToPlayer = function() { 90 | Player.get({id: $scope.search}, function(value) { 91 | $scope.searchError = ''; 92 | $location.path('/players/' + value.name); 93 | }, function(httpResponse) { 94 | $scope.searchError = 'Player not found!'; 95 | }); 96 | }; 97 | 98 | $scope.findPlayers = function(name) { 99 | return Player.query({q: name, limit: 10, fields: 'name'}).$promise; 100 | }; 101 | } 102 | ]); 103 | -------------------------------------------------------------------------------- /public_html/modules/players/player.html: -------------------------------------------------------------------------------- 1 |
2 |

{{player.name}} Online

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
Name:{{player.name}}
Sex:{{player.sex}}
Profession:{{player.profession.name}}
Level:{{player.level}}
Residence:{{player.residence}}
Bank balance:{{player.balance | number}}
Last Seen:{{player.seen}}
Total Online Time:{{player.onlineTime}}
Account Status:{{account.status}}
43 | 44 |

Latest Deaths

45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 60 | 61 | 62 |
DateDescription
{{death.time | moment:'LLL'}} 54 | Unjustly kKilled at level {{death.level}} by 55 | {{death.killed_by}}{{death.killed_by}} 56 | 57 | (most damage by {{death.mostdamage_by}}{{death.mostdamage_by}}) 58 | 59 |
63 |
{{player.name}} has not died recently!
64 | 65 |

Account Information

66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
Position:{{account.position}}
Created:{{account.creation}}
78 | 79 |

All Players on this Account

80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
NameLevel
{{ player.name }}{{player.level}}
92 |
93 | -------------------------------------------------------------------------------- /public_html/modules/players/players.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.when('/players/online', { 4 | // When a module contains multiple routes, use 'moduleName/viewName' in PageUrl function. 5 | templateUrl: PageUrl('players/online'), 6 | controller: 'OnlineController', 7 | resolve: { 8 | vocations: function(Server) { 9 | return Server.vocations().$promise; 10 | } 11 | } 12 | }); 13 | 14 | $routeProvider.when('/players/:id', { 15 | templateUrl: PageUrl('players/player'), 16 | controller: 'PlayerController', 17 | resolve: { 18 | vocations: function(Server) { 19 | return Server.vocations().$promise; 20 | }, 21 | player: function(Player, $route) { 22 | return Player.get({id: $route.current.params.id}).$promise; 23 | } 24 | } 25 | }); 26 | }]); 27 | 28 | // Module Controller(s) 29 | DevAAC.controller('PlayerController', ['$scope', '$location', '$route', 'Account', 'Player', 'Server', 'vocations', 'player', 30 | function($scope, $location, $route, Account, Player, Server, vocations, player) { 31 | $scope.player = { 32 | name: player.name, 33 | sex: player.sex ? 'male' : 'female', 34 | profession: _.findWhere(vocations, {id: player.vocation}), 35 | level: player.level, 36 | residence: player.town_name || player.town_id, 37 | balance: player.balance, 38 | seen: moment.unix(player.lastlogin).format('LLL') + ' → ' + moment.unix(player.lastlogout).format('LLL'), 39 | onlineTime: moment.duration(player.onlinetime, 'seconds').humanize(), 40 | is_online: player.is_online 41 | }; 42 | 43 | $scope.deaths = Player.deaths({id: player.id}); 44 | 45 | $scope.account = Account.factory.get({id: player.account_id}, function(account) { 46 | // these positions are hard-coded in TFS 47 | var positions = [ 48 | 'none', 49 | 'Player', 50 | 'Tutor', 51 | 'Senior Tutor', 52 | 'Gamemaster', 53 | 'God' 54 | ]; 55 | $scope.account = { 56 | id: account.id, 57 | type: account.type, 58 | position: positions[account.type], 59 | premdays: account.premdays, 60 | lastday: account.lastday, 61 | creation: moment(account.creation).format('LLL'), 62 | status: account.premdays > 0 ? 'Premium account' : 'Free account' 63 | }; 64 | }); 65 | 66 | $scope.players = Player.query({account_id: player.account_id}, function(players) { 67 | $scope.players = players; 68 | }); 69 | } 70 | ]); 71 | 72 | DevAAC.controller('OnlineController', ['$scope', 'Player', 'Server', 'vocations', 73 | function($scope, Player, Server, vocations) { 74 | $scope.players = Player.queryOnline(); 75 | $scope.loadingView = true; 76 | 77 | $scope.vocation = function(id) { 78 | return _.findWhere(vocations, {id: id}); 79 | }; 80 | } 81 | ]); 82 | 83 | // Module Factories(s) 84 | DevAAC.factory('Player', ['$resource', 85 | function($resource) { 86 | return $resource(ApiUrl('players/:id'), {}, { 87 | query: { isArray: true, cache: true }, 88 | get: { cache: true }, 89 | queryOnline: { params: {id: 'online', embed: 'player'}, isArray: true, cache: true }, 90 | highExperience: { params: {sort: '-experience', limit: 5}, isArray: true, cache: true }, 91 | my: { url: ApiUrl('accounts/my/players'), isArray: true, cache: true }, 92 | deaths: { url: ApiUrl('players/:id/deaths'), isArray: true, cache: true } 93 | }); 94 | } 95 | ]); 96 | -------------------------------------------------------------------------------- /DevAAC/routes/market.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | use DevAAC\Models\MarketHistory; 33 | use DevAAC\Models\MarketOffer; 34 | 35 | /** 36 | * @SWG\Resource( 37 | * basePath="/api/v1", 38 | * resourcePath="/market", 39 | * @SWG\Api( 40 | * path="/market/history", 41 | * description="Operations on market", 42 | * @SWG\Operation( 43 | * summary="Get market history", 44 | * notes="", 45 | * method="GET", 46 | * type="MarketHistory", 47 | * nickname="getMarketHistory", 48 | * @SWG\Parameter( name="embed", 49 | * description="Pass player to embed player object", 50 | * paramType="query", 51 | * required=false, 52 | * type="string list separated by comma") 53 | * ) 54 | * ) 55 | * ) 56 | */ 57 | $DevAAC->get(ROUTES_API_PREFIX.'/market/history', function() use($DevAAC) { 58 | $req = $DevAAC->request; 59 | 60 | if($req->get('embed') == 'player') 61 | $history = MarketHistory::with('player')->get(); 62 | else 63 | $history = MarketHistory::all(); 64 | 65 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 66 | $DevAAC->response->setBody($history->toJson(JSON_PRETTY_PRINT)); 67 | }); 68 | 69 | /** 70 | * @SWG\Resource( 71 | * basePath="/api/v1", 72 | * resourcePath="/market", 73 | * @SWG\Api( 74 | * path="/market/offers", 75 | * description="Operations on market", 76 | * @SWG\Operation( 77 | * summary="Get market offers", 78 | * notes="", 79 | * method="GET", 80 | * type="MarketOffer", 81 | * nickname="getMarketHistory", 82 | * @SWG\Parameter( name="embed", 83 | * description="Pass player to embed player object", 84 | * paramType="query", 85 | * required=false, 86 | * type="string list separated by comma") 87 | * ) 88 | * ) 89 | * ) 90 | */ 91 | $DevAAC->get(ROUTES_API_PREFIX.'/market/offers', function() use($DevAAC) { 92 | $req = $DevAAC->request; 93 | 94 | // TODO: should not expose player if offer is anonymous 95 | if($req->get('embed') == 'player') 96 | $offers = MarketOffer::with('player')->get(); 97 | else 98 | $offers = MarketOffer::all(); 99 | 100 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 101 | $DevAAC->response->setBody($offers->toJson(JSON_PRETTY_PRINT)); 102 | }); 103 | -------------------------------------------------------------------------------- /DevAAC/Models/AccountBan.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['reason','expires_at','banned_by']") 41 | */ 42 | class AccountBan extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="account_id", type="integer") 45 | * @SWG\Property(name="reason", type="string") 46 | * @SWG\Property(name="banned_at", type="DateTime::ISO8601") 47 | * @SWG\Property(name="expires_at", type="DateTime::ISO8601") 48 | * @SWG\Property(name="banned_by", type="integer") 49 | */ 50 | public $timestamps = false; 51 | 52 | protected $primaryKey = 'account_id'; 53 | 54 | public $incrementing = false; 55 | 56 | protected $guarded = array(); 57 | 58 | public function account() 59 | { 60 | return $this->belongsTo('DevAAC\Models\Account'); 61 | } 62 | 63 | public function bannedByPlayer() 64 | { 65 | return $this->belongsTo('DevAAC\Models\Player', 'banned_by'); 66 | } 67 | 68 | public function getBannedAtAttribute() 69 | { 70 | $date = new DateTime(); 71 | $date->setTimestamp($this->attributes['banned_at']); 72 | return $date; 73 | } 74 | 75 | public function setBannedAtAttribute($d) 76 | { 77 | if($d instanceof \DateTime) 78 | $this->attributes['banned_at'] = $d->getTimestamp(); 79 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 80 | $dt = new DateTime($d); 81 | $this->attributes['banned_at'] = $dt->getTimestamp(); 82 | } else // it is a UNIX timestamp 83 | $this->attributes['banned_at'] = $d; 84 | } 85 | 86 | public function getExpiresAtAttribute() 87 | { 88 | $date = new DateTime(); 89 | $date->setTimestamp($this->attributes['expires_at']); 90 | return $date; 91 | } 92 | 93 | public function setExpiresAtAttribute($d) 94 | { 95 | if($d instanceof \DateTime) 96 | $this->attributes['expires_at'] = $d->getTimestamp(); 97 | elseif((int) $d != (string) $d) { // it's not a UNIX timestamp 98 | $dt = new DateTime($d); 99 | $this->attributes['expires_at'] = $dt->getTimestamp(); 100 | } else // it is a UNIX timestamp 101 | $this->attributes['expires_at'] = $d; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /DevAAC/Models/AccountBanHistory.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['id','account_id','reason','banned_at','expired_at','banned_by']") 41 | */ 42 | class AccountBanHistory extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="id", type="integer") 45 | * @SWG\Property(name="account_id", type="integer") 46 | * @SWG\Property(name="reason", type="string") 47 | * @SWG\Property(name="banned_at", type="DateTime::ISO8601") 48 | * @SWG\Property(name="expired_at", type="DateTime::ISO8601") 49 | * @SWG\Property(name="banned_by", type="integer") 50 | */ 51 | public $timestamps = false; 52 | 53 | protected $guarded = array('id'); 54 | 55 | protected $table = 'account_ban_history'; 56 | 57 | public function account() 58 | { 59 | return $this->belongsTo('DevAAC\Models\Account'); 60 | } 61 | 62 | public function bannedBy() 63 | { 64 | return $this->belongsTo('DevAAC\Models\Player', 'banned_by'); 65 | } 66 | 67 | public function getBannedAtAttribute() 68 | { 69 | $date = new DateTime(); 70 | $date->setTimestamp($this->attributes['banned_at']); 71 | return $date; 72 | } 73 | 74 | public function setBannedAtAttribute($d) 75 | { 76 | if($d instanceof \DateTime) 77 | $this->attributes['banned_at'] = $d->getTimestamp(); 78 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 79 | $dt = new DateTime($d); 80 | $this->attributes['banned_at'] = $dt->getTimestamp(); 81 | } else // it is a UNIX timestamp 82 | $this->attributes['banned_at'] = $d; 83 | } 84 | 85 | public function getExpiredAtAttribute() 86 | { 87 | $date = new DateTime(); 88 | $date->setTimestamp($this->attributes['expired_at']); 89 | return $date; 90 | } 91 | 92 | public function setExpiredAtAttribute($d) 93 | { 94 | if($d instanceof \DateTime) 95 | $this->attributes['expired_at'] = $d->getTimestamp(); 96 | elseif((int) $d != (string) $d) { // it's not a UNIX timestamp 97 | $dt = new DateTime($d); 98 | $this->attributes['expired_at'] = $dt->getTimestamp(); 99 | } else // it is a UNIX timestamp 100 | $this->attributes['expired_at'] = $d; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /DevAAC/Models/MarketHistory.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use \Illuminate\Database\Eloquent\Model; 35 | use DevAAC\Helpers\DateTime; 36 | 37 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 38 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 39 | 40 | /** 41 | * @SWG\Model(required="['id','player_id','sale','itemtype','amount','price','expires_at','inserted','state']") 42 | */ 43 | class MarketHistory extends Model { 44 | /** 45 | * @SWG\Property(name="id", type="integer") 46 | * @SWG\Property(name="player_id", type="integer") 47 | * @SWG\Property(name="sale", type="boolean") 48 | * @SWG\Property(name="itemtype", type="integer") 49 | * @SWG\Property(name="amount", type="integer") 50 | * @SWG\Property(name="price", type="integer") 51 | * @SWG\Property(name="expires_at", type="DateTime::ISO8601") 52 | * @SWG\Property(name="inserted", type="DateTime::ISO8601") 53 | * @SWG\Property(name="state", type="integer") 54 | */ 55 | 56 | protected $table = 'market_history'; 57 | 58 | public $timestamps = false; 59 | 60 | public $incrementing = false; 61 | 62 | public function player() 63 | { 64 | return $this->belongsTo('DevAAC\Models\Player'); 65 | } 66 | 67 | public function getExpiresAtAttribute() 68 | { 69 | $date = new DateTime(); 70 | $date->setTimestamp($this->attributes['expires_at']); 71 | return $date; 72 | } 73 | 74 | public function setExpiresAtAttribute($d) 75 | { 76 | if($d instanceof \DateTime) 77 | $this->attributes['expires_at'] = $d->getTimestamp(); 78 | elseif((int) $d != (string) $d) { // it's not a UNIX timestamp 79 | $dt = new DateTime($d); 80 | $this->attributes['expires_at'] = $dt->getTimestamp(); 81 | } else // it is a UNIX timestamp 82 | $this->attributes['expires_at'] = $d; 83 | } 84 | 85 | public function getInsertedAttribute() 86 | { 87 | $date = new DateTime(); 88 | $date->setTimestamp($this->attributes['inserted']); 89 | return $date; 90 | } 91 | 92 | public function setInsertedAttribute($d) 93 | { 94 | if($d instanceof \DateTime) 95 | $this->attributes['inserted'] = $d->getTimestamp(); 96 | elseif((int) $d != (string) $d) { // it's not a UNIX timestamp 97 | $dt = new DateTime($d); 98 | $this->attributes['inserted'] = $dt->getTimestamp(); 99 | } else // it is a UNIX timestamp 100 | $this->attributes['inserted'] = $d; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DevAAC by developers.pl for [TFS 1.0](https://github.com/otland/forgottenserver) 2 | ===== 3 | Quick facts: 4 | 5 | * This AAC (Automatic Account Creator) is built as a SPA (Single Page Application) on the front-end and a RESTful API on the back-end. 6 | * It is supposed to be easily extensible via plugins (check ```plugins/example.php```. 7 | * The core of this AAC does not modify TFS' database schema. News are loaded as static markdown files from ```public_html/news```. 8 | * The REST API is planned to be utilized by many external projects like OT server lists and OT Client. 9 | 10 | 11 | __Check out the [REST API documentation](http://developerspl.github.io/DevAAC)!__ 12 | 13 | This software is designed to: 14 | 15 | * be easy to understand and modify 16 | * emphasize simplicity and security 17 | * provide an example of good programming practices in PHP 18 | * require zero configuration for simple and secure use 19 | * follow [good practices of REST API](http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api) 20 | * follow [PSR-2 coding guidelines](http://www.php-fig.org/psr/psr-2/) 21 | 22 | Requirements 23 | ===== 24 | * PHP >= 5.4 25 | * PHP JSON extension 26 | * PHP MySQL NATIVE DRIVER (mysqlnd) extension (or [this](http://forumsarchive.laravel.io/viewtopic.php?pid=58151) will happen) 27 | * PHP APC or APCu extension (if you want ```plugins/ratelimiter.php``` to work) 28 | 29 | Installation (zip-bundle release) - stable 30 | ===== 31 | * Download zip-bundle release from [GitHub](https://github.com/DevelopersPL/DevAAC/releases) (green button) 32 | * Unpack to a directory higher than your web root, so that public_html is the web root (you can rename it if you need) 33 | * If you use nginx, you can find sample vhost config [in our wiki](https://github.com/DevelopersPL/DevAAC/wiki) 34 | * Web server MUST be configured to serve public_html as Document Root, DevAAC won't work in a subdirectory! 35 | * Rename ```config.sample.php``` to ```config.php``` and follow instructions in it 36 | 37 | Installation (development) 38 | ===== 39 | * [Get composer](https://getcomposer.org/download) ```curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin``` 40 | * Clone this repo: ```git clone https://github.com/DevelopersPL/DevAAC.git``` 41 | * Install dependencies: ```composer.phar install``` 42 | * Set up your web server to serve DevAAC/public_html as document root and add [required rewrites](https://github.com/DevelopersPL/DevAAC/wiki) 43 | * Rename ```config.sample.php``` to ```config.php``` and follow instructions 44 | 45 | REST API 46 | ===== 47 | * Receive JSON 48 | * Send JSON with ```Content-Type: application/json``` or form input with ```Content-Type: application/x-www-form-urlencoded``` but don't mix them! 49 | * You can override method with X-HTTP-Method-Override header 50 | * Actions return the modified object 51 | * HTTP status codes are meaningful, most common ones: 400 (missing params/bad params), 401 (not logged in), 403 (permission denied) 52 | * If rate limiting is active, it will return 503 with text/plain! 429 is planned but is not supported by all web servers (e.g. nginx) 53 | 54 | Hacking 55 | ===== 56 | * [Slim](http://slimframework.com) framework [documentation](http://docs.slimframework.com/) 57 | * API documentation is awesome thanks to [Swagger](https://helloreverb.com/developers/swagger). Put [Swagger Annotations](http://zircote.com/swagger-php/annotations.html) in the code! 58 | * You can use [Vagrant](http://www.vagrantup.com/) to setup a development machine. [Install Vagrant](http://www.vagrantup.com/downloads), execute ```vagrant up``` in project root and connect to [http://localhost:8044/](http://localhost:8044/) 59 | * Swagger docs are dynamically served at /api/v1/docs 60 | 61 | You can generate Swagger API docs manually: 62 | ``` 63 | php vendor/zircote/swagger-php/swagger.phar DevAAC/ -o api-docs 64 | ``` 65 | 66 | Authors 67 | ===== 68 | * [Daniel Speichert](https://github.com/DSpeichert) 69 | * [Wojciech Guziak](https://github.com/mrwogu) 70 | * [Znote](https://github.com/Znote) 71 | 72 | Contributions are always welcome, please submit pull requests! 73 | We are looking for back-end plugins and front-end functionality of themes. 74 | (It is proper to keep non-essential functionality in the form of plugins.) 75 | 76 | Released under [MIT license](LICENSE). 77 | -------------------------------------------------------------------------------- /DevAAC/Models/IpBan.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['ip','reason','expires_at','banned_by']") 41 | */ 42 | class IpBan extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="ip", type="string") 45 | * @SWG\Property(name="reason", type="string") 46 | * @SWG\Property(name="banned_at", type="DateTime::ISO8601") 47 | * @SWG\Property(name="expires_at", type="DateTime::ISO8601") 48 | * @SWG\Property(name="banned_by", type="integer") 49 | */ 50 | public $timestamps = false; 51 | 52 | protected $primaryKey = 'ip'; 53 | 54 | public $incrementing = false; 55 | 56 | protected $guarded = array(); 57 | 58 | // See this: https://github.com/laravel/framework/issues/3762 59 | public function getKey() 60 | { 61 | return $this->attributes['ip']; 62 | } 63 | 64 | public function bannedBy() 65 | { 66 | return $this->belongsTo('DevAAC\Models\Player', 'banned_by'); 67 | } 68 | 69 | public function getIpAttribute() 70 | { 71 | return long2ip(chbo($this->attributes['ip'])); 72 | } 73 | 74 | public function setIpAttribute($ip) 75 | { 76 | $this->attributes['ip'] = chbo(ip2long($ip)); 77 | } 78 | 79 | public function getBannedAtAttribute() 80 | { 81 | $date = new DateTime(); 82 | $date->setTimestamp($this->attributes['banned_at']); 83 | return $date; 84 | } 85 | 86 | public function setBannedAtAttribute($d) 87 | { 88 | if($d instanceof \DateTime) 89 | $this->attributes['banned_at'] = $d->getTimestamp(); 90 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 91 | $dt = new DateTime($d); 92 | $this->attributes['banned_at'] = $dt->getTimestamp(); 93 | } else // it is a UNIX timestamp 94 | $this->attributes['banned_at'] = $d; 95 | } 96 | 97 | public function getExpiresAtAttribute() 98 | { 99 | $date = new DateTime(); 100 | $date->setTimestamp($this->attributes['expires_at']); 101 | return $date; 102 | } 103 | 104 | public function setExpiresAtAttribute($d) 105 | { 106 | if($d instanceof \DateTime) 107 | $this->attributes['expires_at'] = $d->getTimestamp(); 108 | elseif((int) $d != (string) $d) { // it's not a UNIX timestamp 109 | $dt = new DateTime($d); 110 | $this->attributes['expires_at'] = $dt->getTimestamp(); 111 | } else // it is a UNIX timestamp 112 | $this->attributes['expires_at'] = $d; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /plugins/ratelimiter.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | $meta = array('name' => 'Rate limiter', 33 | 'description' => 'Rate limiter requires APC user cache (APC or APCu)', 34 | 'version' => '1.0', 35 | 'author' => 'Don Daniello', 36 | 'link' => 'https://github.com/DevelopersPL/DevAAC' 37 | ); 38 | 39 | if( !in_array(basename(__FILE__), $DevAAC->enabled_plugins) ) 40 | return array_merge($meta, array('enabled' => false)); 41 | 42 | // THIS PLUGIN CURRENTLY SUPPORTS APC ONLY 43 | if(!extension_loaded('apc') || !ini_get('apc.enabled')) 44 | return array_merge($meta, array('enabled' => false)); 45 | 46 | // DEFAULT CONFIG 47 | defined('RATELIMITER_RULES') || define('RATELIMITER_RULES', serialize(array( 48 | // DEFINE RULES WITHOUT ROUTES_PREFIX OR ROUTES_API_PREFIX 49 | // PATH -> NUMBER OF SECONDS TO WAIT BETWEEN REQUESTS 50 | 'GET' => array( 51 | '/plugins' => 5 52 | ), 53 | 'POST' => array( 54 | '/' => 5, // for Simple AAC (plugin) 55 | '/accounts' => 10, 56 | '/players' => 5, 57 | ) 58 | ))); 59 | // SHOULD WE RESET THE TIMER ON EVERY ATTEMPT? 60 | defined('RATELIMITER_PENALIZE') || define('RATELIMITER_PENALIZE', false); 61 | 62 | // http://docs.slimframework.com/#How-to-Use-Hooks 63 | $DevAAC->hook('slim.before.dispatch', function () use ($DevAAC) { 64 | 65 | $rules = unserialize(RATELIMITER_RULES); 66 | 67 | // $DevAAC->router->currentRoute is NULL in this hook plus it's protected 68 | // we cannot use route names (even if we assigned them) 69 | // unfortunately we need to base on path 70 | 71 | $req = $DevAAC->request; 72 | $path = $req->getPath(); 73 | $method = $req->getMethod(); 74 | 75 | // REMOVE ROUTES_API_PREFIX FROM PATH 76 | if (substr($path, 0, strlen(ROUTES_API_PREFIX)) == ROUTES_API_PREFIX) 77 | $path = substr($path, strlen(ROUTES_API_PREFIX)); 78 | 79 | // REMOVE ROUTES_PREFIX FROM PATH 80 | if (substr($path, 0, strlen(ROUTES_PREFIX)) == ROUTES_PREFIX) 81 | $path = substr($path, strlen(ROUTES_PREFIX)); 82 | 83 | // DO WE HAVE A RULE? 84 | if (array_key_exists($method, $rules) && array_key_exists($path, $rules[$method])) { 85 | // every path for every IP is a separate object to be thread safe 86 | $objname = $req->getIp() . '_' . $path; 87 | 88 | if(apc_fetch($objname) + $rules[$method][$path] > time()) { 89 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 90 | $DevAAC->halt(503, json_encode(array('code' => 503, 'message' => 'Too many requests. Please wait a minute and try again.'))); // 429 IS NOT SUPPORTED BY NGINX SO WE USE 503 91 | 92 | if(!RATELIMITER_PENALIZE) 93 | return; 94 | } 95 | apc_store($objname, time()); 96 | $DevAAC->expires('+'.$rules[$method][$path].' seconds'); 97 | } 98 | }); 99 | 100 | return array_merge($meta, array('enabled' => true)); 101 | -------------------------------------------------------------------------------- /DevAAC/Models/PlayerDeath.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['player_id','time','level','killed_by','is_player','mostdamage_by','mostdamage_is_player','unjustified','mostdamage_unjustified']") 41 | */ 42 | class PlayerDeath extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="player_id", type="integer") 45 | * @SWG\Property(name="time", type="integer") 46 | * @SWG\Property(name="level", type="integer") 47 | * @SWG\Property(name="killed_by", type="string") 48 | * @SWG\Property(name="is_player", type="boolean") 49 | * @SWG\Property(name="mostdamage_by", type="string") 50 | * @SWG\Property(name="mostdamage_is_player", type="boolean") 51 | * @SWG\Property(name="unjustified", type="boolean") 52 | * @SWG\Property(name="mostdamage_unjustified", type="boolean") 53 | */ 54 | public $timestamps = false; 55 | 56 | protected $primaryKey = null; 57 | 58 | public $incrementing = false; 59 | 60 | public function player() 61 | { 62 | return $this->belongsTo('DevAAC\Models\Player'); 63 | } 64 | 65 | public function getTimeAttribute() 66 | { 67 | $date = new DateTime(); 68 | $date->setTimestamp($this->attributes['time']); 69 | return $date; 70 | } 71 | 72 | public function setTimeAttribute($d) 73 | { 74 | if($d instanceof \DateTime) 75 | $this->attributes['time'] = $d->getTimestamp(); 76 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 77 | $dt = new DateTime($d); 78 | $this->attributes['time'] = $dt->getTimestamp(); 79 | } else // it is a UNIX timestamp 80 | $this->attributes['time'] = $d; 81 | } 82 | 83 | public function getIsPlayerAttribute() 84 | { 85 | return (bool)$this->attributes['is_player']; 86 | } 87 | 88 | public function setIsPlayerAttribute($v) 89 | { 90 | $this->attributes['is_player'] = (int)$v; 91 | } 92 | 93 | public function getMostdamageIsPlayerAttribute() 94 | { 95 | return (bool)$this->attributes['mostdamage_is_player']; 96 | } 97 | 98 | public function setMostdamageIsPlayerAttribute($v) 99 | { 100 | $this->attributes['mostdamage_is_player'] = (int)$v; 101 | } 102 | 103 | public function getUnjustifiedAttribute() 104 | { 105 | return (bool)$this->attributes['unjustified']; 106 | } 107 | 108 | public function setUnjustifiedAttribute($v) 109 | { 110 | $this->attributes['unjustified'] = (int)$v; 111 | } 112 | 113 | public function getMostdamageUnjustifiedAttribute() 114 | { 115 | return (bool)$this->attributes['mostdamage_unjustified']; 116 | } 117 | 118 | public function setMostdamageUnjustifiedAttribute($v) 119 | { 120 | $this->attributes['mostdamage_unjustified'] = (int)$v; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /DevAAC/Models/GuildWar.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['id','guild1','guild2','name1','name2']") 41 | */ 42 | class GuildWar extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="id", type="integer") 45 | * @SWG\Property(name="guild1", type="integer") 46 | * @SWG\Property(name="guild2", type="integer") 47 | * @SWG\Property(name="name1", type="string") 48 | * @SWG\Property(name="name2", type="string") 49 | * @SWG\Property(name="status", type="integer") 50 | * @SWG\Property(name="started", type="DateTime::ISO8601") 51 | * @SWG\Property(name="ended", type="DateTime::ISO8601") 52 | */ 53 | 54 | public $timestamps = false; 55 | 56 | protected $guarded = array('id'); 57 | 58 | protected $appends = array('guild1_kills', 'guild2_kills'); 59 | 60 | public function getStartedAttribute() 61 | { 62 | $date = new DateTime(); 63 | $date->setTimestamp($this->attributes['started']); 64 | return $date; 65 | } 66 | 67 | public function setStartedAttribute($d) 68 | { 69 | if($d instanceof \DateTime) 70 | $this->attributes['started'] = $d->getTimestamp(); 71 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 72 | $dt = new DateTime($d); 73 | $this->attributes['started'] = $dt->getTimestamp(); 74 | } else // it is a UNIX timestamp 75 | $this->attributes['started'] = $d; 76 | } 77 | 78 | public function getEndedAttribute() 79 | { 80 | $date = new DateTime(); 81 | $date->setTimestamp($this->attributes['ended']); 82 | return $date; 83 | } 84 | 85 | public function setEndedAttribute($d) 86 | { 87 | if($d instanceof \DateTime) 88 | $this->attributes['ended'] = $d->getTimestamp(); 89 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 90 | $dt = new DateTime($d); 91 | $this->attributes['ended'] = $dt->getTimestamp(); 92 | } else // it is a UNIX timestamp 93 | $this->attributes['ended'] = $d; 94 | } 95 | 96 | public function guild1() 97 | { 98 | return $this->belongsTo('DevAAC\Models\Guild', 'guild1'); 99 | } 100 | 101 | public function guild2() 102 | { 103 | return $this->belongsTo('DevAAC\Models\Guild', 'guild2'); 104 | } 105 | 106 | public function kills() 107 | { 108 | return $this->hasMany('DevAAC\Models\GuildwarKill', 'warid'); 109 | } 110 | 111 | public function getGuild1KillsAttribute() 112 | { 113 | return GuildwarKill::where('warid', $this->id)->where('killerguild', $this->guild1)->count(); 114 | } 115 | 116 | public function getGuild2KillsAttribute() 117 | { 118 | return GuildwarKill::where('warid', $this->id)->where('killerguild', $this->guild2)->count(); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /DevAAC/Models/Guild.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['name','ownerid','creationdata','motd']") 41 | */ 42 | class Guild extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="id", type="integer") 45 | * @SWG\Property(name="name", type="string") 46 | * @SWG\Property(name="ownerid", type="integer") 47 | * @SWG\Property(name="creationdata", type="DateTime::ISO8601") 48 | * @SWG\Property(name="motd", type="string") 49 | */ 50 | 51 | public $timestamps = false; 52 | 53 | protected $guarded = array('id'); 54 | 55 | protected $attributes = array( 56 | 'motd' => '' 57 | ); 58 | 59 | protected $appends = array('total_level', 'average_level', 'members_count', 'online_members'); 60 | 61 | public function getCreationdataAttribute() 62 | { 63 | $date = new DateTime(); 64 | $date->setTimestamp($this->attributes['creationdata']); 65 | return $date; 66 | } 67 | 68 | public function setCreationdataAttribute($d) 69 | { 70 | if($d instanceof \DateTime) 71 | $this->attributes['creationdata'] = $d->getTimestamp(); 72 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 73 | $dt = new DateTime($d); 74 | $this->attributes['creationdata'] = $dt->getTimestamp(); 75 | } else // it is a UNIX timestamp 76 | $this->attributes['creationdata'] = $d; 77 | } 78 | 79 | public function owner() 80 | { 81 | return $this->belongsTo('DevAAC\Models\Player', 'ownerid'); 82 | } 83 | 84 | public function members() 85 | { 86 | return $this->hasManyThrough('DevAAC\Models\Player', 'DevAAC\Models\GuildMembership', 'guild_id', 'id'); 87 | } 88 | 89 | public function memberships() 90 | { 91 | return $this->hasMany('DevAAC\Models\GuildMembership'); 92 | } 93 | 94 | public function invitations() 95 | { 96 | return $this->hasMany('DevAAC\Models\GuildInvite'); 97 | } 98 | 99 | public function ranks() 100 | { 101 | return $this->hasMany('DevAAC\Models\GuildRank'); 102 | } 103 | 104 | public function getTotalLevelAttribute() 105 | { 106 | $sum = 0; 107 | foreach($this->members as $member) 108 | $sum += $member->level; 109 | return $sum; 110 | } 111 | 112 | public function getAverageLevelAttribute() 113 | { 114 | $sum = 0; 115 | foreach($this->members as $member) 116 | $sum += $member->level; 117 | return round($sum/count($this->members)); 118 | } 119 | 120 | public function getMembersCountAttribute() 121 | { 122 | return count($this->members); 123 | } 124 | 125 | public function getOnlineMembersAttribute() 126 | { 127 | $count = 0; 128 | foreach($this->members as $member) 129 | if($member->is_online) 130 | $count++; 131 | return $count; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /public_html/index.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | /** 33 | * This is the primary "kickstarter" file for the AAC 34 | * Your webserver should direct all requests here 35 | * You can put this file anywhere but make sure you adapt APP_ROOT 36 | */ 37 | 38 | // LOAD CONFIG IF IT EXISTS 39 | if(is_file('./config.php')) 40 | include './config.php'; 41 | 42 | // DEFAULT CONFIG - DO NOT EDIT - PUT YOUR CUSTOMIZATIONS IN config.php 43 | defined('APP_ROOT') or define('APP_ROOT', '../DevAAC'); 44 | defined('ENABLE_DEBUG') or define('ENABLE_DEBUG', false); 45 | defined('TFS_ROOT') or die('Please follow instructions in public_html/config.sample.php');; // directory where config.lua is located 46 | defined('TFS_CONFIG') or define('TFS_CONFIG', TFS_ROOT.'/config.lua'); 47 | defined('ROUTES_PREFIX') or define('ROUTES_PREFIX', ''); 48 | defined('ROUTES_API_PREFIX') or define('ROUTES_API_PREFIX', '/api/v1'); 49 | defined('CORS_ALLOW_ORIGIN') or define('CORS_ALLOW_ORIGIN', 'otls.net'); // origin or false 50 | defined('ACCOUNT_RECOVERY_INTERVAL') or define('ACCOUNT_RECOVERY_INTERVAL', 10800); // 3 hours (in seconds) 51 | 52 | // GAME 53 | defined('ACCOUNT_TYPE_GOD') or define('ACCOUNT_TYPE_GOD', 5); 54 | defined('ACCOUNT_TYPE_GAMEMASTER') or define('ACCOUNT_TYPE_GAMEMASTER', 4); 55 | defined('ACCOUNT_TYPE_SENIORTUTOR') or define('ACCOUNT_TYPE_SENIORTUTOR', 3); 56 | defined('ACCOUNT_TYPE_TUTOR') or define('ACCOUNT_TYPE_TUTOR', 2); 57 | 58 | defined('ALLOWED_VOCATIONS') or define('ALLOWED_VOCATIONS', serialize(array(1, 2, 3, 4))); 59 | defined('NEW_PLAYER_LEVEL') or define('NEW_PLAYER_LEVEL', 8); 60 | defined('NEW_PLAYER_TOWN_ID') or define('NEW_PLAYER_TOWN_ID', 1); 61 | 62 | defined('HOUSES_AUCTIONS') or define('HOUSES_AUCTIONS', true); // enable house auction system? 63 | defined('HOUSES_AUCTION_TIME') or define('HOUSES_AUCTION_TIME', 'P7D'); // DateInterval spec notation: http://www.php.net/manual/en/dateinterval.construct.php 64 | defined('HOUSES_PER_PLAYER') or define('HOUSES_PER_PLAYER', 1); 65 | defined('HOUSES_PER_ACCOUNT') or define('HOUSES_PER_ACCOUNT', 1); 66 | 67 | // both HOUSES_BID_RAISE and HOUSES_BID_RAISE_PERCENT are enforced at the same time so it is usually enough to set one of them to 0 68 | defined('HOUSES_BID_RAISE') or define('HOUSES_BID_RAISE', 1000); // the minimum difference between last bid, 69 | // e.g. if the house is currently offered at 15000 and HOUSES_BID_RAISE is 500, you need to bid at least 15500 70 | defined('HOUSES_BID_RAISE_PERCENT') or define('HOUSES_BID_RAISE_PERCENT', 0); // the minimum difference between last bid in %, 71 | // e.g. if the house is currently offered at 15000 and HOUSES_BID_RAISE_PERCENT is 20, then you need to bid at least 18000 (3000 is 20% of 15000) 72 | 73 | // PLUGINS CONFIG - DO NOT EDIT - PUT YOUR CUSTOMIZATIONS IN config.php 74 | defined('DISABLE_PLUGINS') or define('DISABLE_PLUGINS', false); 75 | defined('ENABLED_PLUGINS') or define('ENABLED_PLUGINS', serialize(array('ratelimiter.php', 'simple.php', 'ipban.php'))); 76 | 77 | // DO NOT EDIT 78 | define('PUBLIC_HTML_PATH', realpath('.')); 79 | define('HAS_APC', extension_loaded('apc') && ini_get('apc.enabled')); 80 | 81 | // IF YOU INSTALL PUBLIC_HTML IN A SUBDIRECTORY, FOR EXAMPLE: http://example.com/ots/aac/index.php 82 | // THEN YOU NEED TO SET APP_ROOT ACCORDINGLY. IN THIS CASE TO '../../../DevAAC' 83 | 84 | chdir(APP_ROOT); 85 | require './DevAAC.php'; 86 | // NOTHING IN THIS FILE MATTERS AFTER THIS LINE 87 | 88 | // GOOD PLACE FOR PLUGINS, CUSTOMIZATIONS, ETC 89 | // IS IN A NEW FILE IN plugins DIRECTORY 90 | // THEY ARE AUTOMATICALLY LOADED 91 | -------------------------------------------------------------------------------- /DevAAC/Models/Account.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['name','password','email']") 41 | */ 42 | class Account extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="id", type="integer") 45 | * @SWG\Property(name="name", type="string") 46 | * @SWG\Property(name="password", type="SHA1 hash") 47 | * @SWG\Property(name="type", type="integer") 48 | * @SWG\Property(name="premdays", type="integer") 49 | * @SWG\Property(name="lastday", type="integer") 50 | * @SWG\Property(name="email", type="string") 51 | * @SWG\Property(name="creation", type="DateTime::ISO8601") 52 | */ 53 | public $timestamps = false; 54 | 55 | protected $guarded = array('id'); 56 | 57 | protected $attributes = array( 58 | 'type' => 1, 59 | 'premdays' => 0, 60 | 'lastday' => 0 61 | ); 62 | 63 | public function getCreationAttribute() 64 | { 65 | $date = new DateTime(); 66 | $date->setTimestamp($this->attributes['creation']); 67 | return $date; 68 | } 69 | 70 | public function setCreationAttribute($d) 71 | { 72 | if($d instanceof \DateTime) 73 | $this->attributes['creation'] = $d->getTimestamp(); 74 | elseif((int) $d != (string) $d) { // it's not a UNIX timestamp 75 | $dt = new DateTime($d); 76 | $this->attributes['creation'] = $dt->getTimestamp(); 77 | } else // it is a UNIX timestamp 78 | $this->attributes['creation'] = $d; 79 | } 80 | 81 | public function players() 82 | { 83 | return $this->hasMany('DevAAC\Models\Player'); 84 | } 85 | 86 | public function setPasswordAttribute($pass) 87 | { 88 | if( !filter_var($pass, FILTER_VALIDATE_REGEXP, 89 | array("options" => array("regexp" => "/^[0-9a-f]{40}$/i"))) ) 90 | $pass = sha1($pass); 91 | 92 | $this->attributes['password'] = $pass; 93 | } 94 | 95 | public function comparePassword($pass) 96 | { 97 | return $this->password === sha1($pass); 98 | } 99 | 100 | public function isGod() 101 | { 102 | return $this->type >= ACCOUNT_TYPE_GOD; 103 | } 104 | 105 | public function isGameMaster() 106 | { 107 | return $this->type >= ACCOUNT_TYPE_GAMEMASTER; 108 | } 109 | 110 | public function isSeniorTutor() 111 | { 112 | return $this->type >= ACCOUNT_TYPE_SENIORTUTOR; 113 | } 114 | 115 | public function isTutor() 116 | { 117 | return $this->type >= ACCOUNT_TYPE_TUTOR; 118 | } 119 | 120 | public function ban() 121 | { 122 | return $this->hasOne('DevAAC\Models\AccountBan'); 123 | } 124 | 125 | public function banHistory() 126 | { 127 | return $this->hasMany('DevAAC\Models\AccountBanHistory'); 128 | } 129 | 130 | public function houses() 131 | { 132 | return $this->hasManyThrough('DevAAC\Models\House', 'DevAAC\Models\Player', 'account_id', 'owner'); 133 | } 134 | 135 | public function houseBids() 136 | { 137 | return $this->hasManyThrough('DevAAC\Models\House', 'DevAAC\Models\Player', 'account_id', 'highest_bidder'); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /DevAAC/Models/House.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | namespace DevAAC\Models; 33 | 34 | use DevAAC\Helpers\DateTime; 35 | 36 | // https://github.com/illuminate/database/blob/master/Eloquent/Model.php 37 | // https://github.com/otland/forgottenserver/blob/master/schema.sql 38 | 39 | /** 40 | * @SWG\Model(required="['id','owner','paid','warnings','name','rent','town_id','bid','bid_end','highest_bidder','size','beds']") 41 | */ 42 | class House extends \Illuminate\Database\Eloquent\Model { 43 | /** 44 | * @SWG\Property(name="id", type="integer") 45 | * @SWG\Property(name="owner", type="integer") 46 | * @SWG\Property(name="paid", type="DateTime::ISO8601") 47 | * @SWG\Property(name="warnings", type="integer") 48 | * @SWG\Property(name="name", type="string") 49 | * @SWG\Property(name="rent", type="integer") 50 | * @SWG\Property(name="town_id", type="integer") 51 | * @SWG\Property(name="bid", type="integer") 52 | * @SWG\Property(name="bid_end", type="DateTime::ISO8601") 53 | * @SWG\Property(name="last_bid", type="integer") 54 | * @SWG\Property(name="highest_bidder", type="integer") 55 | * @SWG\Property(name="size", type="integer") 56 | * @SWG\Property(name="beds", type="integer") 57 | */ 58 | public $timestamps = false; 59 | 60 | protected $guarded = array('id'); 61 | 62 | protected $hidden = array('last_bid', 'town'); 63 | 64 | protected $appends = array('town_name'); 65 | 66 | public function owner() 67 | { 68 | return $this->belongsTo('DevAAC\Models\Player', 'owner'); 69 | } 70 | 71 | public function town() 72 | { 73 | return $this->belongsTo('DevAAC\Models\Town'); 74 | } 75 | 76 | public function getTownNameAttribute() 77 | { 78 | return $this->town ? $this->town->name : null; 79 | } 80 | 81 | public function getPaidAttribute() 82 | { 83 | if($this->attributes['paid'] === 0) 84 | return 0; 85 | 86 | $date = new DateTime(); 87 | $date->setTimestamp($this->attributes['paid']); 88 | return $date; 89 | } 90 | 91 | public function setPaidAttribute($d) 92 | { 93 | if($d instanceof \DateTime) 94 | $this->attributes['paid'] = $d->getTimestamp(); 95 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 96 | $dt = new DateTime($d); 97 | $this->attributes['paid'] = $dt->getTimestamp(); 98 | } else // it is a UNIX timestamp 99 | $this->attributes['paid'] = $d; 100 | } 101 | 102 | public function getBidEndAttribute() 103 | { 104 | if($this->attributes['bid_end'] === 0) 105 | return 0; 106 | 107 | $date = new DateTime(); 108 | $date->setTimestamp($this->attributes['bid_end']); 109 | return $date; 110 | } 111 | 112 | public function setBidEndAttribute($d) 113 | { 114 | if($d instanceof \DateTime) 115 | $this->attributes['bid_end'] = $d->getTimestamp(); 116 | elseif((int)$d != (string)$d) { // it's not a UNIX timestamp 117 | $dt = new DateTime($d); 118 | $this->attributes['bid_end'] = $dt->getTimestamp(); 119 | } else // it is a UNIX timestamp 120 | $this->attributes['bid_end'] = $d; 121 | } 122 | 123 | public function highestBidder() 124 | { 125 | return $this->belongsTo('DevAAC\Models\Player', 'highest_bidder'); 126 | } 127 | 128 | public function lists() 129 | { 130 | return $this->hasMany('DevAAC\Models\HouseList'); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /public_html/modules/houses/houses.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.when('/houses', { 4 | templateUrl: PageUrl('houses'), 5 | controller: 'HousesController', 6 | resolve: { 7 | info: function(Server) { 8 | return Server.info().$promise; 9 | } 10 | } 11 | }); 12 | $routeProvider.when('/houses/:id', { 13 | templateUrl: PageUrl('houses/house'), 14 | controller: 'HouseController', 15 | resolve: { 16 | info: function(Server) { 17 | return Server.info().$promise; 18 | }, 19 | house: function(House, $route) { 20 | return House.get({id: $route.current.params.id}).$promise; 21 | } 22 | } 23 | }); 24 | }]); 25 | 26 | // Module Controller(s) 27 | DevAAC.controller('HouseController', ['$scope', '$routeParams', '$location', 'House', 'Player', 'Server', 'info', 'house', 28 | function($scope, $routeParams, $location, House, Player, Server, info, house) { 29 | $scope.isLoggedIn = false; 30 | $scope.statusmsg = { 31 | type: 'danger', 32 | msg: '' 33 | }; 34 | $scope.info = info; 35 | $scope.house = house; 36 | $scope.ends = moment(house.bid_end).fromNow(); 37 | 38 | // Fetch house owner 39 | if(house.owner) { 40 | $scope.owner = { 41 | name: 'Loading...' 42 | }; 43 | 44 | $scope.owner = Player.get({id:house.owner}, function(){}, function(response) { 45 | if (response.status === 404) 46 | $scope.player = { 47 | name: '[Deleted Player]' 48 | } 49 | }); 50 | } 51 | 52 | if(house.highest_bidder) 53 | $scope.highest_bidder = Player.get({id: house.highest_bidder}, function(){}, function(response) { 54 | if (response.status === 404) 55 | $scope.highest_bidder = { 56 | name: '[Deleted Player]' 57 | } 58 | }); 59 | 60 | $scope.bidForm = { 61 | player: false, 62 | bid: $scope.house.bid + $scope.info.houses_bid_raise, 63 | balance: 0, 64 | canBid : false 65 | }; 66 | 67 | $scope.players = Player.my({}, function(players) { 68 | $scope.isLoggedIn = true; 69 | try { 70 | $scope.bidForm.player = _.find($scope.players, function(p) { 71 | return (p.balance >= $scope.bidForm.bid + $scope.house.rent) 72 | }).name; 73 | } catch(e) {} 74 | $scope.checkBalance($scope.bidForm.player); 75 | }); 76 | 77 | $scope.createBid = function() { 78 | // Find player 79 | for (var i = 0; i < $scope.players.length; i++) { 80 | if ($scope.players[i].name == $scope.bidForm.player) { 81 | var bid = { 82 | id: $scope.house.id, 83 | player_id: $scope.players[i].id, 84 | bid: $scope.bidForm.bid 85 | }; 86 | var house = House.get({id: bid.id}); 87 | house.$bid({id: bid.id, player_id: bid.player_id, bid: bid.bid}, function(house) { 88 | $scope.statusmsg.type = 'success'; 89 | $scope.statusmsg.msg = 'You now have the highest pledge on this house!'; 90 | }, function(response) { 91 | $scope.statusmsg.type = 'danger'; 92 | $scope.statusmsg.msg = response.data.message; 93 | }); 94 | } 95 | } 96 | }; 97 | 98 | $scope.checkBalance = function(playername) { 99 | // Required balance to bid 100 | var requiredBalance = $scope.house.bid + $scope.house.rent; 101 | // Find player 102 | for (var i = 0; i < $scope.players.length; i++) { 103 | if ($scope.players[i].name == playername) { 104 | $scope.bidForm.balance = $scope.players[i].balance; 105 | $scope.bidForm.canBid = (requiredBalance < $scope.players[i].balance); 106 | break; 107 | } 108 | } 109 | }; 110 | } 111 | ]); 112 | 113 | DevAAC.controller('HousesController', ['$scope', 'House', 'Player', 'Server', 'info', 114 | function($scope, House, Player, Server, info) { 115 | $scope.info = info; 116 | $scope.houses = House.query(function(){ 117 | $scope.loaded = true; 118 | }); 119 | 120 | $scope.order = 'size'; 121 | $scope.orderReverse = true; 122 | $scope.players = []; 123 | 124 | $scope.player = function(id) { 125 | if(id == 0) 126 | return; 127 | 128 | if($scope.players[id] == undefined) 129 | $scope.players[id] = Player.get({id: id}); 130 | 131 | return $scope.players[id]; 132 | }; 133 | 134 | $scope.fromNow = function(time) { 135 | return moment(time).fromNow(); 136 | }; 137 | } 138 | ]); 139 | 140 | // Module Factories(s) 141 | DevAAC.factory('House', ['$resource', 142 | function($resource){ 143 | return $resource(ApiUrl('houses/:id'), {}, { 144 | get: { cache: true }, 145 | query: { isArray: true, cache: true }, 146 | bid: { url: ApiUrl('houses/:id/bid'), method: 'POST' } 147 | }); 148 | } 149 | ]); -------------------------------------------------------------------------------- /public_html/DevAAC.js: -------------------------------------------------------------------------------- 1 | function PageUrl(module) { 2 | module = module.split('/'); 3 | if (module.length == 1) return '/modules/' + module[0] + '/' + module[0] + '.html'; 4 | else return '/modules/' + module[0] + '/' + module[1] + '.html'; 5 | } 6 | function ApiUrl(link) { 7 | // window.location.host typically includes port 8 | return window.location.protocol + '//' + window.location.host + '/api/v1/' + link; 9 | } 10 | 11 | var Cookie = { 12 | set: function (cname, cvalue, exdays) { 13 | var d = new Date(); 14 | d.setTime( d.getTime() + (exdays*24*60*60*1000) ); 15 | var expires = 'expires=' + d.toUTCString(); 16 | document.cookie = cname + '=' + cvalue + '; ' + expires; 17 | }, 18 | get: function (cname) { 19 | var name = cname + '='; 20 | var ca = document.cookie.split(';'); 21 | var value = false; 22 | for(var i=0; i 131 | DevAAC.directive('ngConfirmClick', [function () { 132 | return { 133 | priority: -1, 134 | restrict: 'A', 135 | link: function (scope, element, attrs) { 136 | element.bind('click', function (e) { 137 | var message = attrs.ngConfirmClick; 138 | if (message && !confirm(message)) { 139 | e.stopImmediatePropagation(); 140 | e.preventDefault(); 141 | } 142 | }); 143 | } 144 | } 145 | }]); 146 | 147 | DevAAC.filter('markdown', function($sce) { 148 | var converter = new Showdown.converter(); 149 | return function(input) { 150 | if(input) 151 | return $sce.trustAsHtml(converter.makeHtml(input)) 152 | }; 153 | }); 154 | 155 | DevAAC.filter('capitalize', function () { 156 | "use strict"; 157 | return function (input) { 158 | return input.charAt(0).toUpperCase() + input.slice(1); 159 | }; 160 | }); 161 | 162 | DevAAC.filter('moment', function () { 163 | return function(value, format) { 164 | return moment(value).format(format); 165 | }; 166 | }); 167 | 168 | DevAAC.filter('reverse', function() { 169 | return function(items) { 170 | return items.slice().reverse(); 171 | }; 172 | }); 173 | 174 | DevAAC.filter('htmlstring', function($sce) { 175 | return function(input) { 176 | if(input) 177 | return $sce.trustAsHtml(input.replace(/\\n/g, "
")) 178 | }; 179 | }); 180 | -------------------------------------------------------------------------------- /plugins/simple.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | use DevAAC\Models\Account; 33 | use DevAAC\Models\Player; 34 | 35 | $meta = array('name' => 'Simple AAC', 36 | 'description' => 'Dead simple one-page AAC', 37 | 'version' => '1.0', 38 | 'author' => 'Don Daniello', 39 | 'link' => 'https://github.com/DevelopersPL/DevAAC' 40 | ); 41 | 42 | if( !in_array(basename(__FILE__), $DevAAC->enabled_plugins) ) 43 | return array_merge($meta, array('enabled' => false)); 44 | 45 | $DevAAC->map(ROUTES_PREFIX.'/', function() use($DevAAC) { 46 | $view = $DevAAC->view(); 47 | $view->setTemplatesDirectory('../plugins/templates'); 48 | $req = $DevAAC->request; 49 | 50 | $data = array(); 51 | $error = false; 52 | if($req->isPost()) { 53 | $data['val'] = $req->post(); 54 | 55 | // VALIDATE CHARACTER NAME 56 | if( !filter_var($req->post('character-name'), FILTER_VALIDATE_REGEXP, 57 | array("options" => array("regexp" => "/^[a-zA-Z ]{5,20}$/"))) ) { 58 | $DevAAC->flashNow('character-name_class', 'has-error'); 59 | $DevAAC->flashNow('danger', 'Character name must have 5-20 characters, only letters and space.'); 60 | $error = true; 61 | } 62 | 63 | // VALIDATE VOCATION 64 | if( ! in_array($req->post('vocation'), array(1, 2, 3, 4)) ) { 65 | $DevAAC->flashNow('vocation_class', 'has-error'); 66 | $error = true; 67 | } 68 | 69 | // VALIDATE SEX 70 | if( ! in_array($req->post('sex'), array(0, 1)) ) { 71 | $DevAAC->flashNow('sex_class', 'has-error'); 72 | $error = true; 73 | } 74 | 75 | // IF VALIDATION ERROR, EXIT 76 | if($error) 77 | goto render; 78 | 79 | $account = Account::where('name', $req->post('account-name'))->first(); 80 | 81 | // IF ACCOUNT EXISTS AND PASSWORD IS WRONG, EXIT 82 | if($account && !$account->comparePassword($req->post('password'))) { 83 | $DevAAC->flashNow('danger', 'This account already exists and password is not correct. Cannot add a character. 84 | Enter correct password or try a different account name.'); 85 | $DevAAC->flashNow('password_class', 'has-error'); 86 | goto render; 87 | } 88 | 89 | $name = ucwords(strtolower($req->post('character-name'))); 90 | // check if character name is available 91 | $player = Player::where('name', $name)->first(); 92 | if($player) { 93 | $DevAAC->flashNow('danger', 'This character already exists.'); 94 | $DevAAC->flashNow('character-name_class', 'has-error'); 95 | goto render; 96 | } 97 | 98 | // IF THE ACCOUNT EXISTS, JUMP TO CREATING PLAYER 99 | if($account) 100 | goto createcharacter; 101 | 102 | // VALIDATE ACCOUNT NAME ONLY IF THE ACCOUNT DOES NOT EXIST 103 | if( !filter_var($req->post('account-name'), FILTER_VALIDATE_REGEXP, 104 | array("options" => array("regexp" => "/^[a-zA-Z]{2,12}$/"))) ) { 105 | $DevAAC->flashNow('account-name_class', 'has-error'); 106 | $DevAAC->flashNow('danger', 'Account name must have 2-12 characters, only letters.'); 107 | $error = true; 108 | } 109 | 110 | // VALIDATE PASSWORD ONLY IF THE ACCOUNT DOES NOT EXIST 111 | if( !filter_var($req->post('password'), FILTER_VALIDATE_REGEXP, 112 | array("options" => array("regexp" => "/^.{6,20}$/"))) ) { 113 | $DevAAC->flashNow('password_class', 'has-error'); 114 | $DevAAC->flashNow('danger', 'Password must have 6-20 characters.'); 115 | $error = true; 116 | } 117 | 118 | // VALIDATE EMAIL ONLY IF THE ACCOUNT DOES NOT EXIST 119 | if( !filter_var($req->post('email'), FILTER_VALIDATE_EMAIL) ) { 120 | $DevAAC->flashNow('email_class', 'has-error'); 121 | $DevAAC->flashNow('danger', 'Enter valid email address'); 122 | $error = true; 123 | } 124 | 125 | // IF VALIDATION ERROR, EXIT 126 | if($error) 127 | goto render; 128 | 129 | // IF ACCOUNT DOES NOT EXIST, CREATE IT NOW 130 | $account = DevAAC\Models\Account::create( array('name' => $req->post('account-name'), 131 | 'password' => $req->post('password'), 132 | 'email' => $req->post('email'), 133 | 'creation' => time()) ); 134 | 135 | createcharacter: 136 | $player = new DevAAC\Models\Player(); 137 | $player->account()->associate($account); 138 | $player->name = $name; 139 | $player->vocation = $req->post('vocation'); 140 | $player->sex = $req->post('sex'); 141 | $player->town_id = 1; 142 | $player->level = 8; 143 | $player->push(); // SAVE PLAYER AND ASSOCIATED OBJECTS (ACCOUNT IN THIS CASE) 144 | 145 | $DevAAC->flashNow('success', 'Player '.ucwords(strtolower($req->post('character-name'))).' has been created!'); 146 | } 147 | 148 | render: 149 | $DevAAC->render('simple.php', $data); 150 | 151 | })->via('GET', 'POST'); 152 | 153 | return array_merge($meta, array('enabled' => true)); 154 | -------------------------------------------------------------------------------- /public_html/modules/about/about.html: -------------------------------------------------------------------------------- 1 |

About this server

2 | 3 |

Server rules

4 |

By creating or using an account, you agree with terms and conditions below.

5 |

No cheating allowed.

6 |

No botting allowed.

7 |

The staff reserve rights to modify, remove or discontinue services without further notice.

8 |

You agree to use our services at your sole risk. We disclaim all warranties or conditions of any kind.

9 |

By accepting these rules you allow us to use your submitted information (including logging your IP and sharing personal information with authorities).

10 |

We provide services "as is". We are not liable for any lost profits or damages arising out of using our services.

11 |

This website uses cookies to let you register and manage your account. You may disable them in your browser settings.

12 | 13 |

Statistics

14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
Players Online{{info.players_online_count}}
Record of Players Online{{(config | filter: {config: 'players_record'})[0].value}}
# of Players{{info.players_count}}
# of Accounts{{info.accounts_count}}
# of Players per Account{{info.players_count / info.accounts_count | number: 2}}
# of Guilds{{info.guilds_count}}
# of Players per Guild{{info.players_count / info.guilds_count | number: 2}}
# of Houses{{info.houses_count}}
# of Players per House{{info.players_count / info.houses_count | number: 2}}
# of MOTDs{{(config | filter: {config: 'motd_num'})[0].value}}
26 | 27 |

Extended server information

28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
Server Name{{info.serverName}}
IP{{info.ip}}
Port{{info.loginProtocolPort}}
World Type:{{info.worldType | uppercase}}
Server Owner:{{info.ownerName}}
Owner Email:{{info.ownerEmail}}
Server Location:{{info.location}}
37 | 38 |

Vocation Balance

39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 82 | 112 | 113 | 114 |
VocationConfiguration
{{vocation.name}} 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
ParameterValue
Promoted from{{(vocations | filter: {id: vocation.fromvoc})[0].name}}
Attack Speed{{vocation.attackspeed}}
Base Speed{{vocation.basespeed}}
Max Soul{{vocation.soulmax}}
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
TypeRegeneration Speed
HP{{vocation.gainhpamount}} HP / {{vocation.gainhpticks}} seconds
Mana{{vocation.gainmanaamount}} MP / {{vocation.gainmanaticks}} seconds
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 |
TypeIncrease per level
HP{{vocation.gainhp}} / level
Mana{{vocation.gainmana}} / level
Cap{{vocation.gaincap}} / level
81 |
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 |
Attack/DefenseMultiplier in hits/defense
Melee Damage{{vocation.formula.meleeDamage}}x
Distance Damage{{vocation.formula.distDamage}}x
Defense{{vocation.formula.defense}}x
Armor{{vocation.formula.armor}}x
95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 |
SkillMultiplier in advances
Fist{{skill.multiplier}}x
Club{{skill.multiplier}}x
Sword{{skill.multiplier}}x
Axe{{skill.multiplier}}x
Distance{{skill.multiplier}}x
Shield{{skill.multiplier}}x
Fishing{{skill.multiplier}}x
Magic{{vocation.manamultiplier}}x
111 |
115 | -------------------------------------------------------------------------------- /public_html/modules/houses/house.html: -------------------------------------------------------------------------------- 1 |
2 |

House: Loading...{{house.name}}

3 |
{{statusmsg.msg}}
4 |
5 |
6 |
7 |
8 |
Size
9 |
10 | {{house.size}} sqm 11 |
12 |
13 |
14 |
15 |
16 |
Beds
17 |
18 | {{house.beds}} beds 19 |
20 |
21 |
22 |
23 |
24 |
{{ info.houseRentPeriod == 'never' ? 'Price' : 'Rent' }}
25 |
26 | {{house.rent | number}} gp 27 |
28 |
29 |
30 |
31 |
32 |
Town
33 |
34 | {{house.town_name || house.town_id}} 35 |
36 |
37 |
38 |
39 | 40 |
41 |

This house is owned by {{owner.name}}

42 |
43 | 44 |
45 |
46 |
47 |

This house is available for auction

48 |

Auction is in progress! Ends {{ ends }}.

49 |

This house is available for purchase!

50 |
51 | 52 |
53 |
54 |
55 | Highest bid: {{house.bid | number}} gp by by: {{highest_bidder.name}} 56 |
57 |
58 | 59 |
60 |
61 |
62 | 63 |
64 | 67 |
68 |
69 | 70 |
71 |
72 |
73 | 74 | gp 75 |
76 |
77 |
78 |
79 | 80 |
81 |
82 | 83 | gp 84 |
85 |
86 |
87 |
88 | + 89 | 90 |
91 |
92 |
93 |
94 | = 95 | 96 |
97 |
98 |
99 |
100 |
101 | 102 | 103 |
104 |
105 |
106 |
107 | 108 |

You need to be logged in to bid on this house.

109 | 110 |

Stand in front of the house entrance and type !buyhouse in game to buy the house.

111 |
112 |
113 |
114 |
115 |
116 | -------------------------------------------------------------------------------- /public_html/modules/account/account.js: -------------------------------------------------------------------------------- 1 | // Module Route(s) 2 | DevAAC.config(['$routeProvider', function($routeProvider) { 3 | $routeProvider.when('/account', { 4 | // When a module contains multiple routes, use 'moduleName/viewName' in PageUrl function. 5 | templateUrl: PageUrl('account/account'), 6 | controller: 'AccountController', 7 | resolve: { 8 | account: function(Account) { 9 | return Account.factory.my().$promise; 10 | }, 11 | vocations: function(Server) { 12 | return Server.vocations().$promise; 13 | }, 14 | info: function(Server) { 15 | return Server.info().$promise; 16 | } 17 | } 18 | }); 19 | 20 | $routeProvider.when('/account/register', { 21 | templateUrl: PageUrl('account/register'), 22 | controller: 'RegisterController' 23 | }); 24 | }]); 25 | 26 | // Module Controller(s) 27 | DevAAC.controller('RegisterController', ['$scope', '$location', 'Account', 28 | function($scope, $location, Account) { 29 | $scope.form = { 30 | name : '', 31 | email : '', 32 | password : '', 33 | passwordAgain : '' 34 | }; 35 | $scope.errorMessage = ''; 36 | 37 | $scope.registerAccount = function() { 38 | $scope.errorMessage = ''; 39 | 40 | if ($scope.form.password !== $scope.form.passwordAgain) 41 | return $scope.errorMessage = "Passwords don't match!"; 42 | 43 | Account.register($scope.form).$promise.then( 44 | function(data) { 45 | $scope.form.name = ''; 46 | $scope.form.email = ''; 47 | $scope.form.password = ''; 48 | $scope.form.passwordAgain = ''; 49 | $location.path('/account'); 50 | }, 51 | function(error) { 52 | console.log(error); 53 | $scope.errorMessage = error.statusText + ': ' + error.data.message; 54 | } 55 | ); 56 | } 57 | } 58 | ]); 59 | 60 | DevAAC.controller('AccountController', ['$scope', '$location', '$cacheFactory', 'Account', 'Player', 'vocations', 'account', 'info', 61 | function($scope, $location, $cacheFactory, Account, Player, vocations, account, info) { 62 | $scope.creatingPlayer = false; 63 | $scope.errorMessage = ''; 64 | $scope.successMessage = ''; 65 | $scope.account = account; 66 | $scope.players = Player.my(); 67 | $scope.available_vocations = []; 68 | $scope.newPlayer = { 69 | name: '', 70 | vocation: 1, 71 | sex: 1 72 | }; 73 | $scope.pwd = { 74 | password : '', 75 | passwordAgain : '' 76 | }; 77 | 78 | $scope.vocation = function(id) { 79 | return _.findWhere(vocations, {id: id}); 80 | }; 81 | 82 | for (var i = 0; i < info.allowed_vocations.length; i++) 83 | $scope.available_vocations.push({id: info.allowed_vocations[i], name: $scope.vocation(info.allowed_vocations[i]).name}); 84 | 85 | $scope.createPlayer = function() { 86 | Player.save($scope.newPlayer, function(data) { 87 | $scope.players.push(data); 88 | $scope.successMessage = 'Player has been created!'; 89 | $scope.errorMessage = ''; 90 | $scope.creatingPlayer = false; 91 | $cacheFactory.get('$http').remove(ApiUrl('accounts/my/players')); 92 | }, function(error) { 93 | $scope.successMessage = ''; 94 | $scope.errorMessage = 'Failed to created player. ' + error.data.message; 95 | $scope.creatingPlayer = false; 96 | }); 97 | }; 98 | 99 | $scope.remove = function(id) { 100 | Player.delete({id: id}, function(data, status) { 101 | $scope.players = _.filter($scope.players, function(p) {return p.id != id}); 102 | $scope.successMessage = 'Player has been deleted!'; 103 | $scope.errorMessage = ''; 104 | $scope.creatingPlayer = false; 105 | $cacheFactory.get('$http').remove(ApiUrl('accounts/my/players')); 106 | }, function(error) { 107 | $scope.successMessage = ''; 108 | $scope.errorMessage = 'Failed to delete player. ' + error.data.message; 109 | $scope.creatingPlayer = false; 110 | }); 111 | }; 112 | 113 | $scope.changePassword = function() { 114 | if ($scope.pwd.password !== $scope.pwd.passwordAgain) 115 | return $scope.errorMessage = "Passwords don't match!"; 116 | 117 | Account.factory.update({id: $scope.account.id}, $scope.pwd, function(data) { 118 | $scope.successMessage = 'Password has been updated!'; 119 | $scope.errorMessage = ''; 120 | $scope.changingPassword = false; 121 | Cookie.set('DevAACToken', Account.generateToken($scope.account.name, $scope.pwd.password), 7); 122 | }, function(error) { 123 | $scope.successMessage = ''; 124 | $scope.errorMessage = 'Failed to change password. ' + error.data.message; 125 | $scope.changingPassword = false; 126 | }); 127 | } 128 | } 129 | ]); 130 | 131 | // Module Factories(s) 132 | DevAAC.factory('Account', ['$http', '$resource', '$cacheFactory', 133 | function($http, $resource, $cacheFactory) { 134 | var token; 135 | 136 | return { 137 | generateToken: function(username, password) { 138 | var p = new jsSHA(password, 'TEXT'); 139 | return btoa(username + ':' + p.getHash('SHA-1', 'HEX')); 140 | }, 141 | register: function(account) { 142 | var self = this; 143 | return this.factory.save(account, function (data, status) { 144 | Cookie.set('DevAACToken', self.generateToken(account.name, account.password), 7); 145 | }); 146 | }, 147 | authenticate: function(account, password) { 148 | token = this.generateToken(account, password); 149 | return $http({ 150 | url: ApiUrl('accounts/my'), 151 | method: 'GET', 152 | headers: { Authorization: 'Basic ' + token } 153 | }) 154 | .success(function (data, status) { 155 | Cookie.set('DevAACToken', token, 7); 156 | }); 157 | }, 158 | logout: function() { 159 | Cookie.set('DevAACToken', '', 1); 160 | $cacheFactory.get('$http').removeAll(); 161 | }, 162 | factory: $resource(ApiUrl('accounts/:id'), {}, { 163 | my: { params: {id: 'my'}, cache: true }, 164 | get: { cache: true }, 165 | query: { isArray: true, cache: true }, 166 | update: { method: 'PUT' }, 167 | recover: { url: ApiUrl('accounts/my/lost'), method: 'POST' } 168 | }) 169 | } 170 | } 171 | ]); -------------------------------------------------------------------------------- /plugins/templates/simple.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | OTS 10 | 11 | 12 | 13 | 14 | 15 | 44 | 45 | 46 |
47 |
48 |
49 | 50 |
51 |

Hello!

52 |

Here you can easily create your account and a character! If you already have an account, 53 | fill in your current details and a new character will be added to your account!

54 |
55 | 56 | ' . $flash['success'] . '
'; 59 | if($flash['info']) 60 | echo '
' . $flash['info'] . '
'; 61 | if($flash['danger']) 62 | echo '
' . $flash['danger'] . '
'; 63 | ?> 64 | 65 |
66 |
67 | 68 |
69 | 70 |
71 |
72 |
73 | 74 |
75 | 76 |
77 |
78 |
79 | 80 |
81 | 82 |
83 |
84 |
85 |
86 | 87 |
88 | 89 |
90 |
91 |
92 | 93 |
94 |
95 | 99 |
100 |
101 | 105 |
106 |
107 |
108 |
109 | 110 |
111 |
112 | 116 |
117 |
118 | 122 |
123 |
124 | 128 |
129 |
130 | 134 |
135 |
136 |
137 | 138 |
139 |
140 | 141 |
142 |
143 |
144 | 145 | 148 | 149 |
150 |
151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /DevAAC/routes/houses.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | use DevAAC\Models\House; 33 | use DevAAC\Models\Player; 34 | 35 | /** 36 | * @SWG\Resource( 37 | * basePath="/api/v1", 38 | * resourcePath="/houses", 39 | * @SWG\Api( 40 | * path="/houses", 41 | * description="Operations on houses", 42 | * @SWG\Operation( 43 | * summary="Get all houses", 44 | * notes="", 45 | * method="GET", 46 | * type="House", 47 | * nickname="getHouses" 48 | * ) 49 | * ) 50 | * ) 51 | */ 52 | $DevAAC->get(ROUTES_API_PREFIX.'/houses', function() use($DevAAC) { 53 | $houses = House::all(); 54 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 55 | $DevAAC->response->setBody($houses->toJson(JSON_PRETTY_PRINT)); 56 | }); 57 | 58 | /** 59 | * @SWG\Resource( 60 | * basePath="/api/v1", 61 | * resourcePath="/houses", 62 | * @SWG\Api( 63 | * path="/houses/{id}", 64 | * description="Operations on houses", 65 | * @SWG\Operation( 66 | * summary="Get house based on ID or name", 67 | * method="GET", 68 | * type="House", 69 | * nickname="getHouseByID", 70 | * @SWG\Parameter( name="id", 71 | * description="ID of House that needs to be fetched", 72 | * paramType="path", 73 | * required=true, 74 | * type="integer"), 75 | * @SWG\Parameter( name="embed", 76 | * description="Pass lists to embed an array of list objects", 77 | * paramType="query", 78 | * required=false, 79 | * type="string list separated by comma"), 80 | * @SWG\ResponseMessage(code=404, message="House not found") 81 | * ) 82 | * ) 83 | * ) 84 | */ 85 | $DevAAC->get(ROUTES_API_PREFIX.'/houses/:id', function($id) use($DevAAC) { 86 | $req = $DevAAC->request; 87 | $house = House::findOrFail($id); 88 | 89 | if ($req->get('embed') == 'lists') 90 | $house->lists; 91 | 92 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 93 | $DevAAC->response->setBody($house->toJson(JSON_PRETTY_PRINT)); 94 | }); 95 | 96 | /** 97 | * @SWG\Resource( 98 | * basePath="/api/v1", 99 | * resourcePath="/houses", 100 | * @SWG\Api( 101 | * path="/houses/{id}/lists", 102 | * description="Operations on houses", 103 | * @SWG\Operation( 104 | * summary="Get house lists based on ID or name", 105 | * method="GET", 106 | * type="array[HouseList]", 107 | * nickname="getHouseListsByID", 108 | * @SWG\Parameter( name="id", 109 | * description="ID of House that lists needs to be fetched", 110 | * paramType="path", 111 | * required=true, 112 | * type="integer"), 113 | * @SWG\ResponseMessage(code=404, message="House not found") 114 | * ) 115 | * ) 116 | * ) 117 | */ 118 | $DevAAC->get(ROUTES_API_PREFIX.'/houses/:id/lists', function($id) use($DevAAC) { 119 | $house = House::findOrFail($id); 120 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 121 | $DevAAC->response->setBody($house->lists->toJson(JSON_PRETTY_PRINT)); 122 | }); 123 | 124 | /** 125 | * @SWG\Resource( 126 | * basePath="/api/v1", 127 | * resourcePath="/houses", 128 | * @SWG\Api( 129 | * path="/houses/{id}/bid", 130 | * description="Operations on houses", 131 | * @SWG\Operation( 132 | * summary="Bid on house by ID", 133 | * notes="Admins can bid with any player", 134 | * method="POST", 135 | * type="House", 136 | * nickname="bidHouseByID", 137 | * @SWG\Parameter( name="id", 138 | * description="ID of House to bid on", 139 | * paramType="path", 140 | * required=true, 141 | * type="integer"), 142 | * @SWG\Parameter( name="player_id", 143 | * description="ID of player which bids", 144 | * paramType="form", 145 | * required=true, 146 | * type="integer"), 147 | * @SWG\Parameter( name="bid", 148 | * description="the amount of bid", 149 | * paramType="form", 150 | * required=true, 151 | * type="integer"), 152 | * @SWG\ResponseMessage(code=400, message="Bad request"), 153 | * @SWG\ResponseMessage(code=401, message="Not logged in"), 154 | * @SWG\ResponseMessage(code=402, message="Not enough money in player's bank"), 155 | * @SWG\ResponseMessage(code=403, message="Player not on authenticated account"), 156 | * @SWG\ResponseMessage(code=404, message="House not found / player not found"), 157 | * @SWG\ResponseMessage(code=405, message="Exceeded limit of houses per player/account"), 158 | * @SWG\ResponseMessage(code=409, message="The bid is too low"), 159 | * @SWG\ResponseMessage(code=410, message="Auction has ended"), 160 | * @SWG\ResponseMessage(code=412, message="House not on auction") 161 | * ) 162 | * ) 163 | * ) 164 | */ 165 | $DevAAC->post(ROUTES_API_PREFIX.'/houses/:id/bid', function($id) use($DevAAC) { 166 | if(!HOUSES_AUCTIONS) 167 | throw new InputErrorException('House auctions are disabled.', 400); 168 | 169 | if( ! $DevAAC->auth_account ) 170 | throw new InputErrorException('You are not logged in.', 401); 171 | 172 | $request = $DevAAC->request; 173 | $house = House::findOrFail($id); 174 | 175 | if($house->owner()->first() instanceof Player) 176 | throw new InputErrorException('This house is not on auction, '.$house->owner()->first()->name.' owns it.', 412); 177 | 178 | if($house->bid_end !== 0 && new DateTime() > $house->bid_end) 179 | throw new InputErrorException('Auction has ended.', 410); 180 | 181 | if($request->getAPIParam('bid') < $house->bid + HOUSES_BID_RAISE 182 | || $request->getAPIParam('bid') < $house->bid + $house->bid * HOUSES_BID_RAISE_PERCENT) 183 | throw new InputErrorException('The bid is too low! You need to offer at least '.max($house->bid + HOUSES_BID_RAISE, 184 | $house->bid + $house->bid * HOUSES_BID_RAISE_PERCENT), 409); 185 | 186 | $player = Player::findOrFail($request->getAPIParam('player_id')); 187 | 188 | if($player->account->id != $DevAAC->auth_account->id && !$DevAAC->auth_account->isGod()) 189 | throw new InputErrorException('You do not have permission to bid with this player.', 403); 190 | 191 | if( $house->highest_bidder != $player->id && count($player->houses()->get()->toArray()) + count($player->houseBids()->get()->toArray()) >= HOUSES_PER_PLAYER ) 192 | throw new InputErrorException('Your player already owns or participates in an auction for a maximum number of houses ('.HOUSES_PER_PLAYER.')!', 405); 193 | 194 | if( $house->highest_bidder != $player->id && count($player->account->houses()->get()->toArray()) + count($player->account->houseBids()->get()->toArray()) >= HOUSES_PER_ACCOUNT ) 195 | throw new InputErrorException('Your account already owns or participates in an auction for a maximum number of houses ('.HOUSES_PER_ACCOUNT.')!', 405); 196 | 197 | if($player->balance < $request->getAPIParam('bid') + $house->rent) 198 | throw new InputErrorException('You do not have enough money! You need the bid amount plus '.$house->rent.' for first rent payment.', 402); 199 | 200 | if ($request->getAPIParam('bid') > $house->last_bid) 201 | { // this is a winning bid, it is over previous winner's limit 202 | $house->highest_bidder = $player->id; // this would break JSON output: $house->highestBidder()->associate($player); 203 | $house->bid = $house->last_bid + 1; 204 | $house->last_bid = $request->getAPIParam('bid'); 205 | } elseif ($request->getAPIParam('bid') < $house->last_bid) 206 | { // this raises previous bid 207 | $house->bid = $request->getAPIParam('bid') + 1; 208 | } 209 | 210 | if($house->bid_end === 0) 211 | { 212 | $house->bid_end = new DateTime(); 213 | $house->bid_end = $house->bid_end->add(new DateInterval(HOUSES_AUCTION_TIME)); 214 | } 215 | 216 | $house->save(); 217 | 218 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 219 | $DevAAC->response->setBody($house->toJson(JSON_PRETTY_PRINT)); 220 | }); 221 | -------------------------------------------------------------------------------- /DevAAC/routes/server.php: -------------------------------------------------------------------------------- 1 | 25 | * @author Wojciech Guziak 26 | * @copyright 2014 Developers.pl 27 | * @license http://opensource.org/licenses/MIT MIT 28 | * @version master 29 | * @link https://github.com/DevelopersPL/DevAAC 30 | */ 31 | 32 | use \DevAAC\Models\ServerConfig; 33 | use \DevAAC\Models\Player; 34 | use \DevAAC\Models\IpBan; 35 | use Illuminate\Database\Capsule\Manager as Capsule; 36 | 37 | /** 38 | * @SWG\Resource( 39 | * basePath="/api/v1", 40 | * resourcePath="/server", 41 | * @SWG\Api( 42 | * path="/server/config", 43 | * description="Operations on server", 44 | * @SWG\Operation( 45 | * summary="Get server config values", 46 | * notes="", 47 | * method="GET", 48 | * type="ServerConfig", 49 | * nickname="getServerConfig" 50 | * ) 51 | * ) 52 | * ) 53 | */ 54 | $DevAAC->get(ROUTES_API_PREFIX.'/server/config', function() use($DevAAC) { 55 | $config = ServerConfig::all(); 56 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 57 | $DevAAC->response->setBody($config->toJson(JSON_PRETTY_PRINT)); 58 | }); 59 | 60 | /** 61 | * @SWG\Resource( 62 | * basePath="/api/v1", 63 | * resourcePath="/server", 64 | * @SWG\Api( 65 | * path="/server/ipBans", 66 | * description="Operations on server", 67 | * @SWG\Operation( 68 | * summary="Get IP bans", 69 | * notes="", 70 | * method="GET", 71 | * type="array[IpBan]", 72 | * nickname="getIPBans" 73 | * ) 74 | * ) 75 | * ) 76 | */ 77 | $DevAAC->get(ROUTES_API_PREFIX.'/server/ipBans', function() use($DevAAC) { 78 | $ipbans = IpBan::all(); 79 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 80 | $DevAAC->response->setBody($ipbans->toJson(JSON_PRETTY_PRINT)); 81 | }); 82 | 83 | /** 84 | * @SWG\Resource( 85 | * basePath="/api/v1", 86 | * resourcePath="/server", 87 | * @SWG\Api( 88 | * path="/server/ipBans", 89 | * description="Operations on server", 90 | * @SWG\Operation( 91 | * summary="Ban IP", 92 | * notes="Need to have admin rights
93 | * Do not provide banned_at in IpBan object - it will be ignored
94 | * The ID of player in banned_by must be of group_id > 1
95 | * expires_at defaults to 0 which means the ban does not expire", 96 | * method="POST", 97 | * type="IpBan", 98 | * nickname="banIP", 99 | * @SWG\Parameter( name="ban", 100 | * description="IpBan object", 101 | * paramType="body", 102 | * required=true, 103 | * type="IpBan"), 104 | * @SWG\ResponseMessage(code=403, message="IP address is not valid"), 105 | * @SWG\ResponseMessage(code=403, message="Permission denied"), 106 | * @SWG\ResponseMessage(code=404, message="banned_by player not found"), 107 | * @SWG\ResponseMessage(code=406, message="banned_by player group_id < 2 / banned_by player not on account"), 108 | * @SWG\ResponseMessage(code=409, message="IP is already banned") 109 | * ) 110 | * ) 111 | * ) 112 | */ 113 | $DevAAC->post(ROUTES_API_PREFIX.'/server/ipBans', function() use($DevAAC) { 114 | $req = $DevAAC->request; 115 | 116 | if(!$DevAAC->auth_account || !$DevAAC->auth_account->isGod()) 117 | throw new InputErrorException('You are not an admin.', 403); 118 | 119 | $ipban = IpBan::find(ip2long($req->getAPIParam('ip'))); 120 | if($ipban) 121 | throw new InputErrorException('This IP is already banned.', 409); 122 | 123 | if( !filter_var($req->getAPIParam('ip'), FILTER_VALIDATE_IP) ) 124 | throw new InputErrorException('IP address is not valid.', 400); 125 | 126 | $player = Player::find($req->getAPIParam('banned_by')); 127 | if(!$player) 128 | throw new InputErrorException('The banned_by player not found.', 404); 129 | 130 | if($player->account->id !== $DevAAC->auth_account->id) 131 | throw new InputErrorException('The banned_by player is not yours!', 406); 132 | 133 | if($player->group_id < 2) 134 | throw new InputErrorException('The banned_by player must have group_id > 1.', 406); 135 | 136 | $ban = new IpBan( 137 | array( 138 | 'ip' => $req->getAPIParam('ip'), 139 | 'reason' => $req->getAPIParam('reason'), 140 | 'banned_at' => new \DevAAC\Helpers\DateTime(), 141 | 'expires_at' => $req->getAPIParam('expires_at', 0), 142 | 'banned_by' => $player->id 143 | ) 144 | ); 145 | 146 | $ban->save(); 147 | 148 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 149 | $DevAAC->response->setBody($ban->toJson(JSON_PRETTY_PRINT)); 150 | }); 151 | 152 | /** 153 | * @SWG\Resource( 154 | * basePath="/api/v1", 155 | * resourcePath="/server", 156 | * @SWG\Api( 157 | * path="/server/ipBans/{ip}", 158 | * description="Operations on server", 159 | * @SWG\Operation( 160 | * summary="Delete IP ban", 161 | * notes="Need to have admin rights", 162 | * method="DELETE", 163 | * type="null", 164 | * nickname="deleteIPBan", 165 | * @SWG\Parameter( name="ip", 166 | * description="IP to lift ban", 167 | * paramType="path", 168 | * required=true, 169 | * type="string"), 170 | * @SWG\ResponseMessage(code=403, message="Permission denied"), 171 | * @SWG\ResponseMessage(code=404, message="IP is not banned") 172 | * ) 173 | * ) 174 | * ) 175 | */ 176 | $DevAAC->delete(ROUTES_API_PREFIX.'/server/ipBans/:ip', function($ip) use($DevAAC) { 177 | if(!$DevAAC->auth_account || !$DevAAC->auth_account->isGod()) 178 | throw new InputErrorException('You are not an admin', 403); 179 | 180 | $ipban = IpBan::find(ip2long($ip)); 181 | if(!$ipban) 182 | throw new InputErrorException('This IP is not banned.', 404); 183 | 184 | $ipban->delete(); 185 | 186 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 187 | $DevAAC->response->setBody(json_encode(null, JSON_PRETTY_PRINT)); 188 | }); 189 | 190 | /** 191 | * @SWG\Resource( 192 | * basePath="/api/v1", 193 | * resourcePath="/server", 194 | * @SWG\Api( 195 | * path="/server/info", 196 | * description="Operations on server", 197 | * @SWG\Operation( 198 | * summary="Get some information", 199 | * notes="The result of this call is cached, last refresh time is given as 'timestamp'", 200 | * method="GET", 201 | * type="array", 202 | * nickname="getServerInfo" 203 | * ) 204 | * ) 205 | * ) 206 | */ 207 | $DevAAC->get(ROUTES_API_PREFIX.'/server/info', function() use($DevAAC) { 208 | if(HAS_APC) 209 | $result = apc_fetch('server_info'); 210 | 211 | if(!HAS_APC || !$result) 212 | { 213 | $result = array( 214 | 'players_online_count' => Capsule::table('players_online')->count(), 215 | 'players_online' => Capsule::table('players')->join('players_online', 'players.id', '=', 'players_online.player_id')->select('players.name')->get(), 216 | 'players_count' => Capsule::table('players')->count(), 217 | 'accounts_count' => Capsule::table('accounts')->count(), 218 | 'guilds_count' => Capsule::table('guilds')->count(), 219 | 'guild_wars_count' => Capsule::table('guild_wars')->count(), 220 | 'houses_count' => Capsule::table('houses')->count(), 221 | 'allowed_vocations' => unserialize(ALLOWED_VOCATIONS), 222 | 223 | 'houses_auctions' => HOUSES_AUCTIONS, 224 | 'houses_bid_raise' => HOUSES_BID_RAISE, 225 | 'houses_bid_raise_percent' => HOUSES_BID_RAISE_PERCENT, 226 | 227 | // config.lua 228 | 'worldType' => $DevAAC->tfsConfigFile['worldType'], 229 | 'ip' => $DevAAC->tfsConfigFile['ip'], 230 | 'loginProtocolPort' => $DevAAC->tfsConfigFile['loginProtocolPort'], 231 | 'statusProtocolPort' => $DevAAC->tfsConfigFile['statusProtocolPort'], 232 | 'maxPlayers' => $DevAAC->tfsConfigFile['maxPlayers'], 233 | 'serverName' => $DevAAC->tfsConfigFile['serverName'], 234 | 'statusTimeout' => $DevAAC->tfsConfigFile['statusTimeout'], 235 | 'ownerName' => $DevAAC->tfsConfigFile['ownerName'], 236 | 'ownerEmail' => $DevAAC->tfsConfigFile['ownerEmail'], 237 | 'url' => $DevAAC->tfsConfigFile['url'], 238 | 'location' => $DevAAC->tfsConfigFile['location'], 239 | 'motd' => strip_tags($DevAAC->tfsConfigFile['motd']), 240 | 'houseRentPeriod' => $DevAAC->tfsConfigFile['houseRentPeriod'], 241 | 242 | // cache hint 243 | 'timestamp' => new \DevAAC\Helpers\DateTime() 244 | 245 | ); 246 | 247 | if(HAS_APC) 248 | apc_store('server_info', $result, 60); 249 | } 250 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 251 | $DevAAC->response->setBody(json_encode($result, JSON_PRETTY_PRINT)); 252 | }); 253 | 254 | /** 255 | * @SWG\Resource( 256 | * basePath="/api/v1", 257 | * resourcePath="/server", 258 | * @SWG\Api( 259 | * path="/server/vocations", 260 | * description="Operations on server", 261 | * @SWG\Operation( 262 | * summary="Get vocations", 263 | * notes="", 264 | * method="GET", 265 | * type="array", 266 | * nickname="getVocations" 267 | * ) 268 | * ) 269 | * ) 270 | */ 271 | $DevAAC->get(ROUTES_API_PREFIX.'/server/vocations', function() use($DevAAC) { 272 | $result = xml2array($DevAAC->vocations)['vocation']; 273 | $DevAAC->response->headers->set('Content-Type', 'application/json'); 274 | $DevAAC->response->setBody(json_encode($result, JSON_PRETTY_PRINT)); 275 | }); 276 | --------------------------------------------------------------------------------