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

Lua Writable Collections #160

Merged
merged 11 commits into from
Dec 7, 2024
Merged
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

- `MOSRotating` Lua function `AddWound` now additionally accepts the format `MOSRotating:AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit, bool isEntryWound, bool isExitWound)`, allowing modders to specify added wounds as entry- or exit wounds, for the purpose of not playing multiple burst sounds on the same frame. These new arguments are optional.

- Various performance improvements.

</details>

<details><summary><b>Fixed</b></summary>
Expand All @@ -147,6 +149,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

- Fixed an issue where internal Lua functions OriginalDoFile, OriginalLoadFile, and OriginalRequire were polluting the global namespace. They have now been made inaccessible.

- Fixed issue where MOSR `Gib`s, `AEmitter` or `PEmitter` `Emission`s, and MetaMan `Player`s were not correctly accessible from script.

- Fixed a crash on launch when the `SupportedGameVersion` INI property was not set.

</details>

<details><summary><b>Removed</b></summary>
Expand Down Expand Up @@ -2677,7 +2683,7 @@ This can be accessed via the new Lua (R/W) `SettingsMan` property `AIUpdateInter

- `TDExplosive.ActivatesWhenReleased` now works properly.

- Various bug fixed related to all the Attachable and Emitter changes, so they can now me affected reliably and safely with lua.
- Various bugs fixed related to all the Attachable and Emitter changes, so they can again be affected reliably and safely with lua.

- Various minor other things that have gotten lost in the shuffle.

Expand Down
6 changes: 3 additions & 3 deletions Source/Activities/AreaEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,12 @@ void AreaEditor::Update() {
m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::PREADDMOVEBOX);
} else {
// Make and name new Area
Scene::Area newArea(m_pNewAreaName->GetText());
Scene::Area* newArea = new Scene::Area(m_pNewAreaName->GetText());
pCurrentScene->m_AreaList.push_back(newArea);
// Set the new area as the active one in the GUI, note we're getting the correct one from the scene, it's a copy of the one passed in
m_pEditorGUI->SetCurrentArea(pCurrentScene->GetArea(newArea.GetName()));
m_pEditorGUI->SetCurrentArea(pCurrentScene->GetArea(newArea->GetName()));
// Update teh picker list of the GUI so we can mousewheel between all the Areas, incl the new one
m_pEditorGUI->UpdatePickerList(newArea.GetName());
m_pEditorGUI->UpdatePickerList(newArea->GetName());
}

// Change mode to start editing the new/newly selected Area
Expand Down
22 changes: 11 additions & 11 deletions Source/Activities/GibEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,14 +400,14 @@ void GibEditor::Update() {
m_pEditedObject->Update();

// Make proxy copies of the loaded objects' gib reference instances and place them in the list to be edited
std::list<Gib>* pLoadedGibList = m_pEditedObject->GetGibList();
std::list<Gib*>* pLoadedGibList = m_pEditedObject->GetGibList();
std::list<MovableObject*>* pEditedGibList = m_pEditorGUI->GetPlacedGibs();
MovableObject* pGibCopy = 0;

for (auto gItr = pLoadedGibList->begin(); gItr != pLoadedGibList->end(); ++gItr) {
pGibCopy = dynamic_cast<MovableObject*>((*gItr).GetParticlePreset()->Clone());
pGibCopy = dynamic_cast<MovableObject*>((*gItr)->GetParticlePreset()->Clone());
if (pGibCopy) {
pGibCopy->SetPos(m_pEditedObject->GetPos() + (*gItr).GetOffset());
pGibCopy->SetPos(m_pEditedObject->GetPos() + (*gItr)->GetOffset());
pEditedGibList->push_back(pGibCopy);
}
pGibCopy = 0;
Expand Down Expand Up @@ -599,8 +599,8 @@ bool GibEditor::SaveObject(const std::string& saveAsName, bool forceOverwrite) {
}
objectWriter.NewProperty(addObjectType);
m_pEditedObject->Entity::Save(objectWriter);
for (const Gib& gib: *m_pEditedObject->GetGibList()) {
objectWriter.NewPropertyWithValue("AddGib", gib);
for (const Gib* gib: *m_pEditedObject->GetGibList()) {
objectWriter.NewPropertyWithValue("AddGib", *gib);
}
objectWriter.ObjectEnd();
objectWriter.EndWrite();
Expand All @@ -626,18 +626,18 @@ void GibEditor::StuffEditedGibs(MOSRotating* pEditedObject) {
return;

// Replace the gibs of the object with the proxies that have been edited in the gui
std::list<Gib>* pObjectGibList = pEditedObject->GetGibList();
std::list<Gib*>* pObjectGibList = pEditedObject->GetGibList();
pObjectGibList->clear();

// Take each proxy object and stuff it into a Gib instance which then gets stuffed into the object to be saved
std::list<MovableObject*>* pProxyGibList = m_pEditorGUI->GetPlacedGibs();
for (std::list<MovableObject*>::iterator gItr = pProxyGibList->begin(); gItr != pProxyGibList->end(); ++gItr) {
Gib newGib;
Gib* newGib;
// Only set the refernce instance directly from the isntanceman. OWNERSHIP IS NOT TRANSFERRED!
newGib.m_GibParticle = dynamic_cast<const MovableObject*>(g_PresetMan.GetEntityPreset((*gItr)->GetClassName(), (*gItr)->GetPresetName(), m_ModuleSpaceID));
if (newGib.m_GibParticle) {
newGib.m_Count = 1;
newGib.m_Offset = (*gItr)->GetPos() - pEditedObject->GetPos();
newGib->m_GibParticle = dynamic_cast<const MovableObject*>(g_PresetMan.GetEntityPreset((*gItr)->GetClassName(), (*gItr)->GetPresetName(), m_ModuleSpaceID));
if (newGib->m_GibParticle) {
newGib->m_Count = 1;
newGib->m_Offset = (*gItr)->GetPos() - pEditedObject->GetPos();
// TODO: do proper velocity calculations here!
// ... actually leave these as 0 and let them be calculated in GibThis
// newGib.m_MinVelocity = (100.0f + 50.0f * NormalRand()) / (*gItr)->GetMass();
Expand Down
102 changes: 54 additions & 48 deletions Source/Entities/AEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ int AEmitter::Create(const AEmitter& reference) {
SetFlash(dynamic_cast<Attachable*>(reference.m_pFlash->Clone()));
}

for (auto itr = reference.m_EmissionList.begin(); itr != reference.m_EmissionList.end(); ++itr) {
m_EmissionList.push_back(*itr);
for (Emission* emission: reference.m_EmissionList) {
m_EmissionList.push_back(static_cast<Emission*>(emission->Clone()));
}
if (reference.m_EmissionSound) {
m_EmissionSound = dynamic_cast<SoundContainer*>(reference.m_EmissionSound->Clone());
Expand Down Expand Up @@ -105,8 +105,8 @@ int AEmitter::ReadProperty(const std::string_view& propName, Reader& reader) {
StartPropertyList(return Attachable::ReadProperty(propName, reader));

MatchProperty("AddEmission", {
Emission emission;
reader >> emission;
Emission* emission = new Emission();
reader >> *emission;
m_EmissionList.push_back(emission);
});
MatchProperty("EmissionSound", {
Expand All @@ -128,8 +128,8 @@ int AEmitter::ReadProperty(const std::string_view& propName, Reader& reader) {
float ppm;
reader >> ppm;
// Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility.
for (Emission& emission: m_EmissionList) {
emission.m_PPM = ppm / static_cast<float>(m_EmissionList.size());
for (Emission* emission: m_EmissionList) {
emission->m_PPM = ppm / static_cast<float>(m_EmissionList.size());
}
});
MatchProperty("NegativeThrottleMultiplier", { reader >> m_NegativeThrottleMultiplier; });
Expand All @@ -140,8 +140,8 @@ int AEmitter::ReadProperty(const std::string_view& propName, Reader& reader) {
int burstSize;
reader >> burstSize;
// Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility.
for (Emission& emission: m_EmissionList) {
emission.m_BurstSize = std::ceil(static_cast<float>(burstSize) / static_cast<float>(m_EmissionList.size()));
for (Emission* emission: m_EmissionList) {
emission->m_BurstSize = std::ceil(static_cast<float>(burstSize) / static_cast<float>(m_EmissionList.size()));
}
});
MatchProperty("BurstScale", { reader >> m_BurstScale; });
Expand All @@ -166,9 +166,9 @@ int AEmitter::ReadProperty(const std::string_view& propName, Reader& reader) {
int AEmitter::Save(Writer& writer) const {
Attachable::Save(writer);

for (auto itr = m_EmissionList.begin(); itr != m_EmissionList.end(); ++itr) {
for (Emission* emission: m_EmissionList) {
writer.NewProperty("AddEmission");
writer << *itr;
writer << *emission;
}
writer.NewProperty("EmissionSound");
writer << m_EmissionSound;
Expand Down Expand Up @@ -233,21 +233,27 @@ void AEmitter::Destroy(bool notInherited) {
m_EmissionSound->Stop();
}

for (Emission* emission: m_EmissionList) {
delete emission;
}

delete m_EmissionSound;
delete m_BurstSound;
delete m_EndSound;

// m_BurstSound.Stop();

if (!notInherited)
if (!notInherited) {
Attachable::Destroy();
}
Clear();
}

void AEmitter::ResetEmissionTimers() {
m_LastEmitTmr.Reset();
for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr)
(*eItr).ResetEmissionTimers();
for (Emission* emission: m_EmissionList) {
emission->ResetEmissionTimers();
}
}

void AEmitter::EnableEmission(bool enable) {
Expand All @@ -268,22 +274,22 @@ float AEmitter::EstimateImpulse(bool burst) {
float velMin, velMax, velRange, spread;

// Go through all emissions and emit them according to their respective rates
for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) {
for (Emission* emission: m_EmissionList) {
// Only check emissions that push the emitter
if ((*eItr).PushesEmitter()) {
float emissions = ((*eItr).GetRate() / 60.0f) * g_TimerMan.GetDeltaTimeSecs();
if (emission->PushesEmitter()) {
float emissions = (emission->GetRate() / 60.0f) * g_TimerMan.GetDeltaTimeSecs();
float scale = 1.0F;
if (burst) {
emissions *= (*eItr).GetBurstSize();
emissions *= emission->GetBurstSize();
scale = m_BurstScale;
}

velMin = (*eItr).GetMinVelocity() * scale;
velRange = ((*eItr).GetMaxVelocity() - (*eItr).GetMinVelocity()) * 0.5F * scale;
spread = (std::max(static_cast<float>(c_PI) - (*eItr).GetSpread(), 0.0F) / c_PI) * scale; // A large spread will cause the forces to cancel eachother out
velMin = emission->GetMinVelocity() * scale;
velRange = (emission->GetMaxVelocity() - emission->GetMinVelocity()) * 0.5F * scale;
spread = (std::max(static_cast<float>(c_PI) - emission->GetSpread(), 0.0F) / c_PI) * scale; // A large spread will cause the forces to cancel eachother out

// Add to accumulative recoil impulse generated, F = m * a.
impulse += (velMin + velRange) * spread * (*eItr).m_pEmission->GetMass() * emissions;
impulse += (velMin + velRange) * spread * emission->m_pEmission->GetMass() * emissions;
}
}

Expand All @@ -305,16 +311,16 @@ float AEmitter::EstimateImpulse(bool burst) {

float AEmitter::GetTotalParticlesPerMinute() const {
float totalPPM = 0;
for (const Emission& emission: m_EmissionList) {
totalPPM += emission.m_PPM;
for (const Emission* emission: m_EmissionList) {
totalPPM += emission->m_PPM;
}
return totalPPM;
}

int AEmitter::GetTotalBurstSize() const {
int totalBurstSize = 0;
for (const Emission& emission: m_EmissionList) {
totalBurstSize += emission.m_BurstSize;
for (const Emission* emission: m_EmissionList) {
totalBurstSize += emission->m_BurstSize;
}
return totalBurstSize;
}
Expand Down Expand Up @@ -382,8 +388,8 @@ void AEmitter::Update() {
}

// Reset the timers of all emissions so they will start/stop at the correct relative offsets from now
for (Emission& emission: m_EmissionList)
emission.ResetEmissionTimers();
for (Emission* emission: m_EmissionList)
emission->ResetEmissionTimers();
}
// Update the distance attenuation
else if (m_EmissionSound) {
Expand Down Expand Up @@ -415,11 +421,11 @@ void AEmitter::Update() {
MovableObject* pParticle = 0;
Vector parentVel, emitVel, pushImpulses;
// Go through all emissions and emit them according to their respective rates
for (Emission& emission: m_EmissionList) {
for (Emission* emission: m_EmissionList) {
// Make sure the emissions only happen between the start time and end time
if (emission.IsEmissionTime()) {
if (emission->IsEmissionTime()) {
// Apply the throttle factor to the emission rate
currentPPM = emission.GetRate() * throttleFactor;
currentPPM = emission->GetRate() * throttleFactor;
int emissionCount = 0;

// Only do all this if the PPM is actually above zero
Expand All @@ -428,71 +434,71 @@ void AEmitter::Update() {
SPE = 60.0 / currentPPM;

// Add the last elapsed time to the accumulator
emission.m_Accumulator += m_LastEmitTmr.GetElapsedSimTimeS();
emission->m_Accumulator += m_LastEmitTmr.GetElapsedSimTimeS();

// Now figure how many full emissions can fit in the current accumulator
emissionCount = std::floor(emission.m_Accumulator / SPE);
emissionCount = std::floor(emission->m_Accumulator / SPE);
// Deduct the about to be emitted emissions from the accumulator
emission.m_Accumulator -= emissionCount * SPE;
emission->m_Accumulator -= emissionCount * SPE;

RTEAssert(emission.m_Accumulator >= 0, "Emission accumulator negative!");
RTEAssert(emission->m_Accumulator >= 0, "Emission accumulator negative!");
} else {
emission.m_Accumulator = 0;
emission->m_Accumulator = 0;
}
float scale = 1.0F;
// Add extra emissions if bursting.
if (m_BurstTriggered) {
emissionCount += emission.GetBurstSize() * std::floor(throttleFactor);
emissionCount += emission->GetBurstSize() * std::floor(throttleFactor);
scale = m_BurstScale;
}
emissionCountTotal += emissionCount;
if (emissionCount > 0) {
int extraEmissions = emission.GetParticleCount() - 1;
int extraEmissions = emission->GetParticleCount() - 1;
emissionCount += extraEmissions;
}
pParticle = 0;
emitVel.Reset();
parentVel = pRootParent->GetVel() * emission.InheritsVelocity();
Vector rotationalVel = (((RotateOffset(emission.GetOffset()) + (m_Pos - pRootParent->GetPos())) * pRootParent->GetAngularVel()).GetPerpendicular() / c_PPM) * emission.InheritsVelocity();
parentVel = pRootParent->GetVel() * emission->InheritsVelocity();
Vector rotationalVel = (((RotateOffset(emission->GetOffset()) + (m_Pos - pRootParent->GetPos())) * pRootParent->GetAngularVel()).GetPerpendicular() / c_PPM) * emission->InheritsVelocity();

for (int i = 0; i < emissionCount; ++i) {
velMin = emission.GetMinVelocity() * scale;
velRange = (emission.GetMaxVelocity() - emission.GetMinVelocity()) * scale;
spread = emission.GetSpread() * scale;
velMin = emission->GetMinVelocity() * scale;
velRange = (emission->GetMaxVelocity() - emission->GetMinVelocity()) * scale;
spread = emission->GetSpread() * scale;
// Make a copy after the reference particle
pParticle = dynamic_cast<MovableObject*>(emission.GetEmissionParticlePreset()->Clone());
pParticle = dynamic_cast<MovableObject*>(emission->GetEmissionParticlePreset()->Clone());
// Set up its position and velocity according to the parameters of this.
// Emission point offset not set

if (emission.GetOffset().IsZero()) {
if (emission->GetOffset().IsZero()) {
if (m_EmissionOffset.IsZero()) {
pParticle->SetPos(m_Pos);
} else {
pParticle->SetPos(m_Pos + RotateOffset(m_EmissionOffset));
}
} else {
pParticle->SetPos(m_Pos + RotateOffset(emission.GetOffset()));
pParticle->SetPos(m_Pos + RotateOffset(emission->GetOffset()));
}
// TODO: Optimize making the random angles!")
emitVel.SetXY(velMin + RandomNum(0.0F, velRange), 0.0F);
emitVel.RadRotate(m_EmitAngle.GetRadAngle() + spread * RandomNormalNum());
emitVel = RotateOffset(emitVel);
pParticle->SetVel(parentVel + rotationalVel + emitVel);
pParticle->SetRotAngle(emitVel.GetAbsRadAngle() + (m_HFlipped ? -c_PI : 0));
pParticle->SetAngularVel(pRootParent->GetAngularVel() * emission.InheritsAngularVelocity());
pParticle->SetAngularVel(pRootParent->GetAngularVel() * emission->InheritsAngularVelocity());
pParticle->SetHFlipped(m_HFlipped);

// Scale the particle's lifetime based on life variation and throttle, as long as it's not 0
if (pParticle->GetLifetime() != 0) {
pParticle->SetLifetime(std::max(static_cast<int>(static_cast<float>(pParticle->GetLifetime()) * (1.0F + (emission.GetLifeVariation() * RandomNormalNum()))), 1));
pParticle->SetLifetime(std::max(static_cast<int>(static_cast<float>(pParticle->GetLifetime()) * (1.0F + (emission->GetLifeVariation() * RandomNormalNum()))), 1));
pParticle->SetLifetime(std::max(static_cast<int>(pParticle->GetLifetime() * throttleFactor), 1));
}
pParticle->SetTeam(m_Team);
pParticle->SetIgnoresTeamHits(true);

// Add to accumulative recoil impulse generated, F = m * a
// If enabled, that is
if (emission.PushesEmitter() && (GetParent() || GetMass() > 0)) {
if (emission->PushesEmitter() && (GetParent() || GetMass() > 0)) {
pushImpulses -= emitVel * pParticle->GetMass();
}

Expand Down
2 changes: 1 addition & 1 deletion Source/Entities/AEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ namespace RTE {
static Entity::ClassInfo m_sClass;

// The list of MO instances that get emitted
std::vector<Emission> m_EmissionList;
std::list<Emission*> m_EmissionList;
// Sounds
SoundContainer* m_EmissionSound;
SoundContainer* m_BurstSound;
Expand Down
Loading
Loading