mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-05-17 05:02:53 +00:00
Merge 706afb70d4 into f78dec6e00
This commit is contained in:
commit
5961b0168b
BIN
.github/doxygen-api-logo.png
vendored
Normal file
BIN
.github/doxygen-api-logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
15
.github/workflows/nightly-server.yml
vendored
15
.github/workflows/nightly-server.yml
vendored
|
|
@ -5,6 +5,7 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'feature/plugin-api'
|
||||
paths:
|
||||
- '**'
|
||||
- '!.gitignore'
|
||||
|
|
@ -35,6 +36,15 @@ jobs:
|
|||
- name: Set platform lowercase
|
||||
run: echo "MATRIX_PLATFORM=$('${{ matrix.platform }}'.ToLower())" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Create temporary global.json
|
||||
run: |
|
||||
echo '{"sdk":{"version": "10.0.201"}}' > ./global.json
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: '10.0.201'
|
||||
|
||||
- name: Setup MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
|
|
@ -61,7 +71,10 @@ jobs:
|
|||
- name: Stage exe and pdb
|
||||
if: matrix.platform == 'Windows64'
|
||||
run: |
|
||||
Copy-Item ./build/${{ env.MATRIX_PLATFORM }}/Minecraft.Server/Release/Minecraft.Server.exe staging/
|
||||
Copy-Item @(
|
||||
"./build/${{ env.MATRIX_PLATFORM }}/Minecraft.Server/Release/Minecraft.Server.exe",
|
||||
"./build/${{ env.MATRIX_PLATFORM }}/Minecraft.Server/Release/Minecraft.Server.Fourkit.dll"
|
||||
) staging/
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v6
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -414,3 +414,6 @@ build/
|
|||
tmp*/
|
||||
_server_asset_probe/
|
||||
server-data/
|
||||
|
||||
|
||||
doxygen/
|
||||
|
|
@ -80,6 +80,7 @@ add_subdirectory(Minecraft.World)
|
|||
add_subdirectory(Minecraft.Client)
|
||||
if(PLATFORM_NAME STREQUAL "Windows64") # Server is only supported on Windows for now
|
||||
add_subdirectory(Minecraft.Server)
|
||||
add_subdirectory(Minecraft.Server.FourKit)
|
||||
endif()
|
||||
|
||||
# ---
|
||||
|
|
@ -100,6 +101,7 @@ add_dependencies(Minecraft.World GenerateBuildVer)
|
|||
add_dependencies(Minecraft.Client GenerateBuildVer)
|
||||
if(PLATFORM_NAME STREQUAL "Windows64")
|
||||
add_dependencies(Minecraft.Server GenerateBuildVer)
|
||||
# add_dependencies(Minecraft.Server.FourKit GenerateBuildVer)
|
||||
endif()
|
||||
|
||||
# ---
|
||||
|
|
|
|||
|
|
@ -1795,6 +1795,7 @@ void MinecraftServer::run(int64_t seed, void *lpParameter)
|
|||
|
||||
chunkPacketManagement_PostTick();
|
||||
}
|
||||
lastTime = getCurrentTimeMillis();
|
||||
// int64_t afterall = System::currentTimeMillis();
|
||||
// PIXReportCounter(L"Server time all",(float)(afterall-beforeall));
|
||||
// PIXReportCounter(L"Server ticks",(float)tickcount);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@
|
|||
#include "..\Minecraft.Server\ServerLogManager.h"
|
||||
#include "..\Minecraft.Server\Access\Access.h"
|
||||
#include "..\Minecraft.World\Socket.h"
|
||||
#include <FourKitBridge.h>
|
||||
#include <Windows64/Network/WinsockNetLayer.h>
|
||||
#endif
|
||||
|
||||
// #ifdef __PS3__
|
||||
// #include "PS3\Network\NetworkPlayerSony.h"
|
||||
// #endif
|
||||
|
|
@ -111,6 +114,58 @@ void PendingConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
std::string connectionIp = "";
|
||||
int connectionPort = 0;
|
||||
|
||||
if (!connection || !connection->getSocket()) {
|
||||
goto handlePreLoginEND;
|
||||
}
|
||||
|
||||
unsigned char smallId = connection->getSocket()->getSmallId();
|
||||
if (smallId == 0) {
|
||||
goto handlePreLoginEND;
|
||||
}
|
||||
|
||||
if (!ServerRuntime::ServerLogManager::TryGetConnectionRemoteIp(smallId, &connectionIp))
|
||||
{
|
||||
SOCKET sock = WinsockNetLayer::GetSocketForSmallId(smallId);
|
||||
if (sock != INVALID_SOCKET)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
int addrLen = sizeof(addr);
|
||||
if (getpeername(sock, (sockaddr*)&addr, &addrLen) == 0)
|
||||
{
|
||||
char ipBuf[64] = {};
|
||||
if (inet_ntop(AF_INET, &addr.sin_addr, ipBuf, sizeof(ipBuf)))
|
||||
{
|
||||
connectionIp = ipBuf;
|
||||
connectionPort = (int)ntohs(addr.sin_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (connectionIp.empty()) {
|
||||
goto handlePreLoginEND;
|
||||
}
|
||||
} else {
|
||||
SOCKET sock = WinsockNetLayer::GetSocketForSmallId(smallId);
|
||||
if (sock != INVALID_SOCKET)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
int addrLen = sizeof(addr);
|
||||
if (getpeername(sock, (sockaddr*)&addr, &addrLen) == 0)
|
||||
connectionPort = (int)ntohs(addr.sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
if (FourKitBridge::FirePlayerPreLogin(packet->loginKey, connectionIp, connectionPort)) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
handlePreLoginEND:
|
||||
// printf("Server: handlePreLogin\n");
|
||||
name = packet->loginKey; // 4J Stu - Change from the login packet as we know better on client end during the pre-login packet
|
||||
sendPreLoginResponse();
|
||||
|
|
@ -186,6 +241,60 @@ void PendingConnection::handleLogin(shared_ptr<LoginPacket> packet)
|
|||
//if (true)// 4J removed !server->onlineMode)
|
||||
bool sentDisconnect = false;
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
std::string connectionIp = "";
|
||||
int connectionPort = 0;
|
||||
|
||||
if (!connection || !connection->getSocket()) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char smallId = connection->getSocket()->getSmallId();
|
||||
if (smallId == 0) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ServerRuntime::ServerLogManager::TryGetConnectionRemoteIp(smallId, &connectionIp))
|
||||
{
|
||||
SOCKET sock = WinsockNetLayer::GetSocketForSmallId(smallId);
|
||||
if (sock != INVALID_SOCKET)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
int addrLen = sizeof(addr);
|
||||
if (getpeername(sock, (sockaddr*)&addr, &addrLen) == 0)
|
||||
{
|
||||
char ipBuf[64] = {};
|
||||
if (inet_ntop(AF_INET, &addr.sin_addr, ipBuf, sizeof(ipBuf)))
|
||||
{
|
||||
connectionIp = ipBuf;
|
||||
connectionPort = (int)ntohs(addr.sin_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (connectionIp.empty()) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SOCKET sock = WinsockNetLayer::GetSocketForSmallId(smallId);
|
||||
if (sock != INVALID_SOCKET)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
int addrLen = sizeof(addr);
|
||||
if (getpeername(sock, (sockaddr*)&addr, &addrLen) == 0)
|
||||
connectionPort = (int)ntohs(addr.sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
if (FourKitBridge::FirePlayerLogin(packet->userName, connectionIp, connectionPort, 1, &packet->m_onlineXuid, &packet->m_offlineXuid)) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Use the same Xuid choice as handleAcceptedLogin (offline first, online fallback).
|
||||
//
|
||||
PlayerUID loginXuid = packet->m_offlineXuid;
|
||||
|
|
@ -326,11 +435,65 @@ void PendingConnection::handleAcceptedLogin(shared_ptr<LoginPacket> packet)
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
std::string connectionIp = "";
|
||||
int connectionPort = 0;
|
||||
|
||||
if (!connection || !connection->getSocket()) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char smallId = connection->getSocket()->getSmallId();
|
||||
if (smallId == 0) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ServerRuntime::ServerLogManager::TryGetConnectionRemoteIp(smallId, &connectionIp))
|
||||
{
|
||||
SOCKET sock = WinsockNetLayer::GetSocketForSmallId(smallId);
|
||||
if (sock != INVALID_SOCKET)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
int addrLen = sizeof(addr);
|
||||
if (getpeername(sock, (sockaddr*)&addr, &addrLen) == 0)
|
||||
{
|
||||
char ipBuf[64] = {};
|
||||
if (inet_ntop(AF_INET, &addr.sin_addr, ipBuf, sizeof(ipBuf)))
|
||||
{
|
||||
connectionIp = ipBuf;
|
||||
connectionPort = (int)ntohs(addr.sin_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (connectionIp.empty()) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SOCKET sock = WinsockNetLayer::GetSocketForSmallId(smallId);
|
||||
if (sock != INVALID_SOCKET)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
int addrLen = sizeof(addr);
|
||||
if (getpeername(sock, (sockaddr*)&addr, &addrLen) == 0)
|
||||
connectionPort = (int)ntohs(addr.sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
if (FourKitBridge::FirePlayerLogin(packet->userName, connectionIp, connectionPort, 2, &packet->m_onlineXuid, &packet->m_offlineXuid)) {
|
||||
disconnect(DisconnectPacket::eDisconnect_EndOfStream); //idk what to use here, eventually it should be set by the event
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Guests use the online xuid, everyone else uses the offline one
|
||||
PlayerUID playerXuid = packet->m_offlineXuid;
|
||||
if(playerXuid == INVALID_XUID) playerXuid = packet->m_onlineXuid;
|
||||
if (playerXuid == INVALID_XUID) playerXuid = packet->m_onlineXuid;
|
||||
|
||||
shared_ptr<ServerPlayer> playerEntity = server->getPlayers()->getPlayerForLogin(this, name, playerXuid,packet->m_onlineXuid);
|
||||
shared_ptr<ServerPlayer> playerEntity = server->getPlayers()->getPlayerForLogin(this, name, playerXuid, packet->m_onlineXuid);
|
||||
if (playerEntity != nullptr)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "Options.h"
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\Minecraft.Server\ServerLogManager.h"
|
||||
#include "..\Minecraft.Server\FourKitBridge.h"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
|
|
@ -62,6 +63,7 @@ PlayerConnection::PlayerConnection(MinecraftServer *server, Connection *connecti
|
|||
aboveGroundTickCount = 0;
|
||||
xLastOk = yLastOk = zLastOk = 0;
|
||||
synched = true;
|
||||
hasDoneFirstTickFourKit = false;
|
||||
didTick = false;
|
||||
lastKeepAliveId = 0;
|
||||
lastKeepAliveTime = 0;
|
||||
|
|
@ -113,6 +115,14 @@ unsigned char PlayerConnection::getLogSmallId()
|
|||
|
||||
void PlayerConnection::tick()
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (!hasDoneFirstTickFourKit)
|
||||
{
|
||||
FourKitBridge::FirePlayerJoin(player->entityId, player->name, player->getUUID(), (unsigned long long)player->getOnlineXuid(), (unsigned long long)player->getXuid());
|
||||
hasDoneFirstTickFourKit = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( done ) return;
|
||||
|
||||
if( m_bCloseOnTick )
|
||||
|
|
@ -153,12 +163,27 @@ void PlayerConnection::disconnect(DisconnectPacket::eDisconnectReason reason)
|
|||
return;
|
||||
}
|
||||
|
||||
std::wstring kickLeaveMessage;
|
||||
bool fourKitHandledQuit = false;
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (reason != DisconnectPacket::eDisconnect_Closed &&
|
||||
reason != DisconnectPacket::eDisconnect_ConnectionCreationFailed &&
|
||||
reason != DisconnectPacket::eDisconnect_Quitting)
|
||||
{
|
||||
if (FourKitBridge::FirePlayerKick(player->entityId, (int)reason, kickLeaveMessage))
|
||||
{
|
||||
m_bWasKicked = false;
|
||||
LeaveCriticalSection(&done_cs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ServerRuntime::ServerLogManager::OnPlayerDisconnected(
|
||||
getLogSmallId(),
|
||||
(player != NULL) ? player->name : std::wstring(),
|
||||
reason,
|
||||
true);
|
||||
fourKitHandledQuit = FourKitBridge::FirePlayerQuit(player->entityId);
|
||||
#endif
|
||||
app.DebugPrintf("PlayerConnection disconect reason: %d\n", reason );
|
||||
player->disconnect();
|
||||
|
|
@ -169,13 +194,20 @@ void PlayerConnection::disconnect(DisconnectPacket::eDisconnectReason reason)
|
|||
connection->sendAndQuit();
|
||||
// 4J-PB - removed, since it needs to be localised in the language the client is in
|
||||
//server->players->broadcastAll( shared_ptr<ChatPacket>( new ChatPacket(L"<22>e" + player->name + L" left the game.") ) );
|
||||
if(getWasKicked())
|
||||
if (!kickLeaveMessage.empty())
|
||||
{
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerKickedFromGame));
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(kickLeaveMessage));
|
||||
}
|
||||
else
|
||||
else if (!fourKitHandledQuit)
|
||||
{
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerLeftGame));
|
||||
if(getWasKicked())
|
||||
{
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerKickedFromGame));
|
||||
}
|
||||
else
|
||||
{
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerLeftGame));
|
||||
}
|
||||
}
|
||||
|
||||
server->getPlayers()->remove(player);
|
||||
|
|
@ -264,6 +296,8 @@ void PlayerConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
|
|||
|
||||
float yRotT = player->yRot;
|
||||
float xRotT = player->xRot;
|
||||
const float yRotOld = yRotT;
|
||||
const float xRotOld = xRotT;
|
||||
|
||||
if (packet->hasPos && packet->y == -999 && packet->yView == -999)
|
||||
{
|
||||
|
|
@ -316,7 +350,7 @@ void PlayerConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
|
|||
// Anti-cheat: reject movement packets that exceed server-authoritative bounds.
|
||||
double velocitySq = player->xd * player->xd + player->yd * player->yd + player->zd * player->zd;
|
||||
double maxAllowedSq = kMoveBaseAllowanceSq + (velocitySq * kMoveVelocityAllowanceScale);
|
||||
if (player->isAllowedToFly() || player->gameMode->isCreative())
|
||||
if (player->isAllowedToFly() || (player->gameMode != nullptr && player->gameMode->isCreative()))
|
||||
{
|
||||
// Creative / flight-allowed players can move farther legitimately per tick.
|
||||
maxAllowedSq *= 1.5;
|
||||
|
|
@ -327,6 +361,31 @@ void PlayerConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (xLastOk != xt || yLastOk != yt || zLastOk != zt || yRotT != yRotOld || xRotT != xRotOld)
|
||||
{
|
||||
double moveToX, moveToY, moveToZ;
|
||||
bool cancelled = FourKitBridge::FirePlayerMove(player->entityId,
|
||||
xLastOk, yLastOk, zLastOk,
|
||||
xt, yt, zt,
|
||||
&moveToX, &moveToY, &moveToZ);
|
||||
if (cancelled)
|
||||
{
|
||||
teleport(xLastOk, yLastOk, zLastOk, yRotT, xRotT);
|
||||
return;
|
||||
}
|
||||
if (moveToX != xt || moveToY != yt || moveToZ != zt)
|
||||
{
|
||||
xt = moveToX;
|
||||
yt = moveToY;
|
||||
zt = moveToZ;
|
||||
xDist = xt - player->x;
|
||||
yDist = yt - player->y;
|
||||
zDist = zt - player->z;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
float r = 1 / 16.0f;
|
||||
bool oldOk = level->getCubes(player, player->bb->copy()->shrink(r, r, r))->empty();
|
||||
|
||||
|
|
@ -433,11 +492,57 @@ void PlayerConnection::handlePlayerAction(shared_ptr<PlayerActionPacket> packet)
|
|||
|
||||
if (packet->action == PlayerActionPacket::DROP_ITEM)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
shared_ptr<ItemInstance> selected = player->inventory->getSelected();
|
||||
if (selected != nullptr && selected->count > 0)
|
||||
{
|
||||
int outId = selected->id, outCount = 1, outAux = selected->getAuxValue();
|
||||
bool cancelled = FourKitBridge::FirePlayerDropItem(
|
||||
player->entityId, selected->id, 1, selected->getAuxValue(),
|
||||
&outId, &outCount, &outAux);
|
||||
if (cancelled)
|
||||
return;
|
||||
player->inventory->removeItem(player->inventory->selected, 1);
|
||||
// oops
|
||||
// fix enchants disappearing
|
||||
shared_ptr<ItemInstance> dropItem = (outId == selected->id)
|
||||
? selected->copy()
|
||||
: std::make_shared<ItemInstance>(outId, outCount, outAux);
|
||||
dropItem->count = outCount;
|
||||
if (outAux != selected->getAuxValue()) dropItem->setAuxValue(outAux);
|
||||
player->drop(dropItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
player->drop(false);
|
||||
return;
|
||||
}
|
||||
else if (packet->action == PlayerActionPacket::DROP_ALL_ITEMS)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
shared_ptr<ItemInstance> selected = player->inventory->getSelected();
|
||||
if (selected != nullptr && selected->count > 0)
|
||||
{
|
||||
int outId = selected->id, outCount = selected->count, outAux = selected->getAuxValue();
|
||||
bool cancelled = FourKitBridge::FirePlayerDropItem(
|
||||
player->entityId, selected->id, selected->count, selected->getAuxValue(),
|
||||
&outId, &outCount, &outAux);
|
||||
if (cancelled)
|
||||
return;
|
||||
player->inventory->removeItem(player->inventory->selected, selected->count);
|
||||
shared_ptr<ItemInstance> dropItem = (outId == selected->id)
|
||||
? selected->copy()
|
||||
: std::make_shared<ItemInstance>(outId, outCount, outAux);
|
||||
dropItem->count = outCount;
|
||||
if (outAux != selected->getAuxValue()) dropItem->setAuxValue(outAux);
|
||||
player->drop(dropItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
player->drop(true);
|
||||
return;
|
||||
}
|
||||
|
|
@ -475,6 +580,23 @@ void PlayerConnection::handlePlayerAction(shared_ptr<PlayerActionPacket> packet)
|
|||
|
||||
if (packet->action == PlayerActionPacket::START_DESTROY_BLOCK)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
lastLeftClickTick = tickCount;
|
||||
{
|
||||
shared_ptr<ItemInstance> heldItem = player->inventory->getSelected();
|
||||
int iId = heldItem ? heldItem->id : 0;
|
||||
int iCount = heldItem ? heldItem->count : 0;
|
||||
int iAux = heldItem ? heldItem->getAuxValue() : 0;
|
||||
int useItemInHand = 1;
|
||||
bool cancelled = FourKitBridge::FirePlayerInteract(
|
||||
player->entityId, 1 /* LEFT_CLICK_BLOCK */,
|
||||
iId, iCount, iAux,
|
||||
x, y, z, packet->face, player->dimension,
|
||||
&useItemInHand);
|
||||
if (cancelled)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// Anti-cheat: validate spawn protection on the server for mining start.
|
||||
if (!server->isUnderSpawnProtection(level, x, y, z, player)) player->gameMode->startDestroyBlock(x, y, z, packet->face);
|
||||
else player->connection->send(std::make_shared<TileUpdatePacket>(x, y, z, level));
|
||||
|
|
@ -506,20 +628,129 @@ void PlayerConnection::handleUseItem(shared_ptr<UseItemPacket> packet)
|
|||
|
||||
if (packet->getFace() == 255)
|
||||
{
|
||||
if (item == nullptr) return;
|
||||
if (item == nullptr) return;
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
int iId = item->id;
|
||||
int iCount = item->count;
|
||||
int iAux = item->getAuxValue();
|
||||
int useItemInHand = 1;
|
||||
bool cancelled = FourKitBridge::FirePlayerInteract(
|
||||
player->entityId, 2,
|
||||
iId, iCount, iAux,
|
||||
0, 0, 0, 6, player->dimension,
|
||||
&useItemInHand);
|
||||
if (cancelled || !useItemInHand)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
player->gameMode->useItem(player, level, item);
|
||||
}
|
||||
else if ((packet->getY() < server->getMaxBuildHeight() - 1) || (packet->getFace() != Facing::UP && packet->getY() < server->getMaxBuildHeight()))
|
||||
{
|
||||
if (synched && player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) < 8 * 8)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
int iId = item ? item->id : 0;
|
||||
int iCount = item ? item->count : 0;
|
||||
int iAux = item ? item->getAuxValue() : 0;
|
||||
int useItemInHand = 1;
|
||||
bool cancelled = FourKitBridge::FirePlayerInteract(
|
||||
player->entityId, 3 /* RIGHT_CLICK_BLOCK */,
|
||||
iId, iCount, iAux,
|
||||
x, y, z, face, player->dimension,
|
||||
&useItemInHand);
|
||||
if (cancelled || !useItemInHand)
|
||||
{
|
||||
informClient = true;
|
||||
goto skipUseItemOn;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Anti-cheat: block placement/use must pass server-side spawn protection.
|
||||
if (!server->isUnderSpawnProtection(level, x, y, z, player))
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
int placeX = x, placeY = y, placeZ = z;
|
||||
bool validFace = true;
|
||||
|
||||
if (face == 0) placeY--;
|
||||
else if (face == 1) placeY++;
|
||||
else if (face == 2) placeZ--;
|
||||
else if (face == 3) placeZ++;
|
||||
else if (face == 4) placeX--;
|
||||
else if (face == 5) placeX++;
|
||||
else validFace = false;
|
||||
|
||||
int oldTileId = validFace ? level->getTile(placeX, placeY, placeZ) : 0;
|
||||
int oldTileData = validFace ? level->getData(placeX, placeY, placeZ) : 0;
|
||||
int oldClickedId = level->getTile(x, y, z);
|
||||
int oldClickedData = level->getData(x, y, z);
|
||||
int savedItemId = item ? item->id : 0;
|
||||
int savedItemCount = item ? item->count : 0;
|
||||
#endif
|
||||
|
||||
player->gameMode->useItemOn(player, level, item, x, y, z, face, packet->getClickX(), packet->getClickY(), packet->getClickZ());
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (validFace)
|
||||
{
|
||||
int newTileId = level->getTile(placeX, placeY, placeZ);
|
||||
int newClickedId = level->getTile(x, y, z);
|
||||
|
||||
int fireX = placeX, fireY = placeY, fireZ = placeZ;
|
||||
int againstX = x, againstY = y, againstZ = z;
|
||||
int revertId = oldTileId, revertData = oldTileData;
|
||||
bool shouldFire = false;
|
||||
|
||||
if (newTileId != 0 && newTileId != oldTileId)
|
||||
{
|
||||
shouldFire = true;
|
||||
}
|
||||
else if (newClickedId != 0 && newClickedId != oldClickedId)
|
||||
{
|
||||
shouldFire = true;
|
||||
fireX = x; fireY = y; fireZ = z;
|
||||
revertId = oldClickedId; revertData = oldClickedData;
|
||||
againstX = x; againstY = y; againstZ = z;
|
||||
if (face == 0) againstY++;
|
||||
else if (face == 1) againstY--;
|
||||
else if (face == 2) againstZ++;
|
||||
else if (face == 3) againstZ--;
|
||||
else if (face == 4) againstX++;
|
||||
else if (face == 5) againstX--;
|
||||
}
|
||||
|
||||
if (shouldFire)
|
||||
{
|
||||
bool cancelled = FourKitBridge::FireBlockPlace(
|
||||
player->entityId, player->dimension,
|
||||
fireX, fireY, fireZ,
|
||||
againstX, againstY, againstZ,
|
||||
savedItemId, savedItemCount, true);
|
||||
|
||||
if (cancelled)
|
||||
{
|
||||
level->setTileAndData(fireX, fireY, fireZ, revertId, revertData, Tile::UPDATE_ALL);
|
||||
auto &slot = player->inventory->items[player->inventory->selected];
|
||||
if (slot != nullptr)
|
||||
{
|
||||
slot->count = savedItemCount;
|
||||
}
|
||||
else if (savedItemId > 0 && savedItemId < 256 && Tile::tiles[savedItemId] != nullptr && savedItemCount > 0)
|
||||
{
|
||||
slot = std::make_shared<ItemInstance>(Tile::tiles[savedItemId], savedItemCount);
|
||||
}
|
||||
informClient = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
skipUseItemOn:
|
||||
informClient = true;
|
||||
}
|
||||
else
|
||||
|
|
@ -588,23 +819,28 @@ void PlayerConnection::onDisconnect(DisconnectPacket::eDisconnectReason reason,
|
|||
LeaveCriticalSection(&done_cs);
|
||||
return;
|
||||
}
|
||||
bool fourKitHandledQuit = false;
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
ServerRuntime::ServerLogManager::OnPlayerDisconnected(
|
||||
getLogSmallId(),
|
||||
(player != NULL) ? player->name : std::wstring(),
|
||||
reason,
|
||||
false);
|
||||
fourKitHandledQuit = FourKitBridge::FirePlayerQuit(player->entityId);
|
||||
#endif
|
||||
// logger.info(player.name + " lost connection: " + reason);
|
||||
// 4J-PB - removed, since it needs to be localised in the language the client is in
|
||||
//server->players->broadcastAll( shared_ptr<ChatPacket>( new ChatPacket(L"<22>e" + player->name + L" left the game.") ) );
|
||||
if(getWasKicked())
|
||||
if (!fourKitHandledQuit)
|
||||
{
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerKickedFromGame));
|
||||
}
|
||||
else
|
||||
{
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerLeftGame));
|
||||
if(getWasKicked())
|
||||
{
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerKickedFromGame));
|
||||
}
|
||||
else
|
||||
{
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerLeftGame));
|
||||
}
|
||||
}
|
||||
server->getPlayers()->remove(player);
|
||||
done = true;
|
||||
|
|
@ -678,8 +914,21 @@ void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
handleCommand(message);
|
||||
return;
|
||||
}
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
std::wstring formatted;
|
||||
if (!FourKitBridge::FirePlayerChat(player->entityId, message, formatted))
|
||||
{
|
||||
if (formatted.empty())
|
||||
formatted = L"<" + player->name + L"> " + message;
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(app.FormatChatMessage(formatted, false)));
|
||||
}
|
||||
}
|
||||
#else
|
||||
wstring formatted = L"<" + player->name + L"> " + message;
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(app.FormatChatMessage(formatted, false))));
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(app.FormatChatMessage(formatted, false))));
|
||||
#endif
|
||||
|
||||
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
|
||||
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10)
|
||||
{
|
||||
|
|
@ -689,6 +938,13 @@ void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
|
||||
void PlayerConnection::handleCommand(const wstring& message)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
std::wstring commandLine = message;
|
||||
if (FourKitBridge::FireCommandPreprocess(player->entityId, commandLine, commandLine))
|
||||
return;
|
||||
if (FourKitBridge::HandlePlayerCommand(player->entityId, commandLine))
|
||||
return;
|
||||
#endif
|
||||
// 4J - TODO
|
||||
#if 0
|
||||
server.getCommandDispatcher().performCommand(player, message);
|
||||
|
|
@ -700,6 +956,23 @@ void PlayerConnection::handleAnimate(shared_ptr<AnimatePacket> packet)
|
|||
player->resetLastActionTime();
|
||||
if (packet->action == AnimatePacket::SWING)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (lastLeftClickTick != tickCount)
|
||||
{
|
||||
int useItemInHand = 1;
|
||||
auto item = player->inventory->getSelected();
|
||||
int iId = item ? item->id : 0;
|
||||
int iCount = item ? item->count : 0;
|
||||
int iAux = item ? item->getAuxValue() : 0;
|
||||
bool cancelled = FourKitBridge::FirePlayerInteract(
|
||||
player->entityId, 0,
|
||||
iId, iCount, iAux,
|
||||
0, 0, 0, 6, player->dimension,
|
||||
&useItemInHand);
|
||||
if (cancelled)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
player->swing();
|
||||
}
|
||||
}
|
||||
|
|
@ -810,10 +1083,31 @@ void PlayerConnection::handleInteract(shared_ptr<InteractPacket> packet)
|
|||
|
||||
if (packet->action == InteractPacket::INTERACT)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
int mappedType = FourKitBridge::MapEntityType((int)target->GetType());
|
||||
float targetHealth = 0, targetMaxHealth = 0, targetEyeHeight = 0;
|
||||
auto living = dynamic_pointer_cast<LivingEntity>(target);
|
||||
if (living)
|
||||
{
|
||||
targetHealth = living->getHealth();
|
||||
targetMaxHealth = living->getMaxHealth();
|
||||
targetEyeHeight = living->getHeadHeight();
|
||||
}
|
||||
if (FourKitBridge::FirePlayerInteractEntity(
|
||||
player->entityId, target->entityId, mappedType,
|
||||
player->dimension, target->x, target->y, target->z,
|
||||
targetHealth, targetMaxHealth, targetEyeHeight))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
player->interact(target);
|
||||
}
|
||||
else if (packet->action == InteractPacket::ATTACK)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
lastLeftClickTick = tickCount;
|
||||
#endif
|
||||
if ((target->GetType() == eTYPE_ITEMENTITY) || (target->GetType() == eTYPE_EXPERIENCEORB) || (target->GetType() == eTYPE_ARROW) || target == player)
|
||||
{
|
||||
//disconnect("Attempting to attack an invalid entity");
|
||||
|
|
@ -1107,7 +1401,13 @@ void PlayerConnection::handleClientCommand(shared_ptr<ClientCommandPacket> packe
|
|||
{
|
||||
if (player->wonGame)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
int oldEntityId = player->entityId;
|
||||
#endif
|
||||
player = server->getPlayers()->respawn(player, player->m_enteredEndExitPortal?0:player->dimension, true);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
FourKitBridge::UpdatePlayerEntityId(oldEntityId, player->entityId);
|
||||
#endif
|
||||
}
|
||||
//else if (player.getLevel().getLevelData().isHardcore())
|
||||
//{
|
||||
|
|
@ -1128,17 +1428,25 @@ void PlayerConnection::handleClientCommand(shared_ptr<ClientCommandPacket> packe
|
|||
else
|
||||
{
|
||||
if (player->getHealth() > 0) return;
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
int oldEntityId = player->entityId;
|
||||
#endif
|
||||
player = server->getPlayers()->respawn(player, 0, false);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
FourKitBridge::UpdatePlayerEntityId(oldEntityId, player->entityId);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
|
||||
{
|
||||
//todo: fire respawn event
|
||||
}
|
||||
|
||||
void PlayerConnection::handleContainerClose(shared_ptr<ContainerClosePacket> packet)
|
||||
{
|
||||
//todo: fire container close event
|
||||
player->doCloseContainer();
|
||||
}
|
||||
|
||||
|
|
@ -1188,6 +1496,20 @@ void PlayerConnection::handleContainerClick(shared_ptr<ContainerClickPacket> pac
|
|||
player->resetLastActionTime();
|
||||
if (player->containerMenu->containerId == packet->containerId && player->containerMenu->isSynched(player))
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
int fourKitClickResult = FourKitBridge::FireInventoryClick(player->entityId, packet->slotNum, packet->buttonNum, packet->clickType);
|
||||
if (fourKitClickResult == 1)
|
||||
{
|
||||
expectedAcks[player->containerMenu->containerId] = packet->uid;
|
||||
player->connection->send(std::make_shared<ContainerAckPacket>(packet->containerId, packet->uid, false));
|
||||
player->containerMenu->setSynched(player, false);
|
||||
vector<shared_ptr<ItemInstance>> items;
|
||||
for (unsigned int i = 0; i < player->containerMenu->slots.size(); i++)
|
||||
items.push_back(player->containerMenu->slots.at(i)->getItem());
|
||||
player->refreshContainer(player->containerMenu, &items);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
shared_ptr<ItemInstance> clicked = player->containerMenu->clicked(packet->slotNum, packet->buttonNum, packet->clickType, player);
|
||||
|
||||
if (ItemInstance::matches(packet->item, clicked))
|
||||
|
|
@ -1215,6 +1537,15 @@ void PlayerConnection::handleContainerClick(shared_ptr<ContainerClickPacket> pac
|
|||
|
||||
// player.containerMenu.broadcastChanges();
|
||||
}
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (fourKitClickResult == 2)
|
||||
{
|
||||
vector<shared_ptr<ItemInstance>> refreshItems;
|
||||
for (unsigned int i = 0; i < player->containerMenu->slots.size(); i++)
|
||||
refreshItems.push_back(player->containerMenu->slots.at(i)->getItem());
|
||||
player->refreshContainer(player->containerMenu, &refreshItems);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1352,10 +1683,31 @@ void PlayerConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
|
|||
int y = packet->y;
|
||||
int z = packet->z;
|
||||
shared_ptr<SignTileEntity> ste = dynamic_pointer_cast<SignTileEntity>(te);
|
||||
|
||||
wstring lines[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
wstring lineText = packet->lines[i].substr(0,15);
|
||||
ste->SetMessage( i, lineText );
|
||||
lines[i] = packet->lines[i].substr(0,15);
|
||||
}
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
std::wstring outLines[4];
|
||||
bool cancelled = FourKitBridge::FireSignChange(
|
||||
player->entityId, player->dimension,
|
||||
x, y, z,
|
||||
lines[0], lines[1], lines[2], lines[3],
|
||||
outLines);
|
||||
if (cancelled)
|
||||
return;
|
||||
for (int i = 0; i < 4; i++)
|
||||
lines[i] = outLines[i];
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
ste->SetMessage( i, lines[i] );
|
||||
}
|
||||
ste->SetVerified(false);
|
||||
ste->setChanged();
|
||||
|
|
@ -1369,8 +1721,13 @@ void PlayerConnection::handleKeepAlive(shared_ptr<KeepAlivePacket> packet)
|
|||
{
|
||||
if (packet->id == lastKeepAliveId)
|
||||
{
|
||||
int time = static_cast<int>(System::nanoTime() / 1000000 - lastKeepAliveTime);
|
||||
player->latency = (player->latency * 3 + time) / 4;
|
||||
int64_t now = (System::nanoTime() / 1000000);
|
||||
if (lastKeepAliveTime == 0) lastKeepAliveTime = now;
|
||||
int64_t delta = static_cast<int64_t>(now - lastKeepAliveTime);
|
||||
|
||||
player->latency = (player->latency * 3 + delta) / 4;
|
||||
|
||||
lastKeepAliveTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1473,6 +1830,7 @@ bool PlayerConnection::isServerPacketListener()
|
|||
|
||||
void PlayerConnection::handlePlayerAbilities(shared_ptr<PlayerAbilitiesPacket> playerAbilitiesPacket)
|
||||
{
|
||||
//todo: fire abilities change event
|
||||
player->abilities.flying = playerAbilitiesPacket->isFlying() && player->abilities.mayfly;
|
||||
}
|
||||
|
||||
|
|
@ -1591,6 +1949,7 @@ void PlayerConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> custo
|
|||
Slot *slot = beaconMenu->getSlot(0);
|
||||
if (slot->hasItem())
|
||||
{
|
||||
//todo: beacon powered event?
|
||||
slot->remove(1);
|
||||
shared_ptr<BeaconTileEntity> beacon = beaconMenu->getBeacon();
|
||||
beacon->setPrimaryPower(primary);
|
||||
|
|
@ -1604,6 +1963,7 @@ void PlayerConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> custo
|
|||
AnvilMenu *menu = dynamic_cast<AnvilMenu *>( player->containerMenu);
|
||||
if (menu)
|
||||
{
|
||||
//todo: anvel item rename event?
|
||||
if (customPayloadPacket->data.data == nullptr || customPayloadPacket->data.length < 1)
|
||||
{
|
||||
menu->setItemName(L"");
|
||||
|
|
@ -1631,6 +1991,7 @@ bool PlayerConnection::isDisconnected()
|
|||
|
||||
void PlayerConnection::handleDebugOptions(shared_ptr<DebugOptionsPacket> packet)
|
||||
{
|
||||
//todo: debug options event?
|
||||
#ifdef _DEBUG
|
||||
// Player player = dynamic_pointer_cast<Player>( player->shared_from_this() );
|
||||
player->SetDebugOptions(packet->m_uiVal);
|
||||
|
|
@ -1717,6 +2078,8 @@ void PlayerConnection::handleCraftItem(shared_ptr<CraftItemPacket> packet)
|
|||
}
|
||||
}
|
||||
|
||||
//todo: fire item crafted event?
|
||||
|
||||
// 4J Stu - Fix for #13119 - We should add the item after we remove the ingredients
|
||||
if(player->inventory->add(pTempItemInst)==false )
|
||||
{
|
||||
|
|
@ -1791,6 +2154,7 @@ void PlayerConnection::handleTradeItem(shared_ptr<TradeItemPacket> packet)
|
|||
int buyBMatches = player->inventory->countMatches(buyBItem);
|
||||
if( (buyAItem != nullptr && buyAMatches >= buyAItem->count) && (buyBItem == nullptr || buyBMatches >= buyBItem->count) )
|
||||
{
|
||||
//todo: fire trade event?
|
||||
menu->getMerchant()->notifyTrade(activeRecipe);
|
||||
|
||||
// Remove the items we are purchasing with
|
||||
|
|
|
|||
|
|
@ -30,11 +30,13 @@ private:
|
|||
|
||||
bool didTick;
|
||||
int lastKeepAliveId;
|
||||
bool hasDoneFirstTickFourKit;
|
||||
int64_t lastKeepAliveTime;
|
||||
static Random random;
|
||||
int64_t lastKeepAliveTick;
|
||||
int chatSpamTickCount;
|
||||
int dropSpamTickCount;
|
||||
int lastLeftClickTick = 0;
|
||||
|
||||
bool m_bHasClientTickedOnce;
|
||||
unsigned char m_logSmallId;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ PlayerList::~PlayerList()
|
|||
|
||||
bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer> player, shared_ptr<LoginPacket> packet)
|
||||
{
|
||||
// (SYLV)todo: we should move emit player join event here
|
||||
CompoundTag *playerTag = load(player);
|
||||
|
||||
bool newPlayer = playerTag == nullptr;
|
||||
|
|
@ -283,7 +284,9 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
|
|||
|
||||
// 4J-PB - removed, since it needs to be localised in the language the client is in
|
||||
//server->players->broadcastAll( shared_ptr<ChatPacket>( new ChatPacket(L"<22>e" + playerEntity->name + L" joined the game.") ) );
|
||||
#if !(defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD))
|
||||
broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerJoinedGame));
|
||||
#endif
|
||||
|
||||
MemSect(14);
|
||||
add(player);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
#include "..\Minecraft.World\compression.h"
|
||||
#include "..\Minecraft.World\OldChunkStorage.h"
|
||||
#include "..\Minecraft.World\Tile.h"
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
#include "..\Minecraft.Server\FourKitBridge.h"
|
||||
#endif
|
||||
|
||||
ServerChunkCache::ServerChunkCache(ServerLevel *level, ChunkStorage *storage, ChunkSource *source)
|
||||
{
|
||||
|
|
@ -152,7 +155,10 @@ LevelChunk *ServerChunkCache::create(int x, int z, bool asyncPostProcess) // 4J
|
|||
{
|
||||
EnterCriticalSection(&m_csLoadCreate);
|
||||
chunk = load(x, z);
|
||||
if (chunk == nullptr)
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
bool isNewChunk = (chunk == nullptr);
|
||||
#endif
|
||||
if (chunk == nullptr)
|
||||
{
|
||||
if (source == nullptr)
|
||||
{
|
||||
|
|
@ -231,6 +237,10 @@ LevelChunk *ServerChunkCache::create(int x, int z, bool asyncPostProcess) // 4J
|
|||
if( hasChunk( x - 1, z ) && hasChunk( x + 1, z ) && hasChunk ( x, z - 1 ) && hasChunk( x, z + 1 ) ) chunk->checkChests( this, x, z );
|
||||
|
||||
LeaveCriticalSection(&m_csLoadCreate);
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
FourKitBridge::FireChunkLoad(level->dimension->id, x, z, isNewChunk);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -378,6 +388,38 @@ void ServerChunkCache::overwriteHellLevelChunkFromSource(int x, int z, int minVa
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
void ServerChunkCache::regenerateChunk(int x, int z)
|
||||
{
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
LevelChunk *freshChunk = source->getChunk(x, z);
|
||||
if (!freshChunk)
|
||||
return;
|
||||
|
||||
LevelChunk *cachedChunk = nullptr;
|
||||
if (hasChunk(x, z))
|
||||
cachedChunk = getChunk(x, z);
|
||||
|
||||
if (cachedChunk && cachedChunk != emptyChunk)
|
||||
{
|
||||
for (int lx = 0; lx < 16; lx++)
|
||||
for (int ly = 0; ly < 128; ly++)
|
||||
for (int lz = 0; lz < 16; lz++)
|
||||
cachedChunk->setTileAndData(lx, ly, lz, freshChunk->getTile(lx, ly, lz), freshChunk->getData(lx, ly, lz));
|
||||
save(cachedChunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
save(freshChunk);
|
||||
}
|
||||
|
||||
freshChunk->unload(false);
|
||||
delete freshChunk;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 4J Added //
|
||||
#ifdef _LARGE_WORLDS
|
||||
void ServerChunkCache::dontDrop(int x, int z)
|
||||
|
|
@ -941,23 +983,30 @@ bool ServerChunkCache::tick()
|
|||
// player's tick is called to remove them from the chunk they used to be in, and add them to their current chunk. This will only be a temporary state and
|
||||
// we should be able to unload the chunk on the next call to this tick.
|
||||
if( !chunk->containsPlayer() )
|
||||
{
|
||||
{
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
if (!FourKitBridge::FireChunkUnload(level->dimension->id, chunk->x, chunk->z))
|
||||
{
|
||||
#endif
|
||||
save(chunk);
|
||||
saveEntities(chunk);
|
||||
chunk->unload(true);
|
||||
|
||||
//loadedChunks.remove(cp);
|
||||
//loadedChunkList.remove(chunk);
|
||||
auto it = std::find(m_loadedChunkList.begin(), m_loadedChunkList.end(), chunk);
|
||||
if(it != m_loadedChunkList.end()) m_loadedChunkList.erase(it);
|
||||
auto it = std::find(m_loadedChunkList.begin(), m_loadedChunkList.end(), chunk);
|
||||
if(it != m_loadedChunkList.end()) m_loadedChunkList.erase(it);
|
||||
|
||||
int ix = chunk->x + XZOFFSET;
|
||||
int iz = chunk->z + XZOFFSET;
|
||||
int idx = ix * XZSIZE + iz;
|
||||
m_unloadedCache[idx] = chunk;
|
||||
cache[idx] = nullptr;
|
||||
}
|
||||
}
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
}
|
||||
#endif
|
||||
m_toDrop.pop_front();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ public:
|
|||
|
||||
#endif
|
||||
virtual LevelChunk **getCache() { return cache; } // 4J added
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
void regenerateChunk(int x, int z);
|
||||
#endif
|
||||
|
||||
// 4J-JEV Added; Remove chunk from the toDrop queue.
|
||||
#ifdef _LARGE_WORLDS
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@
|
|||
#include "..\Minecraft.World\ProgressListener.h"
|
||||
#include "PS3\PS3Extras\ShutdownManager.h"
|
||||
#include "PlayerChunkMap.h"
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\Minecraft.Server\FourKitBridge.h"
|
||||
#endif
|
||||
|
||||
WeighedTreasureArray ServerLevel::RANDOM_BONUS_ITEMS;
|
||||
|
||||
|
|
@ -324,6 +327,8 @@ void ServerLevel::updateSleepingPlayerList()
|
|||
|
||||
for (auto& player : players)
|
||||
{
|
||||
if (player->fk_sleepingIgnored)
|
||||
continue;
|
||||
if (!player->isSleeping())
|
||||
{
|
||||
allPlayersSleeping = false;
|
||||
|
|
@ -368,6 +373,8 @@ bool ServerLevel::allPlayersAreSleeping()
|
|||
// all players are sleeping, but have they slept long enough?
|
||||
for (auto& player : players)
|
||||
{
|
||||
if (player->fk_sleepingIgnored)
|
||||
continue;
|
||||
// System.out.println(player->entityId + ": " + player->getSleepTimer());
|
||||
if (!player->isSleepingLongEnough())
|
||||
{
|
||||
|
|
@ -507,15 +514,21 @@ void ServerLevel::tickTiles()
|
|||
int val = (randValue >> 2);
|
||||
int x = (val & 15);
|
||||
int z = ((val >> 8) & 15);
|
||||
int yy = getTopRainBlock(x + xo, z + zo);
|
||||
if (shouldFreeze(x + xo, yy - 1, z + zo))
|
||||
{
|
||||
setTileAndUpdate(x + xo, yy - 1, z + zo, Tile::ice_Id);
|
||||
}
|
||||
if (isRaining() && shouldSnow(x + xo, yy, z + zo))
|
||||
{
|
||||
setTileAndUpdate(x + xo, yy, z + zo, Tile::topSnow_Id);
|
||||
}
|
||||
int yy = getTopRainBlock(x + xo, z + zo);
|
||||
if (shouldFreeze(x + xo, yy - 1, z + zo))
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (!FourKitBridge::FireBlockForm(dimension->id, x + xo, yy - 1, z + zo, Tile::ice_Id, 0))
|
||||
#endif
|
||||
setTileAndUpdate(x + xo, yy - 1, z + zo, Tile::ice_Id);
|
||||
}
|
||||
if (isRaining() && shouldSnow(x + xo, yy, z + zo))
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (!FourKitBridge::FireBlockForm(dimension->id, x + xo, yy, z + zo, Tile::topSnow_Id, 0))
|
||||
#endif
|
||||
setTileAndUpdate(x + xo, yy, z + zo, Tile::topSnow_Id);
|
||||
}
|
||||
if (isRaining())
|
||||
{
|
||||
Biome *b = getBiome(x + xo, z + zo);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,154 @@
|
|||
#include "..\Minecraft.World\LevelChunk.h"
|
||||
#include "LevelRenderer.h"
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\Minecraft.Server\FourKitBridge.h"
|
||||
#include "..\Minecraft.World\ChatPacket.h"
|
||||
|
||||
static std::wstring FormatDeathMessage(const shared_ptr<ChatPacket>& packet)
|
||||
{
|
||||
if (!packet) return L"";
|
||||
|
||||
std::wstring message;
|
||||
bool replacePlayer = false;
|
||||
bool replaceEntitySource = false;
|
||||
bool replaceItem = false;
|
||||
// coug chough
|
||||
// de hättn echt an gscheidern string konverter für de todesmeldungen macha soin
|
||||
// a globaler helfer waar wahrscheinlich ganz bärig gwen
|
||||
// waaaah
|
||||
|
||||
switch (packet->m_messageType)
|
||||
{
|
||||
case ChatPacket::e_ChatCustom:
|
||||
return packet->m_stringArgs.size() > 0 ? packet->m_stringArgs[0] : L"";
|
||||
case ChatPacket::e_ChatDeathInFire:
|
||||
message = app.GetString(IDS_DEATH_INFIRE); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathOnFire:
|
||||
message = app.GetString(IDS_DEATH_ONFIRE); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathLava:
|
||||
message = app.GetString(IDS_DEATH_LAVA); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathInWall:
|
||||
message = app.GetString(IDS_DEATH_INWALL); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathDrown:
|
||||
message = app.GetString(IDS_DEATH_DROWN); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathStarve:
|
||||
message = app.GetString(IDS_DEATH_STARVE); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathCactus:
|
||||
message = app.GetString(IDS_DEATH_CACTUS); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathFall:
|
||||
message = app.GetString(IDS_DEATH_FALL); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathOutOfWorld:
|
||||
message = app.GetString(IDS_DEATH_OUTOFWORLD); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathGeneric:
|
||||
message = app.GetString(IDS_DEATH_GENERIC); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathExplosion:
|
||||
message = app.GetString(IDS_DEATH_EXPLOSION); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathMagic:
|
||||
message = app.GetString(IDS_DEATH_MAGIC); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathWither:
|
||||
message = app.GetString(IDS_DEATH_WITHER); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathDragonBreath:
|
||||
message = app.GetString(IDS_DEATH_DRAGON_BREATH); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathAnvil:
|
||||
message = app.GetString(IDS_DEATH_FALLING_ANVIL); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathFallingBlock:
|
||||
message = app.GetString(IDS_DEATH_FALLING_TILE); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathFellAccidentLadder:
|
||||
message = app.GetString(IDS_DEATH_FELL_ACCIDENT_LADDER); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathFellAccidentVines:
|
||||
message = app.GetString(IDS_DEATH_FELL_ACCIDENT_VINES); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathFellAccidentWater:
|
||||
message = app.GetString(IDS_DEATH_FELL_ACCIDENT_WATER); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathFellAccidentGeneric:
|
||||
message = app.GetString(IDS_DEATH_FELL_ACCIDENT_GENERIC); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathFellKiller:
|
||||
message = app.GetString(IDS_DEATH_FALL); replacePlayer = true; break;
|
||||
case ChatPacket::e_ChatDeathMob:
|
||||
message = app.GetString(IDS_DEATH_MOB); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathPlayer:
|
||||
message = app.GetString(IDS_DEATH_PLAYER); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathArrow:
|
||||
message = app.GetString(IDS_DEATH_ARROW); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathFireball:
|
||||
message = app.GetString(IDS_DEATH_FIREBALL); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathThrown:
|
||||
message = app.GetString(IDS_DEATH_THROWN); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathIndirectMagic:
|
||||
message = app.GetString(IDS_DEATH_INDIRECT_MAGIC); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathThorns:
|
||||
message = app.GetString(IDS_DEATH_THORNS); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathExplosionPlayer:
|
||||
message = app.GetString(IDS_DEATH_EXPLOSION_PLAYER); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathInFirePlayer:
|
||||
message = app.GetString(IDS_DEATH_INFIRE_PLAYER); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathOnFirePlayer:
|
||||
message = app.GetString(IDS_DEATH_ONFIRE_PLAYER); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathLavaPlayer:
|
||||
message = app.GetString(IDS_DEATH_LAVA_PLAYER); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathDrownPlayer:
|
||||
message = app.GetString(IDS_DEATH_DROWN_PLAYER); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathCactusPlayer:
|
||||
message = app.GetString(IDS_DEATH_CACTUS_PLAYER); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathFellAssist:
|
||||
message = app.GetString(IDS_DEATH_FELL_ASSIST); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathFellFinish:
|
||||
message = app.GetString(IDS_DEATH_FELL_FINISH); replacePlayer = true; replaceEntitySource = true; break;
|
||||
case ChatPacket::e_ChatDeathPlayerItem:
|
||||
message = app.GetString(IDS_DEATH_PLAYER_ITEM); replacePlayer = true; replaceEntitySource = true; replaceItem = true; break;
|
||||
case ChatPacket::e_ChatDeathArrowItem:
|
||||
message = app.GetString(IDS_DEATH_ARROW_ITEM); replacePlayer = true; replaceEntitySource = true; replaceItem = true; break;
|
||||
case ChatPacket::e_ChatDeathFireballItem:
|
||||
message = app.GetString(IDS_DEATH_FIREBALL_ITEM); replacePlayer = true; replaceEntitySource = true; replaceItem = true; break;
|
||||
case ChatPacket::e_ChatDeathThrownItem:
|
||||
message = app.GetString(IDS_DEATH_THROWN_ITEM); replacePlayer = true; replaceEntitySource = true; replaceItem = true; break;
|
||||
case ChatPacket::e_ChatDeathIndirectMagicItem:
|
||||
message = app.GetString(IDS_DEATH_INDIRECT_MAGIC_ITEM); replacePlayer = true; replaceEntitySource = true; replaceItem = true; break;
|
||||
case ChatPacket::e_ChatDeathFellAssistItem:
|
||||
message = app.GetString(IDS_DEATH_FELL_ASSIST_ITEM); replacePlayer = true; replaceEntitySource = true; replaceItem = true; break;
|
||||
case ChatPacket::e_ChatDeathFellFinishItem:
|
||||
message = app.GetString(IDS_DEATH_FELL_FINISH_ITEM); replacePlayer = true; replaceEntitySource = true; replaceItem = true; break;
|
||||
default:
|
||||
message = app.GetString(IDS_DEATH_GENERIC); replacePlayer = true; break;
|
||||
}
|
||||
|
||||
if (replacePlayer)
|
||||
{
|
||||
std::wstring playerName = packet->m_stringArgs.size() > 0 ? packet->m_stringArgs[0] : L"";
|
||||
message = replaceAll(message, L"{*PLAYER*}", playerName);
|
||||
}
|
||||
|
||||
if (replaceEntitySource)
|
||||
{
|
||||
std::wstring sourceName;
|
||||
if (!packet->m_intArgs.empty() && packet->m_intArgs[0] == eTYPE_SERVERPLAYER)
|
||||
{
|
||||
sourceName = packet->m_stringArgs.size() > 1 ? packet->m_stringArgs[1] : L"";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packet->m_stringArgs.size() > 1 && !packet->m_stringArgs[1].empty())
|
||||
{
|
||||
sourceName = packet->m_stringArgs[1];
|
||||
}
|
||||
else if (!packet->m_intArgs.empty())
|
||||
{
|
||||
sourceName = app.getEntityName((eINSTANCEOF)packet->m_intArgs[0]);
|
||||
}
|
||||
}
|
||||
message = replaceAll(message, L"{*SOURCE*}", sourceName);
|
||||
}
|
||||
|
||||
if (replaceItem)
|
||||
{
|
||||
std::wstring itemName = packet->m_stringArgs.size() > 2 ? packet->m_stringArgs[2] : L"";
|
||||
message = replaceAll(message, L"{*ITEM*}", itemName);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ServerPlayer::ServerPlayer(MinecraftServer *server, Level *level, const wstring& name, ServerPlayerGameMode *gameMode) : Player(level, name)
|
||||
{
|
||||
|
|
@ -567,12 +715,38 @@ shared_ptr<ItemInstance> ServerPlayer::getCarried(int slot)
|
|||
|
||||
void ServerPlayer::die(DamageSource *source)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
shared_ptr<ChatPacket> deathPacket = getCombatTracker()->getDeathMessagePacket();
|
||||
std::wstring deathMsg = FormatDeathMessage(deathPacket);
|
||||
|
||||
int exp = getExperienceReward(nullptr);
|
||||
std::wstring outDeathMsg;
|
||||
int keepInventory = 0;
|
||||
int outNewExp = 0, outNewLevel = 0, outKeepLevel = 0;
|
||||
int outExp = FourKitBridge::FirePlayerDeath(entityId, deathMsg, exp, outDeathMsg, &keepInventory,
|
||||
&outNewExp, &outNewLevel, &outKeepLevel);
|
||||
|
||||
fk_hasDeathState = true;
|
||||
fk_deathKeepInventory = (keepInventory != 0);
|
||||
fk_deathKeepLevel = (outKeepLevel != 0);
|
||||
fk_deathNewExp = outNewExp;
|
||||
fk_deathNewLevel = outNewLevel;
|
||||
|
||||
if (!outDeathMsg.empty())
|
||||
server->getPlayers()->broadcastAll(std::make_shared<ChatPacket>(outDeathMsg));
|
||||
|
||||
if (keepInventory == 0 && !level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY))
|
||||
{
|
||||
inventory->dropAll();
|
||||
}
|
||||
#else
|
||||
server->getPlayers()->broadcastAll(getCombatTracker()->getDeathMessagePacket());
|
||||
|
||||
if (!level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY))
|
||||
{
|
||||
inventory->dropAll();
|
||||
}
|
||||
#endif
|
||||
|
||||
vector<Objective *> *objectives = level->getScoreboard()->findObjectiveFor(ObjectiveCriteria::DEATH_COUNT);
|
||||
if(objectives)
|
||||
|
|
@ -765,6 +939,10 @@ void ServerPlayer::changeDimension(int i)
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
bool portalDestModified = false;
|
||||
double portalOutX = 0, portalOutY = 0, portalOutZ = 0;
|
||||
#endif
|
||||
if (dimension == 0 && i == 1)
|
||||
{
|
||||
awardStat(GenericStats::theEnd(), GenericStats::param_theEnd());
|
||||
|
|
@ -772,7 +950,24 @@ void ServerPlayer::changeDimension(int i)
|
|||
Pos *pos = server->getLevel(i)->getDimensionSpecificSpawn();
|
||||
if (pos != nullptr)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
double outX, outY, outZ;
|
||||
bool cancelled = FourKitBridge::FirePlayerPortal(entityId,
|
||||
x, y, z, dimension,
|
||||
pos->x, pos->y, pos->z, i,
|
||||
4,
|
||||
&outX, &outY, &outZ);
|
||||
if (cancelled)
|
||||
{
|
||||
delete pos;
|
||||
return;
|
||||
}
|
||||
connection->teleport(outX, outY, outZ, 0, 0);
|
||||
}
|
||||
#else
|
||||
connection->teleport(pos->x, pos->y, pos->z, 0, 0);
|
||||
#endif
|
||||
delete pos;
|
||||
}
|
||||
|
||||
|
|
@ -780,10 +975,48 @@ void ServerPlayer::changeDimension(int i)
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
double scale = server->getLevel(i)->getLevelData()->getHellScale();
|
||||
double toX = x, toY = y, toZ = z;
|
||||
if (i == -1)
|
||||
{
|
||||
toX = x / scale;
|
||||
toZ = z / scale;
|
||||
}
|
||||
else if (dimension == -1 && i == 0)
|
||||
{
|
||||
toX = x * scale;
|
||||
toZ = z * scale;
|
||||
}
|
||||
|
||||
double outX, outY, outZ;
|
||||
bool cancelled = FourKitBridge::FirePlayerPortal(entityId,
|
||||
x, y, z, dimension,
|
||||
toX, toY, toZ, i,
|
||||
3,
|
||||
&outX, &outY, &outZ);
|
||||
if (cancelled)
|
||||
return;
|
||||
if (outX != toX || outY != toY || outZ != toZ)
|
||||
{
|
||||
portalDestModified = true;
|
||||
portalOutX = outX;
|
||||
portalOutY = outY;
|
||||
portalOutZ = outZ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// 4J: Removed on the advice of the mighty King of Achievments (JV)
|
||||
// awardStat(GenericStats::portal(), GenericStats::param_portal());
|
||||
}
|
||||
server->getPlayers()->toggleDimension( dynamic_pointer_cast<ServerPlayer>(shared_from_this()), i);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (portalDestModified)
|
||||
{
|
||||
connection->teleport(portalOutX, portalOutY, portalOutZ, yRot, xRot);
|
||||
}
|
||||
#endif
|
||||
lastSentExp = -1;
|
||||
lastSentHealth = -1;
|
||||
lastSentFood = -1;
|
||||
|
|
@ -813,6 +1046,10 @@ void ServerPlayer::take(shared_ptr<Entity> e, int orgCount)
|
|||
|
||||
Player::BedSleepingResult ServerPlayer::startSleepInBed(int x, int y, int z, bool bTestUse)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (!bTestUse && FourKitBridge::FireBedEnter(entityId, dimension, x, y, z))
|
||||
return OTHER_PROBLEM;
|
||||
#endif
|
||||
BedSleepingResult result = Player::startSleepInBed(x, y, z, bTestUse);
|
||||
if (result == OK)
|
||||
{
|
||||
|
|
@ -826,12 +1063,22 @@ Player::BedSleepingResult ServerPlayer::startSleepInBed(int x, int y, int z, boo
|
|||
|
||||
void ServerPlayer::stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint)
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
int bedX = bedPosition ? bedPosition->x : 0;
|
||||
int bedY = bedPosition ? bedPosition->y : 0;
|
||||
int bedZ = bedPosition ? bedPosition->z : 0;
|
||||
bool wasSleeping = isSleeping();
|
||||
#endif
|
||||
if (isSleeping())
|
||||
{
|
||||
getLevel()->getTracker()->broadcastAndSend(shared_from_this(), std::make_shared<AnimatePacket>(shared_from_this(), AnimatePacket::WAKE_UP));
|
||||
}
|
||||
Player::stopSleepInBed(forcefulWakeUp, updateLevelList, saveRespawnPoint);
|
||||
if (connection != nullptr) connection->teleport(x, y, z, yRot, xRot);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (wasSleeping)
|
||||
FourKitBridge::FireBedLeave(entityId, dimension, bedX, bedY, bedZ);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ServerPlayer::ride(shared_ptr<Entity> e)
|
||||
|
|
@ -874,10 +1121,18 @@ bool ServerPlayer::startCrafting(int x, int y, int z)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::WORKBENCH, L"", 9, false));
|
||||
containerMenu = new CraftingMenu(inventory, level, x, y, z);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::WORKBENCH, L"", 9))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::WORKBENCH, L"", 9, false));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -892,20 +1147,36 @@ bool ServerPlayer::openFireworks(int x, int y, int z)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::FIREWORKS, L"", 9, false));
|
||||
containerMenu = new FireworksMenu(inventory, level, x, y, z);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::FIREWORKS, L"", 9))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::FIREWORKS, L"", 9, false));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else if(dynamic_cast<CraftingMenu *>(containerMenu) != nullptr)
|
||||
{
|
||||
closeContainer();
|
||||
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::FIREWORKS, L"", 9, false));
|
||||
containerMenu = new FireworksMenu(inventory, level, x, y, z);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::FIREWORKS, L"", 9))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::FIREWORKS, L"", 9, false));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -920,10 +1191,18 @@ bool ServerPlayer::startEnchanting(int x, int y, int z, const wstring &name)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::ENCHANTMENT, name.empty() ? L"" : name, 9, !name.empty()));
|
||||
containerMenu = new EnchantmentMenu(inventory, level, x, y, z);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::ENCHANTMENT, name.empty() ? L"" : name, 9))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::ENCHANTMENT, name.empty() ? L"" : name, 9, !name.empty()));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -938,10 +1217,18 @@ bool ServerPlayer::startRepairing(int x, int y, int z)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::REPAIR_TABLE, L"", 9, false));
|
||||
containerMenu = new AnvilMenu(inventory, level, x, y, z, dynamic_pointer_cast<Player>(shared_from_this()));
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::REPAIR_TABLE, L"", 9))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::REPAIR_TABLE, L"", 9, false));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -961,11 +1248,18 @@ bool ServerPlayer::openContainer(shared_ptr<Container> container)
|
|||
int containerType = container->getContainerType();
|
||||
assert(containerType >= 0);
|
||||
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, containerType, container->getCustomName(), container->getContainerSize(), container->hasCustomName()));
|
||||
|
||||
containerMenu = new ContainerMenu(inventory, container);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, containerType, container->getCustomName(), container->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, containerType, container->getCustomName(), container->getContainerSize(), container->hasCustomName()));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -980,10 +1274,18 @@ bool ServerPlayer::openHopper(shared_ptr<HopperTileEntity> container)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::HOPPER, container->getCustomName(), container->getContainerSize(), container->hasCustomName()));
|
||||
containerMenu = new HopperMenu(inventory, container);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::HOPPER, container->getCustomName(), container->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::HOPPER, container->getCustomName(), container->getContainerSize(), container->hasCustomName()));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -998,10 +1300,18 @@ bool ServerPlayer::openHopper(shared_ptr<MinecartHopper> container)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::HOPPER, container->getCustomName(), container->getContainerSize(), container->hasCustomName()));
|
||||
containerMenu = new HopperMenu(inventory, container);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::HOPPER, container->getCustomName(), container->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::HOPPER, container->getCustomName(), container->getContainerSize(), container->hasCustomName()));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1016,10 +1326,18 @@ bool ServerPlayer::openFurnace(shared_ptr<FurnaceTileEntity> furnace)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::FURNACE, furnace->getCustomName(), furnace->getContainerSize(), furnace->hasCustomName()));
|
||||
containerMenu = new FurnaceMenu(inventory, furnace);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::FURNACE, furnace->getCustomName(), furnace->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::FURNACE, furnace->getCustomName(), furnace->getContainerSize(), furnace->hasCustomName()));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1034,10 +1352,18 @@ bool ServerPlayer::openTrap(shared_ptr<DispenserTileEntity> trap)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, trap->GetType() == eTYPE_DROPPERTILEENTITY ? ContainerOpenPacket::DROPPER : ContainerOpenPacket::TRAP, trap->getCustomName(), trap->getContainerSize(), trap->hasCustomName()));
|
||||
containerMenu = new TrapMenu(inventory, trap);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, trap->GetType() == eTYPE_DROPPERTILEENTITY ? ContainerOpenPacket::DROPPER : ContainerOpenPacket::TRAP, trap->getCustomName(), trap->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, trap->GetType() == eTYPE_DROPPERTILEENTITY ? ContainerOpenPacket::DROPPER : ContainerOpenPacket::TRAP, trap->getCustomName(), trap->getContainerSize(), trap->hasCustomName()));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1052,10 +1378,18 @@ bool ServerPlayer::openBrewingStand(shared_ptr<BrewingStandTileEntity> brewingSt
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::BREWING_STAND, brewingStand->getCustomName(), brewingStand->getContainerSize(), brewingStand->hasCustomName()));
|
||||
containerMenu = new BrewingStandMenu(inventory, brewingStand);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::BREWING_STAND, brewingStand->getCustomName(), brewingStand->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::BREWING_STAND, brewingStand->getCustomName(), brewingStand->getContainerSize(), brewingStand->hasCustomName()));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1070,10 +1404,18 @@ bool ServerPlayer::openBeacon(shared_ptr<BeaconTileEntity> beacon)
|
|||
if(containerMenu == inventoryMenu)
|
||||
{
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::BEACON, beacon->getCustomName(), beacon->getContainerSize(), beacon->hasCustomName()));
|
||||
containerMenu = new BeaconMenu(inventory, beacon);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::BEACON, beacon->getCustomName(), beacon->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::BEACON, beacon->getCustomName(), beacon->getContainerSize(), beacon->hasCustomName()));
|
||||
refreshContainer(containerMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1093,7 +1435,15 @@ bool ServerPlayer::openTrading(shared_ptr<Merchant> traderTarget, const wstring
|
|||
containerMenu->addSlotListener(this);
|
||||
shared_ptr<Container> container = static_cast<MerchantMenu *>(containerMenu)->getTradeContainer();
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::TRADER_NPC, name.empty() ? L"" : name, container->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::TRADER_NPC, name.empty() ? L"" : name, container->getContainerSize(), !name.empty()));
|
||||
refreshContainer(containerMenu);
|
||||
|
||||
MerchantRecipeList *offers = traderTarget->getOffers(dynamic_pointer_cast<Player>(shared_from_this()));
|
||||
if (offers != nullptr)
|
||||
|
|
@ -1123,10 +1473,18 @@ bool ServerPlayer::openHorseInventory(shared_ptr<EntityHorse> horse, shared_ptr<
|
|||
closeContainer();
|
||||
}
|
||||
nextContainerCounter();
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::HORSE, horse->getCustomName(), container->getContainerSize(), container->hasCustomName(), horse->entityId));
|
||||
containerMenu = new HorseInventoryMenu(inventory, container, horse);
|
||||
containerMenu->containerId = containerCounter;
|
||||
containerMenu->addSlotListener(this);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (FourKitBridge::FireInventoryOpen(entityId, ContainerOpenPacket::HORSE, horse->getCustomName(), container->getContainerSize()))
|
||||
{
|
||||
doCloseContainer();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
connection->send(std::make_shared<ContainerOpenPacket>(containerCounter, ContainerOpenPacket::HORSE, horse->getCustomName(), container->getContainerSize(), container->hasCustomName(), horse->entityId));
|
||||
refreshContainer(containerMenu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,16 @@
|
|||
#include "..\Minecraft.World\net.minecraft.world.level.h"
|
||||
#include "..\Minecraft.World\net.minecraft.world.level.chunk.h"
|
||||
#include "..\Minecraft.World\net.minecraft.world.level.dimension.h"
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\Minecraft.World\EnchantmentHelper.h"
|
||||
#include "..\Minecraft.World\ExperienceOrb.h"
|
||||
#include "..\Minecraft.Server\FourKitBridge.h"
|
||||
#endif
|
||||
#include "MultiPlayerLevel.h"
|
||||
#include "LevelRenderer.h"
|
||||
|
||||
extern bool g_suppressExpDrops;
|
||||
|
||||
ServerPlayerGameMode::ServerPlayerGameMode(Level *level)
|
||||
{
|
||||
// 4J - added initialisers
|
||||
|
|
@ -247,7 +254,43 @@ bool ServerPlayerGameMode::destroyBlock(int x, int y, int z)
|
|||
|
||||
int t = level->getTile(x, y, z);
|
||||
int data = level->getData(x, y, z);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
int eventExp = 0;
|
||||
if (!isCreative() && !gameModeForPlayer->isAdventureRestricted())
|
||||
{
|
||||
Tile *tile = Tile::tiles[t];
|
||||
if (tile != nullptr && player->canDestroy(tile))
|
||||
{
|
||||
if (!EnchantmentHelper::hasSilkTouch(player))
|
||||
{
|
||||
// (SYLV)todo: shouldnt we get these values from the actual blocks?
|
||||
if (t == Tile::coalOre_Id)
|
||||
eventExp = Mth::nextInt(level->random, 0, 2);
|
||||
else if (t == Tile::diamondOre_Id)
|
||||
eventExp = Mth::nextInt(level->random, 3, 7);
|
||||
else if (t == Tile::emeraldOre_Id)
|
||||
eventExp = Mth::nextInt(level->random, 3, 7);
|
||||
else if (t == Tile::lapisOre_Id)
|
||||
eventExp = Mth::nextInt(level->random, 2, 5);
|
||||
else if (t == Tile::netherQuartz_Id)
|
||||
eventExp = Mth::nextInt(level->random, 2, 5);
|
||||
else if (t == Tile::redStoneOre_Id || t == Tile::redStoneOre_lit_Id)
|
||||
eventExp = 1 + level->random->nextInt(5);
|
||||
else if (t == Tile::mobSpawner_Id)
|
||||
eventExp = 15 + level->random->nextInt(15) + level->random->nextInt(15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dimId = level->dimension ? level->dimension->id : 0;
|
||||
int breakResult = FourKitBridge::FireBlockBreak(player->entityId, dimId, x, y, z, t, data, eventExp);
|
||||
if (breakResult < 0)
|
||||
{
|
||||
player->connection->send(std::make_shared<TileUpdatePacket>(x, y, z, level));
|
||||
return false;
|
||||
}
|
||||
int finalExp = breakResult;
|
||||
#endif
|
||||
level->levelEvent(player, LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, t + (level->getData(x, y, z) << Tile::TILE_NUM_SHIFT));
|
||||
|
||||
// 4J - In creative mode, the point where we need to tell the renderer that we are about to destroy a tile via destroyingTileAt is quite complicated.
|
||||
|
|
@ -305,8 +348,25 @@ bool ServerPlayerGameMode::destroyBlock(int x, int y, int z)
|
|||
}
|
||||
}
|
||||
if (changed && canDestroy)
|
||||
{
|
||||
{
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
g_suppressExpDrops = true;
|
||||
#endif
|
||||
|
||||
Tile::tiles[t]->playerDestroy(level, player, x, y, z, data);
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
g_suppressExpDrops = false;
|
||||
if (finalExp > 0)
|
||||
{
|
||||
while (finalExp > 0)
|
||||
{
|
||||
int xpDrop = ExperienceOrb::getExperienceValue(finalExp);
|
||||
finalExp -= xpDrop;
|
||||
level->addEntity(std::make_shared<ExperienceOrb>(level, x + .5, y + .5, z + .5, xpDrop));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
#include "..\Minecraft.World\net.minecraft.world.level.h"
|
||||
#include "..\Minecraft.World\net.minecraft.world.level.dimension.h"
|
||||
#include "TeleportCommand.h"
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\Minecraft.Server\FourKitBridge.h"
|
||||
#endif
|
||||
|
||||
EGameCommand TeleportCommand::getId()
|
||||
{
|
||||
|
|
@ -32,7 +35,21 @@ void TeleportCommand::execute(shared_ptr<CommandSender> source, byteArray comman
|
|||
if(subject != nullptr && destination != nullptr && subject->level->dimension->id == destination->level->dimension->id && subject->isAlive() )
|
||||
{
|
||||
subject->ride(nullptr);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
double outX, outY, outZ;
|
||||
bool cancelled = FourKitBridge::FirePlayerTeleport(subject->entityId,
|
||||
subject->x, subject->y, subject->z, subject->dimension,
|
||||
destination->x, destination->y, destination->z, destination->dimension,
|
||||
1 /* COMMAND */,
|
||||
&outX, &outY, &outZ);
|
||||
if (cancelled)
|
||||
return;
|
||||
subject->connection->teleport(outX, outY, outZ, destination->yRot, destination->xRot);
|
||||
}
|
||||
#else
|
||||
subject->connection->teleport(destination->x, destination->y, destination->z, destination->yRot, destination->xRot);
|
||||
#endif
|
||||
//logAdminAction(source, "commands.tp.success", subject->getAName(), destination->getAName());
|
||||
logAdminAction(source, ChatPacket::e_ChatCommandTeleportSuccess, subject->getName(), eTYPE_SERVERPLAYER, destination->getName());
|
||||
|
||||
|
|
|
|||
|
|
@ -119,9 +119,27 @@ bool WinsockNetLayer::Initialize()
|
|||
return true;
|
||||
}
|
||||
|
||||
void WinsockNetLayer::Shutdown()
|
||||
void WinsockNetLayer::StopListening()
|
||||
{
|
||||
StopAdvertising();
|
||||
|
||||
s_active = false;
|
||||
if (s_listenSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_listenSocket);
|
||||
s_listenSocket = INVALID_SOCKET;
|
||||
}
|
||||
if (s_acceptThread != nullptr)
|
||||
{
|
||||
WaitForSingleObject(s_acceptThread, 2000);
|
||||
CloseHandle(s_acceptThread);
|
||||
s_acceptThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void WinsockNetLayer::Shutdown()
|
||||
{
|
||||
StopListening();
|
||||
StopDiscovery();
|
||||
|
||||
s_joinCancel = true;
|
||||
|
|
@ -133,29 +151,14 @@ void WinsockNetLayer::Shutdown()
|
|||
}
|
||||
s_joinState = eJoinState_Idle;
|
||||
|
||||
s_active = false;
|
||||
s_connected = false;
|
||||
|
||||
if (s_listenSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_listenSocket);
|
||||
s_listenSocket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (s_hostConnectionSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
// Stop accept loop first so no new RecvThread can be created while shutting down.
|
||||
if (s_acceptThread != nullptr)
|
||||
{
|
||||
WaitForSingleObject(s_acceptThread, 2000);
|
||||
CloseHandle(s_acceptThread);
|
||||
s_acceptThread = nullptr;
|
||||
}
|
||||
|
||||
std::vector<HANDLE> recvThreads;
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
for (size_t i = 0; i < s_connections.size(); i++)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ class WinsockNetLayer
|
|||
public:
|
||||
static bool Initialize();
|
||||
static void Shutdown();
|
||||
static void StopListening();
|
||||
|
||||
static bool HostGame(int port, const char* bindIp = nullptr);
|
||||
static bool JoinGame(const char* ip, int port);
|
||||
|
|
|
|||
4
Minecraft.Server.FourKit/.editorconfig
Normal file
4
Minecraft.Server.FourKit/.editorconfig
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[*.cs]
|
||||
|
||||
# IDE1006: Naming Styles
|
||||
dotnet_diagnostic.IDE1006.severity = suggestion
|
||||
26
Minecraft.Server.FourKit/Block/Action.cs
Normal file
26
Minecraft.Server.FourKit/Block/Action.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
namespace Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the action type for a player interaction.
|
||||
/// </summary>
|
||||
public enum Action
|
||||
{
|
||||
/// <summary>Left-clicking the air.</summary>
|
||||
LEFT_CLICK_AIR = 0,
|
||||
|
||||
/// <summary>Left-clicking a block.</summary>
|
||||
LEFT_CLICK_BLOCK = 1,
|
||||
|
||||
/// <summary>Right-clicking the air.</summary>
|
||||
RIGHT_CLICK_AIR = 2,
|
||||
|
||||
/// <summary>Right-clicking a block.</summary>
|
||||
RIGHT_CLICK_BLOCK = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Stepping onto or into a block (Ass-pressure).
|
||||
/// Examples: Jumping on soil, Standing on pressure plate,
|
||||
/// Triggering redstone ore, Triggering tripwire.
|
||||
/// </summary>
|
||||
PHYSICAL = 4
|
||||
}
|
||||
109
Minecraft.Server.FourKit/Block/Biome.cs
Normal file
109
Minecraft.Server.FourKit/Block/Biome.cs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
namespace Minecraft.Server.FourKit.Block;
|
||||
|
||||
|
||||
public enum Biome
|
||||
{
|
||||
OCEAN = 0,
|
||||
PLAINS = 1,
|
||||
DESERT = 2,
|
||||
EXTREME_HILLS = 3,
|
||||
FOREST = 4,
|
||||
TAIGA = 5,
|
||||
SWAMPLAND = 6,
|
||||
RIVER = 7,
|
||||
HELL = 8,
|
||||
SKY = 9,
|
||||
FROZEN_OCEAN = 10,
|
||||
FROZEN_RIVER = 11,
|
||||
ICE_PLAINS = 12,
|
||||
ICE_MOUNTAINS = 13,
|
||||
MUSHROOM_ISLAND = 14,
|
||||
MUSHROOM_SHORE = 15,
|
||||
BEACH = 16,
|
||||
DESERT_HILLS = 17,
|
||||
FOREST_HILLS = 18,
|
||||
TAIGA_HILLS = 19,
|
||||
SMALL_MOUNTAINS = 20,
|
||||
JUNGLE = 21,
|
||||
JUNGLE_HILLS = 22,
|
||||
}
|
||||
|
||||
|
||||
// more for internal
|
||||
// eliminates unnecessary overhead
|
||||
internal static class BiomeHelper
|
||||
{
|
||||
private static readonly double[] _temperatures = new double[23];
|
||||
private static readonly double[] _rainfalls = new double[23];
|
||||
|
||||
static BiomeHelper()
|
||||
{
|
||||
_temperatures[(int)Biome.OCEAN] = 0.5;
|
||||
_temperatures[(int)Biome.PLAINS] = 0.8;
|
||||
_temperatures[(int)Biome.DESERT] = 2.0;
|
||||
_temperatures[(int)Biome.EXTREME_HILLS] = 0.2;
|
||||
_temperatures[(int)Biome.FOREST] = 0.7;
|
||||
_temperatures[(int)Biome.TAIGA] = 0.05;
|
||||
_temperatures[(int)Biome.SWAMPLAND] = 0.8;
|
||||
_temperatures[(int)Biome.RIVER] = 0.5;
|
||||
_temperatures[(int)Biome.HELL] = 2.0;
|
||||
_temperatures[(int)Biome.SKY] = 0.5;
|
||||
_temperatures[(int)Biome.FROZEN_OCEAN] = 0.0;
|
||||
_temperatures[(int)Biome.FROZEN_RIVER] = 0.0;
|
||||
_temperatures[(int)Biome.ICE_PLAINS] = 0.0;
|
||||
_temperatures[(int)Biome.ICE_MOUNTAINS] = 0.0;
|
||||
_temperatures[(int)Biome.MUSHROOM_ISLAND] = 0.9;
|
||||
_temperatures[(int)Biome.MUSHROOM_SHORE] = 0.9;
|
||||
_temperatures[(int)Biome.BEACH] = 0.8;
|
||||
_temperatures[(int)Biome.DESERT_HILLS] = 2.0;
|
||||
_temperatures[(int)Biome.FOREST_HILLS] = 0.7;
|
||||
_temperatures[(int)Biome.TAIGA_HILLS] = 0.05;
|
||||
_temperatures[(int)Biome.SMALL_MOUNTAINS] = 0.2;
|
||||
_temperatures[(int)Biome.JUNGLE] = 1.2;
|
||||
_temperatures[(int)Biome.JUNGLE_HILLS] = 1.2;
|
||||
|
||||
_rainfalls[(int)Biome.OCEAN] = 0.5;
|
||||
_rainfalls[(int)Biome.PLAINS] = 0.4;
|
||||
_rainfalls[(int)Biome.DESERT] = 0.0;
|
||||
_rainfalls[(int)Biome.EXTREME_HILLS] = 0.3;
|
||||
_rainfalls[(int)Biome.FOREST] = 0.8;
|
||||
_rainfalls[(int)Biome.TAIGA] = 0.8;
|
||||
_rainfalls[(int)Biome.SWAMPLAND] = 0.9;
|
||||
_rainfalls[(int)Biome.RIVER] = 0.5;
|
||||
_rainfalls[(int)Biome.HELL] = 0.0;
|
||||
_rainfalls[(int)Biome.SKY] = 0.5;
|
||||
_rainfalls[(int)Biome.FROZEN_OCEAN] = 0.5;
|
||||
_rainfalls[(int)Biome.FROZEN_RIVER] = 0.5;
|
||||
_rainfalls[(int)Biome.ICE_PLAINS] = 0.5;
|
||||
_rainfalls[(int)Biome.ICE_MOUNTAINS] = 0.5;
|
||||
_rainfalls[(int)Biome.MUSHROOM_ISLAND] = 1.0;
|
||||
_rainfalls[(int)Biome.MUSHROOM_SHORE] = 1.0;
|
||||
_rainfalls[(int)Biome.BEACH] = 0.4;
|
||||
_rainfalls[(int)Biome.DESERT_HILLS] = 0.0;
|
||||
_rainfalls[(int)Biome.FOREST_HILLS] = 0.8;
|
||||
_rainfalls[(int)Biome.TAIGA_HILLS] = 0.8;
|
||||
_rainfalls[(int)Biome.SMALL_MOUNTAINS] = 0.3;
|
||||
_rainfalls[(int)Biome.JUNGLE] = 0.9;
|
||||
_rainfalls[(int)Biome.JUNGLE_HILLS] = 0.9;
|
||||
}
|
||||
|
||||
public static double getTemperature(this Biome biome)
|
||||
{
|
||||
int id = (int)biome;
|
||||
if (id >= 0 && id < _temperatures.Length) return _temperatures[id];
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public static double getRainfall(this Biome biome)
|
||||
{
|
||||
int id = (int)biome;
|
||||
if (id >= 0 && id < _rainfalls.Length) return _rainfalls[id];
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public static Biome fromId(int id)
|
||||
{
|
||||
if (Enum.IsDefined(typeof(Biome), id)) return (Biome)id;
|
||||
return Biome.PLAINS;
|
||||
}
|
||||
}
|
||||
263
Minecraft.Server.FourKit/Block/Block.cs
Normal file
263
Minecraft.Server.FourKit/Block/Block.cs
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
namespace Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a block. This is a live object, and only one Block may exist for
|
||||
/// any given location in a world.
|
||||
/// </summary>
|
||||
public class Block
|
||||
{
|
||||
private readonly World _world;
|
||||
private readonly int _x;
|
||||
private readonly int _y;
|
||||
private readonly int _z;
|
||||
|
||||
internal Block(World world, int x, int y, int z)
|
||||
{
|
||||
_world = world;
|
||||
_x = x;
|
||||
_y = y;
|
||||
_z = z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Location of the block.
|
||||
/// </summary>
|
||||
/// <returns>Location of the block.</returns>
|
||||
public Location getLocation()
|
||||
{
|
||||
return new Location(_world, _x, _y, _z, 0f, 0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of this block.
|
||||
/// </summary>
|
||||
/// <returns>Block type.</returns>
|
||||
public Material getType()
|
||||
{
|
||||
int id = getTypeId();
|
||||
return Enum.IsDefined(typeof(Material), id) ? (Material)id : Material.AIR;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type ID of this block.
|
||||
/// </summary>
|
||||
/// <returns>Block type ID.</returns>
|
||||
public int getTypeId()
|
||||
{
|
||||
if (NativeBridge.GetTileId != null)
|
||||
return NativeBridge.GetTileId(_world.getDimensionId(), _x, _y, _z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the world which contains this Block.
|
||||
/// </summary>
|
||||
/// <returns>World containing this block.</returns>
|
||||
public World getWorld() => _world;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the x-coordinate of this block.
|
||||
/// </summary>
|
||||
/// <returns>X-coordinate.</returns>
|
||||
public int getX() => _x;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the y-coordinate of this block.
|
||||
/// </summary>
|
||||
/// <returns>Y-coordinate.</returns>
|
||||
public int getY() => _y;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the z-coordinate of this block.
|
||||
/// </summary>
|
||||
/// <returns>Z-coordinate.</returns>
|
||||
public int getZ() => _z;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the type of this block.
|
||||
/// </summary>
|
||||
/// <param name="type">Material to change this block to.</param>
|
||||
public void setType(Material type)
|
||||
{
|
||||
setTypeId((int)type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the type ID of this block.
|
||||
/// </summary>
|
||||
/// <param name="type">Type ID to change this block to.</param>
|
||||
/// <returns>Whether the change was successful.</returns>
|
||||
public bool setTypeId(int type)
|
||||
{
|
||||
NativeBridge.SetTile?.Invoke(_world.getDimensionId(), _x, _y, _z, type, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the metadata value for this block.
|
||||
/// </summary>
|
||||
/// <returns>Block specific metadata.</returns>
|
||||
public byte getData()
|
||||
{
|
||||
return (byte)NativeBridge.GetTileData(_world.getDimensionId(), _x, _y, _z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the metadata value for this block.
|
||||
/// </summary>
|
||||
/// <param name="data">New block specific metadata.</param>
|
||||
public void setData(byte data)
|
||||
{
|
||||
NativeBridge.SetTileData?.Invoke(_world.getDimensionId(), _x, _y, _z, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Breaks the block and spawns items as if a player had digged it.
|
||||
/// </summary>
|
||||
/// <returns>true if the block was destroyed.</returns>
|
||||
public bool breakNaturally()
|
||||
{
|
||||
if (NativeBridge.BreakBlock != null)
|
||||
return NativeBridge.BreakBlock(_world.getDimensionId(), _x, _y, _z) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block at the given offsets
|
||||
/// </summary>
|
||||
/// <param name="modX">X offset</param>
|
||||
/// <param name="modY">Y offset</param>
|
||||
/// <param name="modZ">Z offset</param>
|
||||
/// <returns>Block at the given offsets</returns>
|
||||
public Block getRelative(int modX, int modY, int modZ)
|
||||
{
|
||||
return getWorld().getBlockAt(getX() + modX, getY() + modY, getZ() + modZ);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the chunk which contains this block.
|
||||
/// </summary>
|
||||
/// <returns>Containing Chunk.</returns>
|
||||
public Chunk.Chunk getChunk()
|
||||
{
|
||||
return getWorld().getChunkAt(getX() >> 4, getZ() >> 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block at the given face
|
||||
/// <para>This method is equal to getRelative(face, 1)</para>
|
||||
/// </summary>
|
||||
/// <param name="face">BlockFace to get relative to</param>
|
||||
/// <returns>Block at the given face</returns>
|
||||
public Block getRelative(BlockFace face)
|
||||
{
|
||||
return getRelative(face, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block at the given distance of the given face
|
||||
/// <para>For example, the following method places water at 100,102,100; two
|
||||
/// blocks above 100,100,100.</para>
|
||||
/// <code>
|
||||
/// Block block = world.getBlockAt(100, 100, 100);
|
||||
/// Block shower = block.getRelative(BlockFace.UP, 2);
|
||||
/// shower.setType(Material.WATER);
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="face">BlockFace to get relative to</param>
|
||||
/// <param name="distance">Distance to get relative to</param>
|
||||
/// <returns>Block at the given distance of the given face</returns>
|
||||
public Block getRelative(BlockFace face, int distance)
|
||||
{
|
||||
return getRelative(face.getModX() * distance, face.getModY() * distance, face.getModZ() * distance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the biome that this block resides in.
|
||||
/// </summary>
|
||||
/// <returns>Biome type containing this block.</returns>
|
||||
public Biome getBiome()
|
||||
{
|
||||
if (NativeBridge.GetBiomeId != null)
|
||||
return BiomeHelper.fromId(NativeBridge.GetBiomeId(_world.getDimensionId(), _x, _z));
|
||||
return Biome.PLAINS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the biome that this block resides in.
|
||||
/// </summary>
|
||||
/// <param name="bio">New Biome type for this block.</param>
|
||||
public void setBiome(Biome bio)
|
||||
{
|
||||
NativeBridge.SetBiomeId?.Invoke(_world.getDimensionId(), _x, _z, (int)bio);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the humidity of the biome of this block.
|
||||
/// </summary>
|
||||
/// <returns>Humidity of this block.</returns>
|
||||
public double getHumidity()
|
||||
{
|
||||
return getBiome().getRainfall();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the temperature of the biome of this block.
|
||||
/// </summary>
|
||||
/// <returns>Temperature of this block.</returns>
|
||||
public double getTemperature()
|
||||
{
|
||||
return getBiome().getTemperature();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this block is liquid.
|
||||
/// <para>A block is considered liquid when <see cref="getType()"/> returns
|
||||
/// <see cref="Material.WATER"/>, <see cref="Material.STATIONARY_WATER"/>,
|
||||
/// <see cref="Material.LAVA"/> or <see cref="Material.STATIONARY_LAVA"/>.</para>
|
||||
/// </summary>
|
||||
/// <returns>true if this block is liquid.</returns>
|
||||
public bool isLiquid()
|
||||
{
|
||||
Material type = getType();
|
||||
return type == Material.WATER || type == Material.STATIONARY_WATER ||
|
||||
type == Material.LAVA || type == Material.STATIONARY_LAVA;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the light level between 0-15.
|
||||
/// </summary>
|
||||
/// <returns>Light level.</returns>
|
||||
public byte getLightLevel()
|
||||
{
|
||||
int sky = getLightFromSky();
|
||||
int block = getLightFromBlocks();
|
||||
return (byte)(sky > block ? sky : block);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the amount of light at this block from the sky.
|
||||
/// Any light given from other sources (such as blocks like torches) will be ignored.
|
||||
/// </summary>
|
||||
/// <returns>Sky light level.</returns>
|
||||
public byte getLightFromSky()
|
||||
{
|
||||
if (NativeBridge.GetSkyLight != null)
|
||||
return (byte)NativeBridge.GetSkyLight(_world.getDimensionId(), _x, _y, _z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the amount of light at this block from nearby blocks.
|
||||
/// Any light given from other sources (such as the sun) will be ignored.
|
||||
/// </summary>
|
||||
/// <returns>Block light level.</returns>
|
||||
public byte getLightFromBlocks()
|
||||
{
|
||||
if (NativeBridge.GetBlockLight != null)
|
||||
return (byte)NativeBridge.GetBlockLight(_world.getDimensionId(), _x, _y, _z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
118
Minecraft.Server.FourKit/Block/BlockFace.cs
Normal file
118
Minecraft.Server.FourKit/Block/BlockFace.cs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
namespace Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the face of a block.
|
||||
/// </summary>
|
||||
public enum BlockFace
|
||||
{
|
||||
DOWN = 0,
|
||||
UP = 1,
|
||||
NORTH = 2,
|
||||
SOUTH = 3,
|
||||
WEST = 4,
|
||||
EAST = 5,
|
||||
SELF = 6,
|
||||
NORTH_EAST,
|
||||
NORTH_WEST,
|
||||
SOUTH_EAST,
|
||||
SOUTH_WEST,
|
||||
WEST_NORTH_WEST,
|
||||
NORTH_NORTH_WEST,
|
||||
NORTH_NORTH_EAST,
|
||||
EAST_NORTH_EAST,
|
||||
EAST_SOUTH_EAST,
|
||||
SOUTH_SOUTH_EAST,
|
||||
SOUTH_SOUTH_WEST,
|
||||
WEST_SOUTH_WEST
|
||||
}
|
||||
|
||||
public static class BlockFaceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the amount of X-coordinates to modify to get the represented block.
|
||||
/// </summary>
|
||||
/// <param name="face">The block face.</param>
|
||||
/// <returns>Amount of X-coordinates to modify.</returns>
|
||||
public static int getModX(this BlockFace face) => face switch
|
||||
{
|
||||
BlockFace.EAST => 1,
|
||||
BlockFace.WEST => -1,
|
||||
BlockFace.NORTH_EAST => 1,
|
||||
BlockFace.NORTH_WEST => -1,
|
||||
BlockFace.SOUTH_EAST => 1,
|
||||
BlockFace.SOUTH_WEST => -1,
|
||||
BlockFace.EAST_NORTH_EAST => 1,
|
||||
BlockFace.EAST_SOUTH_EAST => 1,
|
||||
BlockFace.NORTH_NORTH_EAST => 1,
|
||||
BlockFace.SOUTH_SOUTH_EAST => 1,
|
||||
BlockFace.WEST_NORTH_WEST => -1,
|
||||
BlockFace.WEST_SOUTH_WEST => -1,
|
||||
BlockFace.NORTH_NORTH_WEST => -1,
|
||||
BlockFace.SOUTH_SOUTH_WEST => -1,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Get the amount of Y-coordinates to modify to get the represented block.
|
||||
/// </summary>
|
||||
/// <param name="face">The block face.</param>
|
||||
/// <returns>Amount of Y-coordinates to modify.</returns>
|
||||
public static int getModY(this BlockFace face) => face switch
|
||||
{
|
||||
BlockFace.UP => 1,
|
||||
BlockFace.DOWN => -1,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Get the amount of Z-coordinates to modify to get the represented block.
|
||||
/// </summary>
|
||||
/// <param name="face">The block face.</param>
|
||||
/// <returns>Amount of Z-coordinates to modify.</returns>
|
||||
public static int getModZ(this BlockFace face) => face switch
|
||||
{
|
||||
BlockFace.NORTH => -1,
|
||||
BlockFace.SOUTH => 1,
|
||||
BlockFace.NORTH_EAST => -1,
|
||||
BlockFace.NORTH_WEST => -1,
|
||||
BlockFace.SOUTH_EAST => 1,
|
||||
BlockFace.SOUTH_WEST => 1,
|
||||
BlockFace.NORTH_NORTH_EAST => -1,
|
||||
BlockFace.NORTH_NORTH_WEST => -1,
|
||||
BlockFace.EAST_NORTH_EAST => -1,
|
||||
BlockFace.WEST_NORTH_WEST => -1,
|
||||
BlockFace.EAST_SOUTH_EAST => 1,
|
||||
BlockFace.WEST_SOUTH_WEST => 1,
|
||||
BlockFace.SOUTH_SOUTH_EAST => 1,
|
||||
BlockFace.SOUTH_SOUTH_WEST => 1,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the opposite face of this block face.
|
||||
/// </summary>
|
||||
/// <param name="face">The block face.</param>
|
||||
/// <returns>The opposite block face.</returns>
|
||||
public static BlockFace getOppositeFace(this BlockFace face) => face switch
|
||||
{
|
||||
BlockFace.NORTH => BlockFace.SOUTH,
|
||||
BlockFace.SOUTH => BlockFace.NORTH,
|
||||
BlockFace.EAST => BlockFace.WEST,
|
||||
BlockFace.WEST => BlockFace.EAST,
|
||||
BlockFace.UP => BlockFace.DOWN,
|
||||
BlockFace.DOWN => BlockFace.UP,
|
||||
BlockFace.NORTH_EAST => BlockFace.SOUTH_WEST,
|
||||
BlockFace.NORTH_WEST => BlockFace.SOUTH_EAST,
|
||||
BlockFace.SOUTH_EAST => BlockFace.NORTH_WEST,
|
||||
BlockFace.SOUTH_WEST => BlockFace.NORTH_EAST,
|
||||
BlockFace.WEST_NORTH_WEST => BlockFace.EAST_SOUTH_EAST,
|
||||
BlockFace.NORTH_NORTH_WEST => BlockFace.SOUTH_SOUTH_EAST,
|
||||
BlockFace.NORTH_NORTH_EAST => BlockFace.SOUTH_SOUTH_WEST,
|
||||
BlockFace.EAST_NORTH_EAST => BlockFace.WEST_SOUTH_WEST,
|
||||
BlockFace.EAST_SOUTH_EAST => BlockFace.WEST_NORTH_WEST,
|
||||
BlockFace.SOUTH_SOUTH_EAST => BlockFace.NORTH_NORTH_WEST,
|
||||
BlockFace.SOUTH_SOUTH_WEST => BlockFace.NORTH_NORTH_EAST,
|
||||
BlockFace.WEST_SOUTH_WEST => BlockFace.EAST_NORTH_EAST,
|
||||
_ => BlockFace.SELF
|
||||
};
|
||||
}
|
||||
215
Minecraft.Server.FourKit/Block/BlockState.cs
Normal file
215
Minecraft.Server.FourKit/Block/BlockState.cs
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
namespace Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a captured state of a block, which will not change
|
||||
/// automatically.
|
||||
///
|
||||
/// <para>Unlike <see cref="Block"/>, which only one object can exist per
|
||||
/// coordinate, BlockState can exist multiple times for any given Block.
|
||||
/// Note that another plugin may change the state of the block and you will
|
||||
/// not know, or they may change the block to another type entirely, causing
|
||||
/// your BlockState to become invalid.</para>
|
||||
/// </summary>
|
||||
public class BlockState
|
||||
{
|
||||
private readonly World _world;
|
||||
private readonly int _x;
|
||||
private readonly int _y;
|
||||
private readonly int _z;
|
||||
private int _typeId;
|
||||
private int _data;
|
||||
|
||||
internal BlockState(World world, int x, int y, int z, int typeId, int data)
|
||||
{
|
||||
_world = world;
|
||||
_x = x;
|
||||
_y = y;
|
||||
_z = z;
|
||||
_typeId = typeId;
|
||||
_data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block represented by this BlockState.
|
||||
/// </summary>
|
||||
/// <returns>Block that this BlockState represents.</returns>
|
||||
public Block getBlock()
|
||||
{
|
||||
return new Block(_world, _x, _y, _z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the metadata for this block.
|
||||
/// </summary>
|
||||
/// <returns>Block specific metadata.</returns>
|
||||
public int getData() => _data;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the metadata for this block.
|
||||
/// </summary>
|
||||
/// <param name="data">New block specific metadata.</param>
|
||||
public void setData(int data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of this block.
|
||||
/// </summary>
|
||||
/// <returns>Block type.</returns>
|
||||
public Material getType()
|
||||
{
|
||||
return Enum.IsDefined(typeof(Material), _typeId) ? (Material)_typeId : Material.AIR;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type ID of this block.
|
||||
/// </summary>
|
||||
/// <returns>Block type ID.</returns>
|
||||
public int getTypeId() => _typeId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the world which contains this Block.
|
||||
/// </summary>
|
||||
/// <returns>World containing this block.</returns>
|
||||
public World getWorld() => _world;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the x-coordinate of this block.
|
||||
/// </summary>
|
||||
/// <returns>X-coordinate.</returns>
|
||||
public int getX() => _x;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the y-coordinate of this block.
|
||||
/// </summary>
|
||||
/// <returns>Y-coordinate.</returns>
|
||||
public int getY() => _y;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the z-coordinate of this block.
|
||||
/// </summary>
|
||||
/// <returns>Z-coordinate.</returns>
|
||||
public int getZ() => _z;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the chunk which contains this block.
|
||||
/// </summary>
|
||||
/// <returns>Containing Chunk.</returns>
|
||||
public Chunk.Chunk getChunk()
|
||||
{
|
||||
return _world.getChunkAt(_x >> 4, _z >> 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the location of this block.
|
||||
/// </summary>
|
||||
/// <returns>Location.</returns>
|
||||
public Location getLocation()
|
||||
{
|
||||
return new Location(_world, _x, _y, _z, 0f, 0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the location of this block in the provided Location object.
|
||||
/// If the provided Location is null this method does nothing and returns
|
||||
/// null.
|
||||
/// </summary>
|
||||
/// <param name="loc">The location object to store in.</param>
|
||||
/// <returns>The Location object provided or null.</returns>
|
||||
public Location? getLocation(Location? loc)
|
||||
{
|
||||
if (loc == null) return null;
|
||||
loc.X = _x;
|
||||
loc.Y = _y;
|
||||
loc.Z = _z;
|
||||
loc.LocationWorld = _world;
|
||||
return loc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the type of this block.
|
||||
/// </summary>
|
||||
/// <param name="type">Material to change this block to.</param>
|
||||
public void setType(Material type)
|
||||
{
|
||||
_typeId = (int)type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the type ID of this block.
|
||||
/// </summary>
|
||||
/// <param name="type">Type ID to change this block to.</param>
|
||||
/// <returns>Whether the change was accepted.</returns>
|
||||
public bool setTypeId(int type)
|
||||
{
|
||||
_typeId = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to update the block represented by this state, setting it to
|
||||
/// the new values as defined by this state.
|
||||
/// <para>This has the same effect as calling <c>update(false)</c>.</para>
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the update was successful, otherwise
|
||||
/// <c>false</c>.</returns>
|
||||
public bool update()
|
||||
{
|
||||
return update(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to update the block represented by this state, setting it to
|
||||
/// the new values as defined by this state.
|
||||
/// <para>This has the same effect as calling
|
||||
/// <c>update(force, true)</c>.</para>
|
||||
/// </summary>
|
||||
/// <param name="force"><c>true</c> to forcefully set the state.</param>
|
||||
/// <returns><c>true</c> if the update was successful, otherwise
|
||||
/// <c>false</c>.</returns>
|
||||
public bool update(bool force)
|
||||
{
|
||||
return update(force, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to update the block represented by this state, setting it to
|
||||
/// the new values as defined by this state.
|
||||
/// <para>Unless <paramref name="force"/> is true, this will not modify the
|
||||
/// state of a block if it is no longer the same type as it was when this
|
||||
/// state was taken. It will return false in this eventuality.</para>
|
||||
/// <para>If <paramref name="force"/> is true, it will set the type of the
|
||||
/// block to match the new state, set the state data and then return
|
||||
/// true.</para>
|
||||
/// <para>If <paramref name="applyPhysics"/> is true, it will trigger a
|
||||
/// physics update on surrounding blocks which could cause them to update
|
||||
/// or disappear.</para>
|
||||
/// </summary>
|
||||
/// <param name="force"><c>true</c> to forcefully set the state.</param>
|
||||
/// <param name="applyPhysics"><c>false</c> to cancel updating physics on
|
||||
/// surrounding blocks.</param>
|
||||
/// <returns><c>true</c> if the update was successful, otherwise
|
||||
/// <c>false</c>.</returns>
|
||||
public bool update(bool force, bool applyPhysics)
|
||||
{
|
||||
if (NativeBridge.GetTileId == null || NativeBridge.SetTile == null)
|
||||
return false;
|
||||
|
||||
int currentType = NativeBridge.GetTileId(_world.getDimensionId(), _x, _y, _z);
|
||||
if (!force && currentType != _typeId)
|
||||
return false;
|
||||
|
||||
NativeBridge.SetTile(_world.getDimensionId(), _x, _y, _z, _typeId, _data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the light level between 0-15.
|
||||
/// </summary>
|
||||
/// <returns>Light level.</returns>
|
||||
public byte getLightLevel()
|
||||
{
|
||||
return getBlock().getLightLevel();
|
||||
}
|
||||
}
|
||||
32
Minecraft.Server.FourKit/CMakeLists.txt
Normal file
32
Minecraft.Server.FourKit/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
set(FOURKIT_PROJECT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(FOURKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/bin/$<CONFIG>")
|
||||
set(FOURKIT_CSPROJ "${FOURKIT_PROJECT_DIR}/Minecraft.Server.FourKit.csproj")
|
||||
|
||||
file(GLOB_RECURSE FOURKIT_SOURCES RELATIVE "${FOURKIT_PROJECT_DIR}" "${FOURKIT_PROJECT_DIR}/*.cs")
|
||||
list(FILTER FOURKIT_SOURCES EXCLUDE REGEX "([/\\](obj|bin)[/\\])|^(obj|bin)[/\\]")
|
||||
|
||||
set(DOTNET_CONFIG "$<IF:$<CONFIG:Debug>,Debug,Release>")
|
||||
|
||||
foreach(src_file IN LISTS FOURKIT_SOURCES)
|
||||
get_filename_component(src_path "${src_file}" PATH)
|
||||
if(src_path)
|
||||
string(REPLACE "/" "\\" group_path "${src_path}")
|
||||
source_group("${group_path}" FILES "${FOURKIT_PROJECT_DIR}/${src_file}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(TRANSFORM FOURKIT_SOURCES PREPEND "${FOURKIT_PROJECT_DIR}/")
|
||||
|
||||
add_custom_target(Minecraft.Server.FourKit ALL
|
||||
COMMAND dotnet build "${FOURKIT_CSPROJ}"
|
||||
--configuration "${DOTNET_CONFIG}"
|
||||
--output "${FOURKIT_OUTPUT_DIR}"
|
||||
WORKING_DIRECTORY "${FOURKIT_PROJECT_DIR}"
|
||||
SOURCES ${FOURKIT_SOURCES}
|
||||
COMMENT "dotnet build Minecraft.Server.FourKit"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set_target_properties(Minecraft.Server.FourKit PROPERTIES
|
||||
OUTPUT_NAME "Minecraft.Server.FourKit"
|
||||
)
|
||||
311
Minecraft.Server.FourKit/Chunk/Chunk.cs
Normal file
311
Minecraft.Server.FourKit/Chunk/Chunk.cs
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
using Minecraft.Server.FourKit.Block;
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Chunk;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a chunk of blocks.
|
||||
/// </summary>
|
||||
public class Chunk
|
||||
{
|
||||
private readonly World _world;
|
||||
private readonly int _chunkX;
|
||||
private readonly int _chunkZ;
|
||||
|
||||
internal Chunk(World world, int chunkX, int chunkZ)
|
||||
{
|
||||
_world = world;
|
||||
_chunkX = chunkX;
|
||||
_chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X-coordinate of this chunk.
|
||||
/// </summary>
|
||||
/// <returns>X-coordinate.</returns>
|
||||
public int getX() => _chunkX;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Z-coordinate of this chunk.
|
||||
/// </summary>
|
||||
/// <returns>Z-coordinate.</returns>
|
||||
public int getZ() => _chunkZ;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the world containing this chunk.
|
||||
/// </summary>
|
||||
/// <returns>Parent World.</returns>
|
||||
public World getWorld() => _world;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a block from this chunk.
|
||||
/// </summary>
|
||||
/// <param name="x">0-15</param>
|
||||
/// <param name="y">0-127</param>
|
||||
/// <param name="z">0-15</param>
|
||||
/// <returns>The Block.</returns>
|
||||
public Block.Block getBlock(int x, int y, int z)
|
||||
{
|
||||
return _world.getBlockAt((_chunkX << 4) + x, y, (_chunkZ << 4) + z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture thread-safe read-only snapshot of chunk data.
|
||||
/// </summary>
|
||||
/// <returns>ChunkSnapshot.</returns>
|
||||
public ChunkSnapshot getChunkSnapshot()
|
||||
{
|
||||
return getChunkSnapshot(false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture thread-safe read-only snapshot of chunk data.
|
||||
/// </summary>
|
||||
/// <param name="includeBiome">If true, snapshot includes per-coordinate biome type.</param>
|
||||
/// <param name="includeBiomeTempRain">If true, snapshot includes per-coordinate raw biome temperature and rainfall.</param>
|
||||
/// <returns>ChunkSnapshot.</returns>
|
||||
public ChunkSnapshot getChunkSnapshot(bool includeBiome, bool includeBiomeTempRain)
|
||||
{
|
||||
// this has a lot of overhead
|
||||
// (SYLV)todo: clean this up
|
||||
int dimId = _world.getDimensionId();
|
||||
int[] blockIds = new int[16 * 128 * 16];
|
||||
int[] blockData = new int[16 * 128 * 16];
|
||||
int[] maxBlockY = new int[16 * 16];
|
||||
int[] skyLight = new int[16 * 128 * 16];
|
||||
int[] blockLight = new int[16 * 128 * 16];
|
||||
int[]? biomeIds = includeBiome ? new int[16 * 16] : null;
|
||||
double[]? biomeTemp = includeBiomeTempRain ? new double[16 * 16] : null;
|
||||
double[]? biomeRainfall = includeBiomeTempRain ? new double[16 * 16] : null;
|
||||
|
||||
if (NativeBridge.GetChunkSnapshot != null)
|
||||
{
|
||||
var hIds = GCHandle.Alloc(blockIds, GCHandleType.Pinned);
|
||||
var hData = GCHandle.Alloc(blockData, GCHandleType.Pinned);
|
||||
var hMaxY = GCHandle.Alloc(maxBlockY, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
NativeBridge.GetChunkSnapshot(dimId, _chunkX, _chunkZ,
|
||||
hIds.AddrOfPinnedObject(),
|
||||
hData.AddrOfPinnedObject(),
|
||||
hMaxY.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
hIds.Free();
|
||||
hData.Free();
|
||||
hMaxY.Free();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int lx = 0; lx < 16; lx++)
|
||||
{
|
||||
for (int lz = 0; lz < 16; lz++)
|
||||
{
|
||||
int worldX = (_chunkX << 4) + lx;
|
||||
int worldZ = (_chunkZ << 4) + lz;
|
||||
int highest = 0;
|
||||
for (int ly = 0; ly < 128; ly++)
|
||||
{
|
||||
int idx = (lx * 128 * 16) + (ly * 16) + lz;
|
||||
if (NativeBridge.GetTileId != null)
|
||||
blockIds[idx] = NativeBridge.GetTileId(dimId, worldX, ly, worldZ);
|
||||
if (NativeBridge.GetTileData != null)
|
||||
blockData[idx] = NativeBridge.GetTileData(dimId, worldX, ly, worldZ);
|
||||
if (blockIds[idx] != 0)
|
||||
highest = ly;
|
||||
}
|
||||
maxBlockY[lx * 16 + lz] = highest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int lx = 0; lx < 16; lx++)
|
||||
{
|
||||
for (int lz = 0; lz < 16; lz++)
|
||||
{
|
||||
int worldX = (_chunkX << 4) + lx;
|
||||
int worldZ = (_chunkZ << 4) + lz;
|
||||
for (int ly = 0; ly < 128; ly++)
|
||||
{
|
||||
int idx = (lx * 128 * 16) + (ly * 16) + lz;
|
||||
if (NativeBridge.GetSkyLight != null)
|
||||
skyLight[idx] = NativeBridge.GetSkyLight(dimId, worldX, ly, worldZ);
|
||||
if (NativeBridge.GetBlockLight != null)
|
||||
blockLight[idx] = NativeBridge.GetBlockLight(dimId, worldX, ly, worldZ);
|
||||
}
|
||||
if (includeBiome && NativeBridge.GetBiomeId != null)
|
||||
{
|
||||
int colIdx = lx * 16 + lz;
|
||||
int biomeId = NativeBridge.GetBiomeId(dimId, worldX, worldZ);
|
||||
biomeIds![colIdx] = biomeId;
|
||||
if (includeBiomeTempRain)
|
||||
{
|
||||
var biome = Block.BiomeHelper.fromId(biomeId);
|
||||
biomeTemp![colIdx] = biome.getTemperature();
|
||||
biomeRainfall![colIdx] = biome.getRainfall();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long captureTime = 0;
|
||||
if (NativeBridge.GetWorldInfo != null)
|
||||
{
|
||||
double[] info = new double[7];
|
||||
var hInfo = GCHandle.Alloc(info, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
NativeBridge.GetWorldInfo(dimId, hInfo.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
hInfo.Free();
|
||||
}
|
||||
captureTime = (long)info[4];
|
||||
}
|
||||
|
||||
return new ChunkSnapshot(_chunkX, _chunkZ, _world.getName(), captureTime,
|
||||
blockIds, blockData, maxBlockY,
|
||||
skyLight, blockLight, biomeIds, biomeTemp, biomeRainfall);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture thread-safe read-only snapshot of chunk data.
|
||||
/// </summary>
|
||||
/// <param name="includeMaxblocky">(NONFUNCTIONAL) Only here for parity.</param>
|
||||
/// <param name="includeBiome">If true, snapshot includes per-coordinate biome type.</param>
|
||||
/// <param name="includeBiomeTempRain">If true, snapshot includes per-coordinate raw biome temperature and rainfall.</param>
|
||||
/// <returns>ChunkSnapshot.</returns>
|
||||
public ChunkSnapshot getChunkSnapshot(bool includeMaxblocky, bool includeBiome, bool includeBiomeTempRain)
|
||||
{
|
||||
return getChunkSnapshot(includeBiome, includeBiomeTempRain);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all entities in the chunk.
|
||||
/// </summary>
|
||||
/// <returns>The entities.</returns>
|
||||
public Entity.Entity[] getEntities()
|
||||
{
|
||||
if (NativeBridge.GetChunkEntities == null) return Array.Empty<Entity.Entity>();
|
||||
|
||||
int dimId = _world.getDimensionId();
|
||||
int count = NativeBridge.GetChunkEntities(dimId, _chunkX, _chunkZ, out IntPtr buf);
|
||||
if (count <= 0 || buf == IntPtr.Zero) return Array.Empty<Entity.Entity>();
|
||||
|
||||
var result = new Entity.Entity[count];
|
||||
try
|
||||
{
|
||||
int[] data = new int[count * 3];
|
||||
Marshal.Copy(buf, data, 0, count * 3);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int entityId = data[i * 3];
|
||||
int mappedType = data[i * 3 + 1];
|
||||
int isLiving = data[i * 3 + 2];
|
||||
|
||||
var entityType = Enum.IsDefined(typeof(Entity.EntityType), mappedType)
|
||||
? (Entity.EntityType)mappedType
|
||||
: Entity.EntityType.UNKNOWN;
|
||||
|
||||
if (entityType == Entity.EntityType.PLAYER)
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player != null)
|
||||
{
|
||||
result[i] = player;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLiving == 1)
|
||||
{
|
||||
result[i] = new Entity.LivingEntity(entityId, entityType, dimId, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entity = new Entity.Entity();
|
||||
entity.SetEntityIdInternal(entityId);
|
||||
entity.SetEntityTypeInternal(entityType);
|
||||
entity.SetDimensionInternal(dimId);
|
||||
result[i] = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(buf);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the chunk is loaded.
|
||||
/// </summary>
|
||||
/// <returns>True if it is loaded.</returns>
|
||||
public bool isLoaded()
|
||||
{
|
||||
if (NativeBridge.IsChunkLoaded != null)
|
||||
return NativeBridge.IsChunkLoaded(_world.getDimensionId(), _chunkX, _chunkZ) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the chunk.
|
||||
/// </summary>
|
||||
/// <param name="generate">Whether or not to generate a chunk if it doesn't already exist.</param>
|
||||
/// <returns>true if the chunk has loaded successfully, otherwise false.</returns>
|
||||
public bool load(bool generate)
|
||||
{
|
||||
if (NativeBridge.LoadChunk != null)
|
||||
return NativeBridge.LoadChunk(_world.getDimensionId(), _chunkX, _chunkZ, generate ? 1 : 0) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the chunk.
|
||||
/// </summary>
|
||||
/// <returns>true if the chunk has loaded successfully, otherwise false.</returns>
|
||||
public bool load()
|
||||
{
|
||||
return load(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads and optionally saves the Chunk.
|
||||
/// </summary>
|
||||
/// <param name="save">Controls whether the chunk is saved.</param>
|
||||
/// <param name="safe">Controls whether to unload the chunk when players are nearby.</param>
|
||||
/// <returns>true if the chunk has unloaded successfully, otherwise false.</returns>
|
||||
public bool unload(bool save, bool safe)
|
||||
{
|
||||
if (NativeBridge.UnloadChunk != null)
|
||||
return NativeBridge.UnloadChunk(_world.getDimensionId(), _chunkX, _chunkZ, save ? 1 : 0, safe ? 1 : 0) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads and optionally saves the Chunk.
|
||||
/// </summary>
|
||||
/// <param name="save">Controls whether the chunk is saved.</param>
|
||||
/// <returns>true if the chunk has unloaded successfully, otherwise false.</returns>
|
||||
public bool unload(bool save)
|
||||
{
|
||||
return unload(save, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads and optionally saves the Chunk.
|
||||
/// </summary>
|
||||
/// <returns>true if the chunk has unloaded successfully, otherwise false.</returns>
|
||||
public bool unload()
|
||||
{
|
||||
return unload(true, true);
|
||||
}
|
||||
}
|
||||
209
Minecraft.Server.FourKit/Chunk/ChunkSnapshot.cs
Normal file
209
Minecraft.Server.FourKit/Chunk/ChunkSnapshot.cs
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
namespace Minecraft.Server.FourKit.Chunk;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a static, thread-safe snapshot of chunk of blocks.
|
||||
/// Purpose is to allow clean, efficient copy of a chunk data to be made, and
|
||||
/// then handed off for processing in another thread (e.g. map rendering).
|
||||
/// </summary>
|
||||
public class ChunkSnapshot
|
||||
{
|
||||
private readonly int _chunkX;
|
||||
private readonly int _chunkZ;
|
||||
private readonly string _worldName;
|
||||
private readonly long _captureFullTime;
|
||||
private readonly int[] _blockIds;
|
||||
private readonly int[] _blockData;
|
||||
private readonly int[] _maxBlockY;
|
||||
private readonly int[]? _skyLight;
|
||||
private readonly int[]? _blockLight;
|
||||
private readonly int[]? _biome;
|
||||
private readonly double[]? _biomeTemp;
|
||||
private readonly double[]? _biomeRainfall;
|
||||
|
||||
internal ChunkSnapshot(int chunkX, int chunkZ, string worldName, long captureFullTime,
|
||||
int[] blockIds, int[] blockData, int[] maxBlockY,
|
||||
int[]? skyLight = null, int[]? blockLight = null,
|
||||
int[]? biome = null, double[]? biomeTemp = null, double[]? biomeRainfall = null)
|
||||
{
|
||||
_chunkX = chunkX;
|
||||
_chunkZ = chunkZ;
|
||||
_worldName = worldName;
|
||||
_captureFullTime = captureFullTime;
|
||||
_blockIds = blockIds;
|
||||
_blockData = blockData;
|
||||
_maxBlockY = maxBlockY;
|
||||
_skyLight = skyLight;
|
||||
_blockLight = blockLight;
|
||||
_biome = biome;
|
||||
_biomeTemp = biomeTemp;
|
||||
_biomeRainfall = biomeRainfall;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X-coordinate of this chunk.
|
||||
/// </summary>
|
||||
/// <returns>X-coordinate.</returns>
|
||||
public int getX() => _chunkX;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Z-coordinate of this chunk.
|
||||
/// </summary>
|
||||
/// <returns>Z-coordinate.</returns>
|
||||
public int getZ() => _chunkZ;
|
||||
|
||||
/// <summary>
|
||||
/// Gets name of the world containing this chunk.
|
||||
/// </summary>
|
||||
/// <returns>Parent World Name.</returns>
|
||||
public string getWorldName() => _worldName;
|
||||
|
||||
/// <summary>
|
||||
/// Get block type for block at corresponding coordinate in the chunk.
|
||||
/// </summary>
|
||||
/// <param name="x">0-15</param>
|
||||
/// <param name="y">0-127</param>
|
||||
/// <param name="z">0-15</param>
|
||||
/// <returns>0-255</returns>
|
||||
public int getBlockTypeId(int x, int y, int z)
|
||||
{
|
||||
int idx = (x * 128 * 16) + (y * 16) + z;
|
||||
if (idx < 0 || idx >= _blockIds.Length) return 0;
|
||||
return _blockIds[idx];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get block data for block at corresponding coordinate in the chunk.
|
||||
/// </summary>
|
||||
/// <param name="x">0-15</param>
|
||||
/// <param name="y">0-127</param>
|
||||
/// <param name="z">0-15</param>
|
||||
/// <returns>0-15</returns>
|
||||
public int getBlockData(int x, int y, int z)
|
||||
{
|
||||
int idx = (x * 128 * 16) + (y * 16) + z;
|
||||
if (idx < 0 || idx >= _blockData.Length) return 0;
|
||||
return _blockData[idx];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the highest non-air coordinate at the given coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x">X-coordinate of the blocks.</param>
|
||||
/// <param name="z">Z-coordinate of the blocks.</param>
|
||||
/// <returns>Y-coordinate of the highest non-air block.</returns>
|
||||
public int getHighestBlockYAt(int x, int z)
|
||||
{
|
||||
int idx = x * 16 + z;
|
||||
if (idx < 0 || idx >= _maxBlockY.Length) return 0;
|
||||
return _maxBlockY[idx];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get world full time when chunk snapshot was captured.
|
||||
/// </summary>
|
||||
/// <returns>Time in ticks.</returns>
|
||||
public long getCaptureFullTime() => _captureFullTime;
|
||||
|
||||
/// <summary>
|
||||
/// Test if section is empty.
|
||||
/// </summary>
|
||||
/// <param name="sy">Section Y coordinate (block Y / 16).</param>
|
||||
/// <returns>true if empty, false if not.</returns>
|
||||
public bool isSectionEmpty(int sy)
|
||||
{
|
||||
int startY = sy * 16;
|
||||
int endY = startY + 16;
|
||||
if (endY > 128) endY = 128;
|
||||
for (int x = 0; x < 16; x++)
|
||||
{
|
||||
for (int z = 0; z < 16; z++)
|
||||
{
|
||||
for (int y = startY; y < endY; y++)
|
||||
{
|
||||
int idx = (x * 128 * 16) + (y * 16) + z;
|
||||
if (idx >= 0 && idx < _blockIds.Length && _blockIds[idx] != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get sky light level for block at corresponding coordinate in the chunk.
|
||||
/// </summary>
|
||||
/// <param name="x">0-15</param>
|
||||
/// <param name="y">0-127</param>
|
||||
/// <param name="z">0-15</param>
|
||||
/// <returns>0-15</returns>
|
||||
public int getBlockSkyLight(int x, int y, int z)
|
||||
{
|
||||
if (_skyLight == null) return 0;
|
||||
int idx = (x * 128 * 16) + (y * 16) + z;
|
||||
if (idx < 0 || idx >= _skyLight.Length) return 0;
|
||||
return _skyLight[idx];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get light level emitted by block at corresponding coordinate in the chunk.
|
||||
/// </summary>
|
||||
/// <param name="x">0-15</param>
|
||||
/// <param name="y">0-127</param>
|
||||
/// <param name="z">0-15</param>
|
||||
/// <returns>0-15</returns>
|
||||
public int getBlockEmittedLight(int x, int y, int z)
|
||||
{
|
||||
if (_blockLight == null) return 0;
|
||||
int idx = (x * 128 * 16) + (y * 16) + z;
|
||||
if (idx < 0 || idx >= _blockLight.Length) return 0;
|
||||
return _blockLight[idx];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get biome at given coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x">X-coordinate (0-15)</param>
|
||||
/// <param name="z">Z-coordinate (0-15)</param>
|
||||
/// <returns>Biome at given coordinate.</returns>
|
||||
public Biome getBiome(int x, int z)
|
||||
{
|
||||
if (_biome == null) return Biome.PLAINS;
|
||||
int idx = x * 16 + z;
|
||||
if (idx < 0 || idx >= _biome.Length) return Biome.PLAINS;
|
||||
return BiomeHelper.fromId(_biome[idx]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get raw biome temperature (0.0-1.0) at given coordinate.
|
||||
/// </summary>
|
||||
/// <param name="x">X-coordinate (0-15)</param>
|
||||
/// <param name="z">Z-coordinate (0-15)</param>
|
||||
/// <returns>Temperature at given coordinate.</returns>
|
||||
public double getRawBiomeTemperature(int x, int z)
|
||||
{
|
||||
if (_biomeTemp != null)
|
||||
{
|
||||
int idx = x * 16 + z;
|
||||
if (idx >= 0 && idx < _biomeTemp.Length) return _biomeTemp[idx];
|
||||
}
|
||||
return getBiome(x, z).getTemperature();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get raw biome rainfall (0.0-1.0) at given coordinate.
|
||||
/// </summary>
|
||||
/// <param name="x">X-coordinate (0-15)</param>
|
||||
/// <param name="z">Z-coordinate (0-15)</param>
|
||||
/// <returns>Rainfall at given coordinate.</returns>
|
||||
public double getRawBiomeRainfall(int x, int z)
|
||||
{
|
||||
if (_biomeRainfall != null)
|
||||
{
|
||||
int idx = x * 16 + z;
|
||||
if (idx >= 0 && idx < _biomeRainfall.Length) return _biomeRainfall[idx];
|
||||
}
|
||||
return getBiome(x, z).getRainfall();
|
||||
}
|
||||
}
|
||||
110
Minecraft.Server.FourKit/Command/Command.cs
Normal file
110
Minecraft.Server.FourKit/Command/Command.cs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
namespace Minecraft.Server.FourKit.Command;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Command, which executes various tasks upon user input.
|
||||
/// </summary>
|
||||
public abstract class Command
|
||||
{
|
||||
private string _name;
|
||||
private string _description;
|
||||
private string _usage;
|
||||
private List<string> _aliases;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new command with the given name and no aliases.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of this command.</param>
|
||||
protected Command(string name)
|
||||
{
|
||||
_name = name;
|
||||
_description = string.Empty;
|
||||
_usage = "/" + name;
|
||||
_aliases = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new command with the given name, description, and aliases.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of this command.</param>
|
||||
/// <param name="description">A brief description of this command.</param>
|
||||
/// <param name="aliases">A list of aliases for this command.</param>
|
||||
protected Command(string name, string description, List<string> aliases)
|
||||
{
|
||||
_name = name;
|
||||
_description = description ?? string.Empty;
|
||||
_usage = "/" + name;
|
||||
_aliases = aliases ?? new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the command, returning its success.
|
||||
/// </summary>
|
||||
/// <param name="sender">Source of the command.</param>
|
||||
/// <param name="commandLabel">Alias of the command which was used.</param>
|
||||
/// <param name="args">Passed command arguments.</param>
|
||||
/// <returns><c>true</c> if the command was successful, otherwise <c>false</c>.</returns>
|
||||
public abstract bool execute(CommandSender sender, string commandLabel, string[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of active aliases of this command.
|
||||
/// </summary>
|
||||
/// <returns>List of aliases.</returns>
|
||||
public List<string> getAliases() => new(_aliases);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a brief description of this command.
|
||||
/// </summary>
|
||||
/// <returns>Description of this command.</returns>
|
||||
public string getDescription() => _description;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current label for this command.
|
||||
/// </summary>
|
||||
/// <returns>Current label.</returns>
|
||||
public string getLabel() => _name;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of this command.
|
||||
/// </summary>
|
||||
/// <returns>Name of this command.</returns>
|
||||
public string getName() => _name;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an example usage of this command.
|
||||
/// </summary>
|
||||
/// <returns>Usage string.</returns>
|
||||
public string getUsage() => _usage;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the list of aliases to request on registration for this command.
|
||||
/// </summary>
|
||||
/// <param name="aliases">Aliases to register.</param>
|
||||
/// <returns>This command.</returns>
|
||||
public Command setAliases(List<string> aliases)
|
||||
{
|
||||
_aliases = aliases ?? new List<string>();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a brief description of this command.
|
||||
/// </summary>
|
||||
/// <param name="description">New command description.</param>
|
||||
/// <returns>This command.</returns>
|
||||
public Command setDescription(string description)
|
||||
{
|
||||
_description = description ?? string.Empty;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the example usage of this command.
|
||||
/// </summary>
|
||||
/// <param name="usage">New example usage.</param>
|
||||
/// <returns>This command.</returns>
|
||||
public Command setUsage(string usage)
|
||||
{
|
||||
_usage = usage ?? string.Empty;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
17
Minecraft.Server.FourKit/Command/CommandExecutor.cs
Normal file
17
Minecraft.Server.FourKit/Command/CommandExecutor.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
namespace Minecraft.Server.FourKit.Command;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a class which contains a single method for executing commands.
|
||||
/// </summary>
|
||||
public interface CommandExecutor
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the given command, returning its success.
|
||||
/// </summary>
|
||||
/// <param name="sender">Source of the command.</param>
|
||||
/// <param name="command">Command which was executed.</param>
|
||||
/// <param name="label">Alias of the command which was used.</param>
|
||||
/// <param name="args">Passed command arguments.</param>
|
||||
/// <returns><c>true</c> if a valid command, otherwise <c>false</c>.</returns>
|
||||
bool onCommand(CommandSender sender, Command command, string label, string[] args);
|
||||
}
|
||||
25
Minecraft.Server.FourKit/Command/CommandSender.cs
Normal file
25
Minecraft.Server.FourKit/Command/CommandSender.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
namespace Minecraft.Server.FourKit.Command;
|
||||
|
||||
/// <summary>
|
||||
/// Represents something that can send commands and receive messages.
|
||||
/// </summary>
|
||||
public interface CommandSender
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends this sender a message.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to be displayed.</param>
|
||||
void sendMessage(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Sends this sender multiple messages.
|
||||
/// </summary>
|
||||
/// <param name="messages">An array of messages to be displayed.</param>
|
||||
void sendMessage(string[] messages);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of this command sender.
|
||||
/// </summary>
|
||||
/// <returns>Name of the sender.</returns>
|
||||
string getName();
|
||||
}
|
||||
27
Minecraft.Server.FourKit/Command/ConsoleCommandSender.cs
Normal file
27
Minecraft.Server.FourKit/Command/ConsoleCommandSender.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
namespace Minecraft.Server.FourKit.Command;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the server console as a command sender.
|
||||
/// </summary>
|
||||
public class ConsoleCommandSender : CommandSender
|
||||
{
|
||||
internal static readonly ConsoleCommandSender Instance = new();
|
||||
|
||||
private ConsoleCommandSender() { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void sendMessage(string message)
|
||||
{
|
||||
ServerLog.Info("console", message);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void sendMessage(string[] messages)
|
||||
{
|
||||
foreach (var msg in messages)
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string getName() => "CONSOLE";
|
||||
}
|
||||
44
Minecraft.Server.FourKit/Command/PluginCommand.cs
Normal file
44
Minecraft.Server.FourKit/Command/PluginCommand.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
namespace Minecraft.Server.FourKit.Command;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a <see cref="Command"/> belonging to a plugin.
|
||||
/// </summary>
|
||||
public class PluginCommand : Command
|
||||
{
|
||||
private CommandExecutor? _executor;
|
||||
|
||||
// should this remain internal?
|
||||
/// <summary>
|
||||
/// Creates a new plugin command with the given name.
|
||||
/// Use <see cref="FourKit.getCommand"/> to obtain instances.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of this command.</param>
|
||||
internal PluginCommand(string name) : base(name)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool execute(CommandSender sender, string commandLabel, string[] args)
|
||||
{
|
||||
if (_executor != null)
|
||||
return _executor.onCommand(sender, this, commandLabel, args);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="CommandExecutor"/> associated with this command.
|
||||
/// </summary>
|
||||
/// <returns>The command executor, or <c>null</c>.</returns>
|
||||
public CommandExecutor? getExecutor() => _executor;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="CommandExecutor"/> to run when the command is dispatched.
|
||||
/// </summary>
|
||||
/// <param name="executor">New executor to set.</param>
|
||||
/// <returns><c>true</c> if the executor was set.</returns>
|
||||
public bool setExecutor(CommandExecutor executor)
|
||||
{
|
||||
_executor = executor;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class AquaAffinityEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.LEATHER_HELMET, Material.CHAINMAIL_HELMET, Material.GOLD_HELMET, Material.IRON_HELMET, Material.DIAMOND_HELMET,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR_HEAD;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.WATER_WORKER;
|
||||
|
||||
public override int getMaxLevel() => 1;
|
||||
|
||||
public override string getName() => "aquaaffinity";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
//name could be changed
|
||||
public class BaneOfArthropodsEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.DAMAGE_ALL,
|
||||
EnchantmentType.DAMAGE_UNDEAD,
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.DAMAGE_ARTHOPODS;
|
||||
|
||||
public override int getMaxLevel() => 5;
|
||||
|
||||
public override string getName() => "arthopods"; //could be changed
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class BlastProtectionEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
|
||||
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
|
||||
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
|
||||
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
|
||||
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.PROTECTION_ENVIRONMENTAL,
|
||||
EnchantmentType.PROTECTION_FIRE,
|
||||
EnchantmentType.PROTECTION_PROJECTILE,
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_EXPLOSIVE;
|
||||
|
||||
public override int getMaxLevel() => 4;
|
||||
|
||||
public override string getName() => "blastprotection";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class EfficiencyEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
|
||||
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
Material.WOOD_SPADE, Material.STONE_SPADE, Material.IRON_SPADE, Material.GOLD_SPADE, Material.DIAMOND_SPADE,
|
||||
Material.WOOD_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.GOLD_HOE, Material.DIAMOND_HOE,
|
||||
|
||||
Material.SHEARS
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.TOOL;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.DIG_SPEAD;
|
||||
|
||||
public override int getMaxLevel() => 5;
|
||||
|
||||
public override string getName() => "efficiency";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
274
Minecraft.Server.FourKit/Enchantments/Enchantment.cs
Normal file
274
Minecraft.Server.FourKit/Enchantments/Enchantment.cs
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the applicable target for a Enchantment
|
||||
/// </summary>
|
||||
public enum EnchantmentTarget
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on all items
|
||||
/// </summary>
|
||||
ALL,
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on armor
|
||||
/// </summary>
|
||||
ARMOR,
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on feet slot armor
|
||||
/// </summary>
|
||||
ARMOR_FEET,
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on head slot armor
|
||||
/// </summary>
|
||||
ARMOR_HEAD,
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on leg slot armor
|
||||
/// </summary>
|
||||
ARMOR_LEGS,
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on torso slot armor
|
||||
/// </summary>
|
||||
ARMOR_TORSO,
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on bows.
|
||||
/// </summary>
|
||||
BOW,
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on tools (spades, pickaxe, hoes, axes)
|
||||
/// </summary>
|
||||
TOOL,
|
||||
/// <summary>
|
||||
/// Allows the Enchantment to be placed on weapons (swords)
|
||||
/// </summary>
|
||||
WEAPON,
|
||||
}
|
||||
|
||||
//these numbers match the same ones that the enchants register as, Enchantment.cpp - 41
|
||||
|
||||
/// <summary>
|
||||
/// The various type of enchantments that may be added to armour or weapons
|
||||
/// </summary>
|
||||
public enum EnchantmentType
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extra damage when shooting arrows from bows
|
||||
/// </summary>
|
||||
ARROW_DAMAGE = 48,
|
||||
/// <summary>
|
||||
/// Sets entities on fire when hit by arrows shot from a bow
|
||||
/// </summary>
|
||||
ARROW_FIRE = 50,
|
||||
/// <summary>
|
||||
/// Provides infinite arrows when shooting a bow
|
||||
/// </summary>
|
||||
ARROW_INFINITE = 51,
|
||||
/// <summary>
|
||||
/// Provides a knockback when an entity is hit by an arrow from a bow
|
||||
/// </summary>
|
||||
ARROW_KNOCKBACK = 49,
|
||||
/// <summary>
|
||||
/// Increases damage against all targets
|
||||
/// </summary>
|
||||
DAMAGE_ALL = 16,
|
||||
/// <summary>
|
||||
/// Increases damage against arthropod targets
|
||||
/// </summary>
|
||||
DAMAGE_ARTHOPODS = 18,
|
||||
/// <summary>
|
||||
/// Increases damage against undead targets
|
||||
/// </summary>
|
||||
DAMAGE_UNDEAD = 17,
|
||||
/// <summary>
|
||||
/// Increases the rate at which you mine/dig
|
||||
/// </summary>
|
||||
DIG_SPEAD = 32,
|
||||
/// <summary>
|
||||
/// Decreases the rate at which a tool looses durability
|
||||
/// </summary>
|
||||
DURABILITY = 34,
|
||||
/// <summary>
|
||||
/// When attacking a target, has a chance to set them on fire
|
||||
/// </summary>
|
||||
FIRE_ASPECT = 20,
|
||||
/// <summary>
|
||||
/// All damage to other targets will knock them back when hit
|
||||
/// </summary>
|
||||
KNOCKBACK = 19,
|
||||
/// <summary>
|
||||
/// Provides a chance of gaining extra loot when destroying blocks
|
||||
/// </summary>
|
||||
LOOT_BONUS_BLOCKS = 35,
|
||||
/// <summary>
|
||||
/// Provides a chance of gaining extra loot when killing monsters
|
||||
/// </summary>
|
||||
LOOT_BONUS_MOBS = 21,
|
||||
/// <summary>
|
||||
/// Decreases the rate of air loss whilst underwater
|
||||
/// </summary>
|
||||
OXYGEN = 5,
|
||||
/// <summary>
|
||||
/// Provides protection against environmental damage
|
||||
/// </summary>
|
||||
PROTECTION_ENVIRONMENTAL = 0,
|
||||
/// <summary>
|
||||
/// Provides protection against explosive damage
|
||||
/// </summary>
|
||||
PROTECTION_EXPLOSIVE = 3,
|
||||
/// <summary>
|
||||
/// Provides protection against fall damage
|
||||
/// </summary>
|
||||
PROTECTION_FALL = 2,
|
||||
/// <summary>
|
||||
/// Provides protection against fire damage
|
||||
/// </summary>
|
||||
PROTECTION_FIRE = 1,
|
||||
/// <summary>
|
||||
/// Provides protection against projectile damage
|
||||
/// </summary>
|
||||
PROTECTION_PROJECTILE = 4,
|
||||
/// <summary>
|
||||
/// Allows blocks to drop themselves instead of fragments (for example, stone instead of cobblestone)
|
||||
/// </summary>
|
||||
SILK_TOUCH = 33,
|
||||
/// <summary>
|
||||
/// Damages the attacker
|
||||
/// </summary>
|
||||
THORNS = 7,
|
||||
/// <summary>
|
||||
/// Increases the speed at which a player may mine underwater
|
||||
/// </summary>
|
||||
WATER_WORKER = 6
|
||||
}
|
||||
|
||||
public abstract class Enchantment
|
||||
{
|
||||
public static Enchantment PowerEnchantment => _registry[EnchantmentType.ARROW_DAMAGE];
|
||||
public static Enchantment FlameEnchantment => _registry[EnchantmentType.ARROW_FIRE];
|
||||
public static Enchantment InfinityEnchantment => _registry[EnchantmentType.ARROW_INFINITE];
|
||||
public static Enchantment PunchEnchantment => _registry[EnchantmentType.ARROW_KNOCKBACK];
|
||||
public static Enchantment SharpnessEnchantment => _registry[EnchantmentType.DAMAGE_ALL];
|
||||
public static Enchantment BaneOfArthropodsEnchantment => _registry[EnchantmentType.DAMAGE_ARTHOPODS];
|
||||
public static Enchantment SmiteEnchantment => _registry[EnchantmentType.DAMAGE_UNDEAD];
|
||||
public static Enchantment EfficiencyEnchantment => _registry[EnchantmentType.DIG_SPEAD];
|
||||
public static Enchantment UnbreakingEnchantment => _registry[EnchantmentType.DURABILITY];
|
||||
public static Enchantment FireAspectEnchantment => _registry[EnchantmentType.FIRE_ASPECT];
|
||||
public static Enchantment KnockbackEnchantment => _registry[EnchantmentType.KNOCKBACK];
|
||||
public static Enchantment FortuneEnchantment => _registry[EnchantmentType.LOOT_BONUS_BLOCKS];
|
||||
public static Enchantment LootingEnchantment => _registry[EnchantmentType.LOOT_BONUS_MOBS];
|
||||
public static Enchantment RespirationEnchantment => _registry[EnchantmentType.OXYGEN];
|
||||
public static Enchantment ProtectionEnchantment => _registry[EnchantmentType.PROTECTION_ENVIRONMENTAL];
|
||||
public static Enchantment BlastProtectionEnchantment => _registry[EnchantmentType.PROTECTION_EXPLOSIVE];
|
||||
public static Enchantment FeatherFallingEnchantment => _registry[EnchantmentType.PROTECTION_FALL];
|
||||
public static Enchantment FireProtectionEnchantment => _registry[EnchantmentType.PROTECTION_FIRE];
|
||||
public static Enchantment ProjectileProtectionEnchantment => _registry[EnchantmentType.PROTECTION_PROJECTILE];
|
||||
public static Enchantment SilkTouchEnchantment => _registry[EnchantmentType.SILK_TOUCH];
|
||||
public static Enchantment ThornsEnchantment => _registry[EnchantmentType.THORNS];
|
||||
public static Enchantment AquaAffinityEnchantment => _registry[EnchantmentType.WATER_WORKER];
|
||||
|
||||
|
||||
private static Dictionary<EnchantmentType, Enchantment> _registry = new Dictionary<EnchantmentType, Enchantment>()
|
||||
{
|
||||
{ EnchantmentType.ARROW_DAMAGE, new PowerEnchantment() },
|
||||
{ EnchantmentType.ARROW_FIRE, new FlameEnchantment() },
|
||||
{ EnchantmentType.ARROW_INFINITE, new InfinityEnchantment() },
|
||||
{ EnchantmentType.ARROW_KNOCKBACK, new PunchEnchantment() },
|
||||
{ EnchantmentType.DAMAGE_ALL, new SharpnessEnchantment() },
|
||||
{ EnchantmentType.DAMAGE_ARTHOPODS, new BaneOfArthropodsEnchantment() },
|
||||
{ EnchantmentType.DAMAGE_UNDEAD, new SmiteEnchantment() },
|
||||
{ EnchantmentType.DIG_SPEAD, new EfficiencyEnchantment() },
|
||||
{ EnchantmentType.DURABILITY, new UnbreakingEnchantment() },
|
||||
{ EnchantmentType.FIRE_ASPECT, new FireAspectEnchantment() },
|
||||
{ EnchantmentType.KNOCKBACK, new KnockbackEnchantment() },
|
||||
{ EnchantmentType.LOOT_BONUS_BLOCKS, new FortuneEnchantment() },
|
||||
{ EnchantmentType.LOOT_BONUS_MOBS, new LootingEnchantment() },
|
||||
{ EnchantmentType.OXYGEN, new RespirationEnchantment() },
|
||||
{ EnchantmentType.PROTECTION_ENVIRONMENTAL, new ProtectionEnchantment() },
|
||||
{ EnchantmentType.PROTECTION_EXPLOSIVE, new BlastProtectionEnchantment() },
|
||||
{ EnchantmentType.PROTECTION_FALL, new FeatherFallingEnchantment() },
|
||||
{ EnchantmentType.PROTECTION_FIRE, new FireProtectionEnchantment() },
|
||||
{ EnchantmentType.PROTECTION_PROJECTILE, new ProjectileProtectionEnchantment() },
|
||||
{ EnchantmentType.SILK_TOUCH, new SilkTouchEnchantment() },
|
||||
{ EnchantmentType.THORNS, new ThornsEnchantment() },
|
||||
{ EnchantmentType.WATER_WORKER, new AquaAffinityEnchantment() },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this Enchantment may be applied to the given <see cref="ItemStack"/>. This does not check if it conflicts with any enchantments already applied to the item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to test</param>
|
||||
/// <returns>True if the enchantment may be applied, otherwise False</returns>
|
||||
public abstract bool canEnchantItem(ItemStack item);
|
||||
|
||||
/// <summary>
|
||||
/// Check if this enchantment conflicts with another enchantment.
|
||||
/// </summary>
|
||||
/// <param name="other">The enchantment to check against </param>
|
||||
/// <returns>True if there is a conflict.</returns>
|
||||
public abstract bool conflictsWith(Enchantment other);
|
||||
//public abstract Enchantment getById(int id); //deprecated by bukkit
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Enchantment at the specified name
|
||||
/// </summary>
|
||||
/// <param name="name">Name to fetch.</param>
|
||||
/// <returns>Resulting Enchantment, or null if not found</returns>
|
||||
public static Enchantment? getByName(string name)
|
||||
{
|
||||
foreach (KeyValuePair<EnchantmentType, Enchantment> enchantmentPair in _registry)
|
||||
{
|
||||
if (enchantmentPair.Value.getName().Equals(name)) return enchantmentPair.Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Enchantment at the specified type
|
||||
/// </summary>
|
||||
/// <param name="type">Type to fetch.</param>
|
||||
/// <returns>Resulting Enchantment, or null if not found</returns>
|
||||
public static Enchantment getByType(EnchantmentType type)
|
||||
{
|
||||
return _registry[type]; //we should always have the enchant based on the type
|
||||
}
|
||||
|
||||
//public abstract int getId(); //deprecated by bukkit
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of <see cref="ItemStack"/> that may fit this Enchantment.
|
||||
/// </summary>
|
||||
/// <returns>Gets the type of <see cref="ItemStack"/> that may fit this Enchantment.</returns>
|
||||
public abstract EnchantmentTarget getItemTarget();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="EnchantmentType"/>.
|
||||
/// </summary>
|
||||
/// <returns>Gets the enchantment type.</returns>
|
||||
public abstract EnchantmentType getEnchantType();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum level that this Enchantment may become.
|
||||
/// </summary>
|
||||
/// <returns>Maximum level of the Enchantment</returns>
|
||||
public abstract int getMaxLevel();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique name of this enchantment
|
||||
/// </summary>
|
||||
/// <returns>Unique name</returns>
|
||||
public abstract string getName();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the level that this Enchantment should start at
|
||||
/// </summary>
|
||||
/// <returns>Starting level of the Enchantment</returns>
|
||||
public abstract int getStartLevel();
|
||||
|
||||
//public static bool isAcceptingRegistrations(); //we dont have enchant registrations
|
||||
//public static void registerEnchantment(Enchantment enchantment); //we dont have enchant registrations
|
||||
//public static void stopAcceptingRegistrations(); //we dont have enchant registrations
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class FeatherFallingEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.LEATHER_BOOTS, Material.LEATHER_BOOTS, Material.CHAINMAIL_BOOTS, Material.GOLD_BOOTS, Material.IRON_BOOTS, Material.DIAMOND_BOOTS,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR_FEET;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_FALL;
|
||||
|
||||
public override int getMaxLevel() => 4;
|
||||
|
||||
public override string getName() => "featherfalling";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class FireAspectEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.FIRE_ASPECT;
|
||||
|
||||
public override int getMaxLevel() => 2;
|
||||
|
||||
public override string getName() => "fireaspect";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class FireProtectionEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
|
||||
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
|
||||
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
|
||||
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
|
||||
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.PROTECTION_ENVIRONMENTAL,
|
||||
EnchantmentType.PROTECTION_EXPLOSIVE,
|
||||
EnchantmentType.PROTECTION_PROJECTILE,
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_FIRE;
|
||||
|
||||
public override int getMaxLevel() => 4;
|
||||
|
||||
public override string getName() => "fireprotection";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
26
Minecraft.Server.FourKit/Enchantments/FlameEnchantment.cs
Normal file
26
Minecraft.Server.FourKit/Enchantments/FlameEnchantment.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class FlameEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.BOW
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.BOW;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.ARROW_FIRE;
|
||||
|
||||
public override int getMaxLevel() => 1;
|
||||
|
||||
public override string getName() => "flame";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
31
Minecraft.Server.FourKit/Enchantments/FortuneEnchantment.cs
Normal file
31
Minecraft.Server.FourKit/Enchantments/FortuneEnchantment.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class FortuneEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
Material.WOOD_SPADE, Material.STONE_SPADE, Material.IRON_SPADE, Material.GOLD_SPADE, Material.DIAMOND_SPADE,
|
||||
Material.WOOD_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.GOLD_HOE, Material.DIAMOND_HOE,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.SILK_TOUCH
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.TOOL;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.LOOT_BONUS_BLOCKS;
|
||||
|
||||
public override int getMaxLevel() => 3;
|
||||
|
||||
public override string getName() => "fortune";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
26
Minecraft.Server.FourKit/Enchantments/InfinityEnchantment.cs
Normal file
26
Minecraft.Server.FourKit/Enchantments/InfinityEnchantment.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class InfinityEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.BOW
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.BOW;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.ARROW_INFINITE;
|
||||
|
||||
public override int getMaxLevel() => 1;
|
||||
|
||||
public override string getName() => "infinity";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class KnockbackEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.KNOCKBACK;
|
||||
|
||||
public override int getMaxLevel() => 2;
|
||||
|
||||
public override string getName() => "knockback";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
27
Minecraft.Server.FourKit/Enchantments/LootingEnchantment.cs
Normal file
27
Minecraft.Server.FourKit/Enchantments/LootingEnchantment.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class LootingEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.LOOT_BONUS_MOBS;
|
||||
|
||||
public override int getMaxLevel() => 3;
|
||||
|
||||
public override string getName() => "looting";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
26
Minecraft.Server.FourKit/Enchantments/PowerEnchantment.cs
Normal file
26
Minecraft.Server.FourKit/Enchantments/PowerEnchantment.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class PowerEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.BOW
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.BOW;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.ARROW_DAMAGE;
|
||||
|
||||
public override int getMaxLevel() => 5;
|
||||
|
||||
public override string getName() => "power";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class ProjectileProtectionEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
|
||||
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
|
||||
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
|
||||
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
|
||||
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.PROTECTION_ENVIRONMENTAL,
|
||||
EnchantmentType.PROTECTION_EXPLOSIVE,
|
||||
EnchantmentType.PROTECTION_FIRE,
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_PROJECTILE;
|
||||
|
||||
public override int getMaxLevel() => 4;
|
||||
|
||||
public override string getName() => "projectileprotection";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class ProtectionEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
|
||||
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
|
||||
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
|
||||
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
|
||||
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.PROTECTION_EXPLOSIVE,
|
||||
EnchantmentType.PROTECTION_FIRE,
|
||||
EnchantmentType.PROTECTION_PROJECTILE,
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_ENVIRONMENTAL;
|
||||
|
||||
public override int getMaxLevel() => 4;
|
||||
|
||||
public override string getName() => "protection";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
26
Minecraft.Server.FourKit/Enchantments/PunchEnchantment.cs
Normal file
26
Minecraft.Server.FourKit/Enchantments/PunchEnchantment.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class PunchEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.BOW
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.BOW;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.ARROW_KNOCKBACK;
|
||||
|
||||
public override int getMaxLevel() => 2;
|
||||
|
||||
public override string getName() => "punch";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class RespirationEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.LEATHER_HELMET, Material.CHAINMAIL_HELMET, Material.GOLD_HELMET, Material.IRON_HELMET, Material.DIAMOND_HELMET,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR_HEAD;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.OXYGEN;
|
||||
|
||||
public override int getMaxLevel() => 3;
|
||||
|
||||
public override string getName() => "respiration";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class SharpnessEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.DAMAGE_ARTHOPODS,
|
||||
EnchantmentType.DAMAGE_UNDEAD
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.DAMAGE_ALL;
|
||||
|
||||
public override int getMaxLevel() => 5;
|
||||
|
||||
public override string getName() => "sharpness";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class SilkTouchEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
Material.WOOD_SPADE, Material.STONE_SPADE, Material.IRON_SPADE, Material.GOLD_SPADE, Material.DIAMOND_SPADE,
|
||||
Material.WOOD_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.GOLD_HOE, Material.DIAMOND_HOE,
|
||||
|
||||
Material.SHEARS
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.LOOT_BONUS_BLOCKS
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.TOOL;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.SILK_TOUCH;
|
||||
|
||||
public override int getMaxLevel() => 1;
|
||||
|
||||
public override string getName() => "silktouch";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
30
Minecraft.Server.FourKit/Enchantments/SmiteEnchantment.cs
Normal file
30
Minecraft.Server.FourKit/Enchantments/SmiteEnchantment.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class SmiteEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = {
|
||||
EnchantmentType.DAMAGE_ALL,
|
||||
EnchantmentType.DAMAGE_ARTHOPODS
|
||||
};
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.DAMAGE_UNDEAD;
|
||||
|
||||
public override int getMaxLevel() => 5;
|
||||
|
||||
public override string getName() => "smite";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
30
Minecraft.Server.FourKit/Enchantments/ThornsEnchantment.cs
Normal file
30
Minecraft.Server.FourKit/Enchantments/ThornsEnchantment.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class ThornsEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
|
||||
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
|
||||
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
|
||||
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
|
||||
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.THORNS;
|
||||
|
||||
public override int getMaxLevel() => 3;
|
||||
|
||||
public override string getName() => "thorns";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enchantments;
|
||||
|
||||
public class UnbreakingEnchantment : Enchantment
|
||||
{
|
||||
static readonly Material[] supportedItems = {
|
||||
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
|
||||
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
|
||||
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
|
||||
Material.WOOD_SPADE, Material.STONE_SPADE, Material.IRON_SPADE, Material.GOLD_SPADE, Material.DIAMOND_SPADE,
|
||||
Material.WOOD_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.GOLD_HOE, Material.DIAMOND_HOE,
|
||||
|
||||
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
|
||||
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
|
||||
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
|
||||
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
|
||||
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
|
||||
|
||||
Material.FISHING_ROD, Material.BOW,
|
||||
Material.SHEARS, Material.FLINT_AND_STEEL, Material.CARROT_STICK
|
||||
};
|
||||
|
||||
static readonly EnchantmentType[] conflictedEnchants = { };
|
||||
|
||||
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
|
||||
|
||||
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
|
||||
|
||||
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ALL;
|
||||
|
||||
public override EnchantmentType getEnchantType() => EnchantmentType.DURABILITY;
|
||||
|
||||
public override int getMaxLevel() => 3;
|
||||
|
||||
public override string getName() => "unbreaking";
|
||||
|
||||
public override int getStartLevel() => 1;
|
||||
}
|
||||
79
Minecraft.Server.FourKit/Entity/Damageable.cs
Normal file
79
Minecraft.Server.FourKit/Entity/Damageable.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an <see cref="Entity"/> that can take damage and has health.
|
||||
/// </summary>
|
||||
public class Damageable : Entity
|
||||
{
|
||||
private double _health = 20.0;
|
||||
private double _maxHealth = 20.0;
|
||||
private readonly double _originalMaxHealth = 20.0;
|
||||
|
||||
/// <summary>
|
||||
/// Deals the given amount of damage to this entity.
|
||||
/// This calls into the native server to apply real damage.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount of damage to deal.</param>
|
||||
public void damage(double amount)
|
||||
{
|
||||
NativeBridge.DamagePlayer?.Invoke(getEntityId(), (float)amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity's health from 0 to <see cref="getMaxHealth"/>, where 0 is dead.
|
||||
/// </summary>
|
||||
/// <returns>The current health.</returns>
|
||||
public double getHealth() => _health;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum health this entity has.
|
||||
/// </summary>
|
||||
/// <returns>The maximum health.</returns>
|
||||
public double getMaxHealth() => _maxHealth;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the max health to the original amount.
|
||||
/// </summary>
|
||||
public void resetMaxHealth()
|
||||
{
|
||||
_maxHealth = _originalMaxHealth;
|
||||
if (_health > _maxHealth)
|
||||
_health = _maxHealth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the entity's health from 0 to <see cref="getMaxHealth"/>, where 0 is dead.
|
||||
/// This calls into the native server to apply the health change.
|
||||
/// </summary>
|
||||
/// <param name="health">New health value.</param>
|
||||
public void setHealth(double health)
|
||||
{
|
||||
NativeBridge.SetPlayerHealth?.Invoke(getEntityId(), (float)Math.Clamp(health, 0.0, _maxHealth));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum health this entity can have.
|
||||
/// If the entity's current health exceeds the new maximum, it is clamped.
|
||||
/// </summary>
|
||||
/// <param name="health">New maximum health value.</param>
|
||||
public void setMaxHealth(double health)
|
||||
{
|
||||
_maxHealth = health;
|
||||
if (_health > _maxHealth)
|
||||
_health = _maxHealth;
|
||||
}
|
||||
|
||||
// --- Internal setter used by the bridge ---
|
||||
|
||||
/// <summary>
|
||||
/// Updates health directly. Called internally by the bridge.
|
||||
/// </summary>
|
||||
/// <param name="health">The new health value.</param>
|
||||
internal void SetHealthInternal(double health) => _health = health;
|
||||
|
||||
/// <summary>
|
||||
/// Updates max health directly. Called internally by the bridge.
|
||||
/// </summary>
|
||||
/// <param name="maxHealth">The new max health value.</param>
|
||||
internal void SetMaxHealthInternal(double maxHealth) => _maxHealth = maxHealth;
|
||||
}
|
||||
66
Minecraft.Server.FourKit/Entity/DisconnectReason.cs
Normal file
66
Minecraft.Server.FourKit/Entity/DisconnectReason.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
// eh
|
||||
|
||||
/// <summary>
|
||||
/// Enum representing the reason a player was disconnected from the server.
|
||||
/// mirrored from <c>DisconnectPacket::eDisconnectReason</c>.
|
||||
/// </summary>
|
||||
public enum DisconnectReason
|
||||
{
|
||||
/// <summary>No specific reason.</summary>
|
||||
NONE = 0,
|
||||
/// <summary>The player quit voluntarily.</summary>
|
||||
QUITTING = 1,
|
||||
/// <summary>The connection was closed.</summary>
|
||||
CLOSED = 2,
|
||||
/// <summary>The login took too long.</summary>
|
||||
LOGIN_TOO_LONG = 3,
|
||||
/// <summary>The player had an illegal stance.</summary>
|
||||
ILLEGAL_STANCE = 4,
|
||||
/// <summary>The player had an illegal position.</summary>
|
||||
ILLEGAL_POSITION = 5,
|
||||
/// <summary>The player moved too quickly.</summary>
|
||||
MOVED_TOO_QUICKLY = 6,
|
||||
/// <summary>The player was flying when not allowed.</summary>
|
||||
NO_FLYING = 7,
|
||||
/// <summary>The player was kicked by an operator or plugin.</summary>
|
||||
KICKED = 8,
|
||||
/// <summary>The connection timed out.</summary>
|
||||
TIME_OUT = 9,
|
||||
/// <summary>Packet overflow.</summary>
|
||||
OVERFLOW = 10,
|
||||
/// <summary>End of stream reached unexpectedly.</summary>
|
||||
END_OF_STREAM = 11,
|
||||
/// <summary>The server is full.</summary>
|
||||
SERVER_FULL = 12,
|
||||
/// <summary>The server is outdated.</summary>
|
||||
OUTDATED_SERVER = 13,
|
||||
/// <summary>The client is outdated.</summary>
|
||||
OUTDATED_CLIENT = 14,
|
||||
/// <summary>An unexpected packet was received.</summary>
|
||||
UNEXPECTED_PACKET = 15,
|
||||
/// <summary>Connection creation failed.</summary>
|
||||
CONNECTION_CREATION_FAILED = 16,
|
||||
/// <summary>The host does not have multiplayer privileges.</summary>
|
||||
NO_MULTIPLAYER_PRIVILEGES_HOST = 17,
|
||||
/// <summary>The joining player does not have multiplayer privileges.</summary>
|
||||
NO_MULTIPLAYER_PRIVILEGES_JOIN = 18,
|
||||
/// <summary>All local players lack UGC permissions.</summary>
|
||||
NO_UGC_ALL_LOCAL = 19,
|
||||
/// <summary>A single local player lacks UGC permissions.</summary>
|
||||
NO_UGC_SINGLE_LOCAL = 20,
|
||||
/// <summary>All local players have content restrictions.</summary>
|
||||
CONTENT_RESTRICTED_ALL_LOCAL = 21,
|
||||
/// <summary>A single local player has content restrictions.</summary>
|
||||
CONTENT_RESTRICTED_SINGLE_LOCAL = 22,
|
||||
/// <summary>A remote player lacks UGC permissions.</summary>
|
||||
NO_UGC_REMOTE = 23,
|
||||
/// <summary>No friends in the game.</summary>
|
||||
NO_FRIENDS_IN_GAME = 24,
|
||||
/// <summary>The player was banned.</summary>
|
||||
BANNED = 25,
|
||||
/// <summary>The player is not friends with the host.</summary>
|
||||
NOT_FRIENDS_WITH_HOST = 26,
|
||||
/// <summary>NAT type mismatch.</summary>
|
||||
NAT_MISMATCH = 27,
|
||||
}
|
||||
192
Minecraft.Server.FourKit/Entity/Entity.cs
Normal file
192
Minecraft.Server.FourKit/Entity/Entity.cs
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
|
||||
using Minecraft.Server.FourKit.Util;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a base entity in the world
|
||||
/// </summary>
|
||||
public class Entity
|
||||
{
|
||||
private Location _location = new();
|
||||
private Guid _uniqueId = Guid.NewGuid();
|
||||
private float _fallDistance;
|
||||
private int _dimensionId;
|
||||
private int _entityId;
|
||||
private EntityType _entityType = EntityType.UNKNOWN;
|
||||
private bool _onGround;
|
||||
private double _velocityX, _velocityY, _velocityZ;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity's current position.
|
||||
/// </summary>
|
||||
/// <returns>a new copy of <see cref="Location"/> containing the position of this entity</returns>
|
||||
public Location getLocation() => _location;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a unique id for this entity
|
||||
/// </summary>
|
||||
/// <returns>Entity id</returns>
|
||||
public virtual int getEntityId() => _entityId;
|
||||
|
||||
/// <summary>
|
||||
/// Get the type of the entity.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="EntityType"/> of this entity.</returns>
|
||||
public new virtual EntityType getType() => _entityType;
|
||||
public new virtual EntityType GetType() => _entityType;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a unique and persistent id for this entity. Note that this is not the standard UUID for players.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Guid"/> unique to this entity.</returns>
|
||||
public Guid getUniqueId() => _uniqueId;
|
||||
|
||||
/// <summary>
|
||||
/// Teleports this entity to the given location.
|
||||
/// This calls into the native server to perform the actual teleport.
|
||||
/// </summary>
|
||||
/// <param name="location">The destination location.</param>
|
||||
/// <returns><c>true</c> if the teleport was successful.</returns>
|
||||
public virtual bool teleport(Location location)
|
||||
{
|
||||
int targetDimId = location.LocationWorld?.getDimensionId() ?? _dimensionId;
|
||||
NativeBridge.TeleportEntity?.Invoke(getEntityId(), targetDimId, location.getX(), location.getY(), location.getZ());
|
||||
SetLocation(location);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the fall distance for this entity.
|
||||
/// </summary>
|
||||
/// <param name="distance">The fall distance value.</param>
|
||||
public void setFallDistance(float distance)
|
||||
{
|
||||
_fallDistance = distance;
|
||||
NativeBridge.SetFallDistance?.Invoke(getEntityId(), distance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the distance this entity has fallen.
|
||||
/// </summary>
|
||||
/// <returns>The current fall distance.</returns>
|
||||
public float getFallDistance() => _fallDistance;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current world this entity resides in.
|
||||
/// </summary>
|
||||
/// <returns>World containing this entity.</returns>
|
||||
public World getWorld() => FourKit.getWorld(_dimensionId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the entity is supported by a block. This value is a
|
||||
/// state updated by the server and is not recalculated unless the entity moves.
|
||||
/// </summary>
|
||||
/// <returns>True if entity is on ground.</returns>
|
||||
public bool isOnGround() => _onGround;
|
||||
|
||||
/// <summary>
|
||||
/// Gets this entity's current velocity.
|
||||
/// </summary>
|
||||
/// <returns>Current travelling velocity of this entity.</returns>
|
||||
public Vector getVelocity() => new Vector(_velocityX, _velocityY, _velocityZ);
|
||||
|
||||
/// <summary>
|
||||
/// Sets this entity's velocity.
|
||||
/// </summary>
|
||||
/// <param name="velocity">New velocity to travel with.</param>
|
||||
public void setVelocity(Vector velocity)
|
||||
{
|
||||
_velocityX = velocity.getX();
|
||||
_velocityY = velocity.getY();
|
||||
_velocityZ = velocity.getZ();
|
||||
NativeBridge.SetVelocity?.Invoke(getEntityId(), velocity.getX(), velocity.getY(), velocity.getZ());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether this entity is inside a vehicle.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the entity is in a vehicle.</returns>
|
||||
public bool isInsideVehicle()
|
||||
{
|
||||
return (NativeBridge.GetVehicleId?.Invoke(getEntityId()) ?? -1) >= 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Leave the current vehicle. If the entity is currently in a vehicle
|
||||
/// (and is removed from it), <c>true</c> will be returned, otherwise
|
||||
/// <c>false</c> will be returned.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the entity was in a vehicle.</returns>
|
||||
public bool leaveVehicle()
|
||||
{
|
||||
return NativeBridge.LeaveVehicle?.Invoke(getEntityId()) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the vehicle that this entity is inside. If there is no vehicle,
|
||||
/// <c>null</c> will be returned.
|
||||
/// </summary>
|
||||
/// <returns>The current vehicle, or <c>null</c>.</returns>
|
||||
public Entity? getVehicle()
|
||||
{
|
||||
int vehicleId = NativeBridge.GetVehicleId?.Invoke(getEntityId()) ?? -1;
|
||||
if (vehicleId < 0) return null;
|
||||
return FourKit.GetEntityByEntityId(vehicleId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eject any passenger.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if there was a passenger.</returns>
|
||||
public bool eject()
|
||||
{
|
||||
return NativeBridge.Eject?.Invoke(getEntityId()) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primary passenger of a vehicle. For vehicles that could
|
||||
/// have multiple passengers, this will only return the primary passenger.
|
||||
/// </summary>
|
||||
/// <returns>The passenger entity, or <c>null</c>.</returns>
|
||||
public Entity? getPassenger()
|
||||
{
|
||||
int passengerId = NativeBridge.GetPassengerId?.Invoke(getEntityId()) ?? -1;
|
||||
if (passengerId < 0) return null;
|
||||
return FourKit.GetEntityByEntityId(passengerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the passenger of a vehicle.
|
||||
/// </summary>
|
||||
/// <param name="passenger">The new passenger.</param>
|
||||
/// <returns><c>false</c> if it could not be done for whatever reason.</returns>
|
||||
public bool setPassenger(Entity passenger)
|
||||
{
|
||||
if (passenger == null || NativeBridge.SetPassenger == null) return false;
|
||||
return NativeBridge.SetPassenger(getEntityId(), passenger.getEntityId()) != 0;
|
||||
}
|
||||
|
||||
// INTERNAL
|
||||
internal void SetLocation(Location location)
|
||||
{
|
||||
_location = location;
|
||||
}
|
||||
|
||||
internal void SetFallDistanceInternal(float distance) => _fallDistance = distance;
|
||||
|
||||
internal void SetUniqueId(Guid id)
|
||||
{
|
||||
_uniqueId = id;
|
||||
}
|
||||
|
||||
internal void SetDimensionInternal(int dimensionId) => _dimensionId = dimensionId;
|
||||
internal void SetEntityIdInternal(int entityId) => _entityId = entityId;
|
||||
internal void SetEntityTypeInternal(EntityType entityType) => _entityType = entityType;
|
||||
internal void SetOnGroundInternal(bool onGround) => _onGround = onGround;
|
||||
internal void SetVelocityInternal(double x, double y, double z)
|
||||
{
|
||||
_velocityX = x;
|
||||
_velocityY = y;
|
||||
_velocityZ = z;
|
||||
}
|
||||
}
|
||||
132
Minecraft.Server.FourKit/Entity/EntityType.cs
Normal file
132
Minecraft.Server.FourKit/Entity/EntityType.cs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the type of an <see cref="Entity"/>.
|
||||
/// </summary>
|
||||
public enum EntityType
|
||||
{
|
||||
/// <summary>An arrow projectile; may get stuck in the ground.</summary>
|
||||
ARROW,
|
||||
/// <summary>A bat.</summary>
|
||||
BAT,
|
||||
/// <summary>A blaze.</summary>
|
||||
BLAZE,
|
||||
/// <summary>A placed boat.</summary>
|
||||
BOAT,
|
||||
/// <summary>A cave spider.</summary>
|
||||
CAVE_SPIDER,
|
||||
/// <summary>A chicken.</summary>
|
||||
CHICKEN,
|
||||
/// <summary>A complex entity part.</summary>
|
||||
COMPLEX_PART,
|
||||
/// <summary>A cow.</summary>
|
||||
COW,
|
||||
/// <summary>A creeper.</summary>
|
||||
CREEPER,
|
||||
/// <summary>An item resting on the ground.</summary>
|
||||
DROPPED_ITEM,
|
||||
/// <summary>A flying chicken egg.</summary>
|
||||
EGG,
|
||||
/// <summary>An ender crystal.</summary>
|
||||
ENDER_CRYSTAL,
|
||||
/// <summary>An ender dragon.</summary>
|
||||
ENDER_DRAGON,
|
||||
/// <summary>A flying ender pearl.</summary>
|
||||
ENDER_PEARL,
|
||||
/// <summary>An ender eye signal.</summary>
|
||||
ENDER_SIGNAL,
|
||||
/// <summary>An enderman.</summary>
|
||||
ENDERMAN,
|
||||
/// <summary>An experience orb.</summary>
|
||||
EXPERIENCE_ORB,
|
||||
/// <summary>A block that is going to or is about to fall.</summary>
|
||||
FALLING_BLOCK,
|
||||
/// <summary>A flying large fireball, as thrown by a Ghast for example.</summary>
|
||||
FIREBALL,
|
||||
/// <summary>A firework rocket.</summary>
|
||||
FIREWORK,
|
||||
/// <summary>A fishing line and bobber.</summary>
|
||||
FISHING_HOOK,
|
||||
/// <summary>A ghast.</summary>
|
||||
GHAST,
|
||||
/// <summary>A giant.</summary>
|
||||
GIANT,
|
||||
/// <summary>A horse.</summary>
|
||||
HORSE,
|
||||
/// <summary>An iron golem.</summary>
|
||||
IRON_GOLEM,
|
||||
/// <summary>An item frame on a wall.</summary>
|
||||
ITEM_FRAME,
|
||||
/// <summary>A leash attached to a fencepost.</summary>
|
||||
LEASH_HITCH,
|
||||
/// <summary>A bolt of lightning.</summary>
|
||||
LIGHTNING,
|
||||
/// <summary>A magma cube.</summary>
|
||||
MAGMA_CUBE,
|
||||
/// <summary>A minecart.</summary>
|
||||
MINECART,
|
||||
/// <summary>A minecart with a chest.</summary>
|
||||
MINECART_CHEST,
|
||||
/// <summary>A minecart with a command block.</summary>
|
||||
MINECART_COMMAND,
|
||||
/// <summary>A minecart with a furnace.</summary>
|
||||
MINECART_FURNACE,
|
||||
/// <summary>A minecart with a hopper.</summary>
|
||||
MINECART_HOPPER,
|
||||
/// <summary>A minecart with a mob spawner.</summary>
|
||||
MINECART_MOB_SPAWNER,
|
||||
/// <summary>A minecart with TNT.</summary>
|
||||
MINECART_TNT,
|
||||
/// <summary>A mooshroom.</summary>
|
||||
MUSHROOM_COW,
|
||||
/// <summary>An ocelot.</summary>
|
||||
OCELOT,
|
||||
/// <summary>A painting on a wall.</summary>
|
||||
PAINTING,
|
||||
/// <summary>A pig.</summary>
|
||||
PIG,
|
||||
/// <summary>A zombie pigman.</summary>
|
||||
PIG_ZOMBIE,
|
||||
/// <summary>A player.</summary>
|
||||
PLAYER,
|
||||
/// <summary>Primed TNT that is about to explode.</summary>
|
||||
PRIMED_TNT,
|
||||
/// <summary>A sheep.</summary>
|
||||
SHEEP,
|
||||
/// <summary>A silverfish.</summary>
|
||||
SILVERFISH,
|
||||
/// <summary>A skeleton.</summary>
|
||||
SKELETON,
|
||||
/// <summary>A slime.</summary>
|
||||
SLIME,
|
||||
/// <summary>A flying small fireball, such as thrown by a Blaze or player.</summary>
|
||||
SMALL_FIREBALL,
|
||||
/// <summary>A flying snowball.</summary>
|
||||
SNOWBALL,
|
||||
/// <summary>A snowman.</summary>
|
||||
SNOWMAN,
|
||||
/// <summary>A spider.</summary>
|
||||
SPIDER,
|
||||
/// <summary>A flying splash potion.</summary>
|
||||
SPLASH_POTION,
|
||||
/// <summary>A squid.</summary>
|
||||
SQUID,
|
||||
/// <summary>A flying experience bottle.</summary>
|
||||
THROWN_EXP_BOTTLE,
|
||||
/// <summary>An unknown entity without an Entity Class.</summary>
|
||||
UNKNOWN,
|
||||
/// <summary>A villager.</summary>
|
||||
VILLAGER,
|
||||
/// <summary>A weather entity.</summary>
|
||||
WEATHER,
|
||||
/// <summary>A witch.</summary>
|
||||
WITCH,
|
||||
/// <summary>A wither.</summary>
|
||||
WITHER,
|
||||
/// <summary>A flying wither skull projectile.</summary>
|
||||
WITHER_SKULL,
|
||||
/// <summary>A wolf.</summary>
|
||||
WOLF,
|
||||
/// <summary>A zombie.</summary>
|
||||
ZOMBIE,
|
||||
}
|
||||
207
Minecraft.Server.FourKit/Entity/HumanEntity.cs
Normal file
207
Minecraft.Server.FourKit/Entity/HumanEntity.cs
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a human entity in the world (e.g. a player).
|
||||
/// </summary>
|
||||
public abstract class HumanEntity : LivingEntity, InventoryHolder
|
||||
{
|
||||
private GameMode _gameMode = GameMode.SURVIVAL;
|
||||
private string _name = string.Empty;
|
||||
internal PlayerInventory _playerInventory = new();
|
||||
internal EnderChestInventory? _enderChestInventory;
|
||||
private ItemStack? _cursorItem;
|
||||
private bool _sleeping;
|
||||
private int _sleepTicks;
|
||||
|
||||
/// <summary>
|
||||
/// Gets this human's current <see cref="GameMode"/>.
|
||||
/// </summary>
|
||||
/// <returns>The current game mode.</returns>
|
||||
public GameMode getGameMode() => _gameMode;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of this player.
|
||||
/// </summary>
|
||||
/// <returns>The display name.</returns>
|
||||
public string getName() => _name;
|
||||
|
||||
/// <summary>
|
||||
/// Sets this human's current <see cref="GameMode"/>.
|
||||
/// </summary>
|
||||
/// <param name="mode">The new game mode.</param>
|
||||
public void setGameMode(GameMode mode)
|
||||
{
|
||||
NativeBridge.SetPlayerGameMode?.Invoke(getEntityId(), (int)mode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the player's inventory.
|
||||
/// </summary>
|
||||
/// <returns>The inventory of the player, this also contains the armor slots.</returns>
|
||||
Inventory InventoryHolder.getInventory() => getInventory();
|
||||
|
||||
/// <summary>
|
||||
/// Get the player's inventory.
|
||||
/// This also contains the armor slots.
|
||||
/// </summary>
|
||||
/// <returns>The player's inventory.</returns>
|
||||
public PlayerInventory getInventory()
|
||||
{
|
||||
return _playerInventory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the player's EnderChest inventory.
|
||||
/// </summary>
|
||||
/// <returns>The EnderChest of the player.</returns>
|
||||
public Inventory getEnderChest()
|
||||
{
|
||||
// AAAAAH
|
||||
_enderChestInventory ??= new EnderChestInventory(getEntityId());
|
||||
return _enderChestInventory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ItemStack currently in your hand, can be empty.
|
||||
/// </summary>
|
||||
/// <returns>The ItemStack of the item you are currently holding.</returns>
|
||||
public ItemStack? getItemInHand()
|
||||
{
|
||||
return _playerInventory.getItemInHand();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the item to the given ItemStack, this will replace whatever the
|
||||
/// user was holding.
|
||||
/// </summary>
|
||||
/// <param name="item">The ItemStack which will end up in the hand.</param>
|
||||
public void setItemInHand(ItemStack? item)
|
||||
{
|
||||
_playerInventory.setItemInHand(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ItemStack currently on your cursor, can be empty.
|
||||
/// Will always be empty if the player currently has no open window.
|
||||
/// </summary>
|
||||
/// <returns>The ItemStack of the item you are currently moving around.</returns>
|
||||
public ItemStack? getItemOnCursor()
|
||||
{
|
||||
if (NativeBridge.GetCarriedItem != null)
|
||||
{
|
||||
int[] buf = new int[3];
|
||||
var gh = System.Runtime.InteropServices.GCHandle.Alloc(buf, System.Runtime.InteropServices.GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
NativeBridge.GetCarriedItem(getEntityId(), gh.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
gh.Free();
|
||||
}
|
||||
int id = buf[0];
|
||||
int aux = buf[1];
|
||||
int count = buf[2];
|
||||
if (id > 0 && count > 0)
|
||||
_cursorItem = new ItemStack(id, count, (short)aux);
|
||||
else
|
||||
_cursorItem = null;
|
||||
}
|
||||
return _cursorItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the item to the given ItemStack, this will replace whatever the
|
||||
/// user was moving. Will always be empty if the player currently has no open window.
|
||||
/// </summary>
|
||||
/// <param name="item">The ItemStack which will end up in the hand.</param>
|
||||
public void setItemOnCursor(ItemStack? item)
|
||||
{
|
||||
_cursorItem = item;
|
||||
NativeBridge.SetCarriedItem?.Invoke(getEntityId(),
|
||||
item?.getTypeId() ?? 0,
|
||||
item?.getAmount() ?? 0,
|
||||
item?.getDurability() ?? 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the player currently has an inventory window open, this method will
|
||||
/// close it on both the server and client side.
|
||||
/// </summary>
|
||||
public void closeInventory()
|
||||
{
|
||||
NativeBridge.CloseContainer?.Invoke(getEntityId());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an inventory window with the specified inventory on the top.
|
||||
/// </summary>
|
||||
/// <param name="inventory">The inventory to open.</param>
|
||||
/// <returns>The newly opened InventoryView, or null if it could not be opened.</returns>
|
||||
public InventoryView? openInventory(Inventory inventory)
|
||||
{
|
||||
if (NativeBridge.OpenVirtualContainer == null)
|
||||
return null;
|
||||
|
||||
closeInventory();
|
||||
|
||||
int nativeType = inventory.getType() switch
|
||||
{
|
||||
InventoryType.CHEST => 0,
|
||||
InventoryType.DISPENSER => 3,
|
||||
InventoryType.DROPPER => 10,
|
||||
InventoryType.HOPPER => 5,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
int size = inventory.getSize();
|
||||
int[] buf = new int[size * 3];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
var item = inventory._items[i];
|
||||
buf[i * 3] = item?.getTypeId() ?? 0;
|
||||
buf[i * 3 + 1] = item?.getAmount() ?? 0;
|
||||
buf[i * 3 + 2] = item?.getDurability() ?? 0;
|
||||
}
|
||||
|
||||
string title = inventory.getName();
|
||||
int titleByteLen = System.Text.Encoding.UTF8.GetByteCount(title);
|
||||
IntPtr titlePtr = Marshal.StringToCoTaskMemUTF8(title);
|
||||
var gh = GCHandle.Alloc(buf, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
NativeBridge.OpenVirtualContainer(getEntityId(), nativeType, titlePtr, titleByteLen, size, gh.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
gh.Free();
|
||||
Marshal.FreeCoTaskMem(titlePtr);
|
||||
}
|
||||
|
||||
var view = new InventoryView(inventory, getInventory(), this, inventory.getType());
|
||||
return view;
|
||||
}
|
||||
|
||||
internal void SetGameModeInternal(GameMode mode) => _gameMode = mode;
|
||||
|
||||
internal void SetNameInternal(string name) => _name = name;
|
||||
|
||||
internal void SetSleepingInternal(bool sleeping) => _sleeping = sleeping;
|
||||
|
||||
internal void SetSleepTicksInternal(int ticks) => _sleepTicks = ticks;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether this player is slumbering.
|
||||
/// </summary>
|
||||
/// <returns>slumber state</returns>
|
||||
public bool isSleeping() => _sleeping;
|
||||
|
||||
/// <summary>
|
||||
/// Get the sleep ticks of the player. This value may be capped.
|
||||
/// </summary>
|
||||
/// <returns>slumber ticks</returns>
|
||||
public int getSleepTicks() => _sleepTicks;
|
||||
}
|
||||
32
Minecraft.Server.FourKit/Entity/Item.cs
Normal file
32
Minecraft.Server.FourKit/Entity/Item.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dropped item on the ground.
|
||||
/// </summary>
|
||||
public class Item : Entity
|
||||
{
|
||||
private ItemStack _itemStack;
|
||||
|
||||
internal Item(int entityId, int dimId, double x, double y, double z, ItemStack itemStack)
|
||||
{
|
||||
SetEntityIdInternal(entityId);
|
||||
SetEntityTypeInternal(EntityType.DROPPED_ITEM);
|
||||
SetDimensionInternal(dimId);
|
||||
SetLocation(new Location(FourKit.getWorld(dimId), x, y, z));
|
||||
_itemStack = itemStack;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item stack associated with this item.
|
||||
/// </summary>
|
||||
/// <returns>An item stack.</returns>
|
||||
public ItemStack getItemStack() => _itemStack;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the item stack of this item.
|
||||
/// </summary>
|
||||
/// <param name="stack">The new item stack.</param>
|
||||
public void setItemStack(ItemStack stack) => _itemStack = stack;
|
||||
}
|
||||
51
Minecraft.Server.FourKit/Entity/LivingEntity.cs
Normal file
51
Minecraft.Server.FourKit/Entity/LivingEntity.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a living entity in the world that has health and can take damage.
|
||||
/// </summary>
|
||||
public class LivingEntity : Damageable
|
||||
{
|
||||
private double _eyeHeight = 1.62;
|
||||
|
||||
internal LivingEntity() { }
|
||||
|
||||
internal LivingEntity(int entityId, EntityType entityType, int dimId, double x, double y, double z,
|
||||
float health = 20f, float maxHealth = 20f)
|
||||
{
|
||||
SetEntityIdInternal(entityId);
|
||||
SetEntityTypeInternal(entityType);
|
||||
SetDimensionInternal(dimId);
|
||||
SetLocation(new Location(FourKit.getWorld(dimId), x, y, z));
|
||||
if (maxHealth > 0)
|
||||
SetMaxHealthInternal(maxHealth);
|
||||
SetHealthInternal(health);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the living entity's eyes above its <see cref="Location"/>.
|
||||
/// </summary>
|
||||
/// <returns>The eye height.</returns>
|
||||
public double getEyeHeight() => _eyeHeight;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the living entity's eyes above its <see cref="Location"/>.
|
||||
/// </summary>
|
||||
/// <param name="ignoreSneaking">If <c>true</c>, returns the standing eye height regardless of sneak state.</param>
|
||||
/// <returns>The eye height.</returns>
|
||||
public double getEyeHeight(bool ignoreSneaking)
|
||||
{
|
||||
if (ignoreSneaking)
|
||||
return _eyeHeight;
|
||||
|
||||
// When sneaking the eye height is slightly lower
|
||||
return _eyeHeight - 0.08;
|
||||
}
|
||||
|
||||
// --- Internal setter used by the bridge ---
|
||||
|
||||
/// <summary>
|
||||
/// Updates the eye height. Called internally by the bridge.
|
||||
/// </summary>
|
||||
/// <param name="eyeHeight">The new eye height.</param>
|
||||
internal void SetEyeHeightInternal(double eyeHeight) => _eyeHeight = eyeHeight;
|
||||
}
|
||||
26
Minecraft.Server.FourKit/Entity/OfflinePlayer.cs
Normal file
26
Minecraft.Server.FourKit/Entity/OfflinePlayer.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a player identity that may or may not currently be online.
|
||||
/// </summary>
|
||||
public interface OfflinePlayer
|
||||
{
|
||||
/// <summary>Returns the name of this player.</summary>
|
||||
/// <returns>The player's name.</returns>
|
||||
string getName();
|
||||
|
||||
/// <summary>Gets a Player object that this represents, if there is one.</summary>
|
||||
/// <returns>A <see cref="Player"/> instance if the player is online; otherwise <c>null</c>.</returns>
|
||||
Player? getPlayer();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the UUID that uniquely identifies this player across sessions.
|
||||
/// This is the player-specific UUID, not the entity UUID.
|
||||
/// </summary>
|
||||
/// <returns>The player's unique identifier.</returns>
|
||||
Guid getUniqueId();
|
||||
|
||||
/// <summary>Checks if this player is currently online.</summary>
|
||||
/// <returns><c>true</c> if the player is online; otherwise <c>false</c>.</returns>
|
||||
bool isOnline();
|
||||
}
|
||||
665
Minecraft.Server.FourKit/Entity/Player.cs
Normal file
665
Minecraft.Server.FourKit/Entity/Player.cs
Normal file
|
|
@ -0,0 +1,665 @@
|
|||
namespace Minecraft.Server.FourKit.Entity;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Minecraft.Server.FourKit.Command;
|
||||
using Minecraft.Server.FourKit.Experimental;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
using Minecraft.Server.FourKit.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a player connected to the server.
|
||||
/// </summary>
|
||||
public class Player : HumanEntity, OfflinePlayer, CommandSender
|
||||
{
|
||||
private float _saturation = 5.0f;
|
||||
private float _walkSpeed = 0.2f;
|
||||
private float _exhaustion;
|
||||
private int _foodLevel = 20;
|
||||
private int _level;
|
||||
private float _exp;
|
||||
private int _totalExperience;
|
||||
private Guid _playerUniqueId;
|
||||
private ulong _playerRawOnlineXUID;
|
||||
private ulong _playerRawOfflineXUID;
|
||||
private string? _displayName;
|
||||
private bool _sneaking;
|
||||
private bool _sprinting;
|
||||
private bool _allowFlight;
|
||||
private bool _sleepingIgnored;
|
||||
|
||||
private PlayerConnection _connection;
|
||||
|
||||
internal bool IsOnline { get; set; }
|
||||
|
||||
internal Player(int entityId, string name)
|
||||
{
|
||||
SetEntityIdInternal(entityId);
|
||||
SetEntityTypeInternal(EntityType.PLAYER);
|
||||
SetNameInternal(name);
|
||||
IsOnline = true;
|
||||
_playerInventory._holder = this;
|
||||
_connection = new PlayerConnection(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override EntityType getType() => EntityType.PLAYER;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override EntityType GetType() => EntityType.PLAYER;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool teleport(Location location)
|
||||
{
|
||||
int targetDimId = location.LocationWorld?.getDimensionId() ?? getLocation().LocationWorld?.getDimensionId() ?? 0;
|
||||
NativeBridge.TeleportEntity?.Invoke(getEntityId(), targetDimId, location.X, location.Y, location.Z);
|
||||
SetLocation(location);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <b>Experimental.</b> Gets the player's <see cref="PlayerConnection"/>, which can be used
|
||||
/// to send raw packet data directly to the client.
|
||||
/// </summary>
|
||||
/// <returns>The player's connection.</returns>
|
||||
public PlayerConnection getConnection() => _connection;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Player? getPlayer() => IsOnline ? this : null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the "friendly" name to display of this player.
|
||||
/// This may include color. If no custom display name has been set,
|
||||
/// this returns the player's <see cref="HumanEntity.getName"/>.
|
||||
/// </summary>
|
||||
/// <returns>The display name.</returns>
|
||||
public string getDisplayName() => _displayName ?? getName();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the "friendly" name to display of this player.
|
||||
/// </summary>
|
||||
/// <param name="name">The display name, or <c>null</c> to reset to <see cref="HumanEntity.getName"/>.</param>
|
||||
public void setDisplayName(string? name)
|
||||
{
|
||||
_displayName = name;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool isOnline() => IsOnline;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the UUID that uniquely identifies this player across sessions.
|
||||
/// This is the player-specific UUID, not the entity UUID.
|
||||
/// </summary>
|
||||
/// <returns>The player's unique identifier.</returns>
|
||||
public new Guid getUniqueId() => _playerUniqueId;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <b>Experimental.</b> Gets the raw online XUID (Xbox User ID) for this player.
|
||||
/// The online XUID is used for guests.
|
||||
/// </summary>
|
||||
/// <returns>The raw online XUID value.</returns>
|
||||
public ulong getRawOnlineXUID() => _playerRawOnlineXUID;
|
||||
|
||||
/// <summary>
|
||||
/// <b>Experimental.</b> Gets the raw offline XUID (Xbox User ID) for this player.
|
||||
/// The offline XUID is the main XUID used by the client.
|
||||
/// </summary>
|
||||
/// <returns>The raw offline XUID value.</returns>
|
||||
public ulong getRawOfflineXUID() => _playerRawOfflineXUID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player's estimated ping in milliseconds.
|
||||
/// This value represents a weighted average of the response time to application layer ping packets sent. This value does not represent the network round trip time and as such may have less granularity and be impacted by other sources. For these reasons it should not be used for anti-cheat purposes. Its recommended use is only as a qualitative indicator of connection quality.
|
||||
/// </summary>
|
||||
/// <returns>The player's estimated ping in milliseconds.</returns>
|
||||
public int getPing()
|
||||
{
|
||||
if (NativeBridge.GetPlayerLatency == null)
|
||||
return -1;
|
||||
|
||||
return NativeBridge.GetPlayerLatency(getEntityId());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player's current saturation level.
|
||||
/// Saturation acts as a buffer before hunger begins to deplete.
|
||||
/// </summary>
|
||||
/// <returns>The current saturation level.</returns>
|
||||
public float getSaturation() => _saturation;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current allowed speed that a client can walk.
|
||||
/// The default value is 0.2.
|
||||
/// </summary>
|
||||
/// <returns>The current walk speed.</returns>
|
||||
public float getWalkSpeed() => _walkSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the speed at which a client will walk.
|
||||
/// This calls into the native server to apply the change.
|
||||
/// </summary>
|
||||
/// <param name="value">The new walk speed.</param>
|
||||
public void setWalkSpeed(float value)
|
||||
{
|
||||
_walkSpeed = value;
|
||||
NativeBridge.SetWalkSpeed?.Invoke(getEntityId(), value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the player is in sneak mode.
|
||||
/// </summary>
|
||||
/// <returns>True if player is in sneak mode.</returns>
|
||||
public bool isSneaking() => _sneaking;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the player is sprinting or not.
|
||||
/// </summary>
|
||||
/// <returns>True if player is sprinting.</returns>
|
||||
public bool isSprinting() => _sprinting;
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether the player is ignored as not sleeping. If everyone is
|
||||
/// either sleeping or has this flag set, then time will advance to the
|
||||
/// next day. If everyone has this flag set but no one is actually in
|
||||
/// bed, then nothing will happen.
|
||||
/// </summary>
|
||||
/// <param name="isSleeping">Whether to ignore.</param>
|
||||
public void setSleepingIgnored(bool isSleeping)
|
||||
{
|
||||
_sleepingIgnored = isSleeping;
|
||||
NativeBridge.SetSleepingIgnored?.Invoke(getEntityId(), isSleeping ? 1 : 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the player is sleeping ignored.
|
||||
/// </summary>
|
||||
/// <returns>Whether player is ignoring sleep.</returns>
|
||||
public bool isSleepingIgnored() => _sleepingIgnored;
|
||||
|
||||
/// <summary>
|
||||
/// Play a sound for a player at the location.
|
||||
/// This function will fail silently if Location or Sound are null.
|
||||
/// </summary>
|
||||
/// <param name="location">The location to play the sound.</param>
|
||||
/// <param name="sound">The sound to play.</param>
|
||||
/// <param name="volume">The volume of the sound.</param>
|
||||
/// <param name="pitch">The pitch of the sound.</param>
|
||||
public void playSound(Location location, Sound sound, float volume, float pitch)
|
||||
{
|
||||
if (location == null)
|
||||
return;
|
||||
NativeBridge.PlaySound?.Invoke(getEntityId(), (int)sound, location.X, location.Y, location.Z, volume, pitch);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the Player is allowed to fly via jump key double-tap
|
||||
/// like in creative mode.
|
||||
/// </summary>
|
||||
/// <returns>True if the player is allowed to fly.</returns>
|
||||
public bool getAllowFlight() => _allowFlight;
|
||||
|
||||
/// <summary>
|
||||
/// Sets if the Player is allowed to fly via jump key double-tap like
|
||||
/// in creative mode.
|
||||
/// </summary>
|
||||
/// <param name="flight">If flight should be allowed.</param>
|
||||
public void setAllowFlight(bool flight)
|
||||
{
|
||||
_allowFlight = flight;
|
||||
NativeBridge.SetAllowFlight?.Invoke(getEntityId(), flight ? 1 : 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void sendMessage(string message)
|
||||
{
|
||||
if (string.IsNullOrEmpty(message) || NativeBridge.SendMessage == null)
|
||||
return;
|
||||
if (message.Length > FourKit.MAX_CHAT_LENGTH)
|
||||
message = message[..FourKit.MAX_CHAT_LENGTH];
|
||||
|
||||
IntPtr ptr = Marshal.StringToCoTaskMemUTF8(message);
|
||||
try
|
||||
{
|
||||
NativeBridge.SendMessage(getEntityId(), ptr, System.Text.Encoding.UTF8.GetByteCount(message));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void sendMessage(string[] messages)
|
||||
{
|
||||
foreach (var msg in messages)
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kicks player with the default <see cref="DisconnectReason.KICKED"/> reason.
|
||||
/// </summary>
|
||||
public void kickPlayer()
|
||||
{
|
||||
NativeBridge.KickPlayer?.Invoke(getEntityId(), (int)DisconnectReason.KICKED);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bans the player by UID with the specified reason and disconnects them.
|
||||
/// </summary>
|
||||
/// <param name="reason">The ban reason.</param>
|
||||
/// <returns><c>true</c> if the ban was applied successfully.</returns>
|
||||
public bool banPlayer(string reason)
|
||||
{
|
||||
if (NativeBridge.BanPlayer == null) return false;
|
||||
IntPtr ptr = Marshal.StringToCoTaskMemUTF8(reason ?? string.Empty);
|
||||
try
|
||||
{
|
||||
int byteLen = System.Text.Encoding.UTF8.GetByteCount(reason ?? string.Empty);
|
||||
return NativeBridge.BanPlayer(getEntityId(), ptr, byteLen) != 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bans the player's IP address with the specified reason.
|
||||
/// </summary>
|
||||
/// <param name="reason">The ban reason.</param>
|
||||
/// <returns><c>true</c> if the IP ban was applied successfully.</returns>
|
||||
public bool banPlayerIp(string reason)
|
||||
{
|
||||
if (NativeBridge.BanPlayerIp == null) return false;
|
||||
IntPtr ptr = Marshal.StringToCoTaskMemUTF8(reason ?? string.Empty);
|
||||
try
|
||||
{
|
||||
int byteLen = System.Text.Encoding.UTF8.GetByteCount(reason ?? string.Empty);
|
||||
return NativeBridge.BanPlayerIp(getEntityId(), ptr, byteLen) != 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the socket address of this player.
|
||||
/// </summary>
|
||||
/// <returns>The player's socket address, or <c>null</c> if the address could not be determined.</returns>
|
||||
public InetSocketAddress? getAddress()
|
||||
{
|
||||
if (NativeBridge.GetPlayerAddress == null)
|
||||
return null;
|
||||
|
||||
const int ipBufSize = 64;
|
||||
IntPtr ipBuf = Marshal.AllocCoTaskMem(ipBufSize);
|
||||
IntPtr portBuf = Marshal.AllocCoTaskMem(sizeof(int));
|
||||
try
|
||||
{
|
||||
int result = NativeBridge.GetPlayerAddress(getEntityId(), ipBuf, ipBufSize, portBuf);
|
||||
if (result == 0)
|
||||
return null;
|
||||
|
||||
string? ip = Marshal.PtrToStringAnsi(ipBuf);
|
||||
int port = Marshal.ReadInt32(portBuf);
|
||||
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
return null;
|
||||
|
||||
return new InetSocketAddress(new InetAddress(ip), port);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(ipBuf);
|
||||
Marshal.FreeCoTaskMem(portBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the players current experience level.
|
||||
/// </summary>
|
||||
/// <returns>Current experience level.</returns>
|
||||
public int getLevel() => _level;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the players current experience level.
|
||||
/// </summary>
|
||||
/// <param name="level">New experience level.</param>
|
||||
public void setLevel(int level)
|
||||
{
|
||||
_level = level;
|
||||
NativeBridge.SetLevel?.Invoke(getEntityId(), level);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the players current experience points towards the next level.
|
||||
/// This is a percentage value. 0 is "no progress" and 1 is "next level".
|
||||
/// </summary>
|
||||
/// <returns>Current experience points.</returns>
|
||||
public float getExp() => _exp;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the players current experience points towards the next level.
|
||||
/// This is a percentage value. 0 is "no progress" and 1 is "next level".
|
||||
/// </summary>
|
||||
/// <param name="exp">New experience points.</param>
|
||||
public void setExp(float exp)
|
||||
{
|
||||
_exp = exp;
|
||||
NativeBridge.SetExp?.Invoke(getEntityId(), exp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives the player the amount of experience specified.
|
||||
/// </summary>
|
||||
/// <param name="amount">Exp amount to give.</param>
|
||||
public void giveExp(int amount)
|
||||
{
|
||||
NativeBridge.GiveExp?.Invoke(getEntityId(), amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives the player the amount of experience levels specified.
|
||||
/// Levels can be taken by specifying a negative amount.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount of experience levels to give or take.</param>
|
||||
public void giveExpLevels(int amount)
|
||||
{
|
||||
NativeBridge.GiveExpLevels?.Invoke(getEntityId(), amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the players current exhaustion level.
|
||||
/// Exhaustion controls how fast the food level drops. While you have a
|
||||
/// certain amount of exhaustion, your saturation will drop to zero, and
|
||||
/// then your food will drop to zero.
|
||||
/// </summary>
|
||||
/// <returns>Exhaustion level.</returns>
|
||||
public float getExhaustion() => _exhaustion;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the players current exhaustion level.
|
||||
/// </summary>
|
||||
/// <param name="value">Exhaustion level.</param>
|
||||
public void setExhaustion(float value)
|
||||
{
|
||||
_exhaustion = value;
|
||||
NativeBridge.SetExhaustion?.Invoke(getEntityId(), value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the players current saturation level.
|
||||
/// </summary>
|
||||
/// <param name="value">Saturation level.</param>
|
||||
public void setSaturation(float value)
|
||||
{
|
||||
_saturation = value;
|
||||
NativeBridge.SetSaturation?.Invoke(getEntityId(), value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the players current food level.
|
||||
/// </summary>
|
||||
/// <returns>Food level.</returns>
|
||||
public int getFoodLevel() => _foodLevel;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the players current food level.
|
||||
/// </summary>
|
||||
/// <param name="value">New food level.</param>
|
||||
public void setFoodLevel(int value)
|
||||
{
|
||||
_foodLevel = value;
|
||||
NativeBridge.SetFoodLevel?.Invoke(getEntityId(), value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="location">The location to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
public void spawnParticle(Particle particle, Location location, int count)
|
||||
{
|
||||
spawnParticleInternal(particle, location.X, location.Y, location.Z, count, 0, 0, 0, 0, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="x">The position on the x axis to spawn at.</param>
|
||||
/// <param name="y">The position on the y axis to spawn at.</param>
|
||||
/// <param name="z">The position on the z axis to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
public void spawnParticle(Particle particle, double x, double y, double z, int count)
|
||||
{
|
||||
spawnParticleInternal(particle, x, y, z, count, 0, 0, 0, 0, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="location">The location to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="data">The data to use for the particle or null.</param>
|
||||
/// <typeparam name="T">The type of the particle data.</typeparam>
|
||||
public void spawnParticle<T>(Particle particle, Location location, int count, T? data)
|
||||
{
|
||||
spawnParticleInternal(particle, location.X, location.Y, location.Z, count, 0, 0, 0, 0, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="x">The position on the x axis to spawn at.</param>
|
||||
/// <param name="y">The position on the y axis to spawn at.</param>
|
||||
/// <param name="z">The position on the z axis to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="data">The data to use for the particle or null.</param>
|
||||
/// <typeparam name="T">The type of the particle data.</typeparam>
|
||||
public void spawnParticle<T>(Particle particle, double x, double y, double z, int count, T? data)
|
||||
{
|
||||
spawnParticleInternal(particle, x, y, z, count, 0, 0, 0, 0, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. The position of each particle will be
|
||||
/// randomized positively and negatively by the offset parameters
|
||||
/// on each axis. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="location">The location to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="offsetX">The maximum random offset on the X axis.</param>
|
||||
/// <param name="offsetY">The maximum random offset on the Y axis.</param>
|
||||
/// <param name="offsetZ">The maximum random offset on the Z axis.</param>
|
||||
public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ)
|
||||
{
|
||||
spawnParticleInternal(particle, location.X, location.Y, location.Z, count, offsetX, offsetY, offsetZ, 0, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. The position of each particle will be
|
||||
/// randomized positively and negatively by the offset parameters
|
||||
/// on each axis. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="x">The position on the x axis to spawn at.</param>
|
||||
/// <param name="y">The position on the y axis to spawn at.</param>
|
||||
/// <param name="z">The position on the z axis to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="offsetX">The maximum random offset on the X axis.</param>
|
||||
/// <param name="offsetY">The maximum random offset on the Y axis.</param>
|
||||
/// <param name="offsetZ">The maximum random offset on the Z axis.</param>
|
||||
public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ)
|
||||
{
|
||||
spawnParticleInternal(particle, x, y, z, count, offsetX, offsetY, offsetZ, 0, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. The position of each particle will be
|
||||
/// randomized positively and negatively by the offset parameters
|
||||
/// on each axis. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="location">The location to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="offsetX">The maximum random offset on the X axis.</param>
|
||||
/// <param name="offsetY">The maximum random offset on the Y axis.</param>
|
||||
/// <param name="offsetZ">The maximum random offset on the Z axis.</param>
|
||||
/// <param name="data">The data to use for the particle or null.</param>
|
||||
/// <typeparam name="T">The type of the particle data.</typeparam>
|
||||
public void spawnParticle<T>(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, T? data)
|
||||
{
|
||||
spawnParticleInternal(particle, location.X, location.Y, location.Z, count, offsetX, offsetY, offsetZ, 0, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. The position of each particle will be
|
||||
/// randomized positively and negatively by the offset parameters
|
||||
/// on each axis. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="x">The position on the x axis to spawn at.</param>
|
||||
/// <param name="y">The position on the y axis to spawn at.</param>
|
||||
/// <param name="z">The position on the z axis to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="offsetX">The maximum random offset on the X axis.</param>
|
||||
/// <param name="offsetY">The maximum random offset on the Y axis.</param>
|
||||
/// <param name="offsetZ">The maximum random offset on the Z axis.</param>
|
||||
/// <param name="data">The data to use for the particle or null.</param>
|
||||
/// <typeparam name="T">The type of the particle data.</typeparam>
|
||||
public void spawnParticle<T>(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, T? data)
|
||||
{
|
||||
spawnParticleInternal(particle, x, y, z, count, offsetX, offsetY, offsetZ, 0, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. The position of each particle will be
|
||||
/// randomized positively and negatively by the offset parameters
|
||||
/// on each axis. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="location">The location to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="offsetX">The maximum random offset on the X axis.</param>
|
||||
/// <param name="offsetY">The maximum random offset on the Y axis.</param>
|
||||
/// <param name="offsetZ">The maximum random offset on the Z axis.</param>
|
||||
/// <param name="extra">The extra data for this particle, depends on the particle used (normally speed).</param>
|
||||
public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, double extra)
|
||||
{
|
||||
spawnParticleInternal(particle, location.X, location.Y, location.Z, count, offsetX, offsetY, offsetZ, extra, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. The position of each particle will be
|
||||
/// randomized positively and negatively by the offset parameters
|
||||
/// on each axis. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="x">The position on the x axis to spawn at.</param>
|
||||
/// <param name="y">The position on the y axis to spawn at.</param>
|
||||
/// <param name="z">The position on the z axis to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="offsetX">The maximum random offset on the X axis.</param>
|
||||
/// <param name="offsetY">The maximum random offset on the Y axis.</param>
|
||||
/// <param name="offsetZ">The maximum random offset on the Z axis.</param>
|
||||
/// <param name="extra">The extra data for this particle, depends on the particle used (normally speed).</param>
|
||||
public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra)
|
||||
{
|
||||
spawnParticleInternal(particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. The position of each particle will be
|
||||
/// randomized positively and negatively by the offset parameters
|
||||
/// on each axis. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="location">The location to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="offsetX">The maximum random offset on the X axis.</param>
|
||||
/// <param name="offsetY">The maximum random offset on the Y axis.</param>
|
||||
/// <param name="offsetZ">The maximum random offset on the Z axis.</param>
|
||||
/// <param name="extra">The extra data for this particle, depends on the particle used (normally speed).</param>
|
||||
/// <param name="data">The data to use for the particle or null.</param>
|
||||
/// <typeparam name="T">The type of the particle data.</typeparam>
|
||||
public void spawnParticle<T>(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, double extra, T? data)
|
||||
{
|
||||
spawnParticleInternal(particle, location.X, location.Y, location.Z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the particle (the number of times specified by count)
|
||||
/// at the target location. The position of each particle will be
|
||||
/// randomized positively and negatively by the offset parameters
|
||||
/// on each axis. Only this player will see the particle.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle to spawn.</param>
|
||||
/// <param name="x">The position on the x axis to spawn at.</param>
|
||||
/// <param name="y">The position on the y axis to spawn at.</param>
|
||||
/// <param name="z">The position on the z axis to spawn at.</param>
|
||||
/// <param name="count">The number of particles.</param>
|
||||
/// <param name="offsetX">The maximum random offset on the X axis.</param>
|
||||
/// <param name="offsetY">The maximum random offset on the Y axis.</param>
|
||||
/// <param name="offsetZ">The maximum random offset on the Z axis.</param>
|
||||
/// <param name="extra">The extra data for this particle, depends on the particle used (normally speed).</param>
|
||||
/// <param name="data">The data to use for the particle or null.</param>
|
||||
/// <typeparam name="T">The type of the particle data.</typeparam>
|
||||
public void spawnParticle<T>(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T? data)
|
||||
{
|
||||
spawnParticleInternal(particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
private void spawnParticleInternal(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, object? data)
|
||||
{
|
||||
if (NativeBridge.SpawnParticle == null)
|
||||
return;
|
||||
|
||||
int particleId = (int)particle;
|
||||
if (data is ItemStack itemStack &&
|
||||
(particle == Particle.ITEM_CRACK || particle == Particle.BLOCK_CRACK))
|
||||
{
|
||||
int id = itemStack.getTypeId();
|
||||
int aux = itemStack.getDurability();
|
||||
particleId = (int)particle | ((id & 0x0FFF) << 8) | (aux & 0xFF);
|
||||
}
|
||||
|
||||
NativeBridge.SpawnParticle(getEntityId(), particleId,
|
||||
(float)x, (float)y, (float)z,
|
||||
(float)offsetX, (float)offsetY, (float)offsetZ,
|
||||
(float)extra, count);
|
||||
}
|
||||
|
||||
// INTERNAL
|
||||
internal void SetSaturationInternal(float saturation) => _saturation = saturation;
|
||||
internal void SetWalkSpeedInternal(float walkSpeed) => _walkSpeed = walkSpeed;
|
||||
internal void SetPlayerUniqueIdInternal(Guid id) => _playerUniqueId = id;
|
||||
internal void SetPlayerRawOnlineXUIDInternal(ulong xuid) => _playerRawOnlineXUID = xuid;
|
||||
internal void SetPlayerRawOfflineXUIDInternal(ulong xuid) => _playerRawOfflineXUID = xuid;
|
||||
internal void SetSneakingInternal(bool sneaking) => _sneaking = sneaking;
|
||||
internal void SetSprintingInternal(bool sprinting) => _sprinting = sprinting;
|
||||
internal void SetAllowFlightInternal(bool allowFlight) => _allowFlight = allowFlight;
|
||||
internal void SetSleepingIgnoredInternal(bool ignored) => _sleepingIgnored = ignored;
|
||||
internal void SetLevelInternal(int level) => _level = level;
|
||||
internal void SetExpInternal(float exp) => _exp = exp;
|
||||
internal void SetTotalExperienceInternal(int totalExp) => _totalExperience = totalExp;
|
||||
internal void SetFoodLevelInternal(int foodLevel) => _foodLevel = foodLevel;
|
||||
internal void SetExhaustionInternal(float exhaustion) => _exhaustion = exhaustion;
|
||||
}
|
||||
11
Minecraft.Server.FourKit/Enums/LoginType.cs
Normal file
11
Minecraft.Server.FourKit/Enums/LoginType.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enums;
|
||||
|
||||
public enum LoginType
|
||||
{
|
||||
INITIAL = 1,
|
||||
ACCEPTED = 2,
|
||||
}
|
||||
50
Minecraft.Server.FourKit/Enums/TreeType.cs
Normal file
50
Minecraft.Server.FourKit/Enums/TreeType.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Tree and organic structure types.
|
||||
/// </summary>
|
||||
public enum TreeType {
|
||||
/// <summary>
|
||||
/// No tree type.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Redwood tree, shaped like a pine tree.
|
||||
/// </summary>
|
||||
SPRUCE = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Birch tree.
|
||||
/// </summary>
|
||||
BIRCH = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Standard jungle tree; 4 blocks wide and tall.
|
||||
/// </summary>
|
||||
JUNGLE = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Regular tree, extra tall with branches.
|
||||
/// </summary>
|
||||
BIG_OAK = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Regular tree, no branches.
|
||||
/// </summary>
|
||||
OAK = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Big brown mushroom; tall and umbrella-like.
|
||||
/// </summary>
|
||||
BROWN_MUSHROOM = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Big red mushroom; short and fat.
|
||||
/// </summary>
|
||||
RED_MUSHROOM = 7,
|
||||
}
|
||||
50
Minecraft.Server.FourKit/Event/Block/BlockBreakEvent.cs
Normal file
50
Minecraft.Server.FourKit/Event/Block/BlockBreakEvent.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a block is broken by a player.
|
||||
///
|
||||
/// If you wish to have the block drop experience, you must set the experience
|
||||
/// value above 0. By default, experience will be set in the event if:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>The player is not in creative or adventure mode</description></item>
|
||||
/// <item><description>The player can loot the block (ie: does not destroy it completely, by using the correct tool)</description></item>
|
||||
/// <item><description>The player does not have silk touch</description></item>
|
||||
/// <item><description>The block drops experience in vanilla Minecraft</description></item>
|
||||
/// </list>
|
||||
///
|
||||
/// Note: Plugins wanting to simulate a traditional block drop should set the
|
||||
/// block to air and utilize their own methods for determining what the default
|
||||
/// drop for the block being broken is and what to do about it, if anything.
|
||||
///
|
||||
/// If a Block Break event is cancelled, the block will not break and experience
|
||||
/// will not drop.
|
||||
/// </summary>
|
||||
public class BlockBreakEvent : BlockExpEvent, Cancellable
|
||||
{
|
||||
private readonly Player _player;
|
||||
private bool _cancel;
|
||||
internal BlockBreakEvent(Block block, Player player, int exp)
|
||||
: base(block, exp)
|
||||
{
|
||||
_player = player;
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Player that is breaking the block involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>The Player that is breaking the block involved in this event.</returns>
|
||||
public Player getPlayer() => _player;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool isCancelled() => _cancel;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancel = cancel;
|
||||
}
|
||||
}
|
||||
30
Minecraft.Server.FourKit/Event/Block/BlockBurnEvent.cs
Normal file
30
Minecraft.Server.FourKit/Event/Block/BlockBurnEvent.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a block is destroyed as a result of being burnt by fire.
|
||||
///
|
||||
/// <para>If a Block Burn event is cancelled, the block will not be destroyed
|
||||
/// as a result of being burnt by fire.</para>
|
||||
/// </summary>
|
||||
public class BlockBurnEvent : BlockEvent, Cancellable
|
||||
{
|
||||
private bool _cancel;
|
||||
|
||||
internal BlockBurnEvent(Block block) : base(block)
|
||||
{
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool isCancelled() => _cancel;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancel = cancel;
|
||||
}
|
||||
}
|
||||
22
Minecraft.Server.FourKit/Event/Block/BlockEvent.cs
Normal file
22
Minecraft.Server.FourKit/Event/Block/BlockEvent.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Block-related event.
|
||||
/// </summary>
|
||||
public abstract class BlockEvent : Event
|
||||
{
|
||||
private readonly Block _block;
|
||||
|
||||
internal protected BlockEvent(Block block)
|
||||
{
|
||||
_block = block;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>The Block which is involved in this event.</returns>
|
||||
public Block getBlock() => _block;
|
||||
}
|
||||
31
Minecraft.Server.FourKit/Event/Block/BlockExpEvent.cs
Normal file
31
Minecraft.Server.FourKit/Event/Block/BlockExpEvent.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// An event that is called when a block yields experience.
|
||||
/// </summary>
|
||||
public class BlockExpEvent : BlockEvent
|
||||
{
|
||||
private int _exp;
|
||||
internal BlockExpEvent(Block block, int exp)
|
||||
: base(block)
|
||||
{
|
||||
_exp = exp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the experience dropped by the block after the event has processed.
|
||||
/// </summary>
|
||||
/// <returns>The experience to drop.</returns>
|
||||
public int getExpToDrop() => _exp;
|
||||
|
||||
/// <summary>
|
||||
/// Set the amount of experience dropped by the block after the event has processed.
|
||||
/// </summary>
|
||||
/// <param name="exp">1 or higher to drop experience, else nothing will drop.</param>
|
||||
public void setExpToDrop(int exp)
|
||||
{
|
||||
_exp = exp;
|
||||
}
|
||||
}
|
||||
23
Minecraft.Server.FourKit/Event/Block/BlockFormEvent.cs
Normal file
23
Minecraft.Server.FourKit/Event/Block/BlockFormEvent.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a block is formed or spreads based on world conditions.
|
||||
/// Use <see cref="BlockSpreadEvent"/> to catch blocks that actually spread
|
||||
/// and don't just "randomly" form.
|
||||
///
|
||||
/// <para>Examples:</para>
|
||||
/// <list type="bullet">
|
||||
/// <item><description>Snow forming due to a snow storm.</description></item>
|
||||
/// <item><description>Ice forming in a snowy Biome like Taiga or Tundra.</description></item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para>If a Block Form event is cancelled, the block will not be formed.</para>
|
||||
/// </summary>
|
||||
public class BlockFormEvent : BlockGrowEvent, Cancellable
|
||||
{
|
||||
internal BlockFormEvent(Block block, BlockState newState) : base(block, newState)
|
||||
{
|
||||
}
|
||||
}
|
||||
59
Minecraft.Server.FourKit/Event/Block/BlockFromToEvent.cs
Normal file
59
Minecraft.Server.FourKit/Event/Block/BlockFromToEvent.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Represents events with a source block and a destination block, currently
|
||||
/// only applies to liquid (lava and water) and teleporting dragon eggs.
|
||||
///
|
||||
/// <para>If a Block From To event is cancelled, the block will not move
|
||||
/// (the liquid will not flow).</para>
|
||||
/// </summary>
|
||||
public class BlockFromToEvent : BlockEvent, Cancellable
|
||||
{
|
||||
private readonly Block _to;
|
||||
private readonly BlockFace _face;
|
||||
private bool _cancel;
|
||||
|
||||
internal BlockFromToEvent(Block block, BlockFace face) : base(block)
|
||||
{
|
||||
_face = face;
|
||||
_to = block.getRelative(face);
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
internal BlockFromToEvent(Block block, Block toBlock) : base(block)
|
||||
{
|
||||
_to = toBlock;
|
||||
_face = BlockFace.SELF;
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
internal BlockFromToEvent(Block block, Block toBlock, BlockFace face) : base(block)
|
||||
{
|
||||
_to = toBlock;
|
||||
_face = face;
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the BlockFace that the block is moving to.
|
||||
/// </summary>
|
||||
/// <returns>The BlockFace that the block is moving to.</returns>
|
||||
public BlockFace getFace() => _face;
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method for getting the faced Block.
|
||||
/// </summary>
|
||||
/// <returns>The faced Block.</returns>
|
||||
public Block getToBlock() => _to;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool isCancelled() => _cancel;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancel = cancel;
|
||||
}
|
||||
}
|
||||
44
Minecraft.Server.FourKit/Event/Block/BlockGrowEvent.cs
Normal file
44
Minecraft.Server.FourKit/Event/Block/BlockGrowEvent.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a block grows naturally in the world.
|
||||
///
|
||||
/// <para>Examples:</para>
|
||||
/// <list type="bullet">
|
||||
/// <item><description>Wheat</description></item>
|
||||
/// <item><description>Sugar Cane</description></item>
|
||||
/// <item><description>Cactus</description></item>
|
||||
/// <item><description>Watermelon</description></item>
|
||||
/// <item><description>Pumpkin</description></item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para>If a Block Grow event is cancelled, the block will not grow.</para>
|
||||
/// </summary>
|
||||
public class BlockGrowEvent : BlockEvent, Cancellable
|
||||
{
|
||||
private bool _cancel;
|
||||
private readonly BlockState _newState;
|
||||
|
||||
internal BlockGrowEvent(Block block, BlockState newState) : base(block)
|
||||
{
|
||||
_cancel = false;
|
||||
_newState = newState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the block where it will form or spread to.
|
||||
/// </summary>
|
||||
/// <returns>The block state for this events block.</returns>
|
||||
public BlockState getNewState() => _newState;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool isCancelled() => _cancel;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancel = cancel;
|
||||
}
|
||||
}
|
||||
45
Minecraft.Server.FourKit/Event/Block/BlockPistonEvent.cs
Normal file
45
Minecraft.Server.FourKit/Event/Block/BlockPistonEvent.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a piston block is triggered.
|
||||
/// </summary>
|
||||
public abstract class BlockPistonEvent : BlockEvent, Cancellable
|
||||
{
|
||||
private bool _cancel;
|
||||
private readonly BlockFace _direction;
|
||||
|
||||
internal protected BlockPistonEvent(Block block, BlockFace direction) : base(block)
|
||||
{
|
||||
_direction = direction;
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool isCancelled() => _cancel;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void setCancelled(bool cancelled)
|
||||
{
|
||||
_cancel = cancelled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the Piston in the event is sticky.
|
||||
/// </summary>
|
||||
/// <returns>Stickiness of the piston.</returns>
|
||||
public bool isSticky()
|
||||
{
|
||||
var type = getBlock().getType();
|
||||
return type == Material.PISTON_STICKY_BASE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the direction in which the piston will operate.
|
||||
/// </summary>
|
||||
/// <returns>Direction of the piston.</returns>
|
||||
public BlockFace getDirection() => _direction;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a piston extends.
|
||||
/// </summary>
|
||||
public class BlockPistonExtendEvent : BlockPistonEvent
|
||||
{
|
||||
private readonly int _length;
|
||||
|
||||
internal BlockPistonExtendEvent(Block block, int length, BlockFace direction)
|
||||
: base(block, direction)
|
||||
{
|
||||
_length = length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the amount of blocks which will be moved while extending.
|
||||
/// </summary>
|
||||
/// <returns>The amount of moving blocks.</returns>
|
||||
public int getLength() => _length;
|
||||
|
||||
/// <summary>
|
||||
/// Get an immutable list of the blocks which will be moved by the extending.
|
||||
/// </summary>
|
||||
/// <returns>Immutable list of the moved blocks.</returns>
|
||||
public List<Block> getBlocks()
|
||||
{
|
||||
var blocks = new List<Block>();
|
||||
var world = getBlock().getWorld();
|
||||
int x = getBlock().getX();
|
||||
int y = getBlock().getY();
|
||||
int z = getBlock().getZ();
|
||||
var dir = getDirection();
|
||||
|
||||
for (int i = 0; i < _length; i++)
|
||||
{
|
||||
x += dir.getModX();
|
||||
y += dir.getModY();
|
||||
z += dir.getModZ();
|
||||
blocks.Add(new Block(world, x, y, z));
|
||||
}
|
||||
return blocks.AsReadOnly().ToList();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a piston retracts.
|
||||
/// </summary>
|
||||
public class BlockPistonRetractEvent : BlockPistonEvent
|
||||
{
|
||||
internal BlockPistonRetractEvent(Block block, BlockFace direction)
|
||||
: base(block, direction)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the location where the possible moving block might be if the
|
||||
/// retracting piston is sticky.
|
||||
/// </summary>
|
||||
/// <returns>The possible location of the possibly moving block.</returns>
|
||||
public Location getRetractLocation()
|
||||
{
|
||||
var block = getBlock();
|
||||
var dir = getDirection();
|
||||
return new Location(
|
||||
block.getWorld(),
|
||||
block.getX() + dir.getModX() * 2,
|
||||
block.getY() + dir.getModY() * 2,
|
||||
block.getZ() + dir.getModZ() * 2);
|
||||
}
|
||||
}
|
||||
58
Minecraft.Server.FourKit/Event/Block/BlockPlaceEvent.cs
Normal file
58
Minecraft.Server.FourKit/Event/Block/BlockPlaceEvent.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a block is placed by a player.
|
||||
/// </summary>
|
||||
public class BlockPlaceEvent : BlockEvent, Cancellable
|
||||
{
|
||||
protected Block placedAgainst;
|
||||
protected ItemStack itemInHand;
|
||||
protected Player player;
|
||||
protected bool canBuild;
|
||||
protected bool cancel;
|
||||
|
||||
internal BlockPlaceEvent(Block placedBlock, Block placedAgainst, ItemStack itemInHand, Player thePlayer, bool canBuild)
|
||||
: base(placedBlock)
|
||||
{
|
||||
this.placedAgainst = placedAgainst;
|
||||
this.itemInHand = itemInHand;
|
||||
this.player = thePlayer;
|
||||
this.canBuild = canBuild;
|
||||
this.cancel = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player who placed the block involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>The Player who placed the block involved in this event.</returns>
|
||||
public Player getPlayer() => player;
|
||||
|
||||
/// <summary>
|
||||
/// Clarity method for getting the placed block. Not really needed except
|
||||
/// for reasons of clarity.
|
||||
/// </summary>
|
||||
/// <returns>The Block that was placed.</returns>
|
||||
public Block getBlockPlaced() => getBlock();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block that this block was placed against.
|
||||
/// </summary>
|
||||
/// <returns>Block the block that the new block was placed against.</returns>
|
||||
public Block getBlockAgainst() => placedAgainst;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item in the player's hand when they placed the block.
|
||||
/// </summary>
|
||||
/// <returns>The ItemStack for the item in the player's hand when they placed the block.</returns>
|
||||
public ItemStack getItemInHand() => itemInHand;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool isCancelled() => cancel;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void setCancelled(bool cancel) => this.cancel = cancel;
|
||||
}
|
||||
32
Minecraft.Server.FourKit/Event/Block/BlockSpreadEvent.cs
Normal file
32
Minecraft.Server.FourKit/Event/Block/BlockSpreadEvent.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a block spreads based on world conditions.
|
||||
/// Use <see cref="BlockFormEvent"/> to catch blocks that "randomly" form
|
||||
/// instead of actually spread.
|
||||
///
|
||||
/// <para>Examples:</para>
|
||||
/// <list type="bullet">
|
||||
/// <item><description>Mushrooms spreading.</description></item>
|
||||
/// <item><description>Fire spreading.</description></item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para>If a Block Spread event is cancelled, the block will not spread.</para>
|
||||
/// </summary>
|
||||
public class BlockSpreadEvent : BlockFormEvent, Cancellable
|
||||
{
|
||||
private readonly Block _source;
|
||||
|
||||
internal BlockSpreadEvent(Block block, Block source, BlockState newState) : base(block, newState)
|
||||
{
|
||||
_source = source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source block involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>The Block for the source block involved in this event.</returns>
|
||||
public Block getSource() => _source;
|
||||
}
|
||||
65
Minecraft.Server.FourKit/Event/Block/SignChangeEvent.cs
Normal file
65
Minecraft.Server.FourKit/Event/Block/SignChangeEvent.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Block;
|
||||
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a sign is changed by a player.
|
||||
/// </summary>
|
||||
public class SignChangeEvent : BlockEvent, Cancellable
|
||||
{
|
||||
private readonly Player _player;
|
||||
private readonly string[] _lines;
|
||||
private bool _cancel;
|
||||
internal SignChangeEvent(Block theBlock, Player thePlayer, string[] theLines)
|
||||
: base(theBlock)
|
||||
{
|
||||
_player = thePlayer;
|
||||
_lines = theLines;
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player changing the sign involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>The Player involved in this event.</returns>
|
||||
public Player getPlayer() => _player;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all of the lines of text from the sign involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>The String array for the sign's lines new text.</returns>
|
||||
public string[] getLines() => _lines;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single line of text from the sign involved in this event.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the line to get.</param>
|
||||
/// <returns>The String containing the line of text associated with the provided index.</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when the provided index is > 3 or < 0.</exception>
|
||||
public string getLine(int index)
|
||||
{
|
||||
if (index < 0 || index > 3)
|
||||
throw new IndexOutOfRangeException($"Line index must be between 0 and 3, got {index}");
|
||||
return _lines[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a single line for the sign involved in this event.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the line to set.</param>
|
||||
/// <param name="line">Text to set.</param>
|
||||
/// <exception cref="IndexOutOfRangeException">Thrown when the provided index is > 3 or < 0.</exception>
|
||||
public void setLine(int index, string line)
|
||||
{
|
||||
if (index < 0 || index > 3)
|
||||
throw new IndexOutOfRangeException($"Line index must be between 0 and 3, got {index}");
|
||||
_lines[index] = line;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool isCancelled() => _cancel;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void setCancelled(bool cancel) => _cancel = cancel;
|
||||
}
|
||||
14
Minecraft.Server.FourKit/Event/Cancellable.cs
Normal file
14
Minecraft.Server.FourKit/Event/Cancellable.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace Minecraft.Server.FourKit.Event;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for events that can be cancelled by a plugin.
|
||||
/// When cancelled, the server will skip the default action.
|
||||
/// </summary>
|
||||
public interface Cancellable
|
||||
{
|
||||
/// <summary>Gets whether this event is cancelled.</summary>
|
||||
bool isCancelled();
|
||||
|
||||
/// <summary>Sets whether this event is cancelled.</summary>
|
||||
void setCancelled(bool cancel);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Entity;
|
||||
|
||||
using FourKitEntity = Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Called when an entity is damaged by an entity.
|
||||
/// </summary>
|
||||
public class EntityDamageByEntityEvent : EntityDamageEvent
|
||||
{
|
||||
private readonly FourKitEntity.Entity _damager;
|
||||
internal EntityDamageByEntityEvent(FourKitEntity.Entity damager, FourKitEntity.Entity damagee, EntityDamageEvent.DamageCause cause, double damage)
|
||||
: base(damagee, cause, damage)
|
||||
{
|
||||
_damager = damager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the entity that damaged the defender.
|
||||
/// </summary>
|
||||
/// <returns>The Entity that damaged the defender.</returns>
|
||||
public FourKitEntity.Entity getDamager() => _damager;
|
||||
}
|
||||
112
Minecraft.Server.FourKit/Event/Entity/EntityDamageEvent.cs
Normal file
112
Minecraft.Server.FourKit/Event/Entity/EntityDamageEvent.cs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Entity;
|
||||
|
||||
using FourKitEntity = Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Stores data for damage events.
|
||||
/// </summary>
|
||||
public class EntityDamageEvent : EntityEvent, Cancellable
|
||||
{
|
||||
/// <summary>
|
||||
/// An enum to specify the cause of the damage.
|
||||
/// </summary>
|
||||
public enum DamageCause
|
||||
{
|
||||
/// <summary>Damage caused by being in the area when a block explodes.</summary>
|
||||
BLOCK_EXPLOSION,
|
||||
/// <summary>Damage caused when an entity contacts a block such as a Cactus.</summary>
|
||||
CONTACT,
|
||||
/// <summary>Custom damage.</summary>
|
||||
CUSTOM,
|
||||
/// <summary>Damage caused by running out of air while in water.</summary>
|
||||
DROWNING,
|
||||
/// <summary>Damage caused when an entity attacks another entity.</summary>
|
||||
ENTITY_ATTACK,
|
||||
/// <summary>Damage caused by being in the area when an entity, such as a Creeper, explodes.</summary>
|
||||
ENTITY_EXPLOSION,
|
||||
/// <summary>Damage caused when an entity falls a distance greater than 3 blocks.</summary>
|
||||
FALL,
|
||||
/// <summary>Damage caused by being hit by a falling block which deals damage.</summary>
|
||||
FALLING_BLOCK,
|
||||
/// <summary>Damage caused by direct exposure to fire.</summary>
|
||||
FIRE,
|
||||
/// <summary>Damage caused due to burns caused by fire.</summary>
|
||||
FIRE_TICK,
|
||||
/// <summary>Damage caused by direct exposure to lava.</summary>
|
||||
LAVA,
|
||||
/// <summary>Damage caused by being struck by lightning.</summary>
|
||||
LIGHTNING,
|
||||
/// <summary>Damage caused by being hit by a damage potion or spell.</summary>
|
||||
MAGIC,
|
||||
/// <summary>Damage caused due to a snowman melting.</summary>
|
||||
MELTING,
|
||||
/// <summary>Damage caused due to an ongoing poison effect.</summary>
|
||||
POISON,
|
||||
/// <summary>Damage caused when attacked by a projectile.</summary>
|
||||
PROJECTILE,
|
||||
/// <summary>Damage caused by starving due to having an empty hunger bar.</summary>
|
||||
STARVATION,
|
||||
/// <summary>Damage caused by being put in a block.</summary>
|
||||
SUFFOCATION,
|
||||
/// <summary>Damage caused by committing suicide using the command "/kill".</summary>
|
||||
SUICIDE,
|
||||
/// <summary>Damage caused in retaliation to another attack by the Thorns enchantment.</summary>
|
||||
THORNS,
|
||||
/// <summary>Damage caused by falling into the void.</summary>
|
||||
VOID,
|
||||
/// <summary>Damage caused by Wither potion effect.</summary>
|
||||
WITHER,
|
||||
}
|
||||
|
||||
private readonly DamageCause _cause;
|
||||
private double _damage;
|
||||
private readonly double _finalDamage;
|
||||
private bool _cancel;
|
||||
internal EntityDamageEvent(FourKitEntity.Entity damagee, DamageCause cause, double damage)
|
||||
: base(damagee)
|
||||
{
|
||||
_cause = cause;
|
||||
_damage = damage;
|
||||
_finalDamage = damage;
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cause of the damage.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="DamageCause"/> value detailing the cause of the damage.</returns>
|
||||
public DamageCause getCause() => _cause;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw amount of damage caused by the event.
|
||||
/// </summary>
|
||||
/// <returns>The raw amount of damage.</returns>
|
||||
public double getDamage() => _damage;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of damage caused by the event after all damage
|
||||
/// reduction is applied.
|
||||
/// </summary>
|
||||
/// <returns>The amount of damage after reduction.</returns>
|
||||
public double getFinalDamage() => _finalDamage;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool isCancelled() => _cancel;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancel = cancel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the raw amount of damage caused by the event.
|
||||
/// </summary>
|
||||
/// <param name="damage">The raw amount of damage.</param>
|
||||
public void setDamage(double damage)
|
||||
{
|
||||
_damage = damage;
|
||||
}
|
||||
}
|
||||
53
Minecraft.Server.FourKit/Event/Entity/EntityDeathEvent.cs
Normal file
53
Minecraft.Server.FourKit/Event/Entity/EntityDeathEvent.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Entity;
|
||||
|
||||
using FourKitEntity = Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Thrown whenever a LivingEntity dies.
|
||||
/// </summary>
|
||||
public class EntityDeathEvent : EntityEvent
|
||||
{
|
||||
private readonly List<ItemStack> _drops;
|
||||
private int _droppedExp;
|
||||
|
||||
internal EntityDeathEvent(FourKitEntity.LivingEntity entity, List<ItemStack> drops)
|
||||
: this(entity, drops, 0)
|
||||
{
|
||||
}
|
||||
|
||||
internal EntityDeathEvent(FourKitEntity.LivingEntity what, List<ItemStack> drops, int droppedExp)
|
||||
: base(what)
|
||||
{
|
||||
_drops = drops;
|
||||
_droppedExp = droppedExp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Entity involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>Entity who is involved in this event.</returns>
|
||||
public new FourKitEntity.LivingEntity getEntity() => (FourKitEntity.LivingEntity)entity;
|
||||
|
||||
/// <summary>
|
||||
/// Gets how much EXP should be dropped from this death.
|
||||
/// This does not indicate how much EXP should be taken from the entity
|
||||
/// in question, merely how much should be created after its death.
|
||||
/// </summary>
|
||||
/// <returns>Amount of EXP to drop.</returns>
|
||||
public int getDroppedExp() => _droppedExp;
|
||||
|
||||
/// <summary>
|
||||
/// Sets how much EXP should be dropped from this death.
|
||||
/// This does not indicate how much EXP should be taken from the entity
|
||||
/// in question, merely how much should be created after its death.
|
||||
/// </summary>
|
||||
/// <param name="exp">Amount of EXP to drop.</param>
|
||||
public void setDroppedExp(int exp) => _droppedExp = exp;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the items which will drop when the entity dies.
|
||||
/// </summary>
|
||||
/// <returns>Items to drop when the entity dies.</returns>
|
||||
public List<ItemStack> getDrops() => _drops;
|
||||
}
|
||||
28
Minecraft.Server.FourKit/Event/Entity/EntityEvent.cs
Normal file
28
Minecraft.Server.FourKit/Event/Entity/EntityEvent.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Entity;
|
||||
|
||||
using FourKitEntity = Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an Entity-related event.
|
||||
/// </summary>
|
||||
public abstract class EntityEvent : Event
|
||||
{
|
||||
protected FourKitEntity.Entity entity;
|
||||
|
||||
protected EntityEvent(FourKitEntity.Entity what)
|
||||
{
|
||||
entity = what;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Entity involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>Entity who is involved in this event.</returns>
|
||||
public FourKitEntity.Entity getEntity() => entity;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the EntityType of the Entity involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>EntityType of the Entity involved in this event.</returns>
|
||||
public FourKitEntity.EntityType getEntityType() => entity.getType();
|
||||
}
|
||||
110
Minecraft.Server.FourKit/Event/Entity/PlayerDeathEvent.cs
Normal file
110
Minecraft.Server.FourKit/Event/Entity/PlayerDeathEvent.cs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Entity;
|
||||
|
||||
using FourKitEntity = Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Thrown whenever a Player dies.
|
||||
/// </summary>
|
||||
public class PlayerDeathEvent : EntityDeathEvent
|
||||
{
|
||||
private string _deathMessage;
|
||||
private int _newExp;
|
||||
private int _newLevel;
|
||||
private bool _keepLevel;
|
||||
private bool _keepInventory;
|
||||
internal PlayerDeathEvent(FourKitEntity.Player player, List<ItemStack> drops, int droppedExp, string deathMessage)
|
||||
: this(player, drops, droppedExp, 0, deathMessage)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="PlayerDeathEvent"/>.
|
||||
/// </summary>
|
||||
/// <param name="player">The Player who died.</param>
|
||||
/// <param name="drops">The items to drop when the player dies.</param>
|
||||
/// <param name="droppedExp">The amount of experience to drop.</param>
|
||||
/// <param name="newExp">The new EXP the Player should have at respawn.</param>
|
||||
/// <param name="deathMessage">The death message to display.</param>
|
||||
public PlayerDeathEvent(FourKitEntity.Player player, List<ItemStack> drops, int droppedExp, int newExp, string deathMessage)
|
||||
: base(player, drops, droppedExp)
|
||||
{
|
||||
_deathMessage = deathMessage;
|
||||
_newExp = newExp;
|
||||
_newLevel = 0;
|
||||
_keepLevel = false;
|
||||
_keepInventory = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Entity involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>Entity who is involved in this event.</returns>
|
||||
public new FourKitEntity.Player getEntity() => (FourKitEntity.Player)entity;
|
||||
|
||||
/// <summary>
|
||||
/// Get the death message that will appear to everyone on the server.
|
||||
/// </summary>
|
||||
/// <returns>Message to appear to other players on the server.</returns>
|
||||
public string getDeathMessage() => _deathMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Set the death message that will appear to everyone on the server.
|
||||
/// </summary>
|
||||
/// <param name="deathMessage">Message to appear to other players on the server.</param>
|
||||
public void setDeathMessage(string deathMessage) => _deathMessage = deathMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Gets how much EXP the Player should have at respawn.
|
||||
/// This does not indicate how much EXP should be dropped, please see
|
||||
/// <see cref="EntityDeathEvent.getDroppedExp"/> for that.
|
||||
/// </summary>
|
||||
/// <returns>New EXP of the respawned player.</returns>
|
||||
public int getNewExp() => _newExp;
|
||||
|
||||
/// <summary>
|
||||
/// Sets how much EXP the Player should have at respawn.
|
||||
/// This does not indicate how much EXP should be dropped, please see
|
||||
/// <see cref="EntityDeathEvent.setDroppedExp"/> for that.
|
||||
/// </summary>
|
||||
/// <param name="exp">New EXP of the respawned player.</param>
|
||||
public void setNewExp(int exp) => _newExp = exp;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Level the Player should have at respawn.
|
||||
/// </summary>
|
||||
/// <returns>New Level of the respawned player.</returns>
|
||||
public int getNewLevel() => _newLevel;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Level the Player should have at respawn.
|
||||
/// </summary>
|
||||
/// <param name="level">New Level of the respawned player.</param>
|
||||
public void setNewLevel(int level) => _newLevel = level;
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the Player should keep all EXP at respawn.
|
||||
/// This flag overrides other EXP settings.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if Player should keep all pre-death exp.</returns>
|
||||
public bool getKeepLevel() => _keepLevel;
|
||||
|
||||
/// <summary>
|
||||
/// Sets if the Player should keep all EXP at respawn.
|
||||
/// This overrides all other EXP settings.
|
||||
/// </summary>
|
||||
/// <param name="keepLevel"><c>true</c> to keep all current value levels.</param>
|
||||
public void setKeepLevel(bool keepLevel) => _keepLevel = keepLevel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the Player keeps inventory on death.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the player keeps inventory on death.</returns>
|
||||
public bool getKeepInventory() => _keepInventory;
|
||||
|
||||
/// <summary>
|
||||
/// Sets if the Player keeps inventory on death.
|
||||
/// </summary>
|
||||
/// <param name="keepInventory"><c>true</c> to keep the inventory.</param>
|
||||
public void setKeepInventory(bool keepInventory) => _keepInventory = keepInventory;
|
||||
}
|
||||
10
Minecraft.Server.FourKit/Event/Event.cs
Normal file
10
Minecraft.Server.FourKit/Event/Event.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
namespace Minecraft.Server.FourKit.Event;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all events dispatched by the server.
|
||||
/// </summary>
|
||||
public abstract class Event
|
||||
{
|
||||
/// <summary>Gets the name of this event (defaults to the class name).</summary>
|
||||
public virtual string getEventName() => GetType().Name;
|
||||
}
|
||||
40
Minecraft.Server.FourKit/Event/EventHandlerAttribute.cs
Normal file
40
Minecraft.Server.FourKit/Event/EventHandlerAttribute.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
namespace Minecraft.Server.FourKit.Event;
|
||||
|
||||
/// <summary>
|
||||
/// Marks a method inside a <see cref="Listener"/> as an event handler.
|
||||
/// This class is not named "EventHandler" due to a naming conflict with the existing System.EventHandler
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
public sealed class EventHandlerAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Priority of this handler. Lower values run first.
|
||||
/// Default is <see cref="EventPriority.Normal"/>.
|
||||
/// </summary>
|
||||
public EventPriority Priority { get; set; } = EventPriority.Normal;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this handler should be skipped when the event is already
|
||||
/// cancelled by a lower-priority handler. Default is <c>false</c>.
|
||||
/// </summary>
|
||||
public bool IgnoreCancelled { get; set; } = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execution priority for event handlers.
|
||||
/// </summary>
|
||||
public enum EventPriority
|
||||
{
|
||||
/// <summary>Event call is of very low importance and should be ran first, to allow other plugins to further customise the outcome</summary>
|
||||
Lowest = 0,
|
||||
/// <summary>Event call is of low importance</summary>
|
||||
Low = 1,
|
||||
/// <summary>Event call is neither important nor unimportant, and may be ran normally</summary>
|
||||
Normal = 2,
|
||||
/// <summary>Event call is of high importance</summary>
|
||||
High = 3,
|
||||
/// <summary>Event call is critical and must have the final say in what happens to the event</summary>
|
||||
Highest = 4,
|
||||
/// <summary>Event is listened to purely for monitoring the outcome of an event. Should not modify the event.</summary>
|
||||
Monitor = 5
|
||||
}
|
||||
93
Minecraft.Server.FourKit/Event/Inventory/ClickType.cs
Normal file
93
Minecraft.Server.FourKit/Event/Inventory/ClickType.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// What the client did to trigger this action (not the result).
|
||||
/// </summary>
|
||||
public enum ClickType
|
||||
{
|
||||
/// <summary>The left (or primary) mouse button.</summary>
|
||||
LEFT,
|
||||
/// <summary>Holding shift while pressing the left mouse button.</summary>
|
||||
SHIFT_LEFT,
|
||||
/// <summary>The right mouse button.</summary>
|
||||
RIGHT,
|
||||
/// <summary>Holding shift while pressing the right mouse button.</summary>
|
||||
SHIFT_RIGHT,
|
||||
/// <summary>Clicking the left mouse button on the grey area around the inventory.</summary>
|
||||
WINDOW_BORDER_LEFT,
|
||||
/// <summary>Clicking the right mouse button on the grey area around the inventory.</summary>
|
||||
WINDOW_BORDER_RIGHT,
|
||||
/// <summary>The middle mouse button, or a "scrollwheel click".</summary>
|
||||
MIDDLE,
|
||||
/// <summary>One of the number keys 1-9, correspond to slots on the hotbar.</summary>
|
||||
NUMBER_KEY,
|
||||
/// <summary>Pressing the left mouse button twice in quick succession.</summary>
|
||||
DOUBLE_CLICK,
|
||||
/// <summary>The "Drop" key (defaults to Q).</summary>
|
||||
DROP,
|
||||
/// <summary>Holding Ctrl while pressing the "Drop" key (defaults to Q).</summary>
|
||||
CONTROL_DROP,
|
||||
/// <summary>Any action done with the Creative inventory open.</summary>
|
||||
CREATIVE,
|
||||
/// <summary>A type of inventory manipulation not yet recognized by Bukkit.</summary>
|
||||
UNKNOWN,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="ClickType"/>.
|
||||
/// </summary>
|
||||
public static class ClickTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether this ClickType represents the pressing of a key on a keyboard.
|
||||
/// </summary>
|
||||
/// <param name="click">The click type.</param>
|
||||
/// <returns>true if this ClickType represents the pressing of a key.</returns>
|
||||
public static bool isKeyboardClick(this ClickType click)
|
||||
{
|
||||
return click == ClickType.NUMBER_KEY || click == ClickType.DROP || click == ClickType.CONTROL_DROP;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this ClickType represents an action that can only be performed
|
||||
/// by a Player in creative mode.
|
||||
/// </summary>
|
||||
/// <param name="click">The click type.</param>
|
||||
/// <returns>true if this action requires Creative mode.</returns>
|
||||
public static bool isCreativeAction(this ClickType click)
|
||||
{
|
||||
return click == ClickType.CREATIVE || click == ClickType.MIDDLE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this ClickType represents a right click.
|
||||
/// </summary>
|
||||
/// <param name="click">The click type.</param>
|
||||
/// <returns>true if this ClickType represents a right click.</returns>
|
||||
public static bool isRightClick(this ClickType click)
|
||||
{
|
||||
return click == ClickType.RIGHT || click == ClickType.SHIFT_RIGHT;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this ClickType represents a left click.
|
||||
/// </summary>
|
||||
/// <param name="click">The click type.</param>
|
||||
/// <returns>true if this ClickType represents a left click.</returns>
|
||||
public static bool isLeftClick(this ClickType click)
|
||||
{
|
||||
return click == ClickType.LEFT || click == ClickType.SHIFT_LEFT
|
||||
|| click == ClickType.DOUBLE_CLICK || click == ClickType.CREATIVE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this ClickType indicates that the shift key was pressed
|
||||
/// down when the click was made.
|
||||
/// </summary>
|
||||
/// <param name="click">The click type.</param>
|
||||
/// <returns>true if the action uses Shift.</returns>
|
||||
public static bool isShiftClick(this ClickType click)
|
||||
{
|
||||
return click == ClickType.SHIFT_LEFT || click == ClickType.SHIFT_RIGHT;
|
||||
}
|
||||
}
|
||||
46
Minecraft.Server.FourKit/Event/Inventory/InventoryAction.cs
Normal file
46
Minecraft.Server.FourKit/Event/Inventory/InventoryAction.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// An estimation of what the result will be.
|
||||
/// </summary>
|
||||
public enum InventoryAction
|
||||
{
|
||||
/// <summary>Nothing will happen from the click.</summary>
|
||||
NOTHING,
|
||||
/// <summary>All of the items on the clicked slot are moved to the cursor.</summary>
|
||||
PICKUP_ALL,
|
||||
/// <summary>Some of the items on the clicked slot are moved to the cursor.</summary>
|
||||
PICKUP_SOME,
|
||||
/// <summary>Half of the items on the clicked slot are moved to the cursor.</summary>
|
||||
PICKUP_HALF,
|
||||
/// <summary>One of the items on the clicked slot are moved to the cursor.</summary>
|
||||
PICKUP_ONE,
|
||||
/// <summary>All of the items on the cursor are moved to the clicked slot.</summary>
|
||||
PLACE_ALL,
|
||||
/// <summary>Some of the items from the cursor are moved to the clicked slot (usually up to the max stack size).</summary>
|
||||
PLACE_SOME,
|
||||
/// <summary>A single item from the cursor is moved to the clicked slot.</summary>
|
||||
PLACE_ONE,
|
||||
/// <summary>The clicked item and the cursor are exchanged.</summary>
|
||||
SWAP_WITH_CURSOR,
|
||||
/// <summary>The entire cursor item is dropped.</summary>
|
||||
DROP_ALL_CURSOR,
|
||||
/// <summary>One item is dropped from the cursor.</summary>
|
||||
DROP_ONE_CURSOR,
|
||||
/// <summary>The entire clicked slot is dropped.</summary>
|
||||
DROP_ALL_SLOT,
|
||||
/// <summary>One item is dropped from the clicked slot.</summary>
|
||||
DROP_ONE_SLOT,
|
||||
/// <summary>The item is moved to the opposite inventory if a space is found.</summary>
|
||||
MOVE_TO_OTHER_INVENTORY,
|
||||
/// <summary>The clicked item is moved to the hotbar, and the item currently there is re-added to the player's inventory.</summary>
|
||||
HOTBAR_MOVE_AND_READD,
|
||||
/// <summary>The clicked slot and the picked hotbar slot are swapped.</summary>
|
||||
HOTBAR_SWAP,
|
||||
/// <summary>A max-size stack of the clicked item is put on the cursor.</summary>
|
||||
CLONE_STACK,
|
||||
/// <summary>The inventory is searched for the same material, and they are put on the cursor up to Material.getMaxStackSize().</summary>
|
||||
COLLECT_TO_CURSOR,
|
||||
/// <summary>An unrecognized ClickType.</summary>
|
||||
UNKNOWN,
|
||||
}
|
||||
157
Minecraft.Server.FourKit/Event/Inventory/InventoryClickEvent.cs
Normal file
157
Minecraft.Server.FourKit/Event/Inventory/InventoryClickEvent.cs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Inventory;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// This event is called when a player clicks a slot in an inventory.
|
||||
/// <para>
|
||||
/// Because InventoryClickEvent occurs within a modification of the Inventory,
|
||||
/// not all Inventory related methods are safe to use.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The following should never be invoked by an EventHandler for
|
||||
/// InventoryClickEvent using the HumanEntity or InventoryView associated
|
||||
/// with this event:
|
||||
/// <list type="bullet">
|
||||
/// <item><description><see cref="HumanEntity.closeInventory()"/></description></item>
|
||||
/// <item><description><see cref="HumanEntity.openInventory(Inventory)"/></description></item>
|
||||
/// <item><description><see cref="InventoryView.close()"/></description></item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class InventoryClickEvent : InventoryInteractEvent
|
||||
{
|
||||
private readonly SlotType _slotType;
|
||||
private readonly int _rawSlot;
|
||||
private readonly int _whichSlot;
|
||||
private readonly ClickType _click;
|
||||
private readonly InventoryAction _action;
|
||||
private readonly int _hotbarKey;
|
||||
private ItemStack? _currentItem;
|
||||
internal InventoryClickEvent(InventoryView view, SlotType type, int slot,
|
||||
ClickType click, InventoryAction action)
|
||||
: this(view, type, slot, click, action, -1)
|
||||
{
|
||||
}
|
||||
internal InventoryClickEvent(InventoryView view, SlotType type, int slot,
|
||||
ClickType click, InventoryAction action, int key)
|
||||
: base(view)
|
||||
{
|
||||
_slotType = type;
|
||||
_rawSlot = slot;
|
||||
_click = click;
|
||||
_action = action;
|
||||
_hotbarKey = key;
|
||||
_currentItem = view.getItem(slot);
|
||||
_whichSlot = view.convertSlot(slot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the inventory that was clicked, or null if outside of window.
|
||||
/// </summary>
|
||||
/// <returns>The clicked inventory.</returns>
|
||||
public Inventory? getClickedInventory()
|
||||
{
|
||||
if (_rawSlot == InventoryView.OUTSIDE)
|
||||
return null;
|
||||
int topSize = getView().getTopInventory().getSize();
|
||||
if (_rawSlot < topSize)
|
||||
return getView().getTopInventory();
|
||||
return getView().getBottomInventory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of slot that was clicked.
|
||||
/// </summary>
|
||||
/// <returns>The slot type.</returns>
|
||||
public SlotType getSlotType() => _slotType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current ItemStack on the cursor.
|
||||
/// </summary>
|
||||
/// <returns>The cursor ItemStack.</returns>
|
||||
public ItemStack? getCursor() => getView().getCursor();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ItemStack currently in the clicked slot.
|
||||
/// </summary>
|
||||
/// <returns>The item in the clicked slot.</returns>
|
||||
public ItemStack? getCurrentItem() => _currentItem;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the ClickType for this event represents a right click.
|
||||
/// </summary>
|
||||
/// <returns>true if the ClickType uses the right mouse button.</returns>
|
||||
public bool isRightClick() => _click.isRightClick();
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the ClickType for this event represents a left click.
|
||||
/// </summary>
|
||||
/// <returns>true if the ClickType uses the left mouse button.</returns>
|
||||
public bool isLeftClick() => _click.isLeftClick();
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the ClickType for this event indicates that the key was
|
||||
/// pressed down when the click was made.
|
||||
/// </summary>
|
||||
/// <returns>true if the ClickType uses Shift or Ctrl.</returns>
|
||||
public bool isShiftClick() => _click.isShiftClick();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the item on the cursor.
|
||||
/// </summary>
|
||||
/// <param name="stack">The new cursor item.</param>
|
||||
[Obsolete("This changes the ItemStack in their hand before any calculations are applied to the Inventory.")]
|
||||
public void setCursor(ItemStack? stack) => getView().setCursor(stack);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ItemStack currently in the clicked slot.
|
||||
/// </summary>
|
||||
/// <param name="stack">The item to be placed in the current slot.</param>
|
||||
public void setCurrentItem(ItemStack? stack)
|
||||
{
|
||||
_currentItem = stack;
|
||||
if (_rawSlot >= 0)
|
||||
getView().setItem(_rawSlot, stack);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The slot number that was clicked, ready for passing to
|
||||
/// <see cref="Inventory.getItem(int)"/>. Note that there may be two slots
|
||||
/// with the same slot number, since a view links two different inventories.
|
||||
/// </summary>
|
||||
/// <returns>The slot number.</returns>
|
||||
public int getSlot() => _whichSlot;
|
||||
|
||||
/// <summary>
|
||||
/// The raw slot number clicked, ready for passing to
|
||||
/// <see cref="InventoryView.getItem(int)"/>. This slot number is unique
|
||||
/// for the view.
|
||||
/// </summary>
|
||||
/// <returns>The raw slot number.</returns>
|
||||
public int getRawSlot() => _rawSlot;
|
||||
|
||||
/// <summary>
|
||||
/// If the ClickType is NUMBER_KEY, this method will return the index of
|
||||
/// the pressed key (0-8).
|
||||
/// </summary>
|
||||
/// <returns>The number on the key minus 1 (range 0-8); or -1 if not a NUMBER_KEY action.</returns>
|
||||
public int getHotbarButton() => _hotbarKey;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the InventoryAction that triggered this event.
|
||||
/// This action cannot be changed, and represents what the normal outcome
|
||||
/// of the event will be. To change the behavior of this InventoryClickEvent,
|
||||
/// changes must be manually applied.
|
||||
/// </summary>
|
||||
/// <returns>The InventoryAction that triggered this event.</returns>
|
||||
public InventoryAction getAction() => _action;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ClickType for this event.
|
||||
/// This is insulated against changes to the inventory by other plugins.
|
||||
/// </summary>
|
||||
/// <returns>The type of inventory click.</returns>
|
||||
public ClickType getClick() => _click;
|
||||
}
|
||||
45
Minecraft.Server.FourKit/Event/Inventory/InventoryEvent.cs
Normal file
45
Minecraft.Server.FourKit/Event/Inventory/InventoryEvent.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Inventory;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a player related inventory event.
|
||||
/// </summary>
|
||||
public class InventoryEvent : Event
|
||||
{
|
||||
/// <summary>The inventory view associated with this event.</summary>
|
||||
protected readonly InventoryView transaction;
|
||||
internal InventoryEvent(InventoryView transaction)
|
||||
{
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primary Inventory involved in this transaction.
|
||||
/// </summary>
|
||||
/// <returns>The upper inventory.</returns>
|
||||
public global::Minecraft.Server.FourKit.Inventory.Inventory getInventory()
|
||||
{
|
||||
return transaction.getTopInventory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of players viewing the primary (upper) inventory
|
||||
/// involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>A list of people viewing.</returns>
|
||||
public List<HumanEntity> getViewers()
|
||||
{
|
||||
return transaction.getTopInventory().getViewers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view object itself.
|
||||
/// </summary>
|
||||
/// <returns>The InventoryView.</returns>
|
||||
public InventoryView getView()
|
||||
{
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Inventory;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// An abstract base class for events that describe an interaction between a
|
||||
/// <see cref="HumanEntity"/> and the contents of an <see cref="Inventory"/>.
|
||||
/// This is currently not emitted anywhere, use <see cref="InventoryClickEvent"/> instead.
|
||||
/// </summary>
|
||||
public abstract class InventoryInteractEvent : InventoryEvent, Cancellable
|
||||
{
|
||||
private bool _cancelled;
|
||||
internal protected InventoryInteractEvent(InventoryView transaction) : base(transaction)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player who performed the click.
|
||||
/// </summary>
|
||||
/// <returns>The clicking player.</returns>
|
||||
public HumanEntity getWhoClicked()
|
||||
{
|
||||
return transaction.getPlayer();
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool isCancelled() => _cancelled;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void setCancelled(bool cancel) => _cancelled = cancel;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Inventory;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a player opens an inventory. Cancelling this event will prevent
|
||||
/// the inventory screen from showing.
|
||||
/// </summary>
|
||||
public class InventoryOpenEvent : InventoryEvent, Cancellable
|
||||
{
|
||||
private bool _cancelled;
|
||||
internal InventoryOpenEvent(InventoryView transaction) : base(transaction)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the player involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>Player who is involved in this event.</returns>
|
||||
public HumanEntity getPlayer() => transaction.getPlayer();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cancellation state of this event. A cancelled event will not
|
||||
/// be executed in the server, but will still pass to other plugins.
|
||||
/// If an inventory open event is cancelled, the inventory screen will not show.
|
||||
/// </summary>
|
||||
/// <returns>true if this event is cancelled.</returns>
|
||||
public bool isCancelled() => _cancelled;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the cancellation state of this event. A cancelled event will not
|
||||
/// be executed in the server, but will still pass to other plugins.
|
||||
/// If an inventory open event is cancelled, the inventory screen will not show.
|
||||
/// </summary>
|
||||
/// <param name="cancel">true if you wish to cancel this event.</param>
|
||||
public void setCancelled(bool cancel) => _cancelled = cancel;
|
||||
}
|
||||
9
Minecraft.Server.FourKit/Event/Listener.cs
Normal file
9
Minecraft.Server.FourKit/Event/Listener.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
namespace Minecraft.Server.FourKit.Event;
|
||||
|
||||
/// <summary>
|
||||
/// Simple interface for tagging all EventListeners
|
||||
/// Register instances with <see cref="FourKit.addListener(Listener)"/>.
|
||||
/// </summary>
|
||||
public interface Listener
|
||||
{
|
||||
}
|
||||
33
Minecraft.Server.FourKit/Event/Player/PlayerBedEnterEvent.cs
Normal file
33
Minecraft.Server.FourKit/Event/Player/PlayerBedEnterEvent.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Player;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// This event is fired when the player is almost about to enter the bed.
|
||||
/// </summary>
|
||||
public class PlayerBedEnterEvent : PlayerEvent, Cancellable
|
||||
{
|
||||
private readonly Block _bed;
|
||||
private bool _cancelled;
|
||||
|
||||
internal PlayerBedEnterEvent(Player player, Block bed) : base(player)
|
||||
{
|
||||
_bed = bed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the bed block involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>the bed block involved in this event</returns>
|
||||
public Block getBed() => _bed;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool isCancelled() => _cancelled;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancelled = cancel;
|
||||
}
|
||||
}
|
||||
23
Minecraft.Server.FourKit/Event/Player/PlayerBedLeaveEvent.cs
Normal file
23
Minecraft.Server.FourKit/Event/Player/PlayerBedLeaveEvent.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Player;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
|
||||
/// <summary>
|
||||
/// This event is fired when the player is leaving a bed.
|
||||
/// </summary>
|
||||
public class PlayerBedLeaveEvent : PlayerEvent
|
||||
{
|
||||
private readonly Block _bed;
|
||||
|
||||
internal PlayerBedLeaveEvent(Player player, Block bed) : base(player)
|
||||
{
|
||||
_bed = bed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the bed block involved in this event.
|
||||
/// </summary>
|
||||
/// <returns>the bed block involved in this event</returns>
|
||||
public Block getBed() => _bed;
|
||||
}
|
||||
74
Minecraft.Server.FourKit/Event/Player/PlayerChatEvent.cs
Normal file
74
Minecraft.Server.FourKit/Event/Player/PlayerChatEvent.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Player;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player sends a chat message.
|
||||
///
|
||||
/// <para>When the event finishes execution the server formats the final
|
||||
/// output using the same format specifiers from Java.
|
||||
/// <c>%1$s</c> is the player's display name and <c>%2$s</c> is the
|
||||
/// message, exactly like Bukkits <c>PlayerChatEvent</c>.</para>
|
||||
/// </summary>
|
||||
public class PlayerChatEvent : PlayerEvent, Cancellable
|
||||
{
|
||||
private string _message;
|
||||
private string _format;
|
||||
private bool _cancelled;
|
||||
internal PlayerChatEvent(Player player, string message) : base(player)
|
||||
{
|
||||
_message = message;
|
||||
_format = "<%1$s> %2$s";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message that the player is attempting to send.
|
||||
/// This message will be used with <see cref="getFormat"/>.
|
||||
/// </summary>
|
||||
/// <returns>Message the player is attempting to send.</returns>
|
||||
public string getMessage() => _message;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the message that the player will send.
|
||||
/// This message will be used with <see cref="getFormat"/>.
|
||||
/// </summary>
|
||||
/// <param name="message">New message that the player will send.</param>
|
||||
public void setMessage(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the format used to display this chat message.
|
||||
///
|
||||
/// <para>When this event finishes execution, the first format parameter
|
||||
/// (<c>%1$s</c>) is <c>Player.getDisplayName()</c> and the second
|
||||
/// parameter (<c>%2$s</c>) is <c>getMessage()</c>.</para>
|
||||
/// </summary>
|
||||
/// <returns>A Java-style positional format string compatible with Bukkit.</returns>
|
||||
public string getFormat() => _format;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the format used to display this chat message.
|
||||
///
|
||||
/// <para>When this event finishes execution, the first format parameter
|
||||
/// (<c>%1$s</c>) is <c>Player.getDisplayName()</c> and the second
|
||||
/// parameter (<c>%2$s</c>) is <c>getMessage()</c>.</para>
|
||||
/// </summary>
|
||||
/// <param name="format">A Java-style positional format string (e.g. <c>"<%1$s> %2$s"</c>).</param>
|
||||
/// <exception cref="ArgumentNullException">If format is <c>null</c>.</exception>
|
||||
public void setFormat(string format)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(format);
|
||||
_format = format;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool isCancelled() => _cancelled;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancelled = cancel;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Player;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Called early in the command handling process. This event is only for very
|
||||
/// exceptional cases and you should not normally use it.
|
||||
///
|
||||
/// <para>If a PlayerCommandPreprocessEvent is cancelled, the command will not
|
||||
/// be executed in the server, but will still pass to other plugins.</para>
|
||||
/// </summary>
|
||||
public class PlayerCommandPreprocessEvent : PlayerEvent, Cancellable
|
||||
{
|
||||
private string _message;
|
||||
private bool _cancel;
|
||||
|
||||
internal PlayerCommandPreprocessEvent(Player player, string message) : base(player)
|
||||
{
|
||||
_message = message;
|
||||
_cancel = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool isCancelled() => _cancel;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancel = cancel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the command that the player is attempting to send. All commands
|
||||
/// begin with a special character; implementations do not consider the
|
||||
/// first character when executing the content.
|
||||
/// </summary>
|
||||
/// <returns>Message the player is attempting to send.</returns>
|
||||
public string getMessage() => _message;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the command that the player will send. All commands begin with a
|
||||
/// special character; implementations do not consider the first character
|
||||
/// when executing the content.
|
||||
/// </summary>
|
||||
/// <param name="command">New message that the player will send.</param>
|
||||
/// <exception cref="ArgumentException">If command is null or empty.</exception>
|
||||
public void setMessage(string command)
|
||||
{
|
||||
if (string.IsNullOrEmpty(command))
|
||||
throw new ArgumentException("Command may not be null or empty", nameof(command));
|
||||
_message = command;
|
||||
}
|
||||
}
|
||||
46
Minecraft.Server.FourKit/Event/Player/PlayerDropItemEvent.cs
Normal file
46
Minecraft.Server.FourKit/Event/Player/PlayerDropItemEvent.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Player;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
// Yo this event pissed me the fuck off
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player drops an item from their inventory.
|
||||
/// If cancelled, the item will not be dropped and the player keeps it.
|
||||
/// The dropped item can be modified by plugins.
|
||||
/// </summary>
|
||||
public class PlayerDropItemEvent : PlayerEvent, Cancellable
|
||||
{
|
||||
private ItemStack _itemDrop;
|
||||
private bool _cancelled;
|
||||
internal PlayerDropItemEvent(Player player, ItemStack drop)
|
||||
: base(player)
|
||||
{
|
||||
_itemDrop = drop;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ItemDrop created by the player.
|
||||
/// </summary>
|
||||
/// <returns>The ItemStack being dropped.</returns>
|
||||
public ItemStack getItemDrop() => _itemDrop;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the item to be dropped. Plugins can modify which item
|
||||
/// is actually dropped.
|
||||
/// </summary>
|
||||
/// <param name="item">The new item to drop.</param>
|
||||
public void setItemDrop(ItemStack item)
|
||||
{
|
||||
_itemDrop = item;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool isCancelled() => _cancelled;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void setCancelled(bool cancel)
|
||||
{
|
||||
_cancelled = cancel;
|
||||
}
|
||||
}
|
||||
19
Minecraft.Server.FourKit/Event/Player/PlayerEvent.cs
Normal file
19
Minecraft.Server.FourKit/Event/Player/PlayerEvent.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
namespace Minecraft.Server.FourKit.Event.Player;
|
||||
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for events related to a <see cref="FourKit.Player"/>.
|
||||
/// </summary>
|
||||
public abstract class PlayerEvent : Event
|
||||
{
|
||||
private readonly Player _player;
|
||||
|
||||
internal protected PlayerEvent(Player player)
|
||||
{
|
||||
_player = player;
|
||||
}
|
||||
|
||||
/// <summary>Returns the player involved in this event.</summary>
|
||||
public Player getPlayer() => _player;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue