Lua: Implement most API functions

This commit is contained in:
Lion Kortlepel
2021-09-16 19:00:13 +02:00
parent 1c80a4deb7
commit 968d9ff999
6 changed files with 168 additions and 19 deletions

View File

@@ -2,6 +2,7 @@
#include <chrono>
#include <memory>
#include <optional>
#include <queue>
#include <string>
#include <unordered_set>
@@ -98,3 +99,5 @@ private:
int mID = -1;
std::chrono::time_point<std::chrono::high_resolution_clock> mLastPingTime;
};
std::optional<std::weak_ptr<TClient>> GetClient(class TServer& Server, int ID);

View File

@@ -10,5 +10,14 @@ namespace MP {
std::string GetOSName();
std::tuple<int, int, int> GetServerVersion();
bool TriggerClientEvent(int PlayerID, const std::string& EventName, const std::string& Data);
size_t GetPlayerCount() { return Engine->Server().ClientCount(); }
void DropPlayer(int ID, std::optional<std::string> MaybeReason);
void SendChatMessage(int ID, const std::string& Message);
void RemoveVehicle(int PlayerID, int VehicleID);
void Set(int ConfigID, sol::object NewValue);
bool GetPlayerGuest(int ID);
bool IsPlayerConnected(int ID);
void Sleep(size_t Ms);
}
}

View File

@@ -47,6 +47,9 @@ public:
void operator()() override;
TNetwork& Network() { return mNetwork; }
TServer& Server() { return mServer; }
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(TLuaStateId StateID, const std::shared_ptr<std::string>& Script);
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName);
void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false);
@@ -70,11 +73,13 @@ private:
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(const std::string& FunctionName);
void RegisterEvent(const std::string& EventName, const std::string& FunctionName);
void operator()() override;
private:
sol::table Lua_TriggerGlobalEvent(const std::string& EventName);
sol::table Lua_TriggerLocalEvent(const std::string& EventName);
sol::table Lua_GetPlayerIdentifiers(int ID);
sol::table Lua_GetPlayers();
std::string mName;
std::atomic_bool& mShutdown;
TLuaStateId mStateId;
@@ -85,6 +90,7 @@ private:
std::queue<std::pair<std::string, std::shared_ptr<TLuaResult>>> mStateFunctionQueue;
std::recursive_mutex mStateFunctionQueueMutex;
TLuaEngine* mEngine;
sol::state_view mStateView { mState };
};
TNetwork& mNetwork;

View File

@@ -1,7 +1,9 @@
#include "Client.h"
#include "CustomAssert.h"
#include "TServer.h"
#include <memory>
#include <optional>
// FIXME: add debug prints
@@ -100,3 +102,19 @@ int TClient::SecondsSinceLastPing() {
.count();
return int(seconds);
}
std::optional<std::weak_ptr<TClient>> GetClient(TServer& Server, int ID) {
std::optional<std::weak_ptr<TClient>> MaybeClient { std::nullopt };
Server.ForEachClient([&](std::weak_ptr<TClient> CPtr) -> bool {
ReadLock Lock(Server.GetClientMutex());
if (!CPtr.expired()) {
auto C = CPtr.lock();
if (C->GetID() == ID) {
MaybeClient = CPtr;
return false;
}
}
return true;
});
return MaybeClient;
}

View File

@@ -1,4 +1,5 @@
#include "LuaAPI.h"
#include "Client.h"
#include "TLuaEngine.h"
static std::string LuaToString(const sol::object& Value, size_t Indent = 1) {
@@ -63,3 +64,71 @@ void LuaAPI::Print(sol::variadic_args Args) {
}
luaprint(ToPrint);
}
bool LuaAPI::MP::TriggerClientEvent(int PlayerID, const std::string& EventName, const std::string& Data) {
std::string Packet = "E:" + EventName + ":" + Data;
if (PlayerID == -1)
Engine->Network().SendToAll(nullptr, Packet, true, true);
else {
auto MaybeClient = GetClient(Engine->Server(), PlayerID);
if (!MaybeClient || MaybeClient.value().expired()) {
beammp_lua_error("TriggerClientEvent invalid Player ID");
return false;
}
auto c = MaybeClient.value().lock();
if (!Engine->Network().Respond(*c, Packet, true)) {
beammp_lua_error("Respond failed");
return false;
}
}
return true;
}
void LuaAPI::MP::DropPlayer(int ID, std::optional<std::string> MaybeReason) {
auto MaybeClient = GetClient(Engine->Server(), ID);
if (!MaybeClient || MaybeClient.value().expired()) {
return;
}
auto c = MaybeClient.value().lock();
if (!Engine->Network().Respond(*c, "C:Server:You have been Kicked from the server! Reason: " + MaybeReason.value_or("No reason"), true)) {
// Ignore
}
c->SetStatus(-2);
beammp_info("Closing socket due to kick");
CloseSocketProper(c->GetTCPSock());
}
void LuaAPI::MP::SendChatMessage(int ID, const std::string& Message) {
std::string Packet = "C:Server: " + Message;
if (ID == -1) {
//LogChatMessage("<Server> (to everyone) ", -1, Message);
Engine->Network().SendToAll(nullptr, Packet, true, true);
} else {
auto MaybeClient = GetClient(Engine->Server(), ID);
if (MaybeClient && !MaybeClient.value().expired()) {
auto c = MaybeClient.value().lock();
if (!c->IsSynced())
return;
//LogChatMessage("<Server> (to \"" + c->GetName() + "\")", -1, msg);
Engine->Network().Respond(*c, Packet, true);
} else {
beammp_lua_error("SendChatMessage invalid argument [1] invalid ID");
}
}
}
void LuaAPI::MP::RemoveVehicle(int PlayerID, int VehicleID) {
}
void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) {
}
void LuaAPI::MP::Sleep(size_t Ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(Ms));
}
bool LuaAPI::MP::IsPlayerConnected(int ID) {
}
bool LuaAPI::MP::GetPlayerGuest(int ID) {
}

View File

@@ -1,8 +1,8 @@
#include "TLuaEngine.h"
#include "Client.h"
#include "CustomAssert.h"
#include "TLuaPlugin.h"
#include "LuaAPI.h"
#include "TLuaPlugin.h"
#include <chrono>
#include <random>
@@ -185,10 +185,9 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string
}
sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string& EventName) {
sol::state_view StateView(mState);
sol::table Result = StateView.create_table();
sol::table Result = mStateView.create_table();
for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) {
auto Fn = StateView[Handler];
auto Fn = mStateView[Handler];
if (Fn.valid() && Fn.get_type() == sol::type::function) {
Result.add(Fn());
}
@@ -196,6 +195,34 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string&
return Result;
}
sol::table TLuaEngine::StateThreadData::Lua_GetPlayerIdentifiers(int ID) {
auto MaybeClient = GetClient(mEngine->Server(), ID);
if (MaybeClient && !MaybeClient.value().expired()) {
auto IDs = MaybeClient.value().lock()->GetIdentifiers();
if (IDs.empty()) {
return sol::nil;
}
sol::table Result = mStateView.create_table();
for (const auto& Pair : IDs) {
Result[Pair.first] = Pair.second;
}
return Result;
} else {
return sol::nil;
}
}
sol::table TLuaEngine::StateThreadData::Lua_GetPlayers() {
sol::table Result = mStateView.create_table();
mEngine->Server().ForEachClient([&](std::weak_ptr<TClient> Client) -> bool {
if (!Client.expired()) {
auto locked = Client.lock();
Result[locked->GetID()] = locked->GetName();
}
return true;
});
return Result;
}
TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine)
: mName(Name)
, mShutdown(Shutdown)
@@ -206,21 +233,38 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi
sol::state_view StateView(mState);
// StateView.globals()["package"].get()
StateView.set_function("print", &LuaAPI::Print);
StateView.set_function("exit", &Application::GracefullyShutdown);
auto Table = StateView.create_named_table("MP");
Table.set_function("GetOSName", &LuaAPI::MP::GetOSName);
Table.set_function("GetServerVersion", &LuaAPI::MP::GetServerVersion);
Table.set_function("RegisterEvent",
[this](const std::string& EventName, const std::string& FunctionName) {
RegisterEvent(EventName, FunctionName);
});
Table.set_function("TriggerGlobalEvent",
[&](const std::string& EventName) -> sol::table {
return Lua_TriggerGlobalEvent(EventName);
});
Table.set_function("TriggerLocalEvent",
[&](const std::string& EventName) -> sol::table {
return Lua_TriggerLocalEvent(EventName);
});
Table.set_function("RegisterEvent", [this](const std::string& EventName, const std::string& FunctionName) {
RegisterEvent(EventName, FunctionName);
});
Table.set_function("TriggerGlobalEvent", [&](const std::string& EventName) -> sol::table {
return Lua_TriggerGlobalEvent(EventName);
});
Table.set_function("TriggerLocalEvent", [&](const std::string& EventName) -> sol::table {
return Lua_TriggerLocalEvent(EventName);
});
Table.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent);
Table.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount);
Table.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected);
Table.set_function("GetPlayerName", &LuaAPI::MP::GetPlayerName);
Table.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle);
Table.set_function("GetPlayerVehicles", &LuaAPI::MP::GetPlayerVehicles);
Table.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage);
Table.set_function("GetPlayers", [&]() -> sol::table {
return Lua_GetPlayers();
});
Table.set_function("GetPlayerGuest", &LuaAPI::MP::GetPlayerGuest);
Table.set_function("DropPlayer", &LuaAPI::MP::DropPlayer);
Table.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table {
return Lua_GetPlayerIdentifiers(ID);
});
Table.set_function("Sleep", &LuaAPI::MP::Sleep);
Table.set_function("Set", &LuaAPI::MP::Set);
//Table.set_function("HttpsGET", &LuaAPI::MP::HttpsGET);
//Table.set_function("HttpsPOST", &LuaAPI::MP::HttpsPOST);
Table.create_named("Settings",
"Debug", 0,
"Private", 1,