Skip to content

Commit 85dfee4

Browse files
authored
Merge pull request #6852 from pmmp/r5.36.0
R5.36.0
2 parents 8d5e6e7 + a3ea729 commit 85dfee4

File tree

77 files changed

+8188
-454
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+8188
-454
lines changed

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
*.cmd text eol=crlf
1010
*.ps1 text eol=crlf
1111

12+
# Not sure why these use CRLF, but keeping consistent with the old repository for now
13+
/resources/translations/*.ini text eol=crlf
14+
1215
# Custom for Visual Studio
1316
*.cs diff=csharp
1417
*.sln merge=union

.github/dependabot.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ updates:
77
time: "10:00"
88
open-pull-requests-limit: 10
99
ignore:
10-
#only allow patch updates for locale-data - this has to be updated manually due to codegen
11-
- dependency-name: pocketmine/locale-data
12-
update-types:
13-
- "version-update:semver-major"
14-
- "version-update:semver-minor"
15-
1610
#since we lock this to exact versions, it causes conflicts with minor-next & major-next in composer.lock
1711
#better to just test updates to this locally anyway since almost every version breaks something
1812
- dependency-name: phpstan/phpstan
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#Since GitHub automatically disables cron actions after 60 days of repo inactivity, we need the active repo (PM)
2+
#to trigger the branch merge workflow explicitly. This avoids the need for TOS-violating actions which we previously
3+
#used to keep the restricted action active, as the workflow depends on the activity of this repo anyway.
4+
5+
name: Trigger Crowdin download
6+
7+
on:
8+
schedule:
9+
- cron: "0 21 * * *"
10+
workflow_dispatch: #for testing
11+
12+
jobs:
13+
trigger:
14+
name: Trigger Crowdin download RestrictedActions workflow
15+
runs-on: ubuntu-22.04
16+
17+
steps:
18+
- name: Generate access token
19+
id: generate-token
20+
uses: actions/create-github-app-token@v2
21+
with:
22+
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
23+
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
24+
owner: ${{ github.repository_owner }}
25+
repositories: RestrictedActions
26+
27+
- name: Dispatch branch sync restricted action
28+
uses: peter-evans/repository-dispatch@v3
29+
with:
30+
token: ${{ steps.generate-token.outputs.token }}
31+
repository: ${{ github.repository_owner }}/RestrictedActions
32+
event-type: pocketmine_mp_crowdin_download
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Upload translations to Crowdin
2+
3+
on:
4+
push:
5+
paths:
6+
- resources/translations/eng.ini
7+
branches:
8+
- stable
9+
- minor-next
10+
- major-next
11+
workflow_dispatch:
12+
13+
jobs:
14+
upload:
15+
name: Upload translations
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Generate access token
20+
id: generate-token
21+
uses: actions/create-github-app-token@v2
22+
with:
23+
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
24+
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
25+
owner: ${{ github.repository_owner }}
26+
repositories: RestrictedActions
27+
28+
- name: Dispatch restricted action
29+
uses: peter-evans/repository-dispatch@v3
30+
with:
31+
token: ${{ steps.generate-token.outputs.token }}
32+
repository: ${{ github.repository_owner }}/RestrictedActions
33+
event-type: pocketmine_mp_crowdin_upload
34+
client-payload: '{"branch": "${{ github.ref_name }}"}'

.github/workflows/main.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,18 @@ jobs:
4949

5050
- name: Run ShellCheck
5151
uses: ludeeus/[email protected]
52+
53+
translations:
54+
name: Translation checks
55+
runs-on: ubuntu-latest
56+
57+
steps:
58+
- uses: actions/checkout@v4
59+
60+
- name: Setup PHP
61+
uses: shivammathur/[email protected]
62+
with:
63+
php-version: 8.3
64+
65+
- name: Verify translations
66+
run: php .github/workflows/verify-translations.php ${{ github.workspace }}/resources/translations
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
<?php
2+
3+
/*
4+
*
5+
* ____ _ _ __ __ _ __ __ ____
6+
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7+
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8+
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9+
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Lesser General Public License as published by
13+
* the Free Software Foundation, either version 3 of the License, or
14+
* (at your option) any later version.
15+
*
16+
* @author PocketMine Team
17+
* @link http://www.pocketmine.net/
18+
*
19+
*
20+
*/
21+
22+
declare(strict_types=1);
23+
24+
namespace pocketmine\build\generate_known_translation_apis;
25+
26+
use function array_fill_keys;
27+
use function count;
28+
use function explode;
29+
use function file_get_contents;
30+
use function fwrite;
31+
use function in_array;
32+
use function is_array;
33+
use function json_decode;
34+
use function json_encode;
35+
use function parse_ini_file;
36+
use function preg_match_all;
37+
use function str_starts_with;
38+
use const INI_SCANNER_RAW;
39+
use const JSON_PRETTY_PRINT;
40+
use const JSON_THROW_ON_ERROR;
41+
use const PHP_EOL;
42+
use const PHP_INT_MAX;
43+
use const STDERR;
44+
45+
/**
46+
* @param string[] $baseLanguageDef
47+
* @param string[] $altLanguageDef
48+
*
49+
* @phpstan-param array<string, string> $baseLanguageDef
50+
* @phpstan-param array<string, string> $altLanguageDef
51+
*
52+
* @return bool true if everything is OK, false otherwise
53+
*/
54+
function verify_translations(array $baseLanguageDef, string $altLanguageName, array $altLanguageDef) : bool{
55+
$parameterRegex = '/{%(.+?)}/';
56+
57+
$ok = true;
58+
foreach($baseLanguageDef as $key => $baseString){
59+
if(!isset($altLanguageDef[$key])){
60+
continue;
61+
}
62+
$altString = $altLanguageDef[$key];
63+
$baseParams = preg_match_all($parameterRegex, $baseString, $baseMatches);
64+
$altParams = preg_match_all($parameterRegex, $altString, $altMatches);
65+
if($baseParams === false || $altParams === false){
66+
throw new \Error("preg_match_all() should not have failed here");
67+
}
68+
foreach($baseMatches[1] as $paramName){
69+
if(!in_array($paramName, $altMatches[1], true)){
70+
fwrite(STDERR, "$altLanguageName: missing parameter %$paramName in string $key" . PHP_EOL);
71+
$ok = false;
72+
}
73+
}
74+
foreach($altMatches[1] as $paramName){
75+
if(!in_array($paramName, $baseMatches[1], true)){
76+
fwrite(STDERR, "$altLanguageName: unexpected extra parameter %$paramName in string $key" . PHP_EOL);
77+
$ok = false;
78+
}
79+
}
80+
}
81+
foreach($altLanguageDef as $key => $altString){
82+
if(!isset($baseLanguageDef[$key])){
83+
fwrite(STDERR, "$altLanguageName: unexpected extra string $key with no base in eng.ini" . PHP_EOL);
84+
$ok = false;
85+
}
86+
}
87+
return $ok;
88+
}
89+
90+
/**
91+
* @return string[]|null
92+
* @phpstan-return array<string, string>|null
93+
*/
94+
function parse_language_file(string $path, string $code) : ?array{
95+
$lang = parse_ini_file($path . "/" . "$code.ini", false, INI_SCANNER_RAW);
96+
if($lang === false){
97+
return null;
98+
}
99+
return $lang;
100+
}
101+
102+
/**
103+
* @return string[]
104+
* @phpstan-return array<string, string>
105+
*/
106+
function parse_mojang_language_defs(string $contents) : array{
107+
$result = [];
108+
foreach(explode("\n", $contents, limit: PHP_INT_MAX) as $line){
109+
$stripped = explode("##", $line, 2)[0];
110+
$kv = explode("=", $stripped, 2);
111+
if(count($kv) !== 2){
112+
continue;
113+
}
114+
$result[$kv[0]] = $kv[1];
115+
}
116+
117+
return $result;
118+
}
119+
120+
/**
121+
* @param string[] $pocketmine
122+
* @param string[] $mojang
123+
* @param string[] $knownBadKeys
124+
* @phpstan-param array<string, string> $pocketmine
125+
* @phpstan-param array<string, string> $mojang
126+
* @phpstan-param array<string, bool> $knownBadKeys
127+
*
128+
* @return string[]
129+
* @phpstan-return list<string>
130+
*/
131+
function verify_keys(array $pocketmine, array $mojang, array $knownBadKeys) : array{
132+
$wrong = [];
133+
foreach($pocketmine as $k => $v){
134+
if(str_starts_with($k, "pocketmine.")){
135+
continue;
136+
}
137+
138+
if(!isset($mojang[$k]) && !isset($knownBadKeys[$k])){
139+
$wrong[] = $k;
140+
}
141+
}
142+
foreach($knownBadKeys as $k => $_){
143+
if(!isset($pocketmine[$k])){
144+
fwrite(STDERR, "known-bad-keys.json contains key \"$k\" which does not exist in eng.ini\n");
145+
}
146+
}
147+
return $wrong;
148+
}
149+
150+
if(count($argv) !== 2){
151+
fwrite(STDERR, "Required arguments: path\n");
152+
exit(1);
153+
}
154+
$eng = parse_language_file($argv[1], "eng");
155+
if($eng === null){
156+
fwrite(STDERR, "Failed to parse eng.ini\n");
157+
exit(1);
158+
}
159+
160+
$mojangRaw = file_get_contents("https://raw.githubusercontent.com/Mojang/bedrock-samples/refs/heads/main/resource_pack/texts/en_US.lang");
161+
if($mojangRaw === false){
162+
fwrite(STDERR, "Failed to fetch official Mojang sources for verification\n");
163+
exit(1);
164+
}
165+
$mojang = parse_mojang_language_defs($mojangRaw);
166+
167+
$knownBadKeysRaw = file_get_contents($argv[1] . "/known-bad-keys.json");
168+
$knownBadKeysDecoded = $knownBadKeysRaw !== false ? json_decode($knownBadKeysRaw, associative: true, flags: JSON_THROW_ON_ERROR) : [];
169+
170+
if(!is_array($knownBadKeysDecoded)){
171+
fwrite(STDERR, "known-bad-keys.json should contain an array of strings\n");
172+
exit(1);
173+
}
174+
$knownBadKeys = [];
175+
foreach($knownBadKeysDecoded as $key){
176+
if(!is_string($key)){
177+
fwrite(STDERR, "known-bad-keys.json should contain an array of strings\n");
178+
exit(1);
179+
}
180+
$knownBadKeys[] = $key;
181+
}
182+
183+
$badKeys = verify_keys($eng, $mojang, array_fill_keys($knownBadKeys, true));
184+
if(count($badKeys) !== 0){
185+
fwrite(STDERR, "The following non-\"pocketmine.\" keys are not matched by Mojang sources and are not whitelisted:\n");
186+
fwrite(STDERR, json_encode($badKeys, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) . "\n");
187+
fwrite(STDERR, "Keys must either match Mojang sources, or be prefixed with \"pocketmine.\"\n");
188+
fwrite(STDERR, "Failure to do so will cause these to be shown incorrectly on clients, as the server won't translate them\n");
189+
exit(1);
190+
}
191+
192+
$exit = 0;
193+
/**
194+
* @var string[] $match
195+
* @phpstan-var array{0: string, 1: string} $match
196+
*/
197+
foreach(new \RegexIterator(new \FilesystemIterator($argv[1], \FilesystemIterator::CURRENT_AS_PATHNAME), "/([a-z]+)\.ini$/", \RegexIterator::GET_MATCH) as $match){
198+
$code = $match[1];
199+
if($code === "eng"){
200+
continue;
201+
}
202+
$otherLang = parse_language_file($argv[1], $code);
203+
if($otherLang === null){
204+
fwrite(STDERR, "Error parsing $code.ini\n");
205+
$exit = 1;
206+
continue;
207+
}
208+
if(!verify_translations($eng, $code, $otherLang)){
209+
fwrite(STDERR, "Errors found in $code.ini\n");
210+
$exit = 1;
211+
continue;
212+
}
213+
214+
echo "Everything OK in $code.ini\n";
215+
}
216+
exit($exit);

CONTRIBUTING.md

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ Small contributions (e.g. minor bug fixes) can be submitted as pull requests dir
44

55
Larger contributions like feature additions should be preceded by a [Change Proposal](#rfcs--change-proposals) to allow maintainers and other people to discuss and decide if it's a good idea or not.
66

7+
> [!TIP]
8+
> Want to contribute (non-English) translations? Visit our
9+
> [Crowdin Translation Project](https://crowdin.com/project/pocketmine) instead.
10+
>
11+
> Translations need to go through a different review process, so we can't accept changes to them in PRs.
12+
713
## Useful documentation from github.com
814
- [About pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests)
915
- [About forks](https://docs.github.com/en/github/collaborating-with-pull-requests/working-with-forks/about-forks)
@@ -37,22 +43,24 @@ Take a look at the table below if you can't find the class or function you're lo
3743
## Choosing a target branch
3844
PocketMine-MP has three primary branches of development.
3945

40-
| Type of change | `stable` | `minor-next` | `major-next` |
41-
|:--------------------------------------------------------------------------------------------|:--------:|:-------------------------------:|:------------:|
42-
| Bug fixes | ✔️ | ✔️ | ✔️ |
43-
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
44-
| Cleaning up code || ✔️ | ✔️ |
45-
| Changing code formatting or style || ✔️ | ✔️ |
46-
| Addition of new core features || 🟡 Only if non-disruptive | ✔️ |
47-
| Changing core behaviour (e.g. making something use threads) || ✔️ | ✔️ |
48-
| Addition of new configuration options || 🟡 Only if optional | ✔️ |
49-
| Addition of new API classes, methods or constants || ✔️ | ✔️ |
50-
| Deprecating API classes, methods or constants || ✔️ | ✔️ |
51-
| Adding optional parameters to an API method || ✔️ | ✔️ |
52-
| Changing API behaviour || 🟡 Only if backwards-compatible | ✔️ |
53-
| Removal of API ||| ✔️ |
54-
| Backwards-incompatible API change (e.g. renaming a method) ||| ✔️ |
55-
| Backwards-incompatible internals change (e.g. changing things in `pocketmine\network\mcpe`) || ✔️ | ✔️ |
46+
| Type of change | `stable` | `minor-next` | `major-next` |
47+
|:---------------------------------------------------------------------------------------------------------|:--------:|:-------------------------------:|:------------:|
48+
| Bug fixes | ✔️ | ✔️ | ✔️ |
49+
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
50+
| Fixing base (`eng.ini`) language strings, or adding new ones | ✔️ | ✔️ | ✔️ |
51+
| Changes to existing base (`eng.ini`) language strings (e.g. changing parameters, renaming/removing keys) || ✔️ | ✔️ |
52+
| Cleaning up code || ✔️ | ✔️ |
53+
| Changing code formatting or style || ✔️ | ✔️ |
54+
| Addition of new core features || 🟡 Only if non-disruptive | ✔️ |
55+
| Changing core behaviour (e.g. making something use threads) || ✔️ | ✔️ |
56+
| Addition of new configuration options || 🟡 Only if optional | ✔️ |
57+
| Addition of new API classes, methods or constants || ✔️ | ✔️ |
58+
| Deprecating API classes, methods or constants || ✔️ | ✔️ |
59+
| Adding optional parameters to an API method || ✔️ | ✔️ |
60+
| Changing API behaviour || 🟡 Only if backwards-compatible | ✔️ |
61+
| Removal of API ||| ✔️ |
62+
| Backwards-incompatible API change (e.g. renaming a method) ||| ✔️ |
63+
| Backwards-incompatible internals change (e.g. changing things in `pocketmine\network\mcpe`) || ✔️ | ✔️ |
5664

5765
### Notes
5866
- **Non-disruptive** means that usage should not be significantly altered by the change.

0 commit comments

Comments
 (0)