mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-05 03:43:40 +00:00
926 lines
29 KiB
C++
926 lines
29 KiB
C++
#include <MC/Minecraft.hpp>
|
|
|
|
#include <MC/Actor.hpp>
|
|
#include <MC/Mob.hpp>
|
|
#include <MC/Player.hpp>
|
|
#include <MC/ServerPlayer.hpp>
|
|
|
|
#include <MC/Certificate.hpp>
|
|
#include <MC/CompoundTag.hpp>
|
|
|
|
#include <MC/NetworkHandler.hpp>
|
|
#include <MC/ServerNetworkHandler.hpp>
|
|
#include <MC/NetworkIdentifier.hpp>
|
|
#include <MC/NetworkPeer.hpp>
|
|
//#include <MC/ToastRequestPacket.hpp>
|
|
|
|
#include <MC/ExtendedCertificate.hpp>
|
|
#include <MC/ConnectionRequest.hpp>
|
|
#include <MC/MinecraftPackets.hpp>
|
|
#include <MC/CommandRequestPacket.hpp>
|
|
#include <MC/TextPacket.hpp>
|
|
#include <MC/ScorePacketInfo.hpp>
|
|
#include <MC/BinaryStream.hpp>
|
|
#include <MC/TransferPacket.hpp>
|
|
|
|
#include <MC/Level.hpp>
|
|
#include <MC/ItemStack.hpp>
|
|
#include <MC/Container.hpp>
|
|
#include <MC/SimpleContainer.hpp>
|
|
#include <MC/Scoreboard.hpp>
|
|
#include <MC/ScoreboardId.hpp>
|
|
#include <MC/PlaySoundPacket.hpp>
|
|
#include <MC/SetDisplayObjectivePacket.hpp>
|
|
#include <MC/Block.hpp>
|
|
#include <MC/AttributeInstance.hpp>
|
|
|
|
#include <Impl/ObjectivePacketHelper.h>
|
|
#include <Impl/FormPacketHelper.h>
|
|
#include <EventAPI.h>
|
|
#include <bitset>
|
|
//#include <MC/ItemStackDescriptor.hpp>
|
|
//#include <MC/NetworkItemStackDescriptor.hpp>
|
|
//#include <MC/ToastRequestPacket.hpp>
|
|
|
|
extern Logger logger;
|
|
|
|
NetworkIdentifier* Player::getNetworkIdentifier() const{
|
|
//ServerPlayer::isHostingPlayer
|
|
return dAccess<NetworkIdentifier*>(this, 2432);
|
|
}
|
|
|
|
|
|
Certificate* Player::getCertificate() const{
|
|
//KickCommand::_kickPlayer Line116
|
|
return dAccess<Certificate*>(this, 2736);
|
|
}
|
|
|
|
std::string Player::getRealName() {
|
|
return ExtendedCertificate::getIdentityName(*getCertificate());
|
|
}
|
|
|
|
int Player::getAvgPing() {
|
|
return Global<Minecraft>->getNetworkHandler().getPeerForUser(*getNetworkIdentifier())->getNetworkStatus().mAveragePing;
|
|
}
|
|
|
|
int Player::getLastPing() {
|
|
return Global<Minecraft>->getNetworkHandler().getPeerForUser(*getNetworkIdentifier())->getNetworkStatus().mCurrentPing;
|
|
}
|
|
|
|
string Player::getIP() {
|
|
return getNetworkIdentifier()->getIP();
|
|
}
|
|
|
|
#include <MC/Localization.hpp>
|
|
string Player::getLanguageCode() {
|
|
// auto map = Global<ServerNetworkHandler>->fetchConnectionRequest(*getNetworkIdentifier()).mRawToken.get()->mDataInfo.value_.map_;
|
|
// for (auto& iter : *map) {
|
|
// string s(iter.first.c_str());
|
|
// if (s.find("LanguageCode") != std::string::npos) {
|
|
// auto langCode = iter.second.value_.string_;
|
|
// return langCode;
|
|
// }
|
|
// }
|
|
return "unknown";
|
|
}
|
|
|
|
string Player::getServerAddress() {
|
|
// auto map = Global<ServerNetworkHandler>->fetchConnectionRequest(*getNetworkIdentifier()).mRawToken.get()->mDataInfo.value_.map_;
|
|
// for (auto iter = map->begin(); iter != map->end(); ++iter) {
|
|
// string s(iter->first.c_str());
|
|
// if (s.find("ServerAddress") != s.npos) {
|
|
// auto ServerAddress = iter->second.value_.string_;
|
|
// return ServerAddress;
|
|
// }
|
|
// }
|
|
return "unknown";
|
|
}
|
|
|
|
int Player::getPlatform(){
|
|
//AddPlayerPacket::AddPlayerPacket Line59
|
|
return dAccess<int>(this, 256);
|
|
}
|
|
|
|
Container & Player::getInventory(){
|
|
//InventoryContainerModel::_getContainer 2928 + 176
|
|
return dAccess<Container>(this, 3104);
|
|
}
|
|
|
|
enum CommandPermissionLevel Player::getPlayerPermissionLevel(){
|
|
//return dAccess<CommandPermissionLevel&>(this, 2112); can do
|
|
return getCommandPermissionLevel();
|
|
}
|
|
|
|
int Player::getPlayerLevel(){
|
|
auto& attr = getAttribute(Player::LEVEL);
|
|
return attr.getCurrentValue();
|
|
}
|
|
|
|
void Player::sendNetworkPacket(class Packet &pkt) const{
|
|
void (Player::*rv)(class Packet&) const;
|
|
*((void**)&rv) = dlsym("?sendNetworkPacket@ServerPlayer@@UEBAXAEAVPacket@@@Z");
|
|
return (this->*rv)(pkt);
|
|
}
|
|
|
|
string Player::getDeviceTypeName() {
|
|
switch ((int)getPlatform()) {
|
|
case -1:
|
|
return "Unknown";
|
|
case 1:
|
|
return "Android";
|
|
case 2:
|
|
return "iOS";
|
|
case 3:
|
|
return "OSX";
|
|
case 4:
|
|
return "Amazon";
|
|
case 5:
|
|
return "GearVR";
|
|
case 6:
|
|
return "Hololens";
|
|
case 7:
|
|
return "Win10";
|
|
case 8:
|
|
return "WIN32";
|
|
case 9:
|
|
return "Dedicated";
|
|
case 10:
|
|
return "TVOS";
|
|
case 11:
|
|
return "PlayStation";
|
|
case 12:
|
|
return "Nintendo";
|
|
case 13:
|
|
return "Xbox";
|
|
case 14:
|
|
return "WindowsPhone";
|
|
case 15:
|
|
return "Linux";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
bool Player::kick(const std::string& msg) {
|
|
// NetworkIdentifier* pNetworkIdentifier = getNetworkIdentifier();
|
|
// Global<Minecraft>->getServerNetworkHandler()->disconnectClient(*pNetworkIdentifier, 0, msg, 0);
|
|
BinaryStream wp;
|
|
if(msg.empty()){
|
|
wp.writeBool(1);
|
|
}
|
|
else{
|
|
wp.writeBool(0);
|
|
wp.writeString(msg);
|
|
}
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::Disconnect);
|
|
pkt->read(wp);
|
|
this->sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendText(const std::string& text, TextType type) {
|
|
return sendTextPacket(text, type);
|
|
}
|
|
|
|
bool Player::talkAs(const std::string& msg) {
|
|
return sendTextTalkPacket(msg);
|
|
}
|
|
|
|
bool Player::giveItem(ItemStack* item) {
|
|
if (!this->add(*item))
|
|
return false;
|
|
refreshInventory();
|
|
return true;
|
|
}
|
|
|
|
int Player::clearItem(string typeName) {
|
|
int res = 0;
|
|
|
|
// Hand
|
|
ItemStack* item = getHandSlot();
|
|
if (item->getTypeName() == typeName) {
|
|
auto out = item->getCount();
|
|
item->setNull();
|
|
res += out;
|
|
}
|
|
|
|
// OffHand
|
|
item = (ItemStack*)&getOffhandSlot();
|
|
if (item->getTypeName() == typeName) {
|
|
auto out = item->getCount();
|
|
item->setNull();
|
|
res += out;
|
|
}
|
|
|
|
// Inventory
|
|
Container* container = &getInventory();
|
|
auto items = container->getAllSlots();
|
|
int size = container->getSize();
|
|
for (int i = 0; i < size; ++i) {
|
|
if (items[i]->getTypeName() == typeName) {
|
|
int cnt = items[i]->getCount();
|
|
container->removeItem(i, cnt);
|
|
res += cnt;
|
|
}
|
|
}
|
|
|
|
// Armor
|
|
auto& armor = getArmorContainer();
|
|
items = armor.getAllSlots();
|
|
size = armor.getSize();
|
|
for (int i = 0; i < size; ++i) {
|
|
if (items[i]->getTypeName() == typeName) {
|
|
int cnt = items[i]->getCount();
|
|
armor.removeItem(i, cnt);
|
|
res += cnt;
|
|
}
|
|
}
|
|
refreshInventory();
|
|
return res;
|
|
}
|
|
|
|
string Player::getName() {
|
|
return getNameTag();
|
|
}
|
|
|
|
bool Player::runcmd(const string& cmd) {
|
|
return sendCommandRequestPacket(cmd);
|
|
}
|
|
|
|
// Container* Player::getEnderChestContainer() {
|
|
// return dAccess<Container*>(this, 4032); // IDA Player::Player() Line239
|
|
// }
|
|
|
|
bool Player::transferServer(const string& address, unsigned short port) {
|
|
return sendTransferPacket(address, port);
|
|
}
|
|
|
|
BlockPos const & Player::getSpawnPosition(){
|
|
//ServerNetworkHandler::_sendLevelData Line316
|
|
return dAccess<BlockPos>(this, 1797);
|
|
}
|
|
|
|
AutomaticID<Dimension, int> Player::getSpawnDimension(){
|
|
//ServerNetworkHandler::_sendLevelData Line310
|
|
return dAccess<AutomaticID<Dimension, int>>(this, 1800);
|
|
}
|
|
|
|
std::pair<BlockPos, int> Player::getRespawnPosition() {
|
|
BlockPos bp = getSpawnPosition();
|
|
int dimId = getSpawnDimension();
|
|
if (dimId == 3) // has no bed.
|
|
{
|
|
bp = getExpectedSpawnPosition();
|
|
dimId = getExpectedSpawnDimensionId();
|
|
}
|
|
|
|
return {bp, dimId};
|
|
}
|
|
|
|
std::unique_ptr<CompoundTag> Player::getNbt() {
|
|
return CompoundTag::fromPlayer(this);
|
|
}
|
|
|
|
bool Player::setNbt(CompoundTag* nbt) {
|
|
nbt->setPlayer(this);
|
|
return true;
|
|
}
|
|
#include <MC/Attribute.hpp>
|
|
#include <MC/AttributeInstance.hpp>
|
|
#include <MC/HashedString.hpp>
|
|
#include <SendPacketAPI.h>
|
|
bool Player::refreshAttribute(class Attribute const& attribute) {
|
|
return refreshAttributes({&attribute});
|
|
}
|
|
bool Player::refreshAttributes(std::vector<Attribute const*> const& attributes) {
|
|
BinaryStream wp;
|
|
wp.writeUnsignedVarInt64(getRuntimeID()); // EntityId
|
|
wp.writeUnsignedVarInt((unsigned)attributes.size());
|
|
for (auto attribute : attributes) {
|
|
auto& instance = getAttribute(*attribute);
|
|
wp.writeFloat(instance.getMinValue());
|
|
wp.writeFloat(instance.getMaxValue());
|
|
wp.writeFloat(instance.getCurrentValue());
|
|
wp.writeFloat(instance.getDefaultValue(2));
|
|
wp.writeString((*attribute).getName().getString());
|
|
}
|
|
wp.writeUnsignedVarInt64(0);
|
|
auto pkt = MinecraftPackets::createPacket(0x1D);
|
|
pkt->read(wp);
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
string Player::getUuid() const{
|
|
auto result = ExtendedCertificate::getIdentity(*getCertificate());
|
|
return result.asString();
|
|
}
|
|
|
|
string Player::getXuid() const{
|
|
return ExtendedCertificate::getXuid(*getCertificate());
|
|
}
|
|
|
|
mce::UUID Player::getClientUUID()const{
|
|
return dAccess<mce::UUID>(this,2720);
|
|
};
|
|
|
|
unsigned char Player::getClientSubId() {
|
|
//ServerPlayer::sendNetworkPacket 参4
|
|
return dAccess<unsigned char>(this,3520);
|
|
}
|
|
|
|
float Player::getAvgPacketLoss() {
|
|
return Global<Minecraft>->getNetworkHandler().getPeerForUser(*getNetworkIdentifier())->getNetworkStatus().mAveragePacketLoss;
|
|
}
|
|
|
|
float Player::getLastPacketLoss() {
|
|
return Global<Minecraft>->getNetworkHandler().getPeerForUser(*getNetworkIdentifier())->getNetworkStatus().mCurrentPacketLoss;
|
|
}
|
|
|
|
string Player::getClientId() {
|
|
return *getDeviceId();
|
|
}
|
|
|
|
int Player::getDeviceType() {
|
|
return getPlatform();
|
|
}
|
|
|
|
bool Player::isOperator() {
|
|
return (int)getPlayerPermissionLevel() >= 2;
|
|
}
|
|
|
|
bool Player::isOP() {
|
|
return isOperator();
|
|
}
|
|
|
|
int Player::getCurrentExperience() {
|
|
auto& attr = getAttribute(Player::EXPERIENCE);
|
|
float currentExp = getXpNeededForNextLevel() * attr.getCurrentValue();
|
|
return static_cast<int>(currentExp);
|
|
}
|
|
|
|
bool Player::setCurrentExperience(int exp) {
|
|
auto attr = getMutableAttribute(Player::EXPERIENCE);
|
|
if (!attr)
|
|
return false;
|
|
int levelExp = getXpNeededForNextLevel();
|
|
attr->setCurrentValue(static_cast<float>(exp) / levelExp);
|
|
return true;
|
|
}
|
|
|
|
size_t Player::getTotalExperience() {
|
|
int level = getPlayerLevel();
|
|
size_t exp = getTotalXpNeededForLevel(level);
|
|
exp += getCurrentExperience();
|
|
return exp;
|
|
}
|
|
|
|
bool Player::setTotalExperience(size_t exp) {
|
|
resetPlayerLevel();
|
|
if (exp <= INT32_MAX) {
|
|
addExperience(static_cast<int>(exp));
|
|
return true;
|
|
} else {
|
|
addExperience(INT32_MAX);
|
|
size_t newExp = exp - INT32_MAX;
|
|
if (exp <= INT32_MAX) {
|
|
addExperience(static_cast<int>(exp));
|
|
} else {
|
|
// reach max level
|
|
addExperience(INT32_MAX);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Player::reduceExperience(size_t exp) {
|
|
auto attr = getMutableAttribute(Player::EXPERIENCE);
|
|
if (!attr)
|
|
return false;
|
|
int neededExp = getXpNeededForNextLevel();
|
|
int currExp = static_cast<int>(attr->getCurrentValue() * neededExp);
|
|
if (exp <= currExp) {
|
|
attr->setCurrentValue(static_cast<float>(currExp - exp) / neededExp);
|
|
return true;
|
|
}
|
|
attr->setCurrentValue(0);
|
|
size_t needExp = exp - currExp;
|
|
int level = getPlayerLevel();
|
|
while (level > 0) {
|
|
addLevels(-1);
|
|
int levelXp = getXpNeededForNextLevel();
|
|
if (needExp < levelXp) {
|
|
attr->setCurrentValue(static_cast<float>(levelXp - needExp) / getXpNeededForNextLevel());
|
|
return true;
|
|
}
|
|
needExp -= levelXp;
|
|
level = getPlayerLevel();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int Player::getXpNeededForLevel(int nextLevel) {
|
|
int const level = nextLevel - 1;
|
|
if (level / 15) {
|
|
if (level / 15 == 1)
|
|
return 5 * level - 38;
|
|
else
|
|
return 9 * level - 158;
|
|
} else {
|
|
return 2 * level + 7;
|
|
}
|
|
}
|
|
|
|
size_t Player::getTotalXpNeededForLevel(int level) {
|
|
size_t result = 0;
|
|
for (int i = 1; i <= level; ++i) {
|
|
result += getXpNeededForLevel(i);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool Player::crashClient() {
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::LevelChunk);
|
|
dAccess<bool, 56>(pkt.get()) = 1;
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::setSidebar(const std::string& title, const std::vector<std::pair<std::string, int>>& data, ObjectiveSortOrder sortOrder) {
|
|
sendSetDisplayObjectivePacket(title, "FakeScoreObj", (char)sortOrder);
|
|
|
|
vector<ScorePacketInfo> info;
|
|
for (auto& x : data) {
|
|
const ScoreboardId& id = ScoreboardId(NewScoreId());
|
|
ScorePacketInfo i((ScoreboardId*)&id, "FakeScoreObj", IdentityDefinition::Type::Fake, x.second, x.first);
|
|
info.emplace_back(i);
|
|
}
|
|
sendSetScorePacket(0, info);
|
|
return sendSetDisplayObjectivePacket(title, "FakeScoreObj", (char)sortOrder);
|
|
}
|
|
|
|
bool Player::removeSidebar() {
|
|
return sendSetDisplayObjectivePacket("", "", (char)0);
|
|
}
|
|
|
|
int Player::getScore(const string& key) {
|
|
return Scoreboard::getScore(this, key);
|
|
}
|
|
|
|
bool Player::setScore(const string& key, int value) {
|
|
return Scoreboard::setScore(this, key, value);
|
|
}
|
|
|
|
bool Player::addScore(const string& key, int value) {
|
|
return Scoreboard::addScore(this, key, value);
|
|
}
|
|
|
|
bool Player::reduceScore(const string& key, int value) {
|
|
return Scoreboard::reduceScore(this, key, value);
|
|
}
|
|
|
|
bool Player::deleteScore(const string& key) {
|
|
return Scoreboard::deleteScore(this, key);
|
|
}
|
|
|
|
void Player::addBossEvent(int64_t uid, string name, float percent, BossEventColour colour, int overlay) {
|
|
BinaryStream wp;
|
|
wp.writeVarInt64(uid);
|
|
wp.writeUnsignedVarInt((int)0);
|
|
wp.writeString(name);
|
|
wp.writeFloat(percent);
|
|
wp.writeUnsignedShort(1);
|
|
wp.writeUnsignedVarInt((int)colour);
|
|
wp.writeUnsignedVarInt(overlay);
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::BossEvent);
|
|
pkt->read(wp);
|
|
sendAddEntityPacket(uid, "player", Vec3(getPos().x, (float)-70, getPos().z), Vec2{0, 0}, 0);
|
|
sendNetworkPacket(*pkt);
|
|
}
|
|
|
|
void Player::removeBossEvent(int64_t uid) {
|
|
BinaryStream wp;
|
|
wp.writeVarInt64(uid);
|
|
wp.writeUnsignedVarInt((int)2);
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::BossEvent);
|
|
pkt->read(wp);
|
|
sendNetworkPacket(*pkt);
|
|
}
|
|
|
|
void Player::updateBossEvent(int64_t uid, string name, float percent, BossEventColour colour, int overlay) {
|
|
removeBossEvent(uid);
|
|
addBossEvent(uid, name, percent, colour, overlay);
|
|
}
|
|
|
|
|
|
////////////////////////// Packet //////////////////////////
|
|
|
|
static_assert(sizeof(TextPacket) == 208);
|
|
static_assert(sizeof(TransferPacket) == 80);
|
|
|
|
bool Player::sendTextPacket(string text, TextType Type) const {
|
|
// BinaryStream wp;
|
|
// wp.reserve(8 + text.size());
|
|
// wp.writeUnsignedChar((char)Type);
|
|
// wp.writeBool(true);
|
|
// switch (Type) {
|
|
// case TextType::CHAT:
|
|
// case TextType::WHISPER:
|
|
// case TextType::ANNOUNCEMENT:
|
|
// wp.writeString("Server");
|
|
// case TextType::RAW:
|
|
// case TextType::TIP:
|
|
// case TextType::SYSTEM:
|
|
// case TextType::JSON_WHISPER:
|
|
// case TextType::JSON:
|
|
// wp.writeString(text);
|
|
// break;
|
|
// case TextType::TRANSLATION:
|
|
// case TextType::POPUP:
|
|
// case TextType::JUKEBOX_POPUP:
|
|
// wp.writeString(text);
|
|
// wp.writeUnsignedVarInt(0);
|
|
// break;
|
|
// }
|
|
// wp.writeString("");
|
|
// wp.writeString("");
|
|
//
|
|
// auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::Text);
|
|
// pkt->read(wp);
|
|
auto pkt = TextPacket::createSystemMessage(text);
|
|
this->sendNetworkPacket(pkt);
|
|
return true;
|
|
}
|
|
|
|
// bool Player::sendToastPacket(string title, string msg) {
|
|
// ToastRequestPacket pkt = ToastRequestPacket(title, msg);
|
|
// sendNetworkPacket(pkt);
|
|
// return true;
|
|
// }
|
|
|
|
bool Player::sendTitlePacket(string text, TitleType Type, int FadeInDuration, int RemainDuration, int FadeOutDuration) const {
|
|
BinaryStream wp;
|
|
wp.reserve(8 + text.size());
|
|
wp.writeVarInt((int)Type);
|
|
wp.writeString(text);
|
|
wp.writeVarInt(FadeInDuration);
|
|
wp.writeVarInt(RemainDuration);
|
|
wp.writeVarInt(FadeOutDuration);
|
|
wp.writeString(getXuid());
|
|
wp.writeString("");
|
|
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::SetTitle);
|
|
pkt->read(wp);
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendNotePacket(unsigned int tone) {
|
|
if (tone == 0) {
|
|
return false;
|
|
}
|
|
BinaryStream wp;
|
|
wp.writeUnsignedChar(82);
|
|
auto& PlayerPos = getPosition();
|
|
wp.writeFloat(PlayerPos.x);
|
|
wp.writeFloat(PlayerPos.y);
|
|
wp.writeFloat(PlayerPos.z);
|
|
wp.writeVarInt(tone * 2);
|
|
wp.writeString("");
|
|
wp.writeBool(false);
|
|
wp.writeBool(true);
|
|
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::LevelSoundEvent);
|
|
pkt->read(wp);
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendSpawnParticleEffectPacket(Vec3 spawnPos, int dimID, string ParticleName, int64_t EntityUniqueID) const {
|
|
BinaryStream wp;
|
|
wp.writeUnsignedChar(dimID);
|
|
// If EntityUniqueID is not -1, the Position below will be interpreted as relative to the position of the entity associated with this unique ID.
|
|
wp.writeVarInt64(EntityUniqueID);
|
|
wp.writeFloat(spawnPos.x);
|
|
wp.writeFloat(spawnPos.y);
|
|
wp.writeFloat(spawnPos.z);
|
|
// ParticleName is the name of the particle that should be shown. This name may point to a particle effect that is built-in, or to one implemented by behaviour packs.
|
|
wp.writeString(ParticleName);
|
|
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::SpawnParticleEffect);
|
|
pkt->read(wp);
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendPlaySoundPacket(string SoundName, Vec3 Position, float Volume, float Pitch) const {
|
|
PlaySoundPacket playSoundPkt(std::move(SoundName), Position, Volume, Pitch);
|
|
sendNetworkPacket(playSoundPkt);
|
|
return true;
|
|
}
|
|
|
|
#include <SendPacketAPI.h>
|
|
// bool Player::sendAddItemEntityPacket(unsigned long long runtimeID, Item const& item, int stackSize, short aux, Vec3 pos, vector<std::unique_ptr<DataItem>> dataItems) const {
|
|
// BinaryStream wp;
|
|
// wp.writeVarInt64(runtimeID); // RuntimeId
|
|
// wp.writeUnsignedVarInt64(runtimeID); // EntityId
|
|
// ItemStackDescriptor desc(item, aux, stackSize, nullptr);
|
|
// NetworkItemStackDescriptor netDesc(desc);
|
|
// wp.writeType(netDesc);
|
|
// wp.writeType(pos);
|
|
// wp.writeType(Vec3::ZERO);
|
|
|
|
// wp.writeType(dataItems);
|
|
|
|
// wp.writeBool(false);
|
|
|
|
// NetworkPacket<15> pkt(wp.getRaw());
|
|
// sendNetworkPacket(pkt);
|
|
// return true;
|
|
// }
|
|
|
|
bool Player::sendAddEntityPacket(unsigned long long runtimeID, string entityType, Vec3 pos, Vec2 rotation, float headYaw, vector<std::unique_ptr<DataItem>> dataItems) {
|
|
BinaryStream bs;
|
|
bs.writeVarInt64(runtimeID);
|
|
bs.writeUnsignedVarInt64(runtimeID);
|
|
bs.writeString(entityType);
|
|
bs.writeType(pos);
|
|
bs.writeType(Vec3{0, 0, 0});
|
|
bs.writeType(Vec3{0, 0, 0});
|
|
bs.writeFloat(0.0);
|
|
// Atrribute
|
|
bs.writeUnsignedVarInt(0);
|
|
|
|
// DataItem
|
|
bs.writeUnsignedVarInt(0);
|
|
|
|
// Links
|
|
bs.writeUnsignedVarInt(0);
|
|
|
|
//NetworkPacket<13> pkt(bs.getAndReleaseData());
|
|
auto pkt = MinecraftPackets::createPacket(13);
|
|
pkt->read(bs);
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendUpdateBlockPacket(BlockPos const& bpos, unsigned int runtimeId, UpdateBlockFlags flag, UpdateBlockLayer layer) {
|
|
BinaryStream wp;
|
|
wp.writeVarInt(bpos.x);
|
|
wp.writeUnsignedVarInt(bpos.y);
|
|
wp.writeVarInt(bpos.z);
|
|
wp.writeUnsignedVarInt(runtimeId);
|
|
wp.writeUnsignedVarInt((unsigned int)flag);
|
|
wp.writeUnsignedVarInt((unsigned int)layer);
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::UpdateBlock);
|
|
pkt->read(wp);
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
bool Player::sendUpdateBlockPacket(BlockPos const& bpos, const Block& block, UpdateBlockFlags flag, UpdateBlockLayer layer) {
|
|
return sendUpdateBlockPacket(bpos, block.getRuntimeId(), flag, layer);
|
|
}
|
|
|
|
bool Player::sendTransferPacket(const string& address, short port) const {
|
|
auto packet = MinecraftPackets::createPacket(0x55);
|
|
dAccess<short>(packet.get(), 36) = port;
|
|
dAccess<string>(packet.get(), 40) = address;
|
|
sendNetworkPacket(*packet);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendSetDisplayObjectivePacket(const string& title, const string& name, char sortOrder) const {
|
|
SetDisplayObjectivePacket pkt = SetDisplayObjectivePacket("sidebar", name, title, "dummy", ObjectiveSortOrder(sortOrder));
|
|
sendNetworkPacket(pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendSetScorePacket(char type, const vector<ScorePacketInfo>& data) {
|
|
auto packet = MinecraftPackets::createPacket(0x6c);
|
|
dAccess<char>(packet.get(), 48) = type;
|
|
dAccess<vector<ScorePacketInfo>>(packet.get(), 56) = data;
|
|
sendNetworkPacket(*packet);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendBossEventPacket(BossEvent type, string name, float percent, BossEventColour colour, int overlay) {
|
|
BinaryStream wp;
|
|
wp.writeVarInt64(getUniqueID() + 1145141919);
|
|
wp.writeUnsignedVarInt((int)type);
|
|
switch (type) {
|
|
case BossEvent::Show:
|
|
wp.writeString(name);
|
|
wp.writeFloat(percent);
|
|
goto LABEL_3;
|
|
case BossEvent::RegisterPlayer:
|
|
case BossEvent::UnregisterPlayer:
|
|
case BossEvent::ResendRaidBossEventData: {
|
|
wp.writeVarInt64(getUniqueID() + 1145141919);
|
|
break;
|
|
}
|
|
case BossEvent::HealthPercentage: {
|
|
wp.writeFloat(percent);
|
|
break;
|
|
}
|
|
case BossEvent::Title: {
|
|
wp.writeString(name);
|
|
break;
|
|
}
|
|
case BossEvent::AppearanceProperties:
|
|
LABEL_3:
|
|
wp.writeUnsignedShort(1);
|
|
goto LABEL_4;
|
|
case BossEvent::Texture:
|
|
LABEL_4:
|
|
wp.writeUnsignedVarInt((int)colour);
|
|
wp.writeUnsignedVarInt(overlay);
|
|
break;
|
|
}
|
|
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::BossEvent);
|
|
pkt->read(wp);
|
|
sendAddEntityPacket(getUniqueID() + 1145141919, "player", Vec3(getPos().x, (float)-70, getPos().z), Vec2{0, 0}, 0);
|
|
if (type != BossEvent::Hide) {
|
|
sendBossEventPacket(BossEvent::Hide, "", 0, BossEventColour::White);
|
|
}
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendCommandRequestPacket(const string& cmd) {
|
|
auto packet = MinecraftPackets::createPacket(0x4d);
|
|
dAccess<string, 48>(packet.get()) = cmd;
|
|
Global<ServerNetworkHandler>->handle(*getNetworkIdentifier(), *((CommandRequestPacket*)packet.get()));
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendTextTalkPacket(const string& msg) {
|
|
return sendTextTalkPacket(msg, nullptr);
|
|
}
|
|
#include <Utils/DbgHelper.h>
|
|
bool Player::sendTextTalkPacket(const string& msg, Player* target) {
|
|
auto packet = TextPacket::createChat(getName(), msg, getXuid(), "");
|
|
if (target == nullptr) {
|
|
Global<ServerNetworkHandler>->handle(*getNetworkIdentifier(), packet);
|
|
return true;
|
|
}
|
|
try {
|
|
Event::PlayerChatEvent ev;
|
|
ev.mMessage = msg;
|
|
ev.mPlayer = this;
|
|
if (!ev.call())
|
|
return false;
|
|
} catch (...) {
|
|
logger.error("Event Callback Failed!");
|
|
logger.error("Uncaught Exception Detected!");
|
|
logger.error("In Event: PlayerChatEvent");
|
|
PrintCurrentStackTraceback();
|
|
}
|
|
target->sendNetworkPacket(packet);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendRawFormPacket(unsigned formId, const string& data) const {
|
|
BinaryStream wp;
|
|
wp.reserve(32 + data.size());
|
|
wp.writeUnsignedVarInt(formId);
|
|
wp.writeString(data);
|
|
|
|
auto pkt = MinecraftPackets::createPacket(MinecraftPacketIds::ModalFormRequest);
|
|
pkt->read(wp);
|
|
sendNetworkPacket(*pkt);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendSimpleForm(const string& title, const string& content, const vector<string>& buttons, const std::vector<std::string>& images, std::function<void(Player*, int)> callback) const {
|
|
nlohmann::json model = R"({"title": "","content":"","buttons":[],"type":"form"})"_json;
|
|
model["title"] = title;
|
|
model["content"] = content;
|
|
for (int i = 0; i < buttons.size(); ++i) {
|
|
nlohmann::json oneButton = "{}"_json;
|
|
oneButton["text"] = buttons[i];
|
|
if (!images[i].empty()) {
|
|
nlohmann::json image = "{}"_json;
|
|
image["type"] = images[i].find("textures/") == 0 ? "path" : "url";
|
|
image["data"] = images[i];
|
|
oneButton["image"] = image;
|
|
}
|
|
model["buttons"].push_back(oneButton);
|
|
}
|
|
std::string data = model.dump();
|
|
|
|
unsigned formId = NewFormId();
|
|
if (!sendRawFormPacket(formId, data))
|
|
return false;
|
|
SetSimpleFormPacketCallback(formId, callback);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendModalForm(const string& title, const string& content, const string& confirmButton, const string& cancelButton, std::function<void(Player*, bool)> callback) const {
|
|
nlohmann::json model = R"({"title":"","content":"","button1":"","button2":"","type":"modal"})"_json;
|
|
model["title"] = title;
|
|
model["content"] = content;
|
|
model["button1"] = confirmButton;
|
|
model["button2"] = cancelButton;
|
|
std::string data = model.dump();
|
|
unsigned formId = NewFormId();
|
|
if (!sendRawFormPacket(formId, data))
|
|
return false;
|
|
SetModalFormPacketCallback(formId, callback);
|
|
return true;
|
|
}
|
|
|
|
bool Player::sendCustomForm(const std::string& data, std::function<void(Player*, string)> callback) const {
|
|
unsigned formId = NewFormId();
|
|
if (!sendRawFormPacket(formId, data))
|
|
return false;
|
|
SetCustomFormPacketCallback(formId, callback);
|
|
return true;
|
|
}
|
|
|
|
bool Player::isValid(Player* player) {
|
|
auto pls = Level::getAllPlayers();
|
|
for (auto& pl : pls)
|
|
if (pl == player)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// For Compatibility
|
|
bool Player::sendSimpleFormPacket(const string& title, const string& content, const vector<string>& buttons, const std::vector<std::string>& images, std::function<void(int)> callback) const {
|
|
return sendSimpleForm(title, content, buttons, images, [callback](Player* pl, int id) {
|
|
if (!callback || !Player::isValid(pl))
|
|
return;
|
|
try {
|
|
callback(id);
|
|
} catch (...) {
|
|
logger.error("Exception occurred in custom-form packet callback!");
|
|
logger.error("Player: {}", pl->getName());
|
|
}
|
|
});
|
|
}
|
|
bool Player::sendModalFormPacket(const string& title, const string& content, const string& button1, const string& button2, std::function<void(bool)> callback) {
|
|
return sendModalForm(title, content, button1, button2, [callback](Player* pl, bool res) {
|
|
if (!callback || !Player::isValid(pl))
|
|
return;
|
|
try {
|
|
callback(res);
|
|
} catch (...) {
|
|
logger.error("Exception occurred in modal-form packet callback!");
|
|
logger.error("Player: {}", pl->getName());
|
|
}
|
|
});
|
|
}
|
|
|
|
bool Player::sendCustomFormPacket(const std::string& data, std::function<void(string)> callback) {
|
|
return sendCustomForm(data, [callback](Player* pl, string res) {
|
|
if (!callback || !Player::isValid(pl))
|
|
return;
|
|
try {
|
|
callback(res);
|
|
} catch (...) {
|
|
logger.error("Exception occurred in custom-form packet callback!");
|
|
logger.error("Player: {}", pl->getName());
|
|
}
|
|
});
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
bool testPlayerExperience(Player& player) {
|
|
player.resetPlayerLevel();
|
|
size_t totalExp = player.getTotalExperience();
|
|
assert(totalExp == 0);
|
|
player.setTotalExperience(123456);
|
|
totalExp = player.getTotalExperience();
|
|
assert(totalExp == 123456);
|
|
|
|
assert(player.reduceExperience(12345));
|
|
int level = player.getPlayerLevel();
|
|
int exp = player.getCurrentExperience();
|
|
totalExp = player.getTotalExperience();
|
|
logger.warn("level: {} exp: {}, totalExp: {}", level, exp, totalExp);
|
|
assert(totalExp == 123456 - 12345);
|
|
player.resetPlayerLevel();
|
|
player.addLevels(12345);
|
|
level = player.getPlayerLevel();
|
|
exp = player.getCurrentExperience();
|
|
totalExp = player.getTotalExperience();
|
|
logger.warn("level: {} exp: {}, totalExp: {}", level, exp, totalExp);
|
|
player.resetPlayerLevel();
|
|
player.addExperience(INT32_MAX);
|
|
level = player.getPlayerLevel();
|
|
exp = player.getCurrentExperience();
|
|
totalExp = player.getTotalExperience();
|
|
logger.warn("level: {} exp: {}, totalExp: {}", level, exp, totalExp);
|
|
// for (int i = 0; i <= 1000; i++) {
|
|
// int level = i * i;
|
|
// int exp = Player::getXpNeededForLevel(level + 1);
|
|
// size_t total = Player::getTotalXpNeededForLevel(level);
|
|
// logger.warn("Level: {}, exp needed: {}, total exp: {}", level, exp, total);
|
|
// }
|
|
return true;
|
|
}
|
|
|
|
#endif // DEBUG
|