From a833d92d7651f8c74b0ea18bca3b20bddc0a6c59 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Pueyo Date: Wed, 19 Dec 2012 14:23:34 +0100 Subject: [PATCH] Fixed Time, Death and more event issues --- classes/API/EntityAPI.php | 27 +++++++ classes/API/PlayerAPI.php | 2 +- classes/API/TimeAPI.php | 8 +- classes/Entity.class.php | 4 +- classes/PocketMinecraftServer.class.php | 102 +++++++++++++----------- classes/Session.class.php | 12 +-- 6 files changed, 96 insertions(+), 59 deletions(-) diff --git a/classes/API/EntityAPI.php b/classes/API/EntityAPI.php index 9e8efd86f..0b5af081b 100644 --- a/classes/API/EntityAPI.php +++ b/classes/API/EntityAPI.php @@ -29,12 +29,39 @@ class EntityAPI{ private $server; function __construct($server){ $this->server = $server; + $this->server->addHandler("onPlayerDeath", array($this, "handle"), 1); } public function init(){ $this->server->api->console->register("give", "Give items to a player", array($this, "commandHandler")); } + public function handle($data, $event){ + switch($event){ + case "onPlayerDeath": + $message = $data["name"]; + if(is_numeric($data["cause"]) and isset($this->entities[$data["cause"]])){ + $e = $this->api->entity->get($data["cause"]); + switch($e->class){ + case ENTITY_PLAYER: + $message .= " was killed by ".$e->name; + break; + default: + $message .= " was killed"; + break; + } + }else{ + switch($data["cause"]){ + default: + $message .= " was killed"; + break; + } + } + $this->server->chat(false, $message); + break; + } + } + public function commandHandler($cmd, $params){ switch($cmd){ case "give": diff --git a/classes/API/PlayerAPI.php b/classes/API/PlayerAPI.php index d49abc5e4..683f7b5e5 100644 --- a/classes/API/PlayerAPI.php +++ b/classes/API/PlayerAPI.php @@ -44,7 +44,7 @@ class PlayerAPI{ case "onHealthRegeneration": $result = $this->server->query("SELECT ip,port FROM players WHERE EID = (SELECT EID FROM entities WHERE health < 20);", true); if($result !== true and $result !== false){ - while($player = $result->fetchArray()){ + while(false !== ($player = $result->fetchArray())){ $player->entity->setHealth(min(20, $player->entity->getHealth() + $data), "regeneration"); } } diff --git a/classes/API/TimeAPI.php b/classes/API/TimeAPI.php index 6ad1ca45e..35776acd4 100644 --- a/classes/API/TimeAPI.php +++ b/classes/API/TimeAPI.php @@ -96,13 +96,13 @@ class TimeAPI{ $this->server->time += (int) $time; } - public function getDate(){ - $time = $this->get(); + public function getDate($time = false){ + $time = $time === false ? $this->get():$time; return str_pad(strval((floor($time /800) + 6) % 24), 2, "0", STR_PAD_LEFT).":".str_pad(strval(floor(($time % 800) / 13.33)), 2, "0", STR_PAD_LEFT); } - public function getPhase(){ - $time = $this->get(); + public function getPhase($time = false){ + $time = $time === false ? $this->get():$time; if($time < $this->phase["sunset"]){ $time = "day"; }elseif($time < $this->phase["night"]){ diff --git a/classes/Entity.class.php b/classes/Entity.class.php index 00a89fecb..7ebe3b04a 100644 --- a/classes/Entity.class.php +++ b/classes/Entity.class.php @@ -192,10 +192,10 @@ class Entity extends stdClass{ "health" => $this->health, )); } - if($this->health <= 0){ + if($this->health <= 0 and $this->dead === false){ $this->dead = true; if($this->player !== false){ - $this->server->trigger("onPlayerDeath", array("name" => $this->name, "cause" => $cause)); + $this->server->handle("onPlayerDeath", array("name" => $this->name, "cause" => $cause)); } }elseif($this->health > 0){ $this->dead = false; diff --git a/classes/PocketMinecraftServer.class.php b/classes/PocketMinecraftServer.class.php index 6a00b7a71..b7ae717d6 100644 --- a/classes/PocketMinecraftServer.class.php +++ b/classes/PocketMinecraftServer.class.php @@ -80,15 +80,13 @@ class PocketMinecraftServer extends stdClass{ public function getTPS(){ $v = array_values($this->tickMeasure); - $tps = 40/($v[39] - $v[0]); + $tps = 40 / ($v[39] - $v[0]); return round($tps, 4); } public function loadEvents(){ $this->event("onChat", "eventHandler", true); - $this->event("onPlayerDeath", "eventHandler", true); $this->event("onPlayerAdd", "eventHandler", true); - $this->event("onHealthChange", "eventHandler", true); $this->action(500000, '$this->time += (int) ($this->timePerSecond / 2);$this->trigger("onTimeChange", $this->time);'); $this->action(5000000, 'if($this->difficulty < 2){$this->trigger("onHealthRegeneration", 1);}'); @@ -103,19 +101,19 @@ class PocketMinecraftServer extends stdClass{ public function startDatabase(){ $this->preparedSQL = new stdClass(); $this->database = new SQLite3(":memory:"); - $this->query("PRAGMA journal_mode = OFF;"); - $this->query("PRAGMA encoding = \"UTF-8\";"); - $this->query("PRAGMA secure_delete = OFF;"); + //$this->query("PRAGMA journal_mode = OFF;"); + //$this->query("PRAGMA encoding = \"UTF-8\";"); + //$this->query("PRAGMA secure_delete = OFF;"); $this->query("CREATE TABLE players (clientID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE);"); $this->query("CREATE TABLE entities (EID INTEGER PRIMARY KEY, type NUMERIC, class NUMERIC, name TEXT, x NUMERIC, y NUMERIC, z NUMERIC, yaw NUMERIC, pitch NUMERIC, health NUMERIC);"); $this->query("CREATE TABLE metadata (EID INTEGER PRIMARY KEY, name TEXT, value TEXT);"); $this->query("CREATE TABLE actions (ID INTEGER PRIMARY KEY, interval NUMERIC, last NUMERIC, code TEXT, repeat NUMERIC);"); $this->query("CREATE TABLE events (ID INTEGER PRIMARY KEY, name TEXT);"); $this->query("CREATE TABLE handlers (ID INTEGER PRIMARY KEY, name TEXT, priority NUMERIC);"); - $this->query("PRAGMA synchronous = OFF;"); - $this->preparedSQL->selectHandlers = $this->database->prepare("SELECT ID FROM handlers WHERE name = ? ORDER BY priority DESC;"); - $this->preparedSQL->selectEvents = $this->database->prepare("SELECT ID FROM events WHERE name = ?;"); - $this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (? - interval);"); + //$this->query("PRAGMA synchronous = OFF;"); + $this->preparedSQL->selectHandlers = $this->database->prepare("SELECT ID FROM handlers WHERE name = :name ORDER BY priority DESC;"); + $this->preparedSQL->selectEvents = $this->database->prepare("SELECT ID FROM events WHERE name = :name;"); + $this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (:time - interval);"); $this->preparedSQL->updateActions = $this->database->prepare("UPDATE actions SET last = :time WHERE last <= (:time - interval);"); } @@ -193,43 +191,24 @@ class PocketMinecraftServer extends stdClass{ return $this->handCnt++; } - public function handle($event, &$data){ + public function handle($event, $data){ + $this->preparedSQL->selectHandlers->reset(); $this->preparedSQL->selectHandlers->clear(); - $this->preparedSQL->selectHandlers->bindValue(1, $event, SQLITE3_TEXT); + $this->preparedSQL->selectHandlers->bindValue(":name", $event, SQLITE3_TEXT); $handlers = $this->preparedSQL->selectHandlers->execute(); if($handlers === false or $handlers === true){ return $this->trigger($event, $data); } - while($hn = $handlers->fetchArray(SQLITE3_ASSOC)){ + while(false !== ($hn = $handlers->fetchArray(SQLITE3_ASSOC))){ $hnid = (int) $hn["ID"]; call_user_func($this->handlers[$hnid], $data, $event); } + $handlers->finalize(); return true; } public function eventHandler($data, $event){ switch($event){ - case "onPlayerDeath": - $message = $data["name"]; - if(is_numeric($data["cause"]) and isset($this->entities[$data["cause"]])){ - $e = $this->api->entity->get($data["cause"]); - switch($e->class){ - case ENTITY_PLAYER: - $message .= " was killed by ".$e->name; - break; - default: - $message .= " was killed"; - break; - } - }else{ - switch($data["cause"]){ - default: - $message .= " was killed"; - break; - } - } - $this->chat(false, $message); - break; case "onPlayerAdd": console("[DEBUG] Player \"".$data["username"]."\" EID ".$data["eid"]." spawned at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2); break; @@ -357,17 +336,29 @@ class PocketMinecraftServer extends stdClass{ $this->custom["times_".$CID] = ($this->custom["times_".$CID] + 1) % strlen($this->description); break; case 0x05: - if(in_array($packet["ip"], $this->bannedIPs)){ - break; - } - if(count($this->clients) >= $this->maxClients){ + if(in_array($packet["ip"], $this->bannedIPs) or count($this->clients) >= $this->maxClients){ + $this->send(0x80, array( + 0, + 0x00, + array( + "id" => MC_LOGIN_STATUS, + "status" => 1, + ), + ), false, $packet["ip"], $packet["port"]); + $this->send(0x80, array( + 1, + 0x00, + array( + "id" => MC_DISCONNECT, + ), + ), false, $packet["ip"], $packet["port"]); break; } $version = $data[1]; $size = strlen($data[2]); if($version !== $this->protocol){ $this->send(0x1a, array( - 5, + $this->protocol, MAGIC, $this->serverID, ), false, $packet["ip"], $packet["port"]); @@ -381,10 +372,22 @@ class PocketMinecraftServer extends stdClass{ } break; case 0x07: - if(in_array($packet["ip"], $this->bannedIPs)){ - break; - } - if(count($this->clients) >= $this->maxClients){ + if(in_array($packet["ip"], $this->bannedIPs) or count($this->clients) >= $this->maxClients){ + $this->send(0x80, array( + 0, + 0x00, + array( + "id" => MC_LOGIN_STATUS, + "status" => 1, + ), + ), false, $packet["ip"], $packet["port"]); + $this->send(0x80, array( + 1, + 0x00, + array( + "id" => MC_DISCONNECT, + ), + ), false, $packet["ip"], $packet["port"]); break; } $port = $data[2]; @@ -413,16 +416,18 @@ class PocketMinecraftServer extends stdClass{ } public function trigger($event, $data = ""){ + $this->preparedSQL->selectEvents->reset(); $this->preparedSQL->selectEvents->clear(); - $this->preparedSQL->selectEvents->bindValue(1, $event, SQLITE3_TEXT); + $this->preparedSQL->selectEvents->bindValue(":name", $event, SQLITE3_TEXT); $events = $this->preparedSQL->selectEvents->execute(); if($events === false or $events === true){ return; } - while($evn = $events->fetchArray(SQLITE3_ASSOC)){ + while(false !== ($evn = $events->fetchArray(SQLITE3_ASSOC))){ $evid = (int) $evn["ID"]; $this->responses[$evid] = call_user_func($this->events[$evid], $data, $event, $this); } + $events->finalize(); return true; } @@ -442,19 +447,22 @@ class PocketMinecraftServer extends stdClass{ public function tickerFunction($time){ //actions that repeat every x time will go here + $this->preparedSQL->selectActions->reset(); $this->preparedSQL->selectActions->clear(); - $this->preparedSQL->selectActions->bindValue(1, $time, SQLITE3_FLOAT); + $this->preparedSQL->selectActions->bindValue(":time", $time, SQLITE3_FLOAT); $actions = $this->preparedSQL->selectActions->execute(); if($actions === false or $actions === true){ return; } - while($action = $actions->fetchArray(SQLITE3_ASSOC)){ + while(false !== ($action = $actions->fetchArray(SQLITE3_ASSOC))){ eval($action["code"]); if($action["repeat"] === 0){ $this->query("DELETE FROM actions WHERE ID = ".$action["ID"].";"); } } + $actions->finalize(); + $this->preparedSQL->updateActions->reset(); $this->preparedSQL->updateActions->clear(); $this->preparedSQL->updateActions->bindValue(":time", $time, SQLITE3_FLOAT); $this->preparedSQL->updateActions->execute(); diff --git a/classes/Session.class.php b/classes/Session.class.php index 5346e978e..f881f0e22 100644 --- a/classes/Session.class.php +++ b/classes/Session.class.php @@ -28,7 +28,7 @@ the Free Software Foundation, either version 3 of the License, or class Session{ private $server, $timeout, $connected, $evid, $queue, $buffer; - var $clientID, $ip, $port, $counter, $username, $eid, $data, $entity, $auth, $CID, $MTU; + var $clientID, $ip, $port, $counter, $username, $eid, $data, $entity, $auth, $CID, $MTU, $spawned; function __construct($server, $clientID, $ip, $port, $MTU){ $this->queue = array(); $this->buffer = array(); @@ -43,6 +43,7 @@ class Session{ $this->port = $port; $this->timeout = microtime(true) + 25; $this->evid = array(); + $this->spawned = false; $this->evid[] = $this->server->event("onTick", array($this, "onTick")); $this->evid[] = $this->server->event("onClose", array($this, "close")); console("[DEBUG] New Session started with ".$ip.":".$port.". MTU ".$this->MTU.", Client ID ".$this->clientID, true, true, 2); @@ -219,6 +220,7 @@ class Session{ } switch($data["id"]){ case MC_DISCONNECT: + $this->connected = false; $this->close("client disconnect"); break; case MC_CLIENT_CONNECT: @@ -263,9 +265,10 @@ class Session{ )); break; case MC_READY: - if(is_object($this->entity)){ + if($this->spawned !== false){ break; } + $this->spawned = true; $this->entity = $this->server->api->entity->add(ENTITY_PLAYER, 0, array("player" => $this)); $this->eid = $this->entity->eid; $this->server->query("UPDATE players SET EID = ".$this->eid." WHERE clientID = ".$this->clientID.";"); @@ -320,10 +323,9 @@ class Session{ case MC_INTERACT: if(isset($this->server->entities[$data["target"]]) and Utils::distance($this->entity->position, $this->server->entities[$data["target"]]->position) <= 8){ console("[DEBUG] EID ".$this->eid." attacked EID ".$data["target"], true, true, 2); - if($this->server->gamemode !== 1 and $this->server->difficulty > 0){ - + if($this->server->gamemode !== 1 and $this->server->difficulty > 0){ + $this->server->api->entity->harm($data["target"], $this->server->difficulty, $this->eid); } - $this->server->trigger("onHealthChange", array("eid" => $data["target"], "health" => $this->server->entities[$data["target"]]->getHealth() - $this->server->difficulty, "cause" => $this->eid)); } break; case MC_ANIMATE: