LiteLoaderBDS-1.16.40/LiteLoader/Kernel/MC/LevelAPI.cpp
2022-11-17 14:37:18 +08:00

404 lines
13 KiB
C++

#include <Global.h>
#include <string>
#include <utility>
#include <vector>
#include <cctype>
#include <fstream>
#include <MC/Actor.hpp>
#include <MC/ServerPlayer.hpp>
#include <MC/Spawner.hpp>
#include <MC/ActorDamageSource.hpp>
#include <MC/Block.hpp>
#include <MC/BlockSource.hpp>
#include <MC/CommandContext.hpp>
#include <MC/CompoundTag.hpp>
#include <MC/Dimension.hpp>
#include <MC/DropperBlockActor.hpp>
#include <MC/ItemActor.hpp>
#include <MC/ItemStack.hpp>
#include <MC/Level.hpp>
#include <MC/MinecraftCommands.hpp>
#include <MC/Tick.hpp>
#include <MC/Packet.hpp>
#include <MC/PropertiesSettings.hpp>
#include <MC/LoopbackPacketSender.hpp>
#include <MC/ServerCommandOrigin.hpp>
#include <MC/PlayerCommandOrigin.hpp>
Actor* Level::getEntity(ActorUniqueID uniqueId) {
try {
return SymCall("?fetchEntity@Level@@QEBAPEAVActor@@UActorUniqueID@@_N@Z", Actor*, Level*, ActorUniqueID)(Global<Level>, uniqueId);
} catch (...) {
return nullptr;
}
}
BlockSource* Level::getBlockSource(int dimID) {
// auto dim = Global<Level>->createDimension(dimID);
auto dim = Global<Level>->getDimension(dimID);
return &dim->getBlockSourceFromMainChunkSource();
//return dAccess<BlockSource*>(dim, 96);
}
BlockSource* Level::getBlockSource(Actor* ac) {
return const_cast<BlockSource*>(&ac->getRegionConst());
}
Block* Level::getBlock(BlockPos* pos, int dimId) {
return getBlock(*pos, Level::getBlockSource(dimId));
}
Block* Level::getBlock(BlockPos* pos, BlockSource* blockSource) {
return (Block*)&(blockSource->getBlock(*pos));
}
Block* Level::getBlock(const BlockPos& pos, int dimId) {
return getBlock(pos, Level::getBlockSource(dimId));
}
Block* Level::getBlock(const BlockPos& pos, BlockSource* blockSource) {
return (Block*)&(blockSource->getBlock(pos));
}
// Return nullptr when failing to get block
Block* Level::getBlockEx(const BlockPos& pos, int dimId) {
auto dim = Global<Level>->getDimension(dimId);
if (!dim)
return nullptr;
auto bs = &dim->getBlockSourceFromMainChunkSource();
auto lc = bs->getChunkAt(pos);
if (!lc)
return nullptr;
short minHeight = dim->getHeight();
if (pos.y < minHeight || pos.y > dim->getHeight())
return nullptr;
ChunkBlockPos cbpos = ChunkBlockPos(pos, minHeight);
return const_cast<Block*>(&lc->getBlock(cbpos));
}
BlockInstance Level::getBlockInstance(BlockPos* pos, int dimId) {
return {*pos, dimId};
}
BlockInstance Level::getBlockInstance(BlockPos* pos, BlockSource* blockSource) {
return {*pos, blockSource->getDimensionId()};
}
BlockInstance Level::getBlockInstance(const BlockPos& pos, int dim) {
return {pos, dim};
}
BlockInstance Level::getBlockInstance(const BlockPos& pos, BlockSource* blockSource) {
return {pos, blockSource->getDimensionId()};
}
BlockActor* Level::getBlockEntity(BlockPos* pos, int dimId) {
return getBlockEntity(pos, Level::getBlockSource(dimId));
}
BlockActor* Level::getBlockEntity(BlockPos* pos, BlockSource* blockSource) {
return blockSource->getBlockEntity(*pos);
}
BlockActor* Level::getBlockEntity(const BlockPos& pos, int dimId) {
return getBlockEntity((BlockPos*)&pos, Level::getBlockSource(dimId));
}
BlockActor* Level::getBlockEntity(const BlockPos& pos, BlockSource* blockSource) {
return getBlockEntity((BlockPos*)&pos, blockSource);
}
bool Level::setBlock(const BlockPos& pos, int dim, Block* block) {
BlockSource* bs = getBlockSource(dim);
return bs->setBlock(pos, *block, 3, nullptr, nullptr); // updateFlag = 3 from IDA SetBlockCommand::execute()
}
bool Level::setBlock(const BlockPos& pos, int dim, const string& name, unsigned short tileData) {
Block* newBlock = Block::create(name, tileData);
if (!newBlock)
return false;
return setBlock(pos, dim, newBlock);
}
bool Level::setBlock(const BlockPos& pos, int dim, CompoundTag* nbt) {
Block* newBlock = Block::create(nbt);
if (!newBlock)
return false;
return setBlock(pos, dim, newBlock);
}
// bool Level::breakBlockNaturally(BlockSource* bs, const BlockPos& pos) {
// return getBlockInstance(pos, bs).breakNaturally();
// }
// bool Level::breakBlockNaturally(BlockSource* bs, const BlockPos& pos, ItemStack* item) {
// return getBlockInstance(pos, bs).breakNaturally(item);
// }
bool Level::hasContainer(Vec3 pos, int dim) {
return getContainer(pos, dim) != nullptr;
}
Container* Level::getContainer(Vec3 pos, int dim) {
// VirtualCall<Container*>(getBlockEntity(), 224); // IDA ChestBlockActor::`vftable'{for `RandomizableBlockActorContainerBase'}
// This function didn't use 'this' pointer
return ((DropperBlockActor*)nullptr)->_getContainerAt(*Level::getBlockSource(dim), pos);
}
Actor* Level::getDamageSourceEntity(ActorDamageSource* ads) {
ActorUniqueID v6 = ads->getDamagingEntityUniqueID();
return Global<Level>->getEntity(v6);
}
//void* Level::ServerCommandOrigin::fake_vtbl[26];
CompoundTag& getServerOriginTag() {
static auto cached = CompoundTag::fromSNBT(R"({"CommandPermissionLevel":4b,"DimensionId":"Overworld","OriginType":7b,"RequestId":"00000000-0000-0000-0000-000000000000"})");
return *cached;
}
std::unique_ptr<CompoundTag> getPlayerOriginTag(Player& player) {
static auto cached = CompoundTag::fromSNBT(R"({"OriginType":0b,"PlayerId":0l})");
auto tag = cached->clone();
tag->putInt64("PlayerId", player.getUniqueID());
return std::move(tag);
}
bool Level::executeCommand(const string& cmd) {
//auto origin = ::ServerCommandOrigin::load(getServerOriginTag(), *Global<ServerLevel>);
std::string requestID = "00000000-0000-0000-0000-000000000000";
std::unique_ptr<ServerCommandOrigin> origin(new ServerCommandOrigin(requestID,*Global<ServerLevel>, CommandPermissionLevel(4)));
return MinecraftCommands::_runcmd(std::move(origin), cmd);
}
std::unordered_map<CommandOrigin const*, string*> resultOfOrigin = {};
std::pair<bool, string> Level::executeCommandEx(const string& cmd) {
//auto origin = ::ServerCommandOrigin::load(getServerOriginTag(), *Global<ServerLevel>);
const std::string requestID = "00000000-0000-0000-0000-000000000000";
std::unique_ptr<ServerCommandOrigin> origin(new ServerCommandOrigin(requestID,*Global<ServerLevel>, CommandPermissionLevel(4)));
string val;
auto ptr = origin.get();
resultOfOrigin[ptr] = &val;
bool rv = MinecraftCommands::_runcmd(std::move(origin), cmd);
if (resultOfOrigin.count(ptr))
resultOfOrigin.erase(ptr);
return {rv, std::move(val)};
}
// static void* FAKE_PORGVTBL[26];
bool Level::executeCommandAs(Player* pl, const string& cmd) {
auto tag = getPlayerOriginTag(*pl);
std::unique_ptr<PlayerCommandOrigin> origin(new PlayerCommandOrigin(*pl));
return MinecraftCommands::_runcmd(std::move(origin), cmd);
}
std::vector<Player*> Level::getAllPlayers() {
try {
std::vector<Player*> player_list;
Global<Level>->forEachPlayer([&](Player& sp) -> bool {
Player* player = &sp;
player_list.push_back(player);
return true;
});
return player_list;
} catch (...) {
return {};
}
}
std::vector<Actor*> Level::getAllEntities(int dimId) {
try {
Level* lv = Global<Level>;
Dimension* dim = lv->getDimension(dimId);
if (!dim)
return {};
auto& list = *(std::unordered_map<ActorUniqueID, void*>*)((uintptr_t)dim + 320); // IDA Dimension::registerEntity
// Check Valid
std::vector<Actor*> result;
auto currTick = SymCall("?getCurrentTick@Level@@QEBAAEBUTick@@XZ", Tick*, Level*)(lv)->t;
for (auto& i : list) {
// auto entity = SymCall("??$tryUnwrap@VActor@@$$V@WeakEntityRef@@QEBAPEAVActor@@XZ",
// Actor*, void*)(&i.second);
auto entity = getEntity(i.first);
if (!entity)
continue;
auto lastTick = entity->getLastTick();
if (!lastTick)
continue;
if (currTick - lastTick->t == 0 || currTick - lastTick->t == 1)
result.push_back(entity);
}
return result;
} catch (...) {
return {};
}
}
std::vector<Actor*> Level::getAllEntities() {
std::vector<Actor*> entityList;
auto entities = getAllEntities(0);
entityList.insert(entityList.end(), entities.begin(), entities.end());
entities = getAllEntities(1);
entityList.insert(entityList.end(), entities.begin(), entities.end());
entities = getAllEntities(2);
entityList.insert(entityList.end(), entities.begin(), entities.end());
return entityList;
//return Global<Level>->getRuntimeActorList();
}
Player* Level::getPlayer(const string& info) {
string target{info};
std::transform(target.begin(), target.end(), target.begin(), ::tolower); // lower case the string
size_t delta = UINT64_MAX; // c++ int max
Player* found = nullptr;
Global<Level>->forEachPlayer([&](Player& sp) -> bool {
Player* p = &sp;
if (p->getXuid() == target || p->getRealName() == info) {
found = p;
return false;
}
string pName = p->getRealName();
std::transform(pName.begin(), pName.end(), pName.begin(), ::tolower);
//模糊匹配
if (pName.find(target) == 0) {
// 0 ís the index where the "target" appear in "pName"
size_t curDelta = pName.length() - target.length();
if (curDelta == 0) {
found = p;
}
if (curDelta < delta) {
found = p;
delta = curDelta;
}
}
return true;
});
return found;
}
Player* Level::getPlayer(ActorUniqueID id) {
// 裂开,这个符号也没有
// 根据伪代码重新写实现
Actor* actor = Level::fetchEntity(id,0);
if(actor && actor->hasCategory((ActorCategory)1))
return (Player*)actor;
else
return nullptr;
//return SymCall("?getPlayer@Level@@UEBAPEAVPlayer@@UActorUniqueID@@@Z", Player*, Level*, ActorUniqueID)(Global<Level>, id);
}
Player* Level::getPlayer(const mce::UUID& uuid) const{
// 根据函数
// std::_Func_impl_no_alloc__lambda_71cde901375eb38deb56f48a96514d77__bool_Player_const___::_Do_call
Player* findPlayer = this->findPlayer([&](const Player& pl)->bool {
if (pl.getClientUUID() == uuid)
return true;
return false;
});
return findPlayer;
}
Actor* Level::spawnMob(Vec3 pos, int dimId, std::string name) {
Spawner* sp = &Global<Level>->getSpawner();
return sp->spawnMob(pos, dimId, std::move(name));
}
Actor* Level::cloneMob(Vec3 pos, int dimId, Actor* ac) {
Spawner* sp = &Global<Level>->getSpawner();
Mob* mob = sp->spawnMob(pos, dimId, std::move(ac->getTypeName()));
mob->setNbt(ac->getNbt().get());
return mob;
}
Actor* Level::spawnItem(Vec3 pos, int dimId, ItemStack* item) {
Spawner* sp = &Global<Level>->getSpawner();
return sp->spawnItem(pos, dimId, item);
}
bool Level::createExplosion(Vec3 pos, int dimId, Actor* source, float radius, bool createFire, bool canBreak, float maxResistance) {
Global<Level>->explode(*Level::getBlockSource(dimId), source, pos, radius, createFire, canBreak, maxResistance, false);
return true;
}
#include <MC/ItemRegistry.hpp>
ItemStack* Level::getItemStackFromId(short itemId, int aux) {
auto item = ItemRegistry::getItem(itemId);
if (item)
return new ItemStack(*item, 1, aux);
return nullptr;
}
void Level::broadcastText(const string& a1, TextType ty) {
if (!Global<Level>)
return;
Global<Level>->forEachPlayer([&](Player& sp) -> bool {
sp.sendTextPacket(a1, ty);
return true;
});
}
void Level::broadcastTitle(const string& text, TitleType Type, int FadeInDuration, int RemainDuration, int FadeOutDuration) {
if (!Global<Level>)
return;
Global<Level>->forEachPlayer([&](Player& sp) -> bool {
sp.sendTitlePacket(text, Type, FadeInDuration, RemainDuration, FadeOutDuration);
return true;
});
}
void Level::sendPacketForAllPlayers(Packet& pkt) {
if (!Global<Level>)
return;
auto sender = (LoopbackPacketSender*)Global<Level>->getPacketSender();
if (sender)
return sender->sendBroadcast(pkt);
}
// For compatibility
void Level::sendPacketForAllPlayer(Packet& pkt) {
sendPacketForAllPlayers(pkt);
}
std::string Level::getCurrentLevelName() {
if (Global<PropertiesSettings>)
return Global<PropertiesSettings>->getLevelName();
std::ifstream fin("server.properties");
string buf;
while (getline(fin, buf)) {
if (buf.find("level-name=") != string::npos) {
if (buf.back() == '\n')
buf.pop_back();
if (buf.back() == '\r')
buf.pop_back();
return buf.substr(11);
}
}
return "";
}
std::string Level::getCurrentLevelPath() {
return "./worlds/" + getCurrentLevelName();
}
int64_t BossID = 7492341231332ull;
int64_t Level::createBossEvent() {
return ++BossID;
}