Skip to content

Commit

Permalink
✨ Terrain editor: preloaded actors fully editable
Browse files Browse the repository at this point in the history
rotations now work
  • Loading branch information
ohlidalp committed Jan 6, 2025
1 parent f8a91f1 commit 3b12aac
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 47 deletions.
2 changes: 1 addition & 1 deletion source/main/GameContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ void GameContext::ModifyActor(ActorModifyRequest& rq)
}
else if (rq.amr_type == ActorModifyRequest::Type::SOFT_RESPAWN)
{
actor->softRespawn(rq.amr_softrespawn_pos);
actor->softRespawn(rq.amr_softrespawn_position, rq.amr_softrespawn_rotation);
}
else if (rq.amr_type == ActorModifyRequest::Type::REFRESH_VISUALS)
{
Expand Down
10 changes: 9 additions & 1 deletion source/main/physics/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1289,7 +1289,7 @@ void Actor::resetPosition(Ogre::Vector3 translation, bool setInitPosition)
calculateAveragePosition();
}

void Actor::softRespawn(Ogre::Vector3 spawnpos)
void Actor::softRespawn(Ogre::Vector3 spawnpos, Ogre::Quaternion spawnrot)
{
// Perform a hard reset (detach any linked actors etc...)
this->SyncReset(/*reset_position:*/ false);
Expand All @@ -1303,6 +1303,14 @@ void Actor::softRespawn(Ogre::Vector3 spawnpos)
ar_nodes[i].Forces = Ogre::Vector3::ZERO;
ar_nodes[i].Velocity = Ogre::Vector3::ZERO;
}

// Apply spawn position & spawn rotation
// (code taken as-is from `ActorManager::CreateNewActor()`)
for (NodeNum_t i = 0; i < ar_num_nodes; i++)
{
ar_nodes[i].AbsPosition = spawnpos + spawnrot * (ar_nodes[i].AbsPosition - spawnpos);
ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
};
}

void Actor::mouseMove(NodeNum_t node, Vector3 pos, float force)
Expand Down
2 changes: 1 addition & 1 deletion source/main/physics/Actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class Actor : public RefCountingObject<Actor>
// not exported to scripting:
void resetPosition(Ogre::Vector3 translation, bool setInitPosition); //!< Moves the actor to given world coords (pivot point is node 0).
void resetPosition(float px, float pz, bool setInitPosition, float miny); //!< Moves the actor to given world coords (pivot point is node 0).
void softRespawn(Ogre::Vector3 spawnpos); //!< Use `MSG_SIM_MODIFY_ACTOR_REQUESTED` with type `SOFT_RESPAWN`; Resets the actor to given position as if spawned there (pivot point is `spawnpos`).
void softRespawn(Ogre::Vector3 spawnpos, Ogre::Quaternion spawnrot); //!< Use `MSG_SIM_MODIFY_ACTOR_REQUESTED` with type `SOFT_RESPAWN`; Resets the actor to given position as if spawned there (pivot point is `spawnpos`).
void requestRotation(float rotation, Ogre::Vector3 center) { m_rotation_request += rotation; m_rotation_request_center = center; };
void requestAngleSnap(int division) { m_anglesnap_request = division; };
void requestTranslation(Ogre::Vector3 translation) { m_translation_request += translation; };
Expand Down
3 changes: 2 additions & 1 deletion source/main/physics/SimData.h
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,8 @@ struct ActorModifyRequest
amr_saved_state;
CacheEntryPtr amr_addonpart; //!< Primary method of specifying cache entry.
std::string amr_addonpart_fname; //!< Fallback method in case CacheEntry doesn't exist anymore - that means mod was uninstalled in the meantime. Used by REMOVE_ADDONPART_AND_RELOAD.
Ogre::Vector3 amr_softrespawn_pos; //!< Position to use with `SOFT_RESPAWN`.
Ogre::Vector3 amr_softrespawn_position; //!< Position to use with `SOFT_RESPAWN`.
Ogre::Quaternion amr_softrespawn_rotation; //!< Rotation to use with `SOFT_RESPAWN`; use `TObjParser::CalcRotation()` to calculate quaternion from XYZ like in TOBJ file.
};

enum class ActorLinkingRequestType
Expand Down
62 changes: 27 additions & 35 deletions source/main/terrain/TerrainEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,31 @@ Ogre::Vector3 const& TerrainEditorObject::getRotation()
return rotation;
}

void TerrainEditorObjectRefreshActorVisual(TerrainEditorObjectPtr obj)
{
ROR_ASSERT(obj->actor_instance_id != ACTORINSTANCEID_INVALID);
const ActorPtr& actor = App::GetGameContext()->GetActorManager()->GetActorById(obj->actor_instance_id);
ROR_ASSERT(actor != ActorManager::ACTORPTR_NULL);
if (actor != ActorManager::ACTORPTR_NULL)
{
const bool rot_yxz = App::GetGameContext()->GetTerrain()->getObjectManager()->GetEditorObjectFlagRotYXZ(obj);

ActorModifyRequest* req = new ActorModifyRequest();
req->amr_type = ActorModifyRequest::Type::SOFT_RESPAWN;
req->amr_actor = actor->ar_instance_id;
req->amr_softrespawn_position = obj->position;
req->amr_softrespawn_rotation = TObjParser::CalcRotation(obj->rotation, rot_yxz);
App::GetGameContext()->PushMessage(Message(MSG_SIM_MODIFY_ACTOR_REQUESTED, (void*)req));
req = nullptr;

ActorModifyRequest* fxreq = new ActorModifyRequest();
fxreq->amr_type = ActorModifyRequest::Type::REFRESH_VISUALS;
fxreq->amr_actor = actor->ar_instance_id;
App::GetGameContext()->PushMessage(Message(MSG_SIM_MODIFY_ACTOR_REQUESTED, (void*)fxreq));
fxreq = nullptr;
}
}

void TerrainEditorObject::setPosition(Ogre::Vector3 const& pos)
{
position = pos;
Expand All @@ -387,26 +412,7 @@ void TerrainEditorObject::setPosition(Ogre::Vector3 const& pos)
}
else if (special_object_type != TObjSpecialObject::NONE)
{
ROR_ASSERT(actor_instance_id != ACTORINSTANCEID_INVALID);
const ActorPtr& actor = App::GetGameContext()->GetActorManager()->GetActorById(actor_instance_id);
ROR_ASSERT(actor != ActorManager::ACTORPTR_NULL);
if (actor != ActorManager::ACTORPTR_NULL)
{
actor->requestTranslation(pos - actor->getPosition());

ActorModifyRequest* req = new ActorModifyRequest();
req->amr_type = ActorModifyRequest::Type::SOFT_RESPAWN;
req->amr_actor = actor->ar_instance_id;
req->amr_softrespawn_pos = pos;
App::GetGameContext()->PushMessage(Message(MSG_SIM_MODIFY_ACTOR_REQUESTED, (void*)req));
req = nullptr;

ActorModifyRequest* fxreq = new ActorModifyRequest();
fxreq->amr_type = ActorModifyRequest::Type::REFRESH_VISUALS;
fxreq->amr_actor = actor->ar_instance_id;
App::GetGameContext()->PushMessage(Message(MSG_SIM_MODIFY_ACTOR_REQUESTED, (void*)fxreq));
fxreq = nullptr;
}
TerrainEditorObjectRefreshActorVisual(this);
}
}

Expand All @@ -420,21 +426,7 @@ void TerrainEditorObject::setRotation(Ogre::Vector3 const& rot)
}
else if (special_object_type != TObjSpecialObject::NONE)
{
ROR_ASSERT(actor_instance_id != ACTORINSTANCEID_INVALID);
const ActorPtr& actor = App::GetGameContext()->GetActorManager()->GetActorById(actor_instance_id);
ROR_ASSERT(actor != ActorManager::ACTORPTR_NULL);
if (actor != ActorManager::ACTORPTR_NULL)
{
// TBD: only yaw can be requested at the moment.
// FIXME: the rot_xyz flag is currently ignored
Quaternion orientation = TObjParser::CalcRotation(rot, /*rot_xyz:*/false);
actor->requestRotation(orientation.getYaw(/*reprojectAxis:*/false).valueRadians() - actor->getRotation(), actor->getPosition());

ActorModifyRequest* req = new ActorModifyRequest();
req->amr_type = ActorModifyRequest::Type::RESET_ON_SPOT;
req->amr_actor = actor->ar_instance_id;
App::GetGameContext()->PushMessage(Message(MSG_SIM_MODIFY_ACTOR_REQUESTED, (void*)req));
}
TerrainEditorObjectRefreshActorVisual(this);
}
}

Expand Down
21 changes: 13 additions & 8 deletions source/main/terrain/TerrainObjectManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -998,24 +998,29 @@ void TerrainObjectManager::LoadTelepoints()
}
}


void TerrainObjectManager::SpawnSinglePredefinedActor(TerrainEditorObjectPtr const& object)
bool TerrainObjectManager::GetEditorObjectFlagRotYXZ(TerrainEditorObjectPtr const& object)
{
// For terrain editor to work, all preloaded actors must be spawned.
// Most will spawn with terrain, however, some may be excluded for reasons.
// -----------------------------------------------------------------------

// We need the 'rot_yxz' flag - look up the TOBJ document in cache
bool rot_yxz = false;
if (object->tobj_cache_id == -1 || object->tobj_cache_id >= (int)m_tobj_cache.size())
{
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_TERRN, Console::CONSOLE_SYSTEM_WARNING,
fmt::format("Assuming no 'rot_yxz' when spawning preselected actor '{}' - TOBJ document not found", object->getName()));
return false;
}
else
{
rot_yxz = m_tobj_cache[object->tobj_cache_id]->rot_yxz;
return m_tobj_cache[object->tobj_cache_id]->rot_yxz;
}
}


void TerrainObjectManager::SpawnSinglePredefinedActor(TerrainEditorObjectPtr const& object)
{
// For terrain editor to work, all preloaded actors must be spawned.
// Most will spawn with terrain, however, some may be excluded for reasons.
// -----------------------------------------------------------------------

const bool rot_yxz = GetEditorObjectFlagRotYXZ(object);

// Check if already spawned.
if (object->actor_instance_id == ACTORINSTANCEID_INVALID)
Expand Down
1 change: 1 addition & 0 deletions source/main/terrain/TerrainObjectManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class TerrainObjectManager: public RefCountingObject<TerrainObjectManager>
void destroyObject(const Ogre::String& instancename);
void LoadTelepoints();
void SpawnSinglePredefinedActor(TerrainEditorObjectPtr const& object);
bool GetEditorObjectFlagRotYXZ(TerrainEditorObjectPtr const& object);
void LoadPredefinedActors();
bool HasPredefinedActors() { return m_has_predefined_actors; };
bool UpdateTerrainObjects(float dt);
Expand Down

0 comments on commit 3b12aac

Please sign in to comment.