mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-11 03:58:06 +00:00
Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
b4a8f8391b | |||
142d750b9f | |||
948b0b4cbc | |||
d6b596a8ac | |||
eab2d4d704 | |||
8114551600 | |||
8e1d1993c5 | |||
82bf5f6193 | |||
76a86e51f7 | |||
d1e803685a | |||
0a884aa5fb | |||
c410e676b3 | |||
8f1f5fde47 | |||
0f268df2e0 | |||
86108e7010 | |||
5ea448ef36 | |||
389e7767d1 | |||
4c268acc00 | |||
e34a4f6b98 | |||
3925e598d6 | |||
383ec8a8e3 | |||
95313e0a90 | |||
e9a87978a6 | |||
612e9e162c | |||
fdc3faadc9 | |||
9644e72acf | |||
2c678dcf0d | |||
7bd9a2b2e0 | |||
5c26deb517 | |||
8fcb44de7d | |||
bd2e7db3b9 | |||
f4480c07ee | |||
c09e2301c8 | |||
8e9f787d33 | |||
89833b3b68 | |||
a10a656a5d | |||
2659ed8d91 | |||
9c01ecbe7e | |||
6a55021779 | |||
6ada261b04 | |||
c3d80d711d | |||
1a8b33dafe |
48
.github/ISSUE_TEMPLATE.md
vendored
48
.github/ISSUE_TEMPLATE.md
vendored
@ -1,48 +0,0 @@
|
||||
### Issue description
|
||||
<!---
|
||||
THIS ISSUE TRACKER IS FOR BUG REPORTING, NOT FOR HELP & SUPPORT. If you need help, use the links below.
|
||||
- http://pmmp.readthedocs.io/en/rtfd/ - Documentation
|
||||
- https://forums.pmmp.io - PMMP Forums
|
||||
|
||||
Any issues requesting updates to new versions of MCPE will be treated as spam.
|
||||
Please do not create issues for missing/un-implemented gameplay features - they will be closed.
|
||||
-->
|
||||
|
||||
<!--- Write a short description about the issue -->
|
||||
|
||||
<!--- If you are reporting a regression or unexpected behaviour, please include the below information: -->
|
||||
- Expected result: What were you expecting to happen?
|
||||
- Actual result: What actually happened?
|
||||
|
||||
### Steps to reproduce the issue
|
||||
<!--- help us find the problem by adding steps to reproduce the issue -->
|
||||
1. ...
|
||||
2. ...
|
||||
|
||||
### OS and versions
|
||||
<!--- use the 'version' command in PocketMine-MP
|
||||
|
||||
NOTE: LATEST is not a valid version. PocketMine-MP version should include Jenkins build number and/or git commit hash.
|
||||
|
||||
NO support whatsoever will be provided for third-party modified variants of PocketMine-MP. Issues relating to third-party modifications will be closed as spam.
|
||||
|
||||
Note that 32-bit platforms are no longer supported by PocketMine-MP and issues concerning 32-bit platforms will be closed.
|
||||
-->
|
||||
* PocketMine-MP: <!-- LATEST IS NOT A VALID VERSION -->
|
||||
* PHP:
|
||||
* Server OS:
|
||||
* Game version: PE/Win10 (delete as appropriate)
|
||||
|
||||
### Plugins
|
||||
- Test on a clean server without plugins: is the issue reproducible without any plugins loaded?
|
||||
|
||||
If the issue is **not** reproducible without plugins:
|
||||
- Have you asked for help on our forums before creating an issue?
|
||||
- Can you provide sample, *minimal* reproducing code for the issue? If so, paste it in the bottom section
|
||||
- Paste your list of plugins here (use the 'plugins' command in PocketMine-MP)
|
||||
|
||||
### Crashdump, backtrace or other files
|
||||
- Do not paste crashdumps into an issue - please use our Crash Archive at https://crash.pmmp.io for submitting crash reports to not spam the issue tracker. Add links to your reports in the Crash Archive here.
|
||||
- Please use gist or anything else to add other files and add links here
|
||||
|
||||
* ...
|
19
.github/ISSUE_TEMPLATE/api-change-request.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/api-change-request.md
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
name: API change request
|
||||
about: Suggest a change, addition or removal to the plugin API
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--- tell us what you want -->
|
||||
## Description
|
||||
|
||||
|
||||
<!--- explain why you want this and why it's a good idea -->
|
||||
## Justification
|
||||
|
||||
|
||||
<!--- (optional) describe alternative methods you've explored to achieve your goal -->
|
||||
## Alternative methods
|
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Unexpected non-crash behaviour (except missing gameplay features)
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Issue description
|
||||
|
||||
- Expected result: What were you expecting to happen?
|
||||
- Actual result: What actually happened?
|
||||
|
||||
### Steps to reproduce the issue
|
||||
1. ...
|
||||
2. ...
|
||||
|
||||
### OS and versions
|
||||
<!-- try the `version` command | LATEST IS NOT A VALID VERSION -->
|
||||
* PocketMine-MP:
|
||||
* PHP:
|
||||
* Server OS:
|
||||
* Game version: PE/Win10 (delete as appropriate)
|
||||
|
||||
### Plugins
|
||||
<!--- use the `plugins` command and paste the output below -->
|
||||
|
||||
- If you remove all plugins, does the issue still occur?
|
||||
- If the issue is **not** reproducible without plugins:
|
||||
- Have you asked for help on our forums before creating an issue?
|
||||
- Can you provide sample, *minimal* reproducing code for the issue? If so, paste it in the bottom section
|
||||
|
||||
### Crashdump, backtrace or other files
|
||||
<!--- Submit crashdumps at https://crash.pmmp.io and paste a link -->
|
||||
<!--- Use gist or anything else to add other files and add links here -->
|
15
.github/ISSUE_TEMPLATE/crash.md
vendored
Normal file
15
.github/ISSUE_TEMPLATE/crash.md
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: Crash
|
||||
about: Report a crash in PocketMine-MP (not plugins)
|
||||
title: Server crashed
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--- submit crashdump files to https://crash.pmmp.io -->
|
||||
<!--- or, copy the data between ===BEGIN CRASH DUMP=== and ===END CRASH DUMP and paste it on a site like https://pastebin.com -->
|
||||
Link to crashdump:
|
||||
|
||||
<!--- write additional information about the crash to help us find the problem -->
|
||||
### Additional comments (optional)
|
14
.github/ISSUE_TEMPLATE/help---support.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/help---support.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Help & support
|
||||
about: We don't accept support requests here. Try the links on the README.
|
||||
title: ''
|
||||
labels: Support request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
We don't accept support requests on the issue tracker. Please try the following links instead:
|
||||
|
||||
Documentation: http://pmmp.rtfd.io
|
||||
Forums: https://forums.pmmp.io
|
||||
Discord: https://discord.gg/bge7dYQ
|
12
.github/ISSUE_TEMPLATE/security-dos-vulnerability.md
vendored
Normal file
12
.github/ISSUE_TEMPLATE/security-dos-vulnerability.md
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
name: Security/DoS vulnerability
|
||||
about: 'Bug or exploit that can be used to attack servers (hint: don''t report it
|
||||
on a public issue tracker)'
|
||||
title: ''
|
||||
labels: 'Auto: Spam'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please DO NOT report security vulnerabilities here.
|
||||
Instead, send an email to team@pmmp.io or contact a developer directly, IN PRIVATE.
|
6
.github/support.yml
vendored
6
.github/support.yml
vendored
@ -5,7 +5,11 @@ supportLabel: "Support request"
|
||||
# Comment to post on issues marked as support requests. Add a link
|
||||
# to a support page, or set to `false` to disable
|
||||
supportComment: >
|
||||
This issue tracker is not a support forum. Please use the [forums](https://forums.pmmp.io) for support.
|
||||
Thanks, but this issue tracker not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue).
|
||||
|
||||
|
||||
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bge7dYQ) | [Forums](https://forums.pmmp.io)
|
||||
|
||||
# Whether to close issues marked as support requests
|
||||
close: true
|
||||
# Whether to lock issues marked as support requests
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,6 +12,7 @@ server.properties
|
||||
/pocketmine.yml
|
||||
memory_dumps/*
|
||||
resource_packs/
|
||||
server.lock
|
||||
|
||||
# Common IDEs
|
||||
.idea/
|
||||
|
10
README.md
10
README.md
@ -10,13 +10,15 @@ If you don't find what you're looking for there, [talk to a human](#discussion).
|
||||
|
||||
### Discussion
|
||||
- [Forums](https://forums.pmmp.io/)
|
||||
- [Community Discord](https://discord.gg/bge7dYQ)
|
||||
|
||||
### Plugins
|
||||
There are a very wide range of already-written plugins available which you can use to customise your server. Check out [Poggit](https://poggit.pmmp.io), or just search GitHub.
|
||||
|
||||
### For developers
|
||||
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
|
||||
* [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - A development tools plugin for creating plugins.
|
||||
* [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||
|
||||
### Can I contribute?
|
||||
Yes you can! Contributions are welcomed provided that they comply with our [Contributing Guidelines](CONTRIBUTING.md). Please ensure you read the relevant sections of the guidelines carefully before making a Pull Request or opening an Issue.
|
||||
@ -27,6 +29,12 @@ Yes you can! Contributions are welcomed provided that they comply with our [Cont
|
||||
|
||||
**Note: Please avoid development builds unless there is no other alternative for what you need.** Development builds are subject to changes at any time without notice, and it is likely that your server or plugins might break without warning.
|
||||
|
||||
### Donate
|
||||
Donations help support the development of the project and pay for our expenses.
|
||||
- Bitcoin Cash (BCH): `qz9p8dqkv0r7aahdatu5uewqfkvstrglv58f8yle07`
|
||||
- Bitcoin (BTC): `1PVAyDJ2g7kcjCxAC3C89oxpV2ZYcLad8T`
|
||||
- [Patreon](https://www.patreon.com/pocketminemp)
|
||||
|
||||
## Licensing information
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
12
composer.lock
generated
12
composer.lock
generated
@ -160,16 +160,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/nbt",
|
||||
"version": "0.2.6",
|
||||
"version": "0.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/NBT.git",
|
||||
"reference": "92eaf84dd61f700d3ec02ebd01b606cb5b1590d4"
|
||||
"reference": "2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/92eaf84dd61f700d3ec02ebd01b606cb5b1590d4",
|
||||
"reference": "92eaf84dd61f700d3ec02ebd01b606cb5b1590d4",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a",
|
||||
"reference": "2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -194,10 +194,10 @@
|
||||
],
|
||||
"description": "PHP library for working with Named Binary Tags",
|
||||
"support": {
|
||||
"source": "https://github.com/pmmp/NBT/tree/0.2.6",
|
||||
"source": "https://github.com/pmmp/NBT/tree/0.2.7",
|
||||
"issues": "https://github.com/pmmp/NBT/issues"
|
||||
},
|
||||
"time": "2019-02-07T16:28:11+00:00"
|
||||
"time": "2019-03-29T19:39:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib",
|
||||
|
@ -737,9 +737,9 @@ WARN_LOGFILE =
|
||||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = ./src \
|
||||
./vendor/pocketmine \
|
||||
./README.md
|
||||
INPUT = ../src \
|
||||
../vendor/pocketmine \
|
||||
./index.md
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
@ -881,7 +881,7 @@ FILTER_SOURCE_PATTERNS =
|
||||
# (index.html). This can be useful if you have a project on for instance GitHub
|
||||
# and want to reuse the introduction page also for the doxygen output.
|
||||
|
||||
USE_MDFILE_AS_MAINPAGE = ./README.md
|
||||
USE_MDFILE_AS_MAINPAGE = ./index.md
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
10
doxygen/index.md
Normal file
10
doxygen/index.md
Normal file
@ -0,0 +1,10 @@
|
||||
## PocketMine-MP API Documentation
|
||||
|
||||
This site contains auto-generated API documentation for PocketMine-MP (and dependencies which are not outsourced). Documentation here is regenerated for every release.
|
||||
|
||||
This site can be accessed via https://apidoc.pmmp.io.
|
||||
|
||||
### Additional developer resources
|
||||
- [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||
- [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||
- [DeveloperDocs](https://github.com/pmmp/DeveloperDocs/) - Reference, guides and specifications for the PocketMine-MP API
|
@ -2101,6 +2101,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
/** @var float[] $pos */
|
||||
$pos = $this->namedtag->getListTag("Pos")->getAllValues();
|
||||
$this->level->registerChunkLoader($this, ((int) floor($pos[0])) >> 4, ((int) floor($pos[2])) >> 4, true);
|
||||
$this->usedChunks[Level::chunkHash(((int) floor($pos[0])) >> 4, ((int) floor($pos[2])) >> 4)] = false;
|
||||
|
||||
parent::__construct($this->level, $this->namedtag);
|
||||
$ev = new PlayerLoginEvent($this, "Plugin reason");
|
||||
@ -2985,7 +2986,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$t = $this->level->getTile($pos);
|
||||
if($t instanceof Spawnable){
|
||||
$nbt = new NetworkLittleEndianNBTStream();
|
||||
$compound = $nbt->read($packet->namedtag);
|
||||
$_ = 0;
|
||||
$compound = $nbt->read($packet->namedtag, false, $_, 512);
|
||||
|
||||
if(!($compound instanceof CompoundTag)){
|
||||
throw new \InvalidArgumentException("Expected " . CompoundTag::class . " in block entity NBT, got " . (is_object($compound) ? get_class($compound) : gettype($compound)));
|
||||
|
@ -37,7 +37,7 @@ namespace pocketmine {
|
||||
use pocketmine\wizard\SetupWizard;
|
||||
|
||||
const NAME = "PocketMine-MP";
|
||||
const BASE_VERSION = "3.7.0";
|
||||
const BASE_VERSION = "3.7.2";
|
||||
const IS_DEVELOPMENT_BUILD = false;
|
||||
const BUILD_NUMBER = 0;
|
||||
|
||||
@ -189,6 +189,14 @@ namespace pocketmine {
|
||||
mkdir(\pocketmine\DATA, 0777, true);
|
||||
}
|
||||
|
||||
define('pocketmine\LOCK_FILE_PATH', \pocketmine\DATA . 'server.lock');
|
||||
define('pocketmine\LOCK_FILE', fopen(\pocketmine\LOCK_FILE_PATH, "cb"));
|
||||
if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){
|
||||
critical_error("Another " . \pocketmine\NAME . " instance is already using this folder (" . realpath(\pocketmine\DATA) . ").");
|
||||
critical_error("Please stop the other server first before running a new one.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//Logger has a dependency on timezone
|
||||
$tzError = Timezone::init();
|
||||
|
||||
|
@ -1091,9 +1091,19 @@ class Server{
|
||||
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @var LevelProvider $provider
|
||||
* @see LevelProvider::__construct()
|
||||
*/
|
||||
$provider = new $providerClass($path);
|
||||
try{
|
||||
GeneratorManager::getGenerator($provider->getGenerator(), true);
|
||||
}catch(\InvalidArgumentException $e){
|
||||
$this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, "Unknown generator \"" . $provider->getGenerator() . "\""]));
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @see LevelProvider::__construct() */
|
||||
$level = new Level($this, $name, new $providerClass($path));
|
||||
$level = new Level($this, $name, $provider);
|
||||
|
||||
$this->levels[$level->getId()] = $level;
|
||||
|
||||
@ -1677,7 +1687,6 @@ class Server{
|
||||
Entity::init();
|
||||
Tile::init();
|
||||
BlockFactory::init();
|
||||
BlockFactory::registerStaticRuntimeIdMappings();
|
||||
Enchantment::init();
|
||||
ItemFactory::init();
|
||||
Item::initCreativeItems();
|
||||
@ -2583,7 +2592,8 @@ class Server{
|
||||
$this->getLogger()->debug("[Auto Save] Saving worlds...");
|
||||
$start = microtime(true);
|
||||
$this->doAutoSave();
|
||||
$this->getLogger()->debug("[Auto Save] Save completed in " . round(microtime(true) - $start, 3) . "s");
|
||||
$time = (microtime(true) - $start);
|
||||
$this->getLogger()->debug("[Auto Save] Save completed in " . ($time >= 1 ? round($time, 3) . "s" : round($time * 1000) . "ms"));
|
||||
}
|
||||
|
||||
if($this->sendUsageTicker > 0 and --$this->sendUsageTicker === 0){
|
||||
|
@ -36,6 +36,7 @@ use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\metadata\Metadatable;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use function array_merge;
|
||||
@ -117,7 +118,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* @return int
|
||||
*/
|
||||
public function getRuntimeId() : int{
|
||||
return BlockFactory::toStaticRuntimeId($this->getId(), $this->getDamage());
|
||||
return RuntimeBlockMapping::toStaticRuntimeId($this->getId(), $this->getDamage());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,9 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Position;
|
||||
use function file_get_contents;
|
||||
use function json_decode;
|
||||
use function max;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use function min;
|
||||
|
||||
/**
|
||||
@ -52,15 +50,6 @@ class BlockFactory{
|
||||
/** @var \SplFixedArray<float> */
|
||||
public static $blastResistance = null;
|
||||
|
||||
/** @var int[] */
|
||||
public static $staticRuntimeIdMap = [];
|
||||
|
||||
/** @var int[] */
|
||||
public static $legacyIdMap = [];
|
||||
|
||||
/** @var int */
|
||||
private static $lastRuntimeId = 0;
|
||||
|
||||
/**
|
||||
* Initializes the block factory. By default this is called only once on server start, however you may wish to use
|
||||
* this if you need to reset the block factory back to its original defaults for whatever reason.
|
||||
@ -427,21 +416,9 @@ class BlockFactory{
|
||||
return $b !== null and !($b instanceof UnknownBlock);
|
||||
}
|
||||
|
||||
public static function registerStaticRuntimeIdMappings() : void{
|
||||
/** @var mixed[] $runtimeIdMap */
|
||||
$runtimeIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true);
|
||||
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "legacy_id_map.json"), true);
|
||||
foreach($runtimeIdMap as $k => $obj){
|
||||
//this has to use the json offset to make sure the mapping is consistent with what we send over network, even though we aren't using all the entries
|
||||
if(!isset($legacyIdMap[$obj["name"]])){
|
||||
continue;
|
||||
}
|
||||
self::registerMapping($k, $legacyIdMap[$obj["name"]], $obj["data"]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*
|
||||
* @param int $id
|
||||
* @param int $meta
|
||||
@ -449,15 +426,11 @@ class BlockFactory{
|
||||
* @return int
|
||||
*/
|
||||
public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
|
||||
/*
|
||||
* try id+meta first
|
||||
* if not found, try id+0 (strip meta)
|
||||
* if still not found, return update! block
|
||||
*/
|
||||
return self::$staticRuntimeIdMap[($id << 4) | $meta] ?? self::$staticRuntimeIdMap[$id << 4] ?? self::$staticRuntimeIdMap[BlockIds::INFO_UPDATE << 4];
|
||||
return RuntimeBlockMapping::toStaticRuntimeId($id, $meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @internal
|
||||
*
|
||||
* @param int $runtimeId
|
||||
@ -465,13 +438,6 @@ class BlockFactory{
|
||||
* @return int[] [id, meta]
|
||||
*/
|
||||
public static function fromStaticRuntimeId(int $runtimeId) : array{
|
||||
$v = self::$legacyIdMap[$runtimeId];
|
||||
return [$v >> 4, $v & 0xf];
|
||||
}
|
||||
|
||||
private static function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{
|
||||
self::$staticRuntimeIdMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId;
|
||||
self::$legacyIdMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta;
|
||||
self::$lastRuntimeId = max(self::$lastRuntimeId, $staticRuntimeId);
|
||||
return RuntimeBlockMapping::fromStaticRuntimeId($runtimeId);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class KillCommand extends VanillaCommand{
|
||||
|
||||
if(count($args) === 1){
|
||||
if(!$sender->hasPermission("pocketmine.command.kill.other")){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
|
||||
$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -74,7 +74,7 @@ class KillCommand extends VanillaCommand{
|
||||
|
||||
if($sender instanceof Player){
|
||||
if(!$sender->hasPermission("pocketmine.command.kill.self")){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
|
||||
$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class TimeCommand extends VanillaCommand{
|
||||
|
||||
if($args[0] === "start"){
|
||||
if(!$sender->hasPermission("pocketmine.command.time.start")){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
|
||||
$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -61,7 +61,7 @@ class TimeCommand extends VanillaCommand{
|
||||
return true;
|
||||
}elseif($args[0] === "stop"){
|
||||
if(!$sender->hasPermission("pocketmine.command.time.stop")){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
|
||||
$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -72,7 +72,7 @@ class TimeCommand extends VanillaCommand{
|
||||
return true;
|
||||
}elseif($args[0] === "query"){
|
||||
if(!$sender->hasPermission("pocketmine.command.time.query")){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
|
||||
$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -92,7 +92,7 @@ class TimeCommand extends VanillaCommand{
|
||||
|
||||
if($args[0] === "set"){
|
||||
if(!$sender->hasPermission("pocketmine.command.time.set")){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
|
||||
$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -111,7 +111,7 @@ class TimeCommand extends VanillaCommand{
|
||||
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.time.set", [$value]));
|
||||
}elseif($args[0] === "add"){
|
||||
if(!$sender->hasPermission("pocketmine.command.time.add")){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
|
||||
$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -115,9 +115,13 @@ class WhitelistCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function badPerm(CommandSender $sender, string $perm) : bool{
|
||||
if(!$sender->hasPermission("pocketmine.command.whitelist.$perm")){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
|
||||
private function badPerm(CommandSender $sender, string $subcommand) : bool{
|
||||
static $map = [
|
||||
"on" => "enable",
|
||||
"off" => "disable"
|
||||
];
|
||||
if(!$sender->hasPermission("pocketmine.command.whitelist." . ($map[$subcommand] ?? $subcommand))){
|
||||
$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -107,6 +107,10 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
public const DATA_TYPE_LONG = 7;
|
||||
public const DATA_TYPE_VECTOR3F = 8;
|
||||
|
||||
/*
|
||||
* Readers beware: this isn't a nice list. Some of the properties have different types for different entities, and
|
||||
* are used for entirely different things.
|
||||
*/
|
||||
public const DATA_FLAGS = 0;
|
||||
public const DATA_HEALTH = 1; //int (minecart/boat)
|
||||
public const DATA_VARIANT = 2; //int
|
||||
@ -124,17 +128,21 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
public const DATA_PADDLE_TIME_RIGHT = 14; //float
|
||||
public const DATA_EXPERIENCE_VALUE = 15; //int (xp orb)
|
||||
public const DATA_MINECART_DISPLAY_BLOCK = 16; //int (id | (data << 16))
|
||||
public const DATA_HORSE_FLAGS = 16; //int
|
||||
/* 16 (byte) used by wither skull */
|
||||
public const DATA_MINECART_DISPLAY_OFFSET = 17; //int
|
||||
public const DATA_SHOOTER_ID = 17; //long (used by arrows)
|
||||
public const DATA_MINECART_HAS_DISPLAY = 18; //byte (must be 1 for minecart to show block inside)
|
||||
|
||||
//TODO: add more properties
|
||||
|
||||
public const DATA_HORSE_TYPE = 19; //byte
|
||||
/* 20 (unknown)
|
||||
* 21 (unknown) */
|
||||
public const DATA_CHARGE_AMOUNT = 22; //int8, used for ghasts and also crossbow charging
|
||||
public const DATA_ENDERMAN_HELD_ITEM_ID = 23; //short
|
||||
public const DATA_ENTITY_AGE = 24; //short
|
||||
|
||||
/* 26 (byte) player-specific flags
|
||||
* 27 (int) player "index"?
|
||||
* 28 (block coords) bed position */
|
||||
/* 25 (int) used by horse, (byte) used by witch */
|
||||
public const DATA_PLAYER_FLAGS = 26; //byte
|
||||
public const DATA_PLAYER_INDEX = 27; //int, used for marker colours and agent nametag colours
|
||||
public const DATA_PLAYER_BED_POSITION = 28; //blockpos
|
||||
public const DATA_FIREBALL_POWER_X = 29; //float
|
||||
public const DATA_FIREBALL_POWER_Y = 30;
|
||||
public const DATA_FIREBALL_POWER_Z = 31;
|
||||
@ -145,7 +153,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
public const DATA_POTION_AUX_VALUE = 36; //short
|
||||
public const DATA_LEAD_HOLDER_EID = 37; //long
|
||||
public const DATA_SCALE = 38; //float
|
||||
public const DATA_INTERACTIVE_TAG = 39; //string (button text)
|
||||
public const DATA_HAS_NPC_COMPONENT = 39; //byte (???)
|
||||
public const DATA_NPC_SKIN_ID = 40; //string
|
||||
public const DATA_URL_TAG = 41; //string
|
||||
public const DATA_MAX_AIR = 42; //short
|
||||
@ -195,8 +203,8 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
public const DATA_BOAT_BUBBLE_TIME = 86; //int (time in bubble column)
|
||||
public const DATA_PLAYER_AGENT_EID = 87; //long
|
||||
/* 88 (float) related to panda sitting
|
||||
* 89 (float) related to panda sitting
|
||||
* 90 (unknown) */
|
||||
* 89 (float) related to panda sitting */
|
||||
public const DATA_EAT_COUNTER = 90; //int (used by pandas)
|
||||
public const DATA_FLAGS2 = 91; //long (extended data flags)
|
||||
/* 92 (float) related to panda lying down
|
||||
* 93 (float) related to panda lying down */
|
||||
@ -205,7 +213,9 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 96; //float, usually negative
|
||||
public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 97; //float
|
||||
public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 98; //int
|
||||
|
||||
public const DATA_INTERACTIVE_TAG = 99; //string (button text)
|
||||
public const DATA_TRADE_TIER = 100; //int
|
||||
public const DATA_MAX_TRADE_TIER = 101; //int
|
||||
|
||||
public const DATA_FLAG_ONFIRE = 0;
|
||||
public const DATA_FLAG_SNEAKING = 1;
|
||||
@ -278,6 +288,18 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
public const DATA_FLAG_IN_SCAFFOLDING = 68;
|
||||
public const DATA_FLAG_OVER_SCAFFOLDING = 69;
|
||||
public const DATA_FLAG_FALL_THROUGH_SCAFFOLDING = 70;
|
||||
public const DATA_FLAG_BLOCKING = 71; //shield
|
||||
public const DATA_FLAG_DISABLE_BLOCKING = 72;
|
||||
//73 is set when a player is attacked while using shield, unclear on purpose
|
||||
public const DATA_FLAG_SLEEPING = 74;
|
||||
//75 related to sleeping, unclear usage
|
||||
public const DATA_FLAG_TRADE_INTEREST = 76;
|
||||
public const DATA_FLAG_DOOR_BREAKER = 77; //...
|
||||
public const DATA_FLAG_BREAKING_OBSTRUCTION = 78;
|
||||
public const DATA_FLAG_DOOR_OPENER = 79; //...
|
||||
|
||||
public const DATA_PLAYER_FLAG_SLEEP = 1;
|
||||
public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK
|
||||
|
||||
public static $entityCount = 1;
|
||||
/** @var Entity[] */
|
||||
|
@ -70,13 +70,6 @@ use const INT32_MIN;
|
||||
|
||||
class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
|
||||
public const DATA_PLAYER_FLAG_SLEEP = 1;
|
||||
public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK
|
||||
|
||||
public const DATA_PLAYER_FLAGS = 26;
|
||||
|
||||
public const DATA_PLAYER_BED_POSITION = 28;
|
||||
|
||||
/** @var PlayerInventory */
|
||||
protected $inventory;
|
||||
|
||||
|
@ -50,8 +50,6 @@ use const PHP_INT_MAX;
|
||||
|
||||
abstract class Projectile extends Entity{
|
||||
|
||||
public const DATA_SHOOTER_ID = 17;
|
||||
|
||||
/** @var float */
|
||||
protected $damage = 0.0;
|
||||
|
||||
|
@ -78,6 +78,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
|
||||
use pocketmine\network\mcpe\protocol\SetTimePacket;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
@ -382,7 +383,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
$this->worldHeight = $this->provider->getWorldHeight();
|
||||
|
||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.level.preparing", [$this->displayName]));
|
||||
$this->generator = GeneratorManager::getGenerator($this->provider->getGenerator());
|
||||
$this->generator = GeneratorManager::getGenerator($this->provider->getGenerator(), true);
|
||||
//TODO: validate generator options
|
||||
|
||||
$this->folderName = $name;
|
||||
@ -982,7 +983,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
$pk->blockRuntimeId = $b->getRuntimeId();
|
||||
}else{
|
||||
$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
|
||||
$pk->blockRuntimeId = BlockFactory::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
|
||||
$pk->blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
|
||||
}
|
||||
|
||||
$pk->flags = $first ? $flags : UpdateBlockPacket::FLAG_NONE;
|
||||
@ -1004,7 +1005,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
$pk->blockRuntimeId = $b->getRuntimeId();
|
||||
}else{
|
||||
$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
|
||||
$pk->blockRuntimeId = BlockFactory::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
|
||||
$pk->blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
|
||||
}
|
||||
|
||||
$pk->flags = $flags;
|
||||
|
@ -106,7 +106,7 @@ class Flat extends Generator{
|
||||
$split = array_map('\trim', explode(',', $layers));
|
||||
$y = 0;
|
||||
foreach($split as $line){
|
||||
preg_match('#^(?:(\d+)x)?(.+)$#', $line, $matches);
|
||||
preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches);
|
||||
if(count($matches) !== 3){
|
||||
throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\"");
|
||||
}
|
||||
|
@ -74,14 +74,19 @@ final class GeneratorManager{
|
||||
* Returns a class name of a registered Generator matching the given name.
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $throwOnMissing @deprecated this is for backwards compatibility only
|
||||
*
|
||||
* @return string|Generator Name of class that extends Generator (not an actual Generator object)
|
||||
* @throws \InvalidArgumentException if the generator type isn't registered
|
||||
*/
|
||||
public static function getGenerator(string $name){
|
||||
public static function getGenerator(string $name, bool $throwOnMissing = false){
|
||||
if(isset(self::$list[$name = strtolower($name)])){
|
||||
return self::$list[$name];
|
||||
}
|
||||
|
||||
if($throwOnMissing){
|
||||
throw new \InvalidArgumentException("Alias \"$name\" does not map to any known generator");
|
||||
}
|
||||
return Normal::class;
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
if($c !== 1){
|
||||
throw new \UnexpectedValueException("Unexpected NBT count $c");
|
||||
}
|
||||
$nbt = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset);
|
||||
$nbt = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
|
||||
}elseif($nbtLen !== 0){
|
||||
throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen");
|
||||
}
|
||||
|
7
src/pocketmine/network/mcpe/README.md
Normal file
7
src/pocketmine/network/mcpe/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Minecraft: Bedrock Edition network & protocol components
|
||||
This directory (the `pocketmine\network\mcpe` namespace) contains code specific to the current version of Minecraft: Bedrock Edition.
|
||||
|
||||
## WARNING
|
||||
This namespace should be considered **INTERNAL in its entirety**. Publicly exposed API in this namespace can and will change frequently, and without warning.
|
||||
|
||||
This namespace **IS NOT COVERED BY THE API VERSION SYSTEM**. If your plugin uses any code in this namespace, it can and will break without warning.
|
@ -55,19 +55,22 @@ class AvailableCommandsPacket extends DataPacket{
|
||||
public const ARG_TYPE_FLOAT = 0x02;
|
||||
public const ARG_TYPE_VALUE = 0x03;
|
||||
public const ARG_TYPE_WILDCARD_INT = 0x04;
|
||||
public const ARG_TYPE_TARGET = 0x05;
|
||||
public const ARG_TYPE_WILDCARD_TARGET = 0x06;
|
||||
public const ARG_TYPE_OPERATOR = 0x05;
|
||||
public const ARG_TYPE_TARGET = 0x06;
|
||||
|
||||
public const ARG_TYPE_STRING = 0x0f;
|
||||
public const ARG_TYPE_POSITION = 0x10;
|
||||
public const ARG_TYPE_FILEPATH = 0x0e;
|
||||
|
||||
public const ARG_TYPE_MESSAGE = 0x13;
|
||||
public const ARG_TYPE_STRING = 0x1b;
|
||||
|
||||
public const ARG_TYPE_RAWTEXT = 0x15;
|
||||
public const ARG_TYPE_POSITION = 0x1d;
|
||||
|
||||
public const ARG_TYPE_JSON = 0x18;
|
||||
public const ARG_TYPE_MESSAGE = 0x20;
|
||||
|
||||
public const ARG_TYPE_COMMAND = 0x1f;
|
||||
public const ARG_TYPE_RAWTEXT = 0x22;
|
||||
|
||||
public const ARG_TYPE_JSON = 0x25;
|
||||
|
||||
public const ARG_TYPE_COMMAND = 0x2c;
|
||||
|
||||
/**
|
||||
* Enums are a little different: they are composed as follows:
|
||||
|
@ -30,9 +30,8 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use function count;
|
||||
use function file_get_contents;
|
||||
use function json_decode;
|
||||
|
||||
class StartGamePacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::START_GAME_PACKET;
|
||||
@ -251,7 +250,7 @@ class StartGamePacket extends DataPacket{
|
||||
if(self::$runtimeIdTable === null){
|
||||
//this is a really nasty hack, but it'll do for now
|
||||
$stream = new NetworkBinaryStream();
|
||||
$data = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true);
|
||||
$data = RuntimeBlockMapping::getBedrockKnownStates();
|
||||
$stream->putUnsignedVarInt(count($data));
|
||||
foreach($data as $v){
|
||||
$stream->putString($v["name"]);
|
||||
|
@ -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\network\mcpe\protocol\types;
|
||||
|
||||
use pocketmine\block\BlockIds;
|
||||
use function file_get_contents;
|
||||
use function getmypid;
|
||||
use function json_decode;
|
||||
use function mt_rand;
|
||||
use function mt_srand;
|
||||
use function shuffle;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class RuntimeBlockMapping{
|
||||
|
||||
/** @var int[] */
|
||||
private static $legacyToRuntimeMap = [];
|
||||
/** @var int[] */
|
||||
private static $runtimeToLegacyMap = [];
|
||||
/** @var mixed[] */
|
||||
private static $bedrockKnownStates;
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public static function init() : void{
|
||||
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "legacy_id_map.json"), true);
|
||||
|
||||
self::$bedrockKnownStates = self::randomizeTable(json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true));
|
||||
|
||||
foreach(self::$bedrockKnownStates as $k => $obj){
|
||||
//this has to use the json offset to make sure the mapping is consistent with what we send over network, even though we aren't using all the entries
|
||||
if(!isset($legacyIdMap[$obj["name"]])){
|
||||
continue;
|
||||
}
|
||||
self::registerMapping($k, $legacyIdMap[$obj["name"]], $obj["data"]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomizes the order of the runtimeID table to prevent plugins relying on them.
|
||||
* Plugins shouldn't use this stuff anyway, but plugin devs have an irritating habit of ignoring what they
|
||||
* aren't supposed to do, so we have to deliberately break it to make them stop.
|
||||
*
|
||||
* @param array $table
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function randomizeTable(array $table) : array{
|
||||
$postSeed = mt_rand(); //save a seed to set afterwards, to avoid poor quality randoms
|
||||
mt_srand(getmypid() ?: 0); //Use a seed which is the same on all threads. This isn't a secure seed, but we don't care.
|
||||
shuffle($table);
|
||||
mt_srand($postSeed); //restore a good quality seed that isn't dependent on PID
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param int $meta
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
|
||||
/*
|
||||
* try id+meta first
|
||||
* if not found, try id+0 (strip meta)
|
||||
* if still not found, return update! block
|
||||
*/
|
||||
return self::$legacyToRuntimeMap[($id << 4) | $meta] ?? self::$legacyToRuntimeMap[$id << 4] ?? self::$legacyToRuntimeMap[BlockIds::INFO_UPDATE << 4];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $runtimeId
|
||||
*
|
||||
* @return int[] [id, meta]
|
||||
*/
|
||||
public static function fromStaticRuntimeId(int $runtimeId) : array{
|
||||
$v = self::$runtimeToLegacyMap[$runtimeId];
|
||||
return [$v >> 4, $v & 0xf];
|
||||
}
|
||||
|
||||
private static function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{
|
||||
self::$legacyToRuntimeMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId;
|
||||
self::$runtimeToLegacyMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getBedrockKnownStates() : array{
|
||||
return self::$bedrockKnownStates;
|
||||
}
|
||||
}
|
||||
RuntimeBlockMapping::init();
|
@ -68,6 +68,7 @@ abstract class DefaultPermissions{
|
||||
$ban = self::registerPermission(new Permission(self::ROOT . ".command.ban", "Allows the user to ban people", Permission::DEFAULT_OP), $commands);
|
||||
self::registerPermission(new Permission(self::ROOT . ".command.ban.player", "Allows the user to ban players"), $ban);
|
||||
self::registerPermission(new Permission(self::ROOT . ".command.ban.ip", "Allows the user to ban IP addresses"), $ban);
|
||||
self::registerPermission(new Permission(self::ROOT . ".command.ban.list", "Allows the user to list banned players"), $ban);
|
||||
$ban->recalculatePermissibles();
|
||||
|
||||
$unban = self::registerPermission(new Permission(self::ROOT . ".command.unban", "Allows the user to unban people", Permission::DEFAULT_OP), $commands);
|
||||
@ -125,6 +126,7 @@ abstract class DefaultPermissions{
|
||||
self::registerPermission(new Permission(self::ROOT . ".command.setworldspawn", "Allows the user to change the world spawn", Permission::DEFAULT_OP), $commands);
|
||||
self::registerPermission(new Permission(self::ROOT . ".command.transferserver", "Allows the user to transfer self to another server", Permission::DEFAULT_OP), $commands);
|
||||
self::registerPermission(new Permission(self::ROOT . ".command.title", "Allows the user to send a title to the specified player", Permission::DEFAULT_OP), $commands);
|
||||
self::registerPermission(new Permission(self::ROOT . ".command.difficulty", "Allows the user to change the game difficulty", Permission::DEFAULT_OP), $commands);
|
||||
|
||||
$commands->recalculatePermissibles();
|
||||
|
||||
|
@ -36,6 +36,7 @@ use function implode;
|
||||
use function mb_check_encoding;
|
||||
use function mb_scrub;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
|
||||
class Sign extends Spawnable{
|
||||
public const TAG_TEXT_BLOB = "Text";
|
||||
@ -151,6 +152,14 @@ class Sign extends Spawnable{
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
$size = 0;
|
||||
foreach($lines as $line){
|
||||
$size += strlen($line);
|
||||
}
|
||||
if($size > 1000){
|
||||
//trigger kick + IP ban - TODO: on 4.0 this will require a better fix
|
||||
throw new \UnexpectedValueException($player->getName() . " tried to write $size bytes of text onto a sign (bigger than max 1000)");
|
||||
}
|
||||
|
||||
$removeFormat = $player->getRemoveFormat();
|
||||
|
||||
|
@ -74,7 +74,7 @@ abstract class TextFormat{
|
||||
* @return array
|
||||
*/
|
||||
public static function tokenize(string $string) : array{
|
||||
return preg_split("/(" . TextFormat::ESCAPE . "[0-9a-fk-or])/", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||
return preg_split("/(" . TextFormat::ESCAPE . "[0-9a-fk-or])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,6 +87,7 @@ abstract class TextFormat{
|
||||
*/
|
||||
public static function clean(string $string, bool $removeFormat = true) : string{
|
||||
$string = mb_scrub($string, 'UTF-8');
|
||||
$string = preg_replace("/[\x{E000}-\x{F8FF}]/u", "", $string); //remove unicode private-use-area characters (they might break the console)
|
||||
if($removeFormat){
|
||||
$string = str_replace(TextFormat::ESCAPE, "", preg_replace("/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "", $string));
|
||||
}
|
||||
|
Reference in New Issue
Block a user