From b3a061cb794df6b86e38f17518eed10b76978312 Mon Sep 17 00:00:00 2001 From: Omar Aglan Date: Mon, 28 Sep 2026 17:42:23 +0300 Subject: [PATCH 1/3] bugfix(worldbuilder): Handle null boundary lookup output --- Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp | 4 +++- GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp b/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp index 09bbaf42c5b..5d171bdba48 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp @@ -3442,5 +3442,7 @@ void WorldHeightMapEdit::findBoundaryNear(Coord3D *pt, float okDistance, Int *ou } (*outNdx) = -1; - (*outHandle) = -1; + if (outHandle) { + (*outHandle) = -1; + } } diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp index e409b2a42f2..291abf35cd4 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp @@ -3442,5 +3442,7 @@ void WorldHeightMapEdit::findBoundaryNear(Coord3D *pt, float okDistance, Int *ou } (*outNdx) = -1; - (*outHandle) = -1; + if (outHandle) { + (*outHandle) = -1; + } } From f2a327ecaf45f2fd1bc24a477d9f894e8c911f45 Mon Sep 17 00:00:00 2001 From: Omar Aglan Date: Sat, 10 Oct 2026 19:09:22 +0300 Subject: [PATCH 2/3] fix(worldbuilder): Handle nulls in object editing and undo --- .../W3DDevice/GameClient/WorldHeightMap.cpp | 4 +++- .../Code/Tools/WorldBuilder/src/CUndoable.cpp | 8 +++++++- .../WorldBuilder/src/EditObjectParameter.cpp | 2 +- .../Tools/WorldBuilder/src/WHeightMapEdit.cpp | 16 ++++++++++------ .../Code/Tools/WorldBuilder/src/CUndoable.cpp | 8 +++++++- .../WorldBuilder/src/EditObjectParameter.cpp | 2 +- .../Tools/WorldBuilder/src/WHeightMapEdit.cpp | 16 ++++++++++------ 7 files changed, 39 insertions(+), 17 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp index 15ad78d9b47..33d863d30a2 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp @@ -330,7 +330,9 @@ void MapObject::fastAssignAllUniqueIDs() void MapObject::setThingTemplate(const ThingTemplate *thing) { m_thingTemplate = thing; - m_objectName = thing->getName(); + if (thing) { + m_objectName = thing->getName(); + } } diff --git a/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp b/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp index 07ef6c87e26..a8625f84c96 100644 --- a/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp @@ -32,6 +32,7 @@ #include "GameLogic/SidesList.h" #include "W3DDevice/GameClient/HeightMap.h" #include "Common/Debug.h" +#include "Common/ThingTemplate.h" #include "mapobjectprops.h" #include "ObjectOptions.h" #include "BuildList.h" @@ -346,6 +347,8 @@ MoveInfo::MoveInfo( MapObject *pObjToMove): m_oldLocation = *m_objectToModify->getLocation(); m_newThing = m_objectToModify->getThingTemplate(); m_oldThing = m_objectToModify->getThingTemplate(); + m_newName = m_objectToModify->getName(); + m_oldName = m_objectToModify->getName(); } // @@ -375,6 +378,9 @@ void MoveInfo::SetZOffset(CWorldBuilderDoc *pDoc, Real z) void MoveInfo::SetThingTemplate(CWorldBuilderDoc *pDoc, const ThingTemplate* thing) { m_newThing = thing; + if (thing && thing != m_oldThing) { + m_newName = thing->getName(); + } DoMove(pDoc); } @@ -421,7 +427,7 @@ void MoveInfo::UndoMove(CWorldBuilderDoc *pDoc) if (m_newThing != m_oldThing) { m_objectToModify->setThingTemplate(m_oldThing); } - if (m_newName != m_oldName) { + if (m_newName != m_oldName || m_newThing != m_oldThing) { m_objectToModify->setName(m_oldName); } } diff --git a/Generals/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp b/Generals/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp index 8b27855b125..e90f7a2d1a5 100644 --- a/Generals/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp @@ -101,7 +101,7 @@ BOOL EditObjectParameter::OnInitDialog() void EditObjectParameter::addObject( const ThingTemplate *thingTemplate ) { HTREEITEM parent = TVI_ROOT; - const char *leafName; + const char *leafName = nullptr; // // if we have an thing template in mapObject, we've read it from the new INI database, // we will sort those items into the tree based on properties of the template that diff --git a/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp b/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp index 5d171bdba48..8932a15ee66 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp @@ -2006,6 +2006,8 @@ void WorldHeightMapEdit::addObject(MapObject *pMapObj) void WorldHeightMapEdit::removeFirstObject() { MapObject *firstObj = MapObject::TheMapObjectListPtr; + if (!firstObj) + return; MapObject::TheMapObjectListPtr = firstObj->getNext(); firstObj->setNextMap(nullptr); // so we don't delete the whole list. deleteInstance(firstObj); @@ -2045,20 +2047,22 @@ Bool WorldHeightMapEdit::selectDuplicates() } if (pObj->getFlag(FLAG_ROAD_FLAGS)) { - if (pObj->getNext() == nullptr) continue; if (!pObj->getFlag(FLAG_ROAD_POINT1)) { continue; } if (!prevObj->getFlag(FLAG_ROAD_POINT1)) { continue; } - Coord3D nextLoc = *pObj->getNext()->getLocation(); - prevObj = prevObj->getNext(); - if (!prevObj) continue; - if (!prevObj->getFlag(FLAG_ROAD_POINT2)) { + MapObject *nextObj = pObj->getNext(); + if (!nextObj || !nextObj->getFlag(FLAG_ROAD_POINT2)) { + continue; + } + MapObject *prevNextObj = prevObj->getNext(); + if (!prevNextObj || prevNextObj == pObj || !prevNextObj->getFlag(FLAG_ROAD_POINT2)) { continue; } - prevLoc = *prevObj->getLocation(); + Coord3D nextLoc = *nextObj->getLocation(); + prevLoc = *prevNextObj->getLocation(); if (abs(nextLoc.x-prevLoc.x)>DELTA) { continue; // locations don't match. } diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp index 6da9de3268e..28a5c8cde36 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp @@ -32,6 +32,7 @@ #include "GameLogic/SidesList.h" #include "W3DDevice/GameClient/HeightMap.h" #include "Common/Debug.h" +#include "Common/ThingTemplate.h" #include "mapobjectprops.h" #include "ObjectOptions.h" #include "BuildList.h" @@ -346,6 +347,8 @@ MoveInfo::MoveInfo( MapObject *pObjToMove): m_oldLocation = *m_objectToModify->getLocation(); m_newThing = m_objectToModify->getThingTemplate(); m_oldThing = m_objectToModify->getThingTemplate(); + m_newName = m_objectToModify->getName(); + m_oldName = m_objectToModify->getName(); } // @@ -375,6 +378,9 @@ void MoveInfo::SetZOffset(CWorldBuilderDoc *pDoc, Real z) void MoveInfo::SetThingTemplate(CWorldBuilderDoc *pDoc, const ThingTemplate* thing) { m_newThing = thing; + if (thing && thing != m_oldThing) { + m_newName = thing->getName(); + } DoMove(pDoc); } @@ -421,7 +427,7 @@ void MoveInfo::UndoMove(CWorldBuilderDoc *pDoc) if (m_newThing != m_oldThing) { m_objectToModify->setThingTemplate(m_oldThing); } - if (m_newName != m_oldName) { + if (m_newName != m_oldName || m_newThing != m_oldThing) { m_objectToModify->setName(m_oldName); } } diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp index a976d629526..98bd6362665 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp @@ -101,7 +101,7 @@ BOOL EditObjectParameter::OnInitDialog() void EditObjectParameter::addObject( const ThingTemplate *thingTemplate ) { HTREEITEM parent = TVI_ROOT; - const char *leafName; + const char *leafName = nullptr; // // if we have an thing template in mapObject, we've read it from the new INI database, // we will sort those items into the tree based on properties of the template that diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp index 291abf35cd4..538a6cdf771 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp @@ -2006,6 +2006,8 @@ void WorldHeightMapEdit::addObject(MapObject *pMapObj) void WorldHeightMapEdit::removeFirstObject() { MapObject *firstObj = MapObject::TheMapObjectListPtr; + if (!firstObj) + return; MapObject::TheMapObjectListPtr = firstObj->getNext(); firstObj->setNextMap(nullptr); // so we don't delete the whole list. deleteInstance(firstObj); @@ -2045,20 +2047,22 @@ Bool WorldHeightMapEdit::selectDuplicates() } if (pObj->getFlag(FLAG_ROAD_FLAGS)) { - if (pObj->getNext() == nullptr) continue; if (!pObj->getFlag(FLAG_ROAD_POINT1)) { continue; } if (!prevObj->getFlag(FLAG_ROAD_POINT1)) { continue; } - Coord3D nextLoc = *pObj->getNext()->getLocation(); - prevObj = prevObj->getNext(); - if (!prevObj) continue; - if (!prevObj->getFlag(FLAG_ROAD_POINT2)) { + MapObject *nextObj = pObj->getNext(); + if (!nextObj || !nextObj->getFlag(FLAG_ROAD_POINT2)) { + continue; + } + MapObject *prevNextObj = prevObj->getNext(); + if (!prevNextObj || prevNextObj == pObj || !prevNextObj->getFlag(FLAG_ROAD_POINT2)) { continue; } - prevLoc = *prevObj->getLocation(); + Coord3D nextLoc = *nextObj->getLocation(); + prevLoc = *prevNextObj->getLocation(); if (abs(nextLoc.x-prevLoc.x)>DELTA) { continue; // locations don't match. } From 8c7652bebba81f99cf69e1534189c07b00416b66 Mon Sep 17 00:00:00 2001 From: Omar Aglan Date: Mon, 12 Oct 2026 23:51:30 +0300 Subject: [PATCH 3/3] fix(worldbuilder): Use MoveInfo names as the single source for object names MoveInfo::DoMove and MoveInfo::UndoMove now always apply the name stored in MoveInfo after the optional template change, instead of deciding with a compound condition whether the name written by MapObject::setThingTemplate needs to be overwritten. --- Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp | 8 ++------ GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp b/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp index a8625f84c96..433b5221b98 100644 --- a/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp @@ -412,9 +412,7 @@ void MoveInfo::DoMove(CWorldBuilderDoc *pDoc) if (m_newThing != m_oldThing) { m_objectToModify->setThingTemplate(m_newThing); } - if (m_newName != m_oldName) { - m_objectToModify->setName(m_newName); - } + m_objectToModify->setName(m_newName); } void MoveInfo::UndoMove(CWorldBuilderDoc *pDoc) @@ -427,9 +425,7 @@ void MoveInfo::UndoMove(CWorldBuilderDoc *pDoc) if (m_newThing != m_oldThing) { m_objectToModify->setThingTemplate(m_oldThing); } - if (m_newName != m_oldName || m_newThing != m_oldThing) { - m_objectToModify->setName(m_oldName); - } + m_objectToModify->setName(m_oldName); } /************************************************************************* diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp index 28a5c8cde36..5bda3c9540c 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/CUndoable.cpp @@ -412,9 +412,7 @@ void MoveInfo::DoMove(CWorldBuilderDoc *pDoc) if (m_newThing != m_oldThing) { m_objectToModify->setThingTemplate(m_newThing); } - if (m_newName != m_oldName) { - m_objectToModify->setName(m_newName); - } + m_objectToModify->setName(m_newName); } void MoveInfo::UndoMove(CWorldBuilderDoc *pDoc) @@ -427,9 +425,7 @@ void MoveInfo::UndoMove(CWorldBuilderDoc *pDoc) if (m_newThing != m_oldThing) { m_objectToModify->setThingTemplate(m_oldThing); } - if (m_newName != m_oldName || m_newThing != m_oldThing) { - m_objectToModify->setName(m_oldName); - } + m_objectToModify->setName(m_oldName); } /*************************************************************************