Переглянути джерело

implement chat command security level system and grant chat command

Kolja Strohm 1 рік тому
батько
коміт
ec7fdc445a

+ 13 - 2
FactoryCraft/Chat.cpp

@@ -105,7 +105,7 @@ void Chat::removeObserver(int entityId)
     cs.unlock();
 }
 
-void Chat::charApi(Framework::StreamReader* zRequest,
+void Chat::chatApi(Framework::StreamReader* zRequest,
     Entity* zSource,
     NetworkMessage* zResponse)
 {
@@ -122,7 +122,13 @@ void Chat::charApi(Framework::StreamReader* zRequest,
             buffer[len] = 0;
             if (buffer[0] == '/')
             {
-                commandExecutor->execute(buffer, zSource);
+                if (!commandExecutor->execute(buffer, zSource))
+                {
+                    sendMessageTo("Unknown kommand. Use /help to get "
+                                  "information about all known commands.",
+                        zSource,
+                        CHANNEL_ERROR);
+                }
             }
             else
             {
@@ -217,6 +223,11 @@ void Chat::broadcastMessage(Framework::Text message, Framework::Text channel)
 void Chat::sendMessageTo(
     Framework::Text message, Entity* zTarget, Framework::Text channel)
 {
+    if (!zTarget)
+    {
+        std::cout << message << "\n";
+        return;
+    }
     Player* p = dynamic_cast<Player*>(zTarget);
     if (p)
     {

+ 1 - 1
FactoryCraft/Chat.h

@@ -25,7 +25,7 @@ public:
 
     void addObserver(int entityId);
     void removeObserver(int entityId);
-    void charApi(Framework::StreamReader* zRequest,
+    void chatApi(Framework::StreamReader* zRequest,
         Entity* zSource,
         NetworkMessage* zResponse);
     void broadcastMessage(Framework::Text message, Framework::Text channel);

+ 40 - 1
FactoryCraft/ChatCommand.cpp

@@ -1,5 +1,8 @@
 #include "ChatCommand.h"
 
+#include "Game.h"
+#include "Player.h"
+
 ChatCommand::ChatCommand(
     Framework::Text name, Framework::Text description, int securityLevel)
     : Framework::ReferenceCounter(),
@@ -55,7 +58,8 @@ Framework::Text ChatCommand::getHelp() const
     return result;
 }
 
-int ChatCommand::getSecurityLevel() const
+int ChatCommand::getSecurityLevel(
+    Framework::RCArray<Framework::Text> params) const
 {
     return securityLevel;
 }
@@ -91,4 +95,39 @@ Framework::Text ChatCommandParameter::getDescription() const
 bool ChatCommandParameter::isOptional() const
 {
     return optional;
+}
+
+PlayerNameParameter::PlayerNameParameter()
+    : ChatCommandParameter(
+        "player", "The name of the player (has to be online)", 0)
+{}
+
+bool PlayerNameParameter::isLegalValue(Framework::Text value) const
+{
+    return Game::INSTANCE->zPlayerByName(value) != 0;
+}
+
+Framework::Text PlayerNameParameter::getDefaultValue(Entity* zActor) const
+{
+    Player* p = dynamic_cast<Player*>(zActor);
+    if (p) return p->getName();
+    return "";
+}
+
+IntegerParameter::IntegerParameter(Framework::Text name,
+    Framework::Text description,
+    bool optional,
+    std::function<int(Entity* zEntity)> calculateDefault)
+    : ChatCommandParameter(name, description, optional),
+      calculateDefault(calculateDefault)
+{}
+
+bool IntegerParameter::isLegalValue(Framework::Text value) const
+{
+    return Text((int)value).istGleich(value);
+}
+
+Framework::Text IntegerParameter::getDefaultValue(Entity* zActor) const
+{
+    return Text(calculateDefault(zActor));
 }

+ 26 - 1
FactoryCraft/ChatCommand.h

@@ -28,7 +28,8 @@ public:
     const Framework::RCArray<ChatCommandParameter>& getParams() const;
     Framework::Text getName() const;
     Framework::Text getHelp() const;
-    int getSecurityLevel() const;
+    virtual int getSecurityLevel(
+        Framework::RCArray<Framework::Text> params) const;
 };
 
 class ChatCommandParameter : public virtual Framework::ReferenceCounter
@@ -47,4 +48,28 @@ public:
     Framework::Text getName() const;
     Framework::Text getDescription() const;
     bool isOptional() const;
+};
+
+class PlayerNameParameter : public ChatCommandParameter
+{
+public:
+    PlayerNameParameter();
+
+    bool isLegalValue(Framework::Text value) const override;
+    Framework::Text getDefaultValue(Entity* zActor) const override;
+};
+
+class IntegerParameter : public ChatCommandParameter
+{
+private:
+    std::function<int(Entity* zEntity)> calculateDefault;
+
+public:
+    IntegerParameter(Framework::Text name,
+        Framework::Text description,
+        bool optional,
+        std::function<int(Entity* zEntity)> calculateDefault);
+
+    bool isLegalValue(Framework::Text value) const override;
+    Framework::Text getDefaultValue(Entity* zActor) const override;
 };

+ 54 - 24
FactoryCraft/ChatCommandExecutor.cpp

@@ -2,12 +2,14 @@
 
 #include "Game.h"
 #include "SaveCommand.h"
+#include "GrantCommand.h"
 
 ChatCommandExecutor::ChatCommandExecutor()
     : ReferenceCounter()
 {
     knownCommands.add(new SaveCommand());
-}
+    knownCommands.add(new CrantCommand());
+} 
 
 bool ChatCommandExecutor::execute(Framework::Text line, Entity* zActor)
 {
@@ -22,7 +24,6 @@ bool ChatCommandExecutor::execute(Framework::Text line, Entity* zActor)
                 {
                     continue;
                 }
-                // TODO: check security level
                 Framework::RCArray<Framework::Text> params;
                 int start = command->getName().getLength() + 2;
                 bool escaped = 0;
@@ -51,22 +52,49 @@ bool ChatCommandExecutor::execute(Framework::Text line, Entity* zActor)
                         escaped = !escaped;
                     }
                 }
+                if (start < line.getLength())
+                {
+                    if (line.hatAt(start, "'")
+                        && line.hatAt(line.getLength() - 1, "'"))
+                    {
+                        params.add(
+                            line.getTeilText(start + 1, line.getLength() - 1));
+                    }
+                    else
+                    {
+                        params.add(line.getTeilText(start, line.getLength()));
+                    }
+                }
                 int index = 0;
                 for (ChatCommandParameter* param : command->getParams())
                 {
-                    if (params.getEintragAnzahl() > index &&  param->isLegalValue(*params.z(index)))
+                    if (params.getEintragAnzahl() > index
+                        && param->isLegalValue(*params.z(index)))
                     {
                         index++;
                     }
                     else
                     {
+                        bool isError = 0;
                         if (param->isOptional() && zActor)
                         {
-                            params.add(new Framework::Text(
-                                           param->getDefaultValue(zActor)),
-                                index++);
+                            Framework::Text defaultValue
+                                = param->getDefaultValue(zActor);
+                            if (!param->isLegalValue(defaultValue))
+                            {
+                                isError = 1;
+                            }
+                            else
+                            {
+                                params.add(
+                                    new Framework::Text(defaultValue), index++);
+                            }
                         }
                         else
+                        {
+                            isError = 1;
+                        }
+                        if (isError)
                         {
                             Framework::Text error
                                 = "Illegal parameter at position ";
@@ -82,15 +110,8 @@ bool ChatCommandExecutor::execute(Framework::Text line, Entity* zActor)
                             }
                             error += "\n";
                             error += command->getHelp();
-                            if (zActor)
-                            {
-                                Game::INSTANCE->zChat()->sendMessageTo(
-                                    error, zActor, Chat::CHANNEL_ERROR);
-                            }
-                            else
-                            {
-                                std::cout << error << std::endl;
-                            }
+                            Game::INSTANCE->zChat()->sendMessageTo(
+                                error, zActor, Chat::CHANNEL_ERROR);
                             return true;
                         }
                     }
@@ -102,15 +123,24 @@ bool ChatCommandExecutor::execute(Framework::Text line, Entity* zActor)
                     error += *params.z(index);
                     error += "\n";
                     error += command->getHelp();
-                    if (zActor)
-                    {
-                        Game::INSTANCE->zChat()->sendMessageTo(
-                            error, zActor, Chat::CHANNEL_ERROR);
-                    }
-                    else
-                    {
-                        std::cout << error << std::endl;
-                    }
+                    Game::INSTANCE->zChat()->sendMessageTo(
+                        error, zActor, Chat::CHANNEL_ERROR);
+                    return true;
+                }
+                if (zActor
+                    && command->getSecurityLevel(params)
+                           > zActor->getChatSecurityLevel())
+                {
+                    Framework::Text error
+                        = "This command requires a security level of at least ";
+                    error += command->getSecurityLevel(params);
+                    error += ". You have currently a security level of ";
+                    error += zActor->getChatSecurityLevel();
+                    error += ". Ask someone with the required security lavel "
+                             "to grant you the same level.";
+                    Game::INSTANCE->zChat()->sendMessageTo(
+                        error, zActor, Chat::CHANNEL_ERROR);
+                    return true;
                 }
                 command->execute(params, zActor);
                 return true;

+ 2 - 0
FactoryCraft/ChatMessage.cpp

@@ -18,6 +18,7 @@ ChatMessage::ChatMessage(Framework::Text message,
 ChatMessage::ChatMessage(Framework::StreamReader* zReader)
     : ReferenceCounter()
 {
+    zReader->lese((char*)&time, 8);
     short len;
     zReader->lese((char*)&len, 2);
     char* buffer = new char[len + 1];
@@ -52,6 +53,7 @@ Framework::Text ChatMessage::getTargetPlayerName() const
 
 void ChatMessage::writeTo(Framework::StreamWriter* zWriter) const
 {
+    zWriter->schreibe((char*)&time, 8);
     short mLen = (short)message.getLength();
     zWriter->schreibe((char*)&mLen, 2);
     zWriter->schreibe(message.getText(), mLen);

+ 11 - 0
FactoryCraft/Entity.cpp

@@ -171,6 +171,7 @@ ActionTarget* ActionTarget::load(Framework::StreamReader* zReader)
 Entity::Entity(
     int typeId, Framework::Vec3<float> location, int dimensionId, int entityId)
     : Inventory(location, true),
+      chatSecurityLevel(0),
       speed(0, 0, 0),
       faceDir(1, 0, 0),
       target(0),
@@ -550,6 +551,11 @@ void Entity::onFall(float collisionSpeed)
     }
 }
 
+void Entity::setChatSecurityLevel(int level)
+{
+    chatSecurityLevel = level;
+}
+
 void Entity::setPosition(Framework::Vec3<float> pos)
 {
     location = pos;
@@ -706,4 +712,9 @@ float Entity::getMaxSpeed() const
 bool Entity::isMoving() const
 {
     return movements.getEintragAnzahl() > 0;
+}
+
+int Entity::getChatSecurityLevel() const
+{
+    return chatSecurityLevel;
 }

+ 3 - 0
FactoryCraft/Entity.h

@@ -53,6 +53,7 @@ private:
     float hunger;
     float currentHP;
     float thirst;
+    int chatSecurityLevel;
 
 protected:
     float maxHP;
@@ -100,6 +101,7 @@ public:
     virtual void onTargetChange();
 
     virtual void onFall(float collisionSpeed);
+    void setChatSecurityLevel(int level);
     void setPosition(Framework::Vec3<float> pos);
     void setHP(float hp);
     void setStamina(float stamina);
@@ -126,6 +128,7 @@ public:
     virtual ModelInfo getSpecialModel() const;
     float getMaxSpeed() const;
     bool isMoving() const;
+    int getChatSecurityLevel() const;
 
     friend Effect;
     friend EntityType;

+ 2 - 0
FactoryCraft/EntityType.cpp

@@ -23,6 +23,7 @@ void EntityType::loadSuperEntity(
     zReader->lese((char*)&zEntity->hunger, 4);
     zReader->lese((char*)&zEntity->maxHunger, 4);
     zReader->lese((char*)&zEntity->thirst, 4);
+    zReader->lese((char*)&zEntity->chatSecurityLevel, 4);
     zReader->lese((char*)&zEntity->maxThirst, 4);
     zReader->lese((char*)&zEntity->speed.x, 4);
     zReader->lese((char*)&zEntity->speed.y, 4);
@@ -61,6 +62,7 @@ void EntityType::saveSuperEntity(
     zWriter->schreibe((char*)&zEntity->hunger, 4);
     zWriter->schreibe((char*)&zEntity->maxHunger, 4);
     zWriter->schreibe((char*)&zEntity->thirst, 4);
+    zWriter->schreibe((char*)&zEntity->chatSecurityLevel, 4);
     zWriter->schreibe((char*)&zEntity->maxThirst, 4);
     zWriter->schreibe((char*)&zEntity->speed.x, 4);
     zWriter->schreibe((char*)&zEntity->speed.y, 4);

+ 2 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -126,6 +126,7 @@
     <ClInclude Include="Game.h" />
     <ClInclude Include="GeneratedStructure.h" />
     <ClInclude Include="GenerationTemplate.h" />
+    <ClInclude Include="GrantCommand.h" />
     <ClInclude Include="GrasslandBiom.h" />
     <ClInclude Include="Grass.h" />
     <ClInclude Include="Chat.h" />
@@ -200,6 +201,7 @@
     <ClCompile Include="Game.cpp" />
     <ClCompile Include="GeneratedStructure.cpp" />
     <ClCompile Include="GenerationTemplate.cpp" />
+    <ClCompile Include="GrantCommand.cpp" />
     <ClCompile Include="GrasslandBiom.cpp" />
     <ClCompile Include="Grass.cpp" />
     <ClCompile Include="Hoe.cpp" />

+ 6 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -306,6 +306,9 @@
     <ClInclude Include="ChatObserver.h">
       <Filter>chat</Filter>
     </ClInclude>
+    <ClInclude Include="GrantCommand.h">
+      <Filter>chat\commands</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -518,5 +521,8 @@
     <ClCompile Include="ChatMessage.cpp">
       <Filter>chat</Filter>
     </ClCompile>
+    <ClCompile Include="GrantCommand.cpp">
+      <Filter>chat\commands</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 19 - 1
FactoryCraft/Game.cpp

@@ -298,7 +298,7 @@ Game::Game(Framework::Text name, Framework::Text worldsDir)
       nextEntityId(0),
       generator(0),
       loader(0),
-      chat(new Chat()),
+      chat(0),
       totalTickTime(0),
       tickCounter(0)
 {
@@ -334,6 +334,7 @@ void Game::initialize()
     generator = new WorldGenerator(seed);
     loader = new WorldLoader();
     recipies.loadRecipies("data/recipies");
+    chat = new Chat();
 }
 
 void Game::thread()
@@ -555,6 +556,11 @@ void Game::api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin)
             response->setMessage(msg, msgSize);
             break;
         }
+    case 6:
+        { // chat message
+            short mLen = 0;
+            chat->chatApi(zRequest, zOrigin->zEntity() , response);
+        }
     default:
         std::cout << "received unknown api request in game with type "
                   << (int)type << "\n";
@@ -961,4 +967,16 @@ TickOrganizer* Game::zTickOrganizer() const
 Chat* Game::zChat() const
 {
     return chat;
+}
+
+Player* Game::zPlayerByName(const char* name) const
+{
+    for (GameClient* client : *clients)
+    {
+        if (strcmp(client->zEntity()->getName(), name) == 0)
+        {
+            return client->zEntity();
+        }
+    }
+    return 0;
 }

+ 1 - 0
FactoryCraft/Game.h

@@ -136,6 +136,7 @@ public:
     void doLater(std::function<void()> action);
     TickOrganizer* zTickOrganizer() const;
     Chat* zChat() const;
+    Player* zPlayerByName(const char* name) const;
 
     static Game* INSTANCE;
     static Critical INSTANCE_CS;

+ 39 - 0
FactoryCraft/GrantCommand.cpp

@@ -0,0 +1,39 @@
+#include "GrantCommand.h"
+
+#include "Game.h"
+
+CrantCommand::CrantCommand()
+    : ChatCommand("grant", "Grants a player a permission", 0)
+{
+    addParam(new PlayerNameParameter());
+    addParam(new IntegerParameter("securityLavel",
+        "The security level to grant",
+        true,
+        [](Entity* actor) {
+            if (actor) return actor->getChatSecurityLevel();
+            return INT32_MAX;
+        }));
+}
+
+void CrantCommand::execute(
+    Framework::RCArray<Framework::Text> params, Entity* zActor) const
+{
+    int securityLevel = (int)*params.z(1);
+    Entity* zTarget = Game::INSTANCE->zPlayerByName(*params.z(0));
+    if (zTarget)
+    {
+        zTarget->setChatSecurityLevel(securityLevel);
+        Text message = "The security level of player ";
+        message += *params.z(0);
+        message += " is now set to ";
+        message += securityLevel;
+        Game::INSTANCE->zChat()->sendMessageTo(
+            message, zActor, Chat::CHANNEL_INFO);
+    }
+}
+
+int CrantCommand::getSecurityLevel(
+    Framework::RCArray<Framework::Text> params) const
+{
+    return (int)*params.z(1);
+}

+ 13 - 0
FactoryCraft/GrantCommand.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include "ChatCommand.h"
+
+class CrantCommand : public ChatCommand
+{
+public:
+    CrantCommand();
+    void execute(Framework::RCArray<Framework::Text> params,
+        Entity* zActor) const override;
+    int getSecurityLevel(
+        Framework::RCArray<Framework::Text> params) const override;
+};

+ 2 - 2
FactoryCraft/SaveCommand.h

@@ -6,6 +6,6 @@ class SaveCommand : public ChatCommand
 {
 public:
     SaveCommand();
-    virtual void execute(
-        Framework::RCArray<Framework::Text> params, Entity* zActor) const override;
+    void execute(Framework::RCArray<Framework::Text> params,
+        Entity* zActor) const override;
 };