Skip to content

Commit

Permalink
Core/GameObjects: Implemented new gameobject type 11 (transport) stat…
Browse files Browse the repository at this point in the history
…es, fixes elevators in orgrimmar as well as all stoppable elevators

Closes #10019
Closes #12747
Closes #13194
  • Loading branch information
Shauren committed Sep 29, 2014
1 parent 977b5f4 commit 83668e8
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 25 deletions.
109 changes: 101 additions & 8 deletions src/server/game/Entities/GameObject/GameObject.cpp
Expand Up @@ -69,6 +69,8 @@ GameObject::~GameObject()
{
delete m_AI;
delete m_model;
if (m_goInfo->type == GAMEOBJECT_TYPE_TRANSPORT)
delete m_goValue.Transport.StopFrames;
//if (m_uint32Values) // field array can be not exist if GameOBject not loaded
// CleanupsBeforeDelete();
}
Expand Down Expand Up @@ -239,13 +241,29 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 /*phase
SetUInt32Value(GAMEOBJECT_PARENTROTATION, m_goInfo->building.destructibleData);
break;
case GAMEOBJECT_TYPE_TRANSPORT:
SetUInt32Value(GAMEOBJECT_LEVEL, goinfo->transport.pause);
SetGoState(goinfo->transport.startOpen ? GO_STATE_ACTIVE : GO_STATE_READY);
SetGoAnimProgress(animprogress);
m_goValue.Transport.PathProgress = 0;
{
m_goValue.Transport.AnimationInfo = sTransportMgr->GetTransportAnimInfo(goinfo->entry);
m_goValue.Transport.PathProgress = (getMSTime() / GetTransportPeriod());
m_goValue.Transport.PathProgress *= GetTransportPeriod();
m_goValue.Transport.CurrentSeg = 0;
m_goValue.Transport.StateUpdateTimer = 0;
m_goValue.Transport.StopFrames = new std::vector<uint32>();
if (goinfo->transport.stopFrame1 > 0)
m_goValue.Transport.StopFrames->push_back(goinfo->transport.stopFrame1);
if (goinfo->transport.stopFrame2 > 0)
m_goValue.Transport.StopFrames->push_back(goinfo->transport.stopFrame3);
if (goinfo->transport.stopFrame3 > 0)
m_goValue.Transport.StopFrames->push_back(goinfo->transport.stopFrame3);
if (goinfo->transport.stopFrame4 > 0)

This comment has been minimized.

Copy link
@runningnak3d

runningnak3d Oct 18, 2014

Contributor

Derr should have looked at later commits....

m_goValue.Transport.StopFrames->push_back(goinfo->transport.stopFrame4);
if (goinfo->transport.startOpen)
SetTransportState(GO_STATE_TRANSPORT_STOPPED, goinfo->transport.startOpen - 1);
else
SetTransportState(GO_STATE_TRANSPORT_ACTIVE);

SetGoAnimProgress(animprogress);
break;
}
case GAMEOBJECT_TYPE_FISHINGNODE:
SetGoAnimProgress(0);
break;
Expand Down Expand Up @@ -309,11 +327,11 @@ void GameObject::Update(uint32 diff)
if (!m_goValue.Transport.AnimationInfo)
break;

if (GetGoState() == GO_STATE_READY)
if (GetGoState() == GO_STATE_TRANSPORT_ACTIVE)
{
m_goValue.Transport.PathProgress += diff;
/* TODO: Fix movement in unloaded grid - currently GO will just disappear
uint32 timer = m_goValue.Transport.PathProgress % m_goValue.Transport.AnimationInfo->TotalTime;
uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod();
TransportAnimationEntry const* node = m_goValue.Transport.AnimationInfo->GetAnimNode(timer);
if (node && m_goValue.Transport.CurrentSeg != node->TimeSeg)
{
Expand All @@ -333,6 +351,18 @@ void GameObject::Update(uint32 diff)
GetMap()->GameObjectRelocation(this, pos.x, pos.y, pos.z, GetOrientation());
}
*/

if (!m_goValue.Transport.StopFrames->empty())
{
uint32 visualStateBefore = (m_goValue.Transport.StateUpdateTimer / 20000) & 1;
m_goValue.Transport.StateUpdateTimer += diff;
uint32 visualStateAfter = (m_goValue.Transport.StateUpdateTimer / 20000) & 1;
if (visualStateBefore != visualStateAfter)
{
ForceValuesUpdateAtIndex(GAMEOBJECT_LEVEL);
ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
}
}
}
break;
}
Expand Down Expand Up @@ -934,7 +964,7 @@ bool GameObject::IsDynTransport() const
if (!gInfo)
return false;

return gInfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT || (gInfo->type == GAMEOBJECT_TYPE_TRANSPORT && !gInfo->transport.pause);
return gInfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT || (gInfo->type == GAMEOBJECT_TYPE_TRANSPORT && m_goValue.Transport.StopFrames->empty());
}

bool GameObject::IsDestructibleBuilding() const
Expand Down Expand Up @@ -2079,6 +2109,38 @@ void GameObject::SetGoState(GOState state)
}
}

uint32 GameObject::GetTransportPeriod() const
{
ASSERT(GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT);
if (m_goValue.Transport.AnimationInfo)
return m_goValue.Transport.AnimationInfo->TotalTime;

// return something that will nicely divide for GAMEOBJECT_DYNAMIC value calculation
return m_goValue.Transport.PathProgress;
}

void GameObject::SetTransportState(GOState state, uint32 stopFrame /*= 0*/)
{
if (GetGoState() == state)
return;

ASSERT(GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT);
ASSERT(state >= GO_STATE_TRANSPORT_ACTIVE);
if (state == GO_STATE_TRANSPORT_ACTIVE)
{
m_goValue.Transport.StateUpdateTimer = 0;
m_goValue.Transport.PathProgress = getMSTime() + m_goValue.Transport.StopFrames->at(GetGoState() - GO_STATE_TRANSPORT_STOPPED);
SetGoState(GO_STATE_TRANSPORT_ACTIVE);
}
else
{
ASSERT(state < GO_STATE_TRANSPORT_STOPPED + MAX_GO_STATE_TRANSPORT_STOP_FRAMES);
ASSERT(stopFrame < m_goValue.Transport.StopFrames->size());
m_goValue.Transport.PathProgress = getMSTime() + m_goValue.Transport.StopFrames->at(stopFrame);
SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + stopFrame));
}
}

void GameObject::SetDisplayId(uint32 displayid)
{
SetUInt32Value(GAMEOBJECT_DISPLAYID, displayid);
Expand Down Expand Up @@ -2175,6 +2237,7 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
if (!target)
return;

bool isStoppableTransport = GetGoType() == GAMEOBJECT_TYPE_TRANSPORT && !m_goValue.Transport.StopFrames->empty();
bool forcedFlags = GetGoType() == GAMEOBJECT_TYPE_CHEST && GetGOInfo()->chest.groupLootRules && HasLootRecipient();
bool targetIsGM = target->IsGameMaster();

Expand Down Expand Up @@ -2217,9 +2280,18 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
if (ActivateToQuest(target))
dynFlags |= GO_DYNFLAG_LO_SPARKLE;
break;
case GAMEOBJECT_TYPE_TRANSPORT:
{
float timer = float(m_goValue.Transport.PathProgress % GetTransportPeriod());
pathProgress = int16(timer / float(GetTransportPeriod()) * 65535.0f);
break;
}
case GAMEOBJECT_TYPE_MO_TRANSPORT:
pathProgress = int16(float(m_goValue.Transport.PathProgress) / float(GetUInt32Value(GAMEOBJECT_LEVEL)) * 65535.0f);
{
float timer = float(m_goValue.Transport.PathProgress % GetUInt32Value(GAMEOBJECT_LEVEL));
pathProgress = int16(timer / float(GetUInt32Value(GAMEOBJECT_LEVEL)) * 65535.0f);
break;
}
default:
break;
}
Expand All @@ -2236,6 +2308,27 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t

fieldBuffer << flags;
}
else if (index == GAMEOBJECT_LEVEL)
{
if (isStoppableTransport)
fieldBuffer << uint32(m_goValue.Transport.PathProgress);
else
fieldBuffer << m_uint32Values[index];
}
else if (index == GAMEOBJECT_BYTES_1)
{
uint32 bytes1 = m_uint32Values[index];
if (isStoppableTransport && GetGoState() == GO_STATE_TRANSPORT_ACTIVE)
{
if ((m_goValue.Transport.StateUpdateTimer / 20000) & 1)

This comment has been minimized.

Copy link
@karelsimanek

karelsimanek Oct 5, 2014

Could you explain, why 20000 ?

This comment has been minimized.

Copy link
@Shauren

Shauren Oct 5, 2014

Author Member

20 seconds, that was the timing found in all sniffs

This comment has been minimized.

Copy link
@karelsimanek

karelsimanek Oct 5, 2014

So if i get it right, every 20s its stopped if its active?

This comment has been minimized.

Copy link
@Shauren

Shauren Oct 5, 2014

Author Member

No. This sends a "update state" command to client so it keeps running after starting

{
bytes1 &= 0xFFFFFF00;
bytes1 |= GO_STATE_TRANSPORT_STOPPED;
}
}

fieldBuffer << bytes1;
}
else
fieldBuffer << m_uint32Values[index]; // other cases
}
Expand Down
17 changes: 15 additions & 2 deletions src/server/game/Entities/GameObject/GameObject.h
Expand Up @@ -193,11 +193,17 @@ struct GameObjectTemplate
//11 GAMEOBJECT_TYPE_TRANSPORT
struct
{
uint32 pause; //0
int32 stopFrame1; //0
uint32 startOpen; //1
uint32 autoCloseTime; //2 secs till autoclose = autoCloseTime / 0x10000
uint32 pause1EventID; //3
uint32 pause2EventID; //4
uint32 mapId; //5
int32 stopFrame2; //6
uint32 unknown;
int32 stopFrame3; //8
uint32 unknown2;
int32 stopFrame4; //10
} transport;
//12 GAMEOBJECT_TYPE_AREADAMAGE
struct
Expand Down Expand Up @@ -552,6 +558,8 @@ union GameObjectValue
uint32 PathProgress;
TransportAnimation const* AnimationInfo;
uint32 CurrentSeg;
std::vector<uint32>* StopFrames;
uint32 StateUpdateTimer;
} Transport;
//25 GAMEOBJECT_TYPE_FISHINGHOLE
struct
Expand Down Expand Up @@ -582,10 +590,13 @@ enum GOState
{
GO_STATE_ACTIVE = 0, // show in world as used and not reset (closed door open)
GO_STATE_READY = 1, // show in world as ready (closed door close)
GO_STATE_ACTIVE_ALTERNATIVE = 2 // show in world as used in alt way and not reset (closed door open by cannon fire)
GO_STATE_ACTIVE_ALTERNATIVE = 2, // show in world as used in alt way and not reset (closed door open by cannon fire)
GO_STATE_TRANSPORT_ACTIVE = 24,
GO_STATE_TRANSPORT_STOPPED = 25
};

#define MAX_GO_STATE 3
#define MAX_GO_STATE_TRANSPORT_STOP_FRAMES 9

// from `gameobject`
struct GameObjectData
Expand Down Expand Up @@ -720,6 +731,8 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
void SetGoState(GOState state);
uint32 GetTransportPeriod() const;
void SetTransportState(GOState state, uint32 stopFrame = 0);
uint8 GetGoArtKit() const { return GetByteValue(GAMEOBJECT_BYTES_1, 2); }
void SetGoArtKit(uint8 artkit);
uint8 GetGoAnimProgress() const { return GetByteValue(GAMEOBJECT_BYTES_1, 3); }
Expand Down
13 changes: 9 additions & 4 deletions src/server/game/Entities/Object/Object.cpp
Expand Up @@ -346,7 +346,11 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
bool hasSpline = false;
bool hasSplineElevation = false;

uint32 unkLoopCounter = 0;
uint32 stopFrameCount = 0;
if (GameObject const* go = ToGameObject())
if (go->GetGoType() == GAMEOBJECT_TYPE_TRANSPORT)
stopFrameCount = go->GetGOValue()->Transport.StopFrames->size();

// Bit content
data->WriteBit(0);
data->WriteBit(0);
Expand All @@ -356,7 +360,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
data->WriteBit(flags & UPDATEFLAG_SELF);
data->WriteBit(flags & UPDATEFLAG_VEHICLE);
data->WriteBit(flags & UPDATEFLAG_LIVING);
data->WriteBits(unkLoopCounter, 24);
data->WriteBits(stopFrameCount, 24);
data->WriteBit(0);
data->WriteBit(flags & UPDATEFLAG_GO_TRANSPORT_POSITION);
data->WriteBit(flags & UPDATEFLAG_STATIONARY_POSITION);
Expand Down Expand Up @@ -471,8 +475,9 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
data->FlushBits();

// Data
for (uint32 i = 0; i < unkLoopCounter; ++i)
*data << uint32(0);
if (GameObject const* go = ToGameObject())
for (uint32 i = 0; i < stopFrameCount; ++i)
*data << uint32(go->GetGOValue()->Transport.StopFrames->at(i));

if (flags & UPDATEFLAG_LIVING)
{
Expand Down
5 changes: 4 additions & 1 deletion src/server/game/Entities/Player/Player.cpp
Expand Up @@ -23046,7 +23046,10 @@ template<>
inline void UpdateVisibilityOf_helper(GuidSet& s64, GameObject* target, std::set<Unit*>& /*v*/)
{
// @HACK: This is to prevent objects like deeprun tram from disappearing when player moves far from its spawn point while riding it
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
// But exclude stoppable elevators from this hack - they would be teleporting from one end to another
// if affected transports move so far horizontally that it causes them to run out of visibility range then you are out of luck
// fix visibility instead of adding hacks here
if (!target->IsDynTransport())
s64.insert(target->GetGUID());
}

Expand Down
7 changes: 5 additions & 2 deletions src/server/game/Globals/ObjectMgr.cpp
Expand Up @@ -2050,8 +2050,11 @@ void ObjectMgr::LoadGameobjects()
uint32 go_state = fields[13].GetUInt8();
if (go_state >= MAX_GO_STATE)
{
TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid `state` (%u) value, skip", guid, data.id, go_state);
continue;
if (gInfo->type != GAMEOBJECT_TYPE_TRANSPORT || go_state > GO_STATE_TRANSPORT_ACTIVE + MAX_GO_STATE_TRANSPORT_STOP_FRAMES)
{
TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid `state` (%u) value, skip", guid, data.id, go_state);
continue;
}
}
data.go_state = GOState(go_state);

Expand Down
Expand Up @@ -490,10 +490,7 @@ class instance_icecrown_citadel : public InstanceMapScript
case GO_LADY_DEATHWHISPER_ELEVATOR:
LadyDeathwisperElevatorGUID = go->GetGUID();
if (GetBossState(DATA_LADY_DEATHWHISPER) == DONE)
{
go->SetUInt32Value(GAMEOBJECT_LEVEL, 0);
go->SetGoState(GO_STATE_READY);
}
go->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
break;
case GO_THE_SKYBREAKER_H:
case GO_ORGRIMS_HAMMER_A:
Expand Down Expand Up @@ -800,10 +797,7 @@ class instance_icecrown_citadel : public InstanceMapScript
SetTeleporterState(teleporter, true);

if (GameObject* elevator = instance->GetGameObject(LadyDeathwisperElevatorGUID))
{
elevator->SetUInt32Value(GAMEOBJECT_LEVEL, 0);
elevator->SetGoState(GO_STATE_READY);
}
elevator->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);

SpawnGunship();
}
Expand Down

8 comments on commit 83668e8

@Palabola
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice GG!

@msoky
Copy link
Contributor

@msoky msoky commented on 83668e8 Sep 29, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx :) and what with GO state=24?

@Aokromes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"fixes elevators in orgrimmar"

@Dekadencee
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice Shauren xP

@VincentVanclef
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EPIC!

@Dekadencee
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msoky: State 24 represent a active transport (movement in progress), 25 stoped transport (static position)

@Shauren
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not just 25 but also 26... up to 33, each of them corresponding to a different stop frame sent in SMSG_UPDATE_OBJECT

@SeTM
Copy link
Contributor

@SeTM SeTM commented on 83668e8 Oct 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Object 218207 have stop frames (https://gist.github.com/SeTM/8ec0d7175bb7599406f8), but not have UPDATE packets or any stopFrameCount in create packet..

Please sign in to comment.