Skip to content

Commit d70150c

Browse files
committed
👼Script: fixed game.xxObject() not playing nice with terrain editor.
Problem1: removing object while being active in terrain editor caused glitches, as the editor just jumped to the next object (and would probably crash if last object was active). Fix1: Properly reset terrain editor mode on object removal. Problem2: moving object via `game.moveObjectVisuals` wouldn't update the editor object. Fix2: remove `struct StaticObject` altogether, use just TerrainEditorObject to track static objects. Positive side effect: destroyed objects are now really removed, instead of just setting `enabled = false`. Additional code change: TerrainObjectManager funcs renamed to match those in script API.
1 parent 4b32442 commit d70150c

6 files changed

+62
-54
lines changed

source/main/ForwardDeclarations.h

+3
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ namespace RoR
7878

7979
typedef int ScriptRetCode_t; //!< see enum `RoR::ScriptRetCode` - combines AngelScript codes and RoR internal codes.
8080

81+
typedef int TerrainEditorObjectID_t; //!< Offset into `RoR::TerrainObjectManager::m_editor_objects`, use `RoR::TERRAINEDITOROBJECTID_INVALID` as empty value.
82+
static const TerrainEditorObjectID_t TERRAINEDITOROBJECTID_INVALID = -1;
83+
8184
class Actor;
8285
class ActorManager;
8386
class ActorSpawner;

source/main/scripting/GameScript.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ void GameScript::destroyObject(const String& instanceName)
425425

426426
if (App::GetGameContext()->GetTerrain()->getObjectManager())
427427
{
428-
App::GetGameContext()->GetTerrain()->getObjectManager()->unloadObject(instanceName);
428+
App::GetGameContext()->GetTerrain()->getObjectManager()->destroyObject(instanceName);
429429
}
430430
}
431431

@@ -436,7 +436,7 @@ void GameScript::moveObjectVisuals(const String& instanceName, const Vector3& po
436436

437437
if (App::GetGameContext()->GetTerrain()->getObjectManager())
438438
{
439-
App::GetGameContext()->GetTerrain()->getObjectManager()->MoveObjectVisuals(instanceName, pos);
439+
App::GetGameContext()->GetTerrain()->getObjectManager()->moveObjectVisuals(instanceName, pos);
440440
}
441441
}
442442

source/main/terrain/TerrainEditor.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ void TerrainEditor::UpdateInputEvents(float dt)
226226
}
227227
if (App::GetInputEngine()->getEventBoolValue(EV_COMMON_REMOVE_CURRENT_TRUCK))
228228
{
229-
App::GetGameContext()->GetTerrain()->getObjectManager()->unloadObject(object_list[m_object_index]->instance_name);
229+
App::GetGameContext()->GetTerrain()->getObjectManager()->destroyObject(object_list[m_object_index]->instance_name);
230230
}
231231
}
232232
else

source/main/terrain/TerrainEditor.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class TerrainEditorObject : public RefCountingObject<TerrainEditorObject>
4747
int script_handler = -1;
4848
int tobj_cache_id = -1;
4949
std::string tobj_comments;
50+
std::vector<int> static_collision_boxes;
51+
std::vector<int> static_collision_tris;
5052

5153
// Functions are exported to AngelScript
5254
std::string const& getName();
@@ -69,13 +71,13 @@ class TerrainEditor
6971
void UpdateInputEvents(float dt);
7072
void WriteOutputFile();
7173
void ClearSelection();
72-
int GetSelectedObjectIndex() const { return m_object_index; }
74+
TerrainEditorObjectID_t GetSelectedObjectID() const { return m_object_index; }
7375

7476
private:
7577
bool m_object_tracking = true;
7678
int m_rotation_axis = 1; //!< 0=X, 1=Y, 2=Z
7779
std::string m_last_object_name;
78-
int m_object_index = -1;
80+
TerrainEditorObjectID_t m_object_index = TERRAINEDITOROBJECTID_INVALID;
7981
};
8082

8183
/// @} // addtogroup Terrain

source/main/terrain/TerrainObjectManager.cpp

+48-36
Original file line numberDiff line numberDiff line change
@@ -484,50 +484,54 @@ void TerrainObjectManager::ProcessGrass(
484484
#endif //USE_PAGED
485485
}
486486

487-
void TerrainObjectManager::MoveObjectVisuals(const String& instancename, const Ogre::Vector3& pos)
487+
void TerrainObjectManager::moveObjectVisuals(const String& instancename, const Ogre::Vector3& pos)
488488
{
489-
if (m_static_objects.find(instancename) == m_static_objects.end())
489+
// Obsolete function kept for backwards-compatibility; does the same as `TerrainEditorObject::setPosition()`
490+
// -------------------------------------------------------------------------------------------------------
491+
492+
TerrainEditorObjectID_t id = FindEditorObjectByInstanceName(instancename);
493+
if (id == TERRAINEDITOROBJECTID_INVALID)
490494
{
491-
LOG(instancename+ " not found!");
495+
LOG(fmt::format("[RoR] `moveObjectVisuals()`: instance name '{}' not found!", instancename));
492496
return;
493497
}
494498

495-
StaticObject obj = m_static_objects[instancename];
496-
497-
if (!obj.enabled)
498-
return;
499-
500-
obj.sceneNode->setPosition(pos);
499+
m_editor_objects[id]->setPosition(pos);
501500
}
502501

503-
void TerrainObjectManager::unloadObject(const String& instancename)
502+
void TerrainObjectManager::destroyObject(const String& instancename)
504503
{
505-
if (m_static_objects.find(instancename) == m_static_objects.end())
504+
TerrainEditorObjectID_t id = FindEditorObjectByInstanceName(instancename);
505+
if (id == -1)
506506
{
507-
LOG("unable to unload object: " + instancename);
507+
LOG(fmt::format("[RoR] `destroyObject()`: instance name '{}' not found!", instancename));
508508
return;
509509
}
510510

511-
StaticObject obj = m_static_objects[instancename];
512-
513-
if (!obj.enabled)
514-
return;
515-
516-
for (auto tri : obj.collTris)
511+
for (int tri : m_editor_objects[id]->static_collision_tris)
517512
{
518513
terrainManager->GetCollisions()->removeCollisionTri(tri);
519514
}
520-
for (auto box : obj.collBoxes)
515+
for (int box : m_editor_objects[id]->static_collision_boxes)
521516
{
522517
terrainManager->GetCollisions()->removeCollisionBox(box);
523518
}
524519

525-
obj.sceneNode->detachAllObjects();
526-
obj.sceneNode->setVisible(false);
527-
obj.enabled = false;
520+
// Destroy the scene node and everything attached to it.
521+
for (Ogre::MovableObject* mova : m_editor_objects[id]->node->getAttachedObjects())
522+
{
523+
App::GetGfxScene()->GetSceneManager()->destroyMovableObject(mova);
524+
}
525+
App::GetGfxScene()->GetSceneManager()->destroySceneNode(m_editor_objects[id]->node);
528526

529-
m_editor_objects.erase(std::remove_if(m_editor_objects.begin(), m_editor_objects.end(),
530-
[instancename](TerrainEditorObjectPtr& e) { return e->instance_name == instancename; }), m_editor_objects.end());
527+
// Release the object from editor, if active.
528+
if (id == App::GetGameContext()->GetTerrain()->GetTerrainEditor()->GetSelectedObjectID())
529+
{
530+
App::GetGameContext()->GetTerrain()->GetTerrainEditor()->ClearSelection();
531+
}
532+
533+
// Forget the object ever existed.
534+
m_editor_objects.erase(m_editor_objects.begin() + id);
531535
}
532536

533537
ODefDocument* TerrainObjectManager::FetchODef(std::string const & odef_name)
@@ -633,13 +637,6 @@ bool TerrainObjectManager::LoadTerrainObject(const Ogre::String& name, const Ogr
633637
tenode->pitch(Degree(-90));
634638
tenode->setVisible(true);
635639

636-
// register in map
637-
StaticObject* obj = &m_static_objects[instancename];
638-
obj->instanceName = instancename;
639-
obj->enabled = true;
640-
obj->sceneNode = tenode;
641-
obj->collTris.clear();
642-
643640
TerrainEditorObjectPtr object = new TerrainEditorObject();
644641
object->name = name;
645642
object->instance_name = instancename;
@@ -722,7 +719,7 @@ bool TerrainObjectManager::LoadTerrainObject(const Ogre::String& name, const Ogr
722719
m_map_entities.push_back(SurveyMapEntity(object->type, caption, fmt::format("icon_{}.dds", object->type), /*resource_group:*/"", object->position, Ogre::Radian(0), -1));
723720
}
724721

725-
this->ProcessODefCollisionBoxes(obj, odef, object, race_event);
722+
this->ProcessODefCollisionBoxes(object, odef, object, race_event);
726723

727724
for (ODefCollisionMesh& cmesh : odef->collision_meshes)
728725
{
@@ -736,7 +733,7 @@ bool TerrainObjectManager::LoadTerrainObject(const Ogre::String& name, const Ogr
736733
terrainManager->GetCollisions()->addCollisionMesh(
737734
odefname,
738735
cmesh.mesh_name, pos, tenode->getOrientation(),
739-
cmesh.scale, gm, &(obj->collTris));
736+
cmesh.scale, gm, &(object->static_collision_tris));
740737
}
741738

742739
for (ODefParticleSys& psys : odef->particle_systems)
@@ -761,7 +758,7 @@ bool TerrainObjectManager::LoadTerrainObject(const Ogre::String& name, const Ogr
761758
pAff = pParticleSys->getAffector(i);
762759
if (pAff->getType() == "ExtinguishableFire")
763760
{
764-
((ExtinguishableFireAffector*)pAff)->setInstanceName(obj->instanceName);
761+
((ExtinguishableFireAffector*)pAff)->setInstanceName(object->instance_name);
765762
}
766763
}
767764
#endif // USE_ANGELSCRIPT
@@ -1018,7 +1015,7 @@ bool TerrainObjectManager::UpdateTerrainObjects(float dt)
10181015
return true;
10191016
}
10201017

1021-
void TerrainObjectManager::ProcessODefCollisionBoxes(StaticObject* obj, ODefDocument* odef, const TerrainEditorObjectPtr& params, bool race_event)
1018+
void TerrainObjectManager::ProcessODefCollisionBoxes(TerrainEditorObjectPtr obj, ODefDocument* odef, const TerrainEditorObjectPtr& params, bool race_event)
10221019
{
10231020
for (ODefCollisionBox& cbox : odef->collision_boxes)
10241021
{
@@ -1046,7 +1043,7 @@ void TerrainObjectManager::ProcessODefCollisionBoxes(StaticObject* obj, ODefDocu
10461043
params->instance_name, cbox.force_cam_pos, cbox.cam_pos,
10471044
cbox.scale, cbox.direction, cbox.event_filter, params->script_handler);
10481045

1049-
obj->collBoxes.push_back(boxnum);
1046+
obj->static_collision_boxes.push_back(boxnum);
10501047
}
10511048
}
10521049
}
@@ -1066,3 +1063,18 @@ Ogre::SceneNode* TerrainObjectManager::getGroupingSceneNode()
10661063
return App::GetGfxScene()->GetSceneManager()->getRootSceneNode();
10671064
}
10681065

1066+
TerrainEditorObjectID_t TerrainObjectManager::FindEditorObjectByInstanceName(std::string const& needle_instance_name)
1067+
{
1068+
// Is this the right 'ModernC++' approach? :/
1069+
auto itor = std::find_if(m_editor_objects.begin(), m_editor_objects.end(),
1070+
[needle_instance_name](TerrainEditorObjectPtr& obj) { return obj->instance_name == needle_instance_name; });
1071+
if (itor != m_editor_objects.end())
1072+
{
1073+
return static_cast<int>(std::distance(m_editor_objects.begin(), itor));
1074+
}
1075+
else
1076+
{
1077+
return TERRAINEDITOROBJECTID_INVALID;
1078+
}
1079+
}
1080+

source/main/terrain/TerrainObjectManager.h

+4-13
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ class TerrainObjectManager: public RefCountingObject<TerrainObjectManager>
6868
void LoadTObjFile(Ogre::String filename);
6969
bool LoadTerrainObject(const Ogre::String& name, const Ogre::Vector3& pos, const Ogre::Vector3& rot, const Ogre::String& instancename, const Ogre::String& type, float rendering_distance = 0, bool enable_collisions = true, int scripthandler = -1, bool uniquifyMaterial = false);
7070
bool LoadTerrainScript(const Ogre::String& filename);
71-
void MoveObjectVisuals(const Ogre::String& instancename, const Ogre::Vector3& pos);
72-
void unloadObject(const Ogre::String& instancename);
71+
void moveObjectVisuals(const Ogre::String& instancename, const Ogre::Vector3& pos);
72+
void destroyObject(const Ogre::String& instancename);
7373
void LoadTelepoints();
7474
void LoadPredefinedActors();
7575
bool HasPredefinedActors() { return !m_predefined_actors.empty(); };
@@ -114,31 +114,22 @@ class TerrainObjectManager: public RefCountingObject<TerrainObjectManager>
114114
bool freePosition;
115115
};
116116

117-
struct StaticObject
118-
{
119-
Ogre::SceneNode* sceneNode;
120-
Ogre::String instanceName;
121-
bool enabled;
122-
std::vector<int> collBoxes;
123-
std::vector<int> collTris;
124-
};
125-
126117
// ODef processing functions
127118

128119
RoR::ODefDocument* FetchODef(std::string const & odef_name);
129-
void ProcessODefCollisionBoxes(StaticObject* obj, ODefDocument* odef, const TerrainEditorObjectPtr& params, bool race_event);
120+
void ProcessODefCollisionBoxes(TerrainEditorObjectPtr obj, ODefDocument* odef, const TerrainEditorObjectPtr& params, bool race_event);
130121

131122
// Misc functions
132123

133124
bool UpdateAnimatedObjects(float dt);
125+
TerrainEditorObjectID_t FindEditorObjectByInstanceName(std::string const& instance_name); //!< Returns offset to `m_editor_objects` or -1 if not found.
134126

135127
// Variables
136128

137129
LocalizerVec m_localizers;
138130
std::unordered_map<std::string, std::shared_ptr<RoR::ODefDocument>> m_odef_cache;
139131
std::vector<TObjDocumentPtr> m_tobj_cache;
140132
int m_tobj_cache_active_id = -1;
141-
std::map<std::string, StaticObject> m_static_objects;
142133
TerrainEditorObjectPtrVec m_editor_objects;
143134
std::vector<PredefinedActor> m_predefined_actors;
144135
std::vector<AnimatedObject> m_animated_objects;

0 commit comments

Comments
 (0)