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

feat(gamestate/server): CREATE_TRAIN(_CARRIAGE) natives #2322

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion code/components/citizen-server-impl/component.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"vendor:folly",
"vendor:concurrentqueue",
"vendor:xenium",
"vendor:rocksdb"
"vendor:rocksdb",
"vendor:tinyxml2-dll"
],
"provides": []
}
52 changes: 52 additions & 0 deletions code/components/citizen-server-impl/include/parser/Parser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

#include "StdInc.h"
#include <tinyxml2.h>

#include <ScriptWarnings.h>
#include <ClientRegistry.h>
#include <ResourceManager.h>
#include <VFSManager.h>

namespace fx::data {
template<typename T>
class Parser
{
protected:
T m_data;
public:
inline bool LoadFile(fwRefContainer<fx::Resource> resource, std::string_view file)
{
const std::string& rootPath = resource->GetPath();

if (rootPath.empty())
{
return false;
}

fwRefContainer<vfs::Stream> stream = vfs::OpenRead(rootPath + "/" + std::string{ file });

if (!stream.GetRef())
{
fx::scripting::Warningf("", "Unable to locate file at @%s/%s", resource->GetName(), file);
return false;
}

auto data = stream->ReadToEnd();
tinyxml2::XMLDocument document;
tinyxml2::XMLError error = document.Parse(reinterpret_cast<const char*>(data.data()), data.size());

if (error == tinyxml2::XML_SUCCESS)
{
return ParseFile(document);
}
};

virtual bool ParseFile(tinyxml2::XMLDocument&) = 0;

T GetData()
{
return m_data;
};
};
}
144 changes: 144 additions & 0 deletions code/components/citizen-server-impl/include/parser/TrainParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#pragma once

#include "Parser.h"

namespace fx::data
{
struct CTrainCarriageInfo
{
const char* m_modelName;

uint32_t m_maxPedsPerCarriage;
bool m_flipModelDir;
bool m_doInteriorLights;
bool m_carriageVertOffset;
uint32_t m_repeatCount;
};

struct CTrainConfig
{
const char* m_name;
float m_populateTrainDist;
bool m_announceStations;
bool m_doorsBeep;
bool m_carriagesHang;
bool m_carriagesSwing;
bool m_carriagesUseEvenTrackSpacing;
bool m_linkTracksWithAdjacentStations;
bool m_noRandomSpawns;
float m_carriageGap;

std::vector<CTrainCarriageInfo> m_carriages;
};

struct CTrainTrack
{
const char* m_trainConfigName;
bool m_isPingPongTrack;
bool m_stopsAtStations;
bool m_MPStopsAtStations;
int32_t m_speed;
int32_t m_breakingDist;
};
}

namespace fx
{
class CTrainConfigParser : public fwRefCountable, public data::Parser<std::vector<data::CTrainConfig>>
{
bool ParseFile(tinyxml2::XMLDocument& document) override
{
tinyxml2::XMLElement* configs = document.FirstChildElement("train_configs");

if (!configs)
{
return false;
}

std::vector<data::CTrainConfig> trainConfigs;
tinyxml2::XMLElement* config = configs->FirstChildElement("train_config");

if (config == nullptr)
{
return false;
}

while (config)
{
data::CTrainConfig trainConfig{};
trainConfig.m_name = config->Attribute("name");
trainConfig.m_populateTrainDist = config->IntAttribute("populate_train_dist", 0);
trainConfig.m_announceStations = config->BoolAttribute("announce_stations", false);
trainConfig.m_doorsBeep = config->BoolAttribute("doors_beep", false);
trainConfig.m_carriagesHang = config->BoolAttribute("carriages_hang", false);
trainConfig.m_carriagesSwing = config->BoolAttribute("carriages_swing", false);
trainConfig.m_linkTracksWithAdjacentStations = config->BoolAttribute("link_tracks_with_adjacent_stations", true);
trainConfig.m_noRandomSpawns = config->BoolAttribute("no_random_spawn", true);
trainConfig.m_carriageGap = config->FloatAttribute("carriage_gap", 0.1);

tinyxml2::XMLElement* carriage = config->FirstChildElement("carriage");
while (carriage)
{
data::CTrainCarriageInfo carriageInfo{};
carriageInfo.m_modelName = config->Attribute("model_name");
carriageInfo.m_maxPedsPerCarriage = config->IntAttribute("max_peds_per_carriage", 0);
carriageInfo.m_flipModelDir = config->BoolAttribute("flip_model_dir", false);
carriageInfo.m_doInteriorLights = config->BoolAttribute("do_interior_lights", false);
carriageInfo.m_carriageVertOffset = config->FloatAttribute("carriage_vert_offset", 1.0);
carriageInfo.m_repeatCount = config->IntAttribute("repeat_count", 1);

trainConfig.m_carriages.push_back(carriageInfo);

carriage = carriage->NextSiblingElement("carriage");
}

trainConfigs.push_back(trainConfig);
config = config->NextSiblingElement("train_config");
}

m_data = trainConfigs;
return true;
}
};

class CTrainTrackParser : public fwRefCountable, public data::Parser<std::vector<data::CTrainTrack>>
{
bool ParseFile(tinyxml2::XMLDocument& document)
{
tinyxml2::XMLElement* tracks = document.FirstChildElement("train_tracks");

if (!tracks)
{
return false;
}

std::vector<data::CTrainTrack> trainTracks;
tinyxml2::XMLElement* track = tracks->FirstChildElement("train_track");

if (track == nullptr)
{
return false;
}

while (track)
{
data::CTrainTrack trainTrack{};
trainTrack.m_trainConfigName = track->Attribute("trainConfigName");
trainTrack.m_isPingPongTrack = track->BoolAttribute("isPingPongTrack", false);
trainTrack.m_stopsAtStations = track->BoolAttribute("stopsAtStations", false);
trainTrack.m_MPStopsAtStations = track->BoolAttribute("MPstopsAtStations", false);
trainTrack.m_speed = track->IntAttribute("speed", 8);
trainTrack.m_breakingDist = track->IntAttribute("brakingDist", 10);

trainTracks.push_back(trainTrack);
track = track->NextSiblingElement("train_track");
}

m_data = trainTracks;
return true;
}
};
}

DECLARE_INSTANCE_TYPE(fx::CTrainConfigParser);
DECLARE_INSTANCE_TYPE(fx::CTrainTrackParser);
Original file line number Diff line number Diff line change
Expand Up @@ -547,18 +547,18 @@ struct CTrainGameStateDataNodeData
bool isEngine;
bool isCaboose;

bool unk12;
bool isMissionTrain;

bool direction;

bool unk14;
bool hasPassengerCarriages;

bool renderDerailed;

// 2372 {
bool unk198;
bool unk224;
bool unk199;
bool allowRemovalByPopulation;
bool highPrecisionBlending;
bool shouldStopAtStations;
// }

bool forceDoorsOpen;
Expand Down Expand Up @@ -1113,6 +1113,9 @@ struct ScriptGuid
}
};

auto GetTrain(fx::ServerGameState* sgs, uint32_t objectId) -> fx::sync::SyncEntityPtr;
auto GetNextTrain(fx::ServerGameState* sgs, const fx::sync::SyncEntityPtr& entity) -> fx::sync::SyncEntityPtr;

struct EntityCreationState
{
// TODO: allow resending in case the target client disappears
Expand Down
34 changes: 22 additions & 12 deletions code/components/citizen-server-impl/include/state/SyncTrees_Five.h
Original file line number Diff line number Diff line change
Expand Up @@ -2623,21 +2623,31 @@ struct CTrainGameStateDataNode : GenericSerializeDataNode<CTrainGameStateDataNod
// 0 = Moving, 1 = Slowing down, 2 = Doors opening, 3 = Stopped, 4 = Doors closing, 5 = Before depart
s.Serialize(3, data.trainState);

s.Serialize(data.isEngine);
s.Serialize(data.isEngine);

//2372 inserted a bool between isEngine and isCaboose
if (Is2372())
{
//Modified by 0x2310A8F9421EBF43
s.Serialize(data.allowRemovalByPopulation);
}

s.Serialize(data.isCaboose);
s.Serialize(data.unk12);
s.Serialize(data.isMissionTrain);
s.Serialize(data.direction);
s.Serialize(data.unk14);
s.Serialize(data.hasPassengerCarriages);
s.Serialize(data.renderDerailed);

if (Is2372()) // Sequence of bits need to be verified for 2732
{
s.Serialize(data.unk198);
s.Serialize(data.unk224);
s.Serialize(data.unk199);
}

s.Serialize(data.forceDoorsOpen);

if (Is2372())
{
// true on randomly spawned metro trains
s.Serialize(data.shouldStopAtStations);

//Modified by 0xEC0C1D4922AF9754
s.Serialize(data.highPrecisionBlending);
}

return true;
}
Expand Down Expand Up @@ -3278,7 +3288,7 @@ struct SyncTree : public SyncTreeBaseImpl<TNode, false>
}
}
}
}
}

virtual CDoorMovementDataNodeData* GetDoorMovement() override
{
Expand Down Expand Up @@ -3525,7 +3535,7 @@ struct SyncTree : public SyncTreeBaseImpl<TNode, false>
auto [hasNode, node] = this->template GetData<CPedMovementGroupDataNode>();

return hasNode ? &node->data : nullptr;
}
}

virtual void CalculatePosition() override
{
Expand Down
15 changes: 12 additions & 3 deletions code/components/citizen-server-impl/src/state/ServerGameState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <EASTL/fixed_vector.h>

#include <state/Pool.h>
#include <parser/TrainParser.h>

#include <IteratorView.h>

Expand Down Expand Up @@ -839,7 +840,8 @@ void sync::SyncCommandList::Execute(const fx::ClientSharedPtr& client)
}

#ifdef STATE_FIVE
static auto GetTrain(fx::ServerGameState* sgs, uint32_t objectId) -> fx::sync::SyncEntityPtr

auto GetTrain(fx::ServerGameState* sgs, uint32_t objectId) -> fx::sync::SyncEntityPtr
{
if (objectId != 0)
{
Expand All @@ -854,7 +856,7 @@ static auto GetTrain(fx::ServerGameState* sgs, uint32_t objectId) -> fx::sync::S
return {};
};

static auto GetNextTrain(fx::ServerGameState* sgs, const fx::sync::SyncEntityPtr& entity) -> fx::sync::SyncEntityPtr
auto GetNextTrain(fx::ServerGameState* sgs, const fx::sync::SyncEntityPtr& entity) -> fx::sync::SyncEntityPtr
{
if (auto trainState = entity->syncTree->GetTrainState())
{
Expand Down Expand Up @@ -6940,8 +6942,15 @@ static InitFunction initFunction([]()
g_oneSyncWorkaround763185 = instance->AddVariable<bool>("onesync_workaround763185", ConVar_None, false);

fwRefContainer<fx::ServerGameState> sgs = new fx::ServerGameState();

fwRefContainer<fx::CTrainConfigParser> trainConfigParser = new fx::CTrainConfigParser();
fwRefContainer<fx::CTrainTrackParser> trainTrackParser = new fx::CTrainTrackParser();

instance->SetComponent(sgs);
instance->SetComponent<fx::ServerGameStatePublic>(sgs);
instance->SetComponent<fx::ServerGameStatePublic>(sgs);

instance->SetComponent<fx::CTrainConfigParser>(trainConfigParser);
instance->SetComponent<fx::CTrainTrackParser>(trainTrackParser);

instance->GetComponent<fx::GameServer>()->OnSyncTick.Connect([=]()
{
Expand Down
Loading
Loading