mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
add: add ban and pardon commands for Player and IP
This commit is contained in:
parent
842ffe2760
commit
8b68b81ffa
|
|
@ -102,7 +102,12 @@ list(APPEND MINECRAFT_SERVER_SOURCES
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/ServerCliParser.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/ServerCliEngine.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/ServerCliRegistry.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandBan.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandBanIp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandBanList.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandHelp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandPardon.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandPardonIp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandStop.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandList.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandTp.cpp"
|
||||
|
|
|
|||
|
|
@ -5,9 +5,14 @@
|
|||
#include "ServerCliParser.h"
|
||||
#include "ServerCliRegistry.h"
|
||||
#include "commands\IServerCliCommand.h"
|
||||
#include "commands\CliCommandBan.h"
|
||||
#include "commands\CliCommandBanIp.h"
|
||||
#include "commands\CliCommandBanList.h"
|
||||
#include "commands\CliCommandGamemode.h"
|
||||
#include "commands\CliCommandHelp.h"
|
||||
#include "commands\CliCommandList.h"
|
||||
#include "commands\CliCommandPardon.h"
|
||||
#include "commands\CliCommandPardonIp.h"
|
||||
#include "commands\CliCommandStop.h"
|
||||
#include "commands\CliCommandTp.h"
|
||||
#include "..\Common\StringUtils.h"
|
||||
|
|
@ -38,6 +43,11 @@ namespace ServerRuntime
|
|||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandHelp()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandStop()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandList()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandBan()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandBanIp()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandPardon()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandPardonIp()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandBanList()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandTp()));
|
||||
m_registry->Register(std::unique_ptr<IServerCliCommand>(new CliCommandGamemode()));
|
||||
}
|
||||
|
|
|
|||
163
Minecraft.Server/Console/commands/CliCommandBan.cpp
Normal file
163
Minecraft.Server/Console/commands/CliCommandBan.cpp
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include "CliCommandBan.h"
|
||||
|
||||
#include "..\ServerCliEngine.h"
|
||||
#include "..\ServerCliParser.h"
|
||||
#include "..\..\Access\Access.h"
|
||||
#include "..\..\Common\StringUtils.h"
|
||||
#include "..\..\..\Minecraft.Client\PlayerConnection.h"
|
||||
#include "..\..\..\Minecraft.Client\ServerPlayer.h"
|
||||
#include "..\..\..\Minecraft.World\DisconnectPacket.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static std::string JoinTokens(const std::vector<std::string> &tokens, size_t startIndex)
|
||||
{
|
||||
std::string joined;
|
||||
for (size_t i = startIndex; i < tokens.size(); ++i)
|
||||
{
|
||||
if (!joined.empty())
|
||||
{
|
||||
joined.push_back(' ');
|
||||
}
|
||||
joined += tokens[i];
|
||||
}
|
||||
return joined;
|
||||
}
|
||||
|
||||
static void AppendUniqueXuid(PlayerUID xuid, std::vector<PlayerUID> *out)
|
||||
{
|
||||
if (out == NULL || xuid == INVALID_XUID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::find(out->begin(), out->end(), xuid) == out->end())
|
||||
{
|
||||
out->push_back(xuid);
|
||||
}
|
||||
}
|
||||
|
||||
static void CollectPlayerBanXuids(const std::shared_ptr<ServerPlayer> &player, std::vector<PlayerUID> *out)
|
||||
{
|
||||
if (player == NULL || out == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep both identity variants because the dedicated server checks login and online XUIDs separately.
|
||||
AppendUniqueXuid(player->getXuid(), out);
|
||||
AppendUniqueXuid(player->getOnlineXuid(), out);
|
||||
}
|
||||
}
|
||||
|
||||
const char *CliCommandBan::Name() const
|
||||
{
|
||||
return "ban";
|
||||
}
|
||||
|
||||
const char *CliCommandBan::Usage() const
|
||||
{
|
||||
return "ban <player> [reason ...]";
|
||||
}
|
||||
|
||||
const char *CliCommandBan::Description() const
|
||||
{
|
||||
return "Ban an online player.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the live player, writes one or more Access ban entries, and disconnects the target with the banned reason
|
||||
* 対象プレイヤーを解決してBANを保存し切断する
|
||||
*/
|
||||
bool CliCommandBan::Execute(const ServerCliParsedLine &line, ServerCliEngine *engine)
|
||||
{
|
||||
if (line.tokens.size() < 2)
|
||||
{
|
||||
engine->LogWarn("Usage: ban <player> [reason ...]");
|
||||
return false;
|
||||
}
|
||||
if (!ServerRuntime::Access::IsInitialized())
|
||||
{
|
||||
engine->LogWarn("Access manager is not initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<ServerPlayer> target = engine->FindPlayerByNameUtf8(line.tokens[1]);
|
||||
if (target == NULL)
|
||||
{
|
||||
engine->LogWarn("Unknown player: " + line.tokens[1] + " (this server build can only ban players that are currently online).");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<PlayerUID> xuids;
|
||||
CollectPlayerBanXuids(target, &xuids);
|
||||
if (xuids.empty())
|
||||
{
|
||||
engine->LogWarn("Cannot ban that player because no valid XUID is available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasUnbannedIdentity = false;
|
||||
for (size_t i = 0; i < xuids.size(); ++i)
|
||||
{
|
||||
if (!ServerRuntime::Access::IsPlayerBanned(xuids[i]))
|
||||
{
|
||||
hasUnbannedIdentity = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasUnbannedIdentity)
|
||||
{
|
||||
engine->LogWarn("That player is already banned.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ServerRuntime::Access::BanMetadata metadata = ServerRuntime::Access::BanManager::BuildDefaultMetadata("Console");
|
||||
metadata.reason = JoinTokens(line.tokens, 2);
|
||||
if (metadata.reason.empty())
|
||||
{
|
||||
metadata.reason = "Banned by an operator.";
|
||||
}
|
||||
|
||||
const std::string playerName = StringUtils::WideToUtf8(target->getName());
|
||||
for (size_t i = 0; i < xuids.size(); ++i)
|
||||
{
|
||||
if (ServerRuntime::Access::IsPlayerBanned(xuids[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ServerRuntime::Access::AddPlayerBan(xuids[i], playerName, metadata))
|
||||
{
|
||||
engine->LogError("Failed to write player ban.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (target->connection != NULL)
|
||||
{
|
||||
target->connection->disconnect(DisconnectPacket::eDisconnect_Banned);
|
||||
}
|
||||
|
||||
engine->LogInfo("Banned player " + playerName + ".");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests currently connected player names for the Java-style player argument
|
||||
* プレイヤー引数の補完候補を返す
|
||||
*/
|
||||
void CliCommandBan::Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const
|
||||
{
|
||||
if (context.currentTokenIndex == 1)
|
||||
{
|
||||
engine->SuggestPlayers(context.prefix, context.linePrefix, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Minecraft.Server/Console/commands/CliCommandBan.h
Normal file
20
Minecraft.Server/Console/commands/CliCommandBan.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "IServerCliCommand.h"
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
/**
|
||||
* Applies a dedicated-server player ban using Java Edition style syntax and Access-backed persistence
|
||||
* Java Edition 風の ban コマンドで永続プレイヤーBANを行う
|
||||
*/
|
||||
class CliCommandBan : public IServerCliCommand
|
||||
{
|
||||
public:
|
||||
virtual const char *Name() const;
|
||||
virtual const char *Usage() const;
|
||||
virtual const char *Description() const;
|
||||
virtual bool Execute(const ServerCliParsedLine &line, ServerCliEngine *engine);
|
||||
virtual void Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const;
|
||||
};
|
||||
}
|
||||
206
Minecraft.Server/Console/commands/CliCommandBanIp.cpp
Normal file
206
Minecraft.Server/Console/commands/CliCommandBanIp.cpp
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include "CliCommandBanIp.h"
|
||||
|
||||
#include "..\ServerCliEngine.h"
|
||||
#include "..\ServerCliParser.h"
|
||||
#include "..\..\Access\Access.h"
|
||||
#include "..\..\Common\StringUtils.h"
|
||||
#include "..\..\ServerLogManager.h"
|
||||
#include "..\..\..\Minecraft.Client\MinecraftServer.h"
|
||||
#include "..\..\..\Minecraft.Client\PlayerConnection.h"
|
||||
#include "..\..\..\Minecraft.Client\PlayerList.h"
|
||||
#include "..\..\..\Minecraft.Client\ServerPlayer.h"
|
||||
#include "..\..\..\Minecraft.World\Connection.h"
|
||||
#include "..\..\..\Minecraft.World\DisconnectPacket.h"
|
||||
|
||||
#include <WS2tcpip.h>
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static std::string JoinTokens(const std::vector<std::string> &tokens, size_t startIndex)
|
||||
{
|
||||
std::string joined;
|
||||
for (size_t i = startIndex; i < tokens.size(); ++i)
|
||||
{
|
||||
if (!joined.empty())
|
||||
{
|
||||
joined.push_back(' ');
|
||||
}
|
||||
joined += tokens[i];
|
||||
}
|
||||
return joined;
|
||||
}
|
||||
|
||||
// Compare IPs in a canonical lowercase form so literal input and cached values match reliably.
|
||||
static std::string NormalizeIpToken(const std::string &ip)
|
||||
{
|
||||
return StringUtils::ToLowerAscii(StringUtils::TrimAscii(ip));
|
||||
}
|
||||
|
||||
// Accept both IPv4 and IPv6 literals because Java Edition style ban-ip can target either form.
|
||||
static bool IsIpLiteral(const std::string &text)
|
||||
{
|
||||
const std::string trimmed = StringUtils::TrimAscii(text);
|
||||
if (trimmed.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IN_ADDR ipv4 = {};
|
||||
IN6_ADDR ipv6 = {};
|
||||
return InetPtonA(AF_INET, trimmed.c_str(), &ipv4) == 1 || InetPtonA(AF_INET6, trimmed.c_str(), &ipv6) == 1;
|
||||
}
|
||||
|
||||
// The dedicated server keeps the accepted remote IP in ServerLogManager, keyed by connection smallId.
|
||||
// It's a bit strange from a responsibility standpoint, so we'll need to implement it separately.
|
||||
static bool TryGetPlayerRemoteIp(const std::shared_ptr<ServerPlayer> &player, std::string *outIp)
|
||||
{
|
||||
if (outIp == NULL || player == NULL || player->connection == NULL || player->connection->connection == NULL || player->connection->connection->getSocket() == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char smallId = player->connection->connection->getSocket()->getSmallId();
|
||||
if (smallId == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ServerRuntime::ServerLogManager::TryGetConnectionRemoteIp(smallId, outIp);
|
||||
}
|
||||
|
||||
// After persisting the ban, walk a snapshot of current players so every matching session is removed.
|
||||
static int DisconnectPlayersByRemoteIp(const std::string &ip)
|
||||
{
|
||||
MinecraftServer *server = MinecraftServer::getInstance();
|
||||
if (server == NULL || server->getPlayers() == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string normalizedIp = NormalizeIpToken(ip);
|
||||
std::vector<std::shared_ptr<ServerPlayer> > playerSnapshot = server->getPlayers()->players;
|
||||
int disconnectedCount = 0;
|
||||
for (size_t i = 0; i < playerSnapshot.size(); ++i)
|
||||
{
|
||||
std::shared_ptr<ServerPlayer> player = playerSnapshot[i];
|
||||
std::string playerIp;
|
||||
if (!TryGetPlayerRemoteIp(player, &playerIp))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NormalizeIpToken(playerIp) == normalizedIp)
|
||||
{
|
||||
if (player != NULL && player->connection != NULL)
|
||||
{
|
||||
player->connection->disconnect(DisconnectPacket::eDisconnect_Banned);
|
||||
++disconnectedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return disconnectedCount;
|
||||
}
|
||||
}
|
||||
|
||||
const char *CliCommandBanIp::Name() const
|
||||
{
|
||||
return "ban-ip";
|
||||
}
|
||||
|
||||
const char *CliCommandBanIp::Usage() const
|
||||
{
|
||||
return "ban-ip <address|player> [reason ...]";
|
||||
}
|
||||
|
||||
const char *CliCommandBanIp::Description() const
|
||||
{
|
||||
return "Ban an IP address or a player's current IP.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves either a literal IP or an online player's current IP, persists the ban, and disconnects every matching connection
|
||||
* IPまたは接続中プレイヤーの現在IPをBANし一致する接続を切断する
|
||||
*/
|
||||
bool CliCommandBanIp::Execute(const ServerCliParsedLine &line, ServerCliEngine *engine)
|
||||
{
|
||||
if (line.tokens.size() < 2)
|
||||
{
|
||||
engine->LogWarn("Usage: ban-ip <address|player> [reason ...]");
|
||||
return false;
|
||||
}
|
||||
if (!ServerRuntime::Access::IsInitialized())
|
||||
{
|
||||
engine->LogWarn("Access manager is not initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string targetToken = line.tokens[1];
|
||||
std::string remoteIp;
|
||||
// Match Java Edition behavior by accepting either a literal IP or an online player name.
|
||||
std::shared_ptr<ServerPlayer> targetPlayer = engine->FindPlayerByNameUtf8(targetToken);
|
||||
if (targetPlayer != NULL)
|
||||
{
|
||||
if (!TryGetPlayerRemoteIp(targetPlayer, &remoteIp))
|
||||
{
|
||||
engine->LogWarn("Cannot ban that player's IP because no current remote IP is available.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (IsIpLiteral(targetToken))
|
||||
{
|
||||
remoteIp = StringUtils::TrimAscii(targetToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->LogWarn("Unknown player or invalid IP address: " + targetToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Refuse duplicate bans so operators get immediate feedback instead of rewriting the same entry.
|
||||
if (ServerRuntime::Access::IsIpBanned(remoteIp))
|
||||
{
|
||||
engine->LogWarn("That IP address is already banned.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ServerRuntime::Access::BanMetadata metadata = ServerRuntime::Access::BanManager::BuildDefaultMetadata("Console");
|
||||
metadata.reason = JoinTokens(line.tokens, 2);
|
||||
if (metadata.reason.empty())
|
||||
{
|
||||
metadata.reason = "Banned by an operator.";
|
||||
}
|
||||
|
||||
// Publish the ban before disconnecting players so reconnect attempts are rejected immediately.
|
||||
if (!ServerRuntime::Access::AddIpBan(remoteIp, metadata))
|
||||
{
|
||||
engine->LogError("Failed to write IP ban.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int disconnectedCount = DisconnectPlayersByRemoteIp(remoteIp);
|
||||
// Report the resolved IP rather than the original token so player-name targets are explicit in the console.
|
||||
engine->LogInfo("Banned IP address " + remoteIp + ".");
|
||||
if (disconnectedCount > 0)
|
||||
{
|
||||
engine->LogInfo("Disconnected " + std::to_string(disconnectedCount) + " player(s) with that IP.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests online player names for the player-target form of the Java Edition command
|
||||
* プレイヤー名指定時の補完候補を返す
|
||||
*/
|
||||
void CliCommandBanIp::Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const
|
||||
{
|
||||
if (context.currentTokenIndex == 1)
|
||||
{
|
||||
engine->SuggestPlayers(context.prefix, context.linePrefix, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Minecraft.Server/Console/commands/CliCommandBanIp.h
Normal file
19
Minecraft.Server/Console/commands/CliCommandBanIp.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "IServerCliCommand.h"
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
/**
|
||||
* Applies a dedicated-server IP ban using Java Edition style syntax and Access-backed persistence
|
||||
*/
|
||||
class CliCommandBanIp : public IServerCliCommand
|
||||
{
|
||||
public:
|
||||
virtual const char *Name() const;
|
||||
virtual const char *Usage() const;
|
||||
virtual const char *Description() const;
|
||||
virtual bool Execute(const ServerCliParsedLine &line, ServerCliEngine *engine);
|
||||
virtual void Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const;
|
||||
};
|
||||
}
|
||||
135
Minecraft.Server/Console/commands/CliCommandBanList.cpp
Normal file
135
Minecraft.Server/Console/commands/CliCommandBanList.cpp
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include "CliCommandBanList.h"
|
||||
|
||||
#include "..\ServerCliEngine.h"
|
||||
#include "..\ServerCliParser.h"
|
||||
#include "..\..\Access\Access.h"
|
||||
#include "..\..\Common\StringUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static void AppendUniqueText(const std::string &text, std::vector<std::string> *out)
|
||||
{
|
||||
if (out == NULL || text.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::find(out->begin(), out->end(), text) == out->end())
|
||||
{
|
||||
out->push_back(text);
|
||||
}
|
||||
}
|
||||
|
||||
static bool CompareLowerAscii(const std::string &left, const std::string &right)
|
||||
{
|
||||
return StringUtils::ToLowerAscii(left) < StringUtils::ToLowerAscii(right);
|
||||
}
|
||||
|
||||
static bool LogBannedPlayers(ServerCliEngine *engine)
|
||||
{
|
||||
std::vector<ServerRuntime::Access::BannedPlayerEntry> entries;
|
||||
if (!ServerRuntime::Access::SnapshotBannedPlayers(&entries))
|
||||
{
|
||||
engine->LogError("Failed to read banned players.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> names;
|
||||
for (size_t i = 0; i < entries.size(); ++i)
|
||||
{
|
||||
AppendUniqueText(entries[i].name, &names);
|
||||
}
|
||||
std::sort(names.begin(), names.end(), CompareLowerAscii);
|
||||
|
||||
engine->LogInfo("There are " + std::to_string(names.size()) + " banned player(s).");
|
||||
for (size_t i = 0; i < names.size(); ++i)
|
||||
{
|
||||
engine->LogInfo(" " + names[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LogBannedIps(ServerCliEngine *engine)
|
||||
{
|
||||
std::vector<ServerRuntime::Access::BannedIpEntry> entries;
|
||||
if (!ServerRuntime::Access::SnapshotBannedIps(&entries))
|
||||
{
|
||||
engine->LogError("Failed to read banned IPs.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> ips;
|
||||
for (size_t i = 0; i < entries.size(); ++i)
|
||||
{
|
||||
AppendUniqueText(entries[i].ip, &ips);
|
||||
}
|
||||
std::sort(ips.begin(), ips.end(), CompareLowerAscii);
|
||||
|
||||
engine->LogInfo("There are " + std::to_string(ips.size()) + " banned IP(s).");
|
||||
for (size_t i = 0; i < ips.size(); ++i)
|
||||
{
|
||||
engine->LogInfo(" " + ips[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LogAllBans(ServerCliEngine *engine)
|
||||
{
|
||||
if (!LogBannedPlayers(engine))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Always print the IP snapshot as well so ban-ip entries are visible from the same command output.
|
||||
return LogBannedIps(engine);
|
||||
}
|
||||
}
|
||||
|
||||
const char *CliCommandBanList::Name() const
|
||||
{
|
||||
return "banlist";
|
||||
}
|
||||
|
||||
const char *CliCommandBanList::Usage() const
|
||||
{
|
||||
return "banlist";
|
||||
}
|
||||
|
||||
const char *CliCommandBanList::Description() const
|
||||
{
|
||||
return "List all banned players and IPs.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the current Access snapshots and always prints both banned players and banned IPs
|
||||
* Access の一覧を読みプレイヤーBANとIP BANをまとめて表示する
|
||||
*/
|
||||
bool CliCommandBanList::Execute(const ServerCliParsedLine &line, ServerCliEngine *engine)
|
||||
{
|
||||
if (line.tokens.size() > 1)
|
||||
{
|
||||
engine->LogWarn("Usage: banlist");
|
||||
return false;
|
||||
}
|
||||
if (!ServerRuntime::Access::IsInitialized())
|
||||
{
|
||||
engine->LogWarn("Access manager is not initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return LogAllBans(engine);
|
||||
}
|
||||
|
||||
void CliCommandBanList::Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const
|
||||
{
|
||||
(void)context;
|
||||
(void)engine;
|
||||
(void)out;
|
||||
}
|
||||
}
|
||||
22
Minecraft.Server/Console/commands/CliCommandBanList.h
Normal file
22
Minecraft.Server/Console/commands/CliCommandBanList.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "IServerCliCommand.h"
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
/**
|
||||
* **Ban List Command**
|
||||
*
|
||||
* Lists dedicated-server player bans and IP bans in a single command output
|
||||
* 専用サーバーのプレイヤーBANとIP BANをまとめて表示する
|
||||
*/
|
||||
class CliCommandBanList : public IServerCliCommand
|
||||
{
|
||||
public:
|
||||
virtual const char *Name() const;
|
||||
virtual const char *Usage() const;
|
||||
virtual const char *Description() const;
|
||||
virtual bool Execute(const ServerCliParsedLine &line, ServerCliEngine *engine);
|
||||
virtual void Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const;
|
||||
};
|
||||
}
|
||||
173
Minecraft.Server/Console/commands/CliCommandPardon.cpp
Normal file
173
Minecraft.Server/Console/commands/CliCommandPardon.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include "CliCommandPardon.h"
|
||||
|
||||
#include "..\ServerCliEngine.h"
|
||||
#include "..\ServerCliParser.h"
|
||||
#include "..\..\Access\Access.h"
|
||||
#include "..\..\Common\StringUtils.h"
|
||||
#include "..\..\..\Minecraft.Client\ServerPlayer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static void AppendUniqueText(const std::string &text, std::vector<std::string> *out)
|
||||
{
|
||||
if (out == NULL || text.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::find(out->begin(), out->end(), text) == out->end())
|
||||
{
|
||||
out->push_back(text);
|
||||
}
|
||||
}
|
||||
|
||||
static void AppendUniqueXuid(PlayerUID xuid, std::vector<PlayerUID> *out)
|
||||
{
|
||||
if (out == NULL || xuid == INVALID_XUID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::find(out->begin(), out->end(), xuid) == out->end())
|
||||
{
|
||||
out->push_back(xuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *CliCommandPardon::Name() const
|
||||
{
|
||||
return "pardon";
|
||||
}
|
||||
|
||||
const char *CliCommandPardon::Usage() const
|
||||
{
|
||||
return "pardon <player>";
|
||||
}
|
||||
|
||||
const char *CliCommandPardon::Description() const
|
||||
{
|
||||
return "Remove a player ban.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes every Access ban entry that matches the requested player name so dual-XUID entries are cleared together
|
||||
* 名前に一致するBANをまとめて解除する
|
||||
*/
|
||||
bool CliCommandPardon::Execute(const ServerCliParsedLine &line, ServerCliEngine *engine)
|
||||
{
|
||||
if (line.tokens.size() != 2)
|
||||
{
|
||||
engine->LogWarn("Usage: pardon <player>");
|
||||
return false;
|
||||
}
|
||||
if (!ServerRuntime::Access::IsInitialized())
|
||||
{
|
||||
engine->LogWarn("Access manager is not initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<PlayerUID> xuidsToRemove;
|
||||
std::vector<std::string> matchedNames;
|
||||
std::shared_ptr<ServerPlayer> onlineTarget = engine->FindPlayerByNameUtf8(line.tokens[1]);
|
||||
if (onlineTarget != NULL)
|
||||
{
|
||||
if (ServerRuntime::Access::IsPlayerBanned(onlineTarget->getXuid()))
|
||||
{
|
||||
AppendUniqueXuid(onlineTarget->getXuid(), &xuidsToRemove);
|
||||
}
|
||||
if (ServerRuntime::Access::IsPlayerBanned(onlineTarget->getOnlineXuid()))
|
||||
{
|
||||
AppendUniqueXuid(onlineTarget->getOnlineXuid(), &xuidsToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ServerRuntime::Access::BannedPlayerEntry> entries;
|
||||
if (!ServerRuntime::Access::SnapshotBannedPlayers(&entries))
|
||||
{
|
||||
engine->LogError("Failed to read banned players.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string loweredTarget = StringUtils::ToLowerAscii(line.tokens[1]);
|
||||
for (size_t i = 0; i < entries.size(); ++i)
|
||||
{
|
||||
if (StringUtils::ToLowerAscii(entries[i].name) == loweredTarget)
|
||||
{
|
||||
unsigned long long numericXuid = _strtoui64(entries[i].xuid.c_str(), NULL, 0);
|
||||
if (numericXuid != 0ULL)
|
||||
{
|
||||
AppendUniqueXuid((PlayerUID)numericXuid, &xuidsToRemove);
|
||||
}
|
||||
AppendUniqueText(entries[i].name, &matchedNames);
|
||||
}
|
||||
}
|
||||
|
||||
if (xuidsToRemove.empty())
|
||||
{
|
||||
engine->LogWarn("That player is not banned.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < xuidsToRemove.size(); ++i)
|
||||
{
|
||||
if (!ServerRuntime::Access::RemovePlayerBan(xuidsToRemove[i]))
|
||||
{
|
||||
engine->LogError("Failed to remove player ban.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string playerName = line.tokens[1];
|
||||
if (!matchedNames.empty())
|
||||
{
|
||||
playerName = matchedNames[0];
|
||||
}
|
||||
else if (onlineTarget != NULL)
|
||||
{
|
||||
playerName = StringUtils::WideToUtf8(onlineTarget->getName());
|
||||
}
|
||||
|
||||
engine->LogInfo("Unbanned player " + playerName + ".");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests currently banned player names first and then online names for convenience
|
||||
* BAN済み名とオンライン名を補完候補に出す
|
||||
*/
|
||||
void CliCommandPardon::Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const
|
||||
{
|
||||
if (context.currentTokenIndex != 1 || out == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<ServerRuntime::Access::BannedPlayerEntry> entries;
|
||||
if (ServerRuntime::Access::SnapshotBannedPlayers(&entries))
|
||||
{
|
||||
const std::string loweredPrefix = StringUtils::ToLowerAscii(context.prefix);
|
||||
std::vector<std::string> names;
|
||||
for (size_t i = 0; i < entries.size(); ++i)
|
||||
{
|
||||
AppendUniqueText(entries[i].name, &names);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < names.size(); ++i)
|
||||
{
|
||||
if (StringUtils::ToLowerAscii(names[i]).compare(0, loweredPrefix.size(), loweredPrefix) == 0)
|
||||
{
|
||||
out->push_back(context.linePrefix + names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
engine->SuggestPlayers(context.prefix, context.linePrefix, out);
|
||||
}
|
||||
}
|
||||
19
Minecraft.Server/Console/commands/CliCommandPardon.h
Normal file
19
Minecraft.Server/Console/commands/CliCommandPardon.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "IServerCliCommand.h"
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
/**
|
||||
* Removes dedicated-server player bans using Java Edition style syntax and Access-backed persistence
|
||||
*/
|
||||
class CliCommandPardon : public IServerCliCommand
|
||||
{
|
||||
public:
|
||||
virtual const char *Name() const;
|
||||
virtual const char *Usage() const;
|
||||
virtual const char *Description() const;
|
||||
virtual bool Execute(const ServerCliParsedLine &line, ServerCliEngine *engine);
|
||||
virtual void Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const;
|
||||
};
|
||||
}
|
||||
116
Minecraft.Server/Console/commands/CliCommandPardonIp.cpp
Normal file
116
Minecraft.Server/Console/commands/CliCommandPardonIp.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include "CliCommandPardonIp.h"
|
||||
|
||||
#include "..\ServerCliEngine.h"
|
||||
#include "..\ServerCliParser.h"
|
||||
#include "..\..\Access\Access.h"
|
||||
#include "..\..\Common\StringUtils.h"
|
||||
|
||||
#include <WS2tcpip.h>
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Keep validation shared with ban-ip so both commands agree on what counts as a literal address.
|
||||
static bool IsIpLiteral(const std::string &text)
|
||||
{
|
||||
const std::string trimmed = StringUtils::TrimAscii(text);
|
||||
if (trimmed.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IN_ADDR ipv4 = {};
|
||||
IN6_ADDR ipv6 = {};
|
||||
return InetPtonA(AF_INET, trimmed.c_str(), &ipv4) == 1 || InetPtonA(AF_INET6, trimmed.c_str(), &ipv6) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
const char *CliCommandPardonIp::Name() const
|
||||
{
|
||||
return "pardon-ip";
|
||||
}
|
||||
|
||||
const char *CliCommandPardonIp::Usage() const
|
||||
{
|
||||
return "pardon-ip <address>";
|
||||
}
|
||||
|
||||
const char *CliCommandPardonIp::Description() const
|
||||
{
|
||||
return "Remove an IP ban.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the literal IP argument and removes the matching Access IP ban entry
|
||||
* リテラルIPを検証して一致するIP BANを解除する
|
||||
*/
|
||||
bool CliCommandPardonIp::Execute(const ServerCliParsedLine &line, ServerCliEngine *engine)
|
||||
{
|
||||
if (line.tokens.size() != 2)
|
||||
{
|
||||
engine->LogWarn("Usage: pardon-ip <address>");
|
||||
return false;
|
||||
}
|
||||
if (!ServerRuntime::Access::IsInitialized())
|
||||
{
|
||||
engine->LogWarn("Access manager is not initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Java Edition pardon-ip only operates on a literal address, so do not resolve player names here.
|
||||
const std::string ip = StringUtils::TrimAscii(line.tokens[1]);
|
||||
if (!IsIpLiteral(ip))
|
||||
{
|
||||
engine->LogWarn("Invalid IP address: " + line.tokens[1]);
|
||||
return false;
|
||||
}
|
||||
// Distinguish invalid input from a valid but currently unbanned address for clearer operator feedback.
|
||||
if (!ServerRuntime::Access::IsIpBanned(ip))
|
||||
{
|
||||
engine->LogWarn("That IP address is not banned.");
|
||||
return false;
|
||||
}
|
||||
if (!ServerRuntime::Access::RemoveIpBan(ip))
|
||||
{
|
||||
engine->LogError("Failed to remove IP ban.");
|
||||
return false;
|
||||
}
|
||||
|
||||
engine->LogInfo("Unbanned IP address " + ip + ".");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests currently banned IP addresses for the Java Edition literal-IP argument
|
||||
* BAN済みIPの補完候補を返す
|
||||
*/
|
||||
void CliCommandPardonIp::Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const
|
||||
{
|
||||
(void)engine;
|
||||
// Complete from the persisted IP-ban snapshot because this command only accepts already-banned literals.
|
||||
if (context.currentTokenIndex != 1 || out == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<ServerRuntime::Access::BannedIpEntry> entries;
|
||||
if (!ServerRuntime::Access::SnapshotBannedIps(&entries))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Reuse the normalized prefix match used by other commands so completion stays case-insensitive.
|
||||
const std::string loweredPrefix = StringUtils::ToLowerAscii(context.prefix);
|
||||
for (size_t i = 0; i < entries.size(); ++i)
|
||||
{
|
||||
const std::string candidate = entries[i].ip;
|
||||
if (StringUtils::ToLowerAscii(candidate).compare(0, loweredPrefix.size(), loweredPrefix) == 0)
|
||||
{
|
||||
out->push_back(context.linePrefix + candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Minecraft.Server/Console/commands/CliCommandPardonIp.h
Normal file
19
Minecraft.Server/Console/commands/CliCommandPardonIp.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "IServerCliCommand.h"
|
||||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
/**
|
||||
* Removes a dedicated-server IP ban using Java Edition style syntax and Access-backed persistence
|
||||
*/
|
||||
class CliCommandPardonIp : public IServerCliCommand
|
||||
{
|
||||
public:
|
||||
virtual const char *Name() const;
|
||||
virtual const char *Usage() const;
|
||||
virtual const char *Description() const;
|
||||
virtual bool Execute(const ServerCliParsedLine &line, ServerCliEngine *engine);
|
||||
virtual void Complete(const ServerCliCompletionContext &context, const ServerCliEngine *engine, std::vector<std::string> *out) const;
|
||||
};
|
||||
}
|
||||
|
|
@ -652,9 +652,14 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="Console\ServerCli.cpp" />
|
||||
<ClCompile Include="Console\ServerCliInput.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandBan.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandBanIp.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandBanList.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandGamemode.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandHelp.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandList.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandPardon.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandPardonIp.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandStop.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandTp.cpp" />
|
||||
<ClCompile Include="Console\ServerCliEngine.cpp" />
|
||||
|
|
@ -681,9 +686,14 @@
|
|||
<ClInclude Include="Access\BanManager.h" />
|
||||
<ClInclude Include="Console\ServerCli.h" />
|
||||
<ClInclude Include="Console\ServerCliInput.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandBan.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandBanIp.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandBanList.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandGamemode.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandHelp.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandList.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandPardon.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandPardonIp.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandStop.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandTp.h" />
|
||||
<ClInclude Include="Console\commands\IServerCliCommand.h" />
|
||||
|
|
|
|||
|
|
@ -558,6 +558,15 @@
|
|||
<ClCompile Include="..\Minecraft.Client\glWrapper.cpp" />
|
||||
<ClCompile Include="..\Minecraft.Client\stdafx.cpp" />
|
||||
<ClCompile Include="..\Minecraft.Client\stubs.cpp" />
|
||||
<ClCompile Include="Console\commands\CliCommandBan.cpp">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console\commands\CliCommandBanIp.cpp">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console\commands\CliCommandBanList.cpp">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console\commands\CliCommandGamemode.cpp">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -567,6 +576,12 @@
|
|||
<ClCompile Include="Console\commands\CliCommandList.cpp">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console\commands\CliCommandPardon.cpp">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console\commands\CliCommandPardonIp.cpp">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console\commands\CliCommandStop.cpp">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -615,6 +630,15 @@
|
|||
<Filter>Server</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\ServerCliInput.h" />
|
||||
<ClInclude Include="Console\commands\CliCommandBan.h">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\commands\CliCommandBanIp.h">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\commands\CliCommandBanList.h">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\commands\CliCommandGamemode.h">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -624,6 +648,12 @@
|
|||
<ClInclude Include="Console\commands\CliCommandList.h">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\commands\CliCommandPardon.h">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\commands\CliCommandPardonIp.h">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\commands\CliCommandStop.h">
|
||||
<Filter>Server\Console\Commands</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "ServerLogManager.h"
|
||||
|
||||
|
|
@ -367,6 +367,30 @@ namespace ServerRuntime
|
|||
DisconnectReasonToString(reason));
|
||||
}
|
||||
|
||||
/**
|
||||
* For logging purposes, the responsibility is technically misplaced, but the IP is cached in `LogManager`.
|
||||
* Those cached values are then used to retrieve the player's IP.
|
||||
*
|
||||
* Eventually, this should be implemented in a separate class or on the `Minecraft.Client` side instead.
|
||||
*/
|
||||
bool TryGetConnectionRemoteIp(unsigned char smallId, std::string *outIp)
|
||||
{
|
||||
if (!IsDedicatedServerLoggingEnabled() || outIp == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> stateLock(g_serverLogState.stateLock);
|
||||
const ConnectionLogEntry &entry = g_serverLogState.entries[smallId];
|
||||
if (entry.remoteIp.empty() || entry.remoteIp == "unknown")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*outIp = entry.remoteIp;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Provide explicit cache cleanup for paths that terminate without going through disconnect logging.
|
||||
void ClearConnection(unsigned char smallId)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdarg.h>
|
||||
|
|
@ -109,10 +109,18 @@ namespace ServerRuntime
|
|||
DisconnectPacket::eDisconnectReason reason,
|
||||
bool initiatedByServer);
|
||||
|
||||
/**
|
||||
* Reads the cached remote IP for a live smallId without consuming the entry
|
||||
* Eventually, this should be implemented in a separate class or on the `Minecraft.Client` side instead.
|
||||
*
|
||||
* 指定smallIdの接続IPをキャッシュから参照する
|
||||
*/
|
||||
bool TryGetConnectionRemoteIp(unsigned char smallId, std::string *outIp);
|
||||
|
||||
/**
|
||||
* Removes any remembered IP or player name for the specified smallId
|
||||
* 指定smallIdに紐づく接続キャッシュを消去
|
||||
*/
|
||||
void ClearConnection(unsigned char smallId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue