mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-05 09:26:06 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
2
.github/workflows/build-docker-image.yml
vendored
2
.github/workflows/build-docker-image.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Clone pmmp/PocketMine-Docker repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: pmmp/PocketMine-Docker
|
||||
fetch-depth: 1
|
||||
|
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.25.5
|
||||
|
4
.github/workflows/draft-release.yml
vendored
4
.github/workflows/draft-release.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
php-version: [8.1]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@ -86,7 +86,7 @@ jobs:
|
||||
${{ github.workspace }}/build_info.json
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.12.0
|
||||
uses: ncipollo/release-action@v1.13.0
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
commit: ${{ github.sha }}
|
||||
|
13
.github/workflows/main.yml
vendored
13
.github/workflows/main.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
php: ["8.1", "8.2"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
@ -52,7 +52,7 @@ jobs:
|
||||
php: ["8.1", "8.2"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
@ -87,7 +87,7 @@ jobs:
|
||||
php: ["8.1", "8.2"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@ -124,7 +124,7 @@ jobs:
|
||||
php: ["8.1", "8.2"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
@ -158,6 +158,9 @@ jobs:
|
||||
- name: Regenerate BedrockData available files constants
|
||||
run: php build/generate-bedrockdata-path-consts.php
|
||||
|
||||
- name: Regenerate YmlServerProperties constants
|
||||
run: php build/generate-pocketmine-yml-property-consts.php
|
||||
|
||||
- name: Verify code is unchanged
|
||||
run: |
|
||||
git diff
|
||||
@ -170,7 +173,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.25.5
|
||||
|
2
.github/workflows/update-updater-api.yml
vendored
2
.github/workflows/update-updater-api.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
- name: Install jq
|
||||
run: sudo apt update && sudo apt install jq -y
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/update.pmmp.io
|
||||
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
|
||||
|
120
build/generate-pocketmine-yml-property-consts.php
Normal file
120
build/generate-pocketmine-yml-property-consts.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$defaultConfig = yaml_parse(Filesystem::fileGetContents(dirname(__DIR__) . '/resources/pocketmine.yml'));
|
||||
|
||||
if(!is_array($defaultConfig)){
|
||||
fwrite(STDERR, "Invalid default pocketmine.yml\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$constants = [];
|
||||
|
||||
/**
|
||||
* @param mixed[] $properties
|
||||
* @param string[] $constants
|
||||
* @phpstan-param array<string, string> $constants
|
||||
* @phpstan-param-out array<string, string> $constants
|
||||
*/
|
||||
function collectProperties(string $prefix, array $properties, array &$constants) : void{
|
||||
foreach($properties as $propertyName => $property){
|
||||
$fullPropertyName = ($prefix !== "" ? $prefix . "." : "") . $propertyName;
|
||||
|
||||
$constName = str_replace([".", "-"], "_", strtoupper($fullPropertyName));
|
||||
$constants[$constName] = $fullPropertyName;
|
||||
|
||||
if(is_array($property)){
|
||||
collectProperties($fullPropertyName, $property, $constants);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collectProperties("", $defaultConfig, $constants);
|
||||
ksort($constants, SORT_STRING);
|
||||
|
||||
$file = fopen(dirname(__DIR__) . '/src/YmlServerProperties.php', 'wb');
|
||||
if($file === false){
|
||||
fwrite(STDERR, "Failed to open output file\n");
|
||||
exit(1);
|
||||
}
|
||||
fwrite($file, "<?php\n");
|
||||
fwrite($file, <<<'HEADER'
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
HEADER
|
||||
);
|
||||
fwrite($file, "declare(strict_types=1);\n\n");
|
||||
fwrite($file, "namespace pocketmine;\n\n");
|
||||
|
||||
fwrite($file, <<<'DOC'
|
||||
/**
|
||||
* @internal
|
||||
* Constants for all properties available in pocketmine.yml.
|
||||
* This is generated by build/generate-pocketmine-yml-property-consts.php.
|
||||
* Do not edit this file manually.
|
||||
*/
|
||||
|
||||
DOC
|
||||
);
|
||||
fwrite($file, "final class YmlServerProperties{\n");
|
||||
fwrite($file, <<<'CONSTRUCTOR'
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
|
||||
CONSTRUCTOR
|
||||
);
|
||||
foreach(Utils::stringifyKeys($constants) as $constName => $propertyName){
|
||||
fwrite($file, "\tpublic const $constName = '$propertyName';\n");
|
||||
}
|
||||
fwrite($file, "}\n");
|
||||
|
||||
fclose($file);
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
Submodule build/php updated: a053f65e18...3331f8c0d5
@ -60,3 +60,9 @@ Released 9th August 2023.
|
||||
- Fixed `PluginBase->saveResource()` leaking file resources when the data file already exists in the plugin's data folder. This bug existed since 2014 and was only discovered recently.
|
||||
- Fixed coral blocks becoming dead after calling `getDropsForCompatibleTool()` on them.
|
||||
- Fixed `BlockDeathEvent->getOldState()` returning a block which is already dead.
|
||||
|
||||
# 4.23.6
|
||||
Released 21st August 2023.
|
||||
|
||||
## Fixes
|
||||
- Added a workaround for armor and other inventories not working correctly after inventory sync. This is caused by a client bug.
|
||||
|
@ -107,3 +107,27 @@ Released 9th August 2023.
|
||||
## Fixes
|
||||
- Fixed cake accepting candle placement when slices have already been eaten.
|
||||
- Fixed fire charges not lighting candles.
|
||||
|
||||
# 5.4.3
|
||||
Released 21st August 2023.
|
||||
|
||||
## Included releases
|
||||
- [4.23.6](https://github.com/pmmp/PocketMine-MP/blob/4.23.6/changelogs/4.23.md#4236) - Armor inventory client bug workaround
|
||||
|
||||
## Fixes
|
||||
- Fixed crashdumps not generating correctly on fatal errors.
|
||||
- Fixed `PotionCauldron::setPotionItem()` not validating the item type.
|
||||
- Fixed chorus fruit not considering teleport destinations below y=0.
|
||||
- Fixed cake dropping itself when mined.
|
||||
|
||||
# 5.4.4
|
||||
Released 6th September 2023.
|
||||
|
||||
## General
|
||||
- Crashdumps caused by non-phar plugins are now submitted to the Crash Archive, the same as other plugins. Previously, non-phar plugin crashes would not be submitted, causing maintainers to potentially miss important issues.
|
||||
|
||||
## Fixes
|
||||
- Fixed player Y coordinates sometimes being slightly below the top of the block they were standing on (floating point error due to subtracting eye height).
|
||||
- Fixed template slot of smithing tables not accepting any items.
|
||||
- `tools/generate-bedrock-data-from-packets.php` is now significantly less spammy when warning about duplicated recipes.
|
||||
- Fixed empty stack traces in `lastError` data of crashdumps.
|
||||
|
156
changelogs/5.5-beta.md
Normal file
156
changelogs/5.5-beta.md
Normal file
@ -0,0 +1,156 @@
|
||||
# 5.5.0-BETA1
|
||||
Released 23rd August 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.10**
|
||||
|
||||
This is a minor feature release, including performance improvements, new API methods, and new gameplay features.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Dependencies
|
||||
- Updated `pocketmine/math` dependency to [`1.0.0`](https://github.com/pmmp/Math/releases/tag/1.0.0).
|
||||
- Updated `pocketmine/nbt` dependency to [`1.0.0`](https://github.com/pmmp/NBT/releases/tag/1.0.0).
|
||||
|
||||
## Performance
|
||||
- Some events are now no longer fired if no handlers are registered.
|
||||
- This improves performance by avoiding unnecessary object allocations and function calls.
|
||||
- Events such as `DataPacketReceiveEvent`, `DataPacketSendEvent` and `PlayerMoveEvent` are optimized away almost completely by this change, offering some much-needed performance gains.
|
||||
- Significantly improved performance of small moving entities, such as dropped items.
|
||||
- This was achieved by a combination of changes, which together improved observed performance with 2000 item entities moving in water by 30-40%.
|
||||
- The benefit of this will be most noticeable in SkyBlock servers, where large cactus farms can generate thousands of dropped items.
|
||||
- `World->getCollisionBoxes()` now uses an improved search method, which reduces the work done by the function by almost 90% for small entities.
|
||||
- This improves performance of collision detection for small entities, such as dropped items.
|
||||
|
||||
## Gameplay
|
||||
### General
|
||||
- Implemented enchanting using an enchanting table (yes, finally!)
|
||||
- Thanks to [@S3v3Nice](https://github.com/S3v3Nice) for investing lots of time and effort into developing this.
|
||||
- Since this feature is quite complex, it's possible there may be bugs. Please be vigilant and report any issues you find.
|
||||
|
||||
### Blocks
|
||||
- The following new blocks have been implemented:
|
||||
- Pink Petals
|
||||
- Pressure plates are now functional, in the sense that they react when entities stand on them and perform the correct logic.
|
||||
- Note that since redstone is not yet implemented, pressure plates do not activate any redstone devices, similar to buttons and levers.
|
||||
- Signs can now be edited by right-clicking them.
|
||||
- Signs can now be waxed using a honeycomb, which prevents them from being edited.
|
||||
|
||||
### Items
|
||||
- The following new items have been implemented:
|
||||
- Enchanted Book
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new API methods have been added:
|
||||
- `public Block->getEnchantmentTags() : list<string>` returns a list of strings indicating which types of enchantment can be applied to the block when in item form
|
||||
- `public BlockTypeInfo->getEnchantmentTags() : list<string>`
|
||||
- `protected PressurePlate->getActivationBox() : AxisAlignedBB` - returns the AABB entities must intersect with in order to activate the pressure plate (not the same as the visual shape)
|
||||
- `protected PressurePlate->hasOutputSignal() : bool` - returns whether the pressure plate has an output signal - this should be implemented by subclasses
|
||||
- `protected PressurePlate->calculatePlateState() : array{Block, ?bool}` - returns the state the pressure plate will change to if the given list of entities are standing on it, and a bool indicating whether the plate activated or deactivated this tick
|
||||
- `protected PressurePlate->filterIrrelevantEntities(list<Entity> $entities) : list<Entity>` - returns the given list filtered of entities that don't affect the plate's state (e.g. dropped items don't affect stone pressure plates)
|
||||
- `public BaseSign->isWaxed() : bool`
|
||||
- `public BaseSign->setWaxed(bool $waxed) : $this`
|
||||
- `public inventory\EnchantInventory->getInput() : Item`
|
||||
- `public inventory\EnchantInventory->getLapis() : Item`
|
||||
- `public inventory\EnchantInventory->getOutput(int $optionId) : ?Item` - returns the item that would be produced if the input item was enchanted with the selected option, or `null` if the option is invalid
|
||||
- `public inventory\EnchantInventory->getOption(int $optionId) : EnchantOption` - returns the enchanting option at the given index
|
||||
- The following API methods have signature changes:
|
||||
- `BlockTypeInfo->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
|
||||
- `PressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
|
||||
- `WeightedPressurePlate->__construct()` now accepts optional `int $deactivationDelayTicks` and `float $signalStrengthFactor` parameters
|
||||
- `SimplePressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
|
||||
- The following new classes have been added:
|
||||
- `PinkPetals`
|
||||
- `utils\BlockEventHelper` - provides helper methods for calling block-related events
|
||||
- The following classes have been deprecated:
|
||||
- `WeightedPressurePlateLight`
|
||||
- `WeightedPressurePlateHeavy`
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Human->getEnchantmentSeed() : int` - returns the current seed used to randomize options shown on the enchanting table for this human
|
||||
- `public Human->setEnchantmentSeed(int $seed) : void`
|
||||
- `public Human->regenerateEnchantmentSeed() : void` - returns a new randomly generated seed which can be set with `setEnchantmentSeed()`
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following new classes have been added:
|
||||
- `block\FarmlandHydrationChangeEvent` - called when farmland is hydrated or dehydrated
|
||||
- `block\PressurePlateUpdateEvent` - called when a pressure plate is activated or changes its power output
|
||||
- `player\PlayerEnchantingOptionsRequestEvent` - called when a player puts an item to be enchanted into an enchanting table, to allow plugins to modify the enchanting options shown
|
||||
- `player\PlayerItemEnchantEvent` - called when a player enchants an item in an enchanting table
|
||||
- `world\WorldDifficultyChangeEvent` - called when a world's difficulty is changed
|
||||
- The following new API methods have been added:
|
||||
- `public static Event::hasHandlers() : bool` - returns whether the event class has any registered handlers - used like `SomeEvent::hasHandlers()`
|
||||
- `public HandlerListManager->getHandlersFor(class-string<? extends Event> $event) : list<RegisteredListener>` - returns a list of all registered listeners for the given event class, using cache if available
|
||||
|
||||
### `pocketmine\inventory\transaction`
|
||||
- The following new classes have been added:
|
||||
- `EnchantingTransaction` - used when a player enchants an item in an enchanting table
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Armor->getMaterial() : ArmorMaterial` - returns an object containing properties shared by all items of the same armor material
|
||||
- `public ArmorTypeInfo->getMaterial() : ArmorMaterial`
|
||||
- `public Item->getEnchantability() : int` - returns the enchantability value of the item - higher values increase the chance of more powerful enchantments being offered by an enchanting table
|
||||
- `public Item->getEnchantmentTags() : list<string>` - returns a list of strings indicating which types of enchantment can be applied to the item
|
||||
- `public ToolTier->getEnchantability() : int`
|
||||
- The following API methods have signature changes:
|
||||
- `Item->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
|
||||
- `ArmorTypeInfo->__construct()` now accepts an optional `?ArmorMaterial $material` parameter
|
||||
- The following new classes have been added:
|
||||
- `ArmorMaterial` - container for shared armor properties
|
||||
- `VanillaArmorMaterials` - all vanilla armor materials
|
||||
- `EnchantedBook` - represents an enchanted book item
|
||||
|
||||
### `pocketmine\item\enchantment`
|
||||
- The following new classes have been added:
|
||||
- `AvailableEnchantmentRegistry` - enchantments to be displayed on the enchanting table are selected from here - custom enchantments may be added
|
||||
- `EnchantingHelper` - static class containing various helper methods for enchanting tables
|
||||
- `EnchantingOption` - represents an option on the enchanting table menu
|
||||
- `IncompatibleEnchantmentGroups` - list of constants naming groups of enchantments that are incompatible with each other - custom enchantments may be added using these group names to make them incompatible with existing enchantments in the same group
|
||||
- `IncompatibleEnchantmentRegistry` - manages which enchantments are considered incompatible with each other - custom enchantments may be added using existing group names to make them incompatible with existing enchantments in the same group, or to entirely new groups
|
||||
- `ItemEnchantmentTagRegistry` - manages item enchantment compatibility tags and which tags include which other tags
|
||||
- `ItemEnchantmentTags` - list of constants naming item types for enchantment compatibility checks
|
||||
- The following classes have been deprecated
|
||||
- `ItemFlags`
|
||||
- The following API methods have been added:
|
||||
- `public Enchantment->isCompatibleWith(Enchantment $other) : bool`
|
||||
- `public Enchantment->getMinEnchantingPower()` - returns the minimum enchanting power (derived from enchantability and number of bookshelves) needed to allow this enchantment to show on the enchanting table with a given level
|
||||
- `public Enchantment->getMaxEnchantingPower()` - upper limit of enchanting power for this enchantment to be offered on the enchanting table with a given level
|
||||
- The following API methods have signature changes:
|
||||
- `Enchantment->__construct()` now accepts optional `(\Closure(int $level) : int)|null $minEnchantingPower` and `int $enchantingPowerRange` parameters
|
||||
- `Enchantment->__construct()` parameters `$primaryItemFlags` and `$secondaryItemFlags` are now deprecated and no longer used
|
||||
- `ProtectionEnchantment->__construct()` has extra parameters to reflect `Enchantment->__construct()` changes
|
||||
- The following API methods have been deprecated:
|
||||
- `Enchantment->getPrimaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
|
||||
- `Enchantment->getSecondaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
|
||||
- `Enchantment->hasPrimaryItemType()`
|
||||
- `Enchantment->hasSecondaryItemType()`
|
||||
|
||||
### `pocketmine\plugin`
|
||||
- The following new API methods have been added:
|
||||
- `public PluginBase->getResourcePath(string $filename) : string` - returns a URI to an embedded resource file that can be used with `file_get_contents()` and similar functions
|
||||
- `public PluginBase->getResourceFolder() : string` - returns a URI to the plugin's folder of embedded resources
|
||||
- The following API methods have been deprecated:
|
||||
- `PluginBase->getResource()` - prefer using `getResourcePath()` with `file_get_contents()` or other PHP built-in functions instead
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setResourcePacksRequired(bool $value) : void` - sets whether players must accept resource packs in order to join
|
||||
|
||||
### `pocketmine\world\generator`
|
||||
- The following new API methods have been added:
|
||||
- `public GeneratorManager->addAlias(string $name, string $alias) : void` - allows registering a generator alias without copying the generator registration parameters
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following new classes have been added:
|
||||
- `PressurePlateActivateSound`
|
||||
- `PressurePlateDeactivateSound`
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public StringToTParser->registerAlias(string $existing, string $alias) : void` - allows registering a string alias without copying registration parameters
|
162
changelogs/5.5.md
Normal file
162
changelogs/5.5.md
Normal file
@ -0,0 +1,162 @@
|
||||
# 5.5.0
|
||||
Released 6th September 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.10**
|
||||
|
||||
This is a minor feature release, including performance improvements, new API methods, and new gameplay features.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Dependencies
|
||||
- Updated `pocketmine/math` dependency to [`1.0.0`](https://github.com/pmmp/Math/releases/tag/1.0.0).
|
||||
- Updated `pocketmine/nbt` dependency to [`1.0.0`](https://github.com/pmmp/NBT/releases/tag/1.0.0).
|
||||
|
||||
## Performance
|
||||
- Some events are now no longer fired if no handlers are registered.
|
||||
- This improves performance by avoiding unnecessary object allocations and function calls.
|
||||
- Events such as `DataPacketReceiveEvent`, `DataPacketSendEvent` and `PlayerMoveEvent` are optimized away almost completely by this change, offering some much-needed performance gains.
|
||||
- Significantly improved performance of small moving entities, such as dropped items.
|
||||
- This was achieved by a combination of changes, which together improved observed performance with 2000 item entities moving in water by 30-40%.
|
||||
- The benefit of this will be most noticeable in SkyBlock servers, where large cactus farms can generate thousands of dropped items.
|
||||
- `World->getCollisionBoxes()` now uses an improved search method, which reduces the work done by the function by almost 90% for small entities.
|
||||
- This improves performance of collision detection for small entities, such as dropped items.
|
||||
|
||||
## Gameplay
|
||||
### General
|
||||
- Implemented enchanting using an enchanting table (yes, finally!)
|
||||
- Thanks to [@S3v3Nice](https://github.com/S3v3Nice) for investing lots of time and effort into developing this.
|
||||
- Since this feature is quite complex, it's possible there may be bugs. Please be vigilant and report any issues you find.
|
||||
|
||||
### Blocks
|
||||
- The following new blocks have been implemented:
|
||||
- Pink Petals
|
||||
- Pressure plates are now functional, in the sense that they react when entities stand on them and perform the correct logic.
|
||||
- Note that since redstone is not yet implemented, pressure plates do not activate any redstone devices, similar to buttons and levers.
|
||||
- Signs can now be edited by right-clicking them.
|
||||
- Signs can now be waxed using a honeycomb, which prevents them from being edited.
|
||||
|
||||
### Items
|
||||
- The following new items have been implemented:
|
||||
- Enchanted Book
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new API methods have been added:
|
||||
- `public Block->getEnchantmentTags() : list<string>` returns a list of strings indicating which types of enchantment can be applied to the block when in item form
|
||||
- `public BlockTypeInfo->getEnchantmentTags() : list<string>`
|
||||
- `protected PressurePlate->getActivationBox() : AxisAlignedBB` - returns the AABB entities must intersect with in order to activate the pressure plate (not the same as the visual shape)
|
||||
- `protected PressurePlate->hasOutputSignal() : bool` - returns whether the pressure plate has an output signal - this should be implemented by subclasses
|
||||
- `protected PressurePlate->calculatePlateState() : array{Block, ?bool}` - returns the state the pressure plate will change to if the given list of entities are standing on it, and a bool indicating whether the plate activated or deactivated this tick
|
||||
- `protected PressurePlate->filterIrrelevantEntities(list<Entity> $entities) : list<Entity>` - returns the given list filtered of entities that don't affect the plate's state (e.g. dropped items don't affect stone pressure plates)
|
||||
- `public BaseSign->isWaxed() : bool`
|
||||
- `public BaseSign->setWaxed(bool $waxed) : $this`
|
||||
- `public inventory\EnchantInventory->getInput() : Item`
|
||||
- `public inventory\EnchantInventory->getLapis() : Item`
|
||||
- `public inventory\EnchantInventory->getOutput(int $optionId) : ?Item` - returns the item that would be produced if the input item was enchanted with the selected option, or `null` if the option is invalid
|
||||
- `public inventory\EnchantInventory->getOption(int $optionId) : EnchantOption` - returns the enchanting option at the given index
|
||||
- The following API methods have signature changes:
|
||||
- `BlockTypeInfo->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
|
||||
- `PressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
|
||||
- `WeightedPressurePlate->__construct()` now accepts optional `int $deactivationDelayTicks` and `float $signalStrengthFactor` parameters
|
||||
- `SimplePressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
|
||||
- The following new classes have been added:
|
||||
- `PinkPetals`
|
||||
- `utils\BlockEventHelper` - provides helper methods for calling block-related events
|
||||
- The following classes have been deprecated:
|
||||
- `WeightedPressurePlateLight`
|
||||
- `WeightedPressurePlateHeavy`
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Human->getEnchantmentSeed() : int` - returns the current seed used to randomize options shown on the enchanting table for this human
|
||||
- `public Human->setEnchantmentSeed(int $seed) : void`
|
||||
- `public Human->regenerateEnchantmentSeed() : void` - returns a new randomly generated seed which can be set with `setEnchantmentSeed()`
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following new classes have been added:
|
||||
- `block\FarmlandHydrationChangeEvent` - called when farmland is hydrated or dehydrated
|
||||
- `block\PressurePlateUpdateEvent` - called when a pressure plate is activated or changes its power output
|
||||
- `player\PlayerEnchantingOptionsRequestEvent` - called when a player puts an item to be enchanted into an enchanting table, to allow plugins to modify the enchanting options shown
|
||||
- `player\PlayerItemEnchantEvent` - called when a player enchants an item in an enchanting table
|
||||
- `world\WorldDifficultyChangeEvent` - called when a world's difficulty is changed
|
||||
- The following new API methods have been added:
|
||||
- `public static Event::hasHandlers() : bool` - returns whether the event class has any registered handlers - used like `SomeEvent::hasHandlers()`
|
||||
- `public HandlerListManager->getHandlersFor(class-string<? extends Event> $event) : list<RegisteredListener>` - returns a list of all registered listeners for the given event class, using cache if available
|
||||
|
||||
### `pocketmine\inventory\transaction`
|
||||
- The following new classes have been added:
|
||||
- `EnchantingTransaction` - used when a player enchants an item in an enchanting table
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Armor->getMaterial() : ArmorMaterial` - returns an object containing properties shared by all items of the same armor material
|
||||
- `public ArmorTypeInfo->getMaterial() : ArmorMaterial`
|
||||
- `public Item->getEnchantability() : int` - returns the enchantability value of the item - higher values increase the chance of more powerful enchantments being offered by an enchanting table
|
||||
- `public Item->getEnchantmentTags() : list<string>` - returns a list of strings indicating which types of enchantment can be applied to the item
|
||||
- `public ToolTier->getEnchantability() : int`
|
||||
- The following API methods have signature changes:
|
||||
- `Item->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
|
||||
- `ArmorTypeInfo->__construct()` now accepts an optional `?ArmorMaterial $material` parameter
|
||||
- The following new classes have been added:
|
||||
- `ArmorMaterial` - container for shared armor properties
|
||||
- `VanillaArmorMaterials` - all vanilla armor materials
|
||||
- `EnchantedBook` - represents an enchanted book item
|
||||
|
||||
### `pocketmine\item\enchantment`
|
||||
- The following new classes have been added:
|
||||
- `AvailableEnchantmentRegistry` - enchantments to be displayed on the enchanting table are selected from here - custom enchantments may be added
|
||||
- `EnchantingHelper` - static class containing various helper methods for enchanting tables
|
||||
- `EnchantingOption` - represents an option on the enchanting table menu
|
||||
- `IncompatibleEnchantmentGroups` - list of constants naming groups of enchantments that are incompatible with each other - custom enchantments may be added using these group names to make them incompatible with existing enchantments in the same group
|
||||
- `IncompatibleEnchantmentRegistry` - manages which enchantments are considered incompatible with each other - custom enchantments may be added using existing group names to make them incompatible with existing enchantments in the same group, or to entirely new groups
|
||||
- `ItemEnchantmentTagRegistry` - manages item enchantment compatibility tags and which tags include which other tags
|
||||
- `ItemEnchantmentTags` - list of constants naming item types for enchantment compatibility checks
|
||||
- The following classes have been deprecated
|
||||
- `ItemFlags`
|
||||
- The following API methods have been added:
|
||||
- `public Enchantment->isCompatibleWith(Enchantment $other) : bool`
|
||||
- `public Enchantment->getMinEnchantingPower()` - returns the minimum enchanting power (derived from enchantability and number of bookshelves) needed to allow this enchantment to show on the enchanting table with a given level
|
||||
- `public Enchantment->getMaxEnchantingPower()` - upper limit of enchanting power for this enchantment to be offered on the enchanting table with a given level
|
||||
- The following API methods have signature changes:
|
||||
- `Enchantment->__construct()` now accepts optional `(\Closure(int $level) : int)|null $minEnchantingPower` and `int $enchantingPowerRange` parameters
|
||||
- `Enchantment->__construct()` parameters `$primaryItemFlags` and `$secondaryItemFlags` are now deprecated and no longer used
|
||||
- `ProtectionEnchantment->__construct()` has extra parameters to reflect `Enchantment->__construct()` changes
|
||||
- The following API methods have been deprecated:
|
||||
- `Enchantment->getPrimaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
|
||||
- `Enchantment->getSecondaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
|
||||
- `Enchantment->hasPrimaryItemType()`
|
||||
- `Enchantment->hasSecondaryItemType()`
|
||||
|
||||
### `pocketmine\plugin`
|
||||
- The following new API methods have been added:
|
||||
- `public PluginBase->getResourcePath(string $filename) : string` - returns a URI to an embedded resource file that can be used with `file_get_contents()` and similar functions
|
||||
- `public PluginBase->getResourceFolder() : string` - returns a URI to the plugin's folder of embedded resources
|
||||
- The following API methods have been deprecated:
|
||||
- `PluginBase->getResource()` - prefer using `getResourcePath()` with `file_get_contents()` or other PHP built-in functions instead
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setResourcePacksRequired(bool $value) : void` - sets whether players must accept resource packs in order to join
|
||||
|
||||
### `pocketmine\world\generator`
|
||||
- The following new API methods have been added:
|
||||
- `public GeneratorManager->addAlias(string $name, string $alias) : void` - allows registering a generator alias without copying the generator registration parameters
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following new classes have been added:
|
||||
- `PressurePlateActivateSound`
|
||||
- `PressurePlateDeactivateSound`
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public StringToTParser->registerAlias(string $existing, string $alias) : void` - allows registering a string alias without copying registration parameters
|
||||
|
||||
## Internals
|
||||
- Various `TypeIdMap` classes in the `pocketmine\data\bedrock` package now use the new `IntSaveIdMapTrait` to reduce code duplication.
|
||||
- Added a new `ServerProperties` class containing constants for all known `server.properties` keys.
|
||||
- Added a new `YmlServerProperties` class containing generated constants for all known `pocketmine.yml` keys. These keys can be used with `Config->getNested()`.
|
||||
|
@ -44,7 +44,7 @@
|
||||
"pocketmine/locale-data": "~2.19.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/math": "~1.0.0",
|
||||
"pocketmine/nbt": "^0.3.2",
|
||||
"pocketmine/nbt": "~1.0.0",
|
||||
"pocketmine/raklib": "^0.15.0",
|
||||
"pocketmine/raklib-ipc": "^0.2.0",
|
||||
"pocketmine/snooze": "^0.5.0",
|
||||
|
149
composer.lock
generated
149
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "2d51c1adf069760587b6d36f9c4a5db3",
|
||||
"content-hash": "9237955fd97ba7c1697d80314fa9ad6f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -200,16 +200,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "23.0.3+bedrock-1.20.10",
|
||||
"version": "23.0.4+bedrock-1.20.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "e4157c7af3f91e1b08fe21be171eb73dad7029e9"
|
||||
"reference": "ae0d8f4d49506674b7ff622f7c81ce241dc49adb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/e4157c7af3f91e1b08fe21be171eb73dad7029e9",
|
||||
"reference": "e4157c7af3f91e1b08fe21be171eb73dad7029e9",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/ae0d8f4d49506674b7ff622f7c81ce241dc49adb",
|
||||
"reference": "ae0d8f4d49506674b7ff622f7c81ce241dc49adb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -223,7 +223,7 @@
|
||||
"ramsey/uuid": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.7",
|
||||
"phpstan/phpstan": "1.10.33",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
@ -241,9 +241,9 @@
|
||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/23.0.3+bedrock-1.20.10"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/23.0.4+bedrock-1.20.10"
|
||||
},
|
||||
"time": "2023-08-03T15:30:52+00:00"
|
||||
"time": "2023-09-06T07:36:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -521,16 +521,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/nbt",
|
||||
"version": "0.3.4",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/NBT.git",
|
||||
"reference": "62c02464c6708b2467c1e1a2af01af09d5114eda"
|
||||
"reference": "20540271cb59e04672cb163dca73366f207974f1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/62c02464c6708b2467c1e1a2af01af09d5114eda",
|
||||
"reference": "62c02464c6708b2467c1e1a2af01af09d5114eda",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/20540271cb59e04672cb163dca73366f207974f1",
|
||||
"reference": "20540271cb59e04672cb163dca73366f207974f1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -540,7 +540,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "1.10.3",
|
||||
"phpstan/phpstan": "1.10.25",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
@ -557,9 +557,9 @@
|
||||
"description": "PHP library for working with Named Binary Tags",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/NBT/issues",
|
||||
"source": "https://github.com/pmmp/NBT/tree/0.3.4"
|
||||
"source": "https://github.com/pmmp/NBT/tree/1.0.0"
|
||||
},
|
||||
"time": "2023-04-10T11:31:20+00:00"
|
||||
"time": "2023-07-14T13:01:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/netresearch-jsonmapper",
|
||||
@ -985,16 +985,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1009,7 +1009,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@ -1047,7 +1047,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1063,20 +1063,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1091,7 +1091,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@ -1130,7 +1130,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1146,7 +1146,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-07-28T09:04:16+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@ -1440,16 +1440,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "1.3.13",
|
||||
"version": "1.3.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "d8bdab0218c5eb0964338d24a8511b65e9c94fa5"
|
||||
"reference": "614acc10c522e319639bf38b0698a4a566665f04"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d8bdab0218c5eb0964338d24a8511b65e9c94fa5",
|
||||
"reference": "d8bdab0218c5eb0964338d24a8511b65e9c94fa5",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/614acc10c522e319639bf38b0698a4a566665f04",
|
||||
"reference": "614acc10c522e319639bf38b0698a4a566665f04",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1462,7 +1462,7 @@
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.5.1",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "phpstan-extension",
|
||||
@ -1486,9 +1486,9 @@
|
||||
"description": "PHPUnit extensions and rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.13"
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.14"
|
||||
},
|
||||
"time": "2023-05-26T11:05:59+00:00"
|
||||
"time": "2023-08-25T09:46:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
@ -1541,16 +1541,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "10.1.3",
|
||||
"version": "10.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "be1fe461fdc917de2a29a452ccf2657d325b443d"
|
||||
"reference": "cd59bb34756a16ca8253ce9b2909039c227fff71"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/be1fe461fdc917de2a29a452ccf2657d325b443d",
|
||||
"reference": "be1fe461fdc917de2a29a452ccf2657d325b443d",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cd59bb34756a16ca8253ce9b2909039c227fff71",
|
||||
"reference": "cd59bb34756a16ca8253ce9b2909039c227fff71",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1607,7 +1607,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.3"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1615,20 +1615,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-26T13:45:28+00:00"
|
||||
"time": "2023-08-31T14:04:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "4.0.2",
|
||||
"version": "4.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "5647d65443818959172645e7ed999217360654b6"
|
||||
"reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/5647d65443818959172645e7ed999217360654b6",
|
||||
"reference": "5647d65443818959172645e7ed999217360654b6",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
|
||||
"reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1668,7 +1668,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1676,7 +1676,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-07T09:13:23+00:00"
|
||||
"time": "2023-08-31T06:24:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-invoker",
|
||||
@ -1743,16 +1743,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d"
|
||||
"reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/9f3d3709577a527025f55bcf0f7ab8052c8bb37d",
|
||||
"reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
|
||||
"reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1790,7 +1790,8 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.0"
|
||||
"security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1798,7 +1799,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-03T06:56:46+00:00"
|
||||
"time": "2023-08-31T14:07:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-timer",
|
||||
@ -1861,16 +1862,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "10.3.2",
|
||||
"version": "10.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "0dafb1175c366dd274eaa9a625e914451506bcd1"
|
||||
"reference": "241ed4dd0db1c096984e62d414c4e1ac8d5dbff4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0dafb1175c366dd274eaa9a625e914451506bcd1",
|
||||
"reference": "0dafb1175c366dd274eaa9a625e914451506bcd1",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/241ed4dd0db1c096984e62d414c4e1ac8d5dbff4",
|
||||
"reference": "241ed4dd0db1c096984e62d414c4e1ac8d5dbff4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1942,7 +1943,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.2"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1958,7 +1959,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-15T05:34:23+00:00"
|
||||
"time": "2023-09-05T04:34:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -2206,16 +2207,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||
"reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6"
|
||||
"reference": "c70b73893e10757af9c6a48929fa6a333b56a97a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/e67d240970c9dc7ea7b2123a6d520e334dd61dc6",
|
||||
"reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c70b73893e10757af9c6a48929fa6a333b56a97a",
|
||||
"reference": "c70b73893e10757af9c6a48929fa6a333b56a97a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2251,7 +2252,8 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/complexity",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/3.0.0"
|
||||
"security": "https://github.com/sebastianbergmann/complexity/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/3.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2259,7 +2261,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-03T06:59:47+00:00"
|
||||
"time": "2023-08-31T09:55:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
@ -2533,16 +2535,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
||||
"reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130"
|
||||
"reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/17c4d940ecafb3d15d2cf916f4108f664e28b130",
|
||||
"reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/649e40d279e243d985aa8fb6e74dd5bb28dc185d",
|
||||
"reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2578,7 +2580,8 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.0"
|
||||
"security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2586,7 +2589,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-03T07:08:02+00:00"
|
||||
"time": "2023-08-31T09:25:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
@ -2960,5 +2963,5 @@
|
||||
"platform-overrides": {
|
||||
"php": "8.1.0"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\scheduler\GarbageCollectionTask;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\YmlServerProperties as Yml;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function arsort;
|
||||
use function count;
|
||||
@ -109,7 +110,7 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
private function init(ServerConfigGroup $config) : void{
|
||||
$this->memoryLimit = $config->getPropertyInt("memory.main-limit", 0) * 1024 * 1024;
|
||||
$this->memoryLimit = $config->getPropertyInt(Yml::MEMORY_MAIN_LIMIT, 0) * 1024 * 1024;
|
||||
|
||||
$defaultMemory = 1024;
|
||||
|
||||
@ -127,7 +128,7 @@ class MemoryManager{
|
||||
}
|
||||
}
|
||||
|
||||
$hardLimit = $config->getPropertyInt("memory.main-hard-limit", $defaultMemory);
|
||||
$hardLimit = $config->getPropertyInt(Yml::MEMORY_MAIN_HARD_LIMIT, $defaultMemory);
|
||||
|
||||
if($hardLimit <= 0){
|
||||
ini_set("memory_limit", '-1');
|
||||
@ -135,22 +136,22 @@ class MemoryManager{
|
||||
ini_set("memory_limit", $hardLimit . "M");
|
||||
}
|
||||
|
||||
$this->globalMemoryLimit = $config->getPropertyInt("memory.global-limit", 0) * 1024 * 1024;
|
||||
$this->checkRate = $config->getPropertyInt("memory.check-rate", self::DEFAULT_CHECK_RATE);
|
||||
$this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true);
|
||||
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
|
||||
$this->globalMemoryLimit = $config->getPropertyInt(Yml::MEMORY_GLOBAL_LIMIT, 0) * 1024 * 1024;
|
||||
$this->checkRate = $config->getPropertyInt(Yml::MEMORY_CHECK_RATE, self::DEFAULT_CHECK_RATE);
|
||||
$this->continuousTrigger = $config->getPropertyBool(Yml::MEMORY_CONTINUOUS_TRIGGER, true);
|
||||
$this->continuousTriggerRate = $config->getPropertyInt(Yml::MEMORY_CONTINUOUS_TRIGGER_RATE, self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
|
||||
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", self::DEFAULT_TICKS_PER_GC);
|
||||
$this->garbageCollectionTrigger = $config->getPropertyBool("memory.garbage-collection.low-memory-trigger", true);
|
||||
$this->garbageCollectionAsync = $config->getPropertyBool("memory.garbage-collection.collect-async-worker", true);
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt(Yml::MEMORY_GARBAGE_COLLECTION_PERIOD, self::DEFAULT_TICKS_PER_GC);
|
||||
$this->garbageCollectionTrigger = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER, true);
|
||||
$this->garbageCollectionAsync = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER, true);
|
||||
|
||||
$this->lowMemChunkRadiusOverride = $config->getPropertyInt("memory.max-chunks.chunk-radius", 4);
|
||||
$this->lowMemChunkGC = $config->getPropertyBool("memory.max-chunks.trigger-chunk-collect", true);
|
||||
$this->lowMemChunkRadiusOverride = $config->getPropertyInt(Yml::MEMORY_MAX_CHUNKS_CHUNK_RADIUS, 4);
|
||||
$this->lowMemChunkGC = $config->getPropertyBool(Yml::MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT, true);
|
||||
|
||||
$this->lowMemDisableChunkCache = $config->getPropertyBool("memory.world-caches.disable-chunk-cache", true);
|
||||
$this->lowMemClearWorldCache = $config->getPropertyBool("memory.world-caches.low-memory-trigger", true);
|
||||
$this->lowMemDisableChunkCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE, true);
|
||||
$this->lowMemClearWorldCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER, true);
|
||||
|
||||
$this->dumpWorkers = $config->getPropertyBool("memory.memory-dump.dump-async-worker", true);
|
||||
$this->dumpWorkers = $config->getPropertyBool(Yml::MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER, true);
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
|
147
src/Server.php
147
src/Server.php
@ -120,6 +120,7 @@ use pocketmine\world\Position;
|
||||
use pocketmine\world\World;
|
||||
use pocketmine\world\WorldCreationOptions;
|
||||
use pocketmine\world\WorldManager;
|
||||
use pocketmine\YmlServerProperties as Yml;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_fill;
|
||||
@ -357,15 +358,15 @@ class Server{
|
||||
}
|
||||
|
||||
public function getPort() : int{
|
||||
return $this->configGroup->getConfigInt("server-port", self::DEFAULT_PORT_IPV4);
|
||||
return $this->configGroup->getConfigInt(ServerProperties::SERVER_PORT_IPV4, self::DEFAULT_PORT_IPV4);
|
||||
}
|
||||
|
||||
public function getPortV6() : int{
|
||||
return $this->configGroup->getConfigInt("server-portv6", self::DEFAULT_PORT_IPV6);
|
||||
return $this->configGroup->getConfigInt(ServerProperties::SERVER_PORT_IPV6, self::DEFAULT_PORT_IPV6);
|
||||
}
|
||||
|
||||
public function getViewDistance() : int{
|
||||
return max(2, $this->configGroup->getConfigInt("view-distance", self::DEFAULT_MAX_VIEW_DISTANCE));
|
||||
return max(2, $this->configGroup->getConfigInt(ServerProperties::VIEW_DISTANCE, self::DEFAULT_MAX_VIEW_DISTANCE));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -376,12 +377,12 @@ class Server{
|
||||
}
|
||||
|
||||
public function getIp() : string{
|
||||
$str = $this->configGroup->getConfigString("server-ip");
|
||||
$str = $this->configGroup->getConfigString(ServerProperties::SERVER_IPV4);
|
||||
return $str !== "" ? $str : "0.0.0.0";
|
||||
}
|
||||
|
||||
public function getIpV6() : string{
|
||||
$str = $this->configGroup->getConfigString("server-ipv6");
|
||||
$str = $this->configGroup->getConfigString(ServerProperties::SERVER_IPV6);
|
||||
return $str !== "" ? $str : "::";
|
||||
}
|
||||
|
||||
@ -390,30 +391,30 @@ class Server{
|
||||
}
|
||||
|
||||
public function getGamemode() : GameMode{
|
||||
return GameMode::fromString($this->configGroup->getConfigString("gamemode", GameMode::SURVIVAL()->name())) ?? GameMode::SURVIVAL();
|
||||
return GameMode::fromString($this->configGroup->getConfigString(ServerProperties::GAME_MODE, GameMode::SURVIVAL()->name())) ?? GameMode::SURVIVAL();
|
||||
}
|
||||
|
||||
public function getForceGamemode() : bool{
|
||||
return $this->configGroup->getConfigBool("force-gamemode", false);
|
||||
return $this->configGroup->getConfigBool(ServerProperties::FORCE_GAME_MODE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Server global difficulty. Note that this may be overridden in individual worlds.
|
||||
*/
|
||||
public function getDifficulty() : int{
|
||||
return $this->configGroup->getConfigInt("difficulty", World::DIFFICULTY_NORMAL);
|
||||
return $this->configGroup->getConfigInt(ServerProperties::DIFFICULTY, World::DIFFICULTY_NORMAL);
|
||||
}
|
||||
|
||||
public function hasWhitelist() : bool{
|
||||
return $this->configGroup->getConfigBool("white-list", false);
|
||||
return $this->configGroup->getConfigBool(ServerProperties::WHITELIST, false);
|
||||
}
|
||||
|
||||
public function isHardcore() : bool{
|
||||
return $this->configGroup->getConfigBool("hardcore", false);
|
||||
return $this->configGroup->getConfigBool(ServerProperties::HARDCORE, false);
|
||||
}
|
||||
|
||||
public function getMotd() : string{
|
||||
return $this->configGroup->getConfigString("motd", self::DEFAULT_SERVER_NAME);
|
||||
return $this->configGroup->getConfigString(ServerProperties::MOTD, self::DEFAULT_SERVER_NAME);
|
||||
}
|
||||
|
||||
public function getLoader() : ThreadSafeClassLoader{
|
||||
@ -496,7 +497,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function shouldSavePlayerData() : bool{
|
||||
return $this->configGroup->getPropertyBool("player.save-player-data", true);
|
||||
return $this->configGroup->getPropertyBool(Yml::PLAYER_SAVE_PLAYER_DATA, true);
|
||||
}
|
||||
|
||||
public function getOfflinePlayer(string $name) : Player|OfflinePlayer|null{
|
||||
@ -736,7 +737,7 @@ class Server{
|
||||
* @return string[][]
|
||||
*/
|
||||
public function getCommandAliases() : array{
|
||||
$section = $this->configGroup->getProperty("aliases");
|
||||
$section = $this->configGroup->getProperty(YmlServerProperties::ALIASES);
|
||||
$result = [];
|
||||
if(is_array($section)){
|
||||
foreach($section as $key => $value){
|
||||
@ -811,36 +812,36 @@ class Server{
|
||||
$this->configGroup = new ServerConfigGroup(
|
||||
new Config($pocketmineYmlPath, Config::YAML, []),
|
||||
new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES, [
|
||||
"motd" => self::DEFAULT_SERVER_NAME,
|
||||
"server-port" => self::DEFAULT_PORT_IPV4,
|
||||
"server-portv6" => self::DEFAULT_PORT_IPV6,
|
||||
"enable-ipv6" => true,
|
||||
"white-list" => false,
|
||||
"max-players" => self::DEFAULT_MAX_PLAYERS,
|
||||
"gamemode" => GameMode::SURVIVAL()->name(),
|
||||
"force-gamemode" => false,
|
||||
"hardcore" => false,
|
||||
"pvp" => true,
|
||||
"difficulty" => World::DIFFICULTY_NORMAL,
|
||||
"generator-settings" => "",
|
||||
"level-name" => "world",
|
||||
"level-seed" => "",
|
||||
"level-type" => "DEFAULT",
|
||||
"enable-query" => true,
|
||||
"auto-save" => true,
|
||||
"view-distance" => self::DEFAULT_MAX_VIEW_DISTANCE,
|
||||
"xbox-auth" => true,
|
||||
"language" => "eng"
|
||||
ServerProperties::MOTD => self::DEFAULT_SERVER_NAME,
|
||||
ServerProperties::SERVER_PORT_IPV4 => self::DEFAULT_PORT_IPV4,
|
||||
ServerProperties::SERVER_PORT_IPV6 => self::DEFAULT_PORT_IPV6,
|
||||
ServerProperties::ENABLE_IPV6 => true,
|
||||
ServerProperties::WHITELIST => false,
|
||||
ServerProperties::MAX_PLAYERS => self::DEFAULT_MAX_PLAYERS,
|
||||
ServerProperties::GAME_MODE => GameMode::SURVIVAL()->name(),
|
||||
ServerProperties::FORCE_GAME_MODE => false,
|
||||
ServerProperties::HARDCORE => false,
|
||||
ServerProperties::PVP => true,
|
||||
ServerProperties::DIFFICULTY => World::DIFFICULTY_NORMAL,
|
||||
ServerProperties::DEFAULT_WORLD_GENERATOR_SETTINGS => "",
|
||||
ServerProperties::DEFAULT_WORLD_NAME => "world",
|
||||
ServerProperties::DEFAULT_WORLD_SEED => "",
|
||||
ServerProperties::DEFAULT_WORLD_GENERATOR => "DEFAULT",
|
||||
ServerProperties::ENABLE_QUERY => true,
|
||||
ServerProperties::AUTO_SAVE => true,
|
||||
ServerProperties::VIEW_DISTANCE => self::DEFAULT_MAX_VIEW_DISTANCE,
|
||||
ServerProperties::XBOX_AUTH => true,
|
||||
ServerProperties::LANGUAGE => "eng"
|
||||
])
|
||||
);
|
||||
|
||||
$debugLogLevel = $this->configGroup->getPropertyInt("debug.level", 1);
|
||||
$debugLogLevel = $this->configGroup->getPropertyInt(Yml::DEBUG_LEVEL, 1);
|
||||
if($this->logger instanceof MainLogger){
|
||||
$this->logger->setLogDebug($debugLogLevel > 1);
|
||||
}
|
||||
|
||||
$this->forceLanguage = $this->configGroup->getPropertyBool("settings.force-language", false);
|
||||
$selectedLang = $this->configGroup->getConfigString("language", $this->configGroup->getPropertyString("settings.language", Language::FALLBACK_LANGUAGE));
|
||||
$this->forceLanguage = $this->configGroup->getPropertyBool(Yml::SETTINGS_FORCE_LANGUAGE, false);
|
||||
$selectedLang = $this->configGroup->getConfigString(ServerProperties::LANGUAGE, $this->configGroup->getPropertyString("settings.language", Language::FALLBACK_LANGUAGE));
|
||||
try{
|
||||
$this->language = new Language($selectedLang);
|
||||
}catch(LanguageNotFoundException $e){
|
||||
@ -856,11 +857,11 @@ class Server{
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::language_selected($this->getLanguage()->getName(), $this->getLanguage()->getLang())));
|
||||
|
||||
if(VersionInfo::IS_DEVELOPMENT_BUILD){
|
||||
if(!$this->configGroup->getPropertyBool("settings.enable-dev-builds", false)){
|
||||
if(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error1(VersionInfo::NAME)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error2()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error3()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4("settings.enable-dev-builds")));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4(YmlServerProperties::SETTINGS_ENABLE_DEV_BUILDS)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error5("https://github.com/pmmp/PocketMine-MP/releases")));
|
||||
$this->forceShutdownExit();
|
||||
|
||||
@ -878,7 +879,7 @@ class Server{
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
||||
|
||||
if(($poolSize = $this->configGroup->getPropertyString("settings.async-workers", "auto")) === "auto"){
|
||||
if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){
|
||||
$poolSize = 2;
|
||||
$processors = Utils::getCoreCount() - 2;
|
||||
|
||||
@ -889,32 +890,32 @@ class Server{
|
||||
$poolSize = max(1, (int) $poolSize);
|
||||
}
|
||||
|
||||
$this->asyncPool = new AsyncPool($poolSize, max(-1, $this->configGroup->getPropertyInt("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger, $this->tickSleeper);
|
||||
$this->asyncPool = new AsyncPool($poolSize, max(-1, $this->configGroup->getPropertyInt(Yml::MEMORY_ASYNC_WORKER_HARD_LIMIT, 256)), $this->autoloader, $this->logger, $this->tickSleeper);
|
||||
|
||||
$netCompressionThreshold = -1;
|
||||
if($this->configGroup->getPropertyInt("network.batch-threshold", 256) >= 0){
|
||||
$netCompressionThreshold = $this->configGroup->getPropertyInt("network.batch-threshold", 256);
|
||||
if($this->configGroup->getPropertyInt(Yml::NETWORK_BATCH_THRESHOLD, 256) >= 0){
|
||||
$netCompressionThreshold = $this->configGroup->getPropertyInt(Yml::NETWORK_BATCH_THRESHOLD, 256);
|
||||
}
|
||||
if($netCompressionThreshold < 0){
|
||||
$netCompressionThreshold = null;
|
||||
}
|
||||
|
||||
$netCompressionLevel = $this->configGroup->getPropertyInt("network.compression-level", 6);
|
||||
$netCompressionLevel = $this->configGroup->getPropertyInt(Yml::NETWORK_COMPRESSION_LEVEL, 6);
|
||||
if($netCompressionLevel < 1 || $netCompressionLevel > 9){
|
||||
$this->logger->warning("Invalid network compression level $netCompressionLevel set, setting to default 6");
|
||||
$netCompressionLevel = 6;
|
||||
}
|
||||
ZlibCompressor::setInstance(new ZlibCompressor($netCompressionLevel, $netCompressionThreshold, ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE));
|
||||
|
||||
$this->networkCompressionAsync = $this->configGroup->getPropertyBool("network.async-compression", true);
|
||||
$this->networkCompressionAsync = $this->configGroup->getPropertyBool(Yml::NETWORK_ASYNC_COMPRESSION, true);
|
||||
$this->networkCompressionAsyncThreshold = max(
|
||||
$this->configGroup->getPropertyInt("network.async-compression-threshold", self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD),
|
||||
$this->configGroup->getPropertyInt(Yml::NETWORK_ASYNC_COMPRESSION_THRESHOLD, self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD),
|
||||
$netCompressionThreshold ?? self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD
|
||||
);
|
||||
|
||||
EncryptionContext::$ENABLED = $this->configGroup->getPropertyBool("network.enable-encryption", true);
|
||||
EncryptionContext::$ENABLED = $this->configGroup->getPropertyBool(Yml::NETWORK_ENABLE_ENCRYPTION, true);
|
||||
|
||||
$this->doTitleTick = $this->configGroup->getPropertyBool("console.title-tick", true) && Terminal::hasFormattingCodes();
|
||||
$this->doTitleTick = $this->configGroup->getPropertyBool(Yml::CONSOLE_TITLE_TICK, true) && Terminal::hasFormattingCodes();
|
||||
|
||||
$this->operators = new Config(Path::join($this->dataPath, "ops.txt"), Config::ENUM);
|
||||
$this->whitelist = new Config(Path::join($this->dataPath, "white-list.txt"), Config::ENUM);
|
||||
@ -932,9 +933,9 @@ class Server{
|
||||
$this->banByIP = new BanList($bannedIpsTxt);
|
||||
$this->banByIP->load();
|
||||
|
||||
$this->maxPlayers = $this->configGroup->getConfigInt("max-players", self::DEFAULT_MAX_PLAYERS);
|
||||
$this->maxPlayers = $this->configGroup->getConfigInt(ServerProperties::MAX_PLAYERS, self::DEFAULT_MAX_PLAYERS);
|
||||
|
||||
$this->onlineMode = $this->configGroup->getConfigBool("xbox-auth", true);
|
||||
$this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true);
|
||||
if($this->onlineMode){
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
||||
}else{
|
||||
@ -943,8 +944,8 @@ class Server{
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
}
|
||||
|
||||
if($this->configGroup->getConfigBool("hardcore", false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
$this->configGroup->setConfigInt("difficulty", World::DIFFICULTY_HARD);
|
||||
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
$this->configGroup->setConfigInt(ServerProperties::DIFFICULTY, World::DIFFICULTY_HARD);
|
||||
}
|
||||
|
||||
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
|
||||
@ -963,8 +964,8 @@ class Server{
|
||||
)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool("settings.enable-profiling", false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", self::TARGET_TICKS_PER_SECOND);
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
|
||||
|
||||
DefaultPermissions::registerCorePermissions();
|
||||
|
||||
@ -986,14 +987,14 @@ class Server{
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool("plugins.legacy-data-dir", true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||
$this->pluginManager->registerInterface(new FolderPluginLoader($this->autoloader));
|
||||
|
||||
$providerManager = new WorldProviderManager();
|
||||
if(
|
||||
($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString("level-settings.default-format", ""))) !== null &&
|
||||
($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString(Yml::LEVEL_SETTINGS_DEFAULT_FORMAT, ""))) !== null &&
|
||||
$format instanceof WritableWorldProviderManagerEntry
|
||||
){
|
||||
$providerManager->setDefault($format);
|
||||
@ -1002,10 +1003,10 @@ class Server{
|
||||
}
|
||||
|
||||
$this->worldManager = new WorldManager($this, Path::join($this->dataPath, "worlds"), $providerManager);
|
||||
$this->worldManager->setAutoSave($this->configGroup->getConfigBool("auto-save", $this->worldManager->getAutoSave()));
|
||||
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", $this->worldManager->getAutoSaveInterval()));
|
||||
$this->worldManager->setAutoSave($this->configGroup->getConfigBool(ServerProperties::AUTO_SAVE, $this->worldManager->getAutoSave()));
|
||||
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt(Yml::TICKS_PER_AUTOSAVE, $this->worldManager->getAutoSaveInterval()));
|
||||
|
||||
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString("auto-updater.host", "update.pmmp.io"));
|
||||
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString(Yml::AUTO_UPDATER_HOST, "update.pmmp.io"));
|
||||
|
||||
$this->queryInfo = new QueryInfo($this);
|
||||
|
||||
@ -1042,7 +1043,7 @@ class Server{
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
|
||||
if($this->configGroup->getPropertyBool(Yml::ANONYMOUS_STATISTICS_ENABLED, true)){
|
||||
$this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
|
||||
$this->sendUsage(SendUsageTask::TYPE_OPEN);
|
||||
}
|
||||
@ -1058,7 +1059,7 @@ class Server{
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_USERS, $forwarder);
|
||||
|
||||
//TODO: move console parts to a separate component
|
||||
if($this->configGroup->getPropertyBool("console.enable-input", true)){
|
||||
if($this->configGroup->getPropertyBool(Yml::CONSOLE_ENABLE_INPUT, true)){
|
||||
$this->console = new ConsoleReaderChildProcessDaemon($this->logger);
|
||||
}
|
||||
|
||||
@ -1093,7 +1094,7 @@ class Server{
|
||||
|
||||
$anyWorldFailedToLoad = false;
|
||||
|
||||
foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){
|
||||
foreach((array) $this->configGroup->getProperty(Yml::WORLDS, []) as $name => $options){
|
||||
if($options === null){
|
||||
$options = [];
|
||||
}elseif(!is_array($options)){
|
||||
@ -1137,11 +1138,11 @@ class Server{
|
||||
}
|
||||
|
||||
if($this->worldManager->getDefaultWorld() === null){
|
||||
$default = $this->configGroup->getConfigString("level-name", "world");
|
||||
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
if(trim($default) == ""){
|
||||
$this->getLogger()->warning("level-name cannot be null, using default");
|
||||
$default = "world";
|
||||
$this->configGroup->setConfigString("level-name", "world");
|
||||
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
}
|
||||
if(!$this->worldManager->loadWorld($default, true)){
|
||||
if($this->worldManager->isWorldGenerated($default)){
|
||||
@ -1149,8 +1150,8 @@ class Server{
|
||||
|
||||
return false;
|
||||
}
|
||||
$generatorName = $this->configGroup->getConfigString("level-type");
|
||||
$generatorOptions = $this->configGroup->getConfigString("generator-settings");
|
||||
$generatorName = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_GENERATOR);
|
||||
$generatorOptions = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_GENERATOR_SETTINGS);
|
||||
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
|
||||
|
||||
if($generatorClass === null){
|
||||
@ -1160,7 +1161,7 @@ class Server{
|
||||
$creationOptions = WorldCreationOptions::create()
|
||||
->setGeneratorClass($generatorClass)
|
||||
->setGeneratorOptions($generatorOptions);
|
||||
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed"));
|
||||
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_SEED));
|
||||
if($convertedSeed !== null){
|
||||
$creationOptions->setSeed($convertedSeed);
|
||||
}
|
||||
@ -1214,7 +1215,7 @@ class Server{
|
||||
}
|
||||
|
||||
private function startupPrepareNetworkInterfaces() : bool{
|
||||
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
|
||||
$useQuery = $this->configGroup->getConfigBool(ServerProperties::ENABLE_QUERY, true);
|
||||
|
||||
$typeConverter = TypeConverter::getInstance();
|
||||
$packetSerializerContext = new PacketSerializerContext($typeConverter->getItemTypeDictionary());
|
||||
@ -1224,7 +1225,7 @@ class Server{
|
||||
if(
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter) ||
|
||||
(
|
||||
$this->configGroup->getConfigBool("enable-ipv6", true) &&
|
||||
$this->configGroup->getConfigBool(ServerProperties::ENABLE_IPV6, true) &&
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter)
|
||||
)
|
||||
){
|
||||
@ -1239,7 +1240,7 @@ class Server{
|
||||
$this->network->blockAddress($entry->getName(), -1);
|
||||
}
|
||||
|
||||
if($this->configGroup->getPropertyBool("network.upnp-forwarding", false)){
|
||||
if($this->configGroup->getPropertyBool(Yml::NETWORK_UPNP_FORWARDING, false)){
|
||||
$this->network->registerInterface(new UPnPNetworkInterface($this->logger, Internet::getInternalIP(), $this->getPort()));
|
||||
}
|
||||
|
||||
@ -1459,7 +1460,7 @@ class Server{
|
||||
}
|
||||
|
||||
if(isset($this->network)){
|
||||
$this->network->getSessionManager()->close($this->configGroup->getPropertyString("settings.shutdown-message", "Server closed"));
|
||||
$this->network->getSessionManager()->close($this->configGroup->getPropertyString(YmlServerProperties::SETTINGS_SHUTDOWN_MESSAGE, "Server closed"));
|
||||
}
|
||||
|
||||
if(isset($this->worldManager)){
|
||||
@ -1596,7 +1597,7 @@ class Server{
|
||||
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
||||
|
||||
if($this->configGroup->getPropertyBool("auto-report.enabled", true)){
|
||||
if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){
|
||||
$report = true;
|
||||
|
||||
$stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash");
|
||||
@ -1617,7 +1618,7 @@ class Server{
|
||||
}
|
||||
|
||||
if($report){
|
||||
$url = ($this->configGroup->getPropertyBool("auto-report.use-https", true) ? "https" : "http") . "://" . $this->configGroup->getPropertyString("auto-report.host", "crash.pmmp.io") . "/submit/api";
|
||||
$url = ($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_USE_HTTPS, true) ? "https" : "http") . "://" . $this->configGroup->getPropertyString(Yml::AUTO_REPORT_HOST, "crash.pmmp.io") . "/submit/api";
|
||||
$postUrlError = "Unknown error";
|
||||
$reply = Internet::postURL($url, [
|
||||
"report" => "yes",
|
||||
@ -1728,7 +1729,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function sendUsage(int $type = SendUsageTask::TYPE_STATUS) : void{
|
||||
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
|
||||
if($this->configGroup->getPropertyBool(Yml::ANONYMOUS_STATISTICS_ENABLED, true)){
|
||||
$this->asyncPool->submitTask(new SendUsageTask($this, $type, $this->uniquePlayers));
|
||||
}
|
||||
$this->uniquePlayers = [];
|
||||
|
58
src/ServerProperties.php
Normal file
58
src/ServerProperties.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Constants for all properties available in server.properties.
|
||||
*/
|
||||
final class ServerProperties{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public const AUTO_SAVE = "auto-save";
|
||||
public const DEFAULT_WORLD_GENERATOR = "level-type";
|
||||
public const DEFAULT_WORLD_GENERATOR_SETTINGS = "generator-settings";
|
||||
public const DEFAULT_WORLD_NAME = "level-name";
|
||||
public const DEFAULT_WORLD_SEED = "level-seed";
|
||||
public const DIFFICULTY = "difficulty";
|
||||
public const ENABLE_IPV6 = "enable-ipv6";
|
||||
public const ENABLE_QUERY = "enable-query";
|
||||
public const FORCE_GAME_MODE = "force-gamemode";
|
||||
public const GAME_MODE = "gamemode";
|
||||
public const HARDCORE = "hardcore";
|
||||
public const LANGUAGE = "language";
|
||||
public const MAX_PLAYERS = "max-players";
|
||||
public const MOTD = "motd";
|
||||
public const PVP = "pvp";
|
||||
public const SERVER_IPV4 = "server-ip";
|
||||
public const SERVER_IPV6 = "server-ipv6";
|
||||
public const SERVER_PORT_IPV4 = "server-port";
|
||||
public const SERVER_PORT_IPV6 = "server-portv6";
|
||||
public const VIEW_DISTANCE = "view-distance";
|
||||
public const WHITELIST = "white-list";
|
||||
public const XBOX_AUTH = "xbox-auth";
|
||||
}
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.4.3";
|
||||
public const BASE_VERSION = "5.5.1";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
118
src/YmlServerProperties.php
Normal file
118
src/YmlServerProperties.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Constants for all properties available in pocketmine.yml.
|
||||
* This is generated by build/generate-pocketmine-yml-property-consts.php.
|
||||
* Do not edit this file manually.
|
||||
*/
|
||||
final class YmlServerProperties{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public const ALIASES = 'aliases';
|
||||
public const ANONYMOUS_STATISTICS = 'anonymous-statistics';
|
||||
public const ANONYMOUS_STATISTICS_ENABLED = 'anonymous-statistics.enabled';
|
||||
public const ANONYMOUS_STATISTICS_HOST = 'anonymous-statistics.host';
|
||||
public const AUTO_REPORT = 'auto-report';
|
||||
public const AUTO_REPORT_ENABLED = 'auto-report.enabled';
|
||||
public const AUTO_REPORT_HOST = 'auto-report.host';
|
||||
public const AUTO_REPORT_SEND_CODE = 'auto-report.send-code';
|
||||
public const AUTO_REPORT_SEND_PHPINFO = 'auto-report.send-phpinfo';
|
||||
public const AUTO_REPORT_SEND_SETTINGS = 'auto-report.send-settings';
|
||||
public const AUTO_REPORT_USE_HTTPS = 'auto-report.use-https';
|
||||
public const AUTO_UPDATER = 'auto-updater';
|
||||
public const AUTO_UPDATER_ENABLED = 'auto-updater.enabled';
|
||||
public const AUTO_UPDATER_HOST = 'auto-updater.host';
|
||||
public const AUTO_UPDATER_ON_UPDATE = 'auto-updater.on-update';
|
||||
public const AUTO_UPDATER_ON_UPDATE_WARN_CONSOLE = 'auto-updater.on-update.warn-console';
|
||||
public const AUTO_UPDATER_PREFERRED_CHANNEL = 'auto-updater.preferred-channel';
|
||||
public const AUTO_UPDATER_SUGGEST_CHANNELS = 'auto-updater.suggest-channels';
|
||||
public const CHUNK_GENERATION = 'chunk-generation';
|
||||
public const CHUNK_GENERATION_POPULATION_QUEUE_SIZE = 'chunk-generation.population-queue-size';
|
||||
public const CHUNK_SENDING = 'chunk-sending';
|
||||
public const CHUNK_SENDING_PER_TICK = 'chunk-sending.per-tick';
|
||||
public const CHUNK_SENDING_SPAWN_RADIUS = 'chunk-sending.spawn-radius';
|
||||
public const CHUNK_TICKING = 'chunk-ticking';
|
||||
public const CHUNK_TICKING_BLOCKS_PER_SUBCHUNK_PER_TICK = 'chunk-ticking.blocks-per-subchunk-per-tick';
|
||||
public const CHUNK_TICKING_DISABLE_BLOCK_TICKING = 'chunk-ticking.disable-block-ticking';
|
||||
public const CHUNK_TICKING_TICK_RADIUS = 'chunk-ticking.tick-radius';
|
||||
public const CONSOLE = 'console';
|
||||
public const CONSOLE_ENABLE_INPUT = 'console.enable-input';
|
||||
public const CONSOLE_TITLE_TICK = 'console.title-tick';
|
||||
public const DEBUG = 'debug';
|
||||
public const DEBUG_LEVEL = 'debug.level';
|
||||
public const LEVEL_SETTINGS = 'level-settings';
|
||||
public const LEVEL_SETTINGS_DEFAULT_FORMAT = 'level-settings.default-format';
|
||||
public const MEMORY = 'memory';
|
||||
public const MEMORY_ASYNC_WORKER_HARD_LIMIT = 'memory.async-worker-hard-limit';
|
||||
public const MEMORY_CHECK_RATE = 'memory.check-rate';
|
||||
public const MEMORY_CONTINUOUS_TRIGGER = 'memory.continuous-trigger';
|
||||
public const MEMORY_CONTINUOUS_TRIGGER_RATE = 'memory.continuous-trigger-rate';
|
||||
public const MEMORY_GARBAGE_COLLECTION = 'memory.garbage-collection';
|
||||
public const MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER = 'memory.garbage-collection.collect-async-worker';
|
||||
public const MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER = 'memory.garbage-collection.low-memory-trigger';
|
||||
public const MEMORY_GARBAGE_COLLECTION_PERIOD = 'memory.garbage-collection.period';
|
||||
public const MEMORY_GLOBAL_LIMIT = 'memory.global-limit';
|
||||
public const MEMORY_MAIN_HARD_LIMIT = 'memory.main-hard-limit';
|
||||
public const MEMORY_MAIN_LIMIT = 'memory.main-limit';
|
||||
public const MEMORY_MAX_CHUNKS = 'memory.max-chunks';
|
||||
public const MEMORY_MAX_CHUNKS_CHUNK_RADIUS = 'memory.max-chunks.chunk-radius';
|
||||
public const MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT = 'memory.max-chunks.trigger-chunk-collect';
|
||||
public const MEMORY_MEMORY_DUMP = 'memory.memory-dump';
|
||||
public const MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER = 'memory.memory-dump.dump-async-worker';
|
||||
public const MEMORY_WORLD_CACHES = 'memory.world-caches';
|
||||
public const MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE = 'memory.world-caches.disable-chunk-cache';
|
||||
public const MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER = 'memory.world-caches.low-memory-trigger';
|
||||
public const NETWORK = 'network';
|
||||
public const NETWORK_ASYNC_COMPRESSION = 'network.async-compression';
|
||||
public const NETWORK_ASYNC_COMPRESSION_THRESHOLD = 'network.async-compression-threshold';
|
||||
public const NETWORK_BATCH_THRESHOLD = 'network.batch-threshold';
|
||||
public const NETWORK_COMPRESSION_LEVEL = 'network.compression-level';
|
||||
public const NETWORK_ENABLE_ENCRYPTION = 'network.enable-encryption';
|
||||
public const NETWORK_MAX_MTU_SIZE = 'network.max-mtu-size';
|
||||
public const NETWORK_UPNP_FORWARDING = 'network.upnp-forwarding';
|
||||
public const PLAYER = 'player';
|
||||
public const PLAYER_SAVE_PLAYER_DATA = 'player.save-player-data';
|
||||
public const PLAYER_VERIFY_XUID = 'player.verify-xuid';
|
||||
public const PLUGINS = 'plugins';
|
||||
public const PLUGINS_LEGACY_DATA_DIR = 'plugins.legacy-data-dir';
|
||||
public const SETTINGS = 'settings';
|
||||
public const SETTINGS_ASYNC_WORKERS = 'settings.async-workers';
|
||||
public const SETTINGS_ENABLE_DEV_BUILDS = 'settings.enable-dev-builds';
|
||||
public const SETTINGS_ENABLE_PROFILING = 'settings.enable-profiling';
|
||||
public const SETTINGS_FORCE_LANGUAGE = 'settings.force-language';
|
||||
public const SETTINGS_PROFILE_REPORT_TRIGGER = 'settings.profile-report-trigger';
|
||||
public const SETTINGS_QUERY_PLUGINS = 'settings.query-plugins';
|
||||
public const SETTINGS_SHUTDOWN_MESSAGE = 'settings.shutdown-message';
|
||||
public const TICKS_PER = 'ticks-per';
|
||||
public const TICKS_PER_AUTOSAVE = 'ticks-per.autosave';
|
||||
public const TIMINGS = 'timings';
|
||||
public const TIMINGS_HOST = 'timings.host';
|
||||
public const WORLDS = 'worlds';
|
||||
}
|
@ -49,6 +49,8 @@ abstract class BaseSign extends Transparent{
|
||||
use WoodTypeTrait;
|
||||
|
||||
protected SignText $text;
|
||||
private bool $waxed = false;
|
||||
|
||||
protected ?int $editorEntityRuntimeId = null;
|
||||
|
||||
/** @var \Closure() : Item */
|
||||
@ -69,6 +71,7 @@ abstract class BaseSign extends Transparent{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileSign){
|
||||
$this->text = $tile->getText();
|
||||
$this->waxed = $tile->isWaxed();
|
||||
$this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
|
||||
}
|
||||
|
||||
@ -80,6 +83,7 @@ abstract class BaseSign extends Transparent{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
assert($tile instanceof TileSign);
|
||||
$tile->setText($this->text);
|
||||
$tile->setWaxed($this->waxed);
|
||||
$tile->setEditorEntityRuntimeId($this->editorEntityRuntimeId);
|
||||
}
|
||||
|
||||
@ -147,10 +151,26 @@ abstract class BaseSign extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function wax(Player $player, Item $item) : bool{
|
||||
if($this->waxed){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->waxed = true;
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$item->pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player === null){
|
||||
return false;
|
||||
}
|
||||
if($this->waxed){
|
||||
return true;
|
||||
}
|
||||
|
||||
$dyeColor = $item instanceof Dye ? $item->getColor() : match($item->getTypeId()){
|
||||
ItemTypeIds::BONE_MEAL => DyeColor::WHITE(),
|
||||
ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE(),
|
||||
@ -159,20 +179,25 @@ abstract class BaseSign extends Transparent{
|
||||
};
|
||||
if($dyeColor !== null){
|
||||
$color = $dyeColor->equals(DyeColor::BLACK()) ? new Color(0, 0, 0) : $dyeColor->getRgbValue();
|
||||
if($color->toARGB() === $this->text->getBaseColor()->toARGB()){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)){
|
||||
if(
|
||||
$color->toARGB() !== $this->text->getBaseColor()->toARGB() &&
|
||||
$this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)
|
||||
){
|
||||
$this->position->getWorld()->addSound($this->position, new DyeUseSound());
|
||||
return true;
|
||||
}
|
||||
}elseif($item->getTypeId() === ItemTypeIds::INK_SAC){
|
||||
return $this->changeSignGlowingState(false, $player, $item);
|
||||
}elseif($item->getTypeId() === ItemTypeIds::GLOW_INK_SAC){
|
||||
return $this->changeSignGlowingState(true, $player, $item);
|
||||
}elseif(match($item->getTypeId()){
|
||||
ItemTypeIds::INK_SAC => $this->changeSignGlowingState(false, $player, $item),
|
||||
ItemTypeIds::GLOW_INK_SAC => $this->changeSignGlowingState(true, $player, $item),
|
||||
ItemTypeIds::HONEYCOMB => $this->wax($player, $item),
|
||||
default => false
|
||||
}){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
$player->openSignEditor($this->position);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,6 +213,17 @@ abstract class BaseSign extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the sign has been waxed using a honeycomb. If true, the sign cannot be edited by a player.
|
||||
*/
|
||||
public function isWaxed() : bool{ return $this->waxed; }
|
||||
|
||||
/** @return $this */
|
||||
public function setWaxed(bool $waxed) : self{
|
||||
$this->waxed = $waxed;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the runtime entity ID of the player editing this sign. Only this player will be able to edit the sign.
|
||||
* This is used to prevent multiple players from editing the same sign at the same time, and to prevent players
|
||||
@ -217,8 +253,8 @@ abstract class BaseSign extends Transparent{
|
||||
}
|
||||
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) : string{
|
||||
return TextFormat::clean($line, false);
|
||||
}, $text->getLines())));
|
||||
if($this->editorEntityRuntimeId === null || $this->editorEntityRuntimeId !== $author->getId()){
|
||||
}, $text->getLines()), $this->text->getBaseColor(), $this->text->isGlowing()));
|
||||
if($this->waxed || $this->editorEntityRuntimeId !== $author->getId()){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
|
@ -42,7 +42,7 @@ class Fence extends Transparent{
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$block = $this->getSide($facing);
|
||||
if($block instanceof static || $block instanceof FenceGate || ($block->isSolid() && !$block->isTransparent())){
|
||||
if($block instanceof static || $block instanceof FenceGate || $block->getSupportType(Facing::opposite($facing))->equals(SupportType::FULL())){
|
||||
$this->connections[$facing] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
|
@ -41,7 +41,7 @@ class Thin extends Transparent{
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$side = $this->getSide($facing);
|
||||
if($side instanceof Thin || $side instanceof Wall || $side->isFullCube()){
|
||||
if($side instanceof Thin || $side instanceof Wall || $side->getSupportType(Facing::opposite($facing))->equals(SupportType::FULL())){
|
||||
$this->connections[$facing] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
|
@ -101,7 +101,7 @@ class Wall extends Transparent{
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$block = $this->getSide($facing);
|
||||
if($block instanceof static || $block instanceof FenceGate || $block instanceof Thin || ($block->isSolid() && !$block->isTransparent())){
|
||||
if($block instanceof static || $block instanceof FenceGate || $block instanceof Thin || $block->getSupportType(Facing::opposite($facing))->equals(SupportType::FULL())){
|
||||
if(!isset($this->connections[$facing])){
|
||||
$this->connections[$facing] = WallConnectionType::SHORT();
|
||||
$changed++;
|
||||
|
@ -23,11 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\event\player\PlayerEnchantOptionsRequestEvent;
|
||||
use pocketmine\event\player\PlayerEnchantingOptionsRequestEvent;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\item\enchantment\EnchantmentHelper as Helper;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\item\enchantment\EnchantingHelper as Helper;
|
||||
use pocketmine\item\enchantment\EnchantingOption;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\world\Position;
|
||||
use function array_values;
|
||||
@ -39,7 +39,7 @@ class EnchantInventory extends SimpleInventory implements BlockInventory, Tempor
|
||||
public const SLOT_INPUT = 0;
|
||||
public const SLOT_LAPIS = 1;
|
||||
|
||||
/** @var EnchantOption[] $options */
|
||||
/** @var EnchantingOption[] $options */
|
||||
private array $options = [];
|
||||
|
||||
public function __construct(Position $holder){
|
||||
@ -52,9 +52,9 @@ class EnchantInventory extends SimpleInventory implements BlockInventory, Tempor
|
||||
foreach($this->viewers as $viewer){
|
||||
$this->options = [];
|
||||
$item = $this->getInput();
|
||||
$options = Helper::getEnchantOptions($this->holder, $item, $viewer->getEnchantmentSeed());
|
||||
$options = Helper::generateOptions($this->holder, $item, $viewer->getEnchantmentSeed());
|
||||
|
||||
$event = new PlayerEnchantOptionsRequestEvent($viewer, $this, $options);
|
||||
$event = new PlayerEnchantingOptionsRequestEvent($viewer, $this, $options);
|
||||
$event->call();
|
||||
if(!$event->isCancelled() && count($event->getOptions()) > 0){
|
||||
$this->options = array_values($event->getOptions());
|
||||
@ -79,7 +79,7 @@ class EnchantInventory extends SimpleInventory implements BlockInventory, Tempor
|
||||
return $option === null ? null : Helper::enchantItem($this->getInput(), $option->getEnchantments());
|
||||
}
|
||||
|
||||
public function getOption(int $optionId) : ?EnchantOption{
|
||||
public function getOption(int $optionId) : ?EnchantingOption{
|
||||
return $this->options[$optionId] ?? null;
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,6 @@ final class SmithingTableInventory extends SimpleInventory implements BlockInven
|
||||
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(2);
|
||||
parent::__construct(3);
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,8 @@ class Sign extends Spawnable{
|
||||
}
|
||||
|
||||
protected SignText $text;
|
||||
private bool $waxed = false;
|
||||
|
||||
protected ?int $editorEntityRuntimeId = null;
|
||||
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
@ -101,6 +103,7 @@ class Sign extends Spawnable{
|
||||
}
|
||||
$this->text = new SignText($text);
|
||||
}
|
||||
$this->waxed = $nbt->getByte(self::TAG_WAXED, 0) !== 0;
|
||||
}
|
||||
|
||||
protected function writeSaveData(CompoundTag $nbt) : void{
|
||||
@ -113,6 +116,7 @@ class Sign extends Spawnable{
|
||||
$nbt->setInt(self::TAG_TEXT_COLOR, Binary::signInt($this->text->getBaseColor()->toARGB()));
|
||||
$nbt->setByte(self::TAG_GLOWING_TEXT, $this->text->isGlowing() ? 1 : 0);
|
||||
$nbt->setByte(self::TAG_LEGACY_BUG_RESOLVE, 1);
|
||||
$nbt->setByte(self::TAG_WAXED, $this->waxed ? 1 : 0);
|
||||
}
|
||||
|
||||
public function getText() : SignText{
|
||||
@ -123,6 +127,10 @@ class Sign extends Spawnable{
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
public function isWaxed() : bool{ return $this->waxed; }
|
||||
|
||||
public function setWaxed(bool $waxed) : void{ $this->waxed = $waxed; }
|
||||
|
||||
/**
|
||||
* Returns the entity runtime ID of the player who placed this sign. Only the player whose entity ID matches this
|
||||
* one may edit the sign text.
|
||||
@ -153,7 +161,7 @@ class Sign extends Spawnable{
|
||||
->setByte(self::TAG_GLOWING_TEXT, 0)
|
||||
->setByte(self::TAG_PERSIST_FORMATTING, 1)
|
||||
);
|
||||
$nbt->setByte(self::TAG_WAXED, 0);
|
||||
$nbt->setByte(self::TAG_WAXED, $this->waxed ? 1 : 0);
|
||||
$nbt->setLong(self::TAG_LOCKED_FOR_EDITING_BY, $this->editorEntityRuntimeId ?? -1);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\GameMode;
|
||||
use pocketmine\ServerProperties;
|
||||
use function count;
|
||||
|
||||
class DefaultGamemodeCommand extends VanillaCommand{
|
||||
@ -52,7 +53,7 @@ class DefaultGamemodeCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
$sender->getServer()->getConfigGroup()->setConfigString("gamemode", $gameMode->name());
|
||||
$sender->getServer()->getConfigGroup()->setConfigString(ServerProperties::GAME_MODE, $gameMode->name());
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_defaultgamemode_success($gameMode->getTranslatableName()));
|
||||
return true;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\command\CommandSender;
|
||||
use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\ServerProperties;
|
||||
use pocketmine\world\World;
|
||||
use function count;
|
||||
|
||||
@ -54,7 +55,7 @@ class DifficultyCommand extends VanillaCommand{
|
||||
}
|
||||
|
||||
if($difficulty !== -1){
|
||||
$sender->getServer()->getConfigGroup()->setConfigInt("difficulty", $difficulty);
|
||||
$sender->getServer()->getConfigGroup()->setConfigInt(ServerProperties::DIFFICULTY, $difficulty);
|
||||
|
||||
//TODO: add per-world support
|
||||
foreach($sender->getServer()->getWorldManager()->getWorlds() as $world){
|
||||
|
@ -25,7 +25,7 @@ namespace pocketmine\command\defaults;
|
||||
|
||||
use pocketmine\command\CommandSender;
|
||||
use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\item\enchantment\EnchantmentHelper;
|
||||
use pocketmine\item\enchantment\EnchantingHelper;
|
||||
use pocketmine\item\enchantment\EnchantmentInstance;
|
||||
use pocketmine\item\enchantment\StringToEnchantmentParser;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
@ -78,7 +78,7 @@ class EnchantCommand extends VanillaCommand{
|
||||
}
|
||||
|
||||
//this is necessary to deal with enchanted books, which are a different item type than regular books
|
||||
$enchantedItem = EnchantmentHelper::enchantItem($item, [new EnchantmentInstance($enchantment, $level)]);
|
||||
$enchantedItem = EnchantingHelper::enchantItem($item, [new EnchantmentInstance($enchantment, $level)]);
|
||||
$player->getInventory()->setItemInHand($enchantedItem);
|
||||
|
||||
self::broadcastCommandMessage($sender, KnownTranslationFactory::commands_enchant_success($player->getName()));
|
||||
|
@ -35,6 +35,7 @@ use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\utils\InternetException;
|
||||
use pocketmine\utils\InternetRequestResult;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function count;
|
||||
use function fclose;
|
||||
@ -130,7 +131,7 @@ class TimingsCommand extends VanillaCommand{
|
||||
];
|
||||
fclose($fileTimings);
|
||||
|
||||
$host = $sender->getServer()->getConfigGroup()->getPropertyString("timings.host", "timings.pmmp.io");
|
||||
$host = $sender->getServer()->getConfigGroup()->getPropertyString(YmlServerProperties::TIMINGS_HOST, "timings.pmmp.io");
|
||||
|
||||
$sender->getServer()->getAsyncPool()->submitTask(new BulkCurlTask(
|
||||
[new BulkCurlTaskOperation(
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\ServerProperties;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
@ -71,7 +72,7 @@ class WhitelistCommand extends VanillaCommand{
|
||||
case "on":
|
||||
if($this->testPermission($sender, DefaultPermissionNames::COMMAND_WHITELIST_ENABLE)){
|
||||
$server = $sender->getServer();
|
||||
$server->getConfigGroup()->setConfigBool("white-list", true);
|
||||
$server->getConfigGroup()->setConfigBool(ServerProperties::WHITELIST, true);
|
||||
$this->kickNonWhitelistedPlayers($server);
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_whitelist_enabled());
|
||||
}
|
||||
@ -79,7 +80,7 @@ class WhitelistCommand extends VanillaCommand{
|
||||
return true;
|
||||
case "off":
|
||||
if($this->testPermission($sender, DefaultPermissionNames::COMMAND_WHITELIST_DISABLE)){
|
||||
$sender->getServer()->getConfigGroup()->setConfigBool("white-list", false);
|
||||
$sender->getServer()->getConfigGroup()->setConfigBool(ServerProperties::WHITELIST, false);
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_whitelist_disabled());
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\VersionInfo;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_map;
|
||||
use function base64_encode;
|
||||
@ -152,7 +153,7 @@ class CrashDump{
|
||||
private function extraData() : void{
|
||||
global $argv;
|
||||
|
||||
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-settings", true)){
|
||||
if($this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::AUTO_REPORT_SEND_SETTINGS, true)){
|
||||
$this->data->parameters = (array) $argv;
|
||||
if(($serverDotProperties = @file_get_contents(Path::join($this->server->getDataPath(), "server.properties"))) !== false){
|
||||
$this->data->serverDotProperties = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties) ?? throw new AssumptionFailedError("Pattern is valid");
|
||||
@ -170,7 +171,7 @@ class CrashDump{
|
||||
|
||||
$this->data->jit_mode = Utils::getOpcacheJitMode();
|
||||
|
||||
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-phpinfo", true)){
|
||||
if($this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::AUTO_REPORT_SEND_PHPINFO, true)){
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$this->data->phpinfo = ob_get_contents(); // @phpstan-ignore-line
|
||||
@ -206,6 +207,7 @@ class CrashDump{
|
||||
if(isset($lastError)){
|
||||
$this->data->lastError = $lastError;
|
||||
$this->data->lastError["message"] = mb_scrub($this->data->lastError["message"], 'UTF-8');
|
||||
$this->data->lastError["trace"] = array_map(array: $lastError["trace"], callback: fn(ThreadCrashInfoFrame $frame) => $frame->getPrintableFrame());
|
||||
}
|
||||
|
||||
$this->data->error = $error;
|
||||
@ -225,7 +227,7 @@ class CrashDump{
|
||||
}
|
||||
}
|
||||
|
||||
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-code", true) && file_exists($error["fullFile"])){
|
||||
if($this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::AUTO_REPORT_SEND_CODE, true) && file_exists($error["fullFile"])){
|
||||
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
|
||||
if($file !== false){
|
||||
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 && isset($file[$l]); ++$l){
|
||||
|
@ -29,18 +29,10 @@ use pocketmine\utils\SingletonTrait;
|
||||
|
||||
final class DyeColorIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var DyeColor[]
|
||||
* @phpstan-var array<int, DyeColor>
|
||||
*/
|
||||
private array $idToEnum = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<DyeColor> */
|
||||
use IntSaveIdMapTrait {
|
||||
register as registerInt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var DyeColor[]
|
||||
@ -74,16 +66,11 @@ final class DyeColorIdMap{
|
||||
}
|
||||
|
||||
private function register(int $id, string $itemId, DyeColor $color) : void{
|
||||
$this->idToEnum[$id] = $color;
|
||||
$this->enumToId[$color->id()] = $id;
|
||||
$this->registerInt($id, $color);
|
||||
$this->itemIdToEnum[$itemId] = $color;
|
||||
$this->enumToItemId[$color->id()] = $itemId;
|
||||
}
|
||||
|
||||
public function toId(DyeColor $color) : int{
|
||||
return $this->enumToId[$color->id()]; //TODO: is it possible for this to be missing?
|
||||
}
|
||||
|
||||
public function toInvertedId(DyeColor $color) : int{
|
||||
return ~$this->toId($color) & 0xf;
|
||||
}
|
||||
@ -92,10 +79,6 @@ final class DyeColorIdMap{
|
||||
return $this->enumToItemId[$color->id()];
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?DyeColor{
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
public function fromInvertedId(int $id) : ?DyeColor{
|
||||
return $this->fromId(~$id & 0xf);
|
||||
}
|
||||
|
@ -26,23 +26,11 @@ namespace pocketmine\data\bedrock;
|
||||
use pocketmine\entity\effect\Effect;
|
||||
use pocketmine\entity\effect\VanillaEffects;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use function array_key_exists;
|
||||
use function spl_object_id;
|
||||
|
||||
final class EffectIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var Effect[]
|
||||
* @phpstan-var array<int, Effect>
|
||||
*/
|
||||
private array $idToEffect = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $effectToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<Effect> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(EffectIds::SPEED, VanillaEffects::SPEED());
|
||||
@ -76,24 +64,4 @@ final class EffectIdMap{
|
||||
//TODO: VILLAGE_HERO
|
||||
$this->register(EffectIds::DARKNESS, VanillaEffects::DARKNESS());
|
||||
}
|
||||
|
||||
//TODO: not a big fan of the code duplication here :(
|
||||
|
||||
public function register(int $mcpeId, Effect $effect) : void{
|
||||
$this->idToEffect[$mcpeId] = $effect;
|
||||
$this->effectToId[spl_object_id($effect)] = $mcpeId;
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?Effect{
|
||||
//we might not have all the effect IDs registered
|
||||
return $this->idToEffect[$id] ?? null;
|
||||
}
|
||||
|
||||
public function toId(Effect $effect) : int{
|
||||
if(!array_key_exists(spl_object_id($effect), $this->effectToId)){
|
||||
//this should never happen, so we treat it as an exceptional condition
|
||||
throw new \InvalidArgumentException("Effect does not have a mapped ID");
|
||||
}
|
||||
return $this->effectToId[spl_object_id($effect)];
|
||||
}
|
||||
}
|
||||
|
@ -26,25 +26,14 @@ namespace pocketmine\data\bedrock;
|
||||
use pocketmine\item\enchantment\Enchantment;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use function array_key_exists;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
* Handles translation of internal enchantment types to and from Minecraft: Bedrock IDs.
|
||||
*/
|
||||
final class EnchantmentIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var Enchantment[]
|
||||
* @phpstan-var array<int, Enchantment>
|
||||
*/
|
||||
private array $idToEnch = [];
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enchToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<Enchantment> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(EnchantmentIds::PROTECTION, VanillaEnchantments::PROTECTION());
|
||||
@ -77,22 +66,4 @@ final class EnchantmentIdMap{
|
||||
|
||||
$this->register(EnchantmentIds::SWIFT_SNEAK, VanillaEnchantments::SWIFT_SNEAK());
|
||||
}
|
||||
|
||||
public function register(int $mcpeId, Enchantment $enchantment) : void{
|
||||
$this->idToEnch[$mcpeId] = $enchantment;
|
||||
$this->enchToId[spl_object_id($enchantment)] = $mcpeId;
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?Enchantment{
|
||||
//we might not have all the enchantment IDs registered
|
||||
return $this->idToEnch[$id] ?? null;
|
||||
}
|
||||
|
||||
public function toId(Enchantment $enchantment) : int{
|
||||
if(!array_key_exists(spl_object_id($enchantment), $this->enchToId)){
|
||||
//this should never happen, so we treat it as an exceptional condition
|
||||
throw new \InvalidArgumentException("Enchantment does not have a mapped ID");
|
||||
}
|
||||
return $this->enchToId[spl_object_id($enchantment)];
|
||||
}
|
||||
}
|
||||
|
81
src/data/bedrock/IntSaveIdMapTrait.php
Normal file
81
src/data/bedrock/IntSaveIdMapTrait.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock;
|
||||
|
||||
use function array_key_exists;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
* @phpstan-template TObject of object
|
||||
*/
|
||||
trait IntSaveIdMapTrait{
|
||||
|
||||
/**
|
||||
* @var object[]
|
||||
* @phpstan-var array<int, TObject>
|
||||
*/
|
||||
private array $idToEnum = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId = [];
|
||||
|
||||
/**
|
||||
* @phpstan-param TObject $enum
|
||||
*/
|
||||
protected function getRuntimeId(object $enum) : int{
|
||||
//this is fine for enums and non-cloning object registries
|
||||
return spl_object_id($enum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param TObject $enum
|
||||
*/
|
||||
public function register(int $saveId, object $enum) : void{
|
||||
$this->idToEnum[$saveId] = $enum;
|
||||
$this->enumToId[$this->getRuntimeId($enum)] = $saveId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return TObject|null
|
||||
*/
|
||||
public function fromId(int $id) : ?object{
|
||||
//we might not have all the effect IDs registered
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param TObject $enum
|
||||
*/
|
||||
public function toId(object $enum) : int{
|
||||
$runtimeId = $this->getRuntimeId($enum);
|
||||
if(!array_key_exists($runtimeId, $this->enumToId)){
|
||||
//this should never happen, so we treat it as an exceptional condition
|
||||
throw new \InvalidArgumentException("Object does not have a mapped save ID");
|
||||
}
|
||||
return $this->enumToId[$runtimeId];
|
||||
}
|
||||
}
|
@ -28,18 +28,8 @@ use pocketmine\utils\SingletonTrait;
|
||||
|
||||
final class MedicineTypeIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var MedicineType[]
|
||||
* @phpstan-var array<int, MedicineType>
|
||||
*/
|
||||
private array $idToEnum = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<MedicineType> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(MedicineTypeIds::ANTIDOTE, MedicineType::ANTIDOTE());
|
||||
@ -47,20 +37,4 @@ final class MedicineTypeIdMap{
|
||||
$this->register(MedicineTypeIds::EYE_DROPS, MedicineType::EYE_DROPS());
|
||||
$this->register(MedicineTypeIds::TONIC, MedicineType::TONIC());
|
||||
}
|
||||
|
||||
private function register(int $id, MedicineType $type) : void{
|
||||
$this->idToEnum[$id] = $type;
|
||||
$this->enumToId[$type->id()] = $id;
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?MedicineType{
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
public function toId(MedicineType $type) : int{
|
||||
if(!isset($this->enumToId[$type->id()])){
|
||||
throw new \InvalidArgumentException("Type does not have a mapped ID");
|
||||
}
|
||||
return $this->enumToId[$type->id()];
|
||||
}
|
||||
}
|
||||
|
@ -28,18 +28,8 @@ use pocketmine\utils\SingletonTrait;
|
||||
|
||||
final class MobHeadTypeIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var MobHeadType[]
|
||||
* @phpstan-var array<int, MobHeadType>
|
||||
*/
|
||||
private array $idToEnum = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<MobHeadType> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(0, MobHeadType::SKELETON());
|
||||
@ -50,20 +40,4 @@ final class MobHeadTypeIdMap{
|
||||
$this->register(5, MobHeadType::DRAGON());
|
||||
$this->register(6, MobHeadType::PIGLIN());
|
||||
}
|
||||
|
||||
private function register(int $id, MobHeadType $type) : void{
|
||||
$this->idToEnum[$id] = $type;
|
||||
$this->enumToId[$type->id()] = $id;
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?MobHeadType{
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
public function toId(MobHeadType $type) : int{
|
||||
if(!isset($this->enumToId[$type->id()])){
|
||||
throw new \InvalidArgumentException("Type does not have a mapped ID");
|
||||
}
|
||||
return $this->enumToId[$type->id()];
|
||||
}
|
||||
}
|
||||
|
@ -26,21 +26,11 @@ namespace pocketmine\data\bedrock;
|
||||
use pocketmine\block\utils\MushroomBlockType;
|
||||
use pocketmine\data\bedrock\block\BlockLegacyMetadata as LegacyMeta;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use function array_key_exists;
|
||||
|
||||
final class MushroomBlockTypeIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var MushroomBlockType[]
|
||||
* @phpstan-var array<int, MushroomBlockType>
|
||||
*/
|
||||
private array $idToEnum = [];
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<MushroomBlockType> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
public function __construct(){
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_ALL_PORES, MushroomBlockType::PORES());
|
||||
@ -55,20 +45,4 @@ final class MushroomBlockTypeIdMap{
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER, MushroomBlockType::CAP_SOUTHEAST());
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_ALL_CAP, MushroomBlockType::ALL_CAP());
|
||||
}
|
||||
|
||||
public function register(int $id, MushroomBlockType $type) : void{
|
||||
$this->idToEnum[$id] = $type;
|
||||
$this->enumToId[$type->id()] = $id;
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?MushroomBlockType{
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
public function toId(MushroomBlockType $type) : int{
|
||||
if(!array_key_exists($type->id(), $this->enumToId)){
|
||||
throw new \InvalidArgumentException("Mushroom block type does not have a mapped ID"); //this should never happen
|
||||
}
|
||||
return $this->enumToId[$type->id()];
|
||||
}
|
||||
}
|
||||
|
@ -28,18 +28,8 @@ use pocketmine\world\sound\NoteInstrument;
|
||||
|
||||
final class NoteInstrumentIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var NoteInstrument[]
|
||||
* @phpstan-var array<int, NoteInstrument>
|
||||
*/
|
||||
private array $idToEnum = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<NoteInstrument> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(0, NoteInstrument::PIANO());
|
||||
@ -59,20 +49,4 @@ final class NoteInstrumentIdMap{
|
||||
$this->register(14, NoteInstrument::BANJO());
|
||||
$this->register(15, NoteInstrument::PLING());
|
||||
}
|
||||
|
||||
private function register(int $id, NoteInstrument $instrument) : void{
|
||||
$this->idToEnum[$id] = $instrument;
|
||||
$this->enumToId[$instrument->id()] = $id;
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?NoteInstrument{
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
public function toId(NoteInstrument $instrument) : int{
|
||||
if(!isset($this->enumToId[$instrument->id()])){
|
||||
throw new \InvalidArgumentException("Type does not have a mapped ID");
|
||||
}
|
||||
return $this->enumToId[$instrument->id()];
|
||||
}
|
||||
}
|
||||
|
@ -28,18 +28,8 @@ use pocketmine\utils\SingletonTrait;
|
||||
|
||||
final class PotionTypeIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var PotionType[]
|
||||
* @phpstan-var array<int, PotionType>
|
||||
*/
|
||||
private array $idToEnum = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<PotionType> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(PotionTypeIds::WATER, PotionType::WATER());
|
||||
@ -86,20 +76,4 @@ final class PotionTypeIdMap{
|
||||
$this->register(PotionTypeIds::LONG_SLOW_FALLING, PotionType::LONG_SLOW_FALLING());
|
||||
$this->register(PotionTypeIds::STRONG_SLOWNESS, PotionType::STRONG_SLOWNESS());
|
||||
}
|
||||
|
||||
private function register(int $id, PotionType $type) : void{
|
||||
$this->idToEnum[$id] = $type;
|
||||
$this->enumToId[$type->id()] = $id;
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?PotionType{
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
public function toId(PotionType $type) : int{
|
||||
if(!isset($this->enumToId[$type->id()])){
|
||||
throw new \InvalidArgumentException("Type does not have a mapped ID");
|
||||
}
|
||||
return $this->enumToId[$type->id()];
|
||||
}
|
||||
}
|
||||
|
@ -28,18 +28,8 @@ use pocketmine\utils\SingletonTrait;
|
||||
|
||||
final class SuspiciousStewTypeIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var SuspiciousStewType[]
|
||||
* @phpstan-var array<int, SuspiciousStewType>
|
||||
*/
|
||||
private array $idToEnum = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId = [];
|
||||
/** @phpstan-use IntSaveIdMapTrait<SuspiciousStewType> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(SuspiciousStewTypeIds::POPPY, SuspiciousStewType::POPPY());
|
||||
@ -53,20 +43,4 @@ final class SuspiciousStewTypeIdMap{
|
||||
$this->register(SuspiciousStewTypeIds::OXEYE_DAISY, SuspiciousStewType::OXEYE_DAISY());
|
||||
$this->register(SuspiciousStewTypeIds::WITHER_ROSE, SuspiciousStewType::WITHER_ROSE());
|
||||
}
|
||||
|
||||
private function register(int $id, SuspiciousStewType $type) : void{
|
||||
$this->idToEnum[$id] = $type;
|
||||
$this->enumToId[$type->id()] = $id;
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?SuspiciousStewType{
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
public function toId(SuspiciousStewType $type) : int{
|
||||
if(!isset($this->enumToId[$type->id()])){
|
||||
throw new \InvalidArgumentException("Type does not have a mapped ID");
|
||||
}
|
||||
return $this->enumToId[$type->id()];
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ use pocketmine\inventory\InventoryHolder;
|
||||
use pocketmine\inventory\PlayerEnderInventory;
|
||||
use pocketmine\inventory\PlayerInventory;
|
||||
use pocketmine\inventory\PlayerOffHandInventory;
|
||||
use pocketmine\item\enchantment\EnchantingHelper;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Totem;
|
||||
@ -66,7 +67,6 @@ use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Limits;
|
||||
use pocketmine\world\sound\TotemUseSound;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
@ -76,7 +76,6 @@ use function array_key_exists;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
use function min;
|
||||
use function mt_rand;
|
||||
|
||||
class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
|
||||
@ -219,8 +218,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
$this->xpSeed = $seed;
|
||||
}
|
||||
|
||||
public function generateEnchantmentSeed() : int{
|
||||
return mt_rand(Limits::INT32_MIN, Limits::INT32_MAX);
|
||||
public function regenerateEnchantmentSeed() : void{
|
||||
$this->xpSeed = EnchantingHelper::generateSeed();
|
||||
}
|
||||
|
||||
public function getXpDropAmount() : int{
|
||||
@ -346,7 +345,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
if(($xpSeedTag = $nbt->getTag(self::TAG_XP_SEED)) instanceof IntTag){
|
||||
$this->xpSeed = $xpSeedTag->getValue();
|
||||
}else{
|
||||
$this->xpSeed = $this->generateEnchantmentSeed();
|
||||
$this->xpSeed = EnchantingHelper::generateSeed();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,14 +133,18 @@ class HungerManager{
|
||||
if(!$this->enabled){
|
||||
return 0;
|
||||
}
|
||||
$ev = new PlayerExhaustEvent($this->entity, $amount, $cause);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return 0.0;
|
||||
$evAmount = $amount;
|
||||
if(PlayerExhaustEvent::hasHandlers()){
|
||||
$ev = new PlayerExhaustEvent($this->entity, $amount, $cause);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return 0.0;
|
||||
}
|
||||
$evAmount = $ev->getAmount();
|
||||
}
|
||||
|
||||
$exhaustion = $this->getExhaustion();
|
||||
$exhaustion += $ev->getAmount();
|
||||
$exhaustion += $evAmount;
|
||||
|
||||
while($exhaustion >= 4.0){
|
||||
$exhaustion -= 4.0;
|
||||
@ -159,7 +163,7 @@ class HungerManager{
|
||||
}
|
||||
$this->setExhaustion($exhaustion);
|
||||
|
||||
return $ev->getAmount();
|
||||
return $evAmount;
|
||||
}
|
||||
|
||||
public function getFoodTickTimer() : int{
|
||||
|
@ -25,13 +25,12 @@ namespace pocketmine\event\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
/**
|
||||
* Called whenever the list of entities on a pressure plate changes.
|
||||
* Depending on the type of pressure plate, this might turn on/off its signal, or change the signal strength.
|
||||
*/
|
||||
final class PressurePlateUpdateEvent extends BaseBlockChangeEvent implements Cancellable{
|
||||
final class PressurePlateUpdateEvent extends BaseBlockChangeEvent{
|
||||
/**
|
||||
* @param Entity[] $activatingEntities
|
||||
*/
|
||||
|
@ -27,7 +27,7 @@ use pocketmine\block\inventory\EnchantInventory;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\event\Event;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\item\enchantment\EnchantingOption;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use function count;
|
||||
@ -36,36 +36,36 @@ use function count;
|
||||
* Called when a player inserts an item into an enchanting table's input slot.
|
||||
* The options provided by the event will be shown on the enchanting table menu.
|
||||
*/
|
||||
class PlayerEnchantOptionsRequestEvent extends PlayerEvent implements Cancellable{
|
||||
class PlayerEnchantingOptionsRequestEvent extends PlayerEvent implements Cancellable{
|
||||
use CancellableTrait;
|
||||
|
||||
/**
|
||||
* @param EnchantOption[] $options
|
||||
* @param EnchantingOption[] $options
|
||||
*/
|
||||
public function __construct(
|
||||
Player $player,
|
||||
private readonly EnchantInventory $enchantInventory,
|
||||
private readonly EnchantInventory $inventory,
|
||||
private array $options
|
||||
){
|
||||
$this->player = $player;
|
||||
}
|
||||
|
||||
public function getEnchantInventory() : EnchantInventory{
|
||||
return $this->enchantInventory;
|
||||
public function getInventory() : EnchantInventory{
|
||||
return $this->inventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EnchantOption[]
|
||||
* @return EnchantingOption[]
|
||||
*/
|
||||
public function getOptions() : array{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EnchantOption[] $options
|
||||
* @param EnchantingOption[] $options
|
||||
*/
|
||||
public function setOptions(array $options) : void{
|
||||
Utils::validateArrayValueType($options, function(EnchantOption $_) : void{ });
|
||||
Utils::validateArrayValueType($options, function(EnchantingOption $_) : void{ });
|
||||
if(($optionCount = count($options)) > 3){
|
||||
throw new \LogicException("The maximum number of options for an enchanting table is 3, but $optionCount have been passed");
|
||||
}
|
@ -25,8 +25,8 @@ namespace pocketmine\event\player;
|
||||
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\inventory\transaction\EnchantTransaction;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\inventory\transaction\EnchantingTransaction;
|
||||
use pocketmine\item\enchantment\EnchantingOption;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
@ -38,8 +38,8 @@ class PlayerItemEnchantEvent extends PlayerEvent implements Cancellable{
|
||||
|
||||
public function __construct(
|
||||
Player $player,
|
||||
private readonly EnchantTransaction $transaction,
|
||||
private readonly EnchantOption $option,
|
||||
private readonly EnchantingTransaction $transaction,
|
||||
private readonly EnchantingOption $option,
|
||||
private readonly Item $inputItem,
|
||||
private readonly Item $outputItem,
|
||||
private readonly int $cost
|
||||
@ -50,14 +50,14 @@ class PlayerItemEnchantEvent extends PlayerEvent implements Cancellable{
|
||||
/**
|
||||
* Returns the inventory transaction involved in this enchant event.
|
||||
*/
|
||||
public function getTransaction() : EnchantTransaction{
|
||||
public function getTransaction() : EnchantingTransaction{
|
||||
return $this->transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enchantment option used.
|
||||
*/
|
||||
public function getOption() : EnchantOption{
|
||||
public function getOption() : EnchantingOption{
|
||||
return $this->option;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,8 @@ declare(strict_types=1);
|
||||
namespace pocketmine\inventory\transaction;
|
||||
|
||||
use pocketmine\event\player\PlayerItemEnchantEvent;
|
||||
use pocketmine\item\enchantment\EnchantmentHelper;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\item\enchantment\EnchantingHelper;
|
||||
use pocketmine\item\enchantment\EnchantingOption;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\player\Player;
|
||||
@ -33,14 +33,14 @@ use pocketmine\utils\AssumptionFailedError;
|
||||
use function count;
|
||||
use function min;
|
||||
|
||||
class EnchantTransaction extends InventoryTransaction{
|
||||
class EnchantingTransaction extends InventoryTransaction{
|
||||
|
||||
private ?Item $inputItem = null;
|
||||
private ?Item $outputItem = null;
|
||||
|
||||
public function __construct(
|
||||
Player $source,
|
||||
private readonly EnchantOption $option,
|
||||
private readonly EnchantingOption $option,
|
||||
private readonly int $cost
|
||||
){
|
||||
parent::__construct($source);
|
||||
@ -51,7 +51,7 @@ class EnchantTransaction extends InventoryTransaction{
|
||||
throw new AssumptionFailedError("Expected that inputItem and outputItem are not null before validating output");
|
||||
}
|
||||
|
||||
$enchantedInput = EnchantmentHelper::enchantItem($this->inputItem, $this->option->getEnchantments());
|
||||
$enchantedInput = EnchantingHelper::enchantItem($this->inputItem, $this->option->getEnchantments());
|
||||
if(!$this->outputItem->equalsExact($enchantedInput)){
|
||||
throw new TransactionValidationException("Invalid output item");
|
||||
}
|
||||
@ -119,7 +119,7 @@ class EnchantTransaction extends InventoryTransaction{
|
||||
//In this case, as much XP as possible will be taken.
|
||||
$this->source->getXpManager()->subtractXpLevels(min($this->cost, $this->source->getXpManager()->getXpLevel()));
|
||||
}
|
||||
$this->source->setEnchantmentSeed($this->source->generateEnchantmentSeed());
|
||||
$this->source->regenerateEnchantmentSeed();
|
||||
}
|
||||
|
||||
protected function callExecuteEvent() : bool{
|
@ -59,9 +59,9 @@ final class AvailableEnchantmentRegistry{
|
||||
$this->register(Enchantments::SHARPNESS(), [Tags::SWORD, Tags::AXE], []);
|
||||
$this->register(Enchantments::KNOCKBACK(), [Tags::SWORD], []);
|
||||
$this->register(Enchantments::FIRE_ASPECT(), [Tags::SWORD], []);
|
||||
$this->register(Enchantments::EFFICIENCY(), [Tags::DIG_TOOLS], [Tags::SHEARS]);
|
||||
$this->register(Enchantments::FORTUNE(), [Tags::DIG_TOOLS], []);
|
||||
$this->register(Enchantments::SILK_TOUCH(), [Tags::DIG_TOOLS], [Tags::SHEARS]);
|
||||
$this->register(Enchantments::EFFICIENCY(), [Tags::BLOCK_TOOLS], [Tags::SHEARS]);
|
||||
$this->register(Enchantments::FORTUNE(), [Tags::BLOCK_TOOLS], []);
|
||||
$this->register(Enchantments::SILK_TOUCH(), [Tags::BLOCK_TOOLS], [Tags::SHEARS]);
|
||||
$this->register(
|
||||
Enchantments::UNBREAKING(),
|
||||
[Tags::ARMOR, Tags::WEAPONS, Tags::FISHING_ROD],
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\item\enchantment\AvailableEnchantmentRegistry as EnchantmentRegis
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\item\VanillaItems as Items;
|
||||
use pocketmine\utils\Limits;
|
||||
use pocketmine\utils\Random;
|
||||
use pocketmine\world\Position;
|
||||
use function abs;
|
||||
@ -37,12 +38,27 @@ use function count;
|
||||
use function floor;
|
||||
use function max;
|
||||
use function min;
|
||||
use function mt_rand;
|
||||
use function ord;
|
||||
use function round;
|
||||
|
||||
final class EnchantmentHelper{
|
||||
/**
|
||||
* Helper methods used for enchanting using the enchanting table.
|
||||
*/
|
||||
final class EnchantingHelper{
|
||||
private const MAX_BOOKSHELF_COUNT = 15;
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new random seed for enchant option randomization.
|
||||
*/
|
||||
public static function generateSeed() : int{
|
||||
return mt_rand(Limits::INT32_MIN, Limits::INT32_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EnchantmentInstance[] $enchantments
|
||||
*/
|
||||
@ -57,9 +73,9 @@ final class EnchantmentHelper{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EnchantOption[]
|
||||
* @return EnchantingOption[]
|
||||
*/
|
||||
public static function getEnchantOptions(Position $tablePos, Item $input, int $seed) : array{
|
||||
public static function generateOptions(Position $tablePos, Item $input, int $seed) : array{
|
||||
if($input->isNull() || $input->hasEnchantments()){
|
||||
return [];
|
||||
}
|
||||
@ -73,9 +89,9 @@ final class EnchantmentHelper{
|
||||
$bottomRequiredLevel = max($baseRequiredLevel, $bookshelfCount * 2);
|
||||
|
||||
return [
|
||||
self::createEnchantOption($random, $input, $topRequiredLevel),
|
||||
self::createEnchantOption($random, $input, $middleRequiredLevel),
|
||||
self::createEnchantOption($random, $input, $bottomRequiredLevel),
|
||||
self::createOption($random, $input, $topRequiredLevel),
|
||||
self::createOption($random, $input, $middleRequiredLevel),
|
||||
self::createOption($random, $input, $bottomRequiredLevel),
|
||||
];
|
||||
}
|
||||
|
||||
@ -117,7 +133,7 @@ final class EnchantmentHelper{
|
||||
return $bookshelfCount;
|
||||
}
|
||||
|
||||
private static function createEnchantOption(Random $random, Item $inputItem, int $requiredXpLevel) : EnchantOption{
|
||||
private static function createOption(Random $random, Item $inputItem, int $requiredXpLevel) : EnchantingOption{
|
||||
$enchantingPower = $requiredXpLevel;
|
||||
|
||||
$enchantability = $inputItem->getEnchantability();
|
||||
@ -155,7 +171,7 @@ final class EnchantmentHelper{
|
||||
}
|
||||
}
|
||||
|
||||
return new EnchantOption($requiredXpLevel, self::getRandomOptionName($random), $resultEnchantments);
|
||||
return new EnchantingOption($requiredXpLevel, self::getRandomOptionName($random), $resultEnchantments);
|
||||
}
|
||||
|
||||
/**
|
@ -27,7 +27,7 @@ namespace pocketmine\item\enchantment;
|
||||
* Represents an option on the enchanting table menu.
|
||||
* If selected, all the enchantments in the option will be applied to the item.
|
||||
*/
|
||||
class EnchantOption{
|
||||
class EnchantingOption{
|
||||
|
||||
/**
|
||||
* @param EnchantmentInstance[] $enchantments
|
@ -83,6 +83,7 @@ class Enchantment{
|
||||
* Returns a bitset indicating what item types can have this item applied from an enchanting table.
|
||||
*
|
||||
* @deprecated
|
||||
* @see AvailableEnchantmentRegistry::getPrimaryItemTags()
|
||||
*/
|
||||
public function getPrimaryItemFlags() : int{
|
||||
return $this->primaryItemFlags;
|
||||
@ -93,6 +94,7 @@ class Enchantment{
|
||||
* an anvil.
|
||||
*
|
||||
* @deprecated
|
||||
* @see AvailableEnchantmentRegistry::getSecondaryItemTags()
|
||||
*/
|
||||
public function getSecondaryItemFlags() : int{
|
||||
return $this->secondaryItemFlags;
|
||||
@ -102,6 +104,7 @@ class Enchantment{
|
||||
* Returns whether this enchantment can apply to the item type from an enchanting table.
|
||||
*
|
||||
* @deprecated
|
||||
* @see AvailableEnchantmentRegistry
|
||||
*/
|
||||
public function hasPrimaryItemType(int $flag) : bool{
|
||||
return ($this->primaryItemFlags & $flag) !== 0;
|
||||
@ -111,6 +114,7 @@ class Enchantment{
|
||||
* Returns whether this enchantment can apply to the item type from an anvil, if it is not a primary item.
|
||||
*
|
||||
* @deprecated
|
||||
* @see AvailableEnchantmentRegistry
|
||||
*/
|
||||
public function hasSecondaryItemType(int $flag) : bool{
|
||||
return ($this->secondaryItemFlags & $flag) !== 0;
|
||||
|
@ -30,5 +30,5 @@ namespace pocketmine\item\enchantment;
|
||||
final class IncompatibleEnchantmentGroups{
|
||||
public const PROTECTION = "protection";
|
||||
public const BOW_INFINITE = "bow_infinite";
|
||||
public const DIG_DROP = "dig_drop";
|
||||
public const BLOCK_DROPS = "block_drops";
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ final class IncompatibleEnchantmentRegistry{
|
||||
private function __construct(){
|
||||
$this->register(Groups::PROTECTION, [Enchantments::PROTECTION(), Enchantments::FIRE_PROTECTION(), Enchantments::BLAST_PROTECTION(), Enchantments::PROJECTILE_PROTECTION()]);
|
||||
$this->register(Groups::BOW_INFINITE, [Enchantments::INFINITY(), Enchantments::MENDING()]);
|
||||
$this->register(Groups::DIG_DROP, [Enchantments::FORTUNE(), Enchantments::SILK_TOUCH()]);
|
||||
$this->register(Groups::BLOCK_DROPS, [Enchantments::FORTUNE(), Enchantments::SILK_TOUCH()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,7 +56,7 @@ final class ItemEnchantmentTagRegistry{
|
||||
$this->register(Tags::CROSSBOW);
|
||||
$this->register(Tags::SHEARS);
|
||||
$this->register(Tags::FLINT_AND_STEEL);
|
||||
$this->register(Tags::DIG_TOOLS, [Tags::AXE, Tags::PICKAXE, Tags::SHOVEL, Tags::HOE]);
|
||||
$this->register(Tags::BLOCK_TOOLS, [Tags::AXE, Tags::PICKAXE, Tags::SHOVEL, Tags::HOE]);
|
||||
$this->register(Tags::FISHING_ROD);
|
||||
$this->register(Tags::CARROT_ON_STICK);
|
||||
$this->register(Tags::COMPASS);
|
||||
@ -68,7 +68,7 @@ final class ItemEnchantmentTagRegistry{
|
||||
Tags::TRIDENT,
|
||||
Tags::BOW,
|
||||
Tags::CROSSBOW,
|
||||
Tags::DIG_TOOLS,
|
||||
Tags::BLOCK_TOOLS,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ final class ItemEnchantmentTags{
|
||||
public const CROSSBOW = "crossbow";
|
||||
public const SHEARS = "shears";
|
||||
public const FLINT_AND_STEEL = "flint_and_steel";
|
||||
public const DIG_TOOLS = "dig_tools";
|
||||
public const BLOCK_TOOLS = "block_tools";
|
||||
public const AXE = "axe";
|
||||
public const PICKAXE = "pickaxe";
|
||||
public const SHOVEL = "shovel";
|
||||
|
@ -39,8 +39,8 @@ use pocketmine\data\bedrock\EnchantmentIdMap;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\inventory\transaction\action\SlotChangeAction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
use pocketmine\item\enchantment\EnchantingOption;
|
||||
use pocketmine\item\enchantment\EnchantmentInstance;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\network\mcpe\cache\CreativeInventoryCache;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
@ -645,7 +645,7 @@ class InventoryManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EnchantOption[] $options
|
||||
* @param EnchantingOption[] $options
|
||||
*/
|
||||
public function syncEnchantingTableOptions(array $options) : void{
|
||||
$protocolOptions = [];
|
||||
|
@ -108,6 +108,7 @@ use pocketmine\utils\BinaryStream;
|
||||
use pocketmine\utils\ObjectSet;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use function array_map;
|
||||
use function array_values;
|
||||
use function base64_encode;
|
||||
@ -740,7 +741,7 @@ class NetworkSession{
|
||||
}
|
||||
$this->logger->debug("Xbox Live authenticated: " . ($this->authenticated ? "YES" : "NO"));
|
||||
|
||||
$checkXUID = $this->server->getConfigGroup()->getPropertyBool("player.verify-xuid", true);
|
||||
$checkXUID = $this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::PLAYER_VERIFY_XUID, true);
|
||||
$myXUID = $this->info instanceof XboxLivePlayerInfo ? $this->info->getXuid() : "";
|
||||
$kickForXUIDMismatch = function(string $xuid) use ($checkXUID, $myXUID) : bool{
|
||||
if($checkXUID && $myXUID !== $xuid){
|
||||
|
@ -201,7 +201,7 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
$hasMoved = $this->lastPlayerAuthInputPosition === null || !$this->lastPlayerAuthInputPosition->equals($rawPos);
|
||||
$newPos = $rawPos->round(4)->subtract(0, 1.62, 0);
|
||||
$newPos = $rawPos->subtract(0, 1.62, 0)->round(4);
|
||||
|
||||
if($this->forceMoveSync && $hasMoved){
|
||||
$curPos = $this->player->getLocation();
|
||||
|
@ -29,7 +29,7 @@ use pocketmine\inventory\transaction\action\CreateItemAction;
|
||||
use pocketmine\inventory\transaction\action\DestroyItemAction;
|
||||
use pocketmine\inventory\transaction\action\DropItemAction;
|
||||
use pocketmine\inventory\transaction\CraftingTransaction;
|
||||
use pocketmine\inventory\transaction\EnchantTransaction;
|
||||
use pocketmine\inventory\transaction\EnchantingTransaction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
use pocketmine\inventory\transaction\TransactionBuilder;
|
||||
use pocketmine\inventory\transaction\TransactionBuilderInventory;
|
||||
@ -289,7 +289,7 @@ class ItemStackRequestExecutor{
|
||||
* @throws ItemStackRequestProcessException
|
||||
*/
|
||||
private function assertDoingCrafting() : void{
|
||||
if(!$this->specialTransaction instanceof CraftingTransaction && !$this->specialTransaction instanceof EnchantTransaction){
|
||||
if(!$this->specialTransaction instanceof CraftingTransaction && !$this->specialTransaction instanceof EnchantingTransaction){
|
||||
if($this->specialTransaction === null){
|
||||
throw new ItemStackRequestProcessException("Expected CraftRecipe or CraftRecipeAuto action to precede this action");
|
||||
}else{
|
||||
@ -339,7 +339,7 @@ class ItemStackRequestExecutor{
|
||||
if($window instanceof EnchantInventory){
|
||||
$optionId = $this->inventoryManager->getEnchantingTableOptionIndex($action->getRecipeId());
|
||||
if($optionId !== null && ($option = $window->getOption($optionId)) !== null){
|
||||
$this->specialTransaction = new EnchantTransaction($this->player, $option, $optionId + 1);
|
||||
$this->specialTransaction = new EnchantingTransaction($this->player, $option, $optionId + 1);
|
||||
$this->setNextCreatedItem($window->getOutput($optionId));
|
||||
}
|
||||
}else{
|
||||
|
@ -42,6 +42,7 @@ use pocketmine\Server;
|
||||
use pocketmine\thread\ThreadCrashException;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use raklib\generic\DisconnectReason;
|
||||
use raklib\generic\SocketException;
|
||||
use raklib\protocol\EncapsulatedPacket;
|
||||
@ -125,7 +126,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
$threadToMainBuffer,
|
||||
new InternetAddress($ip, $port, $ipV6 ? 6 : 4),
|
||||
$this->rakServerId,
|
||||
$this->server->getConfigGroup()->getPropertyInt("network.max-mtu-size", 1492),
|
||||
$this->server->getConfigGroup()->getPropertyInt(YmlServerProperties::NETWORK_MAX_MTU_SIZE, 1492),
|
||||
self::MCPE_RAKNET_PROTOCOL_VERSION,
|
||||
$sleeperEntry
|
||||
);
|
||||
|
@ -29,6 +29,7 @@ use pocketmine\plugin\Plugin;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use function array_map;
|
||||
use function chr;
|
||||
use function count;
|
||||
@ -66,7 +67,7 @@ final class QueryInfo{
|
||||
|
||||
public function __construct(Server $server){
|
||||
$this->serverName = $server->getMotd();
|
||||
$this->listPlugins = $server->getConfigGroup()->getPropertyBool("settings.query-plugins", true);
|
||||
$this->listPlugins = $server->getConfigGroup()->getPropertyBool(YmlServerProperties::SETTINGS_QUERY_PLUGINS, true);
|
||||
$this->plugins = $server->getPluginManager()->getPlugins();
|
||||
$this->players = array_map(fn(Player $p) => $p->getName(), $server->getOnlinePlayers());
|
||||
|
||||
|
@ -119,6 +119,7 @@ use pocketmine\permission\PermissibleBase;
|
||||
use pocketmine\permission\PermissibleDelegateTrait;
|
||||
use pocketmine\player\chat\StandardChatFormatter;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\ServerProperties;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\TextFormat;
|
||||
@ -134,6 +135,7 @@ use pocketmine\world\sound\FireExtinguishSound;
|
||||
use pocketmine\world\sound\ItemBreakSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use pocketmine\world\World;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
use function abs;
|
||||
use function array_filter;
|
||||
@ -317,8 +319,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$rootPermissions[DefaultPermissions::ROOT_OPERATOR] = true;
|
||||
}
|
||||
$this->perm = new PermissibleBase($rootPermissions);
|
||||
$this->chunksPerTick = $this->server->getConfigGroup()->getPropertyInt("chunk-sending.per-tick", 4);
|
||||
$this->spawnThreshold = (int) (($this->server->getConfigGroup()->getPropertyInt("chunk-sending.spawn-radius", 4) ** 2) * M_PI);
|
||||
$this->chunksPerTick = $this->server->getConfigGroup()->getPropertyInt(YmlServerProperties::CHUNK_SENDING_PER_TICK, 4);
|
||||
$this->spawnThreshold = (int) (($this->server->getConfigGroup()->getPropertyInt(YmlServerProperties::CHUNK_SENDING_SPAWN_RADIUS, 4) ** 2) * M_PI);
|
||||
$this->chunkSelector = new ChunkSelector();
|
||||
|
||||
$this->chunkLoader = new class implements ChunkLoader{};
|
||||
@ -583,7 +585,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
$this->viewDistance = $newViewDistance;
|
||||
|
||||
$this->spawnThreshold = (int) (min($this->viewDistance, $this->server->getConfigGroup()->getPropertyInt("chunk-sending.spawn-radius", 4)) ** 2 * M_PI);
|
||||
$this->spawnThreshold = (int) (min($this->viewDistance, $this->server->getConfigGroup()->getPropertyInt(YmlServerProperties::CHUNK_SENDING_SPAWN_RADIUS, 4)) ** 2 * M_PI);
|
||||
|
||||
$this->nextChunkOrderRun = 0;
|
||||
|
||||
@ -1330,18 +1332,20 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$deltaAngle = abs($this->lastLocation->yaw - $to->yaw) + abs($this->lastLocation->pitch - $to->pitch);
|
||||
|
||||
if($delta > 0.0001 || $deltaAngle > 1.0){
|
||||
$ev = new PlayerMoveEvent($this, $from, $to);
|
||||
if(PlayerMoveEvent::hasHandlers()){
|
||||
$ev = new PlayerMoveEvent($this, $from, $to);
|
||||
|
||||
$ev->call();
|
||||
$ev->call();
|
||||
|
||||
if($ev->isCancelled()){
|
||||
$this->revertMovement($from);
|
||||
return;
|
||||
}
|
||||
if($ev->isCancelled()){
|
||||
$this->revertMovement($from);
|
||||
return;
|
||||
}
|
||||
|
||||
if($to->distanceSquared($ev->getTo()) > 0.01){ //If plugins modify the destination
|
||||
$this->teleport($ev->getTo());
|
||||
return;
|
||||
if($to->distanceSquared($ev->getTo()) > 0.01){ //If plugins modify the destination
|
||||
$this->teleport($ev->getTo());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->lastLocation = $to;
|
||||
@ -1842,7 +1846,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
if(!$this->canInteract($entity->getLocation(), self::MAX_REACH_DISTANCE_ENTITY_INTERACTION)){
|
||||
$this->logger->debug("Cancelled attack of entity " . $entity->getId() . " due to not currently being interactable");
|
||||
$ev->cancel();
|
||||
}elseif($this->isSpectator() || ($entity instanceof Player && !$this->server->getConfigGroup()->getConfigBool("pvp"))){
|
||||
}elseif($this->isSpectator() || ($entity instanceof Player && !$this->server->getConfigGroup()->getConfigBool(ServerProperties::PVP))){
|
||||
$ev->cancel();
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ use pocketmine\utils\Internet;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\VersionInfo;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use function array_map;
|
||||
use function array_values;
|
||||
@ -57,7 +58,7 @@ class SendUsageTask extends AsyncTask{
|
||||
* @phpstan-param array<string, string> $playerList
|
||||
*/
|
||||
public function __construct(Server $server, int $type, array $playerList = []){
|
||||
$endpoint = "http://" . $server->getConfigGroup()->getPropertyString("anonymous-statistics.host", "stats.pocketmine.net") . "/";
|
||||
$endpoint = "http://" . $server->getConfigGroup()->getPropertyString(YmlServerProperties::ANONYMOUS_STATISTICS_HOST, "stats.pocketmine.net") . "/";
|
||||
|
||||
$data = [];
|
||||
$data["uniqueServerId"] = $server->getServerUniqueId()->toString();
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\event\server\UpdateNotifyEvent;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\VersionString;
|
||||
use pocketmine\VersionInfo;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use function date;
|
||||
use function strtolower;
|
||||
use function ucfirst;
|
||||
@ -43,7 +44,7 @@ class UpdateChecker{
|
||||
$this->logger = new \PrefixedLogger($server->getLogger(), "Update Checker");
|
||||
$this->endpoint = "http://$endpoint/api/";
|
||||
|
||||
if($server->getConfigGroup()->getPropertyBool("auto-updater.enabled", true)){
|
||||
if($server->getConfigGroup()->getPropertyBool(YmlServerProperties::AUTO_UPDATER_ENABLED, true)){
|
||||
$this->doCheck();
|
||||
}
|
||||
}
|
||||
@ -59,7 +60,7 @@ class UpdateChecker{
|
||||
$this->checkUpdate($updateInfo);
|
||||
if($this->hasUpdate()){
|
||||
(new UpdateNotifyEvent($this))->call();
|
||||
if($this->server->getConfigGroup()->getPropertyBool("auto-updater.on-update.warn-console", true)){
|
||||
if($this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::AUTO_UPDATER_ON_UPDATE_WARN_CONSOLE, true)){
|
||||
$this->showConsoleUpdate();
|
||||
}
|
||||
}else{
|
||||
@ -157,7 +158,7 @@ class UpdateChecker{
|
||||
* Returns the channel used for update checking (stable, beta, dev)
|
||||
*/
|
||||
public function getChannel() : string{
|
||||
return strtolower($this->server->getConfigGroup()->getPropertyString("auto-updater.preferred-channel", "stable"));
|
||||
return strtolower($this->server->getConfigGroup()->getPropertyString(YmlServerProperties::AUTO_UPDATER_PREFERRED_CHANNEL, "stable"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,6 +58,21 @@ abstract class StringToTParser{
|
||||
$this->callbackMap[$this->reprocess($alias)] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new alias for an existing known alias.
|
||||
*/
|
||||
public function registerAlias(string $existing, string $alias) : void{
|
||||
$existingKey = $this->reprocess($existing);
|
||||
if(!isset($this->callbackMap[$existingKey])){
|
||||
throw new \InvalidArgumentException("Cannot register new alias for unknown existing alias \"$existing\"");
|
||||
}
|
||||
$newKey = $this->reprocess($alias);
|
||||
if(isset($this->callbackMap[$newKey])){
|
||||
throw new \InvalidArgumentException("Alias \"$newKey\" is already registered");
|
||||
}
|
||||
$this->callbackMap[$newKey] = $this->callbackMap[$existingKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse the specified string into a corresponding instance of T.
|
||||
* @phpstan-return T|null
|
||||
|
@ -104,6 +104,7 @@ use pocketmine\world\particle\Particle;
|
||||
use pocketmine\world\sound\BlockPlaceSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use pocketmine\world\utils\SubChunkExplorer;
|
||||
use pocketmine\YmlServerProperties;
|
||||
use function abs;
|
||||
use function array_filter;
|
||||
use function array_key_exists;
|
||||
@ -513,14 +514,14 @@ class World implements ChunkManager{
|
||||
$this->time = $this->provider->getWorldData()->getTime();
|
||||
|
||||
$cfg = $this->server->getConfigGroup();
|
||||
$this->chunkTickRadius = min($this->server->getViewDistance(), max(0, $cfg->getPropertyInt("chunk-ticking.tick-radius", 4)));
|
||||
$this->chunkTickRadius = min($this->server->getViewDistance(), max(0, $cfg->getPropertyInt(YmlServerProperties::CHUNK_TICKING_TICK_RADIUS, 4)));
|
||||
if($cfg->getPropertyInt("chunk-ticking.per-tick", 40) <= 0){
|
||||
//TODO: this needs l10n
|
||||
$this->logger->warning("\"chunk-ticking.per-tick\" setting is deprecated, but you've used it to disable chunk ticking. Set \"chunk-ticking.tick-radius\" to 0 in \"pocketmine.yml\" instead.");
|
||||
$this->chunkTickRadius = 0;
|
||||
}
|
||||
$this->tickedBlocksPerSubchunkPerTick = $cfg->getPropertyInt("chunk-ticking.blocks-per-subchunk-per-tick", self::DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK);
|
||||
$this->maxConcurrentChunkPopulationTasks = $cfg->getPropertyInt("chunk-generation.population-queue-size", 2);
|
||||
$this->tickedBlocksPerSubchunkPerTick = $cfg->getPropertyInt(YmlServerProperties::CHUNK_TICKING_BLOCKS_PER_SUBCHUNK_PER_TICK, self::DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK);
|
||||
$this->maxConcurrentChunkPopulationTasks = $cfg->getPropertyInt(YmlServerProperties::CHUNK_GENERATION_POPULATION_QUEUE_SIZE, 2);
|
||||
|
||||
$this->initRandomTickBlocksFromConfig($cfg);
|
||||
|
||||
@ -541,7 +542,7 @@ class World implements ChunkManager{
|
||||
private function initRandomTickBlocksFromConfig(ServerConfigGroup $cfg) : void{
|
||||
$dontTickBlocks = [];
|
||||
$parser = StringToItemParser::getInstance();
|
||||
foreach($cfg->getProperty("chunk-ticking.disable-block-ticking", []) as $name){
|
||||
foreach($cfg->getProperty(YmlServerProperties::CHUNK_TICKING_DISABLE_BLOCK_TICKING, []) as $name){
|
||||
$name = (string) $name;
|
||||
$item = $parser->parse($name);
|
||||
if($item !== null){
|
||||
@ -694,16 +695,19 @@ class World implements ChunkManager{
|
||||
*/
|
||||
public function addSound(Vector3 $pos, Sound $sound, ?array $players = null) : void{
|
||||
$players ??= $this->getViewersForPosition($pos);
|
||||
$ev = new WorldSoundEvent($this, $sound, $pos, $players);
|
||||
|
||||
$ev->call();
|
||||
if(WorldSoundEvent::hasHandlers()){
|
||||
$ev = new WorldSoundEvent($this, $sound, $pos, $players);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
}
|
||||
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
$sound = $ev->getSound();
|
||||
$players = $ev->getRecipients();
|
||||
}
|
||||
|
||||
$pk = $ev->getSound()->encode($pos);
|
||||
$players = $ev->getRecipients();
|
||||
$pk = $sound->encode($pos);
|
||||
if(count($pk) > 0){
|
||||
if($players === $this->getViewersForPosition($pos)){
|
||||
foreach($pk as $e){
|
||||
@ -720,23 +724,26 @@ class World implements ChunkManager{
|
||||
*/
|
||||
public function addParticle(Vector3 $pos, Particle $particle, ?array $players = null) : void{
|
||||
$players ??= $this->getViewersForPosition($pos);
|
||||
$ev = new WorldParticleEvent($this, $particle, $pos, $players);
|
||||
|
||||
$ev->call();
|
||||
if(WorldParticleEvent::hasHandlers()){
|
||||
$ev = new WorldParticleEvent($this, $particle, $pos, $players);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
}
|
||||
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
$particle = $ev->getParticle();
|
||||
$players = $ev->getRecipients();
|
||||
}
|
||||
|
||||
$pk = $ev->getParticle()->encode($pos);
|
||||
$players = $ev->getRecipients();
|
||||
$pk = $particle->encode($pos);
|
||||
if(count($pk) > 0){
|
||||
if($players === $this->getViewersForPosition($pos)){
|
||||
foreach($pk as $e){
|
||||
$this->broadcastPacketToViewers($pos, $e);
|
||||
}
|
||||
}else{
|
||||
NetworkBroadcastUtils::broadcastPackets($this->filterViewersForPosition($pos, $ev->getRecipients()), $pk);
|
||||
NetworkBroadcastUtils::broadcastPackets($this->filterViewersForPosition($pos, $players), $pk);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2517,7 +2524,9 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
if($oldChunk === null){
|
||||
(new ChunkLoadEvent($this, $chunkX, $chunkZ, $chunk, true))->call();
|
||||
if(ChunkLoadEvent::hasHandlers()){
|
||||
(new ChunkLoadEvent($this, $chunkX, $chunkZ, $chunk, true))->call();
|
||||
}
|
||||
|
||||
foreach($this->getChunkListeners($chunkX, $chunkZ) as $listener){
|
||||
$listener->onChunkLoaded($chunkX, $chunkZ, $chunk);
|
||||
@ -2791,7 +2800,9 @@ class World implements ChunkManager{
|
||||
|
||||
$this->initChunk($x, $z, $chunkData);
|
||||
|
||||
(new ChunkLoadEvent($this, $x, $z, $this->chunks[$chunkHash], false))->call();
|
||||
if(ChunkLoadEvent::hasHandlers()){
|
||||
(new ChunkLoadEvent($this, $x, $z, $this->chunks[$chunkHash], false))->call();
|
||||
}
|
||||
|
||||
if(!$this->isChunkInUse($x, $z)){
|
||||
$this->logger->debug("Newly loaded chunk $x $z has no loaders registered, will be unloaded at next available opportunity");
|
||||
@ -2904,12 +2915,14 @@ class World implements ChunkManager{
|
||||
$chunk = $this->chunks[$chunkHash] ?? null;
|
||||
|
||||
if($chunk !== null){
|
||||
$ev = new ChunkUnloadEvent($this, $x, $z, $chunk);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
$this->timings->doChunkUnload->stopTiming();
|
||||
if(ChunkUnloadEvent::hasHandlers()){
|
||||
$ev = new ChunkUnloadEvent($this, $x, $z, $chunk);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
$this->timings->doChunkUnload->stopTiming();
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if($trySave && $this->getAutoSave()){
|
||||
@ -3366,7 +3379,9 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
if(($oldChunk === null || !$oldChunk->isPopulated()) && $chunk->isPopulated()){
|
||||
(new ChunkPopulateEvent($this, $x, $z, $chunk))->call();
|
||||
if(ChunkPopulateEvent::hasHandlers()){
|
||||
(new ChunkPopulateEvent($this, $x, $z, $chunk))->call();
|
||||
}
|
||||
|
||||
foreach($this->getChunkListeners($x, $z) as $listener){
|
||||
$listener->onChunkPopulated($x, $z, $chunk);
|
||||
|
@ -440,17 +440,22 @@ class ParserPacketHandler extends PacketHandler{
|
||||
//how the data is ordered doesn't matter as long as it's reproducible
|
||||
foreach($recipes as $_type => $entries){
|
||||
$_sortedRecipes = [];
|
||||
$_seen = [];
|
||||
foreach($entries as $entry){
|
||||
$entry = self::sort($entry);
|
||||
$_key = json_encode($entry);
|
||||
while(isset($_sortedRecipes[$_key])){
|
||||
echo "warning: duplicated $_type recipe: $_key\n";
|
||||
$_key .= "a";
|
||||
}
|
||||
$_sortedRecipes[$_key] = $entry;
|
||||
$duplicates = $_seen[$_key] ??= 0;
|
||||
$_seen[$_key]++;
|
||||
$suffix = chr(ord("a") + $duplicates);
|
||||
$_sortedRecipes[$_key . $suffix] = $entry;
|
||||
}
|
||||
ksort($_sortedRecipes, SORT_STRING);
|
||||
$recipes[$_type] = array_values($_sortedRecipes);
|
||||
foreach($_seen as $_key => $_seenCount){
|
||||
if($_seenCount > 1){
|
||||
fwrite(STDERR, "warning: $_type recipe $_key was seen $_seenCount times\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ksort($recipes, SORT_STRING);
|
||||
|
Reference in New Issue
Block a user