Browse Source

make entities targetable by pointing at them

Kolja Strohm 1 month ago
parent
commit
874e3f42cc

+ 2 - 2
FactoryCraft/Animal.cpp

@@ -73,7 +73,7 @@ Entity* AnimalEntityType::createEntity(
     Framework::Vec3<float> position, int dimensionId, int entityId) const
 {
     Animal* result = new Animal(getId(), position, dimensionId, entityId);
-    result->setAI(Game::INSTANCE->zTypeRegistry()->fromJson<AnimalAI>(ai));
+    //result->setAI(Game::INSTANCE->zTypeRegistry()->fromJson<AnimalAI>(ai));
     return result;
 }
 
@@ -103,7 +103,7 @@ const char* AnimalEntityTypeFactory::getTypeToken() const
 JSONObjectValidationBuilder* AnimalEntityTypeFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    return builder
+    return EntityTypeFactoryBase::addToValidator(builder)
         /* TODO: write AnimalAI factories
         ->withRequiredAttribute(
         "ai", Game::INSTANCE->zTypeRegistry()->getValidator<AnimalAI>())*/

+ 23 - 7
FactoryCraft/Chunk.cpp

@@ -466,7 +466,8 @@ void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
         if (observer->getEntityId() == zEntity->getId()) return;
     }
     int id = zEntity->getId();
-    observers.add(new InformationObserver(id));
+    InformationObserver* observer = new InformationObserver(id);
+    observers.add(observer);
     laterHandler.addTodo([this, id]() {
         Framework::InMemoryBuffer buffer;
         buffer.schreibe("\4", 1);
@@ -495,6 +496,15 @@ void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
         else
             msg->release();
     });
+    for (Entity* entity : entitiesInChunk)
+    {
+        NetworkMessage* msg = new NetworkMessage();
+        msg->addEntityMessage(entity);
+        if (!msg->isEmpty())
+        {
+            observer->sendMessage(msg);
+        }
+    }
 }
 
 void Chunk::removeObserver(Entity* zEntity)
@@ -504,6 +514,15 @@ void Chunk::removeObserver(Entity* zEntity)
     {
         if (observer->getEntityId() == zEntity->getId())
         {
+            for (Entity* entity : entitiesInChunk)
+            {
+                NetworkMessage* msg = new NetworkMessage();
+                msg->removeEntityMessage(entity);
+                if (!msg->isEmpty())
+                {
+                    observer->sendMessage(msg);
+                }
+            }
             observers.remove(index);
             return;
         }
@@ -1111,12 +1130,9 @@ void Chunk::save(Framework::StreamWriter* zWriter,
     zWriter->schreibe((char*)&len, 2);
     for (Entity* entity : entitiesInChunk)
     {
-        if (!entity->isRemoved())
-        {
-            int type = entity->zType()->getId();
-            zWriter->schreibe((char*)&type, 4);
-            entity->zType()->saveEntity(entity, zWriter);
-        }
+        int type = entity->zType()->getId();
+        zWriter->schreibe((char*)&type, 4);
+        entity->zType()->saveEntity(entity, zWriter);
         if (lastSavedEntityIds.getWertIndex(entity->getId()) < 0)
         {
             entity->getLastSavedChunkCenter().ifPresent(

+ 32 - 1
FactoryCraft/Dimension.cpp

@@ -516,6 +516,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
     DoLaterHandler laterHandler;
     if (chunk)
     {
+        chunkCs.unlock();
         Game::INSTANCE->zGenerator()->postprocessChunk(chunk);
         chunk->setAdded();
         for (Entity* entity : chunk->getEntitiesInChunk())
@@ -550,7 +551,10 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
         cs.unlock();
         Game::INSTANCE->zTickOrganizer()->addTickSource(chunk);
     }
-    chunkCs.unlock();
+    else
+    {
+        chunkCs.unlock();
+    }
     if (old)
     {
         old->onUnloaded();
@@ -704,6 +708,33 @@ void Dimension::removeOldChunks()
     structurCs.unlock();
 }
 
+Entity* Dimension::zTarget(Framework::Vec3<float> pos,
+    Vec3<float> direction,
+    float maxDistanceSq) const
+{
+    double minDist = 0;
+    Entity* closestEntity = 0;
+    entityCs.lock();
+    for (auto entity : *entities)
+    {
+        if (!entity->isRemoved()
+            && entity->getPosition().abstandSq(pos) <= maxDistanceSq)
+        {
+            double dist = entity->getHitDistance(pos, direction);
+            if (!isnan(dist))
+            {
+                if (!closestEntity || dist < minDist)
+                {
+                    closestEntity = entity;
+                    minDist = dist;
+                }
+            }
+        }
+    }
+    entityCs.unlock();
+    return closestEntity;
+}
+
 Entity* Dimension::zEntity(int id) const
 {
     entityCs.lock();

+ 3 - 0
FactoryCraft/Dimension.h

@@ -93,6 +93,9 @@ public:
     Chunk* zChunk(Framework::Punkt wPos) const;
     float getGravity() const;
     void removeOldChunks();
+    Entity* zTarget(Framework::Vec3<float> pos,
+        Framework::Vec3<float> direction,
+        float maxDistanceSq) const;
     Entity* zEntity(int id) const;
     Entity* zNearestEntity(
         Framework::Vec3<float> pos, std::function<bool(Entity*)> filter) const;

+ 127 - 6
FactoryCraft/Entity.cpp

@@ -1,5 +1,6 @@
 #include "Entity.h"
 
+#include <Mat4.h>
 #include <Text.h>
 
 #include "BlockType.h"
@@ -443,6 +444,8 @@ void Entity::calculateTarget(Framework::Vec3<float> basePos,
     int pz = (int)floor(headPosition.z);
     direction.normalize();
     Direction dir = BOTTOM;
+    bool found = false;
+    bool changed = false;
     while (true)
     {
         if (getDefaultBlock(
@@ -450,13 +453,10 @@ void Entity::calculateTarget(Framework::Vec3<float> basePos,
                     Framework::Vec3<int>{px, py, pz}, dimensionId, 0))
                 ->isInteractable(zItem))
         {
+            found = true;
             if (!target || !target->isBlock({px, py, pz}, dir))
             {
-                cs.lock();
-                delete target;
-                target = new ActionTarget({px, py, pz}, dir);
-                cs.unlock();
-                onTargetChange();
+                changed = true;
             }
             break;
         }
@@ -540,6 +540,29 @@ void Entity::calculateTarget(Framework::Vec3<float> basePos,
             }
         }
         if (target)
+        {
+            changed = true;
+        }
+        break;
+    }
+    float distSq = Framework::Vec3<float>((float)px, (float)py, (float)pz)
+                     .abstandSq(headPosition);
+    Entity* zte = Game::INSTANCE->zDimension(dimensionId)
+                      ->zTarget(headPosition, direction, distSq);
+    if (zte)
+    {
+        if (!target || !target->isEntity(zte->getId()))
+        {
+            cs.lock();
+            delete target;
+            target = new ActionTarget(zte->getId());
+            cs.unlock();
+            onTargetChange();
+        }
+    }
+    else if (changed)
+    {
+        if (target && !found)
         {
             cs.lock();
             delete target;
@@ -547,7 +570,14 @@ void Entity::calculateTarget(Framework::Vec3<float> basePos,
             cs.unlock();
             onTargetChange();
         }
-        break;
+        else
+        {
+            cs.lock();
+            delete target;
+            target = new ActionTarget({px, py, pz}, dir);
+            cs.unlock();
+            onTargetChange();
+        }
     }
 }
 
@@ -922,3 +952,94 @@ void Entity::setRemoved()
 {
     removed = true;
 }
+
+double Entity::getHitDistance(
+    Framework::Vec3<float> rayOrigin, Framework::Vec3<float> rayDirection) const
+{
+    Framework::Mat4<float> rotMat
+        = Framework::Mat4<float>::rotationX(-rotation.x)
+        * Framework::Mat4<float>::rotationY(-rotation.y)
+        * Framework::Mat4<float>::rotationZ(-rotation.z);
+    Framework::Vec3<float> rotatedRayOrigin = rotMat * rayOrigin;
+    Framework::Vec3<float> rotatedRayDirection = rotMat * rayDirection;
+    rotatedRayDirection.normalize();
+    if (rotatedRayDirection.x != 0)
+    {
+        float d;
+        if (rotatedRayDirection.x > 0)
+        {
+            float border = getPosition().x - boundingBox.x;
+            d = (border - rotatedRayOrigin.x) / rotatedRayDirection.x;
+        }
+        else if (rotatedRayDirection.x < 0)
+        {
+            float border = getPosition().x + boundingBox.x;
+            d = (border - rotatedRayOrigin.x) / rotatedRayDirection.x;
+        }
+        if (d > 0)
+        {
+            Framework::Vec3<float> hitPoint
+                = rotatedRayOrigin + rotatedRayDirection * d;
+            if (hitPoint.y >= getPosition().y - boundingBox.y
+                && hitPoint.y <= getPosition().y + boundingBox.y
+                && hitPoint.z >= getPosition().z - boundingBox.z
+                && hitPoint.z <= getPosition().z + boundingBox.z)
+            {
+                return d;
+            }
+        }
+    }
+    if (rotatedRayDirection.y != 0)
+    {
+        float d;
+        if (rotatedRayDirection.y > 0)
+        {
+            float border = getPosition().y - boundingBox.y;
+            d = (border - rotatedRayOrigin.y) / rotatedRayDirection.y;
+        }
+        else if (rotatedRayDirection.y < 0)
+        {
+            float border = getPosition().y + boundingBox.y;
+            d = (border - rotatedRayOrigin.y) / rotatedRayDirection.y;
+        }
+        if (d > 0)
+        {
+            Framework::Vec3<float> hitPoint
+                = rotatedRayOrigin + rotatedRayDirection * d;
+            if (hitPoint.x >= getPosition().x - boundingBox.x
+                && hitPoint.x <= getPosition().x + boundingBox.x
+                && hitPoint.z >= getPosition().z - boundingBox.z
+                && hitPoint.z <= getPosition().z + boundingBox.z)
+            {
+                return d;
+            }
+        }
+    }
+    if (rotatedRayDirection.z != 0)
+    {
+        float d;
+        if (rotatedRayDirection.z > 0)
+        {
+            float border = getPosition().z - boundingBox.z;
+            d = (border - rotatedRayOrigin.z) / rotatedRayDirection.z;
+        }
+        else if (rotatedRayDirection.z < 0)
+        {
+            float border = getPosition().z + boundingBox.z;
+            d = (border - rotatedRayOrigin.z) / rotatedRayDirection.z;
+        }
+        if (d > 0)
+        {
+            Framework::Vec3<float> hitPoint
+                = rotatedRayOrigin + rotatedRayDirection * d;
+            if (hitPoint.x >= getPosition().x - boundingBox.x
+                && hitPoint.x <= getPosition().x + boundingBox.x
+                && hitPoint.y >= getPosition().y - boundingBox.y
+                && hitPoint.y <= getPosition().y + boundingBox.y)
+            {
+                return d;
+            }
+        }
+    }
+    return NAN;
+}

+ 4 - 0
FactoryCraft/Entity.h

@@ -82,6 +82,8 @@ protected:
     Framework::ZeitMesser time;
     Framework::Array<MovementFrame> movements;
     Framework::Critical cs;
+    Framework::Vec3<float> boundingBox;
+    Framework::Vec3<float> rotation;
 
     virtual void onDeath(
         Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill);
@@ -143,6 +145,8 @@ public:
     Framework::Maybe<Framework::Punkt> getLastSavedChunkCenter() const;
     void setLastSavedChunkCenter(Framework::Punkt pos);
     void setRemoved();
+    double getHitDistance(Framework::Vec3<float> rayOrigin,
+        Framework::Vec3<float> rayDirection) const;
 
     friend EntityType;
 };

+ 1 - 1
FactoryCraft/EntityGenerator.cpp

@@ -43,7 +43,7 @@ void EntityGenerator::initialize(JExpressionMemory* zMemory)
 bool EntityGenerator::isGenerated(int x, int y, int z, int dimensionId)
 {
     return (!noise
-               || noise->getNoise((double)x, (double)y, (double)z) <= threshold)
+               || noise->getNoise((double)x, (double)y, (double)z) >= threshold)
         && condition->getValue();
 }
 

+ 4 - 1
FactoryCraft/EntityType.cpp

@@ -95,7 +95,10 @@ void EntityType::saveSuperEntity(
     }
 }
 
-void EntityType::createSuperEntity(Entity* zEntity) const {}
+void EntityType::createSuperEntity(Entity* zEntity) const
+{
+    zEntity->boundingBox = model->getBoundingBox();
+}
 
 bool EntityType::initialize(Game* zGame)
 {

+ 8 - 8
FactoryCraft/Game.cpp

@@ -233,22 +233,22 @@ void Game::initialize()
     itemTypeNameFactory->setItemTypeNames(itemTypeNames);
     Framework::Logging::info() << "Loading entity types";
     Framework::Array<EntityType*> entityTypeArray;
-    /*validator
-        = Framework::JSON::Validator::JSONValidator::buildForArray()
+    validator
+        = Framework::Validator::DataValidator::buildForArray()
               ->addAcceptedTypeInArray(typeRegistry->getValidator<EntityType>())
               ->removeInvalidEntries()
               ->finishArray();
     loadAllJsonsFromDirectory("data/entities",
         [this, &entityTypeArray, validator](
             Framework::JSON::JSONValue* zValue, Framework::Text path) {
-            Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+            Framework::RCArray<Framework::Validator::ValidationResult>
                 validationResults;
             Framework::JSON::JSONValue* validParts
                 = validator->getValidParts(zValue, &validationResults);
-            for (Framework::JSON::Validator::JSONValidationResult* result :
+            for (Framework::Validator::ValidationResult* result :
                 validationResults)
             {
-                result->printInvalidInfo();
+                Framework::Logging::error() << result->getInvalidInfo();
             }
             if (validParts)
             {
@@ -264,7 +264,7 @@ void Game::initialize()
                 validParts->release();
             }
         });
-    validator->release();*/
+    validator->release();
     Framework::Logging::info()
         << "Loaded " << entityTypeArray.getEintragAnzahl()
         << " entity types from data/entities";
@@ -1004,9 +1004,9 @@ void Game::addDimension(Dimension* d)
 
 int Game::getNextEntityId()
 {
-    cs.lock();
+    neidl.lock();
     int result = nextEntityId++;
-    cs.unlock();
+    neidl.unlock();
     return result;
 }
 

+ 1 - 0
FactoryCraft/Game.h

@@ -51,6 +51,7 @@ private:
     bool stop;
     __int64 tickId;
     Framework::Critical cs;
+    Framework::Critical neidl;
     int nextEntityId;
     WorldGenerator* generator;
     WorldLoader* loader;

+ 65 - 1
FactoryCraft/ModelInfo.cpp

@@ -1,5 +1,8 @@
 #include "ModelInfo.h"
 
+#include <M3Datei.h>
+#include <Model3D.h>
+
 using namespace Framework;
 
 ModelInfo::ModelInfo()
@@ -82,6 +85,11 @@ float ModelInfo::getSize() const
     return size;
 }
 
+Framework::Vec3<float> ModelInfo::getBoundingBox() const
+{
+    return boundingBox;
+}
+
 ModelInfoFactory::ModelInfoFactory()
     : ObjectTypeFactory()
 {}
@@ -100,6 +108,51 @@ ModelInfo* ModelInfoFactory::fromJson(Framework::JSON::JSONObject* zJson) const
         zJson->asObject()->zValue("transparent")->asBool()->getBool());
     result->setSize(
         (float)zJson->asObject()->zValue("size")->asNumber()->getNumber());
+    if (zJson->asObject()->hasValue("boundingBox"))
+    {
+        Framework::JSON::JSONArray* bbArr
+            = zJson->asObject()->zValue("boundingBox")->asArray();
+        result->boundingBox.x
+            = (float)bbArr->getValue(0)->asNumber()->getNumber();
+        result->boundingBox.y
+            = (float)bbArr->getValue(1)->asNumber()->getNumber();
+        result->boundingBox.z
+            = (float)bbArr->getValue(2)->asNumber()->getNumber();
+    }
+    else
+    {
+        Text path = "data/models/";
+        path += result->getModelPath();
+        bool loades = 0;
+        if (path.positionVon(".m3/") > 0)
+        {
+            int pos = path.positionVon(".m3/", path.anzahlVon(".m3/") - 1) + 3;
+            Framework::M3Datei m3File(path.getTeilText(0, pos));
+            m3File.leseDaten();
+            Model3DData* data
+                = m3File.ladeModel(path.getTeilText(pos + 1), 0, new Text());
+            if (data)
+            {
+                auto tmp = data->getMaxPos();
+                result->boundingBox.x = abs(tmp.x);
+                result->boundingBox.y = abs(tmp.y);
+                result->boundingBox.z = abs(tmp.z);
+                tmp = data->getMinPos();
+                result->boundingBox.x = max(result->boundingBox.x, abs(tmp.x));
+                result->boundingBox.y = max(result->boundingBox.y, abs(tmp.y));
+                result->boundingBox.z = max(result->boundingBox.z, abs(tmp.z));
+                data->release();
+                loades = 1;
+            }
+        }
+        if (!loades)
+        {
+            result->boundingBox.x = 0.5f;
+            result->boundingBox.y = 0.5f;
+            result->boundingBox.z = 0.5f;
+        }
+    }
+
     return result;
 }
 
@@ -118,6 +171,11 @@ Framework::JSON::JSONObject* ModelInfoFactory::toJsonObject(
     result->addValue(
         "transparent", new Framework::JSON::JSONBool(zObject->transparent));
     result->addValue("size", new Framework::JSON::JSONNumber(zObject->size));
+    Framework::JSON::JSONArray* bbArr = new Framework::JSON::JSONArray();
+    bbArr->addValue(new Framework::JSON::JSONNumber(zObject->boundingBox.x));
+    bbArr->addValue(new Framework::JSON::JSONNumber(zObject->boundingBox.y));
+    bbArr->addValue(new Framework::JSON::JSONNumber(zObject->boundingBox.z));
+    result->addValue("boundingBox", bbArr);
     return result;
 }
 
@@ -136,5 +194,11 @@ JSONObjectValidationBuilder* ModelInfoFactory::addToValidator(
         ->withRequiredNumber("size")
         ->whichIsGreaterThen(0)
         ->withDefault(1.0)
-        ->finishNumber();
+        ->finishNumber()
+        ->withRequiredArray("boundingBox")
+        ->whichIsOptional()
+        ->withRequiredSize(3)
+        ->addAcceptedNumberInArray()
+        ->finishNumber()
+        ->finishArray();
 }

+ 3 - 0
FactoryCraft/ModelInfo.h

@@ -2,6 +2,7 @@
 
 #include <Array.h>
 #include <Text.h>
+#include <Vec3.h>
 #include <Writer.h>
 
 #include "TypeRegistry.h"
@@ -15,6 +16,7 @@ private:
     Framework::RCArray<Framework::Text> texturePaths;
     bool transparent;
     float size;
+    Framework::Vec3<float> boundingBox;
 
 public:
     ModelInfo();
@@ -32,6 +34,7 @@ public:
     Framework::RCArray<Framework::Text> getTexturePaths() const;
     bool isTransparent() const;
     float getSize() const;
+    Framework::Vec3<float> getBoundingBox() const;
 
     friend ModelInfoFactory;
 };

+ 13 - 0
Windows Version/data/entities/animals.json

@@ -0,0 +1,13 @@
+[
+    {
+        "type": "animal",
+        "typeName": "Kow",
+        "drops": [],
+        "model": {
+            "modelPath": "entities.m3/kow",
+            "texturePaths": [
+                "entities.ltdb/kow.png"
+            ]
+        }
+    }
+]

+ 49 - 1
Windows Version/data/generator/overworld.json

@@ -244,7 +244,55 @@
         "bioms": [
             {
                 "name": "Grassland",
-                "entities": [],
+                "entities": [
+                    {
+                        "type": "Kow",
+                        "condition": {
+                            "blockType": "Dirt",
+                            "type": "blockType",
+                            "x": {
+                                "type": "variable",
+                                "name": "x"
+                            },
+                            "y": {
+                                "type": "variable",
+                                "name": "y"
+                            },
+                            "z": {
+                                "type": "operator",
+                                "operator": "-",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "z"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 2
+                                    }
+                                ]
+                            }
+                        },
+                        "threshold": 0.996,
+                        "noise": {
+                            "type": "random",
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 101
+                                    }
+                                ]
+                            }
+                        }
+                    }
+                ],
                 "structurCollections": [
                     {
                         "activeNoise": {

BIN
Windows Version/data/models/blocks.m3


BIN
Windows Version/data/models/entities.m3


BIN
Windows Version/data/models/items.m3


BIN
Windows Version/data/models/plants.m3


BIN
Windows Version/data/models/tools.m3