mirror of
https://github.com/neoStudiosLCE/neoLegacy.git
synced 2026-06-08 23:13:00 +00:00
feat: better kill command, Host Privileges check (#135)
i changed a bit the kill command because it was not working properly, then i added a check for HostPrivileges for each command
This commit is contained in:
parent
128651de24
commit
2417eb4562
|
|
@ -1046,6 +1046,13 @@ void PlayerConnection::handleCommand(const wstring& message)
|
|||
ss >> cmd;
|
||||
if (cmd == L"tp" || cmd == L"teleport")
|
||||
{
|
||||
|
||||
if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled))
|
||||
{
|
||||
warn(L"Cheats are not enabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->hasPermission(eGameCommand_Teleport))
|
||||
{
|
||||
warn(L"You do not have permission to use this command.");
|
||||
|
|
@ -1138,6 +1145,13 @@ if (cmd == L"tp" || cmd == L"teleport")
|
|||
}
|
||||
} else if (cmd == L"time")
|
||||
{
|
||||
|
||||
if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled))
|
||||
{
|
||||
warn(L"Cheats are not enabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->hasPermission(eGameCommand_Time))
|
||||
{
|
||||
warn(L"You do not have permission to use this command.");
|
||||
|
|
@ -1268,15 +1282,44 @@ if (cmd == L"tp" || cmd == L"teleport")
|
|||
}
|
||||
else if (cmd == L"kill")
|
||||
{
|
||||
if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled))
|
||||
{
|
||||
warn(L"Cheats are not enabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->hasPermission(eGameCommand_Kill))
|
||||
{
|
||||
warn(L"You do not have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
server->getCommandDispatcher()->performCommand(player, eGameCommand_Kill, byteArray());
|
||||
|
||||
wstring targetName;
|
||||
ss >> targetName;
|
||||
|
||||
if (targetName.empty())
|
||||
{
|
||||
|
||||
server->getCommandDispatcher()->performCommand(player, eGameCommand_Kill, byteArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ByteArrayOutputStream baos;
|
||||
DataOutputStream dos(&baos);
|
||||
dos.writeUTF(targetName);
|
||||
byteArray data = baos.toByteArray();
|
||||
server->getCommandDispatcher()->performCommand(player, eGameCommand_Kill, data);
|
||||
}
|
||||
}
|
||||
else if (cmd == L"toggledownfall")
|
||||
{
|
||||
if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled))
|
||||
{
|
||||
warn(L"Cheats are not enabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->hasPermission(eGameCommand_ToggleDownfall))
|
||||
{
|
||||
warn(L"You do not have permission to use this command.");
|
||||
|
|
@ -1285,6 +1328,14 @@ if (cmd == L"tp" || cmd == L"teleport")
|
|||
shared_ptr<GameCommandPacket> packet = ToggleDownfallCommand::preparePacket();
|
||||
server->getCommandDispatcher()->performCommand(player, eGameCommand_ToggleDownfall, packet->data);
|
||||
} else if (cmd == L"gamemode") {
|
||||
|
||||
|
||||
if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled))
|
||||
{
|
||||
warn(L"Cheats are not enabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->hasPermission(eGameCommand_GameMode))
|
||||
{
|
||||
warn(L"You do not have permission to use this command.");
|
||||
|
|
@ -1323,6 +1374,13 @@ if (cmd == L"tp" || cmd == L"teleport")
|
|||
shared_ptr<GameCommandPacket> packet = GameModeCommand::preparePacket(target, mode);
|
||||
server->getCommandDispatcher()->performCommand(player, eGameCommand_GameMode, packet->data);
|
||||
} else if (cmd == L"give") {
|
||||
|
||||
if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled))
|
||||
{
|
||||
warn(L"Cheats are not enabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->hasPermission(eGameCommand_Give))
|
||||
{
|
||||
warn(L"You do not have permission to use this command.");
|
||||
|
|
@ -1868,6 +1926,8 @@ void PlayerConnection::handleGameCommand(shared_ptr<GameCommandPacket> packet)
|
|||
player->getName().c_str(), player->isModerator() ? 1 : 0, isHost ? 1 : 0,
|
||||
static_cast<int>(packet->command));
|
||||
#endif
|
||||
|
||||
|
||||
MinecraftServer::getInstance()->getCommandDispatcher()->performCommand(player, packet->command, packet->data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1170,7 +1170,13 @@ bool EnderDragon::hurt(shared_ptr<MultiEntityMobPart> MultiEntityMobPart, Damage
|
|||
|
||||
bool EnderDragon::hurt(DamageSource *source, float damage)
|
||||
{
|
||||
return false;
|
||||
if (source == DamageSource::outOfWorld)
|
||||
{
|
||||
setSynchedAction(e_EnderdragonAction_Sitting_Scanning, true);
|
||||
reallyHurt(source, getMaxHealth() + 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EnderDragon::reallyHurt(DamageSource *source, float damage)
|
||||
|
|
|
|||
118
Minecraft.World/EntityTypeMap.cpp
Normal file
118
Minecraft.World/EntityTypeMap.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#include "stdafx.h"
|
||||
#include "EntityTypeMap.h"
|
||||
|
||||
static const unordered_map<wstring, eINSTANCEOF> s_nameToType = {
|
||||
// animals
|
||||
{ L"pig", eTYPE_PIG },
|
||||
{ L"cow", eTYPE_COW },
|
||||
{ L"sheep", eTYPE_SHEEP },
|
||||
{ L"chicken", eTYPE_CHICKEN },
|
||||
{ L"horse", eTYPE_HORSE },
|
||||
{ L"wolf", eTYPE_WOLF },
|
||||
{ L"ocelot", eTYPE_OCELOT },
|
||||
{ L"rabbit", eTYPE_RABBIT },
|
||||
{ L"mooshroom", eTYPE_MUSHROOMCOW },
|
||||
{ L"squid", eTYPE_SQUID },
|
||||
{ L"bat", eTYPE_BAT },
|
||||
// neutral/passive
|
||||
{ L"villager", eTYPE_VILLAGER },
|
||||
{ L"snowgolem", eTYPE_SNOWMAN },
|
||||
{ L"irongolem", eTYPE_VILLAGERGOLEM },
|
||||
// monsters
|
||||
{ L"zombie", eTYPE_ZOMBIE },
|
||||
{ L"skeleton", eTYPE_SKELETON },
|
||||
{ L"creeper", eTYPE_CREEPER },
|
||||
{ L"spider", eTYPE_SPIDER },
|
||||
{ L"cavespider", eTYPE_CAVESPIDER },
|
||||
{ L"enderman", eTYPE_ENDERMAN },
|
||||
{ L"silverfish", eTYPE_SILVERFISH },
|
||||
{ L"blaze", eTYPE_BLAZE },
|
||||
{ L"witch", eTYPE_WITCH },
|
||||
{ L"ghast", eTYPE_GHAST },
|
||||
{ L"slime", eTYPE_SLIME },
|
||||
{ L"magmacube", eTYPE_LAVASLIME },
|
||||
{ L"zombie_pigman", eTYPE_PIGZOMBIE },
|
||||
{ L"witherboss", eTYPE_WITHERBOSS },
|
||||
{ L"enderdragon", eTYPE_ENDERDRAGON },
|
||||
{ L"giant", eTYPE_GIANT },
|
||||
{ L"endermite", eTYPE_ENDERMITE },
|
||||
{ L"guardian", eTYPE_GUARDIAN },
|
||||
{ L"elder_guardian", eTYPE_ELDER_GUARDIAN },
|
||||
// minecart
|
||||
{ L"minecart", eTYPE_MINECART },
|
||||
{ L"minecart_chest", eTYPE_MINECART_CHEST },
|
||||
{ L"minecart_hopper", eTYPE_MINECART_HOPPER },
|
||||
{ L"minecart_tnt", eTYPE_MINECART_TNT },
|
||||
{ L"minecart_furnace", eTYPE_MINECART_FURNACE },
|
||||
{ L"minecart_spawner", eTYPE_MINECART_SPAWNER },
|
||||
// projectiles
|
||||
{ L"arrow", eTYPE_ARROW },
|
||||
{ L"snowball", eTYPE_SNOWBALL },
|
||||
{ L"egg", eTYPE_THROWNEGG },
|
||||
{ L"enderpearl", eTYPE_THROWNENDERPEARL },
|
||||
{ L"potion", eTYPE_THROWNPOTION },
|
||||
{ L"expbottle", eTYPE_THROWNEXPBOTTLE },
|
||||
{ L"large_fireball", eTYPE_LARGE_FIREBALL },
|
||||
{ L"small_fireball", eTYPE_SMALL_FIREBALL },
|
||||
{ L"wither_skull", eTYPE_WITHER_SKULL },
|
||||
{ L"dragon_fireball", eTYPE_DRAGON_FIREBALL },
|
||||
{ L"fireworks_rocket", eTYPE_FIREWORKS_ROCKET },
|
||||
{ L"eyeofender", eTYPE_EYEOFENDERSIGNAL },
|
||||
// hanging
|
||||
{ L"painting", eTYPE_PAINTING },
|
||||
{ L"item_frame", eTYPE_ITEM_FRAME },
|
||||
{ L"leash_knot", eTYPE_LEASHFENCEKNOT },
|
||||
// others
|
||||
{ L"item", eTYPE_ITEMENTITY },
|
||||
{ L"xp_orb", eTYPE_EXPERIENCEORB },
|
||||
{ L"boat", eTYPE_BOAT },
|
||||
{ L"tnt", eTYPE_PRIMEDTNT },
|
||||
{ L"falling_block", eTYPE_FALLINGTILE },
|
||||
{ L"armor_stand", eTYPE_ARMORSTAND },
|
||||
{ L"ender_crystal", eTYPE_ENDER_CRYSTAL },
|
||||
{ L"lightning_bolt", eTYPE_LIGHTNINGBOLT },
|
||||
};
|
||||
|
||||
static const unordered_map<eINSTANCEOF, wstring> s_typeToName = []()
|
||||
{
|
||||
unordered_map<eINSTANCEOF, wstring> m;
|
||||
for (auto& pair : s_nameToType)
|
||||
{
|
||||
if (m.find(pair.second) == m.end())
|
||||
m[pair.second] = pair.first;
|
||||
}
|
||||
return m;
|
||||
}();
|
||||
|
||||
const unordered_map<wstring, eINSTANCEOF>& EntityTypeMap::getNameToTypeMap()
|
||||
{
|
||||
return s_nameToType;
|
||||
}
|
||||
|
||||
const unordered_map<eINSTANCEOF, wstring>& EntityTypeMap::getTypeToNameMap()
|
||||
{
|
||||
return s_typeToName;
|
||||
}
|
||||
|
||||
eINSTANCEOF EntityTypeMap::getTypeFromName(const wstring& name)
|
||||
{
|
||||
wstring lower = name;
|
||||
transform(lower.begin(), lower.end(), lower.begin(), towlower);
|
||||
auto it = s_nameToType.find(lower);
|
||||
if (it != s_nameToType.end())
|
||||
return it->second;
|
||||
return eTYPE_NOTSET;
|
||||
}
|
||||
|
||||
wstring EntityTypeMap::getNameFromType(eINSTANCEOF type)
|
||||
{
|
||||
auto it = s_typeToName.find(type);
|
||||
if (it != s_typeToName.end())
|
||||
return it->second;
|
||||
return L"";
|
||||
}
|
||||
|
||||
bool EntityTypeMap::isValidType(const wstring& name)
|
||||
{
|
||||
return getTypeFromName(name) != eTYPE_NOTSET;
|
||||
}
|
||||
21
Minecraft.World/EntityTypeMap.h
Normal file
21
Minecraft.World/EntityTypeMap.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include "../Minecraft.World/Class.h"
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
class EntityTypeMap
|
||||
{
|
||||
public:
|
||||
|
||||
static eINSTANCEOF getTypeFromName(const wstring& name);
|
||||
|
||||
static wstring getNameFromType(eINSTANCEOF type);
|
||||
|
||||
|
||||
static bool isValidType(const wstring& name);
|
||||
|
||||
private:
|
||||
static const unordered_map<wstring, eINSTANCEOF>& getNameToTypeMap();
|
||||
static const unordered_map<eINSTANCEOF, wstring>& getTypeToNameMap();
|
||||
};
|
||||
|
|
@ -1,26 +1,197 @@
|
|||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.commands.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.damagesource.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "BasicTypeContainers.h"
|
||||
#include "KillCommand.h"
|
||||
#include "EntityTypeMap.h"
|
||||
|
||||
|
||||
static void killEntity(shared_ptr<Entity> entity)
|
||||
{
|
||||
if (entity->instanceof(eTYPE_LIVINGENTITY))
|
||||
{
|
||||
auto living = dynamic_pointer_cast<LivingEntity>(entity);
|
||||
if (living != nullptr)
|
||||
{
|
||||
living->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
|
||||
return;
|
||||
}
|
||||
|
||||
entity->remove();
|
||||
return;
|
||||
}
|
||||
entity->remove();
|
||||
}
|
||||
|
||||
EGameCommand KillCommand::getId()
|
||||
{
|
||||
return eGameCommand_Kill;
|
||||
return eGameCommand_Kill;
|
||||
}
|
||||
|
||||
int KillCommand::getPermissionLevel()
|
||||
{
|
||||
return LEVEL_ALL;
|
||||
return LEVEL_ALL;
|
||||
}
|
||||
|
||||
void KillCommand::execute(shared_ptr<CommandSender> source, byteArray commandData)
|
||||
{
|
||||
shared_ptr<Player> player = dynamic_pointer_cast<Player>(source);
|
||||
shared_ptr<Player> senderPlayer = dynamic_pointer_cast<Player>(source);
|
||||
if (senderPlayer == nullptr)
|
||||
return;
|
||||
|
||||
player->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
|
||||
Level *level = senderPlayer->level;
|
||||
if (level == nullptr)
|
||||
return;
|
||||
|
||||
source->sendMessage(L"Ouch. That look like it hurt.");
|
||||
//source.sendMessage(ChatMessageComponent.forTranslation("commands.kill.success"));
|
||||
|
||||
//nothing is the same of @s
|
||||
if (commandData.length == 0 || commandData.data == nullptr)
|
||||
{
|
||||
senderPlayer->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayInputStream bais(commandData);
|
||||
DataInputStream dis(&bais);
|
||||
wstring targetName = dis.readUTF();
|
||||
|
||||
wstring targetLower = targetName;
|
||||
transform(targetLower.begin(), targetLower.end(), targetLower.begin(), towlower);
|
||||
|
||||
//@s
|
||||
if (targetLower == L"@s")
|
||||
{
|
||||
senderPlayer->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
|
||||
return;
|
||||
}
|
||||
|
||||
//@a
|
||||
if (targetLower == L"@a")
|
||||
{
|
||||
vector<shared_ptr<Player>> toKill;
|
||||
for (auto& p : level->players)
|
||||
if (p != nullptr && !p->removed)
|
||||
toKill.push_back(p);
|
||||
for (auto& p : toKill)
|
||||
p->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
|
||||
return;
|
||||
}
|
||||
|
||||
//@p
|
||||
if (targetLower == L"@p")
|
||||
{
|
||||
shared_ptr<Player> nearest = level->getNearestPlayer(
|
||||
dynamic_pointer_cast<Entity>(senderPlayer), 9999.0);
|
||||
if (nearest != nullptr)
|
||||
{
|
||||
nearest->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
|
||||
source->sendMessage(L"Killed " + nearest->getName() + L".");
|
||||
}
|
||||
else
|
||||
{
|
||||
source->sendMessage(L"No player found.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//@r
|
||||
if (targetLower == L"@r")
|
||||
{
|
||||
if (level->players.empty())
|
||||
{
|
||||
source->sendMessage(L"No player found.");
|
||||
return;
|
||||
}
|
||||
int idx = rand() % (int)level->players.size();
|
||||
auto& p = level->players[idx];
|
||||
if (p != nullptr && !p->removed)
|
||||
{
|
||||
p->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
|
||||
source->sendMessage(L"Killed " + p->getName() + L".");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// @e
|
||||
if (targetLower.size() >= 2 && targetLower.substr(0, 2) == L"@e")
|
||||
{
|
||||
eINSTANCEOF filterType = eTYPE_NOTSET;
|
||||
bool invertFilter = false;
|
||||
bool filterIsPlayer = false;
|
||||
|
||||
if (targetLower.size() > 3 && targetLower[2] == L'[')
|
||||
{
|
||||
wstring inner = targetLower.substr(3, targetLower.size() - 4);
|
||||
wstring key = L"type=";
|
||||
size_t pos = inner.find(key);
|
||||
if (pos == wstring::npos)
|
||||
{
|
||||
source->sendMessage(L"Invalid selector syntax. Usage: @e[type=<entity_type>]");
|
||||
return;
|
||||
}
|
||||
|
||||
wstring typeStr = inner.substr(pos + key.size());
|
||||
if (!typeStr.empty() && typeStr[0] == L'!')
|
||||
{
|
||||
invertFilter = true;
|
||||
typeStr = typeStr.substr(1);
|
||||
}
|
||||
|
||||
if (typeStr == L"player")
|
||||
{
|
||||
filterIsPlayer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
filterType = EntityTypeMap::getTypeFromName(typeStr);
|
||||
if (filterType == eTYPE_NOTSET)
|
||||
{
|
||||
source->sendMessage(L"Unknown entity type: " + typeStr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<shared_ptr<Entity>> toKill;
|
||||
for (auto& entity : level->entities)
|
||||
{
|
||||
if (entity == nullptr || entity->removed) continue;
|
||||
|
||||
bool isPlayer = entity->instanceof(eTYPE_PLAYER);
|
||||
|
||||
|
||||
bool matchesFilter;
|
||||
if (filterType == eTYPE_NOTSET && !filterIsPlayer)
|
||||
matchesFilter = true;
|
||||
else if (filterIsPlayer)
|
||||
matchesFilter = isPlayer;
|
||||
else
|
||||
matchesFilter = entity->instanceof(filterType);
|
||||
|
||||
if (invertFilter) matchesFilter = !matchesFilter;
|
||||
|
||||
if (matchesFilter)
|
||||
toKill.push_back(entity);
|
||||
}
|
||||
|
||||
for (auto& entity : toKill)
|
||||
if (!entity->removed)
|
||||
killEntity(entity);
|
||||
|
||||
source->sendMessage(L"Killed " + to_wstring(toKill.size()) + L" entities.");
|
||||
return;
|
||||
}
|
||||
|
||||
// by player name
|
||||
shared_ptr<Player> targetPlayer = level->getPlayerByName(targetName);
|
||||
if (targetPlayer != nullptr)
|
||||
{
|
||||
targetPlayer->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
|
||||
source->sendMessage(L"Killed " + targetName + L".");
|
||||
return;
|
||||
}
|
||||
|
||||
source->sendMessage(L"No entity was found.");
|
||||
}
|
||||
|
|
@ -204,6 +204,8 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_COMMANDS_COMMON
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/ToggleDownfallCommand.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/WeatherCommand.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/net.minecraft.commands.common.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/EntityTypeMap.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/EntityTypeMap.cpp"
|
||||
)
|
||||
source_group("net/minecraft/commands/common" FILES ${_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_COMMANDS_COMMON})
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue