mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 02:42:58 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
@ -24,13 +24,16 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function asort;
|
||||
use function file_get_contents;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function log;
|
||||
use function print_r;
|
||||
use const SORT_STRING;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
|
||||
class BlockTest extends TestCase{
|
||||
|
||||
@ -91,34 +94,71 @@ class BlockTest extends TestCase{
|
||||
}
|
||||
}
|
||||
|
||||
public function testConsistency() : void{
|
||||
$list = json_decode(file_get_contents(__DIR__ . '/block_factory_consistency_check.json'), true);
|
||||
if(!is_array($list)){
|
||||
throw new \pocketmine\utils\AssumptionFailedError("Old table should be array{knownStates: array<string, string>, stateDataBits: int}");
|
||||
/**
|
||||
* @return int[]
|
||||
* @phpstan-return array<string, int>
|
||||
*/
|
||||
public static function computeConsistencyCheckTable(RuntimeBlockStateRegistry $blockStateRegistry) : array{
|
||||
$newTable = [];
|
||||
|
||||
$idNameLookup = [];
|
||||
//if we ever split up block registration into multiple registries (e.g. separating chemistry blocks),
|
||||
//we'll need to ensure those additional registries are also included here
|
||||
foreach(Utils::stringifyKeys(VanillaBlocks::getAll()) as $name => $blockType){
|
||||
$id = $blockType->getTypeId();
|
||||
if(isset($idNameLookup[$id])){
|
||||
throw new AssumptionFailedError("TypeID $name collides with " . $idNameLookup[$id]);
|
||||
}
|
||||
$idNameLookup[$id] = $name;
|
||||
}
|
||||
$knownStates = [];
|
||||
/**
|
||||
* @var string $name
|
||||
* @var int[] $stateIds
|
||||
*/
|
||||
foreach($list["knownStates"] as $name => $stateIds){
|
||||
foreach($stateIds as $stateId){
|
||||
$knownStates[$stateId] = $name;
|
||||
|
||||
foreach($blockStateRegistry->getAllKnownStates() as $index => $block){
|
||||
if($index !== $block->getStateId()){
|
||||
throw new AssumptionFailedError("State index should always match state ID");
|
||||
}
|
||||
$idName = $idNameLookup[$block->getTypeId()];
|
||||
$newTable[$idName] = ($newTable[$idName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
return $newTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param array<string, int> $actual
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function computeConsistencyCheckDiff(string $expectedFile, array $actual) : array{
|
||||
$expected = json_decode(Filesystem::fileGetContents($expectedFile), true, 2, JSON_THROW_ON_ERROR);
|
||||
if(!is_array($expected)){
|
||||
throw new AssumptionFailedError("Old table should be array<string, int>");
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
foreach($expected as $typeName => $numStates){
|
||||
if(!is_string($typeName) || !is_int($numStates)){
|
||||
throw new AssumptionFailedError("Old table should be array<string, int>");
|
||||
}
|
||||
if(!isset($actual[$typeName])){
|
||||
$errors[] = "Removed block type $typeName ($numStates permutations)";
|
||||
}elseif($actual[$typeName] !== $numStates){
|
||||
$errors[] = "Block type $typeName permutation count changed: $numStates -> " . $actual[$typeName];
|
||||
}
|
||||
}
|
||||
foreach(Utils::stringifyKeys($actual) as $typeName => $numStates){
|
||||
if(!isset($expected[$typeName])){
|
||||
$errors[] = "Added block type $typeName (" . $actual[$typeName] . " permutations)";
|
||||
}
|
||||
}
|
||||
$oldStateDataSize = $list["stateDataBits"];
|
||||
self::assertSame($oldStateDataSize, Block::INTERNAL_STATE_DATA_BITS, "Changed number of state data bits - consistency check probably need regenerating");
|
||||
|
||||
$states = $this->blockFactory->getAllKnownStates();
|
||||
foreach($states as $stateId => $state){
|
||||
self::assertArrayHasKey($stateId, $knownStates, "New block state $stateId (" . print_r($state, true) . ") - consistency check may need regenerating");
|
||||
self::assertSame($knownStates[$stateId], $state->getName());
|
||||
}
|
||||
asort($knownStates, SORT_STRING);
|
||||
foreach($knownStates as $k => $name){
|
||||
self::assertArrayHasKey($k, $states, "Missing previously-known block state $k " . ($k >> Block::INTERNAL_STATE_DATA_BITS) . ":" . ($k & Block::INTERNAL_STATE_DATA_MASK) . " ($name)");
|
||||
self::assertSame($name, $states[$k]->getName());
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
|
||||
public function testConsistency() : void{
|
||||
$newTable = self::computeConsistencyCheckTable($this->blockFactory);
|
||||
$errors = self::computeConsistencyCheckDiff(__DIR__ . '/block_factory_consistency_check.json', $newTable);
|
||||
|
||||
self::assertEmpty($errors, "Block factory consistency check failed:\n" . implode("\n", $errors));
|
||||
}
|
||||
|
||||
public function testEmptyStateId() : void{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -21,86 +21,31 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockTest;
|
||||
use pocketmine\block\RuntimeBlockStateRegistry;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
require dirname(__DIR__, 3) . '/vendor/autoload.php';
|
||||
|
||||
/* This script needs to be re-run after any intentional blockfactory change (adding or removing a block state). */
|
||||
|
||||
$factory = new RuntimeBlockStateRegistry();
|
||||
$remaps = [];
|
||||
$new = [];
|
||||
foreach(RuntimeBlockStateRegistry::getInstance()->getAllKnownStates() as $index => $block){
|
||||
if($index !== $block->getStateId()){
|
||||
throw new AssumptionFailedError("State index should always match state ID");
|
||||
}
|
||||
$new[$index] = $block->getName();
|
||||
}
|
||||
$newTable = BlockTest::computeConsistencyCheckTable(RuntimeBlockStateRegistry::getInstance());
|
||||
|
||||
$oldTablePath = __DIR__ . '/block_factory_consistency_check.json';
|
||||
if(file_exists($oldTablePath)){
|
||||
$oldTable = json_decode(file_get_contents($oldTablePath), true);
|
||||
if(!is_array($oldTable)){
|
||||
throw new AssumptionFailedError("Old table should be array{knownStates: array<string, string>, stateDataBits: int}");
|
||||
}
|
||||
$old = [];
|
||||
/**
|
||||
* @var string $name
|
||||
* @var int[] $stateIds
|
||||
*/
|
||||
foreach($oldTable["knownStates"] as $name => $stateIds){
|
||||
foreach($stateIds as $stateId){
|
||||
$old[$stateId] = $name;
|
||||
}
|
||||
}
|
||||
$oldStateDataSize = $oldTable["stateDataBits"];
|
||||
$oldStateDataMask = ~(~0 << $oldStateDataSize);
|
||||
$errors = BlockTest::computeConsistencyCheckDiff($oldTablePath, $newTable);
|
||||
|
||||
if($oldStateDataSize !== Block::INTERNAL_STATE_DATA_BITS){
|
||||
echo "State data bits changed from $oldStateDataSize to " . Block::INTERNAL_STATE_DATA_BITS . "\n";
|
||||
}
|
||||
|
||||
foreach($old as $k => $name){
|
||||
[$oldId, $oldStateData] = [$k >> $oldStateDataSize, $k & $oldStateDataMask];
|
||||
$reconstructedK = ($oldId << Block::INTERNAL_STATE_DATA_BITS) | $oldStateData;
|
||||
if(!isset($new[$reconstructedK])){
|
||||
echo "Removed state for $name ($oldId:$oldStateData)\n";
|
||||
}
|
||||
}
|
||||
foreach($new as $k => $name){
|
||||
[$newId, $newStateData] = [$k >> Block::INTERNAL_STATE_DATA_BITS, $k & Block::INTERNAL_STATE_DATA_MASK];
|
||||
if($newStateData > $oldStateDataMask){
|
||||
echo "Added state for $name ($newId, $newStateData)\n";
|
||||
}else{
|
||||
$reconstructedK = ($newId << $oldStateDataSize) | $newStateData;
|
||||
if(!isset($old[$reconstructedK])){
|
||||
echo "Added state for $name ($newId:$newStateData)\n";
|
||||
}elseif($old[$reconstructedK] !== $name){
|
||||
echo "Name changed ($newId:$newStateData) " . $old[$reconstructedK] . " -> " . $name . "\n";
|
||||
}
|
||||
if(count($errors) > 0){
|
||||
echo count($errors) . " changes detected:\n";
|
||||
foreach($errors as $error){
|
||||
echo $error . "\n";
|
||||
}
|
||||
}else{
|
||||
echo "No changes detected\n";
|
||||
}
|
||||
}else{
|
||||
echo "WARNING: Unable to calculate diff, no previous consistency check file found\n";
|
||||
}
|
||||
|
||||
$newTable = [];
|
||||
foreach($new as $stateId => $name){
|
||||
$newTable[$name][] = $stateId;
|
||||
}
|
||||
ksort($newTable, SORT_STRING);
|
||||
foreach(Utils::stringifyKeys($newTable) as $name => $stateIds){
|
||||
sort($stateIds, SORT_NUMERIC);
|
||||
$newTable[$name] = $stateIds;
|
||||
}
|
||||
|
||||
file_put_contents(__DIR__ . '/block_factory_consistency_check.json', json_encode(
|
||||
[
|
||||
"knownStates" => $newTable,
|
||||
"stateDataBits" => Block::INTERNAL_STATE_DATA_BITS
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
));
|
||||
file_put_contents($oldTablePath, json_encode($newTable, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT));
|
||||
|
||||
@ -32,8 +32,6 @@ use pocketmine\utils\MainLogger;
|
||||
use function define;
|
||||
use function dirname;
|
||||
use function microtime;
|
||||
use function sys_get_temp_dir;
|
||||
use function tempnam;
|
||||
use function usleep;
|
||||
|
||||
class AsyncPoolTest extends TestCase{
|
||||
@ -45,13 +43,12 @@ class AsyncPoolTest extends TestCase{
|
||||
|
||||
public function setUp() : void{
|
||||
@define('pocketmine\\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__, 3) . '/vendor/autoload.php');
|
||||
$this->mainLogger = new MainLogger(tempnam(sys_get_temp_dir(), "pmlog"), false, "Main", new \DateTimeZone('UTC'));
|
||||
$this->mainLogger = new MainLogger(null, false, "Main", new \DateTimeZone('UTC'));
|
||||
$this->pool = new AsyncPool(2, 1024, new ThreadSafeClassLoader(), $this->mainLogger, new SleeperHandler());
|
||||
}
|
||||
|
||||
public function tearDown() : void{
|
||||
$this->pool->shutdown();
|
||||
$this->mainLogger->shutdownLogWriterThread();
|
||||
}
|
||||
|
||||
public function testTaskLeak() : void{
|
||||
|
||||
Reference in New Issue
Block a user