mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-03 04:23:39 +00:00
408 lines
13 KiB
C++
408 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));
|
|
}
|
|
|
|
BlockPalette* Level::getBlockPalettePtr(){
|
|
// MovingBlockActor::load Line69
|
|
return dAccess<BlockPalette*>(Global<Level>,2000);
|
|
};
|
|
|
|
// 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;
|
|
} |