Skip to content

Commit

Permalink
[SRV] feat(ScriptEngine): add Spawn Window related functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Insineer committed Sep 21, 2019
1 parent 37dcc94 commit 4d9c045
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 27 deletions.
4 changes: 4 additions & 0 deletions OSS13 Server/Include/IScriptEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

#include <string>

#include <Shared/Network/Protocol/ServerToClient/WorldInfo.h>

class Object;
class Map;
class Player;

class IScriptEngine {
public:
virtual Object *CreateObjectByKey(const std::string& typeKey) = 0;
virtual Object *CreateObject(const std::string& module, const std::string& type = "") = 0;
virtual std::vector<network::protocol::ObjectType *> GetTypesInfo(const std::string &searchString) = 0;

virtual void FillMap(Map *map) = 0;
virtual void OnPlayerJoined(Player *player) = 0;
Expand Down
40 changes: 22 additions & 18 deletions OSS13 Server/Sources/Network/NetworkController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,17 @@ void NetworkController::working() {

bool NetworkController::parsePacket(sf::Packet &packet, sptr<Connection> &connection) {
uf::OutputArchive ar(packet);
auto p = ar.UnpackSerializable();
auto serializable = ar.UnpackSerializable();
auto generalCommand = uptr<network::protocol::Command>(dynamic_cast<network::protocol::Command *>(serializable.release()));

if (auto *command = dynamic_cast<client::AuthorizationCommand *>(p.get())) {
if (!generalCommand) {
LOGE << "Unknown serializable (id is 0x" << std::hex << serializable->Id() << ") is received from "
<< (connection->player ? connection->player->GetCKey() : "unknown client")
<< "!";
return false;
}

if (auto *command = dynamic_cast<client::AuthorizationCommand *>(generalCommand.get())) {
bool secondConnection = false;
for (auto &connection : connections) {
if (connection->player && connection->player->GetCKey() == command->login) {
Expand All @@ -114,15 +122,15 @@ bool NetworkController::parsePacket(sf::Packet &packet, sptr<Connection> &connec
return true;
}

if (auto *command = dynamic_cast<client::RegistrationCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::RegistrationCommand *>(generalCommand.get())) {
if (GServer->Registration(command->login, command->password))
connection->commandsToClient.Push(new network::protocol::server::RegistrationSuccessCommand());
else
connection->commandsToClient.Push(new network::protocol::server::RegistrationFailedCommand());
return true;
}

if (auto *command = dynamic_cast<client::JoinGameCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::JoinGameCommand *>(generalCommand.get())) {
if (connection->player) {
if (GServer->JoinGame(connection->player)) {
connection->commandsToClient.Push(new network::protocol::server::GameJoinSuccessCommand());
Expand All @@ -133,68 +141,64 @@ bool NetworkController::parsePacket(sf::Packet &packet, sptr<Connection> &connec
return true;
}

if (auto *command = dynamic_cast<client::MoveCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::MoveCommand *>(generalCommand.get())) {
if (connection->player)
connection->player->Move(uf::Direction(command->direction));
return true;
}

if (auto *command = dynamic_cast<client::MoveZCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::MoveZCommand *>(generalCommand.get())) {
if (connection->player)
connection->player->MoveZ(command->up);
return true;
}

if (auto *command = dynamic_cast<client::ClickObjectCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::ClickObjectCommand *>(generalCommand.get())) {
if (connection->player)
connection->player->ClickObject(command->id);
return true;
}

if (auto *command = dynamic_cast<client::ClickControlUICommand *>(p.get())) {
if (auto *command = dynamic_cast<client::ClickControlUICommand *>(generalCommand.get())) {
if (connection->player)
connection->player->ClickControlUI(command->id);
return true;
}

if (auto *command = dynamic_cast<client::SendChatMessageCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::SendChatMessageCommand *>(generalCommand.get())) {
if (connection->player)
connection->player->ChatMessage(command->message);
return true;
}

if (auto *command = dynamic_cast<client::DisconnectionCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::DisconnectionCommand *>(generalCommand.get())) {
if (connection->player)
LOGI << "Client " << connection->player->GetCKey() << " disconnected";
return false;
}

if (auto *command = dynamic_cast<client::UIInputCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::UIInputCommand *>(generalCommand.get())) {
if (connection->player) {
connection->player->UIInput(std::move(command->data));
}
return true;
}

if (auto *command = dynamic_cast<client::UITriggerCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::UITriggerCommand *>(generalCommand.get())) {
if (connection->player) {
connection->player->UITrigger(command->window, command->trigger);
}
return true;
}

if (auto *command = dynamic_cast<client::CallVerbCommand *>(p.get())) {
if (auto *command = dynamic_cast<client::CallVerbCommand *>(generalCommand.get())) {
if (connection->player) {
connection->player->CallVerb(command->verb);
}
return true;
}

if (connection->player)
LOGE << "Unknown Command is received from " << connection->player->GetCKey();
else
LOGE << "Unknown Command is received from unregistered client";

connection->player->AddSyncCommandFromClient(std::forward<uptr<network::protocol::Command>>(generalCommand));
return true;
}

Expand Down
48 changes: 48 additions & 0 deletions OSS13 Server/Sources/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <plog/Log.h>

#include <IGame.h>
#include <IScriptEngine.h>
#include <Chat.h>
#include <Network/Connection.hpp>
#include <World/World.hpp>
Expand All @@ -14,13 +15,15 @@
#include <ClientUI/WelcomeWindowSink.h>

#include <Shared/ErrorHandling.h>
#include <Shared/Network/Protocol/ClientToServer/Commands.h>

class Server;

using namespace std::string_literals;

Player::Player(std::string ckey) : ckey(ckey) {
control = nullptr;
AddVerb("spawn", &Player::OpenSpawnWindow);
}

void Player::SetConnection(sptr<Connection> &connection) {
Expand Down Expand Up @@ -70,6 +73,24 @@ void Player::UITrigger(const std::string &window, const std::string &trigger) {
iter->second->OnTrigger(trigger);
}

void Player::SpawnWindowSearchCommand(const std::string &searchBuffer) {
auto types = GGame->GetScriptEngine()->GetTypesInfo(searchBuffer);
auto command = std::make_unique<network::protocol::server::UpdateSpawnWindowCommand>();

for (auto type: types)
command->types.push_back(*type);

AddCommandToClient(command.release());
}

void Player::SpawnWindowSpawnCommand(const std::string &typeKey) {
if (control) {
auto *obj = GGame->GetScriptEngine()->CreateObjectByKey(typeKey);
if (obj)
obj->SetTile(control->GetOwner()->GetTile());
}
}

void Player::updateUISinks(std::chrono::microseconds timeElapsed) {
for (auto iter = uiSinks.begin(); iter != uiSinks.end();) {
auto *sink = iter->second.get();
Expand All @@ -82,6 +103,25 @@ void Player::updateUISinks(std::chrono::microseconds timeElapsed) {
}

void Player::Update(std::chrono::microseconds timeElapsed) {
while (!syncCommands.Empty()) {
auto generalCommand = syncCommands.Pop();

using namespace network::protocol;

if (auto *command = dynamic_cast<client::SpawnWindowSearchCommand *>(generalCommand.get())) {
SpawnWindowSearchCommand(command->searchBuffer);
continue;
}

if (auto *command = dynamic_cast<client::SpawnWindowSpawnCommand *>(generalCommand.get())) {
SpawnWindowSpawnCommand(command->typeKey);
continue;
}

LOGE << "Unknown command (ser id is 0x" << std::hex << generalCommand->Id() << ") was not processed as synced! "
<< "Player: " << ckey;
}

while (!actions.Empty()) {
PlayerCommand *temp = actions.Pop();
if (temp) {
Expand Down Expand Up @@ -154,6 +194,10 @@ void Player::SendGraphicsUpdates(std::chrono::microseconds timeElapsed) {
camera->UpdateView(timeElapsed);
}

void Player::OpenSpawnWindow() {
AddCommandToClient(new network::protocol::server::OpenSpawnWindowCommand());
}

void Player::Suspend() {
camera->Suspend();
}
Expand Down Expand Up @@ -183,3 +227,7 @@ void Player::AddCommandToClient(network::protocol::Command *command) {
if (sptr<Connection> connect = connection.lock())
connect->commandsToClient.Push(command);
}

void Player::AddSyncCommandFromClient(uptr<network::protocol::Command> &&command) {
syncCommands.Push(std::forward<uptr<network::protocol::Command>>(command));
}
6 changes: 6 additions & 0 deletions OSS13 Server/Sources/Player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ friend Server;

void UIInput(uptr<network::protocol::UIData> &&data);
void UITrigger(const std::string &window, const std::string &trigger);
void SpawnWindowSearchCommand(const std::string &searchBuffer);
void SpawnWindowSpawnCommand(const std::string &typeKey);
void CallVerb(const std::string &verb);
///

Expand All @@ -53,6 +55,7 @@ friend Server;
window->Initialize();
uiSinks[window->Id()] = std::move(window);
}
void OpenSpawnWindow();

const std::string &GetCKey() const { return ckey; }

Expand All @@ -67,6 +70,8 @@ friend Server;

void AddCommandToClient(network::protocol::Command *);

void AddSyncCommandFromClient(uptr<network::protocol::Command> &&command);

private:
void updateUISinks(std::chrono::microseconds timeElapsed);

Expand All @@ -78,6 +83,7 @@ friend Server;

wptr<Connection> connection;
uf::ThreadSafeQueue<PlayerCommand *> actions;
uf::ThreadSafeQueue<uptr<network::protocol::Command>> syncCommands;

bool atmosOverlayToggled;

Expand Down
20 changes: 16 additions & 4 deletions OSS13 Server/Sources/ScriptEngine/ObjectType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@

#include <plog/Log.h>

#include <Server.hpp>

ObjectType::ObjectType(py::handle cls) :
cls(cls)
{
name = py::str(cls.attr("__name__"));
typeKey = std::string(py::str(cls.attr("__module__"))) + "." + name;
typeName = py::str(cls.attr("__name__"));
typeKey = std::string(py::str(cls.attr("__module__"))) + "." + typeName;
module = py::module::import("inspect").attr("getmodule")(cls);

canBeSpawned = py::bool_(cls.attr("canBeSpawned"));
name = py::str(cls.attr("defName"));
std::string spriteKey = py::str(cls.attr("defSprite"));
if (spriteKey.empty())
sprite = 0;
else
sprite = GServer->RM()->GetIconInfo(spriteKey).id;
description = py::str(cls.attr("defDescription"));
}

const std::string &ObjectType::GetName() { return name; }
const std::string &ObjectType::GetTypeKey() { return typeKey; }
bool ObjectType::CanBeSpawned() const { return canBeSpawned; }
const std::string &ObjectType::GetName() const { return typeName; }
const std::string &ObjectType::GetTypeKey() const { return typeKey; }
py::handle ObjectType::GetHandle() { return cls; }
py::handle ObjectType::GetModule() { return module; }
12 changes: 7 additions & 5 deletions OSS13 Server/Sources/ScriptEngine/ObjectType.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
#include <Python.h>
#include <pybind11/embed.h>

#include <Shared/Network/Protocol/ServerToClient/WorldInfo.h>

namespace py = pybind11;

class ObjectType {
class ObjectType : public network::protocol::ObjectType {
public:
explicit ObjectType(py::handle cls);

const std::string &GetName();
const std::string &GetTypeKey();
bool CanBeSpawned() const;
const std::string &GetName() const;
const std::string &GetTypeKey() const;
py::handle GetHandle();
py::handle GetModule();

private:
std::string name;
std::string typeKey;
bool canBeSpawned;
py::handle cls;
py::handle module;
};
50 changes: 50 additions & 0 deletions OSS13 Server/Sources/ScriptEngine/ScriptEngine.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ScriptEngine.h"

#include <cctype>
#include <algorithm>
#include <filesystem>

Expand Down Expand Up @@ -78,6 +79,15 @@ ScriptEngine::~ScriptEngine() {
py::finalize_interpreter();
}

Object *ScriptEngine::CreateObjectByKey(const std::string& typeKey) {
try {
return objectTypes[typeKey]->GetHandle()().cast<Object *>();
} catch (const std::exception &e) {
MANAGE_EXCEPTION_WITH_MSG(e, "Failed to create script object (TypeKey: \"" + typeKey + "\")\n");
return nullptr;
}
}

Object *ScriptEngine::CreateObject(const std::string& m, const std::string& type) {
try {
return GetObjectType(m, type).GetHandle()().cast<Object *>();
Expand All @@ -87,6 +97,46 @@ Object *ScriptEngine::CreateObject(const std::string& m, const std::string& type
}
}

std::vector<network::protocol::ObjectType *> GetSelectedTypesInfo(
const std::map<ObjectTypeId, std::unique_ptr<ObjectType>> &objectTypes,
const std::function<bool(const ObjectType &type)> &selector)
{
std::vector<network::protocol::ObjectType *> result;

for (auto &[key, type] : objectTypes) {
if (selector(*type) && type->CanBeSpawned())
result.push_back(type.get());
}

return result;
}

bool isStringIncludeCaseInsensitive(const std::string &string, const std::string &pattern)
{
auto it = std::search(
string.begin(), string.end(),
pattern.begin(), pattern.end(),
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }
);
return (it != string.end());
}

std::vector<network::protocol::ObjectType *> ScriptEngine::GetTypesInfo(const std::string &searchString) {
std::function<bool(const ObjectType &type)> selector;

if (searchString.empty()) {
selector = [&searchString](const ObjectType &type) { return true; };
} else {
selector = [&searchString](const ObjectType &type) {
if (isStringIncludeCaseInsensitive(type.GetTypeKey(), searchString))
return true;
return false;
};
}

return GetSelectedTypesInfo(objectTypes, selector);
}

void ScriptEngine::FillMap(Map *map) {
try {
py::module::import("Engine.Detail.HooksRawArgs").attr("rawFillMap")(map);
Expand Down
Loading

0 comments on commit 4d9c045

Please sign in to comment.