├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── main.yml ├── .gitignore ├── README.md ├── phpstan ├── composer.json └── phpstan.neon.dist ├── plugin.yml └── src ├── BroadcastTask.php ├── ExampleListener.php └── MainClass.php /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | *.php text eol=lf 4 | *.neon text eol=lf 5 | 6 | # Custom for Visual Studio 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # Standard to msysgit 15 | *.doc diff=astextplain 16 | *.DOC diff=astextplain 17 | *.docx diff=astextplain 18 | *.DOCX diff=astextplain 19 | *.dot diff=astextplain 20 | *.DOT diff=astextplain 21 | *.pdf diff=astextplain 22 | *.PDF diff=astextplain 23 | *.rtf diff=astextplain 24 | *.RTF diff=astextplain 25 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | name: PHPStan analysis 11 | runs-on: ubuntu-22.04 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | php: 16 | - "8.1" 17 | - "8.2" 18 | - "8.3" 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - name: Setup PHP 24 | uses: pmmp/setup-php-action@3.2.0 25 | with: 26 | php-version: ${{ matrix.php }} 27 | install-path: "./bin" 28 | pm-version-major: 5 29 | 30 | - name: Restore Composer package cache 31 | id: composer-cache 32 | uses: actions/cache@v4 33 | with: 34 | path: "~/.cache/composer" 35 | key: "php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}" 36 | restore-keys: "php-${{ matrix.php }}-composer-" 37 | 38 | - name: Install PHPStan Composer dependencies 39 | working-directory: ./phpstan 40 | run: composer install --prefer-dist --no-interaction 41 | 42 | - name: Run PHPStan 43 | working-directory: ./phpstan 44 | run: vendor/bin/phpstan analyze 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | ################# 4 | ## Eclipse 5 | ################# 6 | 7 | *.pydevproject 8 | .project 9 | .metadata 10 | bin/ 11 | tmp/ 12 | *.tmp 13 | *.bak 14 | *.swp 15 | *~.nib 16 | local.properties 17 | .classpath 18 | .settings/ 19 | .loadpath 20 | 21 | # External tool builders 22 | .externalToolBuilders/ 23 | 24 | # Locally stored "Eclipse launch configurations" 25 | *.launch 26 | 27 | # CDT-specific 28 | .cproject 29 | 30 | # PDT-specific 31 | .buildpath 32 | 33 | 34 | ################# 35 | ## Visual Studio 36 | ################# 37 | 38 | ## Ignore Visual Studio temporary files, build results, and 39 | ## files generated by popular Visual Studio add-ons. 40 | 41 | # User-specific files 42 | *.suo 43 | *.user 44 | *.sln.docstates 45 | 46 | # Build results 47 | 48 | [Dd]ebug/ 49 | [Rr]elease/ 50 | x64/ 51 | build/ 52 | [Bb]in/ 53 | [Oo]bj/ 54 | 55 | # MSTest test Results 56 | [Tt]est[Rr]esult*/ 57 | [Bb]uild[Ll]og.* 58 | 59 | *_i.c 60 | *_p.c 61 | *.ilk 62 | *.meta 63 | *.obj 64 | *.pch 65 | *.pdb 66 | *.pgc 67 | *.pgd 68 | *.rsp 69 | *.sbr 70 | *.tlb 71 | *.tli 72 | *.tlh 73 | *.tmp 74 | *.tmp_proj 75 | *.log 76 | *.vspscc 77 | *.vssscc 78 | .builds 79 | *.pidb 80 | *.log 81 | *.scc 82 | 83 | # Visual C++ cache files 84 | ipch/ 85 | *.aps 86 | *.ncb 87 | *.opensdf 88 | *.sdf 89 | *.cachefile 90 | 91 | # Visual Studio profiler 92 | *.psess 93 | *.vsp 94 | *.vspx 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | *.ncrunch* 111 | .*crunch*.local.xml 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.Publish.xml 131 | *.pubxml 132 | 133 | # NuGet Packages Directory 134 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 135 | #packages/ 136 | 137 | # Windows Azure Build Output 138 | csx 139 | *.build.csdef 140 | 141 | # Windows Store app package directory 142 | AppPackages/ 143 | 144 | # Others 145 | sql/ 146 | *.Cache 147 | ClientBin/ 148 | [Ss]tyle[Cc]op.* 149 | ~$* 150 | *~ 151 | *.dbmdl 152 | *.[Pp]ublish.xml 153 | *.pfx 154 | *.publishsettings 155 | 156 | # RIA/Silverlight projects 157 | Generated_Code/ 158 | 159 | # Backup & report files from converting an old project file to a newer 160 | # Visual Studio version. Backup files are not needed, because we have git ;-) 161 | _UpgradeReport_Files/ 162 | Backup*/ 163 | UpgradeLog*.XML 164 | UpgradeLog*.htm 165 | 166 | # SQL Server files 167 | App_Data/*.mdf 168 | App_Data/*.ldf 169 | 170 | ############# 171 | ## Windows detritus 172 | ############# 173 | 174 | # Windows image file caches 175 | Thumbs.db 176 | ehthumbs.db 177 | 178 | # Folder config file 179 | Desktop.ini 180 | 181 | # Recycle Bin used on file shares 182 | $RECYCLE.BIN/ 183 | 184 | # Mac crap 185 | .DS_Store 186 | 187 | 188 | ############# 189 | ## Python 190 | ############# 191 | 192 | *.py[co] 193 | 194 | # Packages 195 | *.egg 196 | *.egg-info 197 | dist/ 198 | build/ 199 | eggs/ 200 | parts/ 201 | var/ 202 | sdist/ 203 | develop-eggs/ 204 | .installed.cfg 205 | 206 | # Installer logs 207 | pip-log.txt 208 | 209 | # Unit test / coverage reports 210 | .coverage 211 | .tox 212 | 213 | #Translations 214 | *.mo 215 | 216 | #Mr Developer 217 | .mr.developer.cfg 218 | 219 | /phpstan/vendor/ 220 | /phpstan/composer.lock 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExamplePlugin 2 | 3 | This repository contains a basic example of a modern PocketMine-MP plugin, and a handful of the API features. 4 | 5 | ## PHPStan analysis 6 | This repository shows an example setup for standalone local analysis of a plugin using [PHPStan](https://phpstan.org). 7 | 8 | It uses [Composer](https://getcomposer.org) for autoloading, allowing you to install PHPStan extensions such as [phpstan-strict-rules](https://github.com/phpstan/phpstan-strict-rules). The configuration for this can be seen in [`phpstan/composer.json`](/phpstan/composer.json). 9 | 10 | ### Setting up PHPStan 11 | Assuming you have Composer and a compatible PHP binary available in your PATH, run: 12 | ``` 13 | cd phpstan 14 | composer install 15 | ``` 16 | 17 | Then you can run PHPStan exactly as you would with any other project: 18 | ``` 19 | vendor/bin/phpstan analyze 20 | ``` 21 | 22 | ### Updating the dependencies 23 | ``` 24 | composer update 25 | ``` 26 | 27 | ### GitHub Actions 28 | You can find a workflow suitable for analysing most plugins using this system in [`.github/workflows/main.yml`](/.github/workflows/main.yml). 29 | -------------------------------------------------------------------------------- /phpstan/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pocketmine/phpstan-plugin-config", 3 | "require": { 4 | "pocketmine/pocketmine-mp": "5.0.0" 5 | }, 6 | "require-dev": { 7 | "phpstan/phpstan": "^1.10.0", 8 | "phpstan/phpstan-strict-rules": "^1.0", 9 | "phpstan/extension-installer": "^1.0" 10 | }, 11 | "autoload": { 12 | "psr-4": { 13 | "ExamplePlugin\\": "../src" 14 | } 15 | }, 16 | "config": { 17 | "allow-plugins": { 18 | "phpstan/extension-installer": true 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /phpstan/phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 9 3 | paths: 4 | - ../src 5 | -------------------------------------------------------------------------------- /plugin.yml: -------------------------------------------------------------------------------- 1 | #name, main, version and api are required 2 | name: ExamplePlugin 3 | main: ExamplePlugin\MainClass 4 | src-namespace-prefix: ExamplePlugin 5 | version: 1.4.1+dev 6 | api: 5.0.0 7 | 8 | load: POSTWORLD 9 | author: PocketMine Team 10 | description: Example plugin showing the new API 11 | website: https://github.com/pmmp/ExamplePlugin 12 | commands: 13 | example: 14 | description: Example command 15 | usage: "/example" 16 | permission: exampleplugin.command.example 17 | permissions: 18 | exampleplugin.command.example: 19 | description: "Allows the user to run the example command" 20 | default: true 21 | -------------------------------------------------------------------------------- /src/BroadcastTask.php: -------------------------------------------------------------------------------- 1 | server->broadcastMessage("[ExamplePlugin] I've run on tick " . $this->server->getTick()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ExampleListener.php: -------------------------------------------------------------------------------- 1 | plugin->getServer()->broadcastMessage($event->getPlayer()->getDisplayName() . " has just respawned!"); 41 | } 42 | 43 | /** 44 | * This runs after all other priorities. We mustn't cancel the event at MONITOR priority, we can only observe the 45 | * result. 46 | * 47 | * @priority MONITOR 48 | */ 49 | public function handlerNamesCanBeAnything(PlayerChatEvent $event) : void{ 50 | if(!$event->isCancelled()){ 51 | $this->plugin->getLogger()->info("Player " . $event->getPlayer()->getName() . " sent a message: " . $event->getMessage()); 52 | }else{ 53 | $this->plugin->getLogger()->info("Player " . $event->getPlayer()->getName() . " tried to send a message, but it was cancelled: " . $event->getMessage()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/MainClass.php: -------------------------------------------------------------------------------- 1 | getLogger()->info(TextFormat::WHITE . "I've been loaded!"); 16 | } 17 | 18 | public function onEnable() : void{ 19 | $this->getServer()->getPluginManager()->registerEvents(new ExampleListener($this), $this); 20 | $this->getScheduler()->scheduleRepeatingTask(new BroadcastTask($this->getServer()), 120); 21 | $this->getLogger()->info(TextFormat::DARK_GREEN . "I've been enabled!"); 22 | } 23 | 24 | public function onDisable() : void{ 25 | $this->getLogger()->info(TextFormat::DARK_RED . "I've been disabled!"); 26 | } 27 | 28 | public function onCommand(CommandSender $sender, Command $command, string $label, array $args) : bool{ 29 | switch($command->getName()){ 30 | case "example": 31 | $sender->sendMessage("Hello " . $sender->getName() . "!"); 32 | 33 | return true; 34 | default: 35 | throw new \AssertionError("This line will never be executed"); 36 | } 37 | } 38 | } 39 | --------------------------------------------------------------------------------