mirror of
https://github.com/worldforge/cyphesis
synced 2026-08-13 12:26:04 -04:00
Classes under "rulesets" have been moved to "rules", and split up into futher subdirectories matching their library. As a result we can now better separate the python bindings, so that things that belongs to the simulation are separeted from things that belongs to the ai.
344 lines
11 KiB
C++
344 lines
11 KiB
C++
/*
|
|
Copyright (C) 2014 Erik Ogenvik
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#ifndef PHYSICALDOMAIN_H_
|
|
#define PHYSICALDOMAIN_H_
|
|
|
|
#include "rules/Domain.h"
|
|
#include "rules/Location.h"
|
|
#include "ModeProperty.h"
|
|
|
|
#include <sigc++/connection.h>
|
|
|
|
#include <LinearMath/btVector3.h>
|
|
|
|
#include <map>
|
|
#include <unordered_map>
|
|
#include <tuple>
|
|
#include <array>
|
|
#include <set>
|
|
#include <BulletCollision/CollisionDispatch/btGhostObject.h>
|
|
|
|
namespace Mercator {
|
|
class Segment;
|
|
|
|
class Terrain;
|
|
|
|
class TerrainMod;
|
|
}
|
|
|
|
class btDefaultCollisionConfiguration;
|
|
|
|
class btCollisionDispatcher;
|
|
|
|
class btBroadphaseInterface;
|
|
|
|
class btCollisionWorld;
|
|
|
|
class btSequentialImpulseConstraintSolver;
|
|
|
|
class PhysicalWorld;
|
|
|
|
class btRigidBody;
|
|
|
|
class btCollisionShape;
|
|
|
|
class btSphereShape;
|
|
|
|
class btCollisionObject;
|
|
|
|
class PropertyBase;
|
|
|
|
/**
|
|
* @brief A regular physical domain, behaving very much like the real world.
|
|
*
|
|
* Things move using physical rules, and sights are calculated using line of sight.
|
|
*
|
|
*/
|
|
class PhysicalDomain : public Domain
|
|
{
|
|
public:
|
|
explicit PhysicalDomain(LocatedEntity& entity);
|
|
|
|
~PhysicalDomain() override;
|
|
|
|
void tick(double t, OpVector& res) override;
|
|
|
|
bool isEntityVisibleFor(const LocatedEntity& observingEntity, const LocatedEntity& observedEntity) const override;
|
|
|
|
void getVisibleEntitiesFor(const LocatedEntity& observingEntity, std::list<LocatedEntity*>& entityList) const override;
|
|
|
|
std::list<LocatedEntity*> getObservingEntitiesFor(const LocatedEntity& observedEntity) const override;
|
|
|
|
void addEntity(LocatedEntity& entity) override;
|
|
|
|
void removeEntity(LocatedEntity& entity) override;
|
|
|
|
void applyTransform(LocatedEntity& entity, const TransformData& transformData,
|
|
std::set<LocatedEntity*>& transformedEntities) override;
|
|
|
|
void refreshTerrain(const std::vector<WFMath::AxisBox<2>>& areas) override;
|
|
|
|
void toggleChildPerception(LocatedEntity& entity) override;
|
|
|
|
bool isEntityReachable(const LocatedEntity& reachingEntity, float reach, const LocatedEntity& queriedEntity, const WFMath::Point<3>& positionOnQueriedEntity) const override;
|
|
|
|
protected:
|
|
|
|
friend class SteppingCallback;
|
|
|
|
class PhysicalMotionState;
|
|
|
|
class VisibilityCallback;
|
|
|
|
struct BulletEntry
|
|
{
|
|
LocatedEntity* entity = nullptr;
|
|
std::shared_ptr<btCollisionShape> collisionShape;
|
|
btCollisionObject* collisionObject = nullptr;
|
|
sigc::connection propertyUpdatedConnection;
|
|
Location lastSentLocation;
|
|
PhysicalMotionState* motionState = nullptr;
|
|
|
|
btCollisionObject* visibilitySphere = nullptr;
|
|
btCollisionObject* viewSphere = nullptr;
|
|
|
|
/**
|
|
* Set of entries which are observing by this.
|
|
*/
|
|
std::set<BulletEntry*> observedByThis;
|
|
/**
|
|
* Set of entries which are observing this.
|
|
*/
|
|
std::set<BulletEntry*> observingThis;
|
|
|
|
btVector3 centerOfMassOffset;
|
|
|
|
/**
|
|
* Max speed when on solid ground, derived from the "speed_ground" property and cached for performance.
|
|
*/
|
|
double speedGround;
|
|
/**
|
|
* Max speed when in water (swimming), derived from the "speed_water" property and cached for performance.
|
|
*/
|
|
double speedWater;
|
|
/**
|
|
* Max speed when flying, derived from the "speed_flight" property and cached for performance.
|
|
*/
|
|
double speedFlight;
|
|
|
|
/**
|
|
* The mode of the entity, as known by the physics system.
|
|
*/
|
|
ModeProperty::Mode mode;
|
|
|
|
/**
|
|
* Set to true if the mode has been changed in a tick, which should be communicated in a Move op.
|
|
*/
|
|
bool modeChanged;
|
|
|
|
/**
|
|
* A set of entities which are planted on this. They move along.
|
|
*/
|
|
std::set<BulletEntry*> attachedEntities;
|
|
|
|
/**
|
|
* Keeps track of whether the entity is actively jumping. If so we shouldn't try to clamp it to the ground.
|
|
*/
|
|
bool isJumping = false;
|
|
|
|
};
|
|
|
|
struct TerrainEntry
|
|
{
|
|
std::array<float, 65 * 65>* data;
|
|
btRigidBody* rigidBody;
|
|
};
|
|
|
|
std::unordered_map<long, BulletEntry*> m_entries;
|
|
|
|
std::set<BulletEntry*> m_movingEntities;
|
|
std::set<BulletEntry*> m_lastMovingEntities;
|
|
std::set<BulletEntry*> m_dirtyEntries;
|
|
/**
|
|
* A map of all submerged entities, and the water body they currently are submerged into.
|
|
*/
|
|
std::map<BulletEntry*, btGhostObject*> m_submergedEntities;
|
|
std::vector<WFMath::AxisBox<2>> m_dirtyTerrainAreas;
|
|
|
|
std::unordered_map<long, std::tuple<Mercator::TerrainMod*, WFMath::Point<3>, WFMath::Quaternion, WFMath::AxisBox<2>>> m_terrainMods;
|
|
|
|
|
|
struct PropelEntry
|
|
{
|
|
btRigidBody* rigidBody;
|
|
BulletEntry* bulletEntry;
|
|
btVector3 velocity;
|
|
float stepHeight;
|
|
};
|
|
/**
|
|
* @brief A map of all entities that currently are self-propelling.
|
|
*
|
|
* Each tick the propel force will be applied to these entities.
|
|
*/
|
|
std::map<long, PropelEntry> m_propellingEntries;
|
|
|
|
/**
|
|
* Keeps track of all stepping entries, i.e. those we want clamped to the ground.
|
|
*/
|
|
std::map<long, std::pair<BulletEntry*, float>> m_steppingEntries;
|
|
|
|
/**
|
|
* Struct used to pass information on to the tick callbacks.
|
|
*/
|
|
struct WorldInfo {
|
|
std::map<long, PropelEntry>* propellingEntries;
|
|
std::map<long, std::pair<BulletEntry*, float>>* steppingEntries;
|
|
};
|
|
|
|
WorldInfo mWorldInfo;
|
|
|
|
btDefaultCollisionConfiguration* m_collisionConfiguration;
|
|
btCollisionDispatcher* m_dispatcher;
|
|
btSequentialImpulseConstraintSolver* m_constraintSolver;
|
|
btBroadphaseInterface* m_broadphase;
|
|
PhysicalWorld* m_dynamicsWorld;
|
|
|
|
btCollisionDispatcher* m_visibilityDispatcher;
|
|
btBroadphaseInterface* m_visibilityBroadphase;
|
|
btCollisionWorld* m_visibilityWorld;
|
|
|
|
sigc::connection m_propertyAppliedConnection;
|
|
|
|
float m_visibilityCheckCountdown;
|
|
|
|
BulletEntry mContainingEntityEntry;
|
|
|
|
Mercator::Terrain* m_terrain;
|
|
|
|
std::unique_ptr<btGhostPairCallback> m_ghostPairCallback;
|
|
|
|
/**
|
|
* @brief Contains all terrain segments, as height fields.
|
|
*
|
|
* Each segment is 65*65 points.
|
|
*/
|
|
std::unordered_map<std::string, TerrainEntry> m_terrainSegments;
|
|
|
|
/**
|
|
* Contains the six planes that make out the border, which matches the bounding box of the entity to which this
|
|
* property belongs.
|
|
*/
|
|
std::vector<btRigidBody*> m_borderPlanes;
|
|
|
|
/**
|
|
* Keeps track of all water bodies, which are ghost objects which we use to detect when entities move in and out of the water.
|
|
*/
|
|
std::vector<btGhostObject*> m_waterBodies;
|
|
|
|
/**
|
|
* @brief Creates borders around the domain, which prevents entities from "escaping".
|
|
*
|
|
* This will be done by adding planes matching the bbox of the entity to which the domain belongs.
|
|
*/
|
|
void createDomainBorders();
|
|
|
|
/**
|
|
* @brief Build all terrain pages.
|
|
*/
|
|
void buildTerrainPages();
|
|
|
|
/**
|
|
* @brief Builds one terrain page from a Mercator segment.
|
|
* @param segment
|
|
*/
|
|
TerrainEntry buildTerrainPage(Mercator::Segment& segment);
|
|
|
|
/**
|
|
* Listener method for all child entities, called when their properties change.
|
|
* @param name
|
|
* @param prop
|
|
* @param bulletEntry
|
|
*/
|
|
void childEntityPropertyApplied(const std::string& name, const PropertyBase& prop, BulletEntry* bulletEntry);
|
|
|
|
/**
|
|
* Listener method for changes to properties on the entity to which the property belongs.
|
|
* @param name
|
|
* @param prop
|
|
* @param bulletEntry
|
|
*/
|
|
void entityPropertyApplied(const std::string& name, const PropertyBase& prop);
|
|
|
|
float getMassForEntity(const LocatedEntity& entity) const;
|
|
|
|
void getCollisionFlagsForEntity(const LocatedEntity& entity, short& collisionGroup, short& collisionMask) const;
|
|
|
|
void sendMoveSight(BulletEntry& bulletEntry, bool posChange, bool velocityChange, bool orientationChange, bool angularChange, bool modeChanged);
|
|
|
|
void processMovedEntity(BulletEntry& bulletEntry);
|
|
|
|
void updateVisibilityOfDirtyEntities(OpVector& res);
|
|
|
|
void updateObservedEntry(BulletEntry* entry, OpVector& res, bool generateOps = true);
|
|
|
|
void updateObserverEntry(BulletEntry* bulletEntry, OpVector& res);
|
|
|
|
void applyNewPositionForEntity(BulletEntry* entry, const WFMath::Point<3>& pos, bool calculatePosition = true);
|
|
|
|
bool getTerrainHeight(float x, float y, float& height) const;
|
|
|
|
void updateTerrainMod(const LocatedEntity& entity, bool forceUpdate = false);
|
|
|
|
void processDirtyTerrainAreas();
|
|
|
|
void applyVelocity(BulletEntry& entry, const WFMath::Vector<3>& velocity);
|
|
|
|
void calculatePositionForEntity(ModeProperty::Mode mode, BulletEntry* entry, WFMath::Point<3>& pos);
|
|
|
|
/**
|
|
* Called each tick to process any bodies that are moving in water.
|
|
*/
|
|
void processWaterBodies();
|
|
|
|
std::shared_ptr<btCollisionShape> createCollisionShapeForEntry(LocatedEntity* entity,
|
|
const WFMath::AxisBox<3>& bbox, float mass,
|
|
btVector3& centerOfMassOffse);
|
|
|
|
/**
|
|
* Transform any entities that are resting on the supplied entity.
|
|
*
|
|
* I.e. those that are "free" or "submerged" and are on top of the entity.
|
|
* @param entry
|
|
* @param posTransform
|
|
* @param transformedEntities
|
|
*/
|
|
void transformRestingEntities(BulletEntry* entry,
|
|
const WFMath::Vector<3>& posTransform,
|
|
const WFMath::Quaternion& orientationChange,
|
|
std::set<LocatedEntity*>& transformedEntities);
|
|
|
|
void plantOnEntity(BulletEntry* plantedEntry, BulletEntry* entryPlantedOn);
|
|
|
|
void applyTransformInternal(LocatedEntity& entity, const WFMath::Quaternion& orientation,
|
|
const WFMath::Point<3>& pos, const WFMath::Vector<3>& velocity,
|
|
std::set<LocatedEntity*>& transformedEntities, bool calculatePosition);
|
|
|
|
|
|
};
|
|
|
|
#endif /* PHYSICALDOMAIN_H_ */
|