Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement waiting login sequence #6015

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
361f9b7
implement base async login sequence
ShockedPlot7560 Aug 23, 2023
382a5a3
fix cs
ShockedPlot7560 Aug 23, 2023
74e3b71
fix CS
ShockedPlot7560 Aug 23, 2023
22aac71
remove PlayerCreatedEvent, moove to PlayerCreationEvent
ShockedPlot7560 Aug 29, 2023
7757f4e
remove PlayerCreatedEvent
ShockedPlot7560 Aug 29, 2023
f5ad477
fix CS
ShockedPlot7560 Aug 29, 2023
76230cf
implement solution with Promise & refactor callback hell
ShockedPlot7560 Sep 7, 2023
47b86e2
fix promise rejection continue check & style
ShockedPlot7560 Sep 7, 2023
c488d67
fix PHPstan
ShockedPlot7560 Sep 7, 2023
68baf2c
rename var
ShockedPlot7560 Sep 7, 2023
64a164d
use ObjectSet instead of exposing promises array in event
ShockedPlot7560 Sep 7, 2023
66877e6
rename phpDoc tag to phpstan-
ShockedPlot7560 Sep 7, 2023
b93bae7
set promises value
ShockedPlot7560 Sep 8, 2023
316e9d5
fix cS
ShockedPlot7560 Sep 8, 2023
77f2ab8
Rename TTValue template in TValue
ShockedPlot7560 Sep 8, 2023
1b97763
remove Promise::all template
ShockedPlot7560 Sep 10, 2023
b54bc52
made Promise template covariant
ShockedPlot7560 Sep 12, 2023
e142dc1
add promise template
ShockedPlot7560 Sep 17, 2023
2169aa1
Merge branch 'feat/async-login' of github.com:ShockedPlot7560/PocketM…
ShockedPlot7560 Sep 17, 2023
2123e0d
remove system from PlayerCreationEvent
ShockedPlot7560 Oct 7, 2023
2dfd8bc
moove system to LoginPacket
ShockedPlot7560 Oct 7, 2023
3db11de
Merge remote-tracking branch 'upstream/minor-next' into feat/async-login
ShockedPlot7560 Oct 7, 2023
1eb3a4f
fix documentation
ShockedPlot7560 Oct 7, 2023
b3273b9
fix PHPStan
ShockedPlot7560 Oct 7, 2023
53aa3ac
change PlayerLoginPrepareEvent to PlayerPreCreationEvent
ShockedPlot7560 Oct 27, 2023
19fe4e9
remove Promise covariant
ShockedPlot7560 Oct 27, 2023
2504e0d
fix PHPstan & update docs
ShockedPlot7560 Oct 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
use pocketmine\event\player\PlayerCreationEvent;
use pocketmine\event\player\PlayerDataSaveEvent;
use pocketmine\event\player\PlayerLoginEvent;
use pocketmine\event\player\PlayerPreCreationEvent;
use pocketmine\event\server\CommandEvent;
use pocketmine\event\server\QueryRegenerateEvent;
use pocketmine\lang\KnownTranslationFactory;
Expand Down Expand Up @@ -105,6 +106,7 @@
use pocketmine\utils\MainLogger;
use pocketmine\utils\NotCloneable;
use pocketmine\utils\NotSerializable;
use pocketmine\utils\ObjectSet;
use pocketmine\utils\Process;
use pocketmine\utils\SignalHandler;
use pocketmine\utils\Terminal;
Expand Down Expand Up @@ -553,6 +555,31 @@ public function saveOfflinePlayerData(string $name, CompoundTag $nbtTag) : void{
* @phpstan-return Promise<Player>
*/
public function createPlayer(NetworkSession $session, PlayerInfo $playerInfo, bool $authenticated, ?CompoundTag $offlinePlayerData) : Promise{
/** @var PromiseResolver<Player> $globalResolver */
$globalResolver = new PromiseResolver();

$this->preparePlayerCreation($session)->onCompletion(
function() use ($session, $playerInfo, $authenticated, $offlinePlayerData, $globalResolver) : void{
$this->createPlayerInternal($session, $playerInfo, $authenticated, $offlinePlayerData)->onCompletion(
function(Player $player) use ($globalResolver) : void {
$globalResolver->resolve($player);
}, function() use ($globalResolver) : void {
$globalResolver->reject();
}
);
},
function() use ($globalResolver) : void {
$globalResolver->reject();
}
);

return $globalResolver->getPromise();
}

/**
* @phpstan-return Promise<Player>
*/
private function createPlayerInternal(NetworkSession $session, PlayerInfo $playerInfo, bool $authenticated, ?CompoundTag $offlinePlayerData) : Promise{
$ev = new PlayerCreationEvent($session);
$ev->call();
$class = $ev->getPlayerClass();
Expand Down Expand Up @@ -600,6 +627,18 @@ function() use ($playerPromiseResolver, $session) : void{
return $playerPromiseResolver->getPromise();
}

/**
* @return Promise<array<int, null>>
*/
private function preparePlayerCreation(NetworkSession $session) : Promise{
/** @phpstan-var ObjectSet<Promise<null>> $promises */
$promises = new ObjectSet();
$ev = new PlayerPreCreationEvent($session, $promises);
$ev->call();

return Promise::all($promises->toArray());
}

/**
* @deprecated This method's results are unpredictable. The string "Steve" will return the player named "SteveJobs",
* until another player named "SteveJ" joins the server, at which point it will return that player instead. Prefer
Expand Down
63 changes: 63 additions & 0 deletions src/event/player/PlayerPreCreationEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?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\event\player;

use pocketmine\event\Event;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\promise\Promise;
use pocketmine\utils\ObjectSet;

/**
* Allows the plugins to specify promise that need to be completed before the PlayerCreationEvent is fired.
*/
class PlayerPreCreationEvent extends Event{
/** @phpstan-param ObjectSet<Promise<null>> $promises */
public function __construct(
private NetworkSession $session,
private ObjectSet $promises
){ }

public function getNetworkSession() : NetworkSession{
return $this->session;
}

public function getAddress() : string{
return $this->session->getIp();
}

public function getPort() : int{
return $this->session->getPort();
}

/**
* Adds a promise to the waiting list.
* Once all the promises that have been added have been completed,
* the player creation sequence will continue and the PlayerCreationEvent will be fired.
*
* @phpstan-param Promise<null> $promise
*/
public function addPromise(Promise $promise) : void{
$this->promises->add($promise);
}
}
1 change: 1 addition & 0 deletions src/network/mcpe/NetworkSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
use pocketmine\player\PlayerInfo;
use pocketmine\player\UsedChunkStatus;
use pocketmine\player\XboxLivePlayerInfo;
use pocketmine\promise\Promise;
use pocketmine\Server;
use pocketmine\timings\Timings;
use pocketmine\utils\AssumptionFailedError;
Expand Down
51 changes: 51 additions & 0 deletions src/promise/Promise.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

namespace pocketmine\promise;

use function count;
use function spl_object_id;

/**
Expand Down Expand Up @@ -52,4 +53,54 @@ public function onCompletion(\Closure $onSuccess, \Closure $onFailure) : void{
public function isResolved() : bool{
return $this->shared->resolved;
}

/**
* Returns a promise that will resolve only once all the Promises in
* `$promises` have resolved. The resolution value of the returned promise
* will be an array containing the resolution values of each Promises in
* `$promises` indexed by the respective Promises' array keys.
*
* @template TPromiseValue
* @phpstan-param Promise<TPromiseValue>[] $promises
*
* @phpstan-return Promise<array<int, TPromiseValue>>
*/
public static function all(array $promises) : Promise {
/** @phpstan-var PromiseResolver<array<int, TPromiseValue>> $resolver */
$resolver = new PromiseResolver();
$values = [];
$toResolve = count($promises);
$continue = true;

foreach($promises as $key => $promise){
$values[$key] = null;

$promise->onCompletion(
function(mixed $value) use ($resolver, $key, &$toResolve, &$continue, &$values) : void{
$values[$key] = $value;

if(--$toResolve === 0 && $continue){
$resolver->resolve($values);
}
},
function() use ($resolver, &$continue) : void{
if($continue){
$continue = false;
$resolver->reject();
ShockedPlot7560 marked this conversation as resolved.
Show resolved Hide resolved
}
}
);

if(!$continue){
break;
}
}

if($toResolve === 0){
$continue = false;
$resolver->resolve($values);
}

return $resolver->getPromise();
}
}
5 changes: 5 additions & 0 deletions tests/phpstan/configs/actual-problems.neon
Original file line number Diff line number Diff line change
Expand Up @@ -1205,3 +1205,8 @@ parameters:
count: 1
path: ../../phpunit/scheduler/AsyncPoolTest.php

-
message: "#^Right side of && is always true\\.$#"
count: 1
path: ../../../src/promise/Promise.php
ShockedPlot7560 marked this conversation as resolved.
Show resolved Hide resolved