Merge pull request #1 from VictorWesterlund/feature/backend
Merge "feature/backend"
Before Width: | Height: | Size: 713 B |
36
backend/classes/Crafatar.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
// Get Crafatar from API
|
||||
class Crafatar {
|
||||
|
||||
public function __construct($username,$scale) {
|
||||
$this->uuid = $this->getPlayerUUID($username);
|
||||
$this->url = "https://crafatar.com/renders/body/{$this->uuid}?scale={$scale}";
|
||||
|
||||
$this->data = $this->curl();
|
||||
$this->image = imagecreatefromstring($this->data);
|
||||
$this->size = [imagesx($this->image),imagesy($this->image)];
|
||||
}
|
||||
|
||||
// Get player UUID from username
|
||||
private function getPlayerUUID($username) {
|
||||
$url = "https://playerdb.co/api/player/minecraft/";
|
||||
|
||||
$api = json_decode(file_get_contents($url.$username));
|
||||
return $api->data->player->id;
|
||||
}
|
||||
|
||||
private function curl() {
|
||||
$curl = curl_init();
|
||||
|
||||
curl_setopt($curl, CURLOPT_URL, $this->url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // good edit, thanks!
|
||||
curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1); // also, this seems wise considering output is image.
|
||||
|
||||
$data = curl_exec($curl);
|
||||
curl_close($curl);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
27
backend/classes/Minotar.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
// Get Minotar from API
|
||||
class Minotar {
|
||||
|
||||
public function __construct($username,$size) {
|
||||
$this->url = "https://minotar.net/armor/bust/{$username}/{$size}.png";
|
||||
|
||||
$this->data = $this->curl();
|
||||
$this->image = imagecreatefromstring($this->data);
|
||||
$this->size = [imagesx($this->image),imagesy($this->image)];
|
||||
}
|
||||
|
||||
private function curl() {
|
||||
$curl = curl_init();
|
||||
|
||||
curl_setopt($curl, CURLOPT_URL, $this->url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // good edit, thanks!
|
||||
curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1); // also, this seems wise considering output is image.
|
||||
|
||||
$data = curl_exec($curl);
|
||||
curl_close($curl);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
44
backend/classes/TextLayer.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
// Add horizontally centered text at x,y
|
||||
class TextLayer {
|
||||
|
||||
public function __construct($text,$font,$size) {
|
||||
$this->text = $text;
|
||||
$this->font = $font;
|
||||
|
||||
$this->size = $this->scaleFont($text,$size);
|
||||
$this->setFontPath();
|
||||
}
|
||||
|
||||
// Prevent default GD font lookup path from being used
|
||||
private function setFontPath() {
|
||||
putenv("GDFONTPATH=".realpath("./".$this->font));
|
||||
}
|
||||
|
||||
// Calculate scaled front size from max-width
|
||||
private function scaleFont($text,$baseline) {
|
||||
$len = strlen($this->text);
|
||||
|
||||
$log = $len / 0.6;
|
||||
$size = $baseline - $log;
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
// Center text
|
||||
private function offsetX($x) {
|
||||
$len = strlen($this->text);
|
||||
|
||||
$offset = $x - ($len * ($this->size / 2.2));
|
||||
|
||||
return $offset;
|
||||
}
|
||||
|
||||
// Image resource, x, y
|
||||
public function textcopy($image,$x,$y,$color) {
|
||||
imagettftext($image,$this->size,0,$this->offsetX($x),$y,$color,"font",$this->text);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
BIN
backend/servers/us.mineplex.com/bg.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
backend/servers/us.mineplex.com/font.ttf
Normal file
BIN
backend/servers/us.mineplex.com/tags/admin.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
backend/servers/us.mineplex.com/tags/eternal.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
backend/servers/us.mineplex.com/tags/hero.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
backend/servers/us.mineplex.com/tags/immortal.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
backend/servers/us.mineplex.com/tags/leader.png
Normal file
After Width: | Height: | Size: 7 KiB |
BIN
backend/servers/us.mineplex.com/tags/legend.png
Normal file
After Width: | Height: | Size: 7 KiB |
BIN
backend/servers/us.mineplex.com/tags/mod.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
backend/servers/us.mineplex.com/tags/owner.png
Normal file
After Width: | Height: | Size: 7 KiB |
BIN
backend/servers/us.mineplex.com/tags/srmod.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
backend/servers/us.mineplex.com/tags/titan.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
backend/servers/us.mineplex.com/tags/trainee.png
Normal file
After Width: | Height: | Size: 8 KiB |
BIN
backend/servers/us.mineplex.com/tags/ultra.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 7 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 6.9 KiB |
69
backend/texture.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
require "classes/Minotar.php"; // Player avatar
|
||||
require "classes/TextLayer.php";
|
||||
|
||||
// Main class
|
||||
class Texture {
|
||||
|
||||
public function __construct() {
|
||||
$this->input = [
|
||||
"server" => $_GET["server"],
|
||||
"username" => $_GET["username"],
|
||||
"tag" => $_GET["tag"].".png"
|
||||
];
|
||||
|
||||
$this->path = "servers/{$this->input["server"]}/";
|
||||
|
||||
$this->validate();
|
||||
}
|
||||
|
||||
// Make sure all required urlparams are set
|
||||
private function validate() {
|
||||
foreach($this->input as $key => $value) {
|
||||
if(!$value) {
|
||||
$error[] = "Missing urlparam: '{$key}'.";
|
||||
}
|
||||
}
|
||||
|
||||
if($error) {
|
||||
http_response_code("400 Bad Request");
|
||||
echo implode(" ",$error);
|
||||
die();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a new texture
|
||||
function create($x,$y) {
|
||||
// Layers
|
||||
$bg = imagecreatefrompng($this->path."bg.png");
|
||||
$player = new Minotar($this->input["username"],100);
|
||||
$name = new TextLayer($this->input["username"],$this->path,30);
|
||||
$tag = imagecreatefrompng($this->path."tags/".$this->input["tag"]);
|
||||
|
||||
// Create texture
|
||||
$image = imagecreatetruecolor($x,$y);
|
||||
$alpha = imagecolorallocatealpha($image,0,0,0,127);
|
||||
$color = imagecolorallocate($image,255,255,255);
|
||||
|
||||
// Preserve transparency
|
||||
imagefill($image,0,0,$alpha);
|
||||
imagesavealpha($image,true);
|
||||
|
||||
// Blend layers
|
||||
imagecopy($image,$bg,0,0,0,0,$x,$y); // Background
|
||||
imagecopy($image,$player->image,45,60,0,0,$player->size[0],$player->size[1]); // Player avatar
|
||||
$name->textcopy($image,110,210,$color); // Player name
|
||||
imagecopy($image,$tag,0,0,0,0,$x,$y); // Player rank
|
||||
|
||||
// Output image
|
||||
header("Content-Type: image/png");
|
||||
echo imagepng($image);;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$texture = new Texture();
|
||||
$texture->create(355,275);
|
15
start.py
|
@ -13,7 +13,7 @@ import requests
|
|||
class Chattycape(Thread):
|
||||
|
||||
pollRate = 1 # Logfile pollrate
|
||||
updateRate = 1 # Update rate of Labylib cosmetic
|
||||
updateRate = 15 # Update rate of Labylib cosmetic
|
||||
|
||||
def __init__(self,event,phpsessid,endpoint,logfile,me = "None"):
|
||||
Thread.__init__(self)
|
||||
|
@ -23,7 +23,7 @@ class Chattycape(Thread):
|
|||
self.server = None # Connected to server (hostname)
|
||||
self.config = None # Chat config for current server
|
||||
|
||||
self.line = "[21:42:25] [main/INFO]: [CHAT] 725 IMMORTAL VicW test"
|
||||
self.line = ""
|
||||
self.i = 0
|
||||
|
||||
# Read last line from logfile
|
||||
|
@ -52,7 +52,7 @@ class Chattycape(Thread):
|
|||
continue
|
||||
|
||||
if substr in tagList:
|
||||
tag = substr
|
||||
tag = substr.lower()
|
||||
continue
|
||||
|
||||
# Not ignored, and not a tag, so assume we've reached the username
|
||||
|
@ -65,7 +65,7 @@ class Chattycape(Thread):
|
|||
def update(self):
|
||||
args = self.getUser() # Get minecraft username and tag
|
||||
|
||||
urlparams = f"?server={self.server}&ign={args[0]}&rank={args[1]}"
|
||||
urlparams = f"?server={self.server}&username={args[0]}&tag={args[1]}"
|
||||
|
||||
# Save cape texture from endpoint to disk
|
||||
with open(".cache.png","wb") as handle:
|
||||
|
@ -80,7 +80,8 @@ class Chattycape(Thread):
|
|||
|
||||
handle.write(block)
|
||||
|
||||
# TODO: Labylib here
|
||||
cape = Cape.Texture(self.params[0],".cache.png")
|
||||
cape.update()
|
||||
|
||||
# ----------------------------
|
||||
|
||||
|
@ -118,7 +119,7 @@ class Main:
|
|||
print("-- Labylib Chattycape --")
|
||||
self.logfile = self.locate()
|
||||
|
||||
self.endpoint = self.prompt("Cape render endpoint","http://192.168.86.21/victor-westerlund/labylib-chattycape/back-end/render.php")
|
||||
self.endpoint = self.prompt("Cape render endpoint","https://api.victorwesterlund.com/chattycape")
|
||||
self.me = self.prompt("My Minecraft in-game name (Case Sensitive)","Don't exclude me")
|
||||
self.phpsessid = self.prompt("PHPSESSID cookie")
|
||||
|
||||
|
@ -168,7 +169,7 @@ class Main:
|
|||
|
||||
# Failed to locate Minecraft-installation automatically
|
||||
|
||||
path = self.prompt("Path to your '.minecraft'-folder","/mnt/c/Users/victo/AppData/Roaming/.minecraft")
|
||||
path = self.prompt("Path to your '.minecraft'-folder")
|
||||
|
||||
if(Path(path).exists()):
|
||||
return path + mclog
|
||||
|
|