TrinityCore / TrinityCore/TrinityCore
GameObject Spawn Visual Duplicate [3.3.5]
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 10.8k
- Forks
- 6.4k
- Avg merge
- 3d 16m
- Merged PRs (30d)
- 6
Description
Description
I think this might be a general issue if you try to spawn a gameobject without using a trigger/dummy npc or other worldobject.
The .gobject add command works fine if you spawn the gameobject in the same area where you are but if in my case I tried to create a custom battleground by spawning gameobjects without a dummy/trigger invisible NPCs resulted in a duplicated visual gameobject and I can click on both.
I made a video of the behaviour: https://youtu.be/lUVOrVZvZDc
Expected behaviour
Shouldn't spawn duplicate the same gameobject if no players are around the zone/area or map I believe.
Steps to reproduce the problem
I am building a city battle script, using flags like in arathi basin, 1 in ironforge and 1 and orgrimmar.
I didn't use any invisible NPCs to spawn the flags, I purely do like this:
void CustomCityBattle::SpawnBanner(uint32 objectId, Map* map, float x, float y, float z, float o)
{
if (!objectId)
return;
GameObjectTemplate const* objectInfo = sObjectMgr->GetGameObjectTemplate(objectId);
if (!objectInfo)
return;
if (objectInfo->displayId && !sGameObjectDisplayInfoStore.LookupEntry(objectInfo->displayId))
return;
GameObject* object = new GameObject();
ObjectGuid::LowType guidLow = map->GenerateLowGuid<HighGuid::GameObject>();
TC_LOG_INFO("server.worldserver", "CityBattle: Preparing banner (Entry: {}, Map: {}, Position: {}, {}, {}, {})", objectId, map->GetId(), x, y, z, o);
QuaternionData rot = QuaternionData::fromEulerAnglesZYX(o, 0.f, 0.f);
if (!object->Create(guidLow, objectInfo->entry, map, PHASEMASK_NORMAL, Position(x,y,z,o), rot, 255, GO_STATE_READY))
{
delete object;
return;
}
// fill the gameobject data and save to the db
object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), PHASEMASK_NORMAL);
guidLow = object->GetSpawnId();
// delete the old object and do a clean load from DB with a fresh new GameObject instance.
// this is required to avoid weird behavior and memory leaks
object->RemoveFromWorld();
delete object;
object = new GameObject();
// this will generate a new guid if the object is in an instance
if (!object->LoadFromDB(guidLow, map, true))
{
delete object;
return;
}
/// @todo is it really necessary to add both the real and DB table guid here ?
sObjectMgr->AddGameobjectToGrid(guidLow, sObjectMgr->GetGameObjectData(guidLow));
mSpawnedBanners[guidLow] = { objectId, map->GetId() };
TC_LOG_INFO("server.worldserver", "CityBattle: Spawned banner (Entry: {}, Map: {}, Position: {}, {}, {}, {})", objectId, map->GetId(), x, y, z, o);
}
I used the logic from here: https://github.com/TrinityCore/TrinityCore/blob/3.3.5/src/server/scripts/Commands/cs_gobject.cpp#L105 from the cs_gobject.cpp the ".gobject add" command
Branch
3.3.5
TC rev. hash/commit
https://github.com/TrinityCore/TrinityCore/commit/bacbcb5c1958c7074a852c0d9499a0eeac78f348
Operating system
Windows 11 x64
Custom changes
None
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the .gobject add implementation in src/server/scripts/Commands/cs_gobject.cpp around the referenced line, then compare it with CustomCityBattle::SpawnBanner and its SaveToDB/LoadFromDB sequence. Reproduce the spawn in a custom battleground without nearby players or dummy NPCs and trace when both visuals become clickable. Done means the same gameobject is represented only once in that scenario.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100