mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-18 15:05:56 +00:00
SQLite database, Entities, position, health
This commit is contained in:
parent
842e01ffac
commit
ea1725ed57
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
data/*
|
||||
*.log
|
||||
*.bat
|
||||
server.properties
|
||||
|
@ -184,6 +184,31 @@ class CustomPacketHandler{
|
||||
$this->raw .= Utils::writeFloat($this->data["z"]);
|
||||
}
|
||||
break;
|
||||
case MC_ADD_PLAYER:
|
||||
if($this->c === false){
|
||||
$this->data["clientID"] = Utils::readLong($this->get(8));
|
||||
$this->data["username"] = $this->get(Utils::readShort($this->get(2), false));
|
||||
$this->data["eid"] = Utils::readInt($this->get(4));
|
||||
$this->data["x"] = Utils::readFloat($this->get(4));
|
||||
$this->data["y"] = Utils::readFloat($this->get(4));
|
||||
$this->data["z"] = Utils::readFloat($this->get(4));
|
||||
$this->data["yaw"] = Utils::readFloat($this->get(4));
|
||||
$this->data["pitch"] = Utils::readFloat($this->get(4));
|
||||
$this->data["block"] = Utils::readShort($this->get(2), false);
|
||||
$this->data["meta"] = Utils::readShort($this->get(2), false);
|
||||
}else{
|
||||
$this->raw .= Utils::writeLong($this->data["clientID"]);
|
||||
$this->raw .= Utils::writeShort(strlen($this->data["username"])).$this->data["username"];
|
||||
$this->raw .= Utils::writeInt($this->data["eid"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["x"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["y"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["z"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["yaw"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["pitch"]);
|
||||
$this->raw .= Utils::writeShort($this->data["block"]);
|
||||
$this->raw .= Utils::writeShort($this->data["meta"]);
|
||||
}
|
||||
break;
|
||||
case MC_REMOVE_ENTITY:
|
||||
if($this->c === false){
|
||||
$this->data["eid"] = Utils::readInt($this->get(4));
|
||||
@ -233,8 +258,8 @@ class CustomPacketHandler{
|
||||
case MC_PLAYER_EQUIPMENT:
|
||||
if($this->c === false){
|
||||
$this->data["eid"] = Utils::readInt($this->get(4));
|
||||
$this->data["block"] = Utils::readShort($this->get(2), true);
|
||||
$this->data["meta"] = Utils::readShort($this->get(2), true);
|
||||
$this->data["block"] = Utils::readShort($this->get(2), false);
|
||||
$this->data["meta"] = Utils::readShort($this->get(2), false);
|
||||
}else{
|
||||
$this->raw .= Utils::writeInt($this->data["eid"]);
|
||||
$this->raw .= Utils::writeShort($this->data["block"]);
|
||||
@ -246,6 +271,19 @@ class CustomPacketHandler{
|
||||
$this->data["health"] = ord($this->get(1));
|
||||
}else{
|
||||
$this->raw .= chr($this->data["health"]);
|
||||
}
|
||||
break;
|
||||
case MC_RESPAWN:
|
||||
if($this->c === false){
|
||||
$this->data["eid"] = Utils::readInt($this->get(4));
|
||||
$this->data["x"] = Utils::readFloat($this->get(4));
|
||||
$this->data["y"] = Utils::readFloat($this->get(4));
|
||||
$this->data["z"] = Utils::readFloat($this->get(4));
|
||||
}else{
|
||||
$this->raw .= Utils::writeInt($this->data["eid"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["x"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["y"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["z"]);
|
||||
}
|
||||
break;
|
||||
case MC_CLIENT_MESSAGE:
|
||||
|
157
classes/Entity.class.php
Normal file
157
classes/Entity.class.php
Normal file
@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ POCKET \
|
||||
/ MINECRAFT PHP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
|
||||
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.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
define("ENTITY_PLAYER", 0);
|
||||
define("ENTITY_MOB", 1);
|
||||
define("ENTITY_OBJECT", 2);
|
||||
define("ENTITY_ITEM", 3);
|
||||
define("ENTITY_PAINTING", 4);
|
||||
|
||||
class Entity{
|
||||
var $eid, $type, $name, $position, $dead, $metadata, $class, $attach;
|
||||
protected $health, $client;
|
||||
|
||||
function __construct($eid, $class, $type = 0, $server){ //$type = 0 ---> player
|
||||
$this->server = $server;
|
||||
$this->eid = (int) $eid;
|
||||
$this->type = (int) $type;
|
||||
$this->class = (int) $class;
|
||||
$this->attach = false;
|
||||
$this->status = 0;
|
||||
$this->health = 20;
|
||||
$this->dead = false;
|
||||
$this->server->query("INSERT OR REPLACE INTO entities (EID, type, class, health) VALUES (".$this->eid.", ".$this->type.", ".$this->class.", ".$this->health.");");
|
||||
$this->metadata = array();
|
||||
/*include("misc/entities.php");
|
||||
switch($this->class){
|
||||
case ENTITY_PLAYER:
|
||||
case ENTITY_ITEM:
|
||||
break;
|
||||
|
||||
case ENTITY_MOB:
|
||||
$this->setName((isset($mobs[$this->type]) ? $mobs[$this->type]:$this->type));
|
||||
break;
|
||||
case ENTITY_OBJECT:
|
||||
$this->setName((isset($objects[$this->type]) ? $objects[$this->type]:$this->type));
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
$this->server->query("DELETE FROM entities WHERE EID = ".$this->eid.";");
|
||||
$this->server->trigger("onEntityRemove", $this->eid);
|
||||
}
|
||||
|
||||
public function getEID(){
|
||||
return $this->eid;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName($name){
|
||||
$this->name = $name;
|
||||
$this->server->query("UPDATE entities SET name = '".str_replace("'", "", $this->name)."' WHERE EID = ".$this->eid.";");
|
||||
}
|
||||
|
||||
public function look($pos2){
|
||||
$pos = $this->getPosition();
|
||||
$angle = Utils::angle3D($pos2, $pos);
|
||||
$this->position["yaw"] = $angle["yaw"];
|
||||
$this->position["pitch"] = $angle["pitch"];
|
||||
$this->server->query("UPDATE entities SET pitch = ".$this->position["pitch"].", yaw = ".$this->position["yaw"]." WHERE EID = ".$this->eid.";");
|
||||
}
|
||||
|
||||
public function setCoords($x, $y, $z){
|
||||
if(!isset($this->position)){
|
||||
$this->position = array(
|
||||
"x" => 0,
|
||||
"y" => 0,
|
||||
"z" => 0,
|
||||
"yaw" => 0,
|
||||
"pitch" => 0,
|
||||
"ground" => 0,
|
||||
);
|
||||
}
|
||||
$this->position["x"] = $x;
|
||||
$this->position["y"] = $y;
|
||||
$this->position["z"] = $z;
|
||||
$this->server->query("UPDATE entities SET x = ".$this->position["x"].", y = ".$this->position["y"].", z = ".$this->position["z"]." WHERE EID = ".$this->eid.";");
|
||||
}
|
||||
|
||||
public function move($x, $y, $z, $yaw = 0, $pitch = 0){
|
||||
if(!isset($this->position)){
|
||||
$this->position = array(
|
||||
"x" => 0,
|
||||
"y" => 0,
|
||||
"z" => 0,
|
||||
"yaw" => 0,
|
||||
"pitch" => 0,
|
||||
"ground" => 0,
|
||||
);
|
||||
}
|
||||
$this->position["x"] += $x;
|
||||
$this->position["y"] += $y;
|
||||
$this->position["z"] += $z;
|
||||
$this->position["yaw"] += $yaw;
|
||||
$this->position["yaw"] %= 360;
|
||||
$this->position["pitch"] += $pitch;
|
||||
$this->position["pitch"] %= 90;
|
||||
$this->server->query("UPDATE entities SET x = ".$this->position["x"].", y = ".$this->position["y"].", z = ".$this->position["z"].", pitch = ".$this->position["pitch"].", yaw = ".$this->position["yaw"]." WHERE EID = ".$this->eid.";");
|
||||
}
|
||||
|
||||
public function setPosition($x, $y, $z, $yaw, $pitch){
|
||||
$this->position = array(
|
||||
"x" => $x,
|
||||
"y" => $y,
|
||||
"z" => $z,
|
||||
"yaw" => $yaw,
|
||||
"pitch" => $pitch,
|
||||
"ground" => $ground,
|
||||
);
|
||||
$this->server->query("UPDATE entities SET x = ".$this->position["x"].", y = ".$this->position["y"].", z = ".$this->position["z"].", pitch = ".$this->position["pitch"].", yaw = ".$this->position["yaw"]." WHERE EID = ".$this->eid.";");
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getPosition($round = false){
|
||||
return !isset($this->position) ? false:($round === true ? array_map("floor", $this->position):$this->position);
|
||||
}
|
||||
|
||||
public function setHealth($health){
|
||||
$this->health = (int) $health;
|
||||
$this->server->query("UPDATE entities SET health = ".$this->health." WHERE EID = ".$this->eid.";");
|
||||
}
|
||||
|
||||
public function getHealth(){
|
||||
return $this->health;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -28,11 +28,14 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
require_once("classes/Session.class.php");
|
||||
|
||||
class PocketMinecraftServer{
|
||||
var $seed, $protocol, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd;
|
||||
protected $interface, $entities, $player, $cnt, $events, $version, $serverType;
|
||||
var $seed, $protocol, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $responses, $spawn, $entities;
|
||||
private $database, $interface, $cnt, $events, $version, $serverType, $lastTick;
|
||||
function __construct($name, $gamemode = 1, $seed = false, $protocol = CURRENT_PROTOCOL, $port = 19132, $serverID = false, $version = CURRENT_VERSION){
|
||||
$this->gamemode = (int) $gamemode;
|
||||
$this->port = (int) $port;
|
||||
console("[INFO] Starting Minecraft PE Server at *:".$this->port);
|
||||
console("[INFO] Loading database...");
|
||||
$this->startDatabase();
|
||||
$this->gamemode = (int) $gamemode;
|
||||
$this->version = (int) $version;
|
||||
$this->name = $name;
|
||||
$this->custom = array();
|
||||
@ -44,23 +47,16 @@ class PocketMinecraftServer{
|
||||
$this->bannedIPs = array();
|
||||
$this->motd = "Welcome to ".$name;
|
||||
$this->serverID = $serverID === false ? Utils::readLong(Utils::getRandomBytes(8)):$serverID;
|
||||
$this->seed = $seed === false ? Utils::readInt(Utils::getRandomBytes(4)):((int) $seed);
|
||||
$this->events = array("disabled" => array());
|
||||
$this->actions = array();
|
||||
$this->seed = $seed === false ? Utils::readInt(Utils::getRandomBytes(4)):$seed;
|
||||
$this->clients = array();
|
||||
$this->protocol = (int) $protocol;
|
||||
$this->spawn = array("x" => 128.5,"y" => 100,"z" => 128.5);
|
||||
$this->time = 0;
|
||||
//$this->event("onTick", "onTick", true);
|
||||
$this->event("onChat", "eventHandler", true);
|
||||
$this->action(1000000, '$this->time += 10;$this->trigger("onTimeChange", $this->time);');
|
||||
$this->action(1000000 * 60, '$this->reloadConfig();');
|
||||
$this->action(1000000 * 60 * 10, '$this->custom = array();');
|
||||
$this->timePerSecond = 10;
|
||||
console("[INFO] Loading events...");
|
||||
$this->loadEvents();
|
||||
$this->setType("normal");
|
||||
$this->interface = new MinecraftInterface("255.255.255.255", $this->protocol, $this->port, true, false);
|
||||
console("[INFO] Starting Minecraft PE Server at *:".$this->port);
|
||||
$this->action(1000000 * 3 * 60, '$this->chat(false, "This server uses Pocket-Minecraft-PHP");');
|
||||
sleep(2);
|
||||
$this->action(1000000 * 3 * 60, '$this->chat(false, "Check it at http://bit.ly/RE7uaW");');
|
||||
$this->reloadConfig();
|
||||
console("[INFO] Server Name: ".$this->name);
|
||||
console("[INFO] Server GUID: ".$this->serverID);
|
||||
@ -69,6 +65,37 @@ class PocketMinecraftServer{
|
||||
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
|
||||
console("[INFO] Max Clients: ".$this->maxClients);
|
||||
$this->stop = false;
|
||||
console("[INFO] Server started!");
|
||||
}
|
||||
|
||||
public function loadEvents(){
|
||||
$this->events = array("disabled" => array());
|
||||
|
||||
$this->event("onChat", "eventHandler", true);
|
||||
|
||||
$this->action(1000000, '$this->time += $this->timePerSecond;$this->trigger("onTimeChange", $this->time);');
|
||||
$this->action(1000000 * 60, '$this->reloadConfig();');
|
||||
$this->action(1000000 * 60 * 10, '$this->custom = array();');
|
||||
$this->action(1000000 * 80, '$list = ""; foreach($this->clients as $c){$list .= ", ".$c->username;}$this->chat(false, count($this->clients)."/".$this->maxClients." online: ".substr($list, 2));');
|
||||
$this->action(1000000 * 3 * 60, '$this->chat(false, "This server uses Pocket-Minecraft-PHP");');
|
||||
$this->action(1000000 * 3 * 60, '$this->chat(false, "Check it at http://bit.ly/RE7uaW");');
|
||||
$this->action(1000000 * 75, '$this->debugInfo(true);');
|
||||
}
|
||||
|
||||
public function startDatabase(){
|
||||
$this->database = new SQLite3(":memory:");
|
||||
$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, eventName TEXT, disabled INTEGER);");
|
||||
}
|
||||
|
||||
public function query($sql, $fetch = false){
|
||||
$result = $this->database->query($sql) or console("[ERROR] [SQL Error] ".$this->database->lastErrorMsg().". Query: ".$sql, true, true, 0);
|
||||
if($fetch === true and ($result !== false and $result !== true)){
|
||||
$result = $result->fetchArray(SQLITE3_ASSOC);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function reloadConfig(){
|
||||
@ -78,6 +105,23 @@ class PocketMinecraftServer{
|
||||
$this->bannedIPs = explode("\n", str_replace(array(" ","\t","\r"), "", file_get_contents(FILE_PATH."banned-ips.txt")));
|
||||
}
|
||||
|
||||
public function debugInfo($console = false){
|
||||
$info = array();
|
||||
$info["memory_usage"] = round((memory_get_usage(true) / 1024) / 1024, 2)."MB";
|
||||
$info["memory_peak_usage"] = round((memory_get_peak_usage(true) / 1024) / 1024, 2)."MB";
|
||||
$info["entities"] = $this->query("SELECT count(EID) as count FROM entities;", true);
|
||||
$info["entities"] = $info["entities"]["count"];
|
||||
$info["events"] = $this->query("SELECT count(ID) as count FROM events;", true);
|
||||
$info["events"] = $info["events"]["count"];
|
||||
$info["actions"] = $this->query("SELECT count(ID) as count FROM actions;", true);
|
||||
$info["actions"] = $info["actions"]["count"];
|
||||
$info["garbage"] = gc_collect_cycles();
|
||||
if($console === true){
|
||||
console("[DEBUG] Memory usage: ".$info["memory_usage"]." (Peak ".$info["memory_peak_usage"]."), Entities: ".$info["entities"].", Events: ".$info["events"].", Actions: ".$info["actions"].", Garbage: ".$info["garbage"], true, true, 2);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function close($reason = "stop"){
|
||||
$this->chat(false, "Stopping server...");
|
||||
$this->stop = true;
|
||||
@ -113,28 +157,20 @@ class PocketMinecraftServer{
|
||||
}
|
||||
}
|
||||
|
||||
public function action($microseconds, $code){
|
||||
$this->actions[] = array($microseconds / 1000000, microtime(true), $code);
|
||||
console("[INTERNAL] Attached to action ".$microseconds, true, true, 3);
|
||||
}
|
||||
|
||||
public function start(){
|
||||
declare(ticks=15);
|
||||
register_tick_function(array($this, "tickerFunction"));
|
||||
$this->action(50000, '$this->trigger("onTick", $time);');
|
||||
register_tick_function(array($this, "tick"));
|
||||
$this->event("onTick", "tickerFunction", true);
|
||||
$this->event("onReceivedPacket", "packetHandler", true);
|
||||
register_shutdown_function(array($this, "close"));
|
||||
$this->process();
|
||||
}
|
||||
|
||||
public function tickerFunction(){
|
||||
//actions that repeat every x time will go here
|
||||
public function tick(){
|
||||
$time = microtime(true);
|
||||
foreach($this->actions as $id => $action){
|
||||
if($action[1] <= ($time - $action[0])){
|
||||
$this->actions[$id][1] = $time;
|
||||
eval($action[2]);
|
||||
}
|
||||
if($this->lastTick <= ($time - 0.05)){
|
||||
$this->lastTick = $time;
|
||||
$this->trigger("onTick", $time);
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,9 +237,8 @@ class PocketMinecraftServer{
|
||||
$port = $data[2];
|
||||
$MTU = $data[3];
|
||||
$clientID = $data[4];
|
||||
$EID = $this->eidCnt++;
|
||||
$this->clients[$CID] = new Session($this, $clientID, $EID, $packet["ip"], $packet["port"]);
|
||||
$entities[$EID] = &$this->clients[$CID];
|
||||
$eid = $this->eidCnt++;
|
||||
$this->clients[$CID] = new Session($this, $clientID, $eid, $packet["ip"], $packet["port"]);
|
||||
$this->clients[$CID]->handle(0x07, $data);
|
||||
break;
|
||||
}
|
||||
@ -229,25 +264,61 @@ class PocketMinecraftServer{
|
||||
}
|
||||
|
||||
public function trigger($event, $data = ""){
|
||||
$events = $this->query("SELECT ID FROM events WHERE eventName = '".$event."' AND disabled = 0;");
|
||||
if($events === false or $events === true){
|
||||
return;
|
||||
}
|
||||
console("[INTERNAL] Event ". $event, true, true, 3);
|
||||
if(isset($this->events[$event]) and !isset($this->events["disabled"][$event])){
|
||||
foreach($this->events[$event] as $evid => $ev){
|
||||
if(isset($ev[1]) and ($ev[1] === true or is_object($ev[1]))){
|
||||
$this->responses[$evid] = call_user_func(array(($ev[1] === true ? $this:$ev[1]), $ev[0]), $data, $event, $this);
|
||||
}else{
|
||||
$this->responses[$evid] = call_user_func($ev[0], $data, $event, $this);
|
||||
}
|
||||
while($evn = $events->fetchArray(SQLITE3_ASSOC)){
|
||||
$ev = $this->events[$event][$evn["ID"]];
|
||||
if(isset($ev[1]) and ($ev[1] === true or is_object($ev[1]))){
|
||||
$this->responses[$evn["ID"]] = call_user_func(array(($ev[1] === true ? $this:$ev[1]), $ev[0]), $data, $event, $this);
|
||||
}else{
|
||||
$this->responses[$evn["ID"]] = call_user_func($ev[0], $data, $event, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function response($eid){
|
||||
if(isset($this->responses[$eid])){
|
||||
$res = $this->responses[$eid];
|
||||
unset($this->responses[$eid]);
|
||||
return $res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function action($microseconds, $code, $repeat = true){
|
||||
$this->query("INSERT INTO actions (interval, last, code, repeat) VALUES(".($microseconds / 1000000).", ".microtime(true).", '".str_replace("'", "\\'", $code)."', ".($repeat === true ? 1:0).");");
|
||||
console("[INTERNAL] Attached to action ".$microseconds, true, true, 3);
|
||||
}
|
||||
|
||||
public function tickerFunction(){
|
||||
//actions that repeat every x time will go here
|
||||
$time = microtime(true);
|
||||
$actions = $this->query("SELECT ID,code,repeat FROM actions WHERE last <= (".$time." - interval);");
|
||||
if($actions === false or $actions === true){
|
||||
return;
|
||||
}
|
||||
while($action = $actions->fetchArray(SQLITE3_ASSOC)){
|
||||
eval($action["code"]);
|
||||
if($action["repeat"] === 0){
|
||||
$this->query("DELETE FROM actions WHERE ID = ".$action["ID"].";");
|
||||
}
|
||||
}
|
||||
$this->query("UPDATE actions SET last = ".$time." WHERE last <= (".$time." - interval);");
|
||||
}
|
||||
|
||||
public function toggleEvent($event){
|
||||
if(isset($this->events["disabled"][$event])){
|
||||
unset($this->events["disabled"][$event]);
|
||||
$this->query("UPDATE events SET disabled = 0 WHERE eventName = '".$event."';");
|
||||
console("[INTERNAL] Enabled event ".$event, true, true, 3);
|
||||
}else{
|
||||
$this->events["disabled"][$event] = false;
|
||||
$this->query("UPDATE events SET disabled = 1 WHERE eventName = '".$event."';");
|
||||
console("[INTERNAL] Disabled event ".$event, true, true, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function event($event, $func, $in = false){
|
||||
@ -255,18 +326,23 @@ class PocketMinecraftServer{
|
||||
if(!isset($this->events[$event])){
|
||||
$this->events[$event] = array();
|
||||
}
|
||||
$this->query("INSERT INTO events (ID, eventName, disabled) VALUES (".$this->cnt.", '".str_replace("'", "\\'", $event)."', 0);");
|
||||
$this->events[$event][$this->cnt] = array($func, $in);
|
||||
console("[INTERNAL] Attached to event ".$event, true, true, 3);
|
||||
return $this->cnt;
|
||||
}
|
||||
|
||||
public function deleteEvent($event, $id = -1){
|
||||
$id = (int) $id;
|
||||
if($id === -1){
|
||||
unset($this->events[$event]);
|
||||
$this->query("DELETE FROM events WHERE eventName = '".str_replace("'", "\\'", $event)."';");
|
||||
}else{
|
||||
unset($this->events[$event][$id]);
|
||||
$this->query("DELETE FROM events WHERE ID = ".$id.";");
|
||||
if(isset($this->events[$event]) and count($this->events[$event]) === 0){
|
||||
unset($this->events[$event]);
|
||||
$this->query("DELETE FROM events WHERE eventName = '".str_replace("'", "\\'", $event)."';");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,13 +28,15 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
class Session{
|
||||
protected $server, $serverID, $timeout, $connected, $evid;
|
||||
var $clientID, $ip, $port, $counter, $username, $EID;
|
||||
function __construct($server, $clientID, $EID, $ip, $port){
|
||||
var $clientID, $ip, $port, $counter, $username, $eid, $data;
|
||||
function __construct($server, $clientID, $eid, $ip, $port){
|
||||
$this->server = $server;
|
||||
$this->clientID = $clientID;
|
||||
$this->CID = $this->server->clientID($ip, $port);
|
||||
$this->EID = $EID;
|
||||
$this->eid = $eid;
|
||||
$this->data = array();
|
||||
$this->ip = $ip;
|
||||
$this->entity = false;
|
||||
$this->port = $port;
|
||||
$this->serverID =& $this->server->serverID;
|
||||
$this->timeout = microtime(true) + 25;
|
||||
@ -52,6 +54,21 @@ class Session{
|
||||
}
|
||||
}
|
||||
|
||||
function __destruct(){
|
||||
//$this->close("destruct");
|
||||
}
|
||||
|
||||
public function save(){
|
||||
if(is_object($this->entity)){
|
||||
$this->data["spawn"] = array(
|
||||
"x" => $this->entity->position["x"],
|
||||
"y" => $this->entity->position["y"],
|
||||
"z" => $this->entity->position["z"],
|
||||
);
|
||||
}
|
||||
file_put_contents(FILE_PATH."data/players/".str_replace("/", "", $this->username).".dat", serialize($this->data));
|
||||
}
|
||||
|
||||
public function close($reason = "server stop", $msg = true){
|
||||
foreach($this->evid as $ev){
|
||||
$this->server->deleteEvent($ev[0], $ev[1]);
|
||||
@ -60,12 +77,69 @@ class Session{
|
||||
if($msg === true){
|
||||
$this->server->trigger("onChat", $this->username." left the game");
|
||||
}
|
||||
$this->save();
|
||||
if(is_object($this->entity)){
|
||||
$this->entity->__destruct();
|
||||
}
|
||||
console("[INFO] Session with ".$this->ip.":".$this->port." closed due to ".$reason);
|
||||
unset($this->server->entities[$this->eid]);
|
||||
unset($this->server->clients[$this->CID]);
|
||||
}
|
||||
|
||||
public function eventHandler($data, $event){
|
||||
switch($event){
|
||||
case "onHealthChange":
|
||||
if($data["eid"] === $this->eid){
|
||||
$this->send(0x84, array(
|
||||
$this->counter[0],
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_SET_HEALTH,
|
||||
"health" => $data["health"],
|
||||
),
|
||||
));
|
||||
$this->data["health"] = $data["health"];
|
||||
if(is_object($this->entity)){
|
||||
$this->entity->setHealth($data["health"]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "onPlayerAdd":
|
||||
if($data["eid"] === $this->eid){
|
||||
break;
|
||||
}
|
||||
$this->send(0x84, array(
|
||||
$this->counter[0],
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_ADD_PLAYER,
|
||||
"clientID" => $data["clientID"],
|
||||
"username" => $data["username"],
|
||||
"eid" => $data["eid"],
|
||||
"x" => $data["x"],
|
||||
"y" => $data["y"],
|
||||
"z" => $data["z"],
|
||||
"yaw" => $data["yaw"],
|
||||
"pitch" => $data["pitch"],
|
||||
"block" => $data["block"],
|
||||
"meta" => $data["meta"],
|
||||
),
|
||||
));
|
||||
break;
|
||||
case "onEntityRemove":
|
||||
if($data === $this->eid){
|
||||
$this->close("despawn");
|
||||
}else{
|
||||
$this->send(0x84, array(
|
||||
$this->counter[0],
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_ENTITY_REMOVE,
|
||||
"eid" => $data,
|
||||
),
|
||||
));
|
||||
}
|
||||
break;
|
||||
case "onTimeChange":
|
||||
$this->send(0x84, array(
|
||||
$this->counter[0],
|
||||
@ -133,14 +207,39 @@ class Session{
|
||||
|
||||
break;
|
||||
case MC_LOGIN:
|
||||
$this->username = $data["username"];
|
||||
$this->username = str_replace("/", "", $data["username"]);
|
||||
foreach($this->server->clients as $c){
|
||||
if($c->eid !== $this->eid and $c->username === $this->username){
|
||||
$c->close("logged in from another location");
|
||||
}
|
||||
}
|
||||
if($this->server->whitelist !== false and !in_array($this->username, $this->server->whitelist)){
|
||||
$this->close("\"".$this->username."\" not being on white-list", false);
|
||||
break;
|
||||
}
|
||||
console("[INFO] Player \"".$this->username."\" connected from ".$this->ip.":".$this->port);
|
||||
if(!file_exists(FILE_PATH."data/players/".$this->username.".dat")){
|
||||
console("[NOTICE] Player data not found for \"".$this->username."\", creating new");
|
||||
$this->data = array(
|
||||
"spawn" => array(
|
||||
"x" => $this->server->spawn["x"],
|
||||
"y" => $this->server->spawn["y"],
|
||||
"z" => $this->server->spawn["z"],
|
||||
),
|
||||
"health" => 20,
|
||||
"lastIP" => $this->ip,
|
||||
"lastID" => $this->clientID,
|
||||
);
|
||||
}else{
|
||||
$this->data = unserialize(file_get_contents(FILE_PATH."data/players/".str_replace("/", "", $this->username).".dat"));
|
||||
$this->data["lastIP"] = $this->ip;
|
||||
$this->data["lastID"] = $this->clientID;
|
||||
}
|
||||
$this->evid[] = array("onTimeChange", $this->server->event("onTimeChange", array($this, "eventHandler")));
|
||||
$this->evid[] = array("onChat", $this->server->event("onChat", array($this, "eventHandler")));
|
||||
$this->evid[] = array("onPlayerAdd", $this->server->event("onPlayerAdd", array($this, "eventHandler")));
|
||||
$this->evid[] = array("onEntityDespawn", $this->server->event("onEntityDespawn", array($this, "eventHandler")));
|
||||
$this->evid[] = array("onHealthChange", $this->server->event("onHealthChange", array($this, "eventHandler")));
|
||||
$this->send(0x84, array(
|
||||
$this->counter[0],
|
||||
0x00,
|
||||
@ -156,44 +255,47 @@ class Session{
|
||||
array(
|
||||
"id" => MC_START_GAME,
|
||||
"seed" => $this->server->seed,
|
||||
"x" => 128.5,
|
||||
"y" => 100,
|
||||
"z" => 128.5,
|
||||
"x" => $this->data["spawn"]["x"],
|
||||
"y" => $this->data["spawn"]["y"],
|
||||
"z" => $this->data["spawn"]["z"],
|
||||
"unknown1" => 0,
|
||||
"gamemode" => $this->server->gamemode,
|
||||
"eid" => $this->EID,
|
||||
"eid" => $this->eid,
|
||||
),
|
||||
));
|
||||
++$this->counter[0];
|
||||
break;
|
||||
case MC_READY:
|
||||
$this->send(0x84, array(
|
||||
$this->counter[0],
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_SET_TIME,
|
||||
"time" => $this->server->time,
|
||||
),
|
||||
));
|
||||
console("[DEBUG] Player with EID ".$this->EID." \"".$this->username."\" spawned!", true, true, 2);
|
||||
$this->server->trigger("onChat", $this->username." joined the game");
|
||||
$this->server->trigger("onHealthChange", array("eid" => $this->eid, "health" => $this->data["health"]));
|
||||
console("[DEBUG] Player with EID ".$this->eid." \"".$this->username."\" spawned!", true, true, 2);
|
||||
$this->entity = new Entity($this->eid, ENTITY_PLAYER, 0, $this->server);
|
||||
$this->entity->setName($this->username);
|
||||
$this->server->entities[$this->eid] = &$this->entity;
|
||||
/*$this->server->trigger("onPlayerAdd", array(
|
||||
"clientID" => $this->clientID,
|
||||
"username" => $this->username,
|
||||
"eid" => $this->eid,
|
||||
"x" => $this->data["spawn"]["x"],
|
||||
"y" => $this->data["spawn"]["y"],
|
||||
"z" => $this->data["spawn"]["z"],
|
||||
"yaw" => $this->data["spawn"]["yaw"],
|
||||
"pitch" => $this->data["spawn"]["pitch"],
|
||||
"block" => 0,
|
||||
"meta" => 0,
|
||||
));*/
|
||||
$this->eventHandler($this->server->motd, "onChat");
|
||||
$this->server->trigger("onChat", $this->username." joined the game");
|
||||
break;
|
||||
case MC_MOVE_PLAYER:
|
||||
console("[DEBUG] EID ".$this->EID." moved: X ".$data["x"].", Y ".$data["y"].", Z ".$data["z"].", Pitch ".$data["pitch"].", Yaw ".$data["yaw"], true, true, 2);
|
||||
$this->entity->setPosition($data["x"], $data["y"], $data["z"], $data["x"], $data["yaw"], $data["pitch"]);
|
||||
$this->server->trigger("onPlayerMove", $this->eid);
|
||||
break;
|
||||
case MC_PLAYER_EQUIPMENT:
|
||||
$this->send(0x84, array(
|
||||
$this->counter[0],
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_PLAYER_EQUIPMENT,
|
||||
"eid" => 0,
|
||||
"block" => 323,
|
||||
"meta" => 0,
|
||||
),
|
||||
));
|
||||
console("[DEBUG] EID ".$this->EID." has now ".$data["block"]." with metadata ".$data["meta"]." in their hands!", true, true, 2);
|
||||
console("[DEBUG] EID ".$this->eid." has now ".$data["block"]." with metadata ".$data["meta"]." in their hands!", true, true, 2);
|
||||
break;
|
||||
case MC_RESPAWN:
|
||||
$this->server->trigger("onHealthChange", array("eid" => $this->eid, "health" => 20));
|
||||
$this->entity->setPosition($data["x"], $data["y"], $data["z"], $data["x"], 0, 0);
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -38,6 +38,15 @@ console("[DEBUG] Endianness: ".(ENDIANNESS === LITTLE_ENDIAN ? "Little Endian":"
|
||||
|
||||
class Utils{
|
||||
|
||||
/*public static function hashCode($str){
|
||||
$h = 0;
|
||||
$len = strlen($str);
|
||||
for($i = 0; $i < $len; ++$i) {
|
||||
$h = 31 * $h + $str[$i];
|
||||
}
|
||||
return $h;
|
||||
}*/
|
||||
|
||||
public static function getOS(){
|
||||
$uname = strtoupper(php_uname("s"));
|
||||
if(strpos($uname, "WIN") !== false){
|
||||
|
@ -31,7 +31,7 @@ ini_set("display_errors", 1);
|
||||
ini_set('default_charset', 'utf-8');
|
||||
define("FILE_PATH", dirname(__FILE__)."/../");
|
||||
set_include_path(get_include_path() . PATH_SEPARATOR . FILE_PATH . PATH_SEPARATOR . FILE_PATH . "/classes/");
|
||||
ini_set("memory_limit", "512M");
|
||||
ini_set("memory_limit", "1024M");
|
||||
define("CURRENT_PROTOCOL", 5);
|
||||
define("CURRENT_VERSION", 1);
|
||||
define("LOG", true);
|
||||
|
@ -9,6 +9,7 @@ seed=false
|
||||
server-id=false
|
||||
server-type=normal
|
||||
max-players=20
|
||||
time-per-second=10
|
||||
white-list=false
|
||||
debug=1
|
||||
spawn=128.5;100;128.5
|
||||
|
@ -70,6 +70,7 @@ if($errors > 0){
|
||||
require_once("classes/Utils.class.php");
|
||||
require_once("classes/UDPSocket.class.php");
|
||||
require_once("classes/Packet.class.php");
|
||||
require_once("classes/Entity.class.php");
|
||||
require_once("classes/SerializedPacketHandler.class.php");
|
||||
require_once("classes/CustomPacketHandler.class.php");
|
||||
require_once("classes/MinecraftInterface.class.php");
|
||||
|
@ -44,6 +44,8 @@ define("MC_CHAT", 0x85);
|
||||
define("MC_SET_TIME", 0x86);
|
||||
define("MC_START_GAME", 0x87);
|
||||
|
||||
define("MC_ADD_PLAYER", 0x89);
|
||||
|
||||
define("MC_REMOVE_ENTITY", 0x8d);
|
||||
|
||||
define("MC_MOVE_ENTITY_POSROT", 0x93);
|
||||
|
@ -44,6 +44,8 @@ $dataName = array(
|
||||
MC_SET_TIME => "SetTime",
|
||||
MC_START_GAME => "StartGame",
|
||||
|
||||
MC_ADD_PLAYER => "AddPlayer",
|
||||
|
||||
MC_REMOVE_ENTITY => "RemoveEntity",
|
||||
|
||||
MC_MOVE_ENTITY_POSROT => "MoveEntity_PosRot",
|
||||
|
12
server.php
12
server.php
@ -28,7 +28,6 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
require_once("common/dependencies.php");
|
||||
require_once("classes/PocketMinecraftServer.class.php");
|
||||
file_put_contents("packets.log", "");
|
||||
file_put_contents("console.log", "");
|
||||
|
||||
if(!file_exists(FILE_PATH."white-list.txt")){
|
||||
console("[WARNING] No white-list.txt found, creating blank file");
|
||||
@ -43,8 +42,11 @@ if(!file_exists(FILE_PATH."banned-ips.txt")){
|
||||
if(!file_exists(FILE_PATH."server.properties")){
|
||||
console("[WARNING] No server.properties found, using default settings");
|
||||
copy(FILE_PATH."common/default.properties", FILE_PATH."server.properties");
|
||||
|
||||
}
|
||||
|
||||
@mkdir(FILE_PATH."data/entities/", 0777, true);
|
||||
@mkdir(FILE_PATH."data/players/", 0777);
|
||||
|
||||
$prop = file_get_contents(FILE_PATH."server.properties");
|
||||
$prop = explode("\n", str_replace("\r", "", $prop));
|
||||
$config = array();
|
||||
@ -65,11 +67,13 @@ foreach($prop as $line){
|
||||
case "max-players":
|
||||
case "port":
|
||||
case "debug":
|
||||
case "time-per-second":
|
||||
$v = (int) $v;
|
||||
break;
|
||||
case "seed":
|
||||
case "server-id":
|
||||
$v = trim($v) == "false" ? false:preg_replace("/^[0-9\-]/", "", $v);
|
||||
$v = trim($v);
|
||||
$v = $v == "false" ? false:(preg_match("/[^0-9\-]/", $v) > 0 ? Utils::readInt(substr(md5($v, true), 0, 4)):$v);
|
||||
break;
|
||||
case "spawn":
|
||||
$v = explode(";", $v);
|
||||
@ -86,9 +90,11 @@ define("DEBUG", $config["debug"]);
|
||||
|
||||
$server = new PocketMinecraftServer($config["server-name"], $config["gamemode"], $config["seed"], $config["protocol"], $config["port"], $config["server-id"]);
|
||||
$server->setType($config["type"]);
|
||||
$server->timePerSecond = $config["time-per-second"];
|
||||
$server->maxClients = $config["max-players"];
|
||||
$server->description = $config["description"];
|
||||
$server->motd = $config["motd"];
|
||||
$server->spawn = $config["spawn"];
|
||||
$server->whitelist = $config["white-list"];
|
||||
$server->reloadConfig();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user