Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions src/API/BanAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ public function permissionsCheck($data, $event){
if(!$this->isOp($player->iusername) && $player->level->getName() === $this->server->api->level->getDefault()){
$t = new Vector2($data["target"]->x, $data["target"]->z);
$s = new Vector2($this->server->spawn->x, $this->server->spawn->z);
if($t->distance($s) <= $this->server->api->getProperty("spawn-protection") and $this->server->api->dhandle($event . ".spawn", $data) !== true){
$sp = $player->entity->level->getProperty("spawn-protection");

if($t->distance($s) <= $sp and $this->server->api->dhandle($event . ".spawn", $data) !== true){
return false;
}
}
Expand All @@ -84,7 +86,9 @@ public function permissionsCheck($data, $event){
if(!$this->isOp($player->iusername) && $player->level->getName() === $this->server->api->level->getDefault()){
$t = new Vector2($data["block"]->x, $data["block"]->z);
$s = new Vector2($this->server->spawn->x, $this->server->spawn->z);
if($t->distance($s) <= $this->server->api->getProperty("spawn-protection") and $this->server->api->dhandle($event . ".spawn", $data) !== true){
$sp = $player->entity->level->getProperty("spawn-protection");

if($t->distance($s) <= $sp and $this->server->api->dhandle($event . ".spawn", $data) !== true){
return false;
}
}
Expand Down
8 changes: 2 additions & 6 deletions src/API/EntityAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@ class EntityAPI{
public $entities;
private $server;
private $eCnt = 1;
private $serverSpawnAnimals, $serverSpawnMobs;
function __construct(){
$this->entities = [];
$this->server = ServerAPI::request();

$this->serverSpawnAnimals = $this->server->api->getProperty("spawn-animals");
$this->serverSpawnMobs = $this->server->api->getProperty("spawn-mobs");
}

public function init(){
Expand Down Expand Up @@ -194,8 +190,8 @@ public function getNextEID(){
public function addRaw(Entity $e){
$eid = $e->eid;
$this->entities[$eid] = $e;
$cX = (int)$this->entities[$eid]->x >> 4;
$cZ = (int)$this->entities[$eid]->z >> 4;
$cX = floor($this->entities[$eid]->x >> 4);
$cZ = floor($this->entities[$eid]->z >> 4);
$e->level->entityListPositioned["$cX $cZ"][$eid] = $eid;
$e->level->entityList[$eid] = &$this->entities[$eid];
$this->server->handle("entity.add", $this->entities[$eid]);
Expand Down
89 changes: 84 additions & 5 deletions src/API/LevelAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,28 @@ public function __construct(){
}

public function init(){
//TODO per-level difficulty, interact, random-ticking
$this->registerProperty("difficulty", 2, desc: "WIP for now, Difficulty level. 0 - Peaceful, 1 - Easy, 2 - Normal, 3 - Hard");
$this->registerProperty("mobs-amount", 50, desc: "Max amount of mobs that can be spawned.");
$this->registerProperty("spawn-animals", true, desc: "Spawn animals.");
$this->registerProperty("spawn-monsters", true, desc: "Spawn monsters.");
$this->registerProperty("pvp", true, desc: "Enable or disable pvp in the level");
$this->registerProperty("random-ticking", "subchunk", desc: [
"WIP", "Affects how random ticking works. Available modes:",
"subchunk - tick 16x16x16 areas",
"fullchunk - tick 16x16x128 areas",
"vanilla - tick 256x256x128 area"
]);
$this->registerProperty("interact", true, desc: "WIP, Enable or disable ability to interact with the level");
$this->registerProperty("spawn-protection", 16, desc: "Prevent player interactions <n> blocks around the spawn.");


$this->server->api->console->register("setworldprop", "[world] <property> <value>", [$this, "commandHandler"]);
$this->server->api->console->register("getworldprop", "[world] <property>", [$this, "commandHandler"]);
$this->server->api->console->register("reloadworldprops", "[world]", [$this, "commandHandler"]);
$this->server->api->console->register("createworld", "<worldname> [type] [seed]", [$this, "commandHandler"]);
$this->server->api->console->register("loadworld", "<worldname>", [$this, "commandHandler"]);

$this->server->api->console->register("seed", "[world]", [$this, "commandHandler"]);
$this->server->api->console->register("save-all", "", [$this, "commandHandler"]);
$this->server->api->console->register("save-on", "", [$this, "commandHandler"]);
Expand All @@ -26,6 +48,49 @@ public function init(){
}
$this->server->spawn = $this->getDefault()->getSafeSpawn();
}


private $defaultLevelProperties = [];
private $levelPropsInfo = [];

/**
* Registers a level property
*
* @param string $name - property name
* @param mixed $defaultValue - default property value
* @param array[string]|string|boolean $desc=false - property description(false=none, string=single line, array of strings=multiline)
* @return false if the property exists, true if success
*/
public function registerProperty(string $name, $defaultValue, $desc = false){
if(isset($this->defaultLevelProperties[$name])) return false;

$this->defaultLevelProperties[$name] = $defaultValue;
if(is_array($desc) || is_string($desc)) $this->levelPropsInfo[$name] = $desc;
return true;
}

/**
* Gets a default value for property
* @param string $name - property name
* @param mixed $fail=false - return value if the property doesn't exist
* @return string|mixed
*/
public function getDefaultProperty(string $name, $fail=false){
return $this->defaultLevelProperties[$name] ?? $fail;
}

/**
* Loads a properties for a level
* @param Level $level
*/
public function loadLevelProperties(Level $level){
$propsPath = DATA_PATH . "worlds/{$level->getName()}/properties.yml";

$level->levelProperties = new Config($propsPath, CONFIG_YAML, $this->defaultLevelProperties, comments: $this->levelPropsInfo);
foreach($level->levelProperties->getAll() as $k => $v){
$level->setProperty($k, $v);
}
}

public function loadLevel($name){
if($this->get($name) !== false){
Expand All @@ -50,14 +115,16 @@ public function loadLevel($name){
}
}


$entities = new Config($path . "entities.yml", CONFIG_YAML);
if(file_exists($path . "tileEntities.yml")){
@rename($path . "tileEntities.yml", $path . "tiles.yml");
}
$tiles = new Config($path . "tiles.yml", CONFIG_YAML);
$blockUpdates = new Config($path . "bupdates.yml", CONFIG_YAML);
$this->levels[$name] = new Level($level, $entities, $tiles, $blockUpdates, $name);

$this->levels[$name] = $lvl = new Level($level, $entities, $tiles, $blockUpdates, $name);
$this->loadLevelProperties($lvl);

foreach($entities->getAll() as $entity){
if(!isset($entity["id"])){
break;
Expand All @@ -82,15 +149,12 @@ public function loadLevel($name){
]);
}elseif($entity["id"] === FALLING_SAND){
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_FALLING, $entity["id"], $entity);
//$e->setPosition(new Vector3($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2]), $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth($entity["Health"]);
}elseif(Utils::getEntityTypeByID($entity["id"]) === ENTITY_OBJECT){ //Object
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_OBJECT, $entity["id"], $entity);
//$e->setPosition(new Vector3($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2]), $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth(1);
}else{
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_MOB, $entity["id"], $entity);
//$e->setPosition(new Vector3($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2]), $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth($entity["Health"]);
}
}
Expand Down Expand Up @@ -166,6 +230,21 @@ public function getDefault(){
public function commandHandler($cmd, $params, $issuer, $alias){
$output = "";
switch($cmd){
case "setworldprop":

return "WIP";
case "getworldprop":

return "WIP";
case "reloadworldprops":

return "WIP";
case "createworld":
return "WIP";
case "loadworld":

return "WIP";

case "setwspawn":
if(!($issuer instanceof Player)){
return ("Please run this command in-game. ");
Expand Down
23 changes: 14 additions & 9 deletions src/API/ServerAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,18 @@ public function load(){
"memory-limit" => "128M",
"white-list" => false,
"announce-player-achievements" => true,
"spawn-protection" => 16,
//"spawn-protection" => 16,
"view-distance" => 10,
"max-players" => 20,
"allow-flight" => true,
"spawn-animals" => true,
"spawn-mobs" => true,
"mobs-amount" => 50,
//"spawn-animals" => true,
//"spawn-mobs" => true,
//"mobs-amount" => 50,
"gamemode" => SURVIVAL,
"hardcore" => false,
"pvp" => true,
"difficulty" => 2,
//"pvp" => true,
"generator-settings" => "",
"difficulty" => 2,
"level-name" => "world",
"level-seed" => "",
"level-type" => "DEFAULT",
Expand All @@ -140,7 +140,14 @@ public function load(){
"ticking-mode" => "legacy",
"mushroom-spread" => Block::$mushroomSpread
], comments: [
"level-name" => [
"Default level name"
],
"level-seed" => [
"Default level seed"
],
"level-type" => [
"Default level type",
"Alowed types:",
"FLAT - flat world",
"DEFAULT - use one of the 4 pregenerated worlds from pocketmine",
Expand Down Expand Up @@ -190,7 +197,6 @@ public function load(){
ConsoleAPI::warn("Fly checking is enabled! Players may experience issues with kicking while not flying!");
}
$this->parseProperties();
MobSpawner::$MOB_LIMIT = $this->getProperty("mobs-amount", 50);
Entity::$allowedAI = $this->getProperty("enable-mob-ai", true);
PocketMinecraftServer::$PACKET_READING_LIMIT = $this->getProperty("abort-reading-after-N-packets", PocketMinecraftServer::$PACKET_READING_LIMIT);
PocketMinecraftServer::$TICKING_MODE = match(strtolower($this->getProperty("ticking-mode"))){
Expand All @@ -202,8 +208,7 @@ public function load(){
define("DEBUG", $this->getProperty("debug", 1));
define("ADVANCED_CACHE", false);
//define("MAX_CHUNK_RATE", 20 / $this->getProperty("max-chunks-per-second", 8)); //Default rate ~512 kB/s
MobSpawner::$spawnAnimals = $this->getProperty("spawn-animals");
MobSpawner::$spawnMobs = $this->getProperty("spawn-mobs");

if($this->getProperty("upnp-forwarding")){
console("[INFO] [UPnP] Trying to port forward...");
UPnP_PortForward($this->getProperty("server-port"));
Expand Down
71 changes: 33 additions & 38 deletions src/API/TileAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,42 @@
class TileAPI{

private $server;
/**
* @var Tile[]
*/
private $tiles;
private $tCnt = 1;

function __construct(){
$this->tiles = [];
$this->server = ServerAPI::request();
}
public function getXYZ(Level $level, $x, $y, $z){
$tile = $this->server->query("SELECT * FROM tiles WHERE level = '{$level->getName()}' AND x = $x AND y = $y AND z = $z;", true);
if($tile !== false and $tile !== true and ($tile = $this->getByID($tile["ID"])) !== false){
return $tile;
public function getXYZ(Level $level, int $x, int $y, int $z){
$cX = ($x >> 4);
$cZ = ($z >> 4);
foreach($level->tileEntityListPositioned["$cX $cZ"] ?? [] as $tile){
if($tile->x == $x && $tile->y == $y && $tile->z == $z) return $tile;
}
return false;
}

public function invalidateAll(Level $level, $x, $y, $z){
$x = (int) $x;
$y = (int) $y;
$z = (int) $z;
$tile = $this->server->query("SELECT id FROM tiles WHERE level = '{$level->getName()}' AND x = $x AND y = $y AND z = $z;", false);
public function invalidateAll(Level $level, int $x, int $y, int $z){
$cX = ($x >> 4);
$cZ = ($z >> 4);
$invcnt = 0;
if($tile instanceof SQLite3Result){
while(($t = $tile->fetchArray(SQLITE3_ASSOC)) !== false){
$tl = $this->getByID($t["ID"]);
if($tl instanceof Tile){
++$invcnt;
$tl->close();
}

if($invcnt > 1){
ConsoleAPI::warn("{$level->getName()}: ($x $y $z) has more than 1 tile entity! Invalidated ID {$t["ID"]} (Total invaliated: $invcnt)");
}
foreach($level->tileEntityListPositioned["$cX $cZ"] ?? [] as $tile){
if($tile->x == $x && $tile->y == $y && $tile->z == $z){
++$invcnt;
$tile->close();
}
if($invcnt > 1){
ConsoleAPI::warn("{$level->getName()}: ($x $y $z) has more than 1 tile entity! Invalidated ID {$tile->id} (Total invaliated: $invcnt)");
}
}
}

public function get(Position $pos){
$tile = $this->server->query("SELECT * FROM tiles WHERE level = '" . $pos->level->getName() . "' AND x = {$pos->x} AND y = {$pos->y} AND z = {$pos->z};", true);
if($tile !== false and $tile !== true and ($tile = $this->getByID($tile["ID"])) !== false){
return $tile;
}
return false;
return $this->getXYZ($pos->level, $pos->x, $pos->y, $pos->z);
}

public function getByID($id){
Expand Down Expand Up @@ -75,7 +69,13 @@ public function addSign(Level $level, $x, $y, $z, $lines = ["", "", "", ""]){

public function add(Level $level, $class, $x, $y, $z, $data = []){
$id = $this->tCnt++;
$this->tiles[$id] = new Tile($level, $id, $class, $x, $y, $z, $data);
$clz = Tile::$tileId2tileClass[$class] ?? "Tile";
$this->tiles[$id] = $t = new $clz($level, $id, $class, $x, $y, $z, $data);
$cX = floor($t->x) >> 4;
$cZ = floor($t->z) >> 4;
$t->level->tileEntityList[$id] = $t;
$t->level->tileEntityListPositioned["$cX $cZ"][$id] = $t;

$this->spawnToAll($this->tiles[$id]);
return $this->tiles[$id];
}
Expand All @@ -96,17 +96,7 @@ public function spawnAll(Player $player){

public function getAll($level = null){
if($level instanceof Level){
$tiles = [];
$l = $this->server->query("SELECT ID FROM tiles WHERE level = '" . $level->getName() . "';");
if($l !== false and $l !== true){
while(($t = $l->fetchArray(SQLITE3_ASSOC)) !== false){
$t = $this->getByID($t["ID"]);
if($t instanceof Tile){
$tiles[$t->id] = $t;
}
}
}
return $tiles;
return $level->tileEntityList;
}
return $this->tiles;
}
Expand All @@ -116,9 +106,14 @@ public function remove($id){
$t = $this->tiles[$id];
$this->tiles[$id] = null;
unset($this->tiles[$id]);
if($t->level instanceof Level){
$cX = floor($t->x >> 4);
$cZ = floor($t->z >> 4);
unset($t->level->tileEntityList[$id]);
unset($t->level->tileEntityListPositioned["$cX $cZ"][$id]);
}
$t->closed = true;
$t->close();
$this->server->query("DELETE FROM tiles WHERE ID = " . $id . ";");
$this->server->api->dhandle("tile.remove", $t);
$t = null;
unset($t);
Expand Down
Loading