Skip to content
This repository has been archived by the owner on Nov 9, 2021. It is now read-only.

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
skh6075 authored Dec 9, 2020
1 parent c87a650 commit 5a3d108
Show file tree
Hide file tree
Showing 7 changed files with 361 additions and 0 deletions.
6 changes: 6 additions & 0 deletions plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: S3DItemToolS
main: skh6075\s3ditemtools\S3DItemToolS
author: AvasKr
version: 1.0.0
api: 3.10.0
website: https://github.com/GodVas
42 changes: 42 additions & 0 deletions src/skh6075/s3ditemtools/S3DItemToolS.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace skh6075\s3ditemtools;

use pocketmine\plugin\PluginBase;
use skh6075\s3ditemtools\skin\SkinFactory;
use function is_dir;
use function mkdir;
use const DIRECTORY_SEPARATOR;

class S3DItemToolS extends PluginBase{

/** @var ?S3DItemToolS */
private static $instance = null;
/** @var string[] */
protected $directories = [
"models",
"images",
"skins"
];


public static function getInstance(): ?S3DItemToolS{
return self::$instance;
}

public function onLoad(): void{
if (self::$instance === null) {
self::$instance = $this;
}
}

public function onEnable(): void{
foreach ($this->directories as $directory) {
if (is_dir($this->getDataFolder() . $directory . DIRECTORY_SEPARATOR)) {
continue;
}
mkdir($this->getDataFolder() . $directory . DIRECTORY_SEPARATOR);
}
SkinFactory::getInstance()->init();
}
}
45 changes: 45 additions & 0 deletions src/skh6075/s3ditemtools/listener/EventListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace skh6075\s3ditemtools\listener;

use pocketmine\event\Listener;
use pocketmine\event\player\PlayerItemHeldEvent;
use pocketmine\event\player\PlayerJoinEvent;
use pocketmine\event\player\PlayerQuitEvent;
use skh6075\s3ditemtools\skin\PlayerSkin;
use skh6075\s3ditemtools\skin\SkinFactory;
use skh6075\s3ditemtools\skin\SkinReflection;

class EventListener implements Listener{

/**
* @param PlayerJoinEvent $event
* @priority HIGHEST
*/
public function onPlayerJoin(PlayerJoinEvent $event): void{
$player = $event->getPlayer();
PlayerSkin::getInstance()->makeSkinImage($player);
PlayerSkin::getInstance()->setPlayerSkin($player);
}

/**
* @param PlayerQuitEvent $event
* @priority HIGHEST
*/
public function onPlayerQuit(PlayerQuitEvent $event): void{
PlayerSkin::getInstance()->deleteSkinImage($event->getPlayer());
}

public function onPlayerItemdHeld(PlayerItemHeldEvent $event): void{
$player = $event->getPlayer();
$item = $event->getItem();

if (!is_null($item->getNamedTagEntry("3d_model"))) {
if (($reflection = SkinFactory::getInstance()->getSkinReflection($item->getNamedTagEntry("3d_model")->getValue())) instanceof SkinReflection) {
$reflection->sendSkinImage($player);
} else {
PlayerSkin::getInstance()->callbackSkin($player);
}
}
}
}
171 changes: 171 additions & 0 deletions src/skh6075/s3ditemtools/skin/PlayerSkin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?php

namespace skh6075\s3ditemtools\skin;

use pocketmine\entity\Skin;
use pocketmine\Player;
use pocketmine\Server;
use skh6075\s3ditemtools\S3DItemToolS;
use function file_exists;
use function file_get_contents;
use function unlink;
use function intdiv;
use function ord;
use function chr;
use function imagecreatetruecolor;
use function imagefill;
use function imagecolorallocatealpha;
use function imagesetpixel;
use function imagesavealpha;
use function imagecreatefrompng;
use function imagecopymerge;
use function imagedestroy;
use function getimagesize;

final class PlayerSkin{

/** @var ?PlayerSkin */
private static $instance = null;
/** @var S3DItemToolS */
protected $plugin;
/** @var Skin[] */
private static $skins = [];


public static function getInstance(): ?PlayerSkin{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}

public function __construct() {
$this->plugin = S3DItemToolS::getInstance();
}

public function getPlayerSkin(Player $player): ?Skin{
return self::$skins[$player->getLowerCaseName()] ?? null;
}

public function setPlayerSkin(Player $player): void{
self::$skins[$player->getLowerCaseName()] = $player->getSkin();
}

/**
* @param Player $player
*/
public function makeSkinImage(Player $player): void{
$skinPath = $this->plugin->getDataFolder() . "skins" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png";
$image = $this->convertSkinImage($player->getSkin()->getSkinData());
$background = imagecolorallocate($image, 255, 255, 255);
imagecolortransparent($image, $background);
imagepng($image, $skinPath);
imagedestroy($image);
}

/**
* @param string $skinData
* @return false|resource
*/
private function convertSkinImage(string $skinData) {
$size = strlen($skinData);
$width = SkinMap::SKIN_WIDTH_SIZE[$size];
$height = SkinMap::SKIN_HEIGHT_SIZE[$size];
$pos = 0;
$image = imagecreatetruecolor($width, $height);

imagefill($image, 0, 0, imagecolorallocatealpha($image, 0, 0, 0, 127));
for ($y = 0; $y < $height; $y ++) {
for ($x = 0; $x < $width; $x ++) {
$r = ord($skinData[$pos]);
$pos ++;
$g = ord($skinData[$pos]);
$pos ++;
$b = ord($skinData[$pos]);
$pos ++;
$a = 127 - intdiv(ord($skinData[$pos]), 2);
$pos ++;
$color = imagecolorallocatealpha($image, $r, $g, $b, $a);
imagesetpixel($image, $x, $y, $color);
}
}
imagesavealpha($image, true);
return $image;
}

/**
* @param Player $player
* @param string $resource
*/
public function convertImagemerge(Player $player, string $resource): void{
$playerImage = imagecreatefrompng($this->plugin->getDataFolder() . "skins" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png");
$modelImage = imagecreatefrompng($this->plugin->getDataFolder() . "images" . DIRECTORY_SEPARATOR . $resource . ".png");
[$width, $height] = getimagesize($this->plugin->getDataFolder() . "skins" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png");
imagecopymerge($playerImage, $modelImage, 56, 16, 0, 0, $width, $height, 100);
imagesavealpha($playerImage, true);
imagepng($playerImage, $this->plugin->getDataFolder() . "images" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png");

imagedestroy($playerImage);
imagedestroy($modelImage);
}

/**
* @param Player $player
* @param string $resource
*/
public function sendImageSkin(Player $player, string $resource): void{
$path = $this->plugin->getDataFolder() . "images" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png";
$image = imagecreatefrompng($path);
$skinBytes = "";
$size = (int) getimagesize($path) [1];

for ($y = 0; $y < $size; $y ++) {
for ($x = 0; $x < 64; $x ++) {
$colorat = imagecolorat($image, $x, $y);
$a = ((~((int) ($colorat >> 24))) << 1) & 0xff;
$r = ($colorat >> 16) & 0xff;
$g = ($colorat >> 8) & 0xff;
$b = $colorat & 0xff;
$skinBytes .= chr($r) . chr($g) . chr($b) . chr($a);
}
}
imagedestroy($image);
$skin = new Skin($player->getSkin()->getSkinId(), $skinBytes, "", "geometry." . $resource, file_get_contents($this->plugin->getDataFolder() . "models" . DIRECTORY_SEPARATOR . $resource . ".json"));
$this->broadcastChangeSkin($player, $skin);
}

/**
* @param Player $player
* @param Skin $skin
*/
public function broadcastChangeSkin(Player $player, Skin $skin): void{
$player->setSkin($skin);
foreach (Server::getInstance()->getOnlinePlayers() as $players) {
$player->sendSkin([$players, $player]);
}
}

/**
* @param Player $player
*/
public function deleteSkinImage(Player $player): void{
if (file_exists($this->plugin->getDataFolder() . "skins" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png")) {
unlink($this->plugin->getDataFolder() . "skins" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png");
}
if (file_exists($this->plugin->getDataFolder() . "images" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png")) {
unlink($this->plugin->getDataFolder() . "images" . DIRECTORY_SEPARATOR . $player->getLowerCaseName() . ".png");
}
if (isset(self::$skins[$player->getLowerCaseName()])) {
unset(self::$skins[$player->getLowerCaseName()]);
}
}

/**
* @param Player $player
*/
public function callbackSkin(Player $player): void{
if (($skin = $this->getPlayerSkin($player)) instanceof Skin) {
$this->broadcastChangeSkin($player, $skin);
}
}
}
49 changes: 49 additions & 0 deletions src/skh6075/s3ditemtools/skin/SkinFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace skh6075\s3ditemtools\skin;

use skh6075\s3ditemtools\S3DItemToolS;
use function array_diff;
use function explode;
use function file_exists;
use const DIRECTORY_SEPARATOR;

final class SkinFactory{

/** @var ?SkinFactory */
private static $instance = null;
/** @var S3DItemToolS */
protected $plugin;
/** @var SkinReflection[] */
private static $reflections = [];


public static function getInstance(): ?SkinFactory{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}

public function __construct() {
$this->plugin = S3DItemToolS::getInstance();
}

public function init(): void{
foreach (array_diff(scandir($this->plugin->getDataFolder() . "models" . DIRECTORY_SEPARATOR), ['.', '..']) as $value) {
if (!isset(explode(".", $value)[0]) || explode(".", $value)[1] !== "json" || !file_exists($this->plugin->getDataFolder() . "images" . DIRECTORY_SEPARATOR . $value . ".png")) {
continue;
}
self::$reflections[explode(".", $value) [0]] = new SkinReflection(explode(".", $value) [1]);
}
}

/**
* @param string $name
*
* @return ?SkinReflection
*/
public function getSkinReflection(string $name): ?SkinReflection{
return self::$reflections[$name] ?? null;
}
}
20 changes: 20 additions & 0 deletions src/skh6075/s3ditemtools/skin/SkinMap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace skh6075\s3ditemtools\skin;

final class SkinMap{

/** @var int[] */
public const SKIN_WIDTH_SIZE = [
64 * 32 * 4 => 64,
64 * 64 * 4 => 64,
128 * 128 * 4 => 128
];

/** @var int[] */
public const SKIN_HEIGHT_SIZE = [
64 * 32 * 4 => 32,
64 * 64 * 4 => 64,
128 * 128 * 4 => 128
];
}
28 changes: 28 additions & 0 deletions src/skh6075/s3ditemtools/skin/SkinReflection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace skh6075\s3ditemtools\skin;

use pocketmine\Player;

class SkinReflection{

/** @var string */
protected $name;


public function __construct(string $name) {
$this->name = $name;
}

public function getName(): string{
return $this->name;
}

/**
* @param Player $player
*/
public function sendSkinImage(Player $player): void{
PlayerSkin::getInstance()->convertImagemerge($player, $this->name);
PlayerSkin::getInstance()->sendImageSkin($player, $this->name);
}
}

0 comments on commit 5a3d108

Please sign in to comment.