Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom train tracks #250

Closed
wants to merge 70 commits into from
Closed
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
27c72c2
Add custom train tracks
Cazomino05 Jul 8, 2013
2197e5c
Add missing files and fixed compile errors
Cazomino05 Jul 9, 2013
aed13cd
Small custom train tracks fix
Jul 10, 2013
09fce4e
Fix some custom train track crashes
jushar Jan 31, 2014
d4cae83
Fix build and merges for CTT
qaisjp Jul 13, 2016
3a60da9
Fix crash when creating a new track
qaisjp Jul 13, 2016
09e3ee8
Fix FindClosestRailTrackNode to use CTrainTrackManager
qaisjp Jul 13, 2016
1f83de2
clean up a lot of the CTT api
qaisjp Jul 14, 2016
bebe6b5
allow ints for get/setTrainTrack
qaisjp Jul 14, 2016
7e0039b
rework createTrainTrack function
qaisjp Jul 14, 2016
b1f85e4
remove set node position/count
qaisjp Jul 14, 2016
0455429
improve clientside api
qaisjp Jul 15, 2016
5cc1de4
move ResetTracks() call
qaisjp Jul 21, 2016
1f46669
tweak headers
qaisjp Jul 21, 2016
fedd97e
Revert "move ResetTracks() call"
qaisjp Jul 21, 2016
de2676c
Merge branch 'master' into feature/custom-train-tracks
jushar Sep 29, 2016
94349a0
Move new files
jushar Sep 29, 2016
1bbd37b
Remove duplicate track nodes
jushar Sep 29, 2016
72fa62d
Move train track nodes into shared file
jushar Sep 29, 2016
c99498d
Refactor CTrainTrackManagerSA
jushar Sep 30, 2016
fbc95d3
Refactor CTrainTrackSA
jushar Sep 30, 2016
e84d17e
Implement missing functionality in GameSA module
jushar Sep 30, 2016
e58383c
Implement CTrainTrackManager::Reset
jushar Sep 30, 2016
9aa846a
Add required changes to DM module
jushar Sep 30, 2016
9063a3d
Refactor server CTrainTrack*
jushar Sep 30, 2016
19d74ad
Implement all left stuff
jushar Sep 30, 2016
1fb5e1c
Fix a bunch of issues
jushar Oct 1, 2016
b02f96d
More fixes
jushar Oct 1, 2016
3225fd9
Merge branch 'master' into feature/custom-train-tracks
jushar Oct 11, 2016
8203466
Update Lua train tracks API
jushar Oct 11, 2016
81f990a
Re-enable get-/setTrainTrack
jushar Oct 11, 2016
adc94e3
Linux compile fixes
jushar Oct 11, 2016
5709ae9
Fix linkLastNodes==true and document some variables
jushar Oct 12, 2016
62baa4c
Merge branch 'master' into feature/custom-train-tracks
jushar Dec 1, 2016
082f785
Fix issues when destroying a track
jushar Dec 1, 2016
2cf9dfb
Accept a table of track nodes instead of varargs
jushar Dec 1, 2016
bf56f8f
Fix linux compile errors
jushar Dec 1, 2016
f59bc41
Merge branch 'master' into feature/custom-train-tracks
jushar Jan 15, 2017
5782e59
Use 2d length for track length calculation
jushar Jan 15, 2017
79407b5
Merge branch 'master' into feature/custom-train-tracks
jushar Jan 29, 2017
5d743da
Fix default track sync
jushar Jan 30, 2017
1565ab5
Merge branch 'master' into feature/custom-train-tracks
qaisjp Jul 22, 2018
d09969b
Tweak train track oop
qaisjp Jul 22, 2018
e62edbb
Merge branch 'master' into feature/custom-train-tracks
qaisjp Jul 22, 2018
39945b1
Merge branch 'master' into feature/custom-train-tracks
qaisjp Jul 23, 2018
a905fd8
Merge branch 'master' into feature/custom-train-tracks
qaisjp Aug 27, 2018
5b6ee37
Merge branch 'master' into feature/custom-train-tracks
qaisjp Sep 26, 2018
a59dca4
Add client veh train track oopdefs
qaisjp Sep 26, 2018
7e56130
Merge branch 'master' into feature/custom-train-tracks
qaisjp Sep 4, 2019
f8b5d9c
Fix build by applying refactors from master
qaisjp Sep 4, 2019
7fe49d9
Fix crash when using tram
qaisjp Sep 7, 2019
c1758fa
Fix default track sync issue introduced in 5d743da34d9
qaisjp Sep 7, 2019
8e2fb7b
Merge commit 'master' into feature/custom-train-tracks
qaisjp Sep 16, 2019
7426bb0
Merge branch 'master' into feature/custom-train-tracks
qaisjp Sep 16, 2019
c2742ea
Merge branch 'master' into feature/custom-train-tracks
qaisjp Jan 7, 2020
dff4f6c
Merge branch 'master' into feature/custom-train-tracks
qaisjp Oct 12, 2020
5a2e8ae
Fix line endings
qaisjp Oct 12, 2020
7442da7
Fix IterBegin not being present
qaisjp Oct 12, 2020
33b6674
Mute extra whitespace annoyance
qaisjp Oct 12, 2020
15a8acf
Don't use asm for createMissionTrain
qaisjp Oct 12, 2020
84e0c70
Return normal numbers for getTrackNodePosition
qaisjp Oct 12, 2020
18916b8
Prevent empty tracks from being created because it crashes
qaisjp Oct 13, 2020
fff401e
Merge branch 'master' into feature/custom-train-tracks
qaisjp Oct 16, 2020
c874a80
Fix build
qaisjp Oct 17, 2020
a4217e5
tweak some formatting
qaisjp Oct 17, 2020
3cecd29
Use new parser for some shared things
qaisjp Oct 17, 2020
884fe2b
Remove "Track" from (Get|Set)TrackNodePosition
qaisjp Oct 17, 2020
6217a8b
Reimplement Lua API in new parser
qaisjp Oct 17, 2020
6eba15f
Tweak some defines
qaisjp Oct 17, 2020
a2569ad
Merge branch 'master' into feature/custom-train-tracks
patrikjuvonen Dec 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Client/game_sa/CGameSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ CGameSA::CGameSA()
this->m_pWaterManager = new CWaterManagerSA();
this->m_pWeaponStatsManager = new CWeaponStatManagerSA();
this->m_pPointLights = new CPointLightsSA();
this->m_pTrainTrackManager = new CTrainTrackManagerSA();

// Normal weapon types (WEAPONSKILL_STD)
for (int i = 0; i < NUM_WeaponInfosStdSkill; i++)
Expand Down Expand Up @@ -258,6 +259,7 @@ CGameSA::~CGameSA()
delete reinterpret_cast<CAEAudioHardwareSA*>(m_pAEAudioHardware);
delete reinterpret_cast<CAudioContainerSA*>(m_pAudioContainer);
delete reinterpret_cast<CPointLightsSA*>(m_pPointLights);
delete reinterpret_cast<CTrainTrackManagerSA*>(m_pTrainTrackManager);
}

CWeaponInfo* CGameSA::GetWeaponInfo(eWeaponType weapon, eWeaponSkill skill)
Expand Down
2 changes: 2 additions & 0 deletions Client/game_sa/CGameSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ class CGameSA : public CGame
CWaterManager* GetWaterManager() { return m_pWaterManager; }
CWeaponStatManager* GetWeaponStatManager() { return m_pWeaponStatsManager; }
CPointLights* GetPointLights() { return m_pPointLights; }
CTrainTrackManager* GetTrainTrackManager() { return m_pTrainTrackManager; }
CRenderWareSA* GetRenderWareSA() { return m_pRenderWare; }
CFxManagerSA* GetFxManagerSA() { return m_pFxManager; }

Expand Down Expand Up @@ -466,6 +467,7 @@ class CGameSA : public CGame
CWeaponStatManager* m_pWeaponStatsManager;
CPointLights* m_pPointLights;
CObjectGroupPhysicalProperties* m_pObjectGroupPhysicalProperties;
CTrainTrackManager* m_pTrainTrackManager;

CPad* m_pPad;
CTheCarGenerators* m_pTheCarGenerators;
Expand Down
51 changes: 29 additions & 22 deletions Client/game_sa/CPoolsSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,8 @@ CBuilding* CPoolsSA::AddBuilding(DWORD dwModelID)
return NULL;
}

CVehicle* CPoolsSA::AddTrain(CClientVehicle* pClientVehicle, CVector* vecPosition, DWORD dwModels[], int iSize, bool bDirection, uchar ucTrackId)

CVehicle* CPoolsSA::AddTrain(CClientVehicle* pClientVehicle, CVector * vecPosition, DWORD dwModels[], int iSize, bool bDirection, CTrainTrack* pTrainTrack)
{
DEBUG_TRACE("CVehicle* CPoolsSA::AddTrain ( CClientVehicle* pClientVehicle, CVector * vecPosition, DWORD dwModels[], int iSize, bool bDirection )");

Expand Down Expand Up @@ -871,28 +872,34 @@ CVehicle* CPoolsSA::AddTrain(CClientVehicle* pClientVehicle, CVector* vecPositio

// Find closest track node
float fRailDistance;
int iNodeId = pGame->GetWorld()->FindClosestRailTrackNode(*vecPosition, ucTrackId, fRailDistance);
int iDesiredTrackId = ucTrackId;
auto pTrainTrackManager = g_pCore->GetGame()->GetTrainTrackManager();

DWORD dwFunc = FUNC_CTrain_CreateMissionTrain;
_asm
{
push 0 // place as close to point as possible (rather than at node)? (maybe) (actually seems to have an effect on the speed, so changed from
// 1 to 0)
push iDesiredTrackId // track ID
push iNodeId // node to start at (-1 for closest node)
lea ecx, pTrainEnd
push ecx // end of train
lea ecx, pTrainBeginning
push ecx // begining of train
push 0 // train type (always use 0 as thats where we're writing to)
push bDirection // direction
push fZ // z
push fY // y
push fX // x
call dwFunc
add esp, 0x28
}
auto nodeIndex = pGame->GetWorld()->FindClosestRailTrackNode(*vecPosition, pTrainTrack, fRailDistance); // TODO
uint desiredTrackId = pTrainTrack->GetIndex();

// TODO(qaisjp): this actually returns a CTrainSA, but we don't have that class!
typedef CVehicleSA*(__cdecl* CTrain_CreateMissionTrain)(float fX, float fY, float fZ, bool bDirection, int trainType, CVehicleSAInterface** pTrainBeginning,
CVehicleSAInterface** pTrainEnd, unsigned int nodeIndex, unsigned int desiredTrackId, char unk);
CTrain_CreateMissionTrain createMissionTrain = (CTrain_CreateMissionTrain)(FUNC_CTrain_CreateMissionTrain);

createMissionTrain(
fX, fY, fZ, bDirection,

// NOTE(qaisjp): I have no idea what the below comment means
// train type (always use 0 as thats where we're writing to)
0,

&pTrainBeginning, &pTrainEnd,

// Node to start at (-1 for closest node)
nodeIndex,

// track ID
desiredTrackId,

// NOTE(qaisjp): I have no idea what the below comment is talking about.
// place as close to point as possible (rather than at node)? (maybe) (actually seems to have an effect on the speed, so changed from 1 to 0)
0);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is one problem: you can't set the train position of streamed out trains. Try placing two trains (t1 and t21) on the same track, near each other (trainPositions p1 and p2). Then disconnect, and use your server console to place them at the exact same position (set p1 = p2). Then reconnect (or restart the game and reconnect) and you'll find that the trains have moved.

TODO: we could set the train position here? otherwise the client's train will not match what the server requested it to be. there might be a better time for setting the train position than here, though, such as when the train streams in

// Enable GetVehicle
m_bGetVehicleEnabled = true;
Expand Down
2 changes: 1 addition & 1 deletion Client/game_sa/CPoolsSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class CPoolsSA : public CPools
// Others
CBuilding* AddBuilding(DWORD dwModelID);
void DeleteAllBuildings();
CVehicle* AddTrain(CClientVehicle* pClientVehicle, CVector* vecPosition, DWORD dwModels[], int iSize, bool bDirection, uchar ucTrackId = 0xFF);
CVehicle* AddTrain(CClientVehicle* pClientVehicle, CVector* vecPosition, DWORD dwModels[], int iSize, bool bDirection, CTrainTrack* pTrainTrack = nullptr);

DWORD GetPedPoolIndex(std::uint8_t* pInterface);
DWORD GetVehiclePoolIndex(std::uint8_t* pInterfacee);
Expand Down
188 changes: 188 additions & 0 deletions Client/game_sa/CTrainTrackManagerSA.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CTrainTrackManagerSA.cpp
* PURPOSE: Train Node Manager class
* DEVELOPERS: Cazomino05 <Cazomino05@gmail.com>
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/
#include "StdInc.h"
#include <algorithm>
#include "CTrainTrackSA.h"

CTrainTrackManagerSA::CTrainTrackManagerSA()
{
// Disable CTrain::InitTrains
MemPut(0x6F7440, 0xC3); // Write retn
}

CTrainTrack* CTrainTrackManagerSA::CreateTrainTrack(const std::vector<STrackNode>& nodes, bool bLinkedLastNode)
{
if (m_Tracks.size() >= 255)
return nullptr;

// Dynamically allocate new track
auto index = AllocateTrainTrackIndex();
auto pTrainTrack = std::make_unique<CTrainTrackSA>(index, nodes, bLinkedLastNode, this);

// Add to tracks list
m_Tracks.push_back(std::move(pTrainTrack));

// Patch track count
PatchNumberOfTracks(static_cast<std::uint8_t>(m_Tracks.size()));

return m_Tracks.back().get();
}

void CTrainTrackManagerSA::UpdateTrackData(CTrainTrackSA* pTrainTrack)
{
auto trackIndex = pTrainTrack->GetIndex();

// Update length
m_TrackLengths[trackIndex] = pTrainTrack->GetLength();

// Update track nodes amount
m_NumberOfTrackNodes[trackIndex] = pTrainTrack->GetNumberOfNodes();

// Update nodes pointers in array
m_TrackNodePointers[trackIndex] = pTrainTrack->GetNodesData();
}

CTrainTrack* CTrainTrackManagerSA::GetTrainTrackByIndex(uint trackIndex)
{
auto iter = std::find_if(m_Tracks.begin(), m_Tracks.end(), [trackIndex](auto& pTrainTrack) { return pTrainTrack->GetIndex() == trackIndex; });
if (iter == m_Tracks.end())
return nullptr;

return iter->get();
}

void CTrainTrackManagerSA::DestroyTrainTrack(CTrainTrack* pTrainTrack)
{
// Remove track from arrays
auto trackIndex = pTrainTrack->GetIndex();
m_TrackNodePointers[trackIndex] = nullptr; // Mark as free
m_TrackLengths[trackIndex] = 0.0f;
m_NumberOfTrackNodes[trackIndex] = 0;

// Remove track from list
m_Tracks.erase(std::remove_if(m_Tracks.begin(), m_Tracks.end(), [pTrainTrack](auto& pTrack) { return pTrack.get() == pTrainTrack; }));

// Patch track count
PatchNumberOfTracks(static_cast<std::uint8_t>(m_Tracks.size()));
}

void CTrainTrackManagerSA::Reset()
{
// Clear tracks
m_Tracks.clear();

// Clear SA data
if (m_TrackNodePointers != nullptr)
{
delete m_TrackNodePointers;
delete m_TrackLengths;
delete m_NumberOfTrackNodes;
}
m_TrackNodePointers = nullptr;
m_TrackLengths = nullptr;
m_NumberOfTrackNodes = nullptr;
m_CurrentTrackNodeSize = 0;
}

uint CTrainTrackManagerSA::AllocateTrainTrackIndex()
{
// Check if there is a free index
for (uint i = 0; i < m_CurrentTrackNodeSize; ++i)
{
if (m_TrackNodePointers[i] == nullptr)
return i;
}

// We ran out-of-space, so allocate some more tracks
auto previousTrackNodeSize = m_CurrentTrackNodeSize;
m_CurrentTrackNodeSize += 10;
auto trackNodePtrs = new STrackNode*[m_CurrentTrackNodeSize];
std::memset(trackNodePtrs, 0, m_CurrentTrackNodeSize * sizeof(STrackNode**));
auto trackLengths = new float[m_CurrentTrackNodeSize];
auto numTrackNodes = new std::uint32_t[m_CurrentTrackNodeSize];

if (m_TrackNodePointers != nullptr)
{
// Copy previous data into these arrays
std::memcpy(trackNodePtrs, m_TrackNodePointers, previousTrackNodeSize * sizeof(STrackNode**));
std::memcpy(trackLengths, m_TrackLengths, previousTrackNodeSize * sizeof(float*));
std::memcpy(numTrackNodes, m_NumberOfTrackNodes, previousTrackNodeSize * sizeof(std::uint32_t*));

// Delete old memory
delete m_TrackNodePointers;
delete m_TrackLengths;
delete m_NumberOfTrackNodes;
}

// Replace with new
m_TrackNodePointers = trackNodePtrs;
m_TrackLengths = trackLengths;
m_NumberOfTrackNodes = numTrackNodes;

// Patch references
PatchReferences();

// Return new id
return previousTrackNodeSize;
}

void CTrainTrackManagerSA::PatchReferences()
{
// pGlobalTrainNodes 0xC38014
MemPut(0x6F58D2, m_TrackNodePointers); // 1
MemPut(0x6F59FE, m_TrackNodePointers); // 2
MemPut(0x6F6C06, m_TrackNodePointers); // 3
MemPut(0x6F6D0A, m_TrackNodePointers); // 4
MemPut(0x6F6EB1, m_TrackNodePointers); // 5
MemPut(0x6F6F79, m_TrackNodePointers); // 6
MemPut(0x6F7442, m_TrackNodePointers); // 7
MemPut(0x6F7467, m_TrackNodePointers); // 8
MemPut(0x6F74EC, m_TrackNodePointers); // 9
MemPut(0x6F75B7, m_TrackNodePointers); // 10
MemPut(0x6F7B73, m_TrackNodePointers); // 11
MemPut(0x6F7C60, m_TrackNodePointers); // 12
MemPut(0x6F7DC5, m_TrackNodePointers); // 13
MemPut(0x6F7EE9, m_TrackNodePointers); // 14
MemPut(0x6F8007, m_TrackNodePointers); // 15
MemPut(0x6F809C, m_TrackNodePointers); // 16
MemPut(0x6F871C, m_TrackNodePointers); // 17

// fRailTrackOneLength 0xC37FEC
MemPut(0x6F5BC4, m_TrackLengths); // 1
MemPut(0x6F5BD9, m_TrackLengths); // 2
MemPut(0x6F5C15, m_TrackLengths); // 3
MemPut(0x6F5C32, m_TrackLengths); // 4
MemPut(0x6F745D, m_TrackLengths); // 5
MemPut(0x6F8712, m_TrackLengths); // 6
MemPut(0x6F6FE8, m_TrackLengths); // 7

// iNumberOfTrackNodes 0xC38014
MemPut(0x6F59EB, m_NumberOfTrackNodes); // 1
MemPut(0x6F6BF3, m_NumberOfTrackNodes); // 2
MemPut(0x6F6C96, m_NumberOfTrackNodes); // 3
MemPut(0x6F6CD1, m_NumberOfTrackNodes); // 4
MemPut(0x6F6D04, m_NumberOfTrackNodes); // 5
MemPut(0x6F6F52, m_NumberOfTrackNodes); // 6
MemPut(0x6F7DB6, m_NumberOfTrackNodes); // 7
MemPut(0x6F7F05, m_NumberOfTrackNodes); // 8
MemPut(0x6F7F12, m_NumberOfTrackNodes); // 9
MemPut(0x6F8001, m_NumberOfTrackNodes); // 10
MemPut(0x6F80B6, m_NumberOfTrackNodes); // 11
MemPut(0x6F80C3, m_NumberOfTrackNodes); // 12
MemPut(0x6F8723, m_NumberOfTrackNodes); // 13
}

void CTrainTrackManagerSA::PatchNumberOfTracks(std::uint8_t numTracks)
{
// .text:006F6CA7 cmp esi, 4
MemPut(0x6F6CA9, numTracks);
}
61 changes: 61 additions & 0 deletions Client/game_sa/CTrainTrackManagerSA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CTrainTrackManagerSA.h
* PURPOSE: Header file for train node manager class
* DEVELOPERS: Cazomino05 <Cazomino05@gmail.com>
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/
#pragma once
#include <game/CTrainTrackManager.h>
#include <game/CTrainTrack.h>

struct STrackNode;
class CTrainTrackSA;

class CTrainTrackManagerSA : public CTrainTrackManager
{
public:
CTrainTrackManagerSA();

virtual CTrainTrack* CreateTrainTrack(const std::vector<STrackNode>& nodes, bool bLinkedLastNode) override;
virtual void DestroyTrainTrack(CTrainTrack* pTrainTrack) override;

virtual void Reset() override;

void UpdateTrackData(CTrainTrackSA* pTrainTrack);

virtual CTrainTrack* GetTrainTrackByIndex(uint trackIndex) override;

virtual std::size_t GetNumberOfTrainTracks() const override { return m_Tracks.size(); }
virtual const std::vector<std::unique_ptr<CTrainTrack>>& GetTrackNodes() const override { return m_Tracks; }

private:
uint AllocateTrainTrackIndex();
void PatchReferences();
void PatchNumberOfTracks(std::uint8_t numTracks);

std::vector<std::unique_ptr<CTrainTrack>> m_Tracks;

// Arrays that are directly passed to SA
uint m_CurrentTrackNodeSize = 0;
STrackNode** m_TrackNodePointers = nullptr;
float* m_TrackLengths = nullptr;
std::uint32_t* m_NumberOfTrackNodes = nullptr;
};

/*
DOCUMENTATION:
- m_Tracks: Currently used train tracks (includes new tracks as well)
- m_TrackNodePointers: Contains ALL track nodes for ALL tracks
- m_TrackLengths: Contains overall track lengths

MEMORY ADDRESSES:
- 0xC38014: NUM_RAILTRACKS dwords
- 0xC37FEC: Track Length floats
- 0xC38024: NUM_RAILTRACKS pointers to arrays of STrackNode
- 0x6F6BD0: int GetTrainNodeNearPoint(float x, float y, float z, int* pTrackID) places track ID in *pTrackID and returns node ID
*/
Loading